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
24using namespace llvm;
25
26namespace {
27class NVPTXImageOptimizer : public FunctionPass {
28private:
29 static char ID;
30 SmallVector<Instruction*, 4> InstrToDelete;
31
32public:
33 NVPTXImageOptimizer();
34
35 bool runOnFunction(Function &F) override;
36
37 StringRef getPassName() const override { return "NVPTX Image Optimizer"; }
38
39private:
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
48char NVPTXImageOptimizer::ID = 0;
49
50NVPTXImageOptimizer::NVPTXImageOptimizer()
51 : FunctionPass(ID) {}
52
53bool 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>(Val: &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(I&: Instr);
71 break;
72 case Intrinsic::nvvm_istypep_surface:
73 Changed |= replaceIsTypePSurface(I&: Instr);
74 break;
75 case Intrinsic::nvvm_istypep_texture:
76 Changed |= replaceIsTypePTexture(I&: 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
91bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
92 Value *TexHandle = cleanupValue(V: I.getOperand(i: 0));
93 if (isSampler(*TexHandle)) {
94 // This is an OpenCL sampler, so it must be a samplerref
95 replaceWith(From: &I, To: ConstantInt::getTrue(Context&: I.getContext()));
96 return true;
97 } else if (isImage(*TexHandle)) {
98 // This is an OpenCL image, so it cannot be a samplerref
99 replaceWith(From: &I, To: ConstantInt::getFalse(Context&: 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
107bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
108 Value *TexHandle = cleanupValue(V: I.getOperand(i: 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(From: &I, To: ConstantInt::getTrue(Context&: 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(From: &I, To: ConstantInt::getFalse(Context&: 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
126bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
127 Value *TexHandle = cleanupValue(V: I.getOperand(i: 0));
128 if (isImageReadOnly(*TexHandle)) {
129 // This is an OpenCL read-only image, so it must be a texref
130 replaceWith(From: &I, To: ConstantInt::getTrue(Context&: 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(From: &I, To: ConstantInt::getFalse(Context&: 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
145void 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>(Val&: U)) {
151 if (BI->isUnconditional()) continue;
152 BasicBlock *Dest;
153 if (To->isZero())
154 // Get false block
155 Dest = BI->getSuccessor(i: 1);
156 else
157 // Get true block
158 Dest = BI->getSuccessor(i: 0);
159 BranchInst::Create(IfTrue: Dest, InsertBefore: BI->getIterator());
160 InstrToDelete.push_back(Elt: BI);
161 }
162 }
163 From->replaceAllUsesWith(V: To);
164 InstrToDelete.push_back(Elt: From);
165}
166
167Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
168 if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(Val: V)) {
169 return cleanupValue(V: EVI->getAggregateOperand());
170 }
171 return V;
172}
173
174FunctionPass *llvm::createNVPTXImageOptimizerPass() {
175 return new NVPTXImageOptimizer();
176}
177