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/IR/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 getAdjustmentFromTextureTarget(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       useShadowVariant = false;
     64       return;
     65     case TEXTURE_RECT:
     66     case TEXTURE_1D:
     67     case TEXTURE_2D:
     68     case TEXTURE_3D:
     69     case TEXTURE_CUBE:
     70     case TEXTURE_1D_ARRAY:
     71     case TEXTURE_2D_ARRAY:
     72     case TEXTURE_CUBE_ARRAY:
     73     case TEXTURE_2D_MSAA:
     74     case TEXTURE_2D_ARRAY_MSAA:
     75       useShadowVariant = false;
     76       break;
     77     case TEXTURE_SHADOW1D:
     78     case TEXTURE_SHADOW2D:
     79     case TEXTURE_SHADOWRECT:
     80     case TEXTURE_SHADOW1D_ARRAY:
     81     case TEXTURE_SHADOW2D_ARRAY:
     82     case TEXTURE_SHADOWCUBE:
     83     case TEXTURE_SHADOWCUBE_ARRAY:
     84       useShadowVariant = true;
     85       break;
     86     default:
     87       llvm_unreachable("Unknow Texture Type");
     88     }
     89 
     90     if (TextureType == TEXTURE_RECT ||
     91         TextureType == TEXTURE_SHADOWRECT) {
     92       CT[0] = 0;
     93       CT[1] = 0;
     94     }
     95 
     96     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         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         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 
    207 public:
    208   R600TextureIntrinsicsReplacer():
    209     FunctionPass(ID) {
    210   }
    211 
    212   bool doInitialization(Module &M) override {
    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   bool runOnFunction(Function &F) override {
    249     visit(F);
    250     return false;
    251   }
    252 
    253   const char *getPassName() const override {
    254     return "R600 Texture Intrinsics Replacer";
    255   }
    256 
    257   void getAnalysisUsage(AnalysisUsage &AU) const override {
    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 
    297 char R600TextureIntrinsicsReplacer::ID = 0;
    298 
    299 }
    300 
    301 FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
    302   return new R600TextureIntrinsicsReplacer();
    303 }
    304