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