[RFC] Pretty Printing Immediate Arguments in LLVM Intrinsics
This is a follow-up with a more focused scope on the proposal discussed here.
LLVM is seeing an influx of target-specific intrinsics, each tailored to expose hardware specific features. As the target-specific intrinsics are growing in both number and complexity, improving the readability of LLVM IR has become increasingly important. One aspect that hinders the readability is the use of immediate arguments to encode various compile time options like several instruction/operation modifiers. This RFC proposes adding LLVM infrastructure that enables printing self-explanatory inline comments for the immediate arguments, thereby streamlining debugging and developer productivity.
This proposal extends LLVM’s intrinsic framework by adding a new PrettyPrintImmArg<ArgIndex<N>, "functionName"> property to the intrinsic definitions in the TableGen file. This generates automatic mapping between immediate arguments and target-specific print functions. All formatting logic and mappings are resolved during TableGen processing and embedded in the generated implementation (.inc) files. The AsmWriter is enhanced to detect pretty-print enabled intrinsics and call the appropriate print functions during IR emission, inserting human-readable comments before the immediate arguments.
Core Features
- Opt-In Feature: Enabled by the user via explicit command-line flags in llvm-dis (e.g.,
--print-formatted-intrinsics) - Low Overhead: Intrinsics that do not utilize this feature incur only an O(1) cost to verify that the feature is not enabled and do not pay any extra overhead.
- Comment-Only Addition: All enhancements are pure comments with zero semantic impact.
- No Bitcode Impact: Pretty printing impacts only textual IR representation by addition of comments, and none of the pretty print artifacts go into LLVM bitcode.
- Complete Roundtrip Compatibility: Full llvm-as and llvm-dis roundtrip works smoothly (.bc ↔ .ll)
- Full Backward Compatibility: Existing IR, tools, and workflows remain unaffected.
Example
Consider this example of an intrinsic from the tcgen05.mma.* family below to illustrate the feature.
def int_nvvm_tcgen05_mma_tensor : DefaultAttrsIntrinsic<[],
[llvm_ptr_ty, llvm_ptr_ty, llvm_i64_ty, llvm_i32_ty, llvm_i1_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
[IntrWriteMem, IntrArgMemOnly,
ImmArg<ArgIndex<5>>,
ImmArg<ArgIndex<6>>,
ImmArg<ArgIndex<7>>,
PrettyPrintImmArg<ArgIndex<5>, "printTcgen05MMAKind">,
PrettyPrintImmArg<ArgIndex<6>, "printTcgen05CTAGroup">,
PrettyPrintImmArg<ArgIndex<7>, "printTcgen05CollectorUsageOp">]>;
Without pretty printing (by default)
call void @llvm.nvvm.tcgen05.mma.tensor(ptr addrspace(6) %dtmem, ptr addrspace(6) %atensor, i64 %b, i32 %idesc, i1 %enable_inp_d, i32 3, i32 2, i32 3)
call void @llvm.nvvm.tcgen05.mma.tensor(..., i32 0, i32 1, i32 2)
call void @llvm.nvvm.tcgen05.mma.tensor(..., i32 1, i32 1, i32 1)
call void @llvm.nvvm.tcgen05.mma.tensor(..., i32 2, i32 2, i32 0)
With pretty printing (enabled by --print-formatted-intrinsics)
call void @llvm.nvvm.tcgen05.mma.tensor(..., /* kind::i8 */ i32 3, /* cta_group::2 */ i32 2, /* collector::a::use */ i32 3)
call void @llvm.nvvm.tcgen05.mma.tensor(..., /* kind::f16 */ i32 0, /* cta_group::1 */ i32 1, /* collector::a::fill */ i32 2)
call void @llvm.nvvm.tcgen05.mma.tensor(..., /* kind::tf32 */ i32 1, /* cta_group::1 */ i32 1, /* collector::a::lastuse */ i32 1)
call void @llvm.nvvm.tcgen05.mma.tensor(..., /* kind::f8f6f4 */ i32 2, /* cta_group::2 */ i32 2, /* collector::a::discard */ i32 0)
Although this RFC focuses on the pretty-printing of immediate arguments of the intrinsic, further improvements such as the inclusion of argument names can be explored in future work.
For those interested in the implementation details, a draft PR is available here: [LLVM-Tablegen] Pretty Printing Immediate Arguments in LLVM Intrinsics by DharuniRAcharya · Pull Request #162629 · llvm/llvm-project.