mirror of
https://github.com/RPCS3/llvm.git
synced 2026-07-19 23:23:38 -04:00
[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:
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user