Index: llvm/include/llvm/Target/Target.td =================================================================== --- llvm/include/llvm/Target/Target.td +++ llvm/include/llvm/Target/Target.td @@ -748,6 +748,25 @@ /// of operands. def variable_ops; +/// variable-length instruction utilities. +/// The `seq` operator should be used like this: +/// (seq 0b0110, 0b1101) +/// Which described an 8-bit instruciton encoding 0b11010110. The arguments +/// can either be bits, another DAG with `seq`, or a DAG with `operand`. +/// In addition, we can use `$dec` on `seq` to describe an encoding that is +/// constructed from DAG arguments in reversed ordering. For instance: +/// (seq:$dec 0b0110, 0b1101) +/// This results in an encoding of 0b01101101 rather than 0b11010110 we saw +/// previously. +def seq; +/// The `operand` operator should be used like this: +/// (operand "$src", 4) +/// Which represents a 4-bit encoding for an instruction operand named `$src`. +/// Alternatively, we can use only part of the instruction operand's encoding: +/// (operand "$src", 9, 6) +/// This DAG represents bit 6 to 9 (total of 4 bits) in the encoding of operand `$src`. +/// Note that in this scheme, the second argument should always be the high bit. +def operand; /// PointerLikeRegClass - Values that are designed to have pointer width are /// derived from this. TableGen treats the register class as having a symbolic Index: llvm/test/TableGen/VarLenEncoder.td =================================================================== --- /dev/null +++ llvm/test/TableGen/VarLenEncoder.td @@ -0,0 +1,91 @@ +// RUN: llvm-tblgen -gen-emitter -I %p/../../include %s | FileCheck %s + +// Check if VarLenCodeEmitterGen works correctly. + +include "llvm/Target/Target.td" + +def ArchInstrInfo : InstrInfo { } + +def Arch : Target { + let InstructionSet = ArchInstrInfo; +} + +def Reg : Register<"reg">; + +def RegClass : RegisterClass<"foo", [i64], 0, (add Reg)>; + +def GR64 : RegisterOperand; + +class MyMemOperand : Operand { + let MIOperandInfo = sub_ops; + dag Base; + dag Extension; +} + +class MyVarInst : Instruction { + dag Inst; + + let OutOperandList = (outs GR64:$dst); + let InOperandList = (ins memory_op:$src); + + // Testing `seq` and `seq:$dec` + let Inst = (seq + (seq:$dec 0b10110111, memory_op.Base), + memory_op.Extension, + // Testing operand referencing. + (operand "$dst", 4), + // Testing operand referencing with a certain bit range. + (operand "$dst", 3, 1) + ); +} + +class MemOp16 : MyMemOperand<(ops GR64:$reg, i16imm:$offset)> { + // Testing sub-operand referencing. + let Base = (operand "$"#op_name#".reg", 8); + let Extension = (operand "$"#op_name#".offset", 16); +} + +class MemOp32 : MyMemOperand<(ops GR64:$reg, i32imm:$offset)> { + let Base = (operand "$"#op_name#".reg", 8); + // Testing variable-length instruction encoding. + let Extension = (operand "$"#op_name#".offset", 32); +} + +def FOO16 : MyVarInst>; +def FOO32 : MyVarInst>; + +// The fixed bits part +// CHECK: APInt(39, UINT64_C(46848)), // FOO16 +// CHECK: APInt(55, UINT64_C(46848)), // FOO32 + +// CHECK-LABEL: case ::FOO16: { +// CHECK: if (Scratch.getBitWidth() < 39) +// CHECK-NEXT: Scratch = Scratch.zext(39); +// src.reg +// CHECK: getMachineOpValue(MI, MI.getOperand(1), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 0); +// src.offset +// CHECK: getMachineOpValue(MI, MI.getOperand(2), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(16, 0), 16); +// 1st dst +// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 32); +// 2nd dst +// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 36); + +// CHECK-LABEL: case ::FOO32: { +// CHECK: if (Scratch.getBitWidth() < 55) +// CHECK-NEXT: Scratch = Scratch.zext(55); +// src.reg +// CHECK: getMachineOpValue(MI, MI.getOperand(1), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 0); +// src.offset +// CHECK: getMachineOpValue(MI, MI.getOperand(2), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(32, 0), 16); +// 1st dst +// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 48); +// 2nd dst +// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 52); Index: llvm/utils/TableGen/CMakeLists.txt =================================================================== --- llvm/utils/TableGen/CMakeLists.txt +++ llvm/utils/TableGen/CMakeLists.txt @@ -49,6 +49,7 @@ SubtargetFeatureInfo.cpp TableGen.cpp Types.cpp + VarLenCodeEmitterGen.cpp X86DisassemblerTables.cpp X86EVEX2VEXTablesEmitter.cpp X86FoldTablesEmitter.cpp Index: llvm/utils/TableGen/CodeEmitterGen.cpp =================================================================== --- llvm/utils/TableGen/CodeEmitterGen.cpp +++ llvm/utils/TableGen/CodeEmitterGen.cpp @@ -16,6 +16,7 @@ #include "CodeGenTarget.h" #include "SubtargetFeatureInfo.h" #include "Types.h" +#include "VarLenCodeEmitterGen.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" @@ -396,132 +397,140 @@ ArrayRef NumberedInstructions = Target.getInstructionsByEnumValue(); - const CodeGenHwModes &HWM = Target.getHwModes(); - // The set of HwModes used by instruction encodings. - std::set HwModes; - BitWidth = 0; - for (const CodeGenInstruction *CGI : NumberedInstructions) { - Record *R = CGI->TheDef; - if (R->getValueAsString("Namespace") == "TargetOpcode" || - R->getValueAsBit("isPseudo")) - continue; + if (any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) { + Record *R = CGI->TheDef; + return R->getValue("Inst") && isa(R->getValueInit("Inst")); + })) + VarLenCodeEmitterGen(Records).run(o); + else { + const CodeGenHwModes &HWM = Target.getHwModes(); + // The set of HwModes used by instruction encodings. + std::set HwModes; + BitWidth = 0; + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; - if (const RecordVal *RV = R->getValue("EncodingInfos")) { - if (DefInit *DI = dyn_cast_or_null(RV->getValue())) { - EncodingInfoByHwMode EBM(DI->getDef(), HWM); - for (auto &KV : EBM) { - BitsInit *BI = KV.second->getValueAsBitsInit("Inst"); - BitWidth = std::max(BitWidth, BI->getNumBits()); - HwModes.insert(KV.first); + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (DefInit *DI = dyn_cast_or_null(RV->getValue())) { + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + for (auto &KV : EBM) { + BitsInit *BI = KV.second->getValueAsBitsInit("Inst"); + BitWidth = std::max(BitWidth, BI->getNumBits()); + HwModes.insert(KV.first); + } + continue; } - continue; } + BitsInit *BI = R->getValueAsBitsInit("Inst"); + BitWidth = std::max(BitWidth, BI->getNumBits()); } - BitsInit *BI = R->getValueAsBitsInit("Inst"); - BitWidth = std::max(BitWidth, BI->getNumBits()); - } - UseAPInt = BitWidth > 64; - - // Emit function declaration - if (UseAPInt) { - o << "void " << Target.getName() - << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" - << " SmallVectorImpl &Fixups,\n" - << " APInt &Inst,\n" - << " APInt &Scratch,\n" - << " const MCSubtargetInfo &STI) const {\n"; - } else { - o << "uint64_t " << Target.getName(); - o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" - << " SmallVectorImpl &Fixups,\n" - << " const MCSubtargetInfo &STI) const {\n"; - } - - // Emit instruction base values - if (HwModes.empty()) { - emitInstructionBaseValues(o, NumberedInstructions, Target, -1); - } else { - for (unsigned HwMode : HwModes) - emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode); - } + UseAPInt = BitWidth > 64; - if (!HwModes.empty()) { - o << " const uint64_t *InstBits;\n"; - o << " unsigned HwMode = STI.getHwMode();\n"; - o << " switch (HwMode) {\n"; - o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n"; - for (unsigned I : HwModes) { - o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name - << "; break;\n"; + // Emit function declaration + if (UseAPInt) { + o << "void " << Target.getName() + << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl &Fixups,\n" + << " APInt &Inst,\n" + << " APInt &Scratch,\n" + << " const MCSubtargetInfo &STI) const {\n"; + } else { + o << "uint64_t " << Target.getName(); + o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl &Fixups,\n" + << " const MCSubtargetInfo &STI) const {\n"; } - o << " };\n"; - } - // Map to accumulate all the cases. - std::map> CaseMap; + // Emit instruction base values + if (HwModes.empty()) { + emitInstructionBaseValues(o, NumberedInstructions, Target, -1); + } else { + for (unsigned HwMode : HwModes) + emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode); + } - // Construct all cases statement for each opcode - for (Record *R : Insts) { - if (R->getValueAsString("Namespace") == "TargetOpcode" || - R->getValueAsBit("isPseudo")) - continue; - std::string InstName = - (R->getValueAsString("Namespace") + "::" + R->getName()).str(); - std::string Case = getInstructionCase(R, Target); + if (!HwModes.empty()) { + o << " const uint64_t *InstBits;\n"; + o << " unsigned HwMode = STI.getHwMode();\n"; + o << " switch (HwMode) {\n"; + o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n"; + for (unsigned I : HwModes) { + o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name + << "; break;\n"; + } + o << " };\n"; + } - CaseMap[Case].push_back(std::move(InstName)); - } + // Map to accumulate all the cases. + std::map> CaseMap; - // Emit initial function code - if (UseAPInt) { - int NumWords = APInt::getNumWords(BitWidth); - int NumBytes = (BitWidth + 7) / 8; - o << " const unsigned opcode = MI.getOpcode();\n" - << " if (Inst.getBitWidth() != " << BitWidth << ")\n" - << " Inst = Inst.zext(" << BitWidth << ");\n" - << " if (Scratch.getBitWidth() != " << BitWidth << ")\n" - << " Scratch = Scratch.zext(" << BitWidth << ");\n" - << " LoadIntFromMemory(Inst, (const uint8_t *)&InstBits[opcode * " - << NumWords << "], " << NumBytes << ");\n" - << " APInt &Value = Inst;\n" - << " APInt &op = Scratch;\n" - << " switch (opcode) {\n"; - } else { - o << " const unsigned opcode = MI.getOpcode();\n" - << " uint64_t Value = InstBits[opcode];\n" - << " uint64_t op = 0;\n" - << " (void)op; // suppress warning\n" - << " switch (opcode) {\n"; - } + // Construct all cases statement for each opcode + for (Record *R : Insts) { + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; + std::string InstName = + (R->getValueAsString("Namespace") + "::" + R->getName()).str(); + std::string Case = getInstructionCase(R, Target); + + CaseMap[Case].push_back(std::move(InstName)); + } - // Emit each case statement - std::map>::iterator IE, EE; - for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { - const std::string &Case = IE->first; - std::vector &InstList = IE->second; + // Emit initial function code + if (UseAPInt) { + int NumWords = APInt::getNumWords(BitWidth); + int NumBytes = (BitWidth + 7) / 8; + o << " const unsigned opcode = MI.getOpcode();\n" + << " if (Inst.getBitWidth() != " << BitWidth << ")\n" + << " Inst = Inst.zext(" << BitWidth << ");\n" + << " if (Scratch.getBitWidth() != " << BitWidth << ")\n" + << " Scratch = Scratch.zext(" << BitWidth << ");\n" + << " LoadIntFromMemory(Inst, (const uint8_t *)&InstBits[opcode * " + << NumWords << "], " << NumBytes << ");\n" + << " APInt &Value = Inst;\n" + << " APInt &op = Scratch;\n" + << " switch (opcode) {\n"; + } else { + o << " const unsigned opcode = MI.getOpcode();\n" + << " uint64_t Value = InstBits[opcode];\n" + << " uint64_t op = 0;\n" + << " (void)op; // suppress warning\n" + << " switch (opcode) {\n"; + } - for (int i = 0, N = InstList.size(); i < N; i++) { - if (i) o << "\n"; - o << " case " << InstList[i] << ":"; + // Emit each case statement + std::map>::iterator IE, EE; + for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { + const std::string &Case = IE->first; + std::vector &InstList = IE->second; + + for (int i = 0, N = InstList.size(); i < N; i++) { + if (i) + o << "\n"; + o << " case " << InstList[i] << ":"; + } + o << " {\n"; + o << Case; + o << " break;\n" + << " }\n"; } - o << " {\n"; - o << Case; - o << " break;\n" - << " }\n"; - } - // Default case: unhandled opcode - o << " default:\n" - << " std::string msg;\n" - << " raw_string_ostream Msg(msg);\n" - << " Msg << \"Not supported instr: \" << MI;\n" - << " report_fatal_error(Msg.str().c_str());\n" - << " }\n"; - if (UseAPInt) - o << " Inst = Value;\n"; - else - o << " return Value;\n"; - o << "}\n\n"; + // Default case: unhandled opcode + o << " default:\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Not supported instr: \" << MI;\n" + << " report_fatal_error(Msg.str().c_str());\n" + << " }\n"; + if (UseAPInt) + o << " Inst = Value;\n"; + else + o << " return Value;\n"; + o << "}\n\n"; + } const auto &All = SubtargetFeatureInfo::getAll(Records); std::map SubtargetFeatures; Index: llvm/utils/TableGen/VarLenCodeEmitterGen.h =================================================================== --- /dev/null +++ llvm/utils/TableGen/VarLenCodeEmitterGen.h @@ -0,0 +1,57 @@ +#ifndef LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H +#define LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Record.h" + +namespace llvm { +// Forward declarations +class CodeGenTarget; +class CodeGenInstruction; + +class VarLenCodeEmitterGen { + RecordKeeper &Records; + + class VarLenInst { + size_t NumBits; + + // {Number of bits, Value} + SmallVector, 4> Segments; + + void buildRec(const DagInit *DI); + + public: + VarLenInst() : NumBits(0U) {} + + explicit VarLenInst(const DagInit *DI); + + /// Number of bits + size_t size() const { return NumBits; } + + using const_iterator = decltype(Segments)::const_iterator; + + const_iterator begin() const { return Segments.begin(); } + const_iterator end() const { return Segments.end(); } + size_t getNumSegments() const { return Segments.size(); } + }; + + DenseMap VarLenInsts; + + // Emit based values (i.e. fixed bits in the encoded instructions) + void emitInstructionBaseValues( + raw_ostream &OS, + ArrayRef NumberedInstructions, + CodeGenTarget &Target, int HwMode = -1); + + std::string getInstructionCase(Record *R, CodeGenTarget &Target); + std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef, + CodeGenTarget &Target); + +public: + explicit VarLenCodeEmitterGen(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); +}; +} // end namespace llvm +#endif Index: llvm/utils/TableGen/VarLenCodeEmitterGen.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -0,0 +1,335 @@ +#include "VarLenCodeEmitterGen.h" +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "SubtargetFeatureInfo.h" +#include "llvm/TableGen/Error.h" + +using namespace llvm; + +VarLenCodeEmitterGen::VarLenInst::VarLenInst(const DagInit *DI) : NumBits(0U) { + buildRec(DI); + for (const auto &S : Segments) + NumBits += S.first; +} + +void VarLenCodeEmitterGen::VarLenInst::buildRec(const DagInit *DI) { + auto Op = DI->getOperator()->getAsString(); + + if (Op == "seq") { + bool Reverse = DI->getNameStr() == "dec"; + int i = Reverse ? DI->getNumArgs() - 1 : 0, + e = Reverse ? -1 : DI->getNumArgs(), s = Reverse ? -1 : 1; + for (; i != e; i += s) { + const Init *Arg = DI->getArg(i); + if (const auto *BI = dyn_cast(Arg)) { + if (!BI->isComplete()) + PrintFatalError("Expecting complete bits init in seq"); + Segments.push_back({BI->getNumBits(), BI}); + } else if (const auto *BI = dyn_cast(Arg)) { + if (!BI->isConcrete()) + PrintFatalError("Expecting concrete bit init in seq"); + Segments.push_back({1, BI}); + } else if (const auto *SubDI = dyn_cast(Arg)) + buildRec(SubDI); + else + PrintFatalError("Unrecognized type of argument in seq: " + + Arg->getAsString()); + } + } else if (Op == "operand") { + // There are two formats for `operand` + // 1. (operand , <# of bits>) + // 2. (operand , , ) + if (DI->getNumArgs() < 2) + PrintFatalError("Expecting at least 2 arguments for operand"); + const Init *OperandName = DI->getArg(0), *HiBit = DI->getArg(1), + *LoBit = DI->getNumArgs() >= 3 ? DI->getArg(2) : nullptr; + if (!isa(OperandName) || !isa(HiBit) || + (LoBit && !isa(LoBit))) + PrintFatalError("Invalid format for operand"); + auto HiBitVal = cast(HiBit)->getValue(), + LoBitVal = LoBit ? cast(LoBit)->getValue() : 0; + if (HiBitVal < 0 || LoBitVal < 0 || HiBitVal <= LoBitVal) + PrintFatalError("Invalid bit range. Hi: " + std::to_string(HiBitVal) + + ", Lo: " + std::to_string(LoBitVal)); + unsigned NumBitsVal = static_cast(HiBitVal - LoBitVal); + if (LoBit) { + // (operand , , ) + ++NumBitsVal; + Segments.push_back({NumBitsVal, DI}); + } else { + // (operand , <# of bits>) + Segments.push_back({NumBitsVal, OperandName}); + } + } +} + +void VarLenCodeEmitterGen::run(raw_ostream &OS) { + CodeGenTarget Target(Records); + auto Insts = Records.getAllDerivedDefinitions("Instruction"); + + auto NumberedInstructions = Target.getInstructionsByEnumValue(); + const CodeGenHwModes &HWM = Target.getHwModes(); + + // The set of HwModes used by instruction encodings. + std::set HwModes; + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + + // Create the corresponding VarLenInst instance. + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; + + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (DefInit *DI = dyn_cast_or_null(RV->getValue())) { + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + for (auto &KV : EBM) { + HwModes.insert(KV.first); + Record *EncodingDef = KV.second; + auto *DI = EncodingDef->getValueAsDag("Inst"); + VarLenInsts.insert({EncodingDef, VarLenInst(DI)}); + } + continue; + } + } + auto *DI = R->getValueAsDag("Inst"); + VarLenInsts.insert({R, VarLenInst(DI)}); + } + + // Emit function declaration + OS << "void " << Target.getName() + << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl &Fixups,\n" + << " APInt &Inst,\n" + << " APInt &Scratch,\n" + << " const MCSubtargetInfo &STI) const {\n"; + + // Emit instruction base values + if (HwModes.empty()) { + emitInstructionBaseValues(OS, NumberedInstructions, Target, -1); + } else { + for (unsigned HwMode : HwModes) + emitInstructionBaseValues(OS, NumberedInstructions, Target, (int)HwMode); + } + + if (!HwModes.empty()) { + OS << " const uint64_t *InstBits;\n"; + OS << " unsigned HwMode = STI.getHwMode();\n"; + OS << " switch (HwMode) {\n"; + OS << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n"; + for (unsigned I : HwModes) { + OS << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name + << "; break;\n"; + } + OS << " };\n"; + } + + // Map to accumulate all the cases. + std::map> CaseMap; + + // Construct all cases statement for each opcode + for (Record *R : Insts) { + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) + continue; + std::string InstName = + (R->getValueAsString("Namespace") + "::" + R->getName()).str(); + std::string Case = getInstructionCase(R, Target); + + CaseMap[Case].push_back(std::move(InstName)); + } + + // Emit initial function code + OS << " const unsigned opcode = MI.getOpcode();\n" + << " switch (opcode) {\n"; + + // Emit each case statement + std::map>::iterator IE, EE; + for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { + const std::string &Case = IE->first; + std::vector &InstList = IE->second; + + for (int i = 0, N = InstList.size(); i < N; i++) { + if (i) + OS << "\n"; + OS << " case " << InstList[i] << ":"; + } + OS << " {\n"; + OS << Case; + OS << " break;\n" + << " }\n"; + } + // Default case: unhandled opcode + OS << " default:\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Not supported instr: \" << MI;\n" + << " report_fatal_error(Msg.str().c_str());\n" + << " }\n"; + OS << "}\n\n"; +} + +static void emitInstBits(raw_ostream &OS, const APInt &Bits) { + if (!Bits.getNumWords()) { + // Use factory method to avoid ambiguous usages of ctors. + OS << "APInt::getZeroWidth()"; + return; + } + + OS << "APInt(" << Bits.getBitWidth() << ", "; + // Only emit braces if it's more than one word. + if (Bits.getNumWords() > 1) + OS << "{"; + + for (unsigned I = 0; I < Bits.getNumWords(); ++I) + OS << ((I > 0) ? ", " : "") << "UINT64_C(" << utostr(Bits.getRawData()[I]) + << ")"; + + if (Bits.getNumWords() > 1) + OS << "}"; + OS << ")"; +} + +void VarLenCodeEmitterGen::emitInstructionBaseValues( + raw_ostream &OS, ArrayRef NumberedInstructions, + CodeGenTarget &Target, int HwMode) { + const CodeGenHwModes &HWM = Target.getHwModes(); + if (HwMode == -1) + OS << " static const APInt InstBits[] = {\n"; + else + OS << " static const APInt InstBits_" << HWM.getMode(HwMode).Name + << "[] = {\n"; + + for (const CodeGenInstruction *CGI : NumberedInstructions) { + Record *R = CGI->TheDef; + + if (R->getValueAsString("Namespace") == "TargetOpcode" || + R->getValueAsBit("isPseudo")) { + OS.indent(4) << "APInt::getZeroWidth(),\n"; + continue; + } + + Record *EncodingDef = R; + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (auto *DI = dyn_cast_or_null(RV->getValue())) { + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + if (EBM.hasMode(HwMode)) + EncodingDef = EBM.get(HwMode); + } + } + + if (!VarLenInsts.count(EncodingDef)) + PrintFatalError(EncodingDef, "VarLenInst not found for this record"); + const VarLenInst &VLI = VarLenInsts[EncodingDef]; + + unsigned i = 0U, BitWidth = VLI.size(); + + // Start by filling in fixed values. + APInt Value(BitWidth, 0); + auto SI = VLI.begin(), SE = VLI.end(); + // Scan through all the segments that have fixed-bits values. + while (i < BitWidth && SI != SE) { + unsigned SegmentNumBits = SI->first; + if (const auto *BI = dyn_cast(SI->second)) { + for (unsigned Idx = 0U; Idx != SegmentNumBits; ++Idx) { + auto *B = cast(BI->getBit(Idx)); + Value |= APInt(BitWidth, (uint64_t)B->getValue()) << (i + Idx); + } + } + if (const auto *BI = dyn_cast(SI->second)) + Value.setBitVal(i, BI->getValue()); + + i += SegmentNumBits; + ++SI; + } + OS << " "; + emitInstBits(OS, Value); + OS << "," << '\t' << "// " << R->getName() << "\n"; + } + OS.indent(4) << "APInt::getZeroWidth()\n };\n"; +} + +std::string VarLenCodeEmitterGen::getInstructionCase(Record *R, + CodeGenTarget &Target) { + std::string Case; + if (const RecordVal *RV = R->getValue("EncodingInfos")) { + if (auto *DI = dyn_cast_or_null(RV->getValue())) { + const CodeGenHwModes &HWM = Target.getHwModes(); + EncodingInfoByHwMode EBM(DI->getDef(), HWM); + Case += " switch (HwMode) {\n"; + Case += " default: llvm_unreachable(\"Unhandled HwMode\");\n"; + for (auto &KV : EBM) { + Case += " case " + itostr(KV.first) + ": {\n"; + Case += getInstructionCaseForEncoding(R, KV.second, Target); + Case += " break;\n"; + Case += " }\n"; + } + Case += " }\n"; + return Case; + } + } + return getInstructionCaseForEncoding(R, R, Target); +} + +std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding( + Record *R, Record *EncodingDef, CodeGenTarget &Target) { + if (!VarLenInsts.count(EncodingDef)) + PrintFatalError(EncodingDef, "Parsed encoding record not found"); + const VarLenInst &VLI = VarLenInsts[EncodingDef]; + size_t BitWidth = VLI.size(); + + CodeGenInstruction &CGI = Target.getInstruction(R); + + std::string Case; + raw_string_ostream SS(Case); + // Resize the scratch buffer. + if (BitWidth) { + SS.indent(6) << "if (Scratch.getBitWidth() < " << BitWidth << ")\n"; + SS.indent(6) << " Scratch = Scratch.zext(" << BitWidth << ");\n"; + } + // Populate based value. + SS.indent(6) << "Inst = InstBits[opcode];\n"; + + // Process each segment in VLI. + size_t Offset = 0U; + for (const auto &Pair : VLI) { + unsigned NumBits = Pair.first; + const Init *Val = Pair.second; + // If it's a StringInit or DagInit, it's a reference to an operand. + if (isa(Val) || isa(Val)) { + StringRef OperandName; + unsigned LoBit = 0U; + if (const auto *SV = dyn_cast(Val)) + OperandName = SV->getValue(); + else { + // (operand , , ) + const auto *DV = cast(Val); + OperandName = cast(DV->getArg(0))->getValue(); + LoBit = static_cast(cast(DV->getArg(2))->getValue()); + } + + auto OpIdx = CGI.Operands.ParseOperandName(OperandName); + unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx); + StringRef EncoderMethodName = "getMachineOpValue"; + auto &CustomEncoder = CGI.Operands[OpIdx.first].EncoderMethodName; + if (!CustomEncoder.empty()) + EncoderMethodName = CustomEncoder; + + SS.indent(6) << "Scratch.clearAllBits();\n"; + SS.indent(6) << "// op: " << OperandName.drop_front(1) << "\n"; + SS.indent(6) << EncoderMethodName << "(MI, MI.getOperand(" + << utostr(FlatOpIdx) << "), Scratch, Fixups, STI);\n"; + std::string ExtractStr = + "Scratch.extractBits(" + utostr(NumBits) + ", " + utostr(LoBit) + ")"; + SS.indent(6) << "Inst.insertBits(" << ExtractStr << ", " << Offset + << ");\n"; + } + Offset += NumBits; + } + + StringRef PostEmitter = R->getValueAsString("PostEncoderMethod"); + if (!PostEmitter.empty()) + SS.indent(6) << "Inst = " << PostEmitter << "(MI, Inst, STI);\n"; + + return std::move(SS.str()); +}