--- /dev/null
+// 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
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,
/// 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");
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,
emitOperandNameMappings(OS, Target, NumberedInstructions);
- emitOperandTypesEnum(OS, Target);
+ emitOperandTypeMappings(OS, Target, NumberedInstructions);
emitMCIIHelperMethods(OS, TargetName);
}