diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp @@ -37,8 +37,6 @@ const MCInstrInfo &MCII; MCContext &Ctx; - mutable unsigned MemOpsEmitted; - public: SystemZMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) : MCII(mcii), Ctx(ctx) { @@ -56,6 +54,8 @@ uint64_t getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getOperandBitOffset(const MCInst &MI, unsigned OpNum, + const MCSubtargetInfo &STI) const; // Called by the TableGen code to get the binary encoding of operand // MO in MI. Fixups is the list of fixups against MI. @@ -67,6 +67,7 @@ // add a fixup for it and return 0. uint64_t getDispOpValue(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI, unsigned OpSize, SystemZ::FixupKind Kind) const; // Called by the TableGen code to get the binary encoding of an address. @@ -144,7 +145,6 @@ SmallVectorImpl &CB, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - MemOpsEmitted = 0; uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); unsigned Size = MCII.get(MI.getOpcode()).getSize(); // Big-endian insertion of Size bytes. @@ -166,21 +166,20 @@ llvm_unreachable("Unexpected operand type!"); } -uint64_t SystemZMCCodeEmitter:: -getDispOpValue(const MCInst &MI, unsigned OpNum, - SmallVectorImpl &Fixups, - SystemZ::FixupKind Kind) const { +uint64_t SystemZMCCodeEmitter::getDispOpValue(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI, + unsigned OpSize, + SystemZ::FixupKind Kind) const { const MCOperand &MO = MI.getOperand(OpNum); - if (MO.isImm()) { - ++MemOpsEmitted; + if (MO.isImm()) return static_cast(MO.getImm()); - } if (MO.isExpr()) { - // All instructions follow the pattern where the first displacement has a - // 2 bytes offset, and the second one 4 bytes. - unsigned ByteOffs = MemOpsEmitted++ == 0 ? 2 : 4; - Fixups.push_back(MCFixup::create(ByteOffs, MO.getExpr(), (MCFixupKind)Kind, - MI.getLoc())); + unsigned MIBitSize = MCII.get(MI.getOpcode()).getSize() * 8; + uint32_t RawBitOffset = getOperandBitOffset(MI, OpNum, STI); + uint32_t BitOffset = MIBitSize - RawBitOffset - OpSize; + Fixups.push_back(MCFixup::create(BitOffset >> 3, MO.getExpr(), + (MCFixupKind)Kind, MI.getLoc())); assert(Fixups.size() <= 2 && "More than two memory operands in MI?"); return 0; } @@ -199,14 +198,16 @@ SystemZMCCodeEmitter::getDisp12Encoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return getDispOpValue(MI, OpNum, Fixups, SystemZ::FixupKind::FK_390_12); + return getDispOpValue(MI, OpNum, Fixups, STI, 12, + SystemZ::FixupKind::FK_390_12); } uint64_t SystemZMCCodeEmitter::getDisp20Encoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return getDispOpValue(MI, OpNum, Fixups, SystemZ::FixupKind::FK_390_20); + return getDispOpValue(MI, OpNum, Fixups, STI, 20, + SystemZ::FixupKind::FK_390_20); } uint64_t @@ -241,6 +242,7 @@ return 0; } +#define GET_OPERAND_BIT_OFFSET #include "SystemZGenMCCodeEmitter.inc" MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII, diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp --- a/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -7,8 +7,18 @@ //===----------------------------------------------------------------------===// // // CodeEmitterGen uses the descriptions of instructions and their fields to -// construct an automated code emitter: a function that, given a MachineInstr, -// returns the (currently, 32-bit unsigned) value of the instruction. +// construct an automated code emitter: a function called +// getBinaryCodeForInstr() that, given a MCInst, returns the value of the +// instruction - either as an uint64_t or as an APInt, depending on the +// maximum bit width of all Inst definitions. +// +// In addition, it generates another function called getOperandBitOffset() +// that, given a MCInst and an operand index, returns the minimum of indices of +// all bits that carry some portion of the respective operand. When the target's +// encodeInstruction() stores the instruction in a little-endian byte order, the +// returned value is the offset of the start of the operand in the encoded +// instruction. Other targets might need to adjust the returned value according +// to their encodeInstruction() implementation. // //===----------------------------------------------------------------------===// @@ -46,16 +56,22 @@ private: int getVariableBit(const std::string &VarName, BitsInit *BI, int bit); - std::string getInstructionCase(Record *R, CodeGenTarget &Target); - std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef, - CodeGenTarget &Target); + std::pair + getInstructionCases(Record *R, CodeGenTarget &Target); + void addInstructionCasesForEncoding(Record *R, Record *EncodingDef, + CodeGenTarget &Target, std::string &Case, + std::string &BitOffsetCase); bool addCodeToMergeInOperand(Record *R, BitsInit *BI, - const std::string &VarName, - std::string &Case, CodeGenTarget &Target); + const std::string &VarName, std::string &Case, + std::string &BitOffsetCase, + CodeGenTarget &Target); void emitInstructionBaseValues( raw_ostream &o, ArrayRef NumberedInstructions, CodeGenTarget &Target, int HwMode = -1); + void + emitCaseMap(raw_ostream &o, + const std::map> &CaseMap); unsigned BitWidth = 0u; bool UseAPInt = false; }; @@ -80,6 +96,7 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, std::string &Case, + std::string &BitOffsetCase, CodeGenTarget &Target) { CodeGenInstruction &CGI = Target.getInstruction(R); @@ -175,6 +192,7 @@ ++numOperandLits; } + unsigned BitOffset = -1; for (; bit >= 0; ) { int varBit = getVariableBit(VarName, BI, bit); @@ -183,7 +201,7 @@ --bit; continue; } - + // Figure out the consecutive range of bits covered by this operand, in // order to generate better encoding code. int beginInstBit = bit; @@ -202,6 +220,7 @@ unsigned loBit = beginVarBit - N + 1; unsigned hiBit = loBit + N; unsigned loInstBit = beginInstBit - N + 1; + BitOffset = loInstBit; if (UseAPInt) { std::string extractStr; if (N >= 64) { @@ -243,49 +262,65 @@ } } } + + if (BitOffset != (unsigned)-1) { + BitOffsetCase += " case " + utostr(OpIdx) + ":\n"; + BitOffsetCase += " // op: " + VarName + "\n"; + BitOffsetCase += " return " + utostr(BitOffset) + ";\n"; + } + return true; } -std::string CodeEmitterGen::getInstructionCase(Record *R, - CodeGenTarget &Target) { - std::string Case; +std::pair +CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) { + std::string Case, BitOffsetCase; + + auto append = [&](const char *S) { + Case += S; + BitOffsetCase += S; + }; + 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"; + append(" switch (HwMode) {\n"); + append(" 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"; + append((" case " + itostr(KV.first) + ": {\n").c_str()); + addInstructionCasesForEncoding(R, KV.second, Target, Case, + BitOffsetCase); + append(" break;\n"); + append(" }\n"); } - Case += " }\n"; - return Case; + append(" }\n"); + return std::make_pair(std::move(Case), std::move(BitOffsetCase)); } } - return getInstructionCaseForEncoding(R, R, Target); + addInstructionCasesForEncoding(R, R, Target, Case, BitOffsetCase); + return std::make_pair(std::move(Case), std::move(BitOffsetCase)); } -std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *EncodingDef, - CodeGenTarget &Target) { - std::string Case; +void CodeEmitterGen::addInstructionCasesForEncoding( + Record *R, Record *EncodingDef, CodeGenTarget &Target, std::string &Case, + std::string &BitOffsetCase) { BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst"); // Loop over all of the fields in the instruction, determining which are the // operands to the instruction. bool Success = true; + BitOffsetCase += " switch (OpNum) {\n"; for (const RecordVal &RV : EncodingDef->getValues()) { // Ignore fixed fields in the record, we're looking for values like: // bits<5> RST = { ?, ?, ?, ?, ? }; if (RV.isNonconcreteOK() || RV.getValue()->isComplete()) continue; - Success &= - addCodeToMergeInOperand(R, BI, std::string(RV.getName()), - Case, Target); + Success &= addCodeToMergeInOperand(R, BI, std::string(RV.getName()), Case, + BitOffsetCase, Target); } + BitOffsetCase += " }\n"; if (!Success) { // Dump the record, so we can see what's going on... @@ -304,8 +339,6 @@ Case += ", STI"; Case += ");\n"; } - - return Case; } static void emitInstBits(raw_ostream &OS, const APInt &Bits) { @@ -356,6 +389,26 @@ o << " UINT64_C(0)\n };\n"; } +void CodeEmitterGen::emitCaseMap( + raw_ostream &o, + const std::map> &CaseMap) { + std::map>::const_iterator IE, EE; + for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { + const std::string &Case = IE->first; + const 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"; + } +} + void CodeEmitterGen::run(raw_ostream &o) { emitSourceFileHeader("Machine Code Emitter", o); @@ -437,6 +490,7 @@ // Map to accumulate all the cases. std::map> CaseMap; + std::map> BitOffsetCaseMap; // Construct all cases statement for each opcode for (Record *R : Insts) { @@ -445,9 +499,11 @@ continue; std::string InstName = (R->getValueAsString("Namespace") + "::" + R->getName()).str(); - std::string Case = getInstructionCase(R, Target); + std::string Case, BitOffsetCase; + std::tie(Case, BitOffsetCase) = getInstructionCases(R, Target); - CaseMap[Case].push_back(std::move(InstName)); + CaseMap[Case].push_back(InstName); + BitOffsetCaseMap[BitOffsetCase].push_back(std::move(InstName)); } // Emit initial function code @@ -470,21 +526,7 @@ } // 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"; - } + emitCaseMap(o, CaseMap); // Default case: unhandled opcode o << " default:\n" @@ -498,6 +540,23 @@ else o << " return Value;\n"; o << "}\n\n"; + + o << "#ifdef GET_OPERAND_BIT_OFFSET\n" + << "#undef GET_OPERAND_BIT_OFFSET\n\n" + << "uint32_t " << Target.getName() + << "MCCodeEmitter::getOperandBitOffset(const MCInst &MI,\n" + << " unsigned OpNum,\n" + << " const MCSubtargetInfo &STI) const {\n" + << " switch (MI.getOpcode()) {\n"; + emitCaseMap(o, BitOffsetCaseMap); + o << " }\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Not supported instr[opcode]: \" << MI << \"[\" << OpNum " + "<< \"]\";\n" + << " report_fatal_error(Msg.str().c_str());\n" + << "}\n\n" + << "#endif // GET_OPERAND_BIT_OFFSET\n\n"; } }