R600: Fix bug detected by GCC warning.
[oota-llvm.git] / lib / Target / R600 / R600TextureIntrinsicsReplacer.cpp
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/Analysis/Passes.h"
17 #include "llvm/ADT/Statistic.h"
18 #include "llvm/IR/Function.h"
19 #include "llvm/InstVisitor.h"
20 #include "llvm/IR/IRBuilder.h"
21 #include "llvm/IR/GlobalValue.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     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.tex")
263       ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc");
264     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.txl")
265       ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc");
266     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.txb")
267       ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc");
268     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.txf")
269       ReplaceTXF(I);
270     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.txq")
271       ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq");
272     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.ddx")
273       ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx");
274     if (I.getCalledFunction()->getName() == "llvm.AMDGPU.ddy")
275       ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy");
276   }
277
278 };
279
280 char R600TextureIntrinsicsReplacer::ID = 0;
281
282 }
283
284 FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
285   return new R600TextureIntrinsicsReplacer();
286 }