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
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 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
207public:
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
297char R600TextureIntrinsicsReplacer::ID = 0;
298
299}
300
301FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
302  return new R600TextureIntrinsicsReplacer();
303}
304