blob: 7f271d1c4541c4646fefca5dd5d648700c077055 [file] [log] [blame]
Tom Stellard75aadc22012-12-11 21:25:42 +00001//===-- SIMCCodeEmitter.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/// \file
11/// \brief The SI code emitter produces machine code that can be executed
12/// directly on the GPU device.
13//
14//===----------------------------------------------------------------------===//
15
16#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
18#include "llvm/MC/MCCodeEmitter.h"
19#include "llvm/MC/MCContext.h"
20#include "llvm/MC/MCInst.h"
21#include "llvm/MC/MCInstrInfo.h"
22#include "llvm/MC/MCRegisterInfo.h"
23#include "llvm/MC/MCSubtargetInfo.h"
24#include "llvm/Support/raw_ostream.h"
25
26#define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1))
27#define SI_INSTR_FLAGS_ENCODING_MASK 0xf
28
29// These must be kept in sync with SIInstructions.td and also the
30// InstrEncodingInfo array in SIInstrInfo.cpp.
31//
32// NOTE: This enum is only used to identify the encoding type within LLVM,
33// the actual encoding type that is part of the instruction format is different
34namespace SIInstrEncodingType {
35 enum Encoding {
36 EXP = 0,
37 LDS = 1,
38 MIMG = 2,
39 MTBUF = 3,
40 MUBUF = 4,
41 SMRD = 5,
42 SOP1 = 6,
43 SOP2 = 7,
44 SOPC = 8,
45 SOPK = 9,
46 SOPP = 10,
47 VINTRP = 11,
48 VOP1 = 12,
49 VOP2 = 13,
50 VOP3 = 14,
51 VOPC = 15
52 };
53}
54
55using namespace llvm;
56
57namespace {
58class SIMCCodeEmitter : public AMDGPUMCCodeEmitter {
59 SIMCCodeEmitter(const SIMCCodeEmitter &); // DO NOT IMPLEMENT
60 void operator=(const SIMCCodeEmitter &); // DO NOT IMPLEMENT
61 const MCInstrInfo &MCII;
62 const MCRegisterInfo &MRI;
63 const MCSubtargetInfo &STI;
64 MCContext &Ctx;
65
66public:
67 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
68 const MCSubtargetInfo &sti, MCContext &ctx)
69 : MCII(mcii), MRI(mri), STI(sti), Ctx(ctx) { }
70
71 ~SIMCCodeEmitter() { }
72
73 /// \breif Encode the instruction and write it to the OS.
74 virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
75 SmallVectorImpl<MCFixup> &Fixups) const;
76
77 /// \returns the encoding for an MCOperand.
78 virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
79 SmallVectorImpl<MCFixup> &Fixups) const;
80
81public:
82
83 /// \brief Encode a sequence of registers with the correct alignment.
84 unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const;
85
86 /// \brief Encoding for when 2 consecutive registers are used
87 virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo,
88 SmallVectorImpl<MCFixup> &Fixup) const;
89
90 /// \brief Encoding for when 4 consectuive registers are used
91 virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo,
92 SmallVectorImpl<MCFixup> &Fixup) const;
93
94 /// \brief Encoding for SMRD indexed loads
95 virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
96 SmallVectorImpl<MCFixup> &Fixup) const;
97
98 /// \brief Post-Encoder method for VOP instructions
99 virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const;
100
101private:
102
103 /// \returns this SIInstrEncodingType for this instruction.
104 unsigned getEncodingType(const MCInst &MI) const;
105
106 /// \brief Get then size in bytes of this instructions encoding.
107 unsigned getEncodingBytes(const MCInst &MI) const;
108
109 /// \returns the hardware encoding for a register
110 unsigned getRegBinaryCode(unsigned reg) const;
111
112 /// \brief Generated function that returns the hardware encoding for
113 /// a register
114 unsigned getHWRegNum(unsigned reg) const;
115
116};
117
118} // End anonymous namespace
119
120MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
121 const MCRegisterInfo &MRI,
122 const MCSubtargetInfo &STI,
123 MCContext &Ctx) {
124 return new SIMCCodeEmitter(MCII, MRI, STI, Ctx);
125}
126
127void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
128 SmallVectorImpl<MCFixup> &Fixups) const {
129 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
130 unsigned bytes = getEncodingBytes(MI);
131 for (unsigned i = 0; i < bytes; i++) {
132 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
133 }
134}
135
136uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
137 const MCOperand &MO,
138 SmallVectorImpl<MCFixup> &Fixups) const {
139 if (MO.isReg()) {
140 return getRegBinaryCode(MO.getReg());
141 } else if (MO.isImm()) {
142 return MO.getImm();
143 } else if (MO.isFPImm()) {
144 // XXX: Not all instructions can use inline literals
145 // XXX: We should make sure this is a 32-bit constant
146 union {
147 float F;
148 uint32_t I;
149 } Imm;
150 Imm.F = MO.getFPImm();
151 return Imm.I;
152 } else{
153 llvm_unreachable("Encoding of this operand type is not supported yet.");
154 }
155 return 0;
156}
157
158//===----------------------------------------------------------------------===//
159// Custom Operand Encodings
160//===----------------------------------------------------------------------===//
161
162unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo,
163 unsigned shift) const {
164 unsigned regCode = getRegBinaryCode(MI.getOperand(OpNo).getReg());
165 return regCode >> shift;
166 return 0;
167}
168unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI,
169 unsigned OpNo ,
170 SmallVectorImpl<MCFixup> &Fixup) const {
171 return GPRAlign(MI, OpNo, 1);
172}
173
174unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI,
175 unsigned OpNo,
176 SmallVectorImpl<MCFixup> &Fixup) const {
177 return GPRAlign(MI, OpNo, 2);
178}
179
180#define SMRD_OFFSET_MASK 0xff
181#define SMRD_IMM_SHIFT 8
182#define SMRD_SBASE_MASK 0x3f
183#define SMRD_SBASE_SHIFT 9
184/// This function is responsibe for encoding the offset
185/// and the base ptr for SMRD instructions it should return a bit string in
186/// this format:
187///
188/// OFFSET = bits{7-0}
189/// IMM = bits{8}
190/// SBASE = bits{14-9}
191///
192uint32_t SIMCCodeEmitter::SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
193 SmallVectorImpl<MCFixup> &Fixup) const {
194 uint32_t Encoding;
195
196 const MCOperand &OffsetOp = MI.getOperand(OpNo + 1);
197
198 //XXX: Use this function for SMRD loads with register offsets
199 assert(OffsetOp.isImm());
200
201 Encoding =
202 (getMachineOpValue(MI, OffsetOp, Fixup) & SMRD_OFFSET_MASK)
203 | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit
204 | ((GPR2AlignEncode(MI, OpNo, Fixup) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT)
205 ;
206
207 return Encoding;
208}
209
210//===----------------------------------------------------------------------===//
211// Post Encoder Callbacks
212//===----------------------------------------------------------------------===//
213
214uint64_t SIMCCodeEmitter::VOPPostEncode(const MCInst &MI, uint64_t Value) const{
215 unsigned encodingType = getEncodingType(MI);
216 unsigned numSrcOps;
217 unsigned vgprBitOffset;
218
219 if (encodingType == SIInstrEncodingType::VOP3) {
220 numSrcOps = 3;
221 vgprBitOffset = 32;
222 } else {
223 numSrcOps = 1;
224 vgprBitOffset = 0;
225 }
226
227 // Add one to skip over the destination reg operand.
228 for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) {
229 const MCOperand &MO = MI.getOperand(opIdx);
230 if (MO.isReg()) {
231 unsigned reg = MI.getOperand(opIdx).getReg();
232 if (AMDGPUMCRegisterClasses[AMDGPU::VReg_32RegClassID].contains(reg) ||
233 AMDGPUMCRegisterClasses[AMDGPU::VReg_64RegClassID].contains(reg)) {
234 Value |= (VGPR_BIT(opIdx)) << vgprBitOffset;
235 }
236 } else if (MO.isFPImm()) {
237 union {
238 float f;
239 uint32_t i;
240 } Imm;
241 // XXX: Not all instructions can use inline literals
242 // XXX: We should make sure this is a 32-bit constant
243 Imm.f = MO.getFPImm();
244 Value |= ((uint64_t)Imm.i) << 32;
245 }
246 }
247 return Value;
248}
249
250//===----------------------------------------------------------------------===//
251// Encoding helper functions
252//===----------------------------------------------------------------------===//
253
254unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const {
255 return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK;
256}
257
258unsigned SIMCCodeEmitter::getEncodingBytes(const MCInst &MI) const {
259
260 // These instructions aren't real instructions with an encoding type, so
261 // we need to manually specify their size.
262 switch (MI.getOpcode()) {
263 default: break;
264 case AMDGPU::SI_LOAD_LITERAL_I32:
265 case AMDGPU::SI_LOAD_LITERAL_F32:
266 return 4;
267 }
268
269 unsigned encoding_type = getEncodingType(MI);
270 switch (encoding_type) {
271 case SIInstrEncodingType::EXP:
272 case SIInstrEncodingType::LDS:
273 case SIInstrEncodingType::MUBUF:
274 case SIInstrEncodingType::MTBUF:
275 case SIInstrEncodingType::MIMG:
276 case SIInstrEncodingType::VOP3:
277 return 8;
278 default:
279 return 4;
280 }
281}
282
283
284unsigned SIMCCodeEmitter::getRegBinaryCode(unsigned reg) const {
285 switch (reg) {
286 case AMDGPU::M0: return 124;
287 case AMDGPU::SREG_LIT_0: return 128;
288 case AMDGPU::SI_LITERAL_CONSTANT: return 255;
289 default: return MRI.getEncodingValue(reg);
290 }
291}
292