1249259Sdim//===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim/// \file
11249259Sdim/// \brief The SI code emitter produces machine code that can be executed
12249259Sdim/// directly on the GPU device.
13249259Sdim//
14249259Sdim//===----------------------------------------------------------------------===//
15249259Sdim
16249259Sdim#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17249259Sdim#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
18249259Sdim#include "llvm/MC/MCCodeEmitter.h"
19249259Sdim#include "llvm/MC/MCContext.h"
20249259Sdim#include "llvm/MC/MCFixup.h"
21249259Sdim#include "llvm/MC/MCInst.h"
22249259Sdim#include "llvm/MC/MCInstrInfo.h"
23249259Sdim#include "llvm/MC/MCRegisterInfo.h"
24249259Sdim#include "llvm/MC/MCSubtargetInfo.h"
25249259Sdim#include "llvm/Support/raw_ostream.h"
26249259Sdim
27249259Sdimusing namespace llvm;
28249259Sdim
29249259Sdimnamespace {
30249259Sdim
31249259Sdim/// \brief Helper type used in encoding
32249259Sdimtypedef union {
33249259Sdim  int32_t I;
34249259Sdim  float F;
35249259Sdim} IntFloatUnion;
36249259Sdim
37249259Sdimclass SIMCCodeEmitter : public  AMDGPUMCCodeEmitter {
38249259Sdim  SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION;
39249259Sdim  void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION;
40249259Sdim  const MCInstrInfo &MCII;
41249259Sdim  const MCRegisterInfo &MRI;
42249259Sdim
43249259Sdim  /// \brief Can this operand also contain immediate values?
44249259Sdim  bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
45249259Sdim
46249259Sdim  /// \brief Encode an fp or int literal
47249259Sdim  uint32_t getLitEncoding(const MCOperand &MO) const;
48249259Sdim
49249259Sdimpublic:
50249259Sdim  SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
51249259Sdim                  const MCSubtargetInfo &sti, MCContext &ctx)
52249259Sdim    : MCII(mcii), MRI(mri) { }
53249259Sdim
54249259Sdim  ~SIMCCodeEmitter() { }
55249259Sdim
56249259Sdim  /// \breif Encode the instruction and write it to the OS.
57249259Sdim  virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
58249259Sdim                         SmallVectorImpl<MCFixup> &Fixups) const;
59249259Sdim
60249259Sdim  /// \returns the encoding for an MCOperand.
61249259Sdim  virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
62249259Sdim                                     SmallVectorImpl<MCFixup> &Fixups) const;
63249259Sdim};
64249259Sdim
65249259Sdim} // End anonymous namespace
66249259Sdim
67249259SdimMCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
68249259Sdim                                           const MCRegisterInfo &MRI,
69249259Sdim                                           const MCSubtargetInfo &STI,
70249259Sdim                                           MCContext &Ctx) {
71249259Sdim  return new SIMCCodeEmitter(MCII, MRI, STI, Ctx);
72249259Sdim}
73249259Sdim
74249259Sdimbool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
75249259Sdim                                   unsigned OpNo) const {
76249259Sdim
77249259Sdim  unsigned RegClass = Desc.OpInfo[OpNo].RegClass;
78249259Sdim  return (AMDGPU::SSrc_32RegClassID == RegClass) ||
79249259Sdim         (AMDGPU::SSrc_64RegClassID == RegClass) ||
80249259Sdim         (AMDGPU::VSrc_32RegClassID == RegClass) ||
81249259Sdim         (AMDGPU::VSrc_64RegClassID == RegClass);
82249259Sdim}
83249259Sdim
84249259Sdimuint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const {
85249259Sdim
86249259Sdim  IntFloatUnion Imm;
87249259Sdim  if (MO.isImm())
88249259Sdim    Imm.I = MO.getImm();
89249259Sdim  else if (MO.isFPImm())
90249259Sdim    Imm.F = MO.getFPImm();
91249259Sdim  else
92249259Sdim    return ~0;
93249259Sdim
94249259Sdim  if (Imm.I >= 0 && Imm.I <= 64)
95249259Sdim    return 128 + Imm.I;
96249259Sdim
97249259Sdim  if (Imm.I >= -16 && Imm.I <= -1)
98249259Sdim    return 192 + abs(Imm.I);
99249259Sdim
100249259Sdim  if (Imm.F == 0.5f)
101249259Sdim    return 240;
102249259Sdim
103249259Sdim  if (Imm.F == -0.5f)
104249259Sdim    return 241;
105249259Sdim
106249259Sdim  if (Imm.F == 1.0f)
107249259Sdim    return 242;
108249259Sdim
109249259Sdim  if (Imm.F == -1.0f)
110249259Sdim    return 243;
111249259Sdim
112249259Sdim  if (Imm.F == 2.0f)
113249259Sdim    return 244;
114249259Sdim
115249259Sdim  if (Imm.F == -2.0f)
116249259Sdim    return 245;
117249259Sdim
118249259Sdim  if (Imm.F == 4.0f)
119249259Sdim    return 246;
120249259Sdim
121249259Sdim  if (Imm.F == -4.0f)
122249259Sdim    return 247;
123249259Sdim
124249259Sdim  return 255;
125249259Sdim}
126249259Sdim
127249259Sdimvoid SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
128249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
129249259Sdim
130249259Sdim  uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
131249259Sdim  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
132249259Sdim  unsigned bytes = Desc.getSize();
133249259Sdim
134249259Sdim  for (unsigned i = 0; i < bytes; i++) {
135249259Sdim    OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
136249259Sdim  }
137249259Sdim
138249259Sdim  if (bytes > 4)
139249259Sdim    return;
140249259Sdim
141249259Sdim  // Check for additional literals in SRC0/1/2 (Op 1/2/3)
142249259Sdim  for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
143249259Sdim
144249259Sdim    // Check if this operand should be encoded as [SV]Src
145249259Sdim    if (!isSrcOperand(Desc, i))
146249259Sdim      continue;
147249259Sdim
148249259Sdim    // Is this operand a literal immediate?
149249259Sdim    const MCOperand &Op = MI.getOperand(i);
150249259Sdim    if (getLitEncoding(Op) != 255)
151249259Sdim      continue;
152249259Sdim
153249259Sdim    // Yes! Encode it
154249259Sdim    IntFloatUnion Imm;
155249259Sdim    if (Op.isImm())
156249259Sdim      Imm.I = Op.getImm();
157249259Sdim    else
158249259Sdim      Imm.F = Op.getFPImm();
159249259Sdim
160249259Sdim    for (unsigned j = 0; j < 4; j++) {
161249259Sdim      OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff));
162249259Sdim    }
163249259Sdim
164249259Sdim    // Only one literal value allowed
165249259Sdim    break;
166249259Sdim  }
167249259Sdim}
168249259Sdim
169249259Sdimuint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
170249259Sdim                                            const MCOperand &MO,
171249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
172249259Sdim  if (MO.isReg())
173249259Sdim    return MRI.getEncodingValue(MO.getReg());
174249259Sdim
175249259Sdim  if (MO.isExpr()) {
176249259Sdim    const MCExpr *Expr = MO.getExpr();
177249259Sdim    MCFixupKind Kind = MCFixupKind(FK_PCRel_4);
178249259Sdim    Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc()));
179249259Sdim    return 0;
180249259Sdim  }
181249259Sdim
182249259Sdim  // Figure out the operand number, needed for isSrcOperand check
183249259Sdim  unsigned OpNo = 0;
184249259Sdim  for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
185249259Sdim    if (&MO == &MI.getOperand(OpNo))
186249259Sdim      break;
187249259Sdim  }
188249259Sdim
189249259Sdim  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
190249259Sdim  if (isSrcOperand(Desc, OpNo)) {
191249259Sdim    uint32_t Enc = getLitEncoding(MO);
192249259Sdim    if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
193249259Sdim      return Enc;
194249259Sdim
195249259Sdim  } else if (MO.isImm())
196249259Sdim    return MO.getImm();
197249259Sdim
198249259Sdim  llvm_unreachable("Encoding of this operand type is not supported yet.");
199249259Sdim  return 0;
200249259Sdim}
201249259Sdim
202