Skip to content

Commit c4caeb3

Browse files
[NVVM] Pretty Printing Immediate Arguments in LLVM Intrinsics
This patch adds LLVM infrastructure to support pretty printing of immediate arguments of the intrinsics. The motivation is to increase the readability of LLVM intrinsics and facilitate easy modifications and debugging of LLVM IR. This adds a property PrettyPrintImmArg<ArgIndex, "functionName"> to the intrinsic ImmArgs that enables printing self-explanatory inline comment for the immediate arguments. The addition of pretty print support can provide a simple, low-overhead feature that enhances usability of LLVM intrinsics without disrupting existing workflows. Signed-off-by: Dharuni R Acharya <[email protected]>
1 parent 40ea56f commit c4caeb3

File tree

13 files changed

+297
-21
lines changed

13 files changed

+297
-21
lines changed

llvm/include/llvm/IR/Function.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,8 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
929929
/// Print the function to an output stream with an optional
930930
/// AssemblyAnnotationWriter.
931931
void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW = nullptr,
932-
bool ShouldPreserveUseListOrder = false,
933-
bool IsForDebug = false) const;
932+
bool ShouldPreserveUseListOrder = false, bool IsForDebug = false,
933+
bool PrettyPrintIntrinsicArgs = false) const;
934934

935935
/// viewCFG - This function is meant for use from the debugger. You can just
936936
/// say 'call F->viewCFG()' and a ghostview window should pop up from the

llvm/include/llvm/IR/Intrinsics.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class LLVMContext;
3030
class Module;
3131
class AttributeList;
3232
class AttributeSet;
33+
class raw_ostream;
34+
class Constant;
3335

3436
/// This namespace contains an enum with a value for every intrinsic/builtin
3537
/// function known by LLVM. The enum values are returned by
@@ -81,6 +83,9 @@ namespace Intrinsic {
8183
/// Returns true if the intrinsic can be overloaded.
8284
LLVM_ABI bool isOverloaded(ID id);
8385

86+
/// Returns true if the intrinsic has pretty printed immediate arguments.
87+
LLVM_ABI bool hasPrettyPrintedArgs(ID id);
88+
8489
/// isTargetIntrinsic - Returns true if IID is an intrinsic specific to a
8590
/// certain target. If it is a generic intrinsic false is returned.
8691
LLVM_ABI bool isTargetIntrinsic(ID IID);
@@ -284,6 +289,9 @@ namespace Intrinsic {
284289
/// N.
285290
LLVM_ABI Intrinsic::ID getDeinterleaveIntrinsicID(unsigned Factor);
286291

292+
LLVM_ABI void printImmArg(ID IID, unsigned ArgIdx, raw_ostream &OS,
293+
const Constant *ImmArgVal);
294+
287295
} // namespace Intrinsic
288296

289297
} // namespace llvm

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ class NoUndef<AttrIndex idx> : IntrinsicProperty {
8787
int ArgNo = idx.Value;
8888
}
8989

90+
// PrettyPrintImmArg - The specified immediate argument has a custom pretty-print
91+
// function for diagnostic output.
92+
class PrettyPrintImmArg<AttrIndex idx, string funcname> : IntrinsicProperty {
93+
int ArgNo = idx.Value;
94+
string FunctionName = funcname;
95+
}
96+
9097
// NonNull - The return value or specified argument is not null.
9198
class NonNull<AttrIndex idx> : IntrinsicProperty {
9299
int ArgNo = idx.Value;

llvm/include/llvm/IR/IntrinsicsNVVM.td

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2871,7 +2871,14 @@ foreach sp = [0, 1] in {
28712871
defvar nargs = !size(args);
28722872
defvar scale_d_imm = ArgIndex<!sub(nargs, 1)>;
28732873
defvar scale_d_imm_range = [ImmArg<scale_d_imm>, Range<scale_d_imm, 0, 16>];
2874-
defvar intrinsic_properties = !listconcat(
2874+
2875+
// Check if this is the specific llvm.nvvm.tcgen05.mma.tensor intrinsic.
2876+
defvar is_target_intrinsic = !and(!eq(sp, 0),
2877+
!eq(space, "tensor"),
2878+
!eq(scale_d, 0),
2879+
!eq(ashift, 0));
2880+
2881+
defvar base_properties = !listconcat(
28752882
mma.common_intr_props,
28762883
!if(!eq(scale_d, 1), scale_d_imm_range, []),
28772884
[Range<ArgIndex<nargs>, 0, !if(!eq(scale_d, 1), 2, 4)>, // kind
@@ -2881,6 +2888,13 @@ foreach sp = [0, 1] in {
28812888
]
28822889
);
28832890

2891+
defvar intrinsic_properties = !if(is_target_intrinsic,
2892+
!listconcat(base_properties,
2893+
[PrettyPrintImmArg<ArgIndex<nargs>, "printTcgen05MMAKind">,
2894+
PrettyPrintImmArg<ArgIndex<!add(nargs, 1)>, "printCTAGroupKind">,
2895+
PrettyPrintImmArg<ArgIndex<!add(nargs, 2)>, "printTcgen05CollectorUsageOp">]),
2896+
base_properties);
2897+
28842898
def mma.record:
28852899
DefaultAttrsIntrinsicFlags<[], args, flags, intrinsic_properties,
28862900
mma.intr>;

llvm/include/llvm/IR/Module.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -865,8 +865,8 @@ class LLVM_ABI Module {
865865
/// uselistorder directives so that use-lists can be recreated when reading
866866
/// the assembly.
867867
void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW,
868-
bool ShouldPreserveUseListOrder = false,
869-
bool IsForDebug = false) const;
868+
bool ShouldPreserveUseListOrder = false, bool IsForDebug = false,
869+
bool PrettyPrintIntrinsicArgs = false) const;
870870

871871
/// Dump the module to stderr (for debugging).
872872
void dump() const;

llvm/include/llvm/IR/NVVMIntrinsicUtils.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
#include <stdint.h>
1919

2020
#include "llvm/ADT/APFloat.h"
21+
#include "llvm/ADT/APInt.h"
22+
#include "llvm/IR/Constants.h"
2123
#include "llvm/IR/Intrinsics.h"
2224
#include "llvm/IR/IntrinsicsNVPTX.h"
25+
#include "llvm/Support/raw_ostream.h"
2326

2427
namespace llvm {
2528
namespace nvvm {
@@ -659,6 +662,70 @@ inline APFloat::roundingMode GetFMARoundingMode(Intrinsic::ID IntrinsicID) {
659662
llvm_unreachable("Invalid FP instrinsic rounding mode for NVVM fma");
660663
}
661664

665+
inline void printTcgen05MMAKind(raw_ostream &OS, const Constant *ImmArgVal) {
666+
if (const ConstantInt *CI = dyn_cast<ConstantInt>(ImmArgVal)) {
667+
uint64_t Val = CI->getZExtValue();
668+
switch (static_cast<Tcgen05MMAKind>(Val)) {
669+
case Tcgen05MMAKind::F16:
670+
OS << "kind::f16";
671+
return;
672+
case Tcgen05MMAKind::TF32:
673+
OS << "kind::tf32";
674+
return;
675+
case Tcgen05MMAKind::F8F6F4:
676+
OS << "kind::f8f6f4";
677+
return;
678+
case Tcgen05MMAKind::I8:
679+
OS << "kind::i8";
680+
return;
681+
}
682+
}
683+
llvm_unreachable(
684+
"printTcgen05MMAKind called with invalid value for immediate argument");
685+
}
686+
687+
inline void printTcgen05CollectorUsageOp(raw_ostream &OS,
688+
const Constant *ImmArgVal) {
689+
if (const ConstantInt *CI = dyn_cast<ConstantInt>(ImmArgVal)) {
690+
uint64_t Val = CI->getZExtValue();
691+
switch (static_cast<Tcgen05CollectorUsageOp>(Val)) {
692+
case Tcgen05CollectorUsageOp::DISCARD:
693+
OS << "collector::a::discard";
694+
return;
695+
case Tcgen05CollectorUsageOp::LASTUSE:
696+
OS << "collector::a::lastuse";
697+
return;
698+
case Tcgen05CollectorUsageOp::FILL:
699+
OS << "collector::a::fill";
700+
return;
701+
case Tcgen05CollectorUsageOp::USE:
702+
OS << "collector::a::use";
703+
return;
704+
}
705+
}
706+
llvm_unreachable("printTcgen05CollectorUsageOp called with invalid value for "
707+
"immediate argument");
708+
}
709+
710+
inline void printCTAGroupKind(raw_ostream &OS, const Constant *ImmArgVal) {
711+
if (const ConstantInt *CI = dyn_cast<ConstantInt>(ImmArgVal)) {
712+
uint64_t Val = CI->getZExtValue();
713+
switch (static_cast<CTAGroupKind>(Val)) {
714+
case CTAGroupKind::CG_NONE:
715+
OS << "cta_group::0";
716+
return;
717+
case CTAGroupKind::CG_1:
718+
OS << "cta_group::1";
719+
return;
720+
case CTAGroupKind::CG_2:
721+
OS << "cta_group::2";
722+
return;
723+
}
724+
}
725+
llvm_unreachable(
726+
"printCTAGroupKind called with invalid value for immediate argument");
727+
}
728+
662729
} // namespace nvvm
663730
} // namespace llvm
664731
#endif // LLVM_IR_NVVMINTRINSICUTILS_H

llvm/lib/IR/AsmWriter.cpp

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "llvm/IR/Instruction.h"
5454
#include "llvm/IR/Instructions.h"
5555
#include "llvm/IR/IntrinsicInst.h"
56+
#include "llvm/IR/Intrinsics.h"
5657
#include "llvm/IR/LLVMContext.h"
5758
#include "llvm/IR/Metadata.h"
5859
#include "llvm/IR/Module.h"
@@ -2831,6 +2832,7 @@ class AssemblyWriter {
28312832
SetVector<const Comdat *> Comdats;
28322833
bool IsForDebug;
28332834
bool ShouldPreserveUseListOrder;
2835+
bool PrettyPrintIntrinsicArgs;
28342836
UseListOrderMap UseListOrders;
28352837
SmallVector<StringRef, 8> MDNames;
28362838
/// Synchronization scope names registered with LLVMContext.
@@ -2841,7 +2843,8 @@ class AssemblyWriter {
28412843
/// Construct an AssemblyWriter with an external SlotTracker
28422844
AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M,
28432845
AssemblyAnnotationWriter *AAW, bool IsForDebug,
2844-
bool ShouldPreserveUseListOrder = false);
2846+
bool ShouldPreserveUseListOrder = false,
2847+
bool PrettyPrintIntrinsicArgs = false);
28452848

28462849
AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac,
28472850
const ModuleSummaryIndex *Index, bool IsForDebug);
@@ -2930,10 +2933,12 @@ class AssemblyWriter {
29302933

29312934
AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac,
29322935
const Module *M, AssemblyAnnotationWriter *AAW,
2933-
bool IsForDebug, bool ShouldPreserveUseListOrder)
2936+
bool IsForDebug, bool ShouldPreserveUseListOrder,
2937+
bool PrettyPrintIntrinsicArgs)
29342938
: Out(o), TheModule(M), Machine(Mac), TypePrinter(M), AnnotationWriter(AAW),
29352939
IsForDebug(IsForDebug),
2936-
ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {
2940+
ShouldPreserveUseListOrder(ShouldPreserveUseListOrder),
2941+
PrettyPrintIntrinsicArgs(PrettyPrintIntrinsicArgs) {
29372942
if (!TheModule)
29382943
return;
29392944
for (const GlobalObject &GO : TheModule->global_objects())
@@ -2944,7 +2949,8 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac,
29442949
AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac,
29452950
const ModuleSummaryIndex *Index, bool IsForDebug)
29462951
: Out(o), TheIndex(Index), Machine(Mac), TypePrinter(/*Module=*/nullptr),
2947-
IsForDebug(IsForDebug), ShouldPreserveUseListOrder(false) {}
2952+
IsForDebug(IsForDebug), ShouldPreserveUseListOrder(false),
2953+
PrettyPrintIntrinsicArgs(false) {}
29482954

29492955
void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) {
29502956
if (!Operand) {
@@ -4561,12 +4567,40 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
45614567
Out << ' ';
45624568
writeOperand(Operand, false);
45634569
Out << '(';
4570+
bool HasPrettyPrintedArgs =
4571+
PrettyPrintIntrinsicArgs && isa<IntrinsicInst>(CI) &&
4572+
Intrinsic::hasPrettyPrintedArgs(CI->getIntrinsicID());
4573+
45644574
ListSeparator LS;
4565-
for (unsigned op = 0, Eop = CI->arg_size(); op < Eop; ++op) {
4566-
Out << LS;
4567-
writeParamOperand(CI->getArgOperand(op), PAL.getParamAttrs(op));
4568-
}
4575+
if (HasPrettyPrintedArgs) {
4576+
Function *CalledFunc = CI->getCalledFunction();
4577+
auto PrintArgComment = [&](unsigned ArgNo) {
4578+
if (!CalledFunc->hasParamAttribute(ArgNo, Attribute::ImmArg))
4579+
return;
4580+
const Constant *ConstArg = dyn_cast<Constant>(CI->getArgOperand(ArgNo));
4581+
if (!ConstArg)
4582+
return;
4583+
std::string ArgComment;
4584+
raw_string_ostream ArgCommentStream(ArgComment);
4585+
Intrinsic::ID IID = CalledFunc->getIntrinsicID();
4586+
Intrinsic::printImmArg(IID, ArgNo, ArgCommentStream, ConstArg);
4587+
if (ArgComment.empty())
4588+
return;
4589+
Out << "/* " << ArgComment << " */ ";
4590+
};
45694591

4592+
for (unsigned ArgNo = 0, NumArgs = CI->arg_size(); ArgNo < NumArgs;
4593+
++ArgNo) {
4594+
Out << LS;
4595+
PrintArgComment(ArgNo);
4596+
writeParamOperand(CI->getArgOperand(ArgNo), PAL.getParamAttrs(ArgNo));
4597+
}
4598+
} else {
4599+
for (unsigned op = 0, Eop = CI->arg_size(); op < Eop; ++op) {
4600+
Out << LS;
4601+
writeParamOperand(CI->getArgOperand(op), PAL.getParamAttrs(op));
4602+
}
4603+
}
45704604
// Emit an ellipsis if this is a musttail call in a vararg function. This
45714605
// is only to aid readability, musttail calls forward varargs by default.
45724606
if (CI->isMustTailCall() && CI->getParent() &&
@@ -4990,13 +5024,12 @@ void AssemblyWriter::printUseLists(const Function *F) {
49905024
//===----------------------------------------------------------------------===//
49915025

49925026
void Function::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW,
4993-
bool ShouldPreserveUseListOrder,
4994-
bool IsForDebug) const {
5027+
bool ShouldPreserveUseListOrder, bool IsForDebug,
5028+
bool PrettyPrintIntrinsicArgs) const {
49955029
SlotTracker SlotTable(this->getParent());
49965030
formatted_raw_ostream OS(ROS);
4997-
AssemblyWriter W(OS, SlotTable, this->getParent(), AAW,
4998-
IsForDebug,
4999-
ShouldPreserveUseListOrder);
5031+
AssemblyWriter W(OS, SlotTable, this->getParent(), AAW, IsForDebug,
5032+
ShouldPreserveUseListOrder, PrettyPrintIntrinsicArgs);
50005033
W.printFunction(this);
50015034
}
50025035

@@ -5012,11 +5045,12 @@ void BasicBlock::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW,
50125045
}
50135046

50145047
void Module::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW,
5015-
bool ShouldPreserveUseListOrder, bool IsForDebug) const {
5048+
bool ShouldPreserveUseListOrder, bool IsForDebug,
5049+
bool PrettyPrintIntrinsicArgs) const {
50165050
SlotTracker SlotTable(this);
50175051
formatted_raw_ostream OS(ROS);
50185052
AssemblyWriter W(OS, SlotTable, this, AAW, IsForDebug,
5019-
ShouldPreserveUseListOrder);
5053+
ShouldPreserveUseListOrder, PrettyPrintIntrinsicArgs);
50205054
W.printModule(this);
50215055
}
50225056

llvm/lib/IR/Intrinsics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "llvm/IR/IntrinsicsX86.h"
3333
#include "llvm/IR/IntrinsicsXCore.h"
3434
#include "llvm/IR/Module.h"
35+
#include "llvm/IR/NVVMIntrinsicUtils.h"
3536
#include "llvm/IR/Type.h"
3637

3738
using namespace llvm;
@@ -601,6 +602,12 @@ bool Intrinsic::isOverloaded(ID id) {
601602
#undef GET_INTRINSIC_OVERLOAD_TABLE
602603
}
603604

605+
bool Intrinsic::hasPrettyPrintedArgs(ID id){
606+
#define GET_INTRINSIC_PRETTY_PRINT_TABLE
607+
#include "llvm/IR/IntrinsicImpl.inc"
608+
#undef GET_INTRINSIC_PRETTY_PRINT_TABLE
609+
}
610+
604611
/// Table of per-target intrinsic name tables.
605612
#define GET_INTRINSIC_TARGET_DATA
606613
#include "llvm/IR/IntrinsicImpl.inc"
@@ -1129,3 +1136,7 @@ Intrinsic::ID Intrinsic::getDeinterleaveIntrinsicID(unsigned Factor) {
11291136
assert(Factor >= 2 && Factor <= 8 && "Unexpected factor");
11301137
return InterleaveIntrinsics[Factor - 2].Deinterleave;
11311138
}
1139+
1140+
#define GET_INTRINSIC_PRETTY_PRINT_ARGUMENTS
1141+
#include "llvm/IR/IntrinsicImpl.inc"
1142+
#undef GET_INTRINSIC_PRETTY_PRINT_ARGUMENTS

0 commit comments

Comments
 (0)