[llvm] [TableGen] Split large printInstruction() for NVPTX to avoid compiler limits (PR #218530)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 20:09:17 PDT 2026


kazutakahirata wrote:

Thanks for the update and for making it target-agnostic!

IIUC, you are splitting the large `switch` statement into ~24 smaller `switch` statements, each with at most 500 cases, and using the function-pointer table to select which switch to jump into.  I'm afraid this design is a bit too complicated. Host toolchains generally don't have problems with large constant tables, which simply end up in `.rodata` without causing relocation problems.

What do you think about using a function-pointer table directly across the entire range of `getOpcode()`? We can deduplicate identical operand printing patterns into shared helper functions, which completely eliminates all `switch` statements from the overflow path, eliminates branching at the dispatch site, and removes the need for `PrintInstructionSplitThreshold` in `Target.td`.

Something like this:

```cpp
// Helper function for an exact operand pattern, shared across instructions.
static void printPattern_0(NVPTXInstPrinter *P, const MCInst *MI,
                           uint64_t Address, const MCSubtargetInfo &STI,
                           raw_ostream &O) {
  P->printOperand(MI, 0, STI, O);
  O << ", ";
  P->printOperand(MI, 1, STI, O);
  O << ", ";
  P->printOperand(MI, 2, STI, O);
}

// No-op helper for instructions fully handled by the table-driven logic.
static void printPattern_None(NVPTXInstPrinter *, const MCInst *,
                              uint64_t, const MCSubtargetInfo &,
                              raw_ostream &) {}

// Fallback for invalid or unexpected opcodes (the old default case).
static void printPattern_Unreachable(NVPTXInstPrinter *, const MCInst *,
                                     uint64_t, const MCSubtargetInfo &,
                                     raw_ostream &) {
  llvm_unreachable("Unexpected opcode.");
}

// Function-pointer table covering the entire valid range of getOpcode().
static void (*const NVPTXInstPrinters[])(
    NVPTXInstPrinter *, const MCInst *, uint64_t,
    const MCSubtargetInfo &, raw_ostream &) = {
  &printPattern_0,           // Shared by ADD_rr, SUB_rr, etc.
  &printPattern_None,        // No overflow operands left
  &printPattern_Unreachable, // Invalid opcode
  ...
};

// printInstruction dispatches unconditionally with no branches or switches.
void NVPTXInstPrinter::printInstruction(const MCInst *MI, uint64_t Address,
                                        const MCSubtargetInfo &STI,
                                        raw_ostream &O) {
  ... // Initial tab, mnemonic, and table-driven operand printing

  NVPTXInstPrinters[MI->getOpcode()](this, MI, Address, STI, O);
}
```


https://github.com/llvm/llvm-project/pull/218530


More information about the llvm-commits mailing list