Skip to content

Commit 8380b5c

Browse files
authored
[TableGen][InstrInfo] Cull mapping that have not been enabled/not needed (#126137)
- Detect whether logical operand mapping/named operand mappings have been enabled in a previous pass over instructions and execute the relevant emission code only if those mappings are enabled. - For these mappings, skip the fixed set of predefined instructions as they won't have these mappings enabled. - Emit operand type mappings only for X86 target, as they are only used by X86 and look for X86 specific `X86MemOperand`. - Cleanup `emitOperandTypeMappings` code: remove code to handle empty instruction list and use range for loops.
1 parent 71fcc82 commit 8380b5c

File tree

3 files changed

+107
-84
lines changed

3 files changed

+107
-84
lines changed

llvm/test/TableGen/get-operand-type-no-expand.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ include "llvm/Target/Target.td"
55

66
def archInstrInfo : InstrInfo { }
77

8-
def arch : Target {
8+
def X86 : Target {
99
let InstructionSet = archInstrInfo;
1010
}
1111

@@ -26,7 +26,7 @@ def InstA : Instruction {
2626
let InOperandList = (ins i8complex:$b, i32imm:$c);
2727
field bits<8> Inst;
2828
field bits<8> SoftFail = 0;
29-
let Namespace = "MyNamespace";
29+
let Namespace = "X86";
3030
}
3131

3232
// RUN: llvm-tblgen -gen-instr-info -I %p/../../include %s \

llvm/test/TableGen/get-operand-type.td

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// RUN: llvm-tblgen -gen-instr-info -I %p/../../include %s | FileCheck %s
22

3-
// Check that getOperandType has the expected info in it
3+
// Check that getOperandType has the expected info in it.
44

55
include "llvm/Target/Target.td"
66

77
def archInstrInfo : InstrInfo { }
88

9-
def arch : Target {
9+
def X86 : Target {
1010
let InstructionSet = archInstrInfo;
1111
}
1212

@@ -24,7 +24,7 @@ def InstA : Instruction {
2424
let InOperandList = (ins OpB:$b, i32imm:$c);
2525
field bits<8> Inst;
2626
field bits<8> SoftFail = 0;
27-
let Namespace = "MyNamespace";
27+
let Namespace = "X86";
2828
}
2929

3030
def InstB : Instruction {
@@ -33,7 +33,7 @@ def InstB : Instruction {
3333
let InOperandList = (ins unknown:$x);
3434
field bits<8> Inst;
3535
field bits<8> SoftFail = 0;
36-
let Namespace = "MyNamespace";
36+
let Namespace = "X86";
3737
}
3838

3939
def InstC : Instruction {
@@ -42,12 +42,12 @@ def InstC : Instruction {
4242
let InOperandList = (ins RegOp:$x);
4343
field bits<8> Inst;
4444
field bits<8> SoftFail = 0;
45-
let Namespace = "MyNamespace";
45+
let Namespace = "X86";
4646
}
4747

4848
// CHECK: #ifdef GET_INSTRINFO_OPERAND_TYPE
49-
// CHECK: static const uint{{.*}}_t Offsets[] = {
50-
// CHECK: static const {{.*}} OpcodeOperandTypes[] = {
49+
// CHECK: static constexpr uint{{.*}}_t Offsets[] = {
50+
// CHECK: static constexpr {{.*}} OpcodeOperandTypes[] = {
5151
// CHECK: /* InstA */
5252
// CHECK-NEXT: OpA, OpB, i32imm,
5353
// CHECK-NEXT: /* InstB */

llvm/utils/TableGen/InstrInfoEmitter.cpp

Lines changed: 98 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,11 @@ void InstrInfoEmitter::emitOperandNameMappings(
261261
// Max operand index seen.
262262
unsigned MaxOperandNo = 0;
263263

264-
for (const CodeGenInstruction *Inst : NumberedInstructions) {
264+
// Fixed/Predefined instructions do not have UseNamedOperandTable enabled, so
265+
// we can just skip them.
266+
const unsigned NumFixedInsts = Target.getNumFixedInstructions();
267+
for (const CodeGenInstruction *Inst :
268+
NumberedInstructions.drop_front(NumFixedInsts)) {
265269
if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable"))
266270
continue;
267271
std::map<unsigned, unsigned> OpList;
@@ -335,11 +339,18 @@ void InstrInfoEmitter::emitOperandNameMappings(
335339
/// Generate an enum for all the operand types for this target, under the
336340
/// llvm::TargetNamespace::OpTypes namespace.
337341
/// Operand types are all definitions derived of the Operand Target.td class.
342+
///
338343
void InstrInfoEmitter::emitOperandTypeMappings(
339344
raw_ostream &OS, const CodeGenTarget &Target,
340345
ArrayRef<const CodeGenInstruction *> NumberedInstructions) {
341-
342346
StringRef Namespace = Target.getInstNamespace();
347+
348+
// These generated functions are used only by the X86 target
349+
// (in bolt/lib/Target/X86/X86MCPlusBuilder.cpp). So emit them only
350+
// for X86.
351+
if (Namespace != "X86")
352+
return;
353+
343354
ArrayRef<const Record *> Operands =
344355
Records.getAllDerivedDefinitions("Operand");
345356
ArrayRef<const Record *> RegisterOperands =
@@ -376,73 +387,66 @@ void InstrInfoEmitter::emitOperandTypeMappings(
376387
return NumberedInstructions[I]->TheDef->getName();
377388
};
378389
// TODO: Factor out duplicate operand lists to compress the tables.
379-
if (!NumberedInstructions.empty()) {
380-
std::vector<int> OperandOffsets;
381-
std::vector<const Record *> OperandRecords;
382-
int CurrentOffset = 0;
383-
for (const CodeGenInstruction *Inst : NumberedInstructions) {
384-
OperandOffsets.push_back(CurrentOffset);
385-
for (const auto &Op : Inst->Operands) {
386-
const DagInit *MIOI = Op.MIOperandInfo;
387-
if (!ExpandMIOperandInfo || !MIOI || MIOI->getNumArgs() == 0) {
388-
// Single, anonymous, operand.
389-
OperandRecords.push_back(Op.Rec);
390+
std::vector<size_t> OperandOffsets;
391+
std::vector<const Record *> OperandRecords;
392+
size_t CurrentOffset = 0;
393+
for (const CodeGenInstruction *Inst : NumberedInstructions) {
394+
OperandOffsets.push_back(CurrentOffset);
395+
for (const auto &Op : Inst->Operands) {
396+
const DagInit *MIOI = Op.MIOperandInfo;
397+
if (!ExpandMIOperandInfo || !MIOI || MIOI->getNumArgs() == 0) {
398+
// Single, anonymous, operand.
399+
OperandRecords.push_back(Op.Rec);
400+
++CurrentOffset;
401+
} else {
402+
for (const Init *Arg : MIOI->getArgs()) {
403+
OperandRecords.push_back(cast<DefInit>(Arg)->getDef());
390404
++CurrentOffset;
391-
} else {
392-
for (const Init *Arg : MIOI->getArgs()) {
393-
OperandRecords.push_back(cast<DefInit>(Arg)->getDef());
394-
++CurrentOffset;
395-
}
396405
}
397406
}
398407
}
408+
}
399409

400-
// Emit the table of offsets (indexes) into the operand type table.
401-
// Size the unsigned integer offset to save space.
402-
assert(OperandRecords.size() <= UINT32_MAX &&
403-
"Too many operands for offset table");
404-
OS << " static const " << getMinimalTypeForRange(OperandRecords.size());
405-
OS << " Offsets[] = {\n";
406-
for (int I = 0, E = OperandOffsets.size(); I != E; ++I) {
407-
OS << " /* " << getInstrName(I) << " */\n";
408-
OS << " " << OperandOffsets[I] << ",\n";
409-
}
410-
OS << " };\n";
410+
// Emit the table of offsets (indexes) into the operand type table.
411+
// Size the unsigned integer offset to save space.
412+
assert(OperandRecords.size() <= UINT32_MAX &&
413+
"Too many operands for offset table");
414+
OS << " static constexpr " << getMinimalTypeForRange(OperandRecords.size());
415+
OS << " Offsets[] = {\n";
416+
for (const auto &[Idx, Offset] : enumerate(OperandOffsets))
417+
OS << " " << Offset << ", // " << getInstrName(Idx) << '\n';
418+
OS << " };\n";
411419

412-
// Add an entry for the end so that we don't need to special case it below.
413-
OperandOffsets.push_back(OperandRecords.size());
414-
415-
// Emit the actual operand types in a flat table.
416-
// Size the signed integer operand type to save space.
417-
assert(EnumVal <= INT16_MAX &&
418-
"Too many operand types for operand types table");
419-
OS << "\n using namespace OpTypes;\n";
420-
OS << " static";
421-
OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t");
422-
OS << " OpcodeOperandTypes[] = {\n ";
423-
for (int I = 0, E = OperandRecords.size(), CurOffset = 0; I != E; ++I) {
424-
// We print each Opcode's operands in its own row.
425-
if (I == OperandOffsets[CurOffset]) {
426-
OS << "\n /* " << getInstrName(CurOffset) << " */\n ";
427-
while (OperandOffsets[++CurOffset] == I)
428-
OS << "/* " << getInstrName(CurOffset) << " */\n ";
429-
}
430-
const Record *OpR = OperandRecords[I];
431-
if ((OpR->isSubClassOf("Operand") ||
432-
OpR->isSubClassOf("RegisterOperand") ||
433-
OpR->isSubClassOf("RegisterClass")) &&
434-
!OpR->isAnonymous())
435-
OS << OpR->getName();
436-
else
437-
OS << -1;
438-
OS << ", ";
420+
// Add an entry for the end so that we don't need to special case it below.
421+
OperandOffsets.push_back(OperandRecords.size());
422+
423+
// Emit the actual operand types in a flat table.
424+
// Size the signed integer operand type to save space.
425+
assert(EnumVal <= INT16_MAX &&
426+
"Too many operand types for operand types table");
427+
OS << "\n using namespace OpTypes;\n";
428+
OS << " static";
429+
OS << (EnumVal <= INT8_MAX ? " constexpr int8_t" : " constexpr int16_t");
430+
OS << " OpcodeOperandTypes[] = {";
431+
size_t CurOffset = 0;
432+
for (auto [Idx, OpR] : enumerate(OperandRecords)) {
433+
// We print each Opcode's operands in its own row.
434+
if (Idx == OperandOffsets[CurOffset]) {
435+
OS << "\n /* " << getInstrName(CurOffset) << " */\n ";
436+
while (OperandOffsets[++CurOffset] == Idx)
437+
OS << "/* " << getInstrName(CurOffset) << " */\n ";
439438
}
440-
OS << "\n };\n";
441-
442-
OS << " return OpcodeOperandTypes[Offsets[Opcode] + OpIdx];\n";
443-
} else {
444-
OS << " llvm_unreachable(\"No instructions defined\");\n";
439+
if ((OpR->isSubClassOf("Operand") || OpR->isSubClassOf("RegisterOperand") ||
440+
OpR->isSubClassOf("RegisterClass")) &&
441+
!OpR->isAnonymous())
442+
OS << OpR->getName();
443+
else
444+
OS << -1;
445+
OS << ", ";
445446
}
447+
OS << "\n };\n";
448+
449+
OS << " return OpcodeOperandTypes[Offsets[Opcode] + OpIdx];\n";
446450
OS << "}\n";
447451
OS << "} // end namespace llvm::" << Namespace << "\n";
448452
OS << "#endif // GET_INSTRINFO_OPERAND_TYPE\n\n";
@@ -461,10 +465,10 @@ void InstrInfoEmitter::emitOperandTypeMappings(
461465
SizeToOperandName[Size].push_back(Op->getName());
462466
}
463467
OS << " default: return 0;\n";
464-
for (const auto &KV : SizeToOperandName) {
465-
for (const StringRef &OperandName : KV.second)
468+
for (const auto &[Size, OperandNames] : SizeToOperandName) {
469+
for (const StringRef &OperandName : OperandNames)
466470
OS << " case OpTypes::" << OperandName << ":\n";
467-
OS << " return " << KV.first << ";\n\n";
471+
OS << " return " << Size << ";\n\n";
468472
}
469473
OS << " }\n}\n";
470474
OS << "} // end namespace llvm::" << Namespace << "\n";
@@ -475,12 +479,15 @@ void InstrInfoEmitter::emitLogicalOperandSizeMappings(
475479
raw_ostream &OS, StringRef Namespace,
476480
ArrayRef<const CodeGenInstruction *> NumberedInstructions) {
477481
std::map<std::vector<unsigned>, unsigned> LogicalOpSizeMap;
478-
479482
std::map<unsigned, std::vector<std::string>> InstMap;
480483

481484
size_t LogicalOpListSize = 0U;
482485
std::vector<unsigned> LogicalOpList;
483-
for (const auto *Inst : NumberedInstructions) {
486+
487+
// Fixed/Predefined instructions do not have UseLogicalOperandMappings
488+
// enabled, so we can just skip them.
489+
const unsigned NumFixedInsts = CDP.getTargetInfo().getNumFixedInstructions();
490+
for (const auto *Inst : NumberedInstructions.drop_front(NumFixedInsts)) {
484491
if (!Inst->TheDef->getValueAsBit("UseLogicalOperandMappings"))
485492
continue;
486493

@@ -907,22 +914,34 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
907914
unsigned OperandInfoSize =
908915
CollectOperandInfo(OperandInfoList, OperandInfoMap);
909916

917+
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
918+
Target.getInstructionsByEnumValue();
919+
910920
// Collect all of the instruction's implicit uses and defs.
921+
// Also collect which features are enabled by instructions to control
922+
// emission of various mappings.
923+
924+
bool HasUseLogicalOperandMappings = false;
925+
bool HasUseNamedOperandTable = false;
926+
911927
Timer.startTimer("Collect uses/defs");
912928
std::map<std::vector<const Record *>, unsigned> EmittedLists;
913929
std::vector<std::vector<const Record *>> ImplicitLists;
914930
unsigned ImplicitListSize = 0;
915-
for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
916-
std::vector<const Record *> ImplicitOps = II->ImplicitUses;
917-
llvm::append_range(ImplicitOps, II->ImplicitDefs);
931+
for (const CodeGenInstruction *Inst : NumberedInstructions) {
932+
HasUseLogicalOperandMappings |=
933+
Inst->TheDef->getValueAsBit("UseLogicalOperandMappings");
934+
HasUseNamedOperandTable |=
935+
Inst->TheDef->getValueAsBit("UseNamedOperandTable");
936+
937+
std::vector<const Record *> ImplicitOps = Inst->ImplicitUses;
938+
llvm::append_range(ImplicitOps, Inst->ImplicitDefs);
918939
if (EmittedLists.insert({ImplicitOps, ImplicitListSize}).second) {
919940
ImplicitLists.push_back(ImplicitOps);
920941
ImplicitListSize += ImplicitOps.size();
921942
}
922943
}
923944

924-
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
925-
Target.getInstructionsByEnumValue();
926945
OS << "#if defined(GET_INSTRINFO_MC_DESC) || "
927946
"defined(GET_INSTRINFO_CTOR_DTOR)\n";
928947
OS << "namespace llvm {\n\n";
@@ -1123,14 +1142,18 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
11231142

11241143
OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n";
11251144

1126-
Timer.startTimer("Emit operand name mappings");
1127-
emitOperandNameMappings(OS, Target, NumberedInstructions);
1145+
if (HasUseNamedOperandTable) {
1146+
Timer.startTimer("Emit operand name mappings");
1147+
emitOperandNameMappings(OS, Target, NumberedInstructions);
1148+
}
11281149

11291150
Timer.startTimer("Emit operand type mappings");
11301151
emitOperandTypeMappings(OS, Target, NumberedInstructions);
11311152

1132-
Timer.startTimer("Emit logical operand size mappings");
1133-
emitLogicalOperandSizeMappings(OS, TargetName, NumberedInstructions);
1153+
if (HasUseLogicalOperandMappings) {
1154+
Timer.startTimer("Emit logical operand size mappings");
1155+
emitLogicalOperandSizeMappings(OS, TargetName, NumberedInstructions);
1156+
}
11341157

11351158
Timer.startTimer("Emit logical operand type mappings");
11361159
emitLogicalOperandTypeMappings(OS, TargetName, NumberedInstructions);

0 commit comments

Comments
 (0)