1//===-- MSP430MCCodeEmitter.cpp - Convert MSP430 code to machine code -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the MSP430MCCodeEmitter class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MSP430.h"
14#include "MCTargetDesc/MSP430MCTargetDesc.h"
15#include "MCTargetDesc/MSP430FixupKinds.h"
16
17#include "llvm/ADT/APFloat.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/MC/MCCodeEmitter.h"
20#include "llvm/MC/MCContext.h"
21#include "llvm/MC/MCExpr.h"
22#include "llvm/MC/MCFixup.h"
23#include "llvm/MC/MCInst.h"
24#include "llvm/MC/MCInstrInfo.h"
25#include "llvm/MC/MCRegisterInfo.h"
26#include "llvm/MC/MCSubtargetInfo.h"
27#include "llvm/Support/Endian.h"
28#include "llvm/Support/EndianStream.h"
29#include "llvm/Support/raw_ostream.h"
30
31#define DEBUG_TYPE "mccodeemitter"
32
33namespace llvm {
34
35class MSP430MCCodeEmitter : public MCCodeEmitter {
36  MCContext &Ctx;
37  MCInstrInfo const &MCII;
38
39  // Offset keeps track of current word number being emitted
40  // inside a particular instruction.
41  mutable unsigned Offset;
42
43  /// TableGen'erated function for getting the binary encoding for an
44  /// instruction.
45  uint64_t getBinaryCodeForInstr(const MCInst &MI,
46                                 SmallVectorImpl<MCFixup> &Fixups,
47                                 const MCSubtargetInfo &STI) const;
48
49  /// Returns the binary encoding of operands.
50  ///
51  /// If an operand requires relocation, the relocation is recorded
52  /// and zero is returned.
53  unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
54                             SmallVectorImpl<MCFixup> &Fixups,
55                             const MCSubtargetInfo &STI) const;
56
57  unsigned getMemOpValue(const MCInst &MI, unsigned Op,
58                         SmallVectorImpl<MCFixup> &Fixups,
59                         const MCSubtargetInfo &STI) const;
60
61  unsigned getPCRelImmOpValue(const MCInst &MI, unsigned Op,
62                              SmallVectorImpl<MCFixup> &Fixups,
63                              const MCSubtargetInfo &STI) const;
64
65  unsigned getCGImmOpValue(const MCInst &MI, unsigned Op,
66                           SmallVectorImpl<MCFixup> &Fixups,
67                           const MCSubtargetInfo &STI) const;
68
69  unsigned getCCOpValue(const MCInst &MI, unsigned Op,
70                        SmallVectorImpl<MCFixup> &Fixups,
71                        const MCSubtargetInfo &STI) const;
72
73public:
74  MSP430MCCodeEmitter(MCContext &ctx, MCInstrInfo const &MCII)
75      : Ctx(ctx), MCII(MCII) {}
76
77  void encodeInstruction(const MCInst &MI, raw_ostream &OS,
78                         SmallVectorImpl<MCFixup> &Fixups,
79                         const MCSubtargetInfo &STI) const override;
80};
81
82void MSP430MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
83                                            SmallVectorImpl<MCFixup> &Fixups,
84                                            const MCSubtargetInfo &STI) const {
85  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
86  // Get byte count of instruction.
87  unsigned Size = Desc.getSize();
88
89  // Initialize fixup offset
90  Offset = 2;
91
92  uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);
93  size_t WordCount = Size / 2;
94
95  while (WordCount--) {
96    support::endian::write(OS, (uint16_t)BinaryOpCode, support::little);
97    BinaryOpCode >>= 16;
98  }
99}
100
101unsigned MSP430MCCodeEmitter::getMachineOpValue(const MCInst &MI,
102                                                const MCOperand &MO,
103                                                SmallVectorImpl<MCFixup> &Fixups,
104                                                const MCSubtargetInfo &STI) const {
105  if (MO.isReg())
106    return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
107
108  if (MO.isImm()) {
109    Offset += 2;
110    return MO.getImm();
111  }
112
113  assert(MO.isExpr() && "Expected expr operand");
114  Fixups.push_back(MCFixup::create(Offset, MO.getExpr(),
115      static_cast<MCFixupKind>(MSP430::fixup_16_byte), MI.getLoc()));
116  Offset += 2;
117  return 0;
118}
119
120unsigned MSP430MCCodeEmitter::getMemOpValue(const MCInst &MI, unsigned Op,
121                                            SmallVectorImpl<MCFixup> &Fixups,
122                                            const MCSubtargetInfo &STI) const {
123  const MCOperand &MO1 = MI.getOperand(Op);
124  assert(MO1.isReg() && "Register operand expected");
125  unsigned Reg = Ctx.getRegisterInfo()->getEncodingValue(MO1.getReg());
126
127  const MCOperand &MO2 = MI.getOperand(Op + 1);
128  if (MO2.isImm()) {
129    Offset += 2;
130    return ((unsigned)MO2.getImm() << 4) | Reg;
131  }
132
133  assert(MO2.isExpr() && "Expr operand expected");
134  MSP430::Fixups FixupKind;
135  switch (Reg) {
136  case 0:
137    FixupKind = MSP430::fixup_16_pcrel_byte;
138    break;
139  case 2:
140    FixupKind = MSP430::fixup_16_byte;
141    break;
142  default:
143    FixupKind = MSP430::fixup_16_byte;
144    break;
145  }
146  Fixups.push_back(MCFixup::create(Offset, MO2.getExpr(),
147    static_cast<MCFixupKind>(FixupKind), MI.getLoc()));
148  Offset += 2;
149  return Reg;
150}
151
152unsigned MSP430MCCodeEmitter::getPCRelImmOpValue(const MCInst &MI, unsigned Op,
153                                                 SmallVectorImpl<MCFixup> &Fixups,
154                                                 const MCSubtargetInfo &STI) const {
155  const MCOperand &MO = MI.getOperand(Op);
156  if (MO.isImm())
157    return MO.getImm();
158
159  assert(MO.isExpr() && "Expr operand expected");
160  Fixups.push_back(MCFixup::create(0, MO.getExpr(),
161    static_cast<MCFixupKind>(MSP430::fixup_10_pcrel), MI.getLoc()));
162  return 0;
163}
164
165unsigned MSP430MCCodeEmitter::getCGImmOpValue(const MCInst &MI, unsigned Op,
166                                              SmallVectorImpl<MCFixup> &Fixups,
167                                              const MCSubtargetInfo &STI) const {
168  const MCOperand &MO = MI.getOperand(Op);
169  assert(MO.isImm() && "Expr operand expected");
170
171  int64_t Imm = MO.getImm();
172  switch (Imm) {
173  default:
174    llvm_unreachable("Invalid immediate value");
175  case 4:  return 0x22;
176  case 8:  return 0x32;
177  case 0:  return 0x03;
178  case 1:  return 0x13;
179  case 2:  return 0x23;
180  case -1: return 0x33;
181  }
182}
183
184unsigned MSP430MCCodeEmitter::getCCOpValue(const MCInst &MI, unsigned Op,
185                                           SmallVectorImpl<MCFixup> &Fixups,
186                                           const MCSubtargetInfo &STI) const {
187  const MCOperand &MO = MI.getOperand(Op);
188  assert(MO.isImm() && "Immediate operand expected");
189  switch (MO.getImm()) {
190  case MSP430CC::COND_NE: return 0;
191  case MSP430CC::COND_E:  return 1;
192  case MSP430CC::COND_LO: return 2;
193  case MSP430CC::COND_HS: return 3;
194  case MSP430CC::COND_N:  return 4;
195  case MSP430CC::COND_GE: return 5;
196  case MSP430CC::COND_L:  return 6;
197  default:
198    llvm_unreachable("Unknown condition code");
199  }
200}
201
202MCCodeEmitter *createMSP430MCCodeEmitter(const MCInstrInfo &MCII,
203                                         MCContext &Ctx) {
204  return new MSP430MCCodeEmitter(Ctx, MCII);
205}
206
207#include "MSP430GenMCCodeEmitter.inc"
208
209} // end of namespace llvm
210