OSDN Git Service

R600: BB operand support for SI
[android-x86/external-llvm.git] / lib / Target / R600 / MCTargetDesc / SIMCCodeEmitter.cpp
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 "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/MC/MCFixup.h"
25 #include "llvm/Support/raw_ostream.h"
26
27 #define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1))
28 #define SI_INSTR_FLAGS_ENCODING_MASK 0xf
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 MCRegisterInfo &MRI;
64   const MCSubtargetInfo &STI;
65   MCContext &Ctx;
66
67 public:
68   SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
69                   const MCSubtargetInfo &sti, MCContext &ctx)
70     : MCII(mcii), MRI(mri), STI(sti), Ctx(ctx) { }
71
72   ~SIMCCodeEmitter() { }
73
74   /// \breif Encode the instruction and write it to the OS.
75   virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
76                          SmallVectorImpl<MCFixup> &Fixups) const;
77
78   /// \returns the encoding for an MCOperand.
79   virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
80                                      SmallVectorImpl<MCFixup> &Fixups) const;
81
82 public:
83
84   /// \brief Encode a sequence of registers with the correct alignment.
85   unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const;
86
87   /// \brief Encoding for when 2 consecutive registers are used
88   virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo,
89                                    SmallVectorImpl<MCFixup> &Fixup) const;
90
91   /// \brief Encoding for when 4 consectuive registers are used
92   virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo,
93                                    SmallVectorImpl<MCFixup> &Fixup) const;
94
95   /// \brief Encoding for SMRD indexed loads
96   virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
97                                    SmallVectorImpl<MCFixup> &Fixup) const;
98
99   /// \brief Post-Encoder method for VOP instructions
100   virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const;
101
102 private:
103
104   /// \returns this SIInstrEncodingType for this instruction.
105   unsigned getEncodingType(const MCInst &MI) const;
106
107   /// \brief Get then size in bytes of this instructions encoding.
108   unsigned getEncodingBytes(const MCInst &MI) const;
109
110   /// \returns the hardware encoding for a register
111   unsigned getRegBinaryCode(unsigned reg) const;
112
113   /// \brief Generated function that returns the hardware encoding for
114   /// a register
115   unsigned getHWRegNum(unsigned reg) const;
116
117 };
118
119 } // End anonymous namespace
120
121 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
122                                            const MCRegisterInfo &MRI,
123                                            const MCSubtargetInfo &STI,
124                                            MCContext &Ctx) {
125   return new SIMCCodeEmitter(MCII, MRI, STI, Ctx);
126 }
127
128 void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
129                                        SmallVectorImpl<MCFixup> &Fixups) const {
130   uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
131   unsigned bytes = getEncodingBytes(MI);
132   for (unsigned i = 0; i < bytes; i++) {
133     OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
134   }
135 }
136
137 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
138                                             const MCOperand &MO,
139                                        SmallVectorImpl<MCFixup> &Fixups) const {
140   if (MO.isReg()) {
141     return getRegBinaryCode(MO.getReg());
142   } else if (MO.isImm()) {
143     return MO.getImm();
144   } else if (MO.isFPImm()) {
145     // XXX: Not all instructions can use inline literals
146     // XXX: We should make sure this is a 32-bit constant
147     union {
148       float F;
149       uint32_t I;
150     } Imm;
151     Imm.F = MO.getFPImm();
152     return Imm.I;
153   } else if (MO.isExpr()) {
154     const MCExpr *Expr = MO.getExpr();
155     MCFixupKind Kind = MCFixupKind(FK_PCRel_4);
156     Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc()));
157     return 0;
158   } else{
159     llvm_unreachable("Encoding of this operand type is not supported yet.");
160   }
161   return 0;
162 }
163
164 //===----------------------------------------------------------------------===//
165 // Custom Operand Encodings
166 //===----------------------------------------------------------------------===//
167
168 unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo,
169                                    unsigned shift) const {
170   unsigned regCode = getRegBinaryCode(MI.getOperand(OpNo).getReg());
171   return regCode >> shift;
172   return 0;
173 }
174 unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI,
175                                           unsigned OpNo ,
176                                         SmallVectorImpl<MCFixup> &Fixup) const {
177   return GPRAlign(MI, OpNo, 1);
178 }
179
180 unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI,
181                                           unsigned OpNo,
182                                         SmallVectorImpl<MCFixup> &Fixup) const {
183   return GPRAlign(MI, OpNo, 2);
184 }
185
186 #define SMRD_OFFSET_MASK 0xff
187 #define SMRD_IMM_SHIFT 8
188 #define SMRD_SBASE_MASK 0x3f
189 #define SMRD_SBASE_SHIFT 9
190 /// This function is responsibe for encoding the offset
191 /// and the base ptr for SMRD instructions it should return a bit string in
192 /// this format:
193 ///
194 /// OFFSET = bits{7-0}
195 /// IMM    = bits{8}
196 /// SBASE  = bits{14-9}
197 ///
198 uint32_t SIMCCodeEmitter::SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
199                                         SmallVectorImpl<MCFixup> &Fixup) const {
200   uint32_t Encoding;
201
202   const MCOperand &OffsetOp = MI.getOperand(OpNo + 1);
203
204   //XXX: Use this function for SMRD loads with register offsets
205   assert(OffsetOp.isImm());
206
207   Encoding =
208       (getMachineOpValue(MI, OffsetOp, Fixup) & SMRD_OFFSET_MASK)
209     | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit
210     | ((GPR2AlignEncode(MI, OpNo, Fixup) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT)
211     ;
212
213   return Encoding;
214 }
215
216 //===----------------------------------------------------------------------===//
217 // Post Encoder Callbacks
218 //===----------------------------------------------------------------------===//
219
220 uint64_t SIMCCodeEmitter::VOPPostEncode(const MCInst &MI, uint64_t Value) const{
221   unsigned encodingType = getEncodingType(MI);
222   unsigned numSrcOps;
223   unsigned vgprBitOffset;
224
225   if (encodingType == SIInstrEncodingType::VOP3) {
226     numSrcOps = 3;
227     vgprBitOffset = 32;
228   } else {
229     numSrcOps = 1;
230     vgprBitOffset = 0;
231   }
232
233   // Add one to skip over the destination reg operand.
234   for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) {
235     const MCOperand &MO = MI.getOperand(opIdx);
236     if (MO.isReg()) {
237       unsigned reg = MI.getOperand(opIdx).getReg();
238       if (AMDGPUMCRegisterClasses[AMDGPU::VReg_32RegClassID].contains(reg) ||
239           AMDGPUMCRegisterClasses[AMDGPU::VReg_64RegClassID].contains(reg)) {
240         Value |= (VGPR_BIT(opIdx)) << vgprBitOffset;
241       }
242     } else if (MO.isFPImm()) {
243       union {
244         float f;
245         uint32_t i;
246       } Imm;
247       // XXX: Not all instructions can use inline literals
248       // XXX: We should make sure this is a 32-bit constant
249       Imm.f = MO.getFPImm();
250       Value |= ((uint64_t)Imm.i) << 32;
251     }
252   }
253   return Value;
254 }
255
256 //===----------------------------------------------------------------------===//
257 // Encoding helper functions
258 //===----------------------------------------------------------------------===//
259
260 unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const {
261   return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK;
262 }
263
264 unsigned SIMCCodeEmitter::getEncodingBytes(const MCInst &MI) const {
265
266   // These instructions aren't real instructions with an encoding type, so
267   // we need to manually specify their size.
268   switch (MI.getOpcode()) {
269   default: break;
270   case AMDGPU::SI_LOAD_LITERAL_I32:
271   case AMDGPU::SI_LOAD_LITERAL_F32:
272     return 4;
273   }
274
275   unsigned encoding_type = getEncodingType(MI);
276   switch (encoding_type) {
277     case SIInstrEncodingType::EXP:
278     case SIInstrEncodingType::LDS:
279     case SIInstrEncodingType::MUBUF:
280     case SIInstrEncodingType::MTBUF:
281     case SIInstrEncodingType::MIMG:
282     case SIInstrEncodingType::VOP3:
283       return 8;
284     default:
285       return 4;
286   }
287 }
288
289
290 unsigned SIMCCodeEmitter::getRegBinaryCode(unsigned reg) const {
291   switch (reg) {
292     case AMDGPU::M0: return 124;
293     case AMDGPU::SREG_LIT_0: return 128;
294     case AMDGPU::SI_LITERAL_CONSTANT: return 255;
295     default: return MRI.getEncodingValue(reg);
296   }
297 }
298