]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/lib/Target/R600/R600EmitClauseMarkers.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / lib / Target / R600 / R600EmitClauseMarkers.cpp
1 //===-- R600EmitClauseMarkers.cpp - Emit CF_ALU ---------------------------===//
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 /// Add CF_ALU. R600 Alu instructions are grouped in clause which can hold
12 /// 128 Alu instructions ; these instructions can access up to 4 prefetched
13 /// 4 lines of 16 registers from constant buffers. Such ALU clauses are
14 /// initiated by CF_ALU instructions.
15 //===----------------------------------------------------------------------===//
16
17 #include "AMDGPU.h"
18 #include "R600Defines.h"
19 #include "R600InstrInfo.h"
20 #include "R600MachineFunctionInfo.h"
21 #include "R600RegisterInfo.h"
22 #include "llvm/CodeGen/MachineFunctionPass.h"
23 #include "llvm/CodeGen/MachineInstrBuilder.h"
24 #include "llvm/CodeGen/MachineRegisterInfo.h"
25
26 namespace llvm {
27
28 class R600EmitClauseMarkersPass : public MachineFunctionPass {
29
30 private:
31   static char ID;
32   const R600InstrInfo *TII;
33
34   unsigned OccupiedDwords(MachineInstr *MI) const {
35     switch (MI->getOpcode()) {
36     case AMDGPU::INTERP_PAIR_XY:
37     case AMDGPU::INTERP_PAIR_ZW:
38     case AMDGPU::INTERP_VEC_LOAD:
39     case AMDGPU::DOT4_eg_pseudo:
40     case AMDGPU::DOT4_r600_pseudo:
41       return 4;
42     case AMDGPU::KILL:
43       return 0;
44     default:
45       break;
46     }
47
48     if(TII->isVector(*MI) ||
49         TII->isCubeOp(MI->getOpcode()) ||
50         TII->isReductionOp(MI->getOpcode()))
51       return 4;
52
53     unsigned NumLiteral = 0;
54     for (MachineInstr::mop_iterator It = MI->operands_begin(),
55         E = MI->operands_end(); It != E; ++It) {
56       MachineOperand &MO = *It;
57       if (MO.isReg() && MO.getReg() == AMDGPU::ALU_LITERAL_X)
58         ++NumLiteral;
59     }
60     return 1 + NumLiteral;
61   }
62
63   bool isALU(const MachineInstr *MI) const {
64     if (TII->isALUInstr(MI->getOpcode()))
65       return true;
66     if (TII->isVector(*MI) || TII->isCubeOp(MI->getOpcode()))
67       return true;
68     switch (MI->getOpcode()) {
69     case AMDGPU::PRED_X:
70     case AMDGPU::INTERP_PAIR_XY:
71     case AMDGPU::INTERP_PAIR_ZW:
72     case AMDGPU::INTERP_VEC_LOAD:
73     case AMDGPU::COPY:
74     case AMDGPU::DOT4_eg_pseudo:
75     case AMDGPU::DOT4_r600_pseudo:
76       return true;
77     default:
78       return false;
79     }
80   }
81
82   bool IsTrivialInst(MachineInstr *MI) const {
83     switch (MI->getOpcode()) {
84     case AMDGPU::KILL:
85     case AMDGPU::RETURN:
86       return true;
87     default:
88       return false;
89     }
90   }
91
92   // Register Idx, then Const value
93   std::vector<std::pair<unsigned, unsigned> > ExtractConstRead(MachineInstr *MI)
94       const {
95     const R600Operands::Ops OpTable[3][2] = {
96       {R600Operands::SRC0, R600Operands::SRC0_SEL},
97       {R600Operands::SRC1, R600Operands::SRC1_SEL},
98       {R600Operands::SRC2, R600Operands::SRC2_SEL},
99     };
100     std::vector<std::pair<unsigned, unsigned> > Result;
101
102     if (!TII->isALUInstr(MI->getOpcode()))
103       return Result;
104     for (unsigned j = 0; j < 3; j++) {
105       int SrcIdx = TII->getOperandIdx(MI->getOpcode(), OpTable[j][0]);
106       if (SrcIdx < 0)
107         break;
108       if (MI->getOperand(SrcIdx).getReg() == AMDGPU::ALU_CONST) {
109         unsigned Const = MI->getOperand(
110             TII->getOperandIdx(MI->getOpcode(), OpTable[j][1])).getImm();
111         Result.push_back(std::pair<unsigned, unsigned>(SrcIdx, Const));
112       }
113     }
114     return Result;
115   }
116
117   std::pair<unsigned, unsigned> getAccessedBankLine(unsigned Sel) const {
118     // Sel is (512 + (kc_bank << 12) + ConstIndex) << 2
119     // (See also R600ISelLowering.cpp)
120     // ConstIndex value is in [0, 4095];
121     return std::pair<unsigned, unsigned>(
122         ((Sel >> 2) - 512) >> 12, // KC_BANK
123         // Line Number of ConstIndex
124         // A line contains 16 constant registers however KCX bank can lock
125         // two line at the same time ; thus we want to get an even line number.
126         // Line number can be retrieved with (>>4), using (>>5) <<1 generates
127         // an even number.
128         ((((Sel >> 2) - 512) & 4095) >> 5) << 1);
129   }
130
131   bool SubstituteKCacheBank(MachineInstr *MI,
132       std::vector<std::pair<unsigned, unsigned> > &CachedConsts) const {
133     std::vector<std::pair<unsigned, unsigned> > UsedKCache;
134     std::vector<std::pair<unsigned, unsigned> > Consts = ExtractConstRead(MI);
135     assert(TII->isALUInstr(MI->getOpcode()) && "Can't assign Const");
136     for (unsigned i = 0, n = Consts.size(); i < n; ++i) {
137       unsigned Sel = Consts[i].second;
138       unsigned Chan = Sel & 3, Index = ((Sel >> 2) - 512) & 31;
139       unsigned KCacheIndex = Index * 4 + Chan;
140       const std::pair<unsigned, unsigned> &BankLine = getAccessedBankLine(Sel);
141       if (CachedConsts.empty()) {
142         CachedConsts.push_back(BankLine);
143         UsedKCache.push_back(std::pair<unsigned, unsigned>(0, KCacheIndex));
144         continue;
145       }
146       if (CachedConsts[0] == BankLine) {
147         UsedKCache.push_back(std::pair<unsigned, unsigned>(0, KCacheIndex));
148         continue;
149       }
150       if (CachedConsts.size() == 1) {
151         CachedConsts.push_back(BankLine);
152         UsedKCache.push_back(std::pair<unsigned, unsigned>(1, KCacheIndex));
153         continue;
154       }
155       if (CachedConsts[1] == BankLine) {
156         UsedKCache.push_back(std::pair<unsigned, unsigned>(1, KCacheIndex));
157         continue;
158       }
159       return false;
160     }
161
162     for (unsigned i = 0, n = Consts.size(); i < n; ++i) {
163       switch(UsedKCache[i].first) {
164       case 0:
165         MI->getOperand(Consts[i].first).setReg(
166             AMDGPU::R600_KC0RegClass.getRegister(UsedKCache[i].second));
167         break;
168       case 1:
169         MI->getOperand(Consts[i].first).setReg(
170             AMDGPU::R600_KC1RegClass.getRegister(UsedKCache[i].second));
171         break;
172       default:
173         llvm_unreachable("Wrong Cache Line");
174       }
175     }
176     return true;
177   }
178
179   MachineBasicBlock::iterator
180   MakeALUClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const {
181     MachineBasicBlock::iterator ClauseHead = I;
182     std::vector<std::pair<unsigned, unsigned> > KCacheBanks;
183     bool PushBeforeModifier = false;
184     unsigned AluInstCount = 0;
185     for (MachineBasicBlock::iterator E = MBB.end(); I != E; ++I) {
186       if (IsTrivialInst(I))
187         continue;
188       if (!isALU(I))
189         break;
190       if (AluInstCount > TII->getMaxAlusPerClause())
191         break;
192       if (I->getOpcode() == AMDGPU::PRED_X) {
193         if (TII->getFlagOp(I).getImm() & MO_FLAG_PUSH)
194           PushBeforeModifier = true;
195         AluInstCount ++;
196         continue;
197       }
198       if (I->getOpcode() == AMDGPU::KILLGT) {
199         I++;
200         break;
201       }
202       if (TII->isALUInstr(I->getOpcode()) &&
203           !SubstituteKCacheBank(I, KCacheBanks))
204         break;
205       AluInstCount += OccupiedDwords(I);
206     }
207     unsigned Opcode = PushBeforeModifier ?
208         AMDGPU::CF_ALU_PUSH_BEFORE : AMDGPU::CF_ALU;
209     BuildMI(MBB, ClauseHead, MBB.findDebugLoc(ClauseHead), TII->get(Opcode))
210         .addImm(0) // ADDR
211         .addImm(KCacheBanks.empty()?0:KCacheBanks[0].first) // KB0
212         .addImm((KCacheBanks.size() < 2)?0:KCacheBanks[1].first) // KB1
213         .addImm(KCacheBanks.empty()?0:2) // KM0
214         .addImm((KCacheBanks.size() < 2)?0:2) // KM1
215         .addImm(KCacheBanks.empty()?0:KCacheBanks[0].second) // KLINE0
216         .addImm((KCacheBanks.size() < 2)?0:KCacheBanks[1].second) // KLINE1
217         .addImm(AluInstCount); // COUNT
218     return I;
219   }
220
221 public:
222   R600EmitClauseMarkersPass(TargetMachine &tm) : MachineFunctionPass(ID),
223     TII (static_cast<const R600InstrInfo *>(tm.getInstrInfo())) { }
224
225   virtual bool runOnMachineFunction(MachineFunction &MF) {
226     for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
227                                                     BB != BB_E; ++BB) {
228       MachineBasicBlock &MBB = *BB;
229       MachineBasicBlock::iterator I = MBB.begin();
230       if (I->getOpcode() == AMDGPU::CF_ALU)
231         continue; // BB was already parsed
232       for (MachineBasicBlock::iterator E = MBB.end(); I != E;) {
233         if (isALU(I))
234           I = MakeALUClause(MBB, I);
235         else
236           ++I;
237       }
238     }
239     return false;
240   }
241
242   const char *getPassName() const {
243     return "R600 Emit Clause Markers Pass";
244   }
245 };
246
247 char R600EmitClauseMarkersPass::ID = 0;
248
249 }
250
251
252 llvm::FunctionPass *llvm::createR600EmitClauseMarkers(TargetMachine &TM) {
253   return new R600EmitClauseMarkersPass(TM);
254 }
255