Home | History | Annotate | Download | only in R600
      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 
     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 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 
    208 public:
    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 
    295 char R600TextureIntrinsicsReplacer::ID = 0;
    296 
    297 }
    298 
    299 FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
    300   return new R600TextureIntrinsicsReplacer();
    301 }
    302