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