xref: /freebsd/contrib/llvm-project/llvm/lib/Target/NVPTX/NVVMIntrRange.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- NVVMIntrRange.cpp - Set range attributes for NVVM intrinsics -------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
9*0fca6ea1SDimitry Andric // This pass adds appropriate range attributes for calls to NVVM
100b57cec5SDimitry Andric // intrinsics that return a limited range of values.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "NVPTX.h"
15*0fca6ea1SDimitry Andric #include "NVPTXUtilities.h"
160b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h"
170b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
18*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
190b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
20480093f4SDimitry Andric #include "llvm/IR/IntrinsicsNVPTX.h"
21e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
22480093f4SDimitry Andric #include "llvm/Support/CommandLine.h"
23*0fca6ea1SDimitry Andric #include <cstdint>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #define DEBUG_TYPE "nvvm-intr-range"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace llvm { void initializeNVVMIntrRangePass(PassRegistry &); }
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {
320b57cec5SDimitry Andric class NVVMIntrRange : public FunctionPass {
330b57cec5SDimitry Andric public:
340b57cec5SDimitry Andric   static char ID;
NVVMIntrRange()35*0fca6ea1SDimitry Andric   NVVMIntrRange() : FunctionPass(ID) {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric     initializeNVVMIntrRangePass(*PassRegistry::getPassRegistry());
380b57cec5SDimitry Andric   }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   bool runOnFunction(Function &) override;
410b57cec5SDimitry Andric };
42*0fca6ea1SDimitry Andric } // namespace
430b57cec5SDimitry Andric 
createNVVMIntrRangePass()44*0fca6ea1SDimitry Andric FunctionPass *llvm::createNVVMIntrRangePass() { return new NVVMIntrRange(); }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric char NVVMIntrRange::ID = 0;
470b57cec5SDimitry Andric INITIALIZE_PASS(NVVMIntrRange, "nvvm-intr-range",
480b57cec5SDimitry Andric                 "Add !range metadata to NVVM intrinsics.", false, false)
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric // Adds the passed-in [Low,High) range information as metadata to the
510b57cec5SDimitry Andric // passed-in call instruction.
addRangeAttr(uint64_t Low,uint64_t High,IntrinsicInst * II)52*0fca6ea1SDimitry Andric static bool addRangeAttr(uint64_t Low, uint64_t High, IntrinsicInst *II) {
53*0fca6ea1SDimitry Andric   if (II->getMetadata(LLVMContext::MD_range))
540b57cec5SDimitry Andric     return false;
550b57cec5SDimitry Andric 
56*0fca6ea1SDimitry Andric   const uint64_t BitWidth = II->getType()->getIntegerBitWidth();
57*0fca6ea1SDimitry Andric   ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High));
58*0fca6ea1SDimitry Andric 
59*0fca6ea1SDimitry Andric   if (auto CurrentRange = II->getRange())
60*0fca6ea1SDimitry Andric     Range = Range.intersectWith(CurrentRange.value());
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric   II->addRangeRetAttr(Range);
630b57cec5SDimitry Andric   return true;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
runNVVMIntrRange(Function & F)66*0fca6ea1SDimitry Andric static bool runNVVMIntrRange(Function &F) {
67e8d8bef9SDimitry Andric   struct {
68e8d8bef9SDimitry Andric     unsigned x, y, z;
69e8d8bef9SDimitry Andric   } MaxBlockSize, MaxGridSize;
70e8d8bef9SDimitry Andric 
71*0fca6ea1SDimitry Andric   const unsigned MetadataNTID = getReqNTID(F).value_or(
72*0fca6ea1SDimitry Andric       getMaxNTID(F).value_or(std::numeric_limits<unsigned>::max()));
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric   MaxBlockSize.x = std::min(1024u, MetadataNTID);
75*0fca6ea1SDimitry Andric   MaxBlockSize.y = std::min(1024u, MetadataNTID);
76*0fca6ea1SDimitry Andric   MaxBlockSize.z = std::min(64u, MetadataNTID);
77*0fca6ea1SDimitry Andric 
78*0fca6ea1SDimitry Andric   MaxGridSize.x = 0x7fffffff;
79e8d8bef9SDimitry Andric   MaxGridSize.y = 0xffff;
80e8d8bef9SDimitry Andric   MaxGridSize.z = 0xffff;
81e8d8bef9SDimitry Andric 
820b57cec5SDimitry Andric   // Go through the calls in this function.
830b57cec5SDimitry Andric   bool Changed = false;
840b57cec5SDimitry Andric   for (Instruction &I : instructions(F)) {
85*0fca6ea1SDimitry Andric     IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
86*0fca6ea1SDimitry Andric     if (!II)
870b57cec5SDimitry Andric       continue;
880b57cec5SDimitry Andric 
89*0fca6ea1SDimitry Andric     switch (II->getIntrinsicID()) {
900b57cec5SDimitry Andric     // Index within block
910b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_tid_x:
92*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, MaxBlockSize.x, II);
930b57cec5SDimitry Andric       break;
940b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_tid_y:
95*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, MaxBlockSize.y, II);
960b57cec5SDimitry Andric       break;
970b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_tid_z:
98*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, MaxBlockSize.z, II);
990b57cec5SDimitry Andric       break;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     // Block size
1020b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_ntid_x:
103*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(1, MaxBlockSize.x + 1, II);
1040b57cec5SDimitry Andric       break;
1050b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_ntid_y:
106*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(1, MaxBlockSize.y + 1, II);
1070b57cec5SDimitry Andric       break;
1080b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_ntid_z:
109*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(1, MaxBlockSize.z + 1, II);
1100b57cec5SDimitry Andric       break;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric     // Index within grid
1130b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_ctaid_x:
114*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, MaxGridSize.x, II);
1150b57cec5SDimitry Andric       break;
1160b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_ctaid_y:
117*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, MaxGridSize.y, II);
1180b57cec5SDimitry Andric       break;
1190b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_ctaid_z:
120*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, MaxGridSize.z, II);
1210b57cec5SDimitry Andric       break;
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     // Grid size
1240b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_nctaid_x:
125*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(1, MaxGridSize.x + 1, II);
1260b57cec5SDimitry Andric       break;
1270b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_nctaid_y:
128*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(1, MaxGridSize.y + 1, II);
1290b57cec5SDimitry Andric       break;
1300b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_nctaid_z:
131*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(1, MaxGridSize.z + 1, II);
1320b57cec5SDimitry Andric       break;
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     // warp size is constant 32.
1350b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_warpsize:
136*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(32, 32 + 1, II);
1370b57cec5SDimitry Andric       break;
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     // Lane ID is [0..warpsize)
1400b57cec5SDimitry Andric     case Intrinsic::nvvm_read_ptx_sreg_laneid:
141*0fca6ea1SDimitry Andric       Changed |= addRangeAttr(0, 32, II);
1420b57cec5SDimitry Andric       break;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric     default:
1450b57cec5SDimitry Andric       break;
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   return Changed;
1500b57cec5SDimitry Andric }
151e8d8bef9SDimitry Andric 
runOnFunction(Function & F)152*0fca6ea1SDimitry Andric bool NVVMIntrRange::runOnFunction(Function &F) { return runNVVMIntrRange(F); }
153e8d8bef9SDimitry Andric 
run(Function & F,FunctionAnalysisManager & AM)154e8d8bef9SDimitry Andric PreservedAnalyses NVVMIntrRangePass::run(Function &F,
155e8d8bef9SDimitry Andric                                          FunctionAnalysisManager &AM) {
156*0fca6ea1SDimitry Andric   return runNVVMIntrRange(F) ? PreservedAnalyses::none()
157e8d8bef9SDimitry Andric                              : PreservedAnalyses::all();
158e8d8bef9SDimitry Andric }
159