Index: llvm/include/llvm/Target/Target.td =================================================================== --- llvm/include/llvm/Target/Target.td +++ llvm/include/llvm/Target/Target.td @@ -632,6 +632,11 @@ /// by TableGen. bit UseNamedOperandTable = 0; + /// UseLogicalOperandMappings - If set, several helper functions would be + /// generated for this instruction to map properties like index, type of + /// its logical operands to corresponding MI operands. + bit UseLogicalOperandMappings = 0; + /// Should FastISel ignore this instruction. For certain ISAs, they have /// instructions which map to the same ISD Opcode, value type operands and /// instruction selection predicates. FastISel cannot handle such cases, but Index: llvm/utils/TableGen/CMakeLists.txt =================================================================== --- llvm/utils/TableGen/CMakeLists.txt +++ llvm/utils/TableGen/CMakeLists.txt @@ -55,6 +55,7 @@ X86RecognizableInstr.cpp WebAssemblyDisassemblerEmitter.cpp CTagsEmitter.cpp + CodeBeadsGen.cpp ) target_link_libraries(llvm-tblgen PRIVATE LLVMTableGenGlobalISel) set_target_properties(llvm-tblgen PROPERTIES FOLDER "Tablegenning") Index: llvm/utils/TableGen/CodeBeadsGen.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/CodeBeadsGen.cpp @@ -0,0 +1,127 @@ +//===- CodeBeadsGen.cpp - Code Beads Generator ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// CodeBeads are annotations that can be used to represent non-trivial +// instruction variants. More specifically, complex addressing modes appear in +// many CISC architectures. Without the help of CodeBeads to embed addressing +// modes information into Instructions' TG definitions, MC layer might have a +// hard time finding the right binary encoding for an instruction. +//===----------------------------------------------------------------------===// + +#include "CodeGenTarget.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +#include +using namespace llvm; + +namespace { + +class CodeBeadsGen { + RecordKeeper &Records; + +public: + CodeBeadsGen(RecordKeeper &R) : Records(R) {} + void run(raw_ostream &o); +}; + +void CodeBeadsGen::run(raw_ostream &o) { + CodeGenTarget Target(Records); + std::vector Insts = Records.getAllDerivedDefinitions("Instruction"); + + // For little-endian instruction bit encodings, reverse the bit order + Target.reverseBitsForLittleEndianEncoding(); + + ArrayRef NumberedInstructions = + Target.getInstructionsByEnumValue(); + + // Emit function declaration + o << "const uint8_t * " << Target.getName(); + o << "MCCodeEmitter::getGenInstrBeads(const MCInst &MI) const {\n"; + + unsigned Length = 192; + unsigned Size = 8; + unsigned Parts = Length / Size; + + // Emit instruction base values + // TODO Make it auto-detect size + o << " static const uint" << Size << "_t InstBits[][" << Parts << "] = {\n"; + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) { + o << "\t{ 0x0 },"; + o << '\t' << "// (Pseudo) " << R->getName() << "\n"; + continue; + } + + BitsInit *BI = R->getValueAsBitsInit("Beads"); + + if (!BI->isComplete()) { + PrintFatalError(R->getLoc(), "Record `" + R->getName() + + "', bit field 'Beads' is not complete"); + } + + if (BI->getNumBits() > Length) { + PrintFatalError(R->getLoc(), + "Record `" + R->getName() + + "', bit field 'Beads' is too long(maximum: " + + std::to_string(Length) + ")"); + } + + /// Convert to byte array: + /// [dcba] -> [a][b][c][d] + o << "\t{"; + for (unsigned p = 0; p < Parts; ++p) { + // unsigned Num = BI->getNumBits(); + unsigned Right = Size * p; + unsigned Left = Right + Size; + + uint64_t Value = 0; + for (unsigned i = Right; i != Left; ++i) { + unsigned Shift = i % Size; + if (BitInit *B = dyn_cast(BI->getBit(i))) { + Value |= (uint64_t)B->getValue() << (Shift); + } else { + PrintFatalError(R->getLoc(), + "Record `" + R->getName() + "', bit 'Beads[" + + std::to_string(i) + "]' is not defined"); + } + } + + if (p) + o << ','; + o << " 0x"; + o.write_hex(Value); + o << ""; + } + o << " }," << '\t' << "// " << R->getName() << "\n"; + } + o << "\t{ 0x0 }\n };\n"; + + // Emit initial function code + o << " const unsigned opcode = MI.getOpcode();\n" + << " return (uint8_t *)InstBits[opcode];\n" + << "}\n\n"; +} + +} // End anonymous namespace + +namespace llvm { + +void EmitCodeBeads(RecordKeeper &RK, raw_ostream &OS) { + emitSourceFileHeader("Machine Code Beads", OS); + CodeBeadsGen(RK).run(OS); +} + +} // namespace llvm Index: llvm/utils/TableGen/InstrInfoEmitter.cpp =================================================================== --- llvm/utils/TableGen/InstrInfoEmitter.cpp +++ llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -19,6 +19,7 @@ #include "SequenceToOffsetTable.h" #include "TableGenBackends.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" @@ -27,6 +28,7 @@ #include "llvm/TableGen/TableGenBackend.h" #include #include +#include #include #include #include @@ -87,6 +89,13 @@ void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, ArrayRef NumberedInstructions); + void emitLogicalOperandSizeMappings( + raw_ostream &OS, StringRef Namespace, + ArrayRef NumberedInstructions); + void emitLogicalOperandTypeMappings( + raw_ostream &OS, StringRef Namespace, + ArrayRef NumberedInstructions); + // Operand information. void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs); std::vector GetOperandInfo(const CodeGenInstruction &Inst); @@ -433,6 +442,193 @@ OS << "#endif // GET_INSTRINFO_OPERAND_TYPE\n\n"; } +void InstrInfoEmitter::emitLogicalOperandSizeMappings( + raw_ostream &OS, StringRef Namespace, + ArrayRef NumberedInstructions) { + std::map, unsigned> LogicalOpSizeMap; + + std::map> InstMap; + + unsigned LogicalOpListSize = 0; + std::vector LogicalOpList; + for (const auto *Inst : NumberedInstructions) { + if (!Inst->TheDef->getValueAsBit("UseLogicalOperandMappings")) + continue; + + LogicalOpList.clear(); + llvm::transform(Inst->Operands, std::back_inserter(LogicalOpList), + [](const CGIOperandList::OperandInfo &Op) -> unsigned { + auto *MIOI = Op.MIOperandInfo; + if (!MIOI || MIOI->getNumArgs() == 0) + return 1; + return MIOI->getNumArgs(); + }); + if (LogicalOpList.size() > LogicalOpListSize) + LogicalOpListSize = LogicalOpList.size(); + + auto I = LogicalOpSizeMap.find(LogicalOpList); + if (I == LogicalOpSizeMap.end()) { + I = LogicalOpSizeMap.insert({LogicalOpList, LogicalOpSizeMap.size()}) + .first; + } + InstMap[I->second].push_back(Namespace.str() + + "::" + Inst->TheDef->getName().str()); + } + + OS << "#ifdef GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n"; + OS << "#undef GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n"; + OS << "namespace llvm {\n"; + OS << "namespace " << Namespace << " {\n"; + OS << "LLVM_READONLY static unsigned\n"; + OS << "getLogicalOperandSize(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; + if (!InstMap.empty()) { + std::vector *> LogicalOpSizeList( + LogicalOpSizeMap.size()); + for (auto &P : LogicalOpSizeMap) { + LogicalOpSizeList[P.second] = &P.first; + } + OS << " static const unsigned SizeMap[][" << LogicalOpListSize + << "] = {\n"; + for (int r = 0, rs = LogicalOpSizeList.size(); r < rs; ++r) { + auto &Row = *LogicalOpSizeList[r]; + OS << " {"; + int i, s = Row.size(); + for (i = 0; i < s; ++i) { + if (i > 0) + OS << ", "; + OS << Row[i]; + } + for (; i < static_cast(LogicalOpListSize); ++i) { + if (i > 0) + OS << ", "; + OS << "0"; + } + OS << "}"; + if (r != rs - 1) + OS << ","; + OS << "\n"; + } + OS << " };\n"; + + OS << " switch(Opcode) {\n"; + OS << " default: return LogicalOpIdx;\n"; + for (auto &P : InstMap) { + auto OpMapIdx = P.first; + auto &Insts = P.second; + llvm::for_each( + Insts, [&](const std::string &S) { OS << " case " << S << ":\n"; }); + OS << " return SizeMap[" << OpMapIdx << "][LogicalOpIdx];\n"; + } + OS << " }\n"; + } else { + OS << " return LogicalOpIdx;\n"; + } + OS << "}\n"; + + OS << "LLVM_READONLY static inline unsigned\n"; + OS << "getLogicalOperandIdx(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; + OS << " auto S = 0U;\n"; + OS << " for(auto i = 0U; i < LogicalOpIdx; ++i)\n"; + OS << " S += getLogicalOperandSize(Opcode, i);\n"; + OS << " return S;\n"; + OS << "}\n"; + + OS << "} // end namespace " << Namespace << "\n"; + OS << "} // end namespace llvm\n"; + OS << "#endif // GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP\n\n"; +} + +void InstrInfoEmitter::emitLogicalOperandTypeMappings( + raw_ostream &OS, StringRef Namespace, + ArrayRef NumberedInstructions) { + std::map, unsigned> LogicalOpTypeMap; + + std::map> InstMap; + + unsigned OpTypeListSize = 0; + std::vector LogicalOpTypeList; + for (const auto *Inst : NumberedInstructions) { + if (!Inst->TheDef->getValueAsBit("UseLogicalOperandMappings")) + continue; + + LogicalOpTypeList.clear(); + for (const auto &Op : Inst->Operands) { + auto *OpR = Op.Rec; + if ((OpR->isSubClassOf("Operand") || + OpR->isSubClassOf("RegisterOperand") || + OpR->isSubClassOf("RegisterClass")) && + !OpR->isAnonymous()) { + LogicalOpTypeList.push_back(Namespace.str() + + "::OpTypes::" + Op.Rec->getName().str()); + } else { + LogicalOpTypeList.push_back("-1"); + } + } + if (LogicalOpTypeList.size() > OpTypeListSize) + OpTypeListSize = LogicalOpTypeList.size(); + + auto I = LogicalOpTypeMap.find(LogicalOpTypeList); + if (I == LogicalOpTypeMap.end()) { + auto Size = LogicalOpTypeMap.size(); + I = LogicalOpTypeMap.insert({LogicalOpTypeList, Size}).first; + } + InstMap[I->second].push_back(Namespace.str() + + "::" + Inst->TheDef->getName().str()); + } + + OS << "#ifdef GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP\n"; + OS << "#undef GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP\n"; + OS << "namespace llvm {\n"; + OS << "namespace " << Namespace << " {\n"; + OS << "LLVM_READONLY static int\n"; + OS << "getLogicalOperandType(uint16_t Opcode, uint16_t LogicalOpIdx) {\n"; + if (!InstMap.empty()) { + std::vector *> LogicalOpTypeList( + LogicalOpTypeMap.size()); + for (auto &P : LogicalOpTypeMap) { + LogicalOpTypeList[P.second] = &P.first; + } + OS << " static const int TypeMap[][" << OpTypeListSize << "] = {\n"; + for (int r = 0, rs = LogicalOpTypeList.size(); r < rs; ++r) { + auto &Row = *LogicalOpTypeList[r]; + OS << " {"; + int i, s = Row.size(); + for (i = 0; i < s; ++i) { + if (i > 0) + OS << ", "; + OS << Row[i]; + } + for (; i < static_cast(OpTypeListSize); ++i) { + if (i > 0) + OS << ", "; + OS << "-1"; + } + OS << "}"; + if (r != rs - 1) + OS << ","; + OS << "\n"; + } + OS << " };\n"; + + OS << " switch(Opcode) {\n"; + OS << " default: return -1;\n"; + for (auto &P : InstMap) { + auto OpMapIdx = P.first; + auto &Insts = P.second; + llvm::for_each( + Insts, [&](const std::string &S) { OS << " case " << S << ":\n"; }); + OS << " return TypeMap[" << OpMapIdx << "][LogicalOpIdx];\n"; + } + OS << " }\n"; + } else { + OS << " return -1;\n"; + } + OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n"; + OS << "} // end namespace llvm\n"; + OS << "#endif // GET_INSTRINFO_LOGICAL_OPERAND_TYPE_MAP\n\n"; +} + void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS, StringRef TargetName) { RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); @@ -710,6 +906,9 @@ emitOperandTypeMappings(OS, Target, NumberedInstructions); + emitLogicalOperandSizeMappings(OS, TargetName, NumberedInstructions); + emitLogicalOperandTypeMappings(OS, TargetName, NumberedInstructions); + emitMCIIHelperMethods(OS, TargetName); } Index: llvm/utils/TableGen/TableGen.cpp =================================================================== --- llvm/utils/TableGen/TableGen.cpp +++ llvm/utils/TableGen/TableGen.cpp @@ -23,6 +23,7 @@ PrintRecords, DumpJSON, GenEmitter, + GenCodeBeads, GenRegisterInfo, GenInstrInfo, GenInstrDocs, @@ -78,6 +79,8 @@ clEnumValN(DumpJSON, "dump-json", "Dump all records as machine-readable JSON"), clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"), + clEnumValN(GenCodeBeads, "gen-code-beads", + "Generate machine code beads"), clEnumValN(GenRegisterInfo, "gen-register-info", "Generate registers and register classes info"), clEnumValN(GenInstrInfo, "gen-instr-info", @@ -158,6 +161,9 @@ case GenEmitter: EmitCodeEmitter(Records, OS); break; + case GenCodeBeads: + EmitCodeBeads(Records, OS); + break; case GenRegisterInfo: EmitRegisterInfo(Records, OS); break; Index: llvm/utils/TableGen/TableGenBackends.h =================================================================== --- llvm/utils/TableGen/TableGenBackends.h +++ llvm/utils/TableGen/TableGenBackends.h @@ -67,6 +67,7 @@ void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS); void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS); void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS); +void EmitCodeBeads(RecordKeeper &RK, raw_ostream &OS); void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS); void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS); void EmitDisassembler(RecordKeeper &RK, raw_ostream &OS);