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