[llvm] [TableGen] Split large printInstruction() for NVPTX to avoid compiler limits (PR #218530)
Kazu Hirata via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 23 19:54:04 PDT 2026
================
@@ -575,33 +600,125 @@ void AsmWriterEmitter::EmitPrintInstruction(
BitsLeft -= NumBits;
}
- // Okay, delete instructions with no operand info left.
- llvm::erase_if(Instructions,
- [](AsmWriterInst &Inst) { return Inst.Operands.empty(); });
-
- // Because this is a vector, we want to emit from the end. Reverse all of the
- // elements in the vector.
- std::reverse(Instructions.begin(), Instructions.end());
-
- std::vector<InstructionGroup> Groups = groupInstructions(Instructions);
-
// Now that we've emitted all of the operand info that fit into 64 bits, emit
// information for those instructions that are left. This is a less dense
// encoding, but we expect the main 64-bit table to handle the majority of
// instructions.
- if (!Groups.empty()) {
- // Find the opcode # of inline asm.
- O << " switch (MI->getOpcode()) {\n";
- O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
- for (const InstructionGroup &G : Groups)
- emitInstructions(G, O, PassSubtarget);
+ if (!Instructions.empty()) {
+ if (UseFnPtrTable) {
+ // Single unconditional indirect call; the function-pointer table was
+ // emitted above, before printInstruction().
+ EmitOpcodePatternDispatch(O, Target.getName(), ClassName, PassSubtarget);
+ } else {
+ // Because this is a vector, we want to emit from the end. Reverse all
+ // of the elements in the vector.
+ std::reverse(Instructions.begin(), Instructions.end());
- O << " }\n";
+ std::vector<InstructionGroup> Groups = groupInstructions(Instructions);
+
+ O << " switch (MI->getOpcode()) {\n";
+ O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
+ for (const InstructionGroup &G : Groups)
+ emitInstructions(G, O, PassSubtarget);
+
+ O << " }\n";
+ }
}
O << "}\n";
}
+void AsmWriterEmitter::EmitOpcodePatternTable(raw_ostream &O,
+ StringRef TargetName,
+ StringRef ClassName,
+ bool PassSubtarget) {
+ assert(!Instructions.empty() && "caller should have checked HasOverflow");
+
+ // Serialize each instruction's complete operand sequence into a string key.
+ // Instructions with identical keys share one printPattern_N function.
+ // getCode() with Receiver="P->" turns member calls like printOperand(...)
+ // into P->printOperand(...), which is correct for a static free function.
+ using PatternBody = std::vector<std::string>;
+ std::map<PatternBody, unsigned> PatternMap;
+ SmallVector<PatternBody, 64> Patterns;
+
+ // Table: index by CGIIndex, value = pattern index (~0U for non-overflow).
+ std::vector<unsigned> OpcodeToPattern(NumberedInstructions.size(), ~0U);
+
+ for (const AsmWriterInst &AWI : Instructions) {
+ PatternBody Body;
+ for (const AsmWriterOperand &Op : AWI.Operands)
+ Body.push_back(Op.getCode(PassSubtarget, "P->"));
+ auto [It, Inserted] = PatternMap.emplace(Body, Patterns.size());
+ if (Inserted)
+ Patterns.push_back(Body);
+ OpcodeToPattern[AWI.CGIIndex] = It->second;
+ }
+
+ std::string FullClassName = (TargetName + ClassName).str();
+ // Include ClassName in the table name so multiple AsmWriter variants in the
+ // same TU (e.g. AArch64GenAsmWriter.inc + AArch64GenAsmWriter1.inc) don't
+ // produce conflicting variable declarations.
+ std::string PtrTableName = FullClassName + "Printers";
+ std::string ParamList = " " + FullClassName +
+ " *, const MCInst *,\n"
+ " uint64_t," +
+ (PassSubtarget ? " const MCSubtargetInfo &," : "") +
+ " raw_ostream &";
+
+ // printPattern_None: no-op for instructions fully handled by table-driven
+ // path.
+ O << "static void printPattern_None(\n" << ParamList << ") {}\n\n";
+
+ // One printPattern_N per unique operand sequence.
+ for (unsigned PIdx = 0, E = Patterns.size(); PIdx < E; ++PIdx) {
+ O << "static void printPattern_" << PIdx << "(\n"
+ << " " << FullClassName << " *P, const MCInst *MI,\n"
+ << " uint64_t Address,";
+ if (PassSubtarget)
+ O << " const MCSubtargetInfo &STI,";
+ O << " raw_ostream &O) {\n";
+ for (const std::string &Line : Patterns[PIdx])
+ O << " " << Line << "\n";
+ O << "}\n\n";
+ }
+
+ // Function-pointer table indexed by opcode, covering the full opcode range.
+ // Non-overflow opcodes → printPattern_None.
+ // Overflow opcodes → their deduplicated printPattern_N.
+ O << "static void (*const " << PtrTableName << "[])(\n"
+ << ParamList << ") = {\n";
+ for (unsigned i = 0, E = NumberedInstructions.size(); i < E; ++i) {
+ unsigned PIdx = OpcodeToPattern[i];
+ if (PIdx == ~0U)
+ O << " &printPattern_None";
+ else
+ O << " &printPattern_" << PIdx;
+ if (i + 1 < E)
+ O << ",";
+ O << "\t// " << NumberedInstructions[i]->getName() << "\n";
+ }
+ O << "};\n\n";
+
+ LLVM_DEBUG(dbgs() << "[AsmWriter] " << TargetName << ": "
+ << OpcodeInsts.size() << " overflow instructions -> "
----------------
kazutakahirata wrote:
`OpcodeInsts` is still referenced inside `LLVM_DEBUG`, which causes assertion-enabled (`-DLLVM_ENABLE_ASSERTIONS=ON`) CI builds to fail:
```suggestion
<< Instructions.size() << " overflow instructions -> "
```
https://github.com/llvm/llvm-project/pull/218530
More information about the llvm-commits
mailing list