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 
getAdjustmentFromTextureTarget(unsigned TextureType,bool hasLOD,unsigned SrcSelect[4],unsigned CT[4],bool & useShadowVariant)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 
ReplaceCallInst(CallInst & I,FunctionType * FT,const char * Name,unsigned SrcSelect[4],Value * Offset[3],Value * Resource,Value * Sampler,unsigned CT[4],Value * Coord)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 
ReplaceTexIntrinsic(CallInst & I,bool hasLOD,FunctionType * FT,const char * VanillaInt,const char * ShadowInt)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 
ReplaceTXF(CallInst & I)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:
R600TextureIntrinsicsReplacer()208   R600TextureIntrinsicsReplacer():
209     FunctionPass(ID) {
210   }
211 
doInitialization(Module & M)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 
runOnFunction(Function & F)248   bool runOnFunction(Function &F) override {
249     visit(F);
250     return false;
251   }
252 
getPassName() const253   const char *getPassName() const override {
254     return "R600 Texture Intrinsics Replacer";
255   }
256 
getAnalysisUsage(AnalysisUsage & AU) const257   void getAnalysisUsage(AnalysisUsage &AU) const override {
258   }
259 
visitCallInst(CallInst & I)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 
createR600TextureIntrinsicsReplacer()301 FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
302   return new R600TextureIntrinsicsReplacer();
303 }
304