const MCInstrInfo &MCII;
MCContext &Ctx;
- mutable unsigned MemOpsEmitted;
-
public:
SystemZMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
: MCII(mcii), Ctx(ctx) {
uint64_t getBinaryCodeForInstr(const MCInst &MI,
SmallVectorImpl<MCFixup> &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.
// add a fixup for it and return 0.
uint64_t getDispOpValue(const MCInst &MI, unsigned OpNum,
SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI, unsigned OpSize,
SystemZ::FixupKind Kind) const;
// Called by the TableGen code to get the binary encoding of an address.
SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &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.
llvm_unreachable("Unexpected operand type!");
}
-uint64_t SystemZMCCodeEmitter::
-getDispOpValue(const MCInst &MI, unsigned OpNum,
- SmallVectorImpl<MCFixup> &Fixups,
- SystemZ::FixupKind Kind) const {
+uint64_t SystemZMCCodeEmitter::getDispOpValue(const MCInst &MI, unsigned OpNum,
+ SmallVectorImpl<MCFixup> &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<uint64_t>(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;
}
SystemZMCCodeEmitter::getDisp12Encoding(const MCInst &MI, unsigned OpNum,
SmallVectorImpl<MCFixup> &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<MCFixup> &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
return 0;
}
+#define GET_OPERAND_BIT_OFFSET
#include "SystemZGenMCCodeEmitter.inc"
MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
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<std::string, std::string>
+ 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<const CodeGenInstruction *> NumberedInstructions,
CodeGenTarget &Target, int HwMode = -1);
+ void
+ emitCaseMap(raw_ostream &o,
+ const std::map<std::string, std::vector<std::string>> &CaseMap);
unsigned BitWidth = 0u;
bool UseAPInt = false;
};
bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
const std::string &VarName,
std::string &Case,
+ std::string &BitOffsetCase,
CodeGenTarget &Target) {
CodeGenInstruction &CGI = Target.getInstruction(R);
++numOperandLits;
}
+ unsigned BitOffset = -1;
for (; bit >= 0; ) {
int varBit = getVariableBit(VarName, BI, bit);
--bit;
continue;
}
-
+
// Figure out the consecutive range of bits covered by this operand, in
// order to generate better encoding code.
int beginInstBit = bit;
unsigned loBit = beginVarBit - N + 1;
unsigned hiBit = loBit + N;
unsigned loInstBit = beginInstBit - N + 1;
+ BitOffset = loInstBit;
if (UseAPInt) {
std::string extractStr;
if (N >= 64) {
}
}
}
+
+ 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<std::string, std::string>
+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<DefInit>(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...
Case += ", STI";
Case += ");\n";
}
-
- return Case;
}
static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
o << " UINT64_C(0)\n };\n";
}
+void CodeEmitterGen::emitCaseMap(
+ raw_ostream &o,
+ const std::map<std::string, std::vector<std::string>> &CaseMap) {
+ std::map<std::string, std::vector<std::string>>::const_iterator IE, EE;
+ for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
+ const std::string &Case = IE->first;
+ const std::vector<std::string> &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);
// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string>> CaseMap;
+ std::map<std::string, std::vector<std::string>> BitOffsetCaseMap;
// Construct all cases statement for each opcode
for (Record *R : Insts) {
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
}
// Emit each case statement
- std::map<std::string, std::vector<std::string>>::iterator IE, EE;
- for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
- const std::string &Case = IE->first;
- std::vector<std::string> &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"
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";
}
}