1 //===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass implements IR-level optimizations of image access code,
10 // including:
11 //
12 // 1. Eliminate istypep intrinsics when image access qualifier is known
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "NVPTX.h"
17 #include "NVPTXUtilities.h"
18 #include "llvm/Analysis/ConstantFolding.h"
19 #include "llvm/IR/Instructions.h"
20 #include "llvm/IR/Intrinsics.h"
21 #include "llvm/IR/IntrinsicsNVPTX.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/Pass.h"
24 
25 using namespace llvm;
26 
27 namespace {
28 class NVPTXImageOptimizer : public FunctionPass {
29 private:
30   static char ID;
31   SmallVector<Instruction*, 4> InstrToDelete;
32 
33 public:
34   NVPTXImageOptimizer();
35 
36   bool runOnFunction(Function &F) override;
37 
38   StringRef getPassName() const override { return "NVPTX Image Optimizer"; }
39 
40 private:
41   bool replaceIsTypePSampler(Instruction &I);
42   bool replaceIsTypePSurface(Instruction &I);
43   bool replaceIsTypePTexture(Instruction &I);
44   Value *cleanupValue(Value *V);
45   void replaceWith(Instruction *From, ConstantInt *To);
46 };
47 }
48 
49 char NVPTXImageOptimizer::ID = 0;
50 
51 NVPTXImageOptimizer::NVPTXImageOptimizer()
52   : FunctionPass(ID) {}
53 
54 bool NVPTXImageOptimizer::runOnFunction(Function &F) {
55   if (skipFunction(F))
56     return false;
57 
58   bool Changed = false;
59   InstrToDelete.clear();
60 
61   // Look for call instructions in the function
62   for (BasicBlock &BB : F) {
63     for (Instruction &Instr : BB) {
64       if (CallInst *CI = dyn_cast<CallInst>(&Instr)) {
65         Function *CalledF = CI->getCalledFunction();
66         if (CalledF && CalledF->isIntrinsic()) {
67           // This is an intrinsic function call, check if its an istypep
68           switch (CalledF->getIntrinsicID()) {
69           default: break;
70           case Intrinsic::nvvm_istypep_sampler:
71             Changed |= replaceIsTypePSampler(Instr);
72             break;
73           case Intrinsic::nvvm_istypep_surface:
74             Changed |= replaceIsTypePSurface(Instr);
75             break;
76           case Intrinsic::nvvm_istypep_texture:
77             Changed |= replaceIsTypePTexture(Instr);
78             break;
79           }
80         }
81       }
82     }
83   }
84 
85   // Delete any istypep instances we replaced in the IR
86   for (Instruction *I : InstrToDelete)
87     I->eraseFromParent();
88 
89   return Changed;
90 }
91 
92 bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
93   Value *TexHandle = cleanupValue(I.getOperand(0));
94   if (isSampler(*TexHandle)) {
95     // This is an OpenCL sampler, so it must be a samplerref
96     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
97     return true;
98   } else if (isImage(*TexHandle)) {
99     // This is an OpenCL image, so it cannot be a samplerref
100     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
101     return true;
102   } else {
103     // The image type is unknown, so we cannot eliminate the intrinsic
104     return false;
105   }
106 }
107 
108 bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
109   Value *TexHandle = cleanupValue(I.getOperand(0));
110   if (isImageReadWrite(*TexHandle) ||
111       isImageWriteOnly(*TexHandle)) {
112     // This is an OpenCL read-only/read-write image, so it must be a surfref
113     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
114     return true;
115   } else if (isImageReadOnly(*TexHandle) ||
116              isSampler(*TexHandle)) {
117     // This is an OpenCL read-only/ imageor sampler, so it cannot be
118     // a surfref
119     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
120     return true;
121   } else {
122     // The image type is unknown, so we cannot eliminate the intrinsic
123     return false;
124   }
125 }
126 
127 bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
128   Value *TexHandle = cleanupValue(I.getOperand(0));
129   if (isImageReadOnly(*TexHandle)) {
130     // This is an OpenCL read-only image, so it must be a texref
131     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
132     return true;
133   } else if (isImageWriteOnly(*TexHandle) ||
134              isImageReadWrite(*TexHandle) ||
135              isSampler(*TexHandle)) {
136     // This is an OpenCL read-write/write-only image or a sampler, so it
137     // cannot be a texref
138     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
139     return true;
140   } else {
141     // The image type is unknown, so we cannot eliminate the intrinsic
142     return false;
143   }
144 }
145 
146 void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
147   // We implement "poor man's DCE" here to make sure any code that is no longer
148   // live is actually unreachable and can be trivially eliminated by the
149   // unreachable block elimination pass.
150   for (Use &U : From->uses()) {
151     if (BranchInst *BI = dyn_cast<BranchInst>(U)) {
152       if (BI->isUnconditional()) continue;
153       BasicBlock *Dest;
154       if (To->isZero())
155         // Get false block
156         Dest = BI->getSuccessor(1);
157       else
158         // Get true block
159         Dest = BI->getSuccessor(0);
160       BranchInst::Create(Dest, BI);
161       InstrToDelete.push_back(BI);
162     }
163   }
164   From->replaceAllUsesWith(To);
165   InstrToDelete.push_back(From);
166 }
167 
168 Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
169   if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
170     return cleanupValue(EVI->getAggregateOperand());
171   }
172   return V;
173 }
174 
175 FunctionPass *llvm::createNVPTXImageOptimizerPass() {
176   return new NVPTXImageOptimizer();
177 }
178