1259698Sdim//===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===//
2259698Sdim//
3259698Sdim//                     The LLVM Compiler Infrastructure
4259698Sdim//
5259698Sdim// This file is distributed under the University of Illinois Open Source
6259698Sdim// License. See LICENSE.TXT for details.
7259698Sdim//
8259698Sdim//===----------------------------------------------------------------------===//
9259698Sdim//
10259698Sdim/// \file
11259698Sdim/// This pass translates tgsi-like texture intrinsics into R600 texture
12259698Sdim/// closer to hardware intrinsics.
13259698Sdim//===----------------------------------------------------------------------===//
14259698Sdim
15259698Sdim#include "AMDGPU.h"
16259698Sdim#include "llvm/ADT/Statistic.h"
17259698Sdim#include "llvm/Analysis/Passes.h"
18259698Sdim#include "llvm/IR/Function.h"
19259698Sdim#include "llvm/IR/GlobalValue.h"
20259698Sdim#include "llvm/IR/IRBuilder.h"
21259698Sdim#include "llvm/InstVisitor.h"
22259698Sdim
23259698Sdimusing namespace llvm;
24259698Sdim
25259698Sdimnamespace {
26259698Sdimclass R600TextureIntrinsicsReplacer :
27259698Sdim    public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> {
28259698Sdim  static char ID;
29259698Sdim
30259698Sdim  Module *Mod;
31259698Sdim  Type *FloatType;
32259698Sdim  Type *Int32Type;
33259698Sdim  Type *V4f32Type;
34259698Sdim  Type *V4i32Type;
35259698Sdim  FunctionType *TexSign;
36259698Sdim  FunctionType *TexQSign;
37259698Sdim
38259698Sdim  void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD,
39259698Sdim                                      unsigned SrcSelect[4], unsigned CT[4],
40259698Sdim                                      bool &useShadowVariant) {
41259698Sdim    enum TextureTypes {
42259698Sdim      TEXTURE_1D = 1,
43259698Sdim      TEXTURE_2D,
44259698Sdim      TEXTURE_3D,
45259698Sdim      TEXTURE_CUBE,
46259698Sdim      TEXTURE_RECT,
47259698Sdim      TEXTURE_SHADOW1D,
48259698Sdim      TEXTURE_SHADOW2D,
49259698Sdim      TEXTURE_SHADOWRECT,
50259698Sdim      TEXTURE_1D_ARRAY,
51259698Sdim      TEXTURE_2D_ARRAY,
52259698Sdim      TEXTURE_SHADOW1D_ARRAY,
53259698Sdim      TEXTURE_SHADOW2D_ARRAY,
54259698Sdim      TEXTURE_SHADOWCUBE,
55259698Sdim      TEXTURE_2D_MSAA,
56259698Sdim      TEXTURE_2D_ARRAY_MSAA,
57259698Sdim      TEXTURE_CUBE_ARRAY,
58259698Sdim      TEXTURE_SHADOWCUBE_ARRAY
59259698Sdim    };
60259698Sdim
61259698Sdim    switch (TextureType) {
62259698Sdim    case 0:
63259698Sdim      useShadowVariant = false;
64259698Sdim      return;
65259698Sdim    case TEXTURE_RECT:
66259698Sdim    case TEXTURE_1D:
67259698Sdim    case TEXTURE_2D:
68259698Sdim    case TEXTURE_3D:
69259698Sdim    case TEXTURE_CUBE:
70259698Sdim    case TEXTURE_1D_ARRAY:
71259698Sdim    case TEXTURE_2D_ARRAY:
72259698Sdim    case TEXTURE_CUBE_ARRAY:
73259698Sdim    case TEXTURE_2D_MSAA:
74259698Sdim    case TEXTURE_2D_ARRAY_MSAA:
75259698Sdim      useShadowVariant = false;
76259698Sdim      break;
77259698Sdim    case TEXTURE_SHADOW1D:
78259698Sdim    case TEXTURE_SHADOW2D:
79259698Sdim    case TEXTURE_SHADOWRECT:
80259698Sdim    case TEXTURE_SHADOW1D_ARRAY:
81259698Sdim    case TEXTURE_SHADOW2D_ARRAY:
82259698Sdim    case TEXTURE_SHADOWCUBE:
83259698Sdim    case TEXTURE_SHADOWCUBE_ARRAY:
84259698Sdim      useShadowVariant = true;
85259698Sdim      break;
86259698Sdim    default:
87259698Sdim      llvm_unreachable("Unknow Texture Type");
88259698Sdim    }
89259698Sdim
90259698Sdim    if (TextureType == TEXTURE_RECT ||
91259698Sdim        TextureType == TEXTURE_SHADOWRECT) {
92259698Sdim      CT[0] = 0;
93259698Sdim      CT[1] = 0;
94259698Sdim    }
95259698Sdim
96259698Sdim    if (TextureType == TEXTURE_CUBE_ARRAY ||
97259698Sdim        TextureType == TEXTURE_SHADOWCUBE_ARRAY)
98259698Sdim      CT[2] = 0;
99259698Sdim
100259698Sdim    if (TextureType == TEXTURE_1D_ARRAY ||
101259698Sdim        TextureType == TEXTURE_SHADOW1D_ARRAY) {
102259698Sdim      if (hasLOD && useShadowVariant) {
103259698Sdim        CT[1] = 0;
104259698Sdim      } else {
105259698Sdim        CT[2] = 0;
106259698Sdim        SrcSelect[2] = 1;
107259698Sdim      }
108259698Sdim    } else if (TextureType == TEXTURE_2D_ARRAY ||
109259698Sdim        TextureType == TEXTURE_SHADOW2D_ARRAY) {
110259698Sdim      CT[2] = 0;
111259698Sdim    }
112259698Sdim
113259698Sdim    if ((TextureType == TEXTURE_SHADOW1D ||
114259698Sdim        TextureType == TEXTURE_SHADOW2D ||
115259698Sdim        TextureType == TEXTURE_SHADOWRECT ||
116259698Sdim        TextureType == TEXTURE_SHADOW1D_ARRAY) &&
117259698Sdim        !(hasLOD && useShadowVariant))
118259698Sdim      SrcSelect[3] = 2;
119259698Sdim  }
120259698Sdim
121259698Sdim  void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name,
122259698Sdim                       unsigned SrcSelect[4], Value *Offset[3], Value *Resource,
123259698Sdim                       Value *Sampler, unsigned CT[4], Value *Coord) {
124259698Sdim    IRBuilder<> Builder(&I);
125259698Sdim    Constant *Mask[] = {
126259698Sdim      ConstantInt::get(Int32Type, SrcSelect[0]),
127259698Sdim      ConstantInt::get(Int32Type, SrcSelect[1]),
128259698Sdim      ConstantInt::get(Int32Type, SrcSelect[2]),
129259698Sdim      ConstantInt::get(Int32Type, SrcSelect[3])
130259698Sdim    };
131259698Sdim    Value *SwizzleMask = ConstantVector::get(Mask);
132259698Sdim    Value *SwizzledCoord =
133259698Sdim        Builder.CreateShuffleVector(Coord, Coord, SwizzleMask);
134259698Sdim
135259698Sdim    Value *Args[] = {
136259698Sdim      SwizzledCoord,
137259698Sdim      Offset[0],
138259698Sdim      Offset[1],
139259698Sdim      Offset[2],
140259698Sdim      Resource,
141259698Sdim      Sampler,
142259698Sdim      ConstantInt::get(Int32Type, CT[0]),
143259698Sdim      ConstantInt::get(Int32Type, CT[1]),
144259698Sdim      ConstantInt::get(Int32Type, CT[2]),
145259698Sdim      ConstantInt::get(Int32Type, CT[3])
146259698Sdim    };
147259698Sdim
148259698Sdim    Function *F = Mod->getFunction(Name);
149259698Sdim    if (!F) {
150259698Sdim      F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod);
151259698Sdim      F->addFnAttr(Attribute::ReadNone);
152259698Sdim    }
153259698Sdim    I.replaceAllUsesWith(Builder.CreateCall(F, Args));
154259698Sdim    I.eraseFromParent();
155259698Sdim  }
156259698Sdim
157259698Sdim  void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT,
158259698Sdim                           const char *VanillaInt,
159259698Sdim                           const char *ShadowInt) {
160259698Sdim    Value *Coord = I.getArgOperand(0);
161259698Sdim    Value *ResourceId = I.getArgOperand(1);
162259698Sdim    Value *SamplerId = I.getArgOperand(2);
163259698Sdim
164259698Sdim    unsigned TextureType =
165259698Sdim        dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue();
166259698Sdim
167259698Sdim    unsigned SrcSelect[4] = { 0, 1, 2, 3 };
168259698Sdim    unsigned CT[4] = {1, 1, 1, 1};
169259698Sdim    Value *Offset[3] = {
170259698Sdim      ConstantInt::get(Int32Type, 0),
171259698Sdim      ConstantInt::get(Int32Type, 0),
172259698Sdim      ConstantInt::get(Int32Type, 0)
173259698Sdim    };
174259698Sdim    bool useShadowVariant;
175259698Sdim
176259698Sdim    getAdjustmentFromTextureTarget(TextureType, hasLOD, SrcSelect, CT,
177259698Sdim                                   useShadowVariant);
178259698Sdim
179259698Sdim    ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect,
180259698Sdim                    Offset, ResourceId, SamplerId, CT, Coord);
181259698Sdim  }
182259698Sdim
183259698Sdim  void ReplaceTXF(CallInst &I) {
184259698Sdim    Value *Coord = I.getArgOperand(0);
185259698Sdim    Value *ResourceId = I.getArgOperand(4);
186259698Sdim    Value *SamplerId = I.getArgOperand(5);
187259698Sdim
188259698Sdim    unsigned TextureType =
189259698Sdim        dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue();
190259698Sdim
191259698Sdim    unsigned SrcSelect[4] = { 0, 1, 2, 3 };
192259698Sdim    unsigned CT[4] = {1, 1, 1, 1};
193259698Sdim    Value *Offset[3] = {
194259698Sdim      I.getArgOperand(1),
195259698Sdim      I.getArgOperand(2),
196259698Sdim      I.getArgOperand(3),
197259698Sdim    };
198259698Sdim    bool useShadowVariant;
199259698Sdim
200259698Sdim    getAdjustmentFromTextureTarget(TextureType, false, SrcSelect, CT,
201259698Sdim                                   useShadowVariant);
202259698Sdim
203259698Sdim    ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect,
204259698Sdim                    Offset, ResourceId, SamplerId, CT, Coord);
205259698Sdim  }
206259698Sdim
207259698Sdimpublic:
208259698Sdim  R600TextureIntrinsicsReplacer():
209259698Sdim    FunctionPass(ID) {
210259698Sdim  }
211259698Sdim
212259698Sdim  virtual bool doInitialization(Module &M) {
213259698Sdim    LLVMContext &Ctx = M.getContext();
214259698Sdim    Mod = &M;
215259698Sdim    FloatType = Type::getFloatTy(Ctx);
216259698Sdim    Int32Type = Type::getInt32Ty(Ctx);
217259698Sdim    V4f32Type = VectorType::get(FloatType, 4);
218259698Sdim    V4i32Type = VectorType::get(Int32Type, 4);
219259698Sdim    Type *ArgsType[] = {
220259698Sdim      V4f32Type,
221259698Sdim      Int32Type,
222259698Sdim      Int32Type,
223259698Sdim      Int32Type,
224259698Sdim      Int32Type,
225259698Sdim      Int32Type,
226259698Sdim      Int32Type,
227259698Sdim      Int32Type,
228259698Sdim      Int32Type,
229259698Sdim      Int32Type,
230259698Sdim    };
231259698Sdim    TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false);
232259698Sdim    Type *ArgsQType[] = {
233259698Sdim      V4i32Type,
234259698Sdim      Int32Type,
235259698Sdim      Int32Type,
236259698Sdim      Int32Type,
237259698Sdim      Int32Type,
238259698Sdim      Int32Type,
239259698Sdim      Int32Type,
240259698Sdim      Int32Type,
241259698Sdim      Int32Type,
242259698Sdim      Int32Type,
243259698Sdim    };
244259698Sdim    TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false);
245259698Sdim    return false;
246259698Sdim  }
247259698Sdim
248259698Sdim  virtual bool runOnFunction(Function &F) {
249259698Sdim    visit(F);
250259698Sdim    return false;
251259698Sdim  }
252259698Sdim
253259698Sdim  virtual const char *getPassName() const {
254259698Sdim    return "R600 Texture Intrinsics Replacer";
255259698Sdim  }
256259698Sdim
257259698Sdim  void getAnalysisUsage(AnalysisUsage &AU) const {
258259698Sdim  }
259259698Sdim
260259698Sdim  void visitCallInst(CallInst &I) {
261259698Sdim    if (!I.getCalledFunction())
262259698Sdim      return;
263259698Sdim
264259698Sdim    StringRef Name = I.getCalledFunction()->getName();
265259698Sdim    if (Name == "llvm.AMDGPU.tex") {
266259698Sdim      ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc");
267259698Sdim      return;
268259698Sdim    }
269259698Sdim    if (Name == "llvm.AMDGPU.txl") {
270259698Sdim      ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc");
271259698Sdim      return;
272259698Sdim    }
273259698Sdim    if (Name == "llvm.AMDGPU.txb") {
274259698Sdim      ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc");
275259698Sdim      return;
276259698Sdim    }
277259698Sdim    if (Name == "llvm.AMDGPU.txf") {
278259698Sdim      ReplaceTXF(I);
279259698Sdim      return;
280259698Sdim    }
281259698Sdim    if (Name == "llvm.AMDGPU.txq") {
282259698Sdim      ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq");
283259698Sdim      return;
284259698Sdim    }
285259698Sdim    if (Name == "llvm.AMDGPU.ddx") {
286259698Sdim      ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx");
287259698Sdim      return;
288259698Sdim    }
289259698Sdim    if (Name == "llvm.AMDGPU.ddy") {
290259698Sdim      ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy");
291259698Sdim      return;
292259698Sdim    }
293259698Sdim  }
294259698Sdim
295259698Sdim};
296259698Sdim
297259698Sdimchar R600TextureIntrinsicsReplacer::ID = 0;
298259698Sdim
299259698Sdim}
300259698Sdim
301259698SdimFunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
302259698Sdim  return new R600TextureIntrinsicsReplacer();
303259698Sdim}
304