1259698Sdim//===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===// 2259698Sdim// 3259698Sdim// The LLVM Compiler Infrastructure 4259698Sdim// 5259698Sdim// This file is distributed under the University of Illinois Open Source 6259698Sdim// License. See LICENSE.TXT for details. 7259698Sdim// 8259698Sdim//===----------------------------------------------------------------------===// 9259698Sdim// 10259698Sdim/// \file 11259698Sdim/// This pass translates tgsi-like texture intrinsics into R600 texture 12259698Sdim/// closer to hardware intrinsics. 13259698Sdim//===----------------------------------------------------------------------===// 14259698Sdim 15259698Sdim#include "AMDGPU.h" 16259698Sdim#include "llvm/ADT/Statistic.h" 17259698Sdim#include "llvm/Analysis/Passes.h" 18259698Sdim#include "llvm/IR/Function.h" 19259698Sdim#include "llvm/IR/GlobalValue.h" 20259698Sdim#include "llvm/IR/IRBuilder.h" 21259698Sdim#include "llvm/InstVisitor.h" 22259698Sdim 23259698Sdimusing namespace llvm; 24259698Sdim 25259698Sdimnamespace { 26259698Sdimclass R600TextureIntrinsicsReplacer : 27259698Sdim public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> { 28259698Sdim static char ID; 29259698Sdim 30259698Sdim Module *Mod; 31259698Sdim Type *FloatType; 32259698Sdim Type *Int32Type; 33259698Sdim Type *V4f32Type; 34259698Sdim Type *V4i32Type; 35259698Sdim FunctionType *TexSign; 36259698Sdim FunctionType *TexQSign; 37259698Sdim 38259698Sdim void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD, 39259698Sdim unsigned SrcSelect[4], unsigned CT[4], 40259698Sdim bool &useShadowVariant) { 41259698Sdim enum TextureTypes { 42259698Sdim TEXTURE_1D = 1, 43259698Sdim TEXTURE_2D, 44259698Sdim TEXTURE_3D, 45259698Sdim TEXTURE_CUBE, 46259698Sdim TEXTURE_RECT, 47259698Sdim TEXTURE_SHADOW1D, 48259698Sdim TEXTURE_SHADOW2D, 49259698Sdim TEXTURE_SHADOWRECT, 50259698Sdim TEXTURE_1D_ARRAY, 51259698Sdim TEXTURE_2D_ARRAY, 52259698Sdim TEXTURE_SHADOW1D_ARRAY, 53259698Sdim TEXTURE_SHADOW2D_ARRAY, 54259698Sdim TEXTURE_SHADOWCUBE, 55259698Sdim TEXTURE_2D_MSAA, 56259698Sdim TEXTURE_2D_ARRAY_MSAA, 57259698Sdim TEXTURE_CUBE_ARRAY, 58259698Sdim TEXTURE_SHADOWCUBE_ARRAY 59259698Sdim }; 60259698Sdim 61259698Sdim switch (TextureType) { 62259698Sdim case 0: 63259698Sdim useShadowVariant = false; 64259698Sdim return; 65259698Sdim case TEXTURE_RECT: 66259698Sdim case TEXTURE_1D: 67259698Sdim case TEXTURE_2D: 68259698Sdim case TEXTURE_3D: 69259698Sdim case TEXTURE_CUBE: 70259698Sdim case TEXTURE_1D_ARRAY: 71259698Sdim case TEXTURE_2D_ARRAY: 72259698Sdim case TEXTURE_CUBE_ARRAY: 73259698Sdim case TEXTURE_2D_MSAA: 74259698Sdim case TEXTURE_2D_ARRAY_MSAA: 75259698Sdim useShadowVariant = false; 76259698Sdim break; 77259698Sdim case TEXTURE_SHADOW1D: 78259698Sdim case TEXTURE_SHADOW2D: 79259698Sdim case TEXTURE_SHADOWRECT: 80259698Sdim case TEXTURE_SHADOW1D_ARRAY: 81259698Sdim case TEXTURE_SHADOW2D_ARRAY: 82259698Sdim case TEXTURE_SHADOWCUBE: 83259698Sdim case TEXTURE_SHADOWCUBE_ARRAY: 84259698Sdim useShadowVariant = true; 85259698Sdim break; 86259698Sdim default: 87259698Sdim llvm_unreachable("Unknow Texture Type"); 88259698Sdim } 89259698Sdim 90259698Sdim if (TextureType == TEXTURE_RECT || 91259698Sdim TextureType == TEXTURE_SHADOWRECT) { 92259698Sdim CT[0] = 0; 93259698Sdim CT[1] = 0; 94259698Sdim } 95259698Sdim 96259698Sdim if (TextureType == TEXTURE_CUBE_ARRAY || 97259698Sdim TextureType == TEXTURE_SHADOWCUBE_ARRAY) 98259698Sdim CT[2] = 0; 99259698Sdim 100259698Sdim if (TextureType == TEXTURE_1D_ARRAY || 101259698Sdim TextureType == TEXTURE_SHADOW1D_ARRAY) { 102259698Sdim if (hasLOD && useShadowVariant) { 103259698Sdim CT[1] = 0; 104259698Sdim } else { 105259698Sdim CT[2] = 0; 106259698Sdim SrcSelect[2] = 1; 107259698Sdim } 108259698Sdim } else if (TextureType == TEXTURE_2D_ARRAY || 109259698Sdim TextureType == TEXTURE_SHADOW2D_ARRAY) { 110259698Sdim CT[2] = 0; 111259698Sdim } 112259698Sdim 113259698Sdim if ((TextureType == TEXTURE_SHADOW1D || 114259698Sdim TextureType == TEXTURE_SHADOW2D || 115259698Sdim TextureType == TEXTURE_SHADOWRECT || 116259698Sdim TextureType == TEXTURE_SHADOW1D_ARRAY) && 117259698Sdim !(hasLOD && useShadowVariant)) 118259698Sdim SrcSelect[3] = 2; 119259698Sdim } 120259698Sdim 121259698Sdim void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name, 122259698Sdim unsigned SrcSelect[4], Value *Offset[3], Value *Resource, 123259698Sdim Value *Sampler, unsigned CT[4], Value *Coord) { 124259698Sdim IRBuilder<> Builder(&I); 125259698Sdim Constant *Mask[] = { 126259698Sdim ConstantInt::get(Int32Type, SrcSelect[0]), 127259698Sdim ConstantInt::get(Int32Type, SrcSelect[1]), 128259698Sdim ConstantInt::get(Int32Type, SrcSelect[2]), 129259698Sdim ConstantInt::get(Int32Type, SrcSelect[3]) 130259698Sdim }; 131259698Sdim Value *SwizzleMask = ConstantVector::get(Mask); 132259698Sdim Value *SwizzledCoord = 133259698Sdim Builder.CreateShuffleVector(Coord, Coord, SwizzleMask); 134259698Sdim 135259698Sdim Value *Args[] = { 136259698Sdim SwizzledCoord, 137259698Sdim Offset[0], 138259698Sdim Offset[1], 139259698Sdim Offset[2], 140259698Sdim Resource, 141259698Sdim Sampler, 142259698Sdim ConstantInt::get(Int32Type, CT[0]), 143259698Sdim ConstantInt::get(Int32Type, CT[1]), 144259698Sdim ConstantInt::get(Int32Type, CT[2]), 145259698Sdim ConstantInt::get(Int32Type, CT[3]) 146259698Sdim }; 147259698Sdim 148259698Sdim Function *F = Mod->getFunction(Name); 149259698Sdim if (!F) { 150259698Sdim F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod); 151259698Sdim F->addFnAttr(Attribute::ReadNone); 152259698Sdim } 153259698Sdim I.replaceAllUsesWith(Builder.CreateCall(F, Args)); 154259698Sdim I.eraseFromParent(); 155259698Sdim } 156259698Sdim 157259698Sdim void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT, 158259698Sdim const char *VanillaInt, 159259698Sdim const char *ShadowInt) { 160259698Sdim Value *Coord = I.getArgOperand(0); 161259698Sdim Value *ResourceId = I.getArgOperand(1); 162259698Sdim Value *SamplerId = I.getArgOperand(2); 163259698Sdim 164259698Sdim unsigned TextureType = 165259698Sdim dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue(); 166259698Sdim 167259698Sdim unsigned SrcSelect[4] = { 0, 1, 2, 3 }; 168259698Sdim unsigned CT[4] = {1, 1, 1, 1}; 169259698Sdim Value *Offset[3] = { 170259698Sdim ConstantInt::get(Int32Type, 0), 171259698Sdim ConstantInt::get(Int32Type, 0), 172259698Sdim ConstantInt::get(Int32Type, 0) 173259698Sdim }; 174259698Sdim bool useShadowVariant; 175259698Sdim 176259698Sdim getAdjustmentFromTextureTarget(TextureType, hasLOD, SrcSelect, CT, 177259698Sdim useShadowVariant); 178259698Sdim 179259698Sdim ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect, 180259698Sdim Offset, ResourceId, SamplerId, CT, Coord); 181259698Sdim } 182259698Sdim 183259698Sdim void ReplaceTXF(CallInst &I) { 184259698Sdim Value *Coord = I.getArgOperand(0); 185259698Sdim Value *ResourceId = I.getArgOperand(4); 186259698Sdim Value *SamplerId = I.getArgOperand(5); 187259698Sdim 188259698Sdim unsigned TextureType = 189259698Sdim dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue(); 190259698Sdim 191259698Sdim unsigned SrcSelect[4] = { 0, 1, 2, 3 }; 192259698Sdim unsigned CT[4] = {1, 1, 1, 1}; 193259698Sdim Value *Offset[3] = { 194259698Sdim I.getArgOperand(1), 195259698Sdim I.getArgOperand(2), 196259698Sdim I.getArgOperand(3), 197259698Sdim }; 198259698Sdim bool useShadowVariant; 199259698Sdim 200259698Sdim getAdjustmentFromTextureTarget(TextureType, false, SrcSelect, CT, 201259698Sdim useShadowVariant); 202259698Sdim 203259698Sdim ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect, 204259698Sdim Offset, ResourceId, SamplerId, CT, Coord); 205259698Sdim } 206259698Sdim 207259698Sdimpublic: 208259698Sdim R600TextureIntrinsicsReplacer(): 209259698Sdim FunctionPass(ID) { 210259698Sdim } 211259698Sdim 212259698Sdim virtual bool doInitialization(Module &M) { 213259698Sdim LLVMContext &Ctx = M.getContext(); 214259698Sdim Mod = &M; 215259698Sdim FloatType = Type::getFloatTy(Ctx); 216259698Sdim Int32Type = Type::getInt32Ty(Ctx); 217259698Sdim V4f32Type = VectorType::get(FloatType, 4); 218259698Sdim V4i32Type = VectorType::get(Int32Type, 4); 219259698Sdim Type *ArgsType[] = { 220259698Sdim V4f32Type, 221259698Sdim Int32Type, 222259698Sdim Int32Type, 223259698Sdim Int32Type, 224259698Sdim Int32Type, 225259698Sdim Int32Type, 226259698Sdim Int32Type, 227259698Sdim Int32Type, 228259698Sdim Int32Type, 229259698Sdim Int32Type, 230259698Sdim }; 231259698Sdim TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false); 232259698Sdim Type *ArgsQType[] = { 233259698Sdim V4i32Type, 234259698Sdim Int32Type, 235259698Sdim Int32Type, 236259698Sdim Int32Type, 237259698Sdim Int32Type, 238259698Sdim Int32Type, 239259698Sdim Int32Type, 240259698Sdim Int32Type, 241259698Sdim Int32Type, 242259698Sdim Int32Type, 243259698Sdim }; 244259698Sdim TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false); 245259698Sdim return false; 246259698Sdim } 247259698Sdim 248259698Sdim virtual bool runOnFunction(Function &F) { 249259698Sdim visit(F); 250259698Sdim return false; 251259698Sdim } 252259698Sdim 253259698Sdim virtual const char *getPassName() const { 254259698Sdim return "R600 Texture Intrinsics Replacer"; 255259698Sdim } 256259698Sdim 257259698Sdim void getAnalysisUsage(AnalysisUsage &AU) const { 258259698Sdim } 259259698Sdim 260259698Sdim void visitCallInst(CallInst &I) { 261259698Sdim if (!I.getCalledFunction()) 262259698Sdim return; 263259698Sdim 264259698Sdim StringRef Name = I.getCalledFunction()->getName(); 265259698Sdim if (Name == "llvm.AMDGPU.tex") { 266259698Sdim ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc"); 267259698Sdim return; 268259698Sdim } 269259698Sdim if (Name == "llvm.AMDGPU.txl") { 270259698Sdim ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc"); 271259698Sdim return; 272259698Sdim } 273259698Sdim if (Name == "llvm.AMDGPU.txb") { 274259698Sdim ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc"); 275259698Sdim return; 276259698Sdim } 277259698Sdim if (Name == "llvm.AMDGPU.txf") { 278259698Sdim ReplaceTXF(I); 279259698Sdim return; 280259698Sdim } 281259698Sdim if (Name == "llvm.AMDGPU.txq") { 282259698Sdim ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq"); 283259698Sdim return; 284259698Sdim } 285259698Sdim if (Name == "llvm.AMDGPU.ddx") { 286259698Sdim ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx"); 287259698Sdim return; 288259698Sdim } 289259698Sdim if (Name == "llvm.AMDGPU.ddy") { 290259698Sdim ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy"); 291259698Sdim return; 292259698Sdim } 293259698Sdim } 294259698Sdim 295259698Sdim}; 296259698Sdim 297259698Sdimchar R600TextureIntrinsicsReplacer::ID = 0; 298259698Sdim 299259698Sdim} 300259698Sdim 301259698SdimFunctionPass *llvm::createR600TextureIntrinsicsReplacer() { 302259698Sdim return new R600TextureIntrinsicsReplacer(); 303259698Sdim} 304