[TableGen] Add "getOperandType" to get operand types from opcode/opidx

The InstrInfoEmitter outputs an enum called "OperandType" which gives
numerical IDs to each operand type. This patch makes use of this enum
to define a function called "getOperandType", which allows looking up
the type of an operand given its opcode and operand index.

Patch by Nicolas Guillemot. Thanks!

Differential Revision: https://reviews.llvm.org/D63320

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366274 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Justin Bogner
2019-07-16 22:10:16 +00:00
parent b261aae297
commit 8a6db15ff2
2 changed files with 97 additions and 4 deletions
+40
View File
@@ -0,0 +1,40 @@
// RUN: llvm-tblgen -gen-instr-info -I %p/../../include %s | FileCheck %s
// Check that getOperandType has the expected info in it
include "llvm/Target/Target.td"
def archInstrInfo : InstrInfo { }
def arch : Target {
let InstructionSet = archInstrInfo;
}
def Reg : Register<"reg">;
def RegClass : RegisterClass<"foo", [i32], 0, (add Reg)>;
def OpA : Operand<i32>;
def OpB : Operand<i32>;
def InstA : Instruction {
let Size = 1;
let OutOperandList = (outs OpA:$a);
let InOperandList = (ins OpB:$b, i32imm:$c);
field bits<8> Inst;
field bits<8> SoftFail = 0;
let Namespace = "MyNamespace";
}
def InstB : Instruction {
let Size = 1;
let OutOperandList = (outs i32imm:$d);
let InOperandList = (ins unknown:$x);
field bits<8> Inst;
field bits<8> SoftFail = 0;
let Namespace = "MyNamespace";
}
// CHECK: #ifdef GET_INSTRINFO_OPERAND_TYPE
// CHECK: { OpTypes::OpA, OpTypes::OpB, OpTypes::i32imm, }
// CHECK-NEXT: { OpTypes::i32imm, -1, }
// CHECK: #endif //GET_INSTRINFO_OPERAND_TYPE
+57 -4
View File
@@ -76,7 +76,9 @@ private:
std::map<std::vector<Record*>, unsigned> &EL,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS);
void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target);
void emitOperandTypeMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions);
void initOperandMapData(
ArrayRef<const CodeGenInstruction *> NumberedInstructions,
StringRef Namespace,
@@ -324,8 +326,9 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
/// Generate an enum for all the operand types for this target, under the
/// llvm::TargetNamespace::OpTypes namespace.
/// Operand types are all definitions derived of the Operand Target.td class.
void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,
const CodeGenTarget &Target) {
void InstrInfoEmitter::emitOperandTypeMappings(
raw_ostream &OS, const CodeGenTarget &Target,
ArrayRef<const CodeGenInstruction *> NumberedInstructions) {
StringRef Namespace = Target.getInstNamespace();
std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand");
@@ -349,6 +352,56 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,
OS << "} // end namespace " << Namespace << "\n";
OS << "} // end namespace llvm\n";
OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n";
OS << "#ifdef GET_INSTRINFO_OPERAND_TYPE\n";
OS << "#undef GET_INSTRINFO_OPERAND_TYPE\n";
OS << "namespace llvm {\n";
OS << "namespace " << Namespace << " {\n";
OS << "LLVM_READONLY\n";
OS << "int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n";
if (!NumberedInstructions.empty()) {
OS << " static const std::initializer_list<int> OpcodeOperandTypes[] = "
"{\n";
for (const CodeGenInstruction *Inst : NumberedInstructions) {
OS << " { ";
for (const auto &Op : Inst->Operands) {
// Handle aggregate operands and normal operands the same way by
// expanding either case into a list of operands for this op.
std::vector<CGIOperandList::OperandInfo> OperandList;
const DagInit *MIOI = Op.MIOperandInfo;
if (!MIOI || MIOI->getNumArgs() == 0) {
// Single, anonymous, operand.
OperandList.push_back(Op);
} else {
for (unsigned j = 0, e = Op.MINumOperands; j != e; ++j) {
OperandList.push_back(Op);
auto *OpR = cast<DefInit>(MIOI->getArg(j))->getDef();
OperandList.back().Rec = OpR;
}
}
for (unsigned j = 0, e = OperandList.size(); j != e; ++j) {
Record *OpR = OperandList[j].Rec;
if (OpR->isSubClassOf("Operand") && !OpR->isAnonymous())
OS << "OpTypes::" << OpR->getName();
else
OS << -1;
OS << ", ";
}
}
OS << "},\n";
}
OS << " };\n";
OS << " return OpcodeOperandTypes[Opcode].begin()[OpIdx];\n";
} else {
OS << " llvm_unreachable(\"No instructions defined\");\n";
}
OS << "}\n";
OS << "} // end namespace " << Namespace << "\n";
OS << "} // end namespace llvm\n";
OS << "#endif //GET_INSTRINFO_OPERAND_TYPE\n\n";
}
void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
@@ -560,7 +613,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
emitOperandNameMappings(OS, Target, NumberedInstructions);
emitOperandTypesEnum(OS, Target);
emitOperandTypeMappings(OS, Target, NumberedInstructions);
emitMCIIHelperMethods(OS, TargetName);
}