1178476Sjb//===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===// 2178476Sjb// 3178476Sjb// The LLVM Compiler Infrastructure 4178476Sjb// 5178476Sjb// This file is distributed under the University of Illinois Open Source 6178476Sjb// License. See LICENSE.TXT for details. 7178476Sjb// 8178476Sjb//===----------------------------------------------------------------------===// 9178476Sjb// 10178476Sjb/// \file 11178476Sjb/// This pass translates tgsi-like texture intrinsics into R600 texture 12178476Sjb/// closer to hardware intrinsics. 13178476Sjb//===----------------------------------------------------------------------===// 14178476Sjb 15178476Sjb#include "AMDGPU.h" 16178476Sjb#include "llvm/ADT/Statistic.h" 17178476Sjb#include "llvm/Analysis/Passes.h" 18178476Sjb#include "llvm/IR/Function.h" 19178476Sjb#include "llvm/IR/GlobalValue.h" 20178476Sjb#include "llvm/IR/IRBuilder.h" 21178476Sjb#include "llvm/InstVisitor.h" 22178476Sjb 23178476Sjbusing namespace llvm; 24178476Sjb 25178476Sjbnamespace { 26178476Sjbclass R600TextureIntrinsicsReplacer : 27178476Sjb public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> { 28178476Sjb static char ID; 29178476Sjb 30178476Sjb Module *Mod; 31178476Sjb Type *FloatType; 32178476Sjb Type *Int32Type; 33178476Sjb Type *V4f32Type; 34178476Sjb Type *V4i32Type; 35178476Sjb FunctionType *TexSign; 36178476Sjb FunctionType *TexQSign; 37178476Sjb 38178476Sjb void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD, 39178476Sjb unsigned SrcSelect[4], unsigned CT[4], 40178476Sjb bool &useShadowVariant) { 41178476Sjb enum TextureTypes { 42178476Sjb TEXTURE_1D = 1, 43178476Sjb TEXTURE_2D, 44178476Sjb TEXTURE_3D, 45178476Sjb TEXTURE_CUBE, 46178476Sjb TEXTURE_RECT, 47178476Sjb TEXTURE_SHADOW1D, 48178476Sjb TEXTURE_SHADOW2D, 49178476Sjb TEXTURE_SHADOWRECT, 50178476Sjb TEXTURE_1D_ARRAY, 51178476Sjb TEXTURE_2D_ARRAY, 52178476Sjb TEXTURE_SHADOW1D_ARRAY, 53178476Sjb TEXTURE_SHADOW2D_ARRAY, 54178476Sjb TEXTURE_SHADOWCUBE, 55178476Sjb TEXTURE_2D_MSAA, 56178476Sjb TEXTURE_2D_ARRAY_MSAA, 57178476Sjb TEXTURE_CUBE_ARRAY, 58178476Sjb TEXTURE_SHADOWCUBE_ARRAY 59178476Sjb }; 60178476Sjb 61178476Sjb switch (TextureType) { 62178476Sjb case 0: 63178476Sjb useShadowVariant = false; 64178476Sjb return; 65178476Sjb case TEXTURE_RECT: 66178476Sjb case TEXTURE_1D: 67178476Sjb case TEXTURE_2D: 68178476Sjb case TEXTURE_3D: 69178476Sjb case TEXTURE_CUBE: 70178476Sjb case TEXTURE_1D_ARRAY: 71178476Sjb case TEXTURE_2D_ARRAY: 72178476Sjb case TEXTURE_CUBE_ARRAY: 73178476Sjb case TEXTURE_2D_MSAA: 74178476Sjb case TEXTURE_2D_ARRAY_MSAA: 75178476Sjb useShadowVariant = false; 76178476Sjb break; 77178476Sjb case TEXTURE_SHADOW1D: 78178476Sjb case TEXTURE_SHADOW2D: 79178476Sjb case TEXTURE_SHADOWRECT: 80178476Sjb case TEXTURE_SHADOW1D_ARRAY: 81178476Sjb case TEXTURE_SHADOW2D_ARRAY: 82178476Sjb case TEXTURE_SHADOWCUBE: 83178476Sjb case TEXTURE_SHADOWCUBE_ARRAY: 84178476Sjb useShadowVariant = true; 85178476Sjb break; 86178476Sjb default: 87178476Sjb llvm_unreachable("Unknow Texture Type"); 88178476Sjb } 89178476Sjb 90178476Sjb if (TextureType == TEXTURE_RECT || 91178476Sjb TextureType == TEXTURE_SHADOWRECT) { 92178476Sjb CT[0] = 0; 93178476Sjb CT[1] = 0; 94211545Srpaulo } 95178476Sjb 96178476Sjb 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 207public: 208 R600TextureIntrinsicsReplacer(): 209 FunctionPass(ID) { 210 } 211 212 virtual bool doInitialization(Module &M) { 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 virtual bool runOnFunction(Function &F) { 249 visit(F); 250 return false; 251 } 252 253 virtual const char *getPassName() const { 254 return "R600 Texture Intrinsics Replacer"; 255 } 256 257 void getAnalysisUsage(AnalysisUsage &AU) const { 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 297char R600TextureIntrinsicsReplacer::ID = 0; 298 299} 300 301FunctionPass *llvm::createR600TextureIntrinsicsReplacer() { 302 return new R600TextureIntrinsicsReplacer(); 303} 304