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