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/InstVisitor.h" 22 23using namespace llvm; 24 25namespace { 26class 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 getAdjustementFromTextureTarget(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 return; 64 case TEXTURE_RECT: 65 case TEXTURE_1D: 66 case TEXTURE_2D: 67 case TEXTURE_3D: 68 case TEXTURE_CUBE: 69 case TEXTURE_1D_ARRAY: 70 case TEXTURE_2D_ARRAY: 71 case TEXTURE_CUBE_ARRAY: 72 case TEXTURE_2D_MSAA: 73 case TEXTURE_2D_ARRAY_MSAA: 74 useShadowVariant = false; 75 break; 76 case TEXTURE_SHADOW1D: 77 case TEXTURE_SHADOW2D: 78 case TEXTURE_SHADOWRECT: 79 case TEXTURE_SHADOW1D_ARRAY: 80 case TEXTURE_SHADOW2D_ARRAY: 81 case TEXTURE_SHADOWCUBE: 82 case TEXTURE_SHADOWCUBE_ARRAY: 83 useShadowVariant = true; 84 break; 85 default: 86 llvm_unreachable("Unknow Texture Type"); 87 } 88 89 if (TextureType == TEXTURE_RECT || 90 TextureType == TEXTURE_SHADOWRECT) { 91 CT[0] = 0; 92 CT[1] = 0; 93 } 94 95 if (TextureType == TEXTURE_CUBE_ARRAY || 96 TextureType == TEXTURE_SHADOWCUBE_ARRAY) { 97 CT[2] = 0; 98 } 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 122 void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name, 123 unsigned SrcSelect[4], Value *Offset[3], Value *Resource, 124 Value *Sampler, unsigned CT[4], Value *Coord) { 125 IRBuilder<> Builder(&I); 126 Constant *Mask[] = { 127 ConstantInt::get(Int32Type, SrcSelect[0]), 128 ConstantInt::get(Int32Type, SrcSelect[1]), 129 ConstantInt::get(Int32Type, SrcSelect[2]), 130 ConstantInt::get(Int32Type, SrcSelect[3]) 131 }; 132 Value *SwizzleMask = ConstantVector::get(Mask); 133 Value *SwizzledCoord = 134 Builder.CreateShuffleVector(Coord, Coord, SwizzleMask); 135 136 Value *Args[] = { 137 SwizzledCoord, 138 Offset[0], 139 Offset[1], 140 Offset[2], 141 Resource, 142 Sampler, 143 ConstantInt::get(Int32Type, CT[0]), 144 ConstantInt::get(Int32Type, CT[1]), 145 ConstantInt::get(Int32Type, CT[2]), 146 ConstantInt::get(Int32Type, CT[3]) 147 }; 148 149 Function *F = Mod->getFunction(Name); 150 if (!F) { 151 F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod); 152 F->addFnAttr(Attribute::ReadNone); 153 } 154 I.replaceAllUsesWith(Builder.CreateCall(F, Args)); 155 I.eraseFromParent(); 156 } 157 158 void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT, 159 const char *VanillaInt, 160 const char *ShadowInt) { 161 Value *Coord = I.getArgOperand(0); 162 Value *ResourceId = I.getArgOperand(1); 163 Value *SamplerId = I.getArgOperand(2); 164 165 unsigned TextureType = 166 dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue(); 167 168 unsigned SrcSelect[4] = { 0, 1, 2, 3 }; 169 unsigned CT[4] = {1, 1, 1, 1}; 170 Value *Offset[3] = { 171 ConstantInt::get(Int32Type, 0), 172 ConstantInt::get(Int32Type, 0), 173 ConstantInt::get(Int32Type, 0) 174 }; 175 bool useShadowVariant; 176 177 getAdjustementFromTextureTarget(TextureType, hasLOD, SrcSelect, CT, 178 useShadowVariant); 179 180 ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect, 181 Offset, ResourceId, SamplerId, CT, Coord); 182 } 183 184 void ReplaceTXF(CallInst &I) { 185 Value *Coord = I.getArgOperand(0); 186 Value *ResourceId = I.getArgOperand(4); 187 Value *SamplerId = I.getArgOperand(5); 188 189 unsigned TextureType = 190 dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue(); 191 192 unsigned SrcSelect[4] = { 0, 1, 2, 3 }; 193 unsigned CT[4] = {1, 1, 1, 1}; 194 Value *Offset[3] = { 195 I.getArgOperand(1), 196 I.getArgOperand(2), 197 I.getArgOperand(3), 198 }; 199 bool useShadowVariant; 200 201 getAdjustementFromTextureTarget(TextureType, false, SrcSelect, CT, 202 useShadowVariant); 203 204 ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect, 205 Offset, ResourceId, SamplerId, CT, Coord); 206 } 207 208public: 209 R600TextureIntrinsicsReplacer(): 210 FunctionPass(ID) { 211 } 212 213 virtual bool doInitialization(Module &M) { 214 LLVMContext &Ctx = M.getContext(); 215 Mod = &M; 216 FloatType = Type::getFloatTy(Ctx); 217 Int32Type = Type::getInt32Ty(Ctx); 218 V4f32Type = VectorType::get(FloatType, 4); 219 V4i32Type = VectorType::get(Int32Type, 4); 220 Type *ArgsType[] = { 221 V4f32Type, 222 Int32Type, 223 Int32Type, 224 Int32Type, 225 Int32Type, 226 Int32Type, 227 Int32Type, 228 Int32Type, 229 Int32Type, 230 Int32Type, 231 }; 232 TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false); 233 Type *ArgsQType[] = { 234 V4i32Type, 235 Int32Type, 236 Int32Type, 237 Int32Type, 238 Int32Type, 239 Int32Type, 240 Int32Type, 241 Int32Type, 242 Int32Type, 243 Int32Type, 244 }; 245 TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false); 246 return false; 247 } 248 249 virtual bool runOnFunction(Function &F) { 250 visit(F); 251 return false; 252 } 253 254 virtual const char *getPassName() const { 255 return "R600 Texture Intrinsics Replacer"; 256 } 257 258 void getAnalysisUsage(AnalysisUsage &AU) const { 259 } 260 261 void visitCallInst(CallInst &I) { 262 StringRef Name = I.getCalledFunction()->getName(); 263 if (Name == "llvm.AMDGPU.tex") { 264 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc"); 265 return; 266 } 267 if (Name == "llvm.AMDGPU.txl") { 268 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc"); 269 return; 270 } 271 if (Name == "llvm.AMDGPU.txb") { 272 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc"); 273 return; 274 } 275 if (Name == "llvm.AMDGPU.txf") { 276 ReplaceTXF(I); 277 return; 278 } 279 if (Name == "llvm.AMDGPU.txq") { 280 ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq"); 281 return; 282 } 283 if (Name == "llvm.AMDGPU.ddx") { 284 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx"); 285 return; 286 } 287 if (Name == "llvm.AMDGPU.ddy") { 288 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy"); 289 return; 290 } 291 } 292 293}; 294 295char R600TextureIntrinsicsReplacer::ID = 0; 296 297} 298 299FunctionPass *llvm::createR600TextureIntrinsicsReplacer() { 300 return new R600TextureIntrinsicsReplacer(); 301} 302