xref: /freebsd/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXImageOptimizer.cpp (revision 6966ac055c3b7a39266fb982493330df7a097997)
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/Module.h"
22 #include "llvm/Pass.h"
23 
24 using namespace llvm;
25 
26 namespace {
27 class NVPTXImageOptimizer : public FunctionPass {
28 private:
29   static char ID;
30   SmallVector<Instruction*, 4> InstrToDelete;
31 
32 public:
33   NVPTXImageOptimizer();
34 
35   bool runOnFunction(Function &F) override;
36 
37 private:
38   bool replaceIsTypePSampler(Instruction &I);
39   bool replaceIsTypePSurface(Instruction &I);
40   bool replaceIsTypePTexture(Instruction &I);
41   Value *cleanupValue(Value *V);
42   void replaceWith(Instruction *From, ConstantInt *To);
43 };
44 }
45 
46 char NVPTXImageOptimizer::ID = 0;
47 
48 NVPTXImageOptimizer::NVPTXImageOptimizer()
49   : FunctionPass(ID) {}
50 
51 bool NVPTXImageOptimizer::runOnFunction(Function &F) {
52   if (skipFunction(F))
53     return false;
54 
55   bool Changed = false;
56   InstrToDelete.clear();
57 
58   // Look for call instructions in the function
59   for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE;
60        ++BI) {
61     for (BasicBlock::iterator I = (*BI).begin(), E = (*BI).end();
62          I != E; ++I) {
63       Instruction &Instr = *I;
64       if (CallInst *CI = dyn_cast<CallInst>(I)) {
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 (unsigned i = 0, e = InstrToDelete.size(); i != e; ++i)
87     InstrToDelete[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 (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end();
151        UI != UE; ++UI) {
152     if (BranchInst *BI = dyn_cast<BranchInst>(*UI)) {
153       if (BI->isUnconditional()) continue;
154       BasicBlock *Dest;
155       if (To->isZero())
156         // Get false block
157         Dest = BI->getSuccessor(1);
158       else
159         // Get true block
160         Dest = BI->getSuccessor(0);
161       BranchInst::Create(Dest, BI);
162       InstrToDelete.push_back(BI);
163     }
164   }
165   From->replaceAllUsesWith(To);
166   InstrToDelete.push_back(From);
167 }
168 
169 Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
170   if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
171     return cleanupValue(EVI->getAggregateOperand());
172   }
173   return V;
174 }
175 
176 FunctionPass *llvm::createNVPTXImageOptimizerPass() {
177   return new NVPTXImageOptimizer();
178 }
179