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 /// \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 "AMDGPU.h"
17 #include "MCTargetDesc/AMDGPUFixupKinds.h"
18 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
19 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
20 #include "SIDefines.h"
21 #include "Utils/AMDGPUBaseInfo.h"
22 #include "llvm/MC/MCCodeEmitter.h"
23 #include "llvm/MC/MCContext.h"
24 #include "llvm/MC/MCFixup.h"
25 #include "llvm/MC/MCInst.h"
26 #include "llvm/MC/MCInstrInfo.h"
27 #include "llvm/MC/MCRegisterInfo.h"
28 #include "llvm/MC/MCSubtargetInfo.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/Support/raw_ostream.h"
31 
32 using namespace llvm;
33 
34 namespace {
35 
36 class SIMCCodeEmitter : public  AMDGPUMCCodeEmitter {
37   SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
38   void operator=(const SIMCCodeEmitter &) = delete;
39   const MCRegisterInfo &MRI;
40 
41   /// \brief Encode an fp or int literal
42   uint32_t getLitEncoding(const MCOperand &MO, const MCOperandInfo &OpInfo,
43                           const MCSubtargetInfo &STI) const;
44 
45 public:
46   SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
47                   MCContext &ctx)
48       : AMDGPUMCCodeEmitter(mcii), MRI(mri) {}
49 
50   ~SIMCCodeEmitter() override {}
51 
52   /// \brief Encode the instruction and write it to the OS.
53   void encodeInstruction(const MCInst &MI, raw_ostream &OS,
54                          SmallVectorImpl<MCFixup> &Fixups,
55                          const MCSubtargetInfo &STI) const override;
56 
57   /// \returns the encoding for an MCOperand.
58   uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
59                              SmallVectorImpl<MCFixup> &Fixups,
60                              const MCSubtargetInfo &STI) const override;
61 
62   /// \brief Use a fixup to encode the simm16 field for SOPP branch
63   ///        instructions.
64   unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
65                              SmallVectorImpl<MCFixup> &Fixups,
66                              const MCSubtargetInfo &STI) const override;
67 };
68 
69 } // End anonymous namespace
70 
71 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
72                                            const MCRegisterInfo &MRI,
73                                            MCContext &Ctx) {
74   return new SIMCCodeEmitter(MCII, MRI, Ctx);
75 }
76 
77 // Returns the encoding value to use if the given integer is an integer inline
78 // immediate value, or 0 if it is not.
79 template <typename IntTy>
80 static uint32_t getIntInlineImmEncoding(IntTy Imm) {
81   if (Imm >= 0 && Imm <= 64)
82     return 128 + Imm;
83 
84   if (Imm >= -16 && Imm <= -1)
85     return 192 + std::abs(Imm);
86 
87   return 0;
88 }
89 
90 static uint32_t getLit16Encoding(uint16_t Val, const MCSubtargetInfo &STI) {
91   uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
92   if (IntImm != 0)
93     return IntImm;
94 
95   if (Val == 0x3800) // 0.5
96     return 240;
97 
98   if (Val == 0xB800) // -0.5
99     return 241;
100 
101   if (Val == 0x3C00) // 1.0
102     return 242;
103 
104   if (Val == 0xBC00) // -1.0
105     return 243;
106 
107   if (Val == 0x4000) // 2.0
108     return 244;
109 
110   if (Val == 0xC000) // -2.0
111     return 245;
112 
113   if (Val == 0x4400) // 4.0
114     return 246;
115 
116   if (Val == 0xC400) // -4.0
117     return 247;
118 
119   if (Val == 0x3118 && // 1.0 / (2.0 * pi)
120       STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
121     return 248;
122 
123   return 255;
124 }
125 
126 static uint32_t getLit32Encoding(uint32_t Val, const MCSubtargetInfo &STI) {
127   uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
128   if (IntImm != 0)
129     return IntImm;
130 
131   if (Val == FloatToBits(0.5f))
132     return 240;
133 
134   if (Val == FloatToBits(-0.5f))
135     return 241;
136 
137   if (Val == FloatToBits(1.0f))
138     return 242;
139 
140   if (Val == FloatToBits(-1.0f))
141     return 243;
142 
143   if (Val == FloatToBits(2.0f))
144     return 244;
145 
146   if (Val == FloatToBits(-2.0f))
147     return 245;
148 
149   if (Val == FloatToBits(4.0f))
150     return 246;
151 
152   if (Val == FloatToBits(-4.0f))
153     return 247;
154 
155   if (Val == 0x3e22f983 && // 1.0 / (2.0 * pi)
156       STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
157     return 248;
158 
159   return 255;
160 }
161 
162 static uint32_t getLit64Encoding(uint64_t Val, const MCSubtargetInfo &STI) {
163   uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
164   if (IntImm != 0)
165     return IntImm;
166 
167   if (Val == DoubleToBits(0.5))
168     return 240;
169 
170   if (Val == DoubleToBits(-0.5))
171     return 241;
172 
173   if (Val == DoubleToBits(1.0))
174     return 242;
175 
176   if (Val == DoubleToBits(-1.0))
177     return 243;
178 
179   if (Val == DoubleToBits(2.0))
180     return 244;
181 
182   if (Val == DoubleToBits(-2.0))
183     return 245;
184 
185   if (Val == DoubleToBits(4.0))
186     return 246;
187 
188   if (Val == DoubleToBits(-4.0))
189     return 247;
190 
191   if (Val == 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
192       STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
193     return 248;
194 
195   return 255;
196 }
197 
198 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
199                                          const MCOperandInfo &OpInfo,
200                                          const MCSubtargetInfo &STI) const {
201 
202   int64_t Imm;
203   if (MO.isExpr()) {
204     const MCConstantExpr *C = dyn_cast<MCConstantExpr>(MO.getExpr());
205     if (!C)
206       return 255;
207 
208     Imm = C->getValue();
209   } else {
210 
211     assert(!MO.isFPImm());
212 
213     if (!MO.isImm())
214       return ~0;
215 
216     Imm = MO.getImm();
217   }
218 
219   switch (AMDGPU::getOperandSize(OpInfo)) {
220   case 4:
221     return getLit32Encoding(static_cast<uint32_t>(Imm), STI);
222   case 8:
223     return getLit64Encoding(static_cast<uint64_t>(Imm), STI);
224   case 2:
225     return getLit16Encoding(static_cast<uint16_t>(Imm), STI);
226   default:
227     llvm_unreachable("invalid operand size");
228   }
229 }
230 
231 void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
232                                        SmallVectorImpl<MCFixup> &Fixups,
233                                        const MCSubtargetInfo &STI) const {
234   verifyInstructionPredicates(MI,
235                               computeAvailableFeatures(STI.getFeatureBits()));
236 
237   uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
238   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
239   unsigned bytes = Desc.getSize();
240 
241   for (unsigned i = 0; i < bytes; i++) {
242     OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
243   }
244 
245   if (bytes > 4)
246     return;
247 
248   // Check for additional literals in SRC0/1/2 (Op 1/2/3)
249   for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
250 
251     // Check if this operand should be encoded as [SV]Src
252     if (!AMDGPU::isSISrcOperand(Desc, i))
253       continue;
254 
255     // Is this operand a literal immediate?
256     const MCOperand &Op = MI.getOperand(i);
257     if (getLitEncoding(Op, Desc.OpInfo[i], STI) != 255)
258       continue;
259 
260     // Yes! Encode it
261     int64_t Imm = 0;
262 
263     if (Op.isImm())
264       Imm = Op.getImm();
265     else if (Op.isExpr()) {
266       if (const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Op.getExpr()))
267         Imm = C->getValue();
268 
269     } else if (!Op.isExpr()) // Exprs will be replaced with a fixup value.
270       llvm_unreachable("Must be immediate or expr");
271 
272     for (unsigned j = 0; j < 4; j++) {
273       OS.write((uint8_t) ((Imm >> (8 * j)) & 0xff));
274     }
275 
276     // Only one literal value allowed
277     break;
278   }
279 }
280 
281 unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
282                                             SmallVectorImpl<MCFixup> &Fixups,
283                                             const MCSubtargetInfo &STI) const {
284   const MCOperand &MO = MI.getOperand(OpNo);
285 
286   if (MO.isExpr()) {
287     const MCExpr *Expr = MO.getExpr();
288     MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br;
289     Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc()));
290     return 0;
291   }
292 
293   return getMachineOpValue(MI, MO, Fixups, STI);
294 }
295 
296 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
297                                             const MCOperand &MO,
298                                        SmallVectorImpl<MCFixup> &Fixups,
299                                        const MCSubtargetInfo &STI) const {
300   if (MO.isReg())
301     return MRI.getEncodingValue(MO.getReg());
302 
303   if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) {
304     const MCSymbolRefExpr *Expr = dyn_cast<MCSymbolRefExpr>(MO.getExpr());
305     MCFixupKind Kind;
306     if (Expr && Expr->getSymbol().isExternal())
307       Kind = FK_Data_4;
308     else
309       Kind = FK_PCRel_4;
310     Fixups.push_back(MCFixup::create(4, MO.getExpr(), Kind, MI.getLoc()));
311   }
312 
313   // Figure out the operand number, needed for isSrcOperand check
314   unsigned OpNo = 0;
315   for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
316     if (&MO == &MI.getOperand(OpNo))
317       break;
318   }
319 
320   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
321   if (AMDGPU::isSISrcOperand(Desc, OpNo)) {
322     uint32_t Enc = getLitEncoding(MO, Desc.OpInfo[OpNo], STI);
323     if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
324       return Enc;
325 
326   } else if (MO.isImm())
327     return MO.getImm();
328 
329   llvm_unreachable("Encoding of this operand type is not supported yet.");
330   return 0;
331 }
332 
333