radeon/llvm: Add flag operand to some instructions
[mesa.git] / src / gallium / drivers / radeon / SICodeEmitter.cpp
1 //===-- SICodeEmitter.cpp - SI Code Emitter -------------------------------===//
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 // The SI code emitter produces machine code that can be executed directly on
11 // the GPU device.
12 //
13 //===----------------------------------------------------------------------===//
14
15
16 #include "AMDGPU.h"
17 #include "AMDGPUCodeEmitter.h"
18 #include "SIInstrInfo.h"
19 #include "SIMachineFunctionInfo.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/Support/FormattedStream.h"
24 #include "llvm/Target/TargetMachine.h"
25
26 #include <map>
27 #include <stdio.h>
28
29 #define LITERAL_REG 255
30 #define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1))
31 using namespace llvm;
32
33 namespace {
34
35 class SICodeEmitter : public MachineFunctionPass, public AMDGPUCodeEmitter {
36
37 private:
38 static char ID;
39 formatted_raw_ostream &_OS;
40 const TargetMachine *TM;
41
42 //Program Info
43 unsigned MaxSGPR;
44 unsigned MaxVGPR;
45 unsigned CurrentInstrIndex;
46 std::map<int, unsigned> BBIndexes;
47
48 void InitProgramInfo(MachineFunction &MF);
49 void EmitState(MachineFunction & MF);
50 void emitInstr(MachineInstr &MI);
51
52 void outputBytes(uint64_t value, unsigned bytes);
53 unsigned GPRAlign(const MachineInstr &MI, unsigned OpNo, unsigned shift)
54 const;
55
56 public:
57 SICodeEmitter(formatted_raw_ostream &OS) : MachineFunctionPass(ID),
58 _OS(OS), TM(NULL), MaxSGPR(0), MaxVGPR(0), CurrentInstrIndex(0) { }
59 const char *getPassName() const { return "SI Code Emitter"; }
60 bool runOnMachineFunction(MachineFunction &MF);
61
62 /// getMachineOpValue - Return the encoding for MO
63 virtual uint64_t getMachineOpValue(const MachineInstr &MI,
64 const MachineOperand &MO) const;
65
66 /// GPR4AlignEncode - Encoding for when 4 consectuive registers are used
67 virtual unsigned GPR4AlignEncode(const MachineInstr &MI, unsigned OpNo)
68 const;
69
70 /// GPR2AlignEncode - Encoding for when 2 consecutive registers are used
71 virtual unsigned GPR2AlignEncode(const MachineInstr &MI, unsigned OpNo)
72 const;
73 /// i32LiteralEncode - Encode an i32 literal this is used as an operand
74 /// for an instruction in place of a register.
75 virtual uint64_t i32LiteralEncode(const MachineInstr &MI, unsigned OpNo)
76 const;
77 /// SMRDmemriEncode - Encoding for SMRD indexed loads
78 virtual uint32_t SMRDmemriEncode(const MachineInstr &MI, unsigned OpNo)
79 const;
80
81 /// VOPPostEncode - Post-Encoder method for VOP instructions
82 virtual uint64_t VOPPostEncode(const MachineInstr &MI,
83 uint64_t Value) const;
84 };
85 }
86
87 char SICodeEmitter::ID = 0;
88
89 FunctionPass *llvm::createSICodeEmitterPass(formatted_raw_ostream &OS) {
90 return new SICodeEmitter(OS);
91 }
92
93 void SICodeEmitter::EmitState(MachineFunction & MF) {
94 SIMachineFunctionInfo * MFI = MF.getInfo<SIMachineFunctionInfo>();
95 outputBytes(MaxSGPR + 1, 4);
96 outputBytes(MaxVGPR + 1, 4);
97 outputBytes(MFI->spi_ps_input_addr, 4);
98 }
99
100 void SICodeEmitter::InitProgramInfo(MachineFunction &MF) {
101 unsigned InstrIndex = 0;
102 bool VCCUsed = false;
103 const SIRegisterInfo * RI =
104 static_cast<const SIRegisterInfo*>(TM->getRegisterInfo());
105
106 for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
107 BB != BB_E; ++BB) {
108 MachineBasicBlock &MBB = *BB;
109 BBIndexes[MBB.getNumber()] = InstrIndex;
110 InstrIndex += MBB.size();
111 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
112 I != E; ++I) {
113 MachineInstr &MI = *I;
114
115 unsigned numOperands = MI.getNumOperands();
116 for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
117 MachineOperand & MO = MI.getOperand(op_idx);
118 unsigned maxUsed;
119 unsigned width = 0;
120 bool isSGPR = false;
121 unsigned reg;
122 unsigned hwReg;
123 if (!MO.isReg()) {
124 continue;
125 }
126 reg = MO.getReg();
127 if (reg == AMDGPU::VCC) {
128 VCCUsed = true;
129 continue;
130 }
131 if (AMDGPU::SReg_32RegClass.contains(reg)) {
132 isSGPR = true;
133 width = 1;
134 } else if (AMDGPU::VReg_32RegClass.contains(reg)) {
135 isSGPR = false;
136 width = 1;
137 } else if (AMDGPU::SReg_64RegClass.contains(reg)) {
138 isSGPR = true;
139 width = 2;
140 } else if (AMDGPU::VReg_64RegClass.contains(reg)) {
141 isSGPR = false;
142 width = 2;
143 } else if (AMDGPU::SReg_128RegClass.contains(reg)) {
144 isSGPR = true;
145 width = 4;
146 } else if (AMDGPU::VReg_128RegClass.contains(reg)) {
147 isSGPR = false;
148 width = 4;
149 } else if (AMDGPU::SReg_256RegClass.contains(reg)) {
150 isSGPR = true;
151 width = 8;
152 } else {
153 assert("!Unknown register class");
154 }
155 hwReg = RI->getHWRegNum(reg);
156 maxUsed = hwReg + width - 1;
157 if (isSGPR) {
158 MaxSGPR = maxUsed > MaxSGPR ? maxUsed : MaxSGPR;
159 } else {
160 MaxVGPR = maxUsed > MaxVGPR ? maxUsed : MaxVGPR;
161 }
162 }
163 }
164 }
165 if (VCCUsed) {
166 MaxSGPR += 2;
167 }
168 }
169
170 bool SICodeEmitter::runOnMachineFunction(MachineFunction &MF)
171 {
172 TM = &MF.getTarget();
173 const AMDGPUSubtarget &STM = TM->getSubtarget<AMDGPUSubtarget>();
174
175 if (STM.dumpCode()) {
176 MF.dump();
177 }
178
179 InitProgramInfo(MF);
180
181 EmitState(MF);
182
183 for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
184 BB != BB_E; ++BB) {
185 MachineBasicBlock &MBB = *BB;
186 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
187 I != E; ++I) {
188 MachineInstr &MI = *I;
189 if (MI.getOpcode() != AMDGPU::KILL && MI.getOpcode() != AMDGPU::RETURN) {
190 emitInstr(MI);
191 CurrentInstrIndex++;
192 }
193 }
194 }
195 // Emit S_END_PGM
196 MachineInstr * End = BuildMI(MF, DebugLoc(),
197 TM->getInstrInfo()->get(AMDGPU::S_ENDPGM));
198 emitInstr(*End);
199 return false;
200 }
201
202 void SICodeEmitter::emitInstr(MachineInstr &MI)
203 {
204 const SIInstrInfo * SII = static_cast<const SIInstrInfo*>(TM->getInstrInfo());
205
206 uint64_t hwInst = getBinaryCodeForInstr(MI);
207
208 if ((hwInst & 0xffffffff) == 0xffffffff) {
209 fprintf(stderr, "Unsupported Instruction: \n");
210 MI.dump();
211 abort();
212 }
213
214 unsigned bytes = SII->getEncodingBytes(MI);
215 outputBytes(hwInst, bytes);
216 }
217
218 uint64_t SICodeEmitter::getMachineOpValue(const MachineInstr &MI,
219 const MachineOperand &MO) const
220 {
221 const SIRegisterInfo * RI =
222 static_cast<const SIRegisterInfo*>(TM->getRegisterInfo());
223
224 switch(MO.getType()) {
225 case MachineOperand::MO_Register:
226 return RI->getBinaryCode(MO.getReg());
227
228 case MachineOperand::MO_Immediate:
229 return MO.getImm();
230
231 case MachineOperand::MO_FPImmediate:
232 // XXX: Not all instructions can use inline literals
233 // XXX: We should make sure this is a 32-bit constant
234 return LITERAL_REG;
235
236 case MachineOperand::MO_MachineBasicBlock:
237 return (*BBIndexes.find(MI.getParent()->getNumber())).second -
238 CurrentInstrIndex - 1;
239 default:
240 llvm_unreachable("Encoding of this operand type is not supported yet.");
241 break;
242 }
243 }
244
245 unsigned SICodeEmitter::GPRAlign(const MachineInstr &MI, unsigned OpNo,
246 unsigned shift) const
247 {
248 const SIRegisterInfo * RI =
249 static_cast<const SIRegisterInfo*>(TM->getRegisterInfo());
250 unsigned regCode = RI->getHWRegNum(MI.getOperand(OpNo).getReg());
251 return regCode >> shift;
252 }
253
254 unsigned SICodeEmitter::GPR4AlignEncode(const MachineInstr &MI,
255 unsigned OpNo) const
256 {
257 return GPRAlign(MI, OpNo, 2);
258 }
259
260 unsigned SICodeEmitter::GPR2AlignEncode(const MachineInstr &MI,
261 unsigned OpNo) const
262 {
263 return GPRAlign(MI, OpNo, 1);
264 }
265
266 uint64_t SICodeEmitter::i32LiteralEncode(const MachineInstr &MI,
267 unsigned OpNo) const
268 {
269 return LITERAL_REG | (MI.getOperand(OpNo).getImm() << 32);
270 }
271
272 #define SMRD_OFFSET_MASK 0xff
273 #define SMRD_IMM_SHIFT 8
274 #define SMRD_SBASE_MASK 0x3f
275 #define SMRD_SBASE_SHIFT 9
276 /// SMRDmemriEncode - This function is responsibe for encoding the offset
277 /// and the base ptr for SMRD instructions it should return a bit string in
278 /// this format:
279 ///
280 /// OFFSET = bits{7-0}
281 /// IMM = bits{8}
282 /// SBASE = bits{14-9}
283 ///
284 uint32_t SICodeEmitter::SMRDmemriEncode(const MachineInstr &MI,
285 unsigned OpNo) const
286 {
287 uint32_t encoding;
288
289 const MachineOperand &OffsetOp = MI.getOperand(OpNo + 1);
290
291 //XXX: Use this function for SMRD loads with register offsets
292 assert(OffsetOp.isImm());
293
294 encoding =
295 (getMachineOpValue(MI, OffsetOp) & SMRD_OFFSET_MASK)
296 | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit
297 | ((GPR2AlignEncode(MI, OpNo) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT)
298 ;
299
300 return encoding;
301 }
302
303 /// Set the "VGPR" bit for VOP args that can take either a VGPR or a SGPR.
304 /// XXX: It would be nice if we could handle this without a PostEncode function.
305 uint64_t SICodeEmitter::VOPPostEncode(const MachineInstr &MI,
306 uint64_t Value) const
307 {
308 const SIInstrInfo * SII = static_cast<const SIInstrInfo*>(TM->getInstrInfo());
309 unsigned encodingType = SII->getEncodingType(MI);
310 unsigned numSrcOps;
311 unsigned vgprBitOffset;
312
313 if (encodingType == SIInstrEncodingType::VOP3) {
314 numSrcOps = 3;
315 vgprBitOffset = 32;
316 } else {
317 numSrcOps = 1;
318 vgprBitOffset = 0;
319 }
320
321 // Add one to skip over the destination reg operand.
322 for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) {
323 const MachineOperand &MO = MI.getOperand(opIdx);
324 switch(MO.getType()) {
325 case MachineOperand::MO_Register:
326 {
327 unsigned reg = MI.getOperand(opIdx).getReg();
328 if (AMDGPU::VReg_32RegClass.contains(reg)
329 || AMDGPU::VReg_64RegClass.contains(reg)) {
330 Value |= (VGPR_BIT(opIdx)) << vgprBitOffset;
331 }
332 }
333 break;
334
335 case MachineOperand::MO_FPImmediate:
336 // XXX: Not all instructions can use inline literals
337 // XXX: We should make sure this is a 32-bit constant
338 Value |= (MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue() << 32);
339 continue;
340
341 default:
342 break;
343 }
344 }
345 return Value;
346 }
347
348
349 void SICodeEmitter::outputBytes(uint64_t value, unsigned bytes)
350 {
351 for (unsigned i = 0; i < bytes; i++) {
352 _OS.write((uint8_t) ((value >> (8 * i)) & 0xff));
353 }
354 }