1 //===- NVVMIntrRange.cpp - Set range attributes for NVVM intrinsics -------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass adds appropriate range attributes for calls to NVVM
10 // intrinsics that return a limited range of values.
12 //===----------------------------------------------------------------------===//
15 #include "NVPTXUtilities.h"
16 #include "llvm/IR/InstIterator.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/IntrinsicInst.h"
19 #include "llvm/IR/Intrinsics.h"
20 #include "llvm/IR/IntrinsicsNVPTX.h"
21 #include "llvm/IR/PassManager.h"
22 #include "llvm/Support/CommandLine.h"
27 #define DEBUG_TYPE "nvvm-intr-range"
29 namespace llvm
{ void initializeNVVMIntrRangePass(PassRegistry
&); }
32 class NVVMIntrRange
: public FunctionPass
{
35 NVVMIntrRange() : FunctionPass(ID
) {
37 initializeNVVMIntrRangePass(*PassRegistry::getPassRegistry());
40 bool runOnFunction(Function
&) override
;
44 FunctionPass
*llvm::createNVVMIntrRangePass() { return new NVVMIntrRange(); }
46 char NVVMIntrRange::ID
= 0;
47 INITIALIZE_PASS(NVVMIntrRange
, "nvvm-intr-range",
48 "Add !range metadata to NVVM intrinsics.", false, false)
50 // Adds the passed-in [Low,High) range information as metadata to the
51 // passed-in call instruction.
52 static bool addRangeAttr(uint64_t Low
, uint64_t High
, IntrinsicInst
*II
) {
53 if (II
->getMetadata(LLVMContext::MD_range
))
56 const uint64_t BitWidth
= II
->getType()->getIntegerBitWidth();
57 ConstantRange
Range(APInt(BitWidth
, Low
), APInt(BitWidth
, High
));
59 if (auto CurrentRange
= II
->getRange())
60 Range
= Range
.intersectWith(CurrentRange
.value());
62 II
->addRangeRetAttr(Range
);
66 static bool runNVVMIntrRange(Function
&F
) {
69 } MaxBlockSize
, MaxGridSize
;
71 const unsigned MetadataNTID
= getReqNTID(F
).value_or(
72 getMaxNTID(F
).value_or(std::numeric_limits
<unsigned>::max()));
74 MaxBlockSize
.x
= std::min(1024u, MetadataNTID
);
75 MaxBlockSize
.y
= std::min(1024u, MetadataNTID
);
76 MaxBlockSize
.z
= std::min(64u, MetadataNTID
);
78 MaxGridSize
.x
= 0x7fffffff;
79 MaxGridSize
.y
= 0xffff;
80 MaxGridSize
.z
= 0xffff;
82 // Go through the calls in this function.
84 for (Instruction
&I
: instructions(F
)) {
85 IntrinsicInst
*II
= dyn_cast
<IntrinsicInst
>(&I
);
89 switch (II
->getIntrinsicID()) {
91 case Intrinsic::nvvm_read_ptx_sreg_tid_x
:
92 Changed
|= addRangeAttr(0, MaxBlockSize
.x
, II
);
94 case Intrinsic::nvvm_read_ptx_sreg_tid_y
:
95 Changed
|= addRangeAttr(0, MaxBlockSize
.y
, II
);
97 case Intrinsic::nvvm_read_ptx_sreg_tid_z
:
98 Changed
|= addRangeAttr(0, MaxBlockSize
.z
, II
);
102 case Intrinsic::nvvm_read_ptx_sreg_ntid_x
:
103 Changed
|= addRangeAttr(1, MaxBlockSize
.x
+ 1, II
);
105 case Intrinsic::nvvm_read_ptx_sreg_ntid_y
:
106 Changed
|= addRangeAttr(1, MaxBlockSize
.y
+ 1, II
);
108 case Intrinsic::nvvm_read_ptx_sreg_ntid_z
:
109 Changed
|= addRangeAttr(1, MaxBlockSize
.z
+ 1, II
);
113 case Intrinsic::nvvm_read_ptx_sreg_ctaid_x
:
114 Changed
|= addRangeAttr(0, MaxGridSize
.x
, II
);
116 case Intrinsic::nvvm_read_ptx_sreg_ctaid_y
:
117 Changed
|= addRangeAttr(0, MaxGridSize
.y
, II
);
119 case Intrinsic::nvvm_read_ptx_sreg_ctaid_z
:
120 Changed
|= addRangeAttr(0, MaxGridSize
.z
, II
);
124 case Intrinsic::nvvm_read_ptx_sreg_nctaid_x
:
125 Changed
|= addRangeAttr(1, MaxGridSize
.x
+ 1, II
);
127 case Intrinsic::nvvm_read_ptx_sreg_nctaid_y
:
128 Changed
|= addRangeAttr(1, MaxGridSize
.y
+ 1, II
);
130 case Intrinsic::nvvm_read_ptx_sreg_nctaid_z
:
131 Changed
|= addRangeAttr(1, MaxGridSize
.z
+ 1, II
);
134 // warp size is constant 32.
135 case Intrinsic::nvvm_read_ptx_sreg_warpsize
:
136 Changed
|= addRangeAttr(32, 32 + 1, II
);
139 // Lane ID is [0..warpsize)
140 case Intrinsic::nvvm_read_ptx_sreg_laneid
:
141 Changed
|= addRangeAttr(0, 32, II
);
152 bool NVVMIntrRange::runOnFunction(Function
&F
) { return runNVVMIntrRange(F
); }
154 PreservedAnalyses
NVVMIntrRangePass::run(Function
&F
,
155 FunctionAnalysisManager
&AM
) {
156 return runNVVMIntrRange(F
) ? PreservedAnalyses::none()
157 : PreservedAnalyses::all();