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 private:
39   bool replaceIsTypePSampler(Instruction &I);
40   bool replaceIsTypePSurface(Instruction &I);
41   bool replaceIsTypePTexture(Instruction &I);
42   Value *cleanupValue(Value *V);
43   void replaceWith(Instruction *From, ConstantInt *To);
44 };
45 }
46 
47 char NVPTXImageOptimizer::ID = 0;
48 
49 NVPTXImageOptimizer::NVPTXImageOptimizer()
50   : FunctionPass(ID) {}
51 
52 bool NVPTXImageOptimizer::runOnFunction(Function &F) {
53   if (skipFunction(F))
54     return false;
55 
56   bool Changed = false;
57   InstrToDelete.clear();
58 
59   // Look for call instructions in the function
60   for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE;
61        ++BI) {
62     for (BasicBlock::iterator I = (*BI).begin(), E = (*BI).end();
63          I != E; ++I) {
64       Instruction &Instr = *I;
65       if (CallInst *CI = dyn_cast<CallInst>(I)) {
66         Function *CalledF = CI->getCalledFunction();
67         if (CalledF && CalledF->isIntrinsic()) {
68           // This is an intrinsic function call, check if its an istypep
69           switch (CalledF->getIntrinsicID()) {
70           default: break;
71           case Intrinsic::nvvm_istypep_sampler:
72             Changed |= replaceIsTypePSampler(Instr);
73             break;
74           case Intrinsic::nvvm_istypep_surface:
75             Changed |= replaceIsTypePSurface(Instr);
76             break;
77           case Intrinsic::nvvm_istypep_texture:
78             Changed |= replaceIsTypePTexture(Instr);
79             break;
80           }
81         }
82       }
83     }
84   }
85 
86   // Delete any istypep instances we replaced in the IR
87   for (unsigned i = 0, e = InstrToDelete.size(); i != e; ++i)
88     InstrToDelete[i]->eraseFromParent();
89 
90   return Changed;
91 }
92 
93 bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
94   Value *TexHandle = cleanupValue(I.getOperand(0));
95   if (isSampler(*TexHandle)) {
96     // This is an OpenCL sampler, so it must be a samplerref
97     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
98     return true;
99   } else if (isImage(*TexHandle)) {
100     // This is an OpenCL image, so it cannot be a samplerref
101     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
102     return true;
103   } else {
104     // The image type is unknown, so we cannot eliminate the intrinsic
105     return false;
106   }
107 }
108 
109 bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
110   Value *TexHandle = cleanupValue(I.getOperand(0));
111   if (isImageReadWrite(*TexHandle) ||
112       isImageWriteOnly(*TexHandle)) {
113     // This is an OpenCL read-only/read-write image, so it must be a surfref
114     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
115     return true;
116   } else if (isImageReadOnly(*TexHandle) ||
117              isSampler(*TexHandle)) {
118     // This is an OpenCL read-only/ imageor sampler, so it cannot be
119     // a surfref
120     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
121     return true;
122   } else {
123     // The image type is unknown, so we cannot eliminate the intrinsic
124     return false;
125   }
126 }
127 
128 bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
129   Value *TexHandle = cleanupValue(I.getOperand(0));
130   if (isImageReadOnly(*TexHandle)) {
131     // This is an OpenCL read-only image, so it must be a texref
132     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
133     return true;
134   } else if (isImageWriteOnly(*TexHandle) ||
135              isImageReadWrite(*TexHandle) ||
136              isSampler(*TexHandle)) {
137     // This is an OpenCL read-write/write-only image or a sampler, so it
138     // cannot be a texref
139     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
140     return true;
141   } else {
142     // The image type is unknown, so we cannot eliminate the intrinsic
143     return false;
144   }
145 }
146 
147 void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
148   // We implement "poor man's DCE" here to make sure any code that is no longer
149   // live is actually unreachable and can be trivially eliminated by the
150   // unreachable block elimination pass.
151   for (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end();
152        UI != UE; ++UI) {
153     if (BranchInst *BI = dyn_cast<BranchInst>(*UI)) {
154       if (BI->isUnconditional()) continue;
155       BasicBlock *Dest;
156       if (To->isZero())
157         // Get false block
158         Dest = BI->getSuccessor(1);
159       else
160         // Get true block
161         Dest = BI->getSuccessor(0);
162       BranchInst::Create(Dest, BI);
163       InstrToDelete.push_back(BI);
164     }
165   }
166   From->replaceAllUsesWith(To);
167   InstrToDelete.push_back(From);
168 }
169 
170 Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
171   if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
172     return cleanupValue(EVI->getAggregateOperand());
173   }
174   return V;
175 }
176 
177 FunctionPass *llvm::createNVPTXImageOptimizerPass() {
178   return new NVPTXImageOptimizer();
179 }
180