diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm-project/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp | |
parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) |
Notes
Diffstat (limited to 'contrib/llvm-project/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp b/contrib/llvm-project/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp new file mode 100644 index 000000000000..365cba5a60ca --- /dev/null +++ b/contrib/llvm-project/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp @@ -0,0 +1,173 @@ +//===- WebAssemblyDisassemblerEmitter.cpp - Disassembler tables -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is part of the WebAssembly Disassembler Emitter. +// It contains the implementation of the disassembler tables. +// Documentation for the disassembler emitter in general can be found in +// WebAssemblyDisassemblerEmitter.h. +// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyDisassemblerEmitter.h" +#include "llvm/TableGen/Record.h" + +namespace llvm { + +static constexpr int WebAssemblyInstructionTableSize = 256; + +void emitWebAssemblyDisassemblerTables( + raw_ostream &OS, + const ArrayRef<const CodeGenInstruction *> &NumberedInstructions) { + // First lets organize all opcodes by (prefix) byte. Prefix 0 is the + // starting table. + std::map<unsigned, + std::map<unsigned, std::pair<unsigned, const CodeGenInstruction *>>> + OpcodeTable; + for (unsigned I = 0; I != NumberedInstructions.size(); ++I) { + auto &CGI = *NumberedInstructions[I]; + auto &Def = *CGI.TheDef; + if (!Def.getValue("Inst")) + continue; + auto &Inst = *Def.getValueAsBitsInit("Inst"); + auto Opc = static_cast<unsigned>( + reinterpret_cast<IntInit *>(Inst.convertInitializerTo(IntRecTy::get())) + ->getValue()); + if (Opc == 0xFFFFFFFF) + continue; // No opcode defined. + assert(Opc <= 0xFFFF); + auto Prefix = Opc >> 8; + Opc = Opc & 0xFF; + auto &CGIP = OpcodeTable[Prefix][Opc]; + // All wasm instructions have a StackBased field of type string, we only + // want the instructions for which this is "true". + auto StackString = + Def.getValue("StackBased")->getValue()->getCastTo(StringRecTy::get()); + auto IsStackBased = + StackString && + reinterpret_cast<const StringInit *>(StackString)->getValue() == "true"; + if (!IsStackBased) + continue; + if (CGIP.second) { + // We already have an instruction for this slot, so decide which one + // should be the canonical one. This determines which variant gets + // printed in a disassembly. We want e.g. "call" not "i32.call", and + // "end" when we don't know if its "end_loop" or "end_block" etc. + auto IsCanonicalExisting = CGIP.second->TheDef->getValue("IsCanonical") + ->getValue() + ->getAsString() == "1"; + // We already have one marked explicitly as canonical, so keep it. + if (IsCanonicalExisting) + continue; + auto IsCanonicalNew = + Def.getValue("IsCanonical")->getValue()->getAsString() == "1"; + // If the new one is explicitly marked as canonical, take it. + if (!IsCanonicalNew) { + // Neither the existing or new instruction is canonical. + // Pick the one with the shortest name as heuristic. + // Though ideally IsCanonical is always defined for at least one + // variant so this never has to apply. + if (CGIP.second->AsmString.size() <= CGI.AsmString.size()) + continue; + } + } + // Set this instruction as the one to use. + CGIP = std::make_pair(I, &CGI); + } + OS << "#include \"MCTargetDesc/WebAssemblyMCTargetDesc.h\"\n"; + OS << "\n"; + OS << "namespace llvm {\n\n"; + OS << "static constexpr int WebAssemblyInstructionTableSize = "; + OS << WebAssemblyInstructionTableSize << ";\n\n"; + OS << "enum EntryType : uint8_t { "; + OS << "ET_Unused, ET_Prefix, ET_Instruction };\n\n"; + OS << "struct WebAssemblyInstruction {\n"; + OS << " uint16_t Opcode;\n"; + OS << " EntryType ET;\n"; + OS << " uint8_t NumOperands;\n"; + OS << " uint16_t OperandStart;\n"; + OS << "};\n\n"; + std::vector<std::string> OperandTable, CurOperandList; + // Output one table per prefix. + for (auto &PrefixPair : OpcodeTable) { + if (PrefixPair.second.empty()) + continue; + OS << "WebAssemblyInstruction InstructionTable" << PrefixPair.first; + OS << "[] = {\n"; + for (unsigned I = 0; I < WebAssemblyInstructionTableSize; I++) { + auto InstIt = PrefixPair.second.find(I); + if (InstIt != PrefixPair.second.end()) { + // Regular instruction. + assert(InstIt->second.second); + auto &CGI = *InstIt->second.second; + OS << " // 0x"; + OS.write_hex(static_cast<unsigned long long>(I)); + OS << ": " << CGI.AsmString << "\n"; + OS << " { " << InstIt->second.first << ", ET_Instruction, "; + OS << CGI.Operands.OperandList.size() << ", "; + // Collect operand types for storage in a shared list. + CurOperandList.clear(); + for (auto &Op : CGI.Operands.OperandList) { + assert(Op.OperandType != "MCOI::OPERAND_UNKNOWN"); + CurOperandList.push_back(Op.OperandType); + } + // See if we already have stored this sequence before. This is not + // strictly necessary but makes the table really small. + size_t OperandStart = OperandTable.size(); + if (CurOperandList.size() <= OperandTable.size()) { + for (size_t J = 0; J <= OperandTable.size() - CurOperandList.size(); + ++J) { + size_t K = 0; + for (; K < CurOperandList.size(); ++K) { + if (OperandTable[J + K] != CurOperandList[K]) break; + } + if (K == CurOperandList.size()) { + OperandStart = J; + break; + } + } + } + // Store operands if no prior occurrence. + if (OperandStart == OperandTable.size()) { + OperandTable.insert(OperandTable.end(), CurOperandList.begin(), + CurOperandList.end()); + } + OS << OperandStart; + } else { + auto PrefixIt = OpcodeTable.find(I); + // If we have a non-empty table for it that's not 0, this is a prefix. + if (PrefixIt != OpcodeTable.end() && I && !PrefixPair.first) { + OS << " { 0, ET_Prefix, 0, 0"; + } else { + OS << " { 0, ET_Unused, 0, 0"; + } + } + OS << " },\n"; + } + OS << "};\n\n"; + } + // Create a table of all operands: + OS << "const uint8_t OperandTable[] = {\n"; + for (auto &Op : OperandTable) { + OS << " " << Op << ",\n"; + } + OS << "};\n\n"; + // Create a table of all extension tables: + OS << "struct { uint8_t Prefix; const WebAssemblyInstruction *Table; }\n"; + OS << "PrefixTable[] = {\n"; + for (auto &PrefixPair : OpcodeTable) { + if (PrefixPair.second.empty() || !PrefixPair.first) + continue; + OS << " { " << PrefixPair.first << ", InstructionTable" + << PrefixPair.first; + OS << " },\n"; + } + OS << " { 0, nullptr }\n};\n\n"; + OS << "} // End llvm namespace\n"; +} + +} // namespace llvm |