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