1 //===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 /// \file 11 /// This pass translates tgsi-like texture intrinsics into R600 texture 12 /// closer to hardware intrinsics. 13 //===----------------------------------------------------------------------===// 14 15 #include "AMDGPU.h" 16 #include "llvm/ADT/Statistic.h" 17 #include "llvm/Analysis/Passes.h" 18 #include "llvm/IR/Function.h" 19 #include "llvm/IR/GlobalValue.h" 20 #include "llvm/IR/IRBuilder.h" 21 #include "llvm/IR/InstVisitor.h" 22 23 using namespace llvm; 24 25 namespace { 26 class R600TextureIntrinsicsReplacer : 27 public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> { 28 static char ID; 29 30 Module *Mod; 31 Type *FloatType; 32 Type *Int32Type; 33 Type *V4f32Type; 34 Type *V4i32Type; 35 FunctionType *TexSign; 36 FunctionType *TexQSign; 37 38 void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD, 39 unsigned SrcSelect[4], unsigned CT[4], 40 bool &useShadowVariant) { 41 enum TextureTypes { 42 TEXTURE_1D = 1, 43 TEXTURE_2D, 44 TEXTURE_3D, 45 TEXTURE_CUBE, 46 TEXTURE_RECT, 47 TEXTURE_SHADOW1D, 48 TEXTURE_SHADOW2D, 49 TEXTURE_SHADOWRECT, 50 TEXTURE_1D_ARRAY, 51 TEXTURE_2D_ARRAY, 52 TEXTURE_SHADOW1D_ARRAY, 53 TEXTURE_SHADOW2D_ARRAY, 54 TEXTURE_SHADOWCUBE, 55 TEXTURE_2D_MSAA, 56 TEXTURE_2D_ARRAY_MSAA, 57 TEXTURE_CUBE_ARRAY, 58 TEXTURE_SHADOWCUBE_ARRAY 59 }; 60 61 switch (TextureType) { 62 case 0: 63 useShadowVariant = false; 64 return; 65 case TEXTURE_RECT: 66 case TEXTURE_1D: 67 case TEXTURE_2D: 68 case TEXTURE_3D: 69 case TEXTURE_CUBE: 70 case TEXTURE_1D_ARRAY: 71 case TEXTURE_2D_ARRAY: 72 case TEXTURE_CUBE_ARRAY: 73 case TEXTURE_2D_MSAA: 74 case TEXTURE_2D_ARRAY_MSAA: 75 useShadowVariant = false; 76 break; 77 case TEXTURE_SHADOW1D: 78 case TEXTURE_SHADOW2D: 79 case TEXTURE_SHADOWRECT: 80 case TEXTURE_SHADOW1D_ARRAY: 81 case TEXTURE_SHADOW2D_ARRAY: 82 case TEXTURE_SHADOWCUBE: 83 case TEXTURE_SHADOWCUBE_ARRAY: 84 useShadowVariant = true; 85 break; 86 default: 87 llvm_unreachable("Unknow Texture Type"); 88 } 89 90 if (TextureType == TEXTURE_RECT || 91 TextureType == TEXTURE_SHADOWRECT) { 92 CT[0] = 0; 93 CT[1] = 0; 94 } 95 96 if (TextureType == TEXTURE_CUBE_ARRAY || 97 TextureType == TEXTURE_SHADOWCUBE_ARRAY) 98 CT[2] = 0; 99 100 if (TextureType == TEXTURE_1D_ARRAY || 101 TextureType == TEXTURE_SHADOW1D_ARRAY) { 102 if (hasLOD && useShadowVariant) { 103 CT[1] = 0; 104 } else { 105 CT[2] = 0; 106 SrcSelect[2] = 1; 107 } 108 } else if (TextureType == TEXTURE_2D_ARRAY || 109 TextureType == TEXTURE_SHADOW2D_ARRAY) { 110 CT[2] = 0; 111 } 112 113 if ((TextureType == TEXTURE_SHADOW1D || 114 TextureType == TEXTURE_SHADOW2D || 115 TextureType == TEXTURE_SHADOWRECT || 116 TextureType == TEXTURE_SHADOW1D_ARRAY) && 117 !(hasLOD && useShadowVariant)) 118 SrcSelect[3] = 2; 119 } 120 121 void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name, 122 unsigned SrcSelect[4], Value *Offset[3], Value *Resource, 123 Value *Sampler, unsigned CT[4], Value *Coord) { 124 IRBuilder<> Builder(&I); 125 Constant *Mask[] = { 126 ConstantInt::get(Int32Type, SrcSelect[0]), 127 ConstantInt::get(Int32Type, SrcSelect[1]), 128 ConstantInt::get(Int32Type, SrcSelect[2]), 129 ConstantInt::get(Int32Type, SrcSelect[3]) 130 }; 131 Value *SwizzleMask = ConstantVector::get(Mask); 132 Value *SwizzledCoord = 133 Builder.CreateShuffleVector(Coord, Coord, SwizzleMask); 134 135 Value *Args[] = { 136 SwizzledCoord, 137 Offset[0], 138 Offset[1], 139 Offset[2], 140 Resource, 141 Sampler, 142 ConstantInt::get(Int32Type, CT[0]), 143 ConstantInt::get(Int32Type, CT[1]), 144 ConstantInt::get(Int32Type, CT[2]), 145 ConstantInt::get(Int32Type, CT[3]) 146 }; 147 148 Function *F = Mod->getFunction(Name); 149 if (!F) { 150 F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod); 151 F->addFnAttr(Attribute::ReadNone); 152 } 153 I.replaceAllUsesWith(Builder.CreateCall(F, Args)); 154 I.eraseFromParent(); 155 } 156 157 void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT, 158 const char *VanillaInt, 159 const char *ShadowInt) { 160 Value *Coord = I.getArgOperand(0); 161 Value *ResourceId = I.getArgOperand(1); 162 Value *SamplerId = I.getArgOperand(2); 163 164 unsigned TextureType = 165 dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue(); 166 167 unsigned SrcSelect[4] = { 0, 1, 2, 3 }; 168 unsigned CT[4] = {1, 1, 1, 1}; 169 Value *Offset[3] = { 170 ConstantInt::get(Int32Type, 0), 171 ConstantInt::get(Int32Type, 0), 172 ConstantInt::get(Int32Type, 0) 173 }; 174 bool useShadowVariant; 175 176 getAdjustmentFromTextureTarget(TextureType, hasLOD, SrcSelect, CT, 177 useShadowVariant); 178 179 ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect, 180 Offset, ResourceId, SamplerId, CT, Coord); 181 } 182 183 void ReplaceTXF(CallInst &I) { 184 Value *Coord = I.getArgOperand(0); 185 Value *ResourceId = I.getArgOperand(4); 186 Value *SamplerId = I.getArgOperand(5); 187 188 unsigned TextureType = 189 dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue(); 190 191 unsigned SrcSelect[4] = { 0, 1, 2, 3 }; 192 unsigned CT[4] = {1, 1, 1, 1}; 193 Value *Offset[3] = { 194 I.getArgOperand(1), 195 I.getArgOperand(2), 196 I.getArgOperand(3), 197 }; 198 bool useShadowVariant; 199 200 getAdjustmentFromTextureTarget(TextureType, false, SrcSelect, CT, 201 useShadowVariant); 202 203 ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect, 204 Offset, ResourceId, SamplerId, CT, Coord); 205 } 206 207 public: 208 R600TextureIntrinsicsReplacer(): 209 FunctionPass(ID) { 210 } 211 212 bool doInitialization(Module &M) override { 213 LLVMContext &Ctx = M.getContext(); 214 Mod = &M; 215 FloatType = Type::getFloatTy(Ctx); 216 Int32Type = Type::getInt32Ty(Ctx); 217 V4f32Type = VectorType::get(FloatType, 4); 218 V4i32Type = VectorType::get(Int32Type, 4); 219 Type *ArgsType[] = { 220 V4f32Type, 221 Int32Type, 222 Int32Type, 223 Int32Type, 224 Int32Type, 225 Int32Type, 226 Int32Type, 227 Int32Type, 228 Int32Type, 229 Int32Type, 230 }; 231 TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false); 232 Type *ArgsQType[] = { 233 V4i32Type, 234 Int32Type, 235 Int32Type, 236 Int32Type, 237 Int32Type, 238 Int32Type, 239 Int32Type, 240 Int32Type, 241 Int32Type, 242 Int32Type, 243 }; 244 TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false); 245 return false; 246 } 247 248 bool runOnFunction(Function &F) override { 249 visit(F); 250 return false; 251 } 252 253 const char *getPassName() const override { 254 return "R600 Texture Intrinsics Replacer"; 255 } 256 257 void getAnalysisUsage(AnalysisUsage &AU) const override { 258 } 259 260 void visitCallInst(CallInst &I) { 261 if (!I.getCalledFunction()) 262 return; 263 264 StringRef Name = I.getCalledFunction()->getName(); 265 if (Name == "llvm.AMDGPU.tex") { 266 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc"); 267 return; 268 } 269 if (Name == "llvm.AMDGPU.txl") { 270 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc"); 271 return; 272 } 273 if (Name == "llvm.AMDGPU.txb") { 274 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc"); 275 return; 276 } 277 if (Name == "llvm.AMDGPU.txf") { 278 ReplaceTXF(I); 279 return; 280 } 281 if (Name == "llvm.AMDGPU.txq") { 282 ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq"); 283 return; 284 } 285 if (Name == "llvm.AMDGPU.ddx") { 286 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx"); 287 return; 288 } 289 if (Name == "llvm.AMDGPU.ddy") { 290 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy"); 291 return; 292 } 293 } 294 295 }; 296 297 char R600TextureIntrinsicsReplacer::ID = 0; 298 299 } 300 301 FunctionPass *llvm::createR600TextureIntrinsicsReplacer() { 302 return new R600TextureIntrinsicsReplacer(); 303 } 304