OSDN Git Service

radeonsi: initial WIP SI code
[android-x86/external-mesa.git] / src / gallium / drivers / radeon / SICodeEmitter.cpp
1 //===-- SICodeEmitter.cpp - TODO: Add brief description -------===//
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 // TODO: Add full description
11 //
12 //===----------------------------------------------------------------------===//
13
14
15 #include "AMDGPU.h"
16 #include "AMDGPUUtil.h"
17 #include "AMDILCodeEmitter.h"
18 #include "SIInstrInfo.h"
19 #include "SIMachineFunctionInfo.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/Support/FormattedStream.h"
23 #include "llvm/Target/TargetMachine.h"
24
25 #include <stdio.h>
26
27 #define LITERAL_REG 255
28 #define VGPR_BIT(src_idx) (1 << (8 * (src_idx)))
29 using namespace llvm;
30
31 namespace {
32
33   class SICodeEmitter : public MachineFunctionPass, public AMDILCodeEmitter {
34
35   private:
36     static char ID;
37     formatted_raw_ostream &_OS;
38     const TargetMachine *TM;
39     void emitState(MachineFunction & MF);
40     void emitInstr(MachineInstr &MI);
41
42     void outputBytes(uint64_t value, unsigned bytes);
43     unsigned GPRAlign(const MachineInstr &MI, unsigned OpNo, unsigned shift)
44                                                                       const;
45
46   public:
47     SICodeEmitter(formatted_raw_ostream &OS) : MachineFunctionPass(ID),
48         _OS(OS), TM(NULL) { }
49     const char *getPassName() const { return "SI Code Emitter"; }
50     bool runOnMachineFunction(MachineFunction &MF);
51     virtual uint64_t getMachineOpValue(const MachineInstr &MI,
52                                        const MachineOperand &MO) const;
53     virtual unsigned GPR4AlignEncode(const MachineInstr  &MI, unsigned OpNo)
54                                                                       const;
55     virtual unsigned GPR2AlignEncode(const MachineInstr &MI, unsigned OpNo)
56                                                                       const;
57     virtual uint64_t i32LiteralEncode(const MachineInstr &MI, unsigned OpNo)
58                                                                       const;
59     virtual uint64_t VOPPostEncode(const MachineInstr &MI,
60                                    uint64_t Value) const;
61   };
62 }
63
64 char SICodeEmitter::ID = 0;
65
66 FunctionPass *llvm::createSICodeEmitterPass(formatted_raw_ostream &OS) {
67   return new SICodeEmitter(OS);
68 }
69
70 void SICodeEmitter::emitState(MachineFunction & MF)
71 {
72   unsigned maxSGPR = 0;
73   unsigned maxVGPR = 0;
74   bool VCCUsed = false;
75   const SIRegisterInfo * RI =
76                 static_cast<const SIRegisterInfo*>(TM->getRegisterInfo());
77   SIMachineFunctionInfo * MFI = MF.getInfo<SIMachineFunctionInfo>();
78
79   for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
80                                                   BB != BB_E; ++BB) {
81     MachineBasicBlock &MBB = *BB;
82     for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
83                                                       I != E; ++I) {
84       MachineInstr &MI = *I;
85       unsigned numOperands = MI.getNumOperands();
86       for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
87         MachineOperand & MO = MI.getOperand(op_idx);
88         unsigned maxUsed;
89         unsigned width = 0;
90         bool isSGPR = false;
91         unsigned reg;
92         unsigned hwReg;
93         if (!MO.isReg()) {
94           continue;
95         }
96         reg = MO.getReg();
97         if (reg == AMDIL::VCC) {
98           VCCUsed = true;
99           continue;
100         }
101         if (AMDIL::SReg_32RegClass.contains(reg)) {
102           isSGPR = true;
103           width = 1;
104         } else if (AMDIL::VReg_32RegClass.contains(reg)) {
105           isSGPR = false;
106           width = 1;
107         } else if (AMDIL::SReg_64RegClass.contains(reg)) {
108           isSGPR = true;
109           width = 2;
110         } else if (AMDIL::VReg_64RegClass.contains(reg)) {
111           isSGPR = false;
112           width = 2;
113         } else if (AMDIL::SReg_128RegClass.contains(reg)) {
114           isSGPR = true;
115           width = 4;
116         } else if (AMDIL::VReg_128RegClass.contains(reg)) {
117           isSGPR = false;
118           width = 4;
119         } else if (AMDIL::SReg_256RegClass.contains(reg)) {
120           isSGPR = true;
121           width = 8;
122         } else {
123           assert("!Unknown register class");
124         }
125         hwReg = RI->getHWRegNum(reg);
126         maxUsed = ((hwReg + 1) * width) - 1;
127         if (isSGPR) {
128           maxSGPR = maxUsed > maxSGPR ? maxUsed : maxSGPR;
129         } else {
130           maxVGPR = maxUsed > maxVGPR ? maxUsed : maxVGPR;
131         }
132       }
133     }
134   }
135   if (VCCUsed) {
136     maxSGPR += 2;
137   }
138   outputBytes(maxSGPR + 1, 4);
139   outputBytes(maxVGPR + 1, 4);
140   outputBytes(MFI->spi_ps_input_addr, 4);
141 }
142
143 bool SICodeEmitter::runOnMachineFunction(MachineFunction &MF)
144 {
145   MF.dump();
146   TM = &MF.getTarget();
147   const AMDGPUInstrInfo * TII =
148                         static_cast<const AMDGPUInstrInfo*>(TM->getInstrInfo());
149
150   emitState(MF);
151
152   for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
153                                                   BB != BB_E; ++BB) {
154     MachineBasicBlock &MBB = *BB;
155     for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
156                                                       I != E; ++I) {
157       MachineInstr &MI = *I;
158       if (!TII->isRegPreload(MI) && MI.getOpcode() != AMDIL::KILL
159           && MI.getOpcode() != AMDIL::RETURN) {
160         emitInstr(MI);
161       }
162     }
163   }
164   return false;
165 }
166
167 void SICodeEmitter::emitInstr(MachineInstr &MI)
168 {
169   const SIInstrInfo * SII = static_cast<const SIInstrInfo*>(TM->getInstrInfo());
170
171   uint64_t hwInst = getBinaryCodeForInstr(MI);
172
173   if ((hwInst & 0xffffffff) == 0xffffffff) {
174     fprintf(stderr, "Unsupported Instruction: \n");
175     MI.dump();
176     abort();
177   }
178
179 //  hwInst |= SII->getBinaryCode(MI);
180
181   unsigned bytes = SII->getEncodingBytes(MI);
182   outputBytes(hwInst, bytes);
183 }
184
185 uint64_t SICodeEmitter::getMachineOpValue(const MachineInstr &MI,
186                                           const MachineOperand &MO) const
187 {
188   const SIRegisterInfo * RI =
189                 static_cast<const SIRegisterInfo*>(TM->getRegisterInfo());
190
191   switch(MO.getType()) {
192   case MachineOperand::MO_Register:
193     return RI->getBinaryCode(MO.getReg());
194
195   case MachineOperand::MO_Immediate:
196     return MO.getImm();
197
198   case MachineOperand::MO_FPImmediate:
199     /* XXX: Not all instructions can use inline literals */
200     /* XXX: We should make sure this is a 32-bit constant */
201     return LITERAL_REG | (MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue() << 32);
202   default:
203     llvm_unreachable("Encoding of this operand type is not supported yet.");
204     break;
205   }
206 }
207
208 unsigned SICodeEmitter::GPRAlign(const MachineInstr &MI, unsigned OpNo,
209     unsigned shift) const
210 {
211   const SIRegisterInfo * RI =
212                 static_cast<const SIRegisterInfo*>(TM->getRegisterInfo());
213   unsigned regCode = RI->getHWRegNum(MI.getOperand(OpNo).getReg());
214   return regCode >> shift;
215 }
216
217 unsigned SICodeEmitter::GPR4AlignEncode(const MachineInstr &MI,
218     unsigned OpNo) const
219 {
220   return GPRAlign(MI, OpNo, 2);
221 }
222
223 unsigned SICodeEmitter::GPR2AlignEncode(const MachineInstr &MI,
224     unsigned OpNo) const
225 {
226   return GPRAlign(MI, OpNo, 1);
227 }
228
229 uint64_t SICodeEmitter::i32LiteralEncode(const MachineInstr &MI,
230     unsigned OpNo) const
231 {
232   return LITERAL_REG | (MI.getOperand(OpNo).getImm() << 32);
233 }
234
235 /* Set the "VGPR" bit for VOP args that can take either a VGPR or a SGPR.
236  * XXX: It would be nice if we could handle this without a PostEncode function.
237  */
238 uint64_t SICodeEmitter::VOPPostEncode(const MachineInstr &MI,
239     uint64_t Value) const
240 {
241   const SIInstrInfo * SII = static_cast<const SIInstrInfo*>(TM->getInstrInfo());
242   unsigned encodingType = SII->getEncodingType(MI);
243   unsigned numSrcOps;
244   unsigned vgprBitOffset;
245
246   if (encodingType == SIInstrEncodingType::VOP3) {
247     numSrcOps = 3;
248     vgprBitOffset = 32;
249   } else {
250     numSrcOps = 1;
251     vgprBitOffset = 0;
252   }
253
254   /* Add one to skip over the destination reg operand. */
255   for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) {
256     if (!MI.getOperand(opIdx).isReg()) {
257       continue;
258     }
259     unsigned reg = MI.getOperand(opIdx).getReg();
260     if (AMDIL::VReg_32RegClass.contains(reg)
261         || AMDIL::VReg_64RegClass.contains(reg)) {
262       Value |= (VGPR_BIT(opIdx)) << vgprBitOffset;
263     }
264   }
265   return Value;
266 }
267
268
269 void SICodeEmitter::outputBytes(uint64_t value, unsigned bytes)
270 {
271   for (unsigned i = 0; i < bytes; i++) {
272     _OS.write((uint8_t) ((value >> (8 * i)) & 0xff));
273   }
274 }