SIMCCodeEmitter.cpp revision f4632b58c7df992e77a4be3927e7aa72c1235dff
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/MCFixup.h"
21#include "llvm/MC/MCInst.h"
22#include "llvm/MC/MCInstrInfo.h"
23#include "llvm/MC/MCRegisterInfo.h"
24#include "llvm/MC/MCSubtargetInfo.h"
25#include "llvm/Support/raw_ostream.h"
26
27using namespace llvm;
28
29namespace {
30
31/// \brief Helper type used in encoding
32typedef union {
33  int32_t I;
34  float F;
35} IntFloatUnion;
36
37class SIMCCodeEmitter : public  AMDGPUMCCodeEmitter {
38  SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION;
39  void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION;
40  const MCInstrInfo &MCII;
41  const MCRegisterInfo &MRI;
42  const MCSubtargetInfo &STI;
43  MCContext &Ctx;
44
45  /// \brief Can this operand also contain immediate values?
46  bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
47
48  /// \brief Encode an fp or int literal
49  uint32_t getLitEncoding(const MCOperand &MO) const;
50
51public:
52  SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
53                  const MCSubtargetInfo &sti, MCContext &ctx)
54    : MCII(mcii), MRI(mri), STI(sti), Ctx(ctx) { }
55
56  ~SIMCCodeEmitter() { }
57
58  /// \breif Encode the instruction and write it to the OS.
59  virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
60                         SmallVectorImpl<MCFixup> &Fixups) const;
61
62  /// \returns the encoding for an MCOperand.
63  virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
64                                     SmallVectorImpl<MCFixup> &Fixups) const;
65};
66
67} // End anonymous namespace
68
69MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
70                                           const MCRegisterInfo &MRI,
71                                           const MCSubtargetInfo &STI,
72                                           MCContext &Ctx) {
73  return new SIMCCodeEmitter(MCII, MRI, STI, Ctx);
74}
75
76bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
77                                   unsigned OpNo) const {
78
79  unsigned RegClass = Desc.OpInfo[OpNo].RegClass;
80  return (AMDGPU::SSrc_32RegClassID == RegClass) ||
81         (AMDGPU::SSrc_64RegClassID == RegClass) ||
82         (AMDGPU::VSrc_32RegClassID == RegClass) ||
83         (AMDGPU::VSrc_64RegClassID == RegClass);
84}
85
86uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const {
87
88  IntFloatUnion Imm;
89  if (MO.isImm())
90    Imm.I = MO.getImm();
91  else if (MO.isFPImm())
92    Imm.F = MO.getFPImm();
93  else
94    return ~0;
95
96  if (Imm.I >= 0 && Imm.I <= 64)
97    return 128 + Imm.I;
98
99  if (Imm.I >= -16 && Imm.I <= -1)
100    return 192 + abs(Imm.I);
101
102  if (Imm.F == 0.5f)
103    return 240;
104
105  if (Imm.F == -0.5f)
106    return 241;
107
108  if (Imm.F == 1.0f)
109    return 242;
110
111  if (Imm.F == -1.0f)
112    return 243;
113
114  if (Imm.F == 2.0f)
115    return 244;
116
117  if (Imm.F == -2.0f)
118    return 245;
119
120  if (Imm.F == 4.0f)
121    return 246;
122
123  if (Imm.F == -4.0f)
124    return 247;
125
126  return 255;
127}
128
129void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
130                                       SmallVectorImpl<MCFixup> &Fixups) const {
131
132  uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
133  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
134  unsigned bytes = Desc.getSize();
135
136  for (unsigned i = 0; i < bytes; i++) {
137    OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
138  }
139
140  if (bytes > 4)
141    return;
142
143  // Check for additional literals in SRC0/1/2 (Op 1/2/3)
144  for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
145
146    // Check if this operand should be encoded as [SV]Src
147    if (!isSrcOperand(Desc, i))
148      continue;
149
150    // Is this operand a literal immediate?
151    const MCOperand &Op = MI.getOperand(i);
152    if (getLitEncoding(Op) != 255)
153      continue;
154
155    // Yes! Encode it
156    IntFloatUnion Imm;
157    if (Op.isImm())
158      Imm.I = Op.getImm();
159    else
160      Imm.F = Op.getFPImm();
161
162    for (unsigned j = 0; j < 4; j++) {
163      OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff));
164    }
165
166    // Only one literal value allowed
167    break;
168  }
169}
170
171uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
172                                            const MCOperand &MO,
173                                       SmallVectorImpl<MCFixup> &Fixups) const {
174  if (MO.isReg())
175    return MRI.getEncodingValue(MO.getReg());
176
177  if (MO.isExpr()) {
178    const MCExpr *Expr = MO.getExpr();
179    MCFixupKind Kind = MCFixupKind(FK_PCRel_4);
180    Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc()));
181    return 0;
182  }
183
184  // Figure out the operand number, needed for isSrcOperand check
185  unsigned OpNo = 0;
186  for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
187    if (&MO == &MI.getOperand(OpNo))
188      break;
189  }
190
191  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
192  if (isSrcOperand(Desc, OpNo)) {
193    uint32_t Enc = getLitEncoding(MO);
194    if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
195      return Enc;
196
197  } else if (MO.isImm())
198    return MO.getImm();
199
200  llvm_unreachable("Encoding of this operand type is not supported yet.");
201  return 0;
202}
203
204