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