1//===-- MBlazeMCCodeEmitter.cpp - Convert MBlaze code to machine code -----===//
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// This file implements the MBlazeMCCodeEmitter class.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "mccodeemitter"
15#include "MCTargetDesc/MBlazeBaseInfo.h"
16#include "MCTargetDesc/MBlazeMCTargetDesc.h"
17#include "llvm/MC/MCCodeEmitter.h"
18#include "llvm/MC/MCExpr.h"
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCInstrInfo.h"
21#include "llvm/MC/MCSubtargetInfo.h"
22#include "llvm/MC/MCSymbol.h"
23#include "llvm/MC/MCFixup.h"
24#include "llvm/ADT/Statistic.h"
25#include "llvm/Support/raw_ostream.h"
26using namespace llvm;
27
28STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
29
30namespace {
31class MBlazeMCCodeEmitter : public MCCodeEmitter {
32  MBlazeMCCodeEmitter(const MBlazeMCCodeEmitter &) LLVM_DELETED_FUNCTION;
33  void operator=(const MBlazeMCCodeEmitter &) LLVM_DELETED_FUNCTION;
34  const MCInstrInfo &MCII;
35
36public:
37  MBlazeMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti,
38                      MCContext &ctx)
39    : MCII(mcii) {
40  }
41
42  ~MBlazeMCCodeEmitter() {}
43
44  // getBinaryCodeForInstr - TableGen'erated function for getting the
45  // binary encoding for an instruction.
46  uint64_t getBinaryCodeForInstr(const MCInst &MI) const;
47
48  /// getMachineOpValue - Return binary encoding of operand. If the machine
49  /// operand requires relocation, record the relocation and return zero.
50  unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO) const;
51  unsigned getMachineOpValue(const MCInst &MI, unsigned OpIdx) const {
52    return getMachineOpValue(MI, MI.getOperand(OpIdx));
53  }
54
55  static unsigned GetMBlazeRegNum(const MCOperand &MO) {
56    // FIXME: getMBlazeRegisterNumbering() is sufficient?
57    llvm_unreachable("MBlazeMCCodeEmitter::GetMBlazeRegNum() not yet "
58                     "implemented.");
59  }
60
61  void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const {
62    // The MicroBlaze uses a bit reversed format so we need to reverse the
63    // order of the bits. Taken from:
64    // http://graphics.stanford.edu/~seander/bithacks.html
65    C = ((C * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
66
67    OS << (char)C;
68    ++CurByte;
69  }
70
71  void EmitRawByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const {
72    OS << (char)C;
73    ++CurByte;
74  }
75
76  void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte,
77                    raw_ostream &OS) const {
78    assert(Size <= 8 && "size too big in emit constant");
79
80    for (unsigned i = 0; i != Size; ++i) {
81      EmitByte(Val & 255, CurByte, OS);
82      Val >>= 8;
83    }
84  }
85
86  void EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const;
87  void EmitIMM(const MCInst &MI, unsigned &CurByte, raw_ostream &OS) const;
88
89  void EmitImmediate(const MCInst &MI, unsigned opNo, bool pcrel,
90                     unsigned &CurByte, raw_ostream &OS,
91                     SmallVectorImpl<MCFixup> &Fixups) const;
92
93  void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
94                         SmallVectorImpl<MCFixup> &Fixups) const;
95};
96
97} // end anonymous namespace
98
99
100MCCodeEmitter *llvm::createMBlazeMCCodeEmitter(const MCInstrInfo &MCII,
101                                               const MCRegisterInfo &MRI,
102                                               const MCSubtargetInfo &STI,
103                                               MCContext &Ctx) {
104  return new MBlazeMCCodeEmitter(MCII, STI, Ctx);
105}
106
107/// getMachineOpValue - Return binary encoding of operand. If the machine
108/// operand requires relocation, record the relocation and return zero.
109unsigned MBlazeMCCodeEmitter::getMachineOpValue(const MCInst &MI,
110                                             const MCOperand &MO) const {
111  if (MO.isReg())
112    return getMBlazeRegisterNumbering(MO.getReg());
113  if (MO.isImm())
114    return static_cast<unsigned>(MO.getImm());
115  if (MO.isExpr())
116    return 0; // The relocation has already been recorded at this point.
117#ifndef NDEBUG
118  errs() << MO;
119#endif
120  llvm_unreachable(0);
121}
122
123void MBlazeMCCodeEmitter::
124EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const {
125  int32_t val = (int32_t)imm.getImm();
126  if (val > 32767 || val < -32768) {
127    EmitByte(0x0D, CurByte, OS);
128    EmitByte(0x00, CurByte, OS);
129    EmitRawByte((val >> 24) & 0xFF, CurByte, OS);
130    EmitRawByte((val >> 16) & 0xFF, CurByte, OS);
131  }
132}
133
134void MBlazeMCCodeEmitter::
135EmitIMM(const MCInst &MI, unsigned &CurByte,raw_ostream &OS) const {
136  switch (MI.getOpcode()) {
137  default: break;
138
139  case MBlaze::ADDIK32:
140  case MBlaze::ORI32:
141  case MBlaze::BRLID32:
142    EmitByte(0x0D, CurByte, OS);
143    EmitByte(0x00, CurByte, OS);
144    EmitRawByte(0, CurByte, OS);
145    EmitRawByte(0, CurByte, OS);
146  }
147}
148
149void MBlazeMCCodeEmitter::
150EmitImmediate(const MCInst &MI, unsigned opNo, bool pcrel, unsigned &CurByte,
151              raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups) const {
152  assert(MI.getNumOperands()>opNo && "Not enought operands for instruction");
153
154  MCOperand oper = MI.getOperand(opNo);
155
156  if (oper.isImm()) {
157    EmitIMM(oper, CurByte, OS);
158  } else if (oper.isExpr()) {
159    MCFixupKind FixupKind;
160    switch (MI.getOpcode()) {
161    default:
162      FixupKind = pcrel ? FK_PCRel_2 : FK_Data_2;
163      Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind));
164      break;
165    case MBlaze::ORI32:
166    case MBlaze::ADDIK32:
167    case MBlaze::BRLID32:
168      FixupKind = pcrel ? FK_PCRel_4 : FK_Data_4;
169      Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind));
170      break;
171    }
172  }
173}
174
175
176
177void MBlazeMCCodeEmitter::
178EncodeInstruction(const MCInst &MI, raw_ostream &OS,
179                  SmallVectorImpl<MCFixup> &Fixups) const {
180  unsigned Opcode = MI.getOpcode();
181  const MCInstrDesc &Desc = MCII.get(Opcode);
182  uint64_t TSFlags = Desc.TSFlags;
183  // Keep track of the current byte being emitted.
184  unsigned CurByte = 0;
185
186  // Emit an IMM instruction if the instruction we are encoding requires it
187  EmitIMM(MI,CurByte,OS);
188
189  switch ((TSFlags & MBlazeII::FormMask)) {
190  default: break;
191  case MBlazeII::FPseudo:
192    // Pseudo instructions don't get encoded.
193    return;
194  case MBlazeII::FRRI:
195    EmitImmediate(MI, 2, false, CurByte, OS, Fixups);
196    break;
197  case MBlazeII::FRIR:
198    EmitImmediate(MI, 1, false, CurByte, OS, Fixups);
199    break;
200  case MBlazeII::FCRI:
201    EmitImmediate(MI, 1, true, CurByte, OS, Fixups);
202    break;
203  case MBlazeII::FRCI:
204    EmitImmediate(MI, 1, true, CurByte, OS, Fixups);
205  case MBlazeII::FCCI:
206    EmitImmediate(MI, 0, true, CurByte, OS, Fixups);
207    break;
208  }
209
210  ++MCNumEmitted;  // Keep track of the # of mi's emitted
211  unsigned Value = getBinaryCodeForInstr(MI);
212  EmitConstant(Value, 4, CurByte, OS);
213}
214
215// FIXME: These #defines shouldn't be necessary. Instead, tblgen should
216// be able to generate code emitter helpers for either variant, like it
217// does for the AsmWriter.
218#define MBlazeCodeEmitter MBlazeMCCodeEmitter
219#define MachineInstr MCInst
220#include "MBlazeGenCodeEmitter.inc"
221#undef MBlazeCodeEmitter
222#undef MachineInstr
223