|  | //===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | /// \file | 
|  | /// This pass translates tgsi-like texture intrinsics into R600 texture | 
|  | /// closer to hardware intrinsics. | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "AMDGPU.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/Analysis/Passes.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/GlobalValue.h" | 
|  | #include "llvm/IR/IRBuilder.h" | 
|  | #include "llvm/IR/InstVisitor.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  | class R600TextureIntrinsicsReplacer : | 
|  | public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> { | 
|  | static char ID; | 
|  |  | 
|  | Module *Mod; | 
|  | Type *FloatType; | 
|  | Type *Int32Type; | 
|  | Type *V4f32Type; | 
|  | Type *V4i32Type; | 
|  | FunctionType *TexSign; | 
|  | FunctionType *TexQSign; | 
|  |  | 
|  | void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD, | 
|  | unsigned SrcSelect[4], unsigned CT[4], | 
|  | bool &useShadowVariant) { | 
|  | enum TextureTypes { | 
|  | TEXTURE_1D = 1, | 
|  | TEXTURE_2D, | 
|  | TEXTURE_3D, | 
|  | TEXTURE_CUBE, | 
|  | TEXTURE_RECT, | 
|  | TEXTURE_SHADOW1D, | 
|  | TEXTURE_SHADOW2D, | 
|  | TEXTURE_SHADOWRECT, | 
|  | TEXTURE_1D_ARRAY, | 
|  | TEXTURE_2D_ARRAY, | 
|  | TEXTURE_SHADOW1D_ARRAY, | 
|  | TEXTURE_SHADOW2D_ARRAY, | 
|  | TEXTURE_SHADOWCUBE, | 
|  | TEXTURE_2D_MSAA, | 
|  | TEXTURE_2D_ARRAY_MSAA, | 
|  | TEXTURE_CUBE_ARRAY, | 
|  | TEXTURE_SHADOWCUBE_ARRAY | 
|  | }; | 
|  |  | 
|  | switch (TextureType) { | 
|  | case 0: | 
|  | useShadowVariant = false; | 
|  | return; | 
|  | case TEXTURE_RECT: | 
|  | case TEXTURE_1D: | 
|  | case TEXTURE_2D: | 
|  | case TEXTURE_3D: | 
|  | case TEXTURE_CUBE: | 
|  | case TEXTURE_1D_ARRAY: | 
|  | case TEXTURE_2D_ARRAY: | 
|  | case TEXTURE_CUBE_ARRAY: | 
|  | case TEXTURE_2D_MSAA: | 
|  | case TEXTURE_2D_ARRAY_MSAA: | 
|  | useShadowVariant = false; | 
|  | break; | 
|  | case TEXTURE_SHADOW1D: | 
|  | case TEXTURE_SHADOW2D: | 
|  | case TEXTURE_SHADOWRECT: | 
|  | case TEXTURE_SHADOW1D_ARRAY: | 
|  | case TEXTURE_SHADOW2D_ARRAY: | 
|  | case TEXTURE_SHADOWCUBE: | 
|  | case TEXTURE_SHADOWCUBE_ARRAY: | 
|  | useShadowVariant = true; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Unknow Texture Type"); | 
|  | } | 
|  |  | 
|  | if (TextureType == TEXTURE_RECT || | 
|  | TextureType == TEXTURE_SHADOWRECT) { | 
|  | CT[0] = 0; | 
|  | CT[1] = 0; | 
|  | } | 
|  |  | 
|  | if (TextureType == TEXTURE_CUBE_ARRAY || | 
|  | TextureType == TEXTURE_SHADOWCUBE_ARRAY) | 
|  | CT[2] = 0; | 
|  |  | 
|  | if (TextureType == TEXTURE_1D_ARRAY || | 
|  | TextureType == TEXTURE_SHADOW1D_ARRAY) { | 
|  | if (hasLOD && useShadowVariant) { | 
|  | CT[1] = 0; | 
|  | } else { | 
|  | CT[2] = 0; | 
|  | SrcSelect[2] = 1; | 
|  | } | 
|  | } else if (TextureType == TEXTURE_2D_ARRAY || | 
|  | TextureType == TEXTURE_SHADOW2D_ARRAY) { | 
|  | CT[2] = 0; | 
|  | } | 
|  |  | 
|  | if ((TextureType == TEXTURE_SHADOW1D || | 
|  | TextureType == TEXTURE_SHADOW2D || | 
|  | TextureType == TEXTURE_SHADOWRECT || | 
|  | TextureType == TEXTURE_SHADOW1D_ARRAY) && | 
|  | !(hasLOD && useShadowVariant)) | 
|  | SrcSelect[3] = 2; | 
|  | } | 
|  |  | 
|  | void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name, | 
|  | unsigned SrcSelect[4], Value *Offset[3], Value *Resource, | 
|  | Value *Sampler, unsigned CT[4], Value *Coord) { | 
|  | IRBuilder<> Builder(&I); | 
|  | Constant *Mask[] = { | 
|  | ConstantInt::get(Int32Type, SrcSelect[0]), | 
|  | ConstantInt::get(Int32Type, SrcSelect[1]), | 
|  | ConstantInt::get(Int32Type, SrcSelect[2]), | 
|  | ConstantInt::get(Int32Type, SrcSelect[3]) | 
|  | }; | 
|  | Value *SwizzleMask = ConstantVector::get(Mask); | 
|  | Value *SwizzledCoord = | 
|  | Builder.CreateShuffleVector(Coord, Coord, SwizzleMask); | 
|  |  | 
|  | Value *Args[] = { | 
|  | SwizzledCoord, | 
|  | Offset[0], | 
|  | Offset[1], | 
|  | Offset[2], | 
|  | Resource, | 
|  | Sampler, | 
|  | ConstantInt::get(Int32Type, CT[0]), | 
|  | ConstantInt::get(Int32Type, CT[1]), | 
|  | ConstantInt::get(Int32Type, CT[2]), | 
|  | ConstantInt::get(Int32Type, CT[3]) | 
|  | }; | 
|  |  | 
|  | Function *F = Mod->getFunction(Name); | 
|  | if (!F) { | 
|  | F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod); | 
|  | F->addFnAttr(Attribute::ReadNone); | 
|  | } | 
|  | I.replaceAllUsesWith(Builder.CreateCall(F, Args)); | 
|  | I.eraseFromParent(); | 
|  | } | 
|  |  | 
|  | void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT, | 
|  | const char *VanillaInt, | 
|  | const char *ShadowInt) { | 
|  | Value *Coord = I.getArgOperand(0); | 
|  | Value *ResourceId = I.getArgOperand(1); | 
|  | Value *SamplerId = I.getArgOperand(2); | 
|  |  | 
|  | unsigned TextureType = | 
|  | dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue(); | 
|  |  | 
|  | unsigned SrcSelect[4] = { 0, 1, 2, 3 }; | 
|  | unsigned CT[4] = {1, 1, 1, 1}; | 
|  | Value *Offset[3] = { | 
|  | ConstantInt::get(Int32Type, 0), | 
|  | ConstantInt::get(Int32Type, 0), | 
|  | ConstantInt::get(Int32Type, 0) | 
|  | }; | 
|  | bool useShadowVariant; | 
|  |  | 
|  | getAdjustmentFromTextureTarget(TextureType, hasLOD, SrcSelect, CT, | 
|  | useShadowVariant); | 
|  |  | 
|  | ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect, | 
|  | Offset, ResourceId, SamplerId, CT, Coord); | 
|  | } | 
|  |  | 
|  | void ReplaceTXF(CallInst &I) { | 
|  | Value *Coord = I.getArgOperand(0); | 
|  | Value *ResourceId = I.getArgOperand(4); | 
|  | Value *SamplerId = I.getArgOperand(5); | 
|  |  | 
|  | unsigned TextureType = | 
|  | dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue(); | 
|  |  | 
|  | unsigned SrcSelect[4] = { 0, 1, 2, 3 }; | 
|  | unsigned CT[4] = {1, 1, 1, 1}; | 
|  | Value *Offset[3] = { | 
|  | I.getArgOperand(1), | 
|  | I.getArgOperand(2), | 
|  | I.getArgOperand(3), | 
|  | }; | 
|  | bool useShadowVariant; | 
|  |  | 
|  | getAdjustmentFromTextureTarget(TextureType, false, SrcSelect, CT, | 
|  | useShadowVariant); | 
|  |  | 
|  | ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect, | 
|  | Offset, ResourceId, SamplerId, CT, Coord); | 
|  | } | 
|  |  | 
|  | public: | 
|  | R600TextureIntrinsicsReplacer(): | 
|  | FunctionPass(ID) { | 
|  | } | 
|  |  | 
|  | bool doInitialization(Module &M) override { | 
|  | LLVMContext &Ctx = M.getContext(); | 
|  | Mod = &M; | 
|  | FloatType = Type::getFloatTy(Ctx); | 
|  | Int32Type = Type::getInt32Ty(Ctx); | 
|  | V4f32Type = VectorType::get(FloatType, 4); | 
|  | V4i32Type = VectorType::get(Int32Type, 4); | 
|  | Type *ArgsType[] = { | 
|  | V4f32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | }; | 
|  | TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false); | 
|  | Type *ArgsQType[] = { | 
|  | V4i32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | Int32Type, | 
|  | }; | 
|  | TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool runOnFunction(Function &F) override { | 
|  | visit(F); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const char *getPassName() const override { | 
|  | return "R600 Texture Intrinsics Replacer"; | 
|  | } | 
|  |  | 
|  | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
|  | } | 
|  |  | 
|  | void visitCallInst(CallInst &I) { | 
|  | if (!I.getCalledFunction()) | 
|  | return; | 
|  |  | 
|  | StringRef Name = I.getCalledFunction()->getName(); | 
|  | if (Name == "llvm.AMDGPU.tex") { | 
|  | ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc"); | 
|  | return; | 
|  | } | 
|  | if (Name == "llvm.AMDGPU.txl") { | 
|  | ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc"); | 
|  | return; | 
|  | } | 
|  | if (Name == "llvm.AMDGPU.txb") { | 
|  | ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc"); | 
|  | return; | 
|  | } | 
|  | if (Name == "llvm.AMDGPU.txf") { | 
|  | ReplaceTXF(I); | 
|  | return; | 
|  | } | 
|  | if (Name == "llvm.AMDGPU.txq") { | 
|  | ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq"); | 
|  | return; | 
|  | } | 
|  | if (Name == "llvm.AMDGPU.ddx") { | 
|  | ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx"); | 
|  | return; | 
|  | } | 
|  | if (Name == "llvm.AMDGPU.ddy") { | 
|  | ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy"); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | }; | 
|  |  | 
|  | char R600TextureIntrinsicsReplacer::ID = 0; | 
|  |  | 
|  | } | 
|  |  | 
|  | FunctionPass *llvm::createR600TextureIntrinsicsReplacer() { | 
|  | return new R600TextureIntrinsicsReplacer(); | 
|  | } |