blob: 65f3eb5d99a436800481b30a5994c941861df63b [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
Tom Stellard067c8152014-07-21 14:01:14 +000016#include "AMDGPU.h"
Tom Stellardb4a313a2014-08-01 00:32:39 +000017#include "SIDefines.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000018#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
19#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
Tom Stellard01825af2014-07-21 14:01:08 +000020#include "MCTargetDesc/AMDGPUFixupKinds.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000021#include "llvm/MC/MCCodeEmitter.h"
22#include "llvm/MC/MCContext.h"
Chandler Carruthbe810232013-01-02 10:22:59 +000023#include "llvm/MC/MCFixup.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000024#include "llvm/MC/MCInst.h"
25#include "llvm/MC/MCInstrInfo.h"
26#include "llvm/MC/MCRegisterInfo.h"
27#include "llvm/MC/MCSubtargetInfo.h"
28#include "llvm/Support/raw_ostream.h"
29
Tom Stellard75aadc22012-12-11 21:25:42 +000030using namespace llvm;
31
32namespace {
Christian Konigc756cb992013-02-16 11:28:22 +000033
34/// \brief Helper type used in encoding
35typedef union {
36 int32_t I;
37 float F;
38} IntFloatUnion;
39
Tom Stellard75aadc22012-12-11 21:25:42 +000040class SIMCCodeEmitter : public AMDGPUMCCodeEmitter {
David Blaikie772d4f72013-02-18 23:11:17 +000041 SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION;
42 void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION;
Tom Stellard75aadc22012-12-11 21:25:42 +000043 const MCInstrInfo &MCII;
44 const MCRegisterInfo &MRI;
Tom Stellard067c8152014-07-21 14:01:14 +000045 MCContext &Ctx;
Tom Stellard75aadc22012-12-11 21:25:42 +000046
Christian Konigc756cb992013-02-16 11:28:22 +000047 /// \brief Can this operand also contain immediate values?
48 bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
49
50 /// \brief Encode an fp or int literal
51 uint32_t getLitEncoding(const MCOperand &MO) const;
52
Tom Stellard75aadc22012-12-11 21:25:42 +000053public:
54 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
David Woodhoused2cca112014-01-28 23:13:25 +000055 MCContext &ctx)
Tom Stellard067c8152014-07-21 14:01:14 +000056 : MCII(mcii), MRI(mri), Ctx(ctx) { }
Tom Stellard75aadc22012-12-11 21:25:42 +000057
58 ~SIMCCodeEmitter() { }
59
Alp Tokercb402912014-01-24 17:20:08 +000060 /// \brief Encode the instruction and write it to the OS.
Craig Topper5656db42014-04-29 07:57:24 +000061 void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
David Woodhouse9784cef2014-01-28 23:13:07 +000062 SmallVectorImpl<MCFixup> &Fixups,
Craig Topper5656db42014-04-29 07:57:24 +000063 const MCSubtargetInfo &STI) const override;
Tom Stellard75aadc22012-12-11 21:25:42 +000064
65 /// \returns the encoding for an MCOperand.
Craig Topper5656db42014-04-29 07:57:24 +000066 uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
67 SmallVectorImpl<MCFixup> &Fixups,
68 const MCSubtargetInfo &STI) const override;
Tom Stellard01825af2014-07-21 14:01:08 +000069
70 /// \brief Use a fixup to encode the simm16 field for SOPP branch
71 /// instructions.
72 unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
73 SmallVectorImpl<MCFixup> &Fixups,
74 const MCSubtargetInfo &STI) const override;
Tom Stellard75aadc22012-12-11 21:25:42 +000075};
76
77} // End anonymous namespace
78
79MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
80 const MCRegisterInfo &MRI,
81 const MCSubtargetInfo &STI,
82 MCContext &Ctx) {
David Woodhoused2cca112014-01-28 23:13:25 +000083 return new SIMCCodeEmitter(MCII, MRI, Ctx);
Tom Stellard75aadc22012-12-11 21:25:42 +000084}
85
Christian Konigc756cb992013-02-16 11:28:22 +000086bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
87 unsigned OpNo) const {
Tom Stellardb4a313a2014-08-01 00:32:39 +000088 // FIXME: We need a better way to figure out which operands can be immediate
89 // values
90 //
91 // Some VOP* instructions like ADDC use VReg32 as the register class
92 // for source 0, because they read VCC and can't take an SGPR as an
93 // argument due to constant bus restrictions.
94 if (OpNo == 1 && (Desc.TSFlags & (SIInstrFlags::VOP1 | SIInstrFlags::VOP2 |
95 SIInstrFlags::VOPC)))
96 return true;
Christian Konigc756cb992013-02-16 11:28:22 +000097
98 unsigned RegClass = Desc.OpInfo[OpNo].RegClass;
99 return (AMDGPU::SSrc_32RegClassID == RegClass) ||
100 (AMDGPU::SSrc_64RegClassID == RegClass) ||
101 (AMDGPU::VSrc_32RegClassID == RegClass) ||
102 (AMDGPU::VSrc_64RegClassID == RegClass);
103}
104
105uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const {
106
107 IntFloatUnion Imm;
108 if (MO.isImm())
109 Imm.I = MO.getImm();
110 else if (MO.isFPImm())
111 Imm.F = MO.getFPImm();
Tom Stellard067c8152014-07-21 14:01:14 +0000112 else if (MO.isExpr())
113 return 255;
Christian Konigc756cb992013-02-16 11:28:22 +0000114 else
115 return ~0;
116
117 if (Imm.I >= 0 && Imm.I <= 64)
118 return 128 + Imm.I;
119
120 if (Imm.I >= -16 && Imm.I <= -1)
121 return 192 + abs(Imm.I);
122
123 if (Imm.F == 0.5f)
124 return 240;
125
126 if (Imm.F == -0.5f)
127 return 241;
128
129 if (Imm.F == 1.0f)
130 return 242;
131
132 if (Imm.F == -1.0f)
133 return 243;
134
135 if (Imm.F == 2.0f)
136 return 244;
137
138 if (Imm.F == -2.0f)
139 return 245;
140
141 if (Imm.F == 4.0f)
142 return 246;
143
Christian Konigd76ed542013-02-26 17:51:57 +0000144 if (Imm.F == -4.0f)
Christian Konigc756cb992013-02-16 11:28:22 +0000145 return 247;
146
147 return 255;
148}
149
Tom Stellard75aadc22012-12-11 21:25:42 +0000150void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
David Woodhouse9784cef2014-01-28 23:13:07 +0000151 SmallVectorImpl<MCFixup> &Fixups,
152 const MCSubtargetInfo &STI) const {
Christian Konigc756cb992013-02-16 11:28:22 +0000153
David Woodhouse3fa98a62014-01-28 23:13:18 +0000154 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
Christian Konigc756cb992013-02-16 11:28:22 +0000155 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
156 unsigned bytes = Desc.getSize();
157
Tom Stellard75aadc22012-12-11 21:25:42 +0000158 for (unsigned i = 0; i < bytes; i++) {
159 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
160 }
Christian Konigc756cb992013-02-16 11:28:22 +0000161
162 if (bytes > 4)
163 return;
164
165 // Check for additional literals in SRC0/1/2 (Op 1/2/3)
166 for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
167
168 // Check if this operand should be encoded as [SV]Src
169 if (!isSrcOperand(Desc, i))
170 continue;
171
172 // Is this operand a literal immediate?
173 const MCOperand &Op = MI.getOperand(i);
174 if (getLitEncoding(Op) != 255)
175 continue;
176
177 // Yes! Encode it
178 IntFloatUnion Imm;
179 if (Op.isImm())
180 Imm.I = Op.getImm();
Tom Stellard067c8152014-07-21 14:01:14 +0000181 else if (Op.isFPImm())
Christian Konigc756cb992013-02-16 11:28:22 +0000182 Imm.F = Op.getFPImm();
Tom Stellard067c8152014-07-21 14:01:14 +0000183 else {
184 assert(Op.isExpr());
185 // This will be replaced with a fixup value.
186 Imm.I = 0;
187 }
Christian Konigc756cb992013-02-16 11:28:22 +0000188
189 for (unsigned j = 0; j < 4; j++) {
190 OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff));
191 }
192
193 // Only one literal value allowed
194 break;
195 }
Tom Stellard75aadc22012-12-11 21:25:42 +0000196}
197
Tom Stellard01825af2014-07-21 14:01:08 +0000198unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
199 SmallVectorImpl<MCFixup> &Fixups,
200 const MCSubtargetInfo &STI) const {
201 const MCOperand &MO = MI.getOperand(OpNo);
202
203 if (MO.isExpr()) {
204 const MCExpr *Expr = MO.getExpr();
205 MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br;
206 Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc()));
207 return 0;
208 }
209
210 return getMachineOpValue(MI, MO, Fixups, STI);
211}
212
Tom Stellard75aadc22012-12-11 21:25:42 +0000213uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
214 const MCOperand &MO,
David Woodhouse3fa98a62014-01-28 23:13:18 +0000215 SmallVectorImpl<MCFixup> &Fixups,
216 const MCSubtargetInfo &STI) const {
Christian Konigc756cb992013-02-16 11:28:22 +0000217 if (MO.isReg())
Tom Stellard1c822a82013-02-07 19:39:45 +0000218 return MRI.getEncodingValue(MO.getReg());
Christian Konigc756cb992013-02-16 11:28:22 +0000219
Tom Stellard067c8152014-07-21 14:01:14 +0000220 if (MO.isExpr()) {
221 const MCSymbolRefExpr *Expr = cast<MCSymbolRefExpr>(MO.getExpr());
222 MCFixupKind Kind;
223 const MCSymbol *Sym =
224 Ctx.GetOrCreateSymbol(StringRef(END_OF_TEXT_LABEL_NAME));
225
226 if (&Expr->getSymbol() == Sym) {
227 // Add the offset to the beginning of the constant values.
228 Kind = (MCFixupKind)AMDGPU::fixup_si_end_of_text;
229 } else {
230 // This is used for constant data stored in .rodata.
231 Kind = (MCFixupKind)AMDGPU::fixup_si_rodata;
232 }
233 Fixups.push_back(MCFixup::Create(4, Expr, Kind, MI.getLoc()));
234 }
235
Christian Konigc756cb992013-02-16 11:28:22 +0000236 // Figure out the operand number, needed for isSrcOperand check
237 unsigned OpNo = 0;
238 for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
239 if (&MO == &MI.getOperand(OpNo))
240 break;
241 }
242
243 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
244 if (isSrcOperand(Desc, OpNo)) {
245 uint32_t Enc = getLitEncoding(MO);
246 if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
247 return Enc;
248
249 } else if (MO.isImm())
250 return MO.getImm();
251
252 llvm_unreachable("Encoding of this operand type is not supported yet.");
Tom Stellard75aadc22012-12-11 21:25:42 +0000253 return 0;
254}
255