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