• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass implements IR-level optimizations of image access code,
11 // including:
12 //
13 // 1. Eliminate istypep intrinsics when image access qualifier is known
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "NVPTX.h"
18 #include "NVPTXUtilities.h"
19 #include "llvm/Analysis/ConstantFolding.h"
20 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/Intrinsics.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 
NVPTXImageOptimizer()49 NVPTXImageOptimizer::NVPTXImageOptimizer()
50   : FunctionPass(ID) {}
51 
runOnFunction(Function & F)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 
replaceIsTypePSampler(Instruction & I)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 (isImageWriteOnly(*TexHandle) ||
100              isImageReadWrite(*TexHandle) ||
101              isImageReadOnly(*TexHandle)) {
102     // This is an OpenCL image, so it cannot be a samplerref
103     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
104     return true;
105   } else {
106     // The image type is unknown, so we cannot eliminate the intrinsic
107     return false;
108   }
109 }
110 
replaceIsTypePSurface(Instruction & I)111 bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
112   Value *TexHandle = cleanupValue(I.getOperand(0));
113   if (isImageReadWrite(*TexHandle) ||
114       isImageWriteOnly(*TexHandle)) {
115     // This is an OpenCL read-only/read-write image, so it must be a surfref
116     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
117     return true;
118   } else if (isImageReadOnly(*TexHandle) ||
119              isSampler(*TexHandle)) {
120     // This is an OpenCL read-only/ imageor sampler, so it cannot be
121     // a surfref
122     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
123     return true;
124   } else {
125     // The image type is unknown, so we cannot eliminate the intrinsic
126     return false;
127   }
128 }
129 
replaceIsTypePTexture(Instruction & I)130 bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
131   Value *TexHandle = cleanupValue(I.getOperand(0));
132   if (isImageReadOnly(*TexHandle)) {
133     // This is an OpenCL read-only image, so it must be a texref
134     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
135     return true;
136   } else if (isImageWriteOnly(*TexHandle) ||
137              isImageReadWrite(*TexHandle) ||
138              isSampler(*TexHandle)) {
139     // This is an OpenCL read-write/write-only image or a sampler, so it
140     // cannot be a texref
141     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
142     return true;
143   } else {
144     // The image type is unknown, so we cannot eliminate the intrinsic
145     return false;
146   }
147 }
148 
replaceWith(Instruction * From,ConstantInt * To)149 void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
150   // We implement "poor man's DCE" here to make sure any code that is no longer
151   // live is actually unreachable and can be trivially eliminated by the
152   // unreachable block elimination pass.
153   for (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end();
154        UI != UE; ++UI) {
155     if (BranchInst *BI = dyn_cast<BranchInst>(*UI)) {
156       if (BI->isUnconditional()) continue;
157       BasicBlock *Dest;
158       if (To->isZero())
159         // Get false block
160         Dest = BI->getSuccessor(1);
161       else
162         // Get true block
163         Dest = BI->getSuccessor(0);
164       BranchInst::Create(Dest, BI);
165       InstrToDelete.push_back(BI);
166     }
167   }
168   From->replaceAllUsesWith(To);
169   InstrToDelete.push_back(From);
170 }
171 
cleanupValue(Value * V)172 Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
173   if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
174     return cleanupValue(EVI->getAggregateOperand());
175   }
176   return V;
177 }
178 
createNVPTXImageOptimizerPass()179 FunctionPass *llvm::createNVPTXImageOptimizerPass() {
180   return new NVPTXImageOptimizer();
181 }
182