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, SmallVectorImpl<char> &CB,
78 SmallVectorImpl<MCFixup> &Fixups,
79 const MCSubtargetInfo &STI) const override;
80};
81
82void MSP430MCCodeEmitter::encodeInstruction(const MCInst &MI,
83 SmallVectorImpl<char> &CB,
84 SmallVectorImpl<MCFixup> &Fixups,
85 const MCSubtargetInfo &STI) const {
86 const MCInstrDesc &Desc = MCII.get(Opcode: MI.getOpcode());
87 // Get byte count of instruction.
88 unsigned Size = Desc.getSize();
89
90 // Initialize fixup offset
91 Offset = 2;
92
93 uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);
94 size_t WordCount = Size / 2;
95
96 while (WordCount--) {
97 support::endian::write(Out&: CB, V: (uint16_t)BinaryOpCode,
98 E: llvm::endianness::little);
99 BinaryOpCode >>= 16;
100 }
101}
102
103unsigned MSP430MCCodeEmitter::getMachineOpValue(const MCInst &MI,
104 const MCOperand &MO,
105 SmallVectorImpl<MCFixup> &Fixups,
106 const MCSubtargetInfo &STI) const {
107 if (MO.isReg())
108 return Ctx.getRegisterInfo()->getEncodingValue(RegNo: MO.getReg());
109
110 if (MO.isImm()) {
111 Offset += 2;
112 return MO.getImm();
113 }
114
115 assert(MO.isExpr() && "Expected expr operand");
116 Fixups.push_back(Elt: MCFixup::create(Offset, Value: MO.getExpr(),
117 Kind: static_cast<MCFixupKind>(MSP430::fixup_16_byte), Loc: MI.getLoc()));
118 Offset += 2;
119 return 0;
120}
121
122unsigned MSP430MCCodeEmitter::getMemOpValue(const MCInst &MI, unsigned Op,
123 SmallVectorImpl<MCFixup> &Fixups,
124 const MCSubtargetInfo &STI) const {
125 const MCOperand &MO1 = MI.getOperand(i: Op);
126 assert(MO1.isReg() && "Register operand expected");
127 unsigned Reg = Ctx.getRegisterInfo()->getEncodingValue(RegNo: MO1.getReg());
128
129 const MCOperand &MO2 = MI.getOperand(i: Op + 1);
130 if (MO2.isImm()) {
131 Offset += 2;
132 return ((unsigned)MO2.getImm() << 4) | Reg;
133 }
134
135 assert(MO2.isExpr() && "Expr operand expected");
136 MSP430::Fixups FixupKind;
137 switch (Reg) {
138 case 0:
139 FixupKind = MSP430::fixup_16_pcrel_byte;
140 break;
141 case 2:
142 FixupKind = MSP430::fixup_16_byte;
143 break;
144 default:
145 FixupKind = MSP430::fixup_16_byte;
146 break;
147 }
148 Fixups.push_back(Elt: MCFixup::create(Offset, Value: MO2.getExpr(),
149 Kind: static_cast<MCFixupKind>(FixupKind), Loc: MI.getLoc()));
150 Offset += 2;
151 return Reg;
152}
153
154unsigned MSP430MCCodeEmitter::getPCRelImmOpValue(const MCInst &MI, unsigned Op,
155 SmallVectorImpl<MCFixup> &Fixups,
156 const MCSubtargetInfo &STI) const {
157 const MCOperand &MO = MI.getOperand(i: Op);
158 if (MO.isImm())
159 return MO.getImm();
160
161 assert(MO.isExpr() && "Expr operand expected");
162 Fixups.push_back(Elt: MCFixup::create(Offset: 0, Value: MO.getExpr(),
163 Kind: static_cast<MCFixupKind>(MSP430::fixup_10_pcrel), Loc: MI.getLoc()));
164 return 0;
165}
166
167unsigned MSP430MCCodeEmitter::getCGImmOpValue(const MCInst &MI, unsigned Op,
168 SmallVectorImpl<MCFixup> &Fixups,
169 const MCSubtargetInfo &STI) const {
170 const MCOperand &MO = MI.getOperand(i: Op);
171 assert(MO.isImm() && "Expr operand expected");
172
173 int64_t Imm = MO.getImm();
174 switch (Imm) {
175 default:
176 llvm_unreachable("Invalid immediate value");
177 case 4: return 0x22;
178 case 8: return 0x32;
179 case 0: return 0x03;
180 case 1: return 0x13;
181 case 2: return 0x23;
182 case -1: return 0x33;
183 }
184}
185
186unsigned MSP430MCCodeEmitter::getCCOpValue(const MCInst &MI, unsigned Op,
187 SmallVectorImpl<MCFixup> &Fixups,
188 const MCSubtargetInfo &STI) const {
189 const MCOperand &MO = MI.getOperand(i: Op);
190 assert(MO.isImm() && "Immediate operand expected");
191 switch (MO.getImm()) {
192 case MSP430CC::COND_NE: return 0;
193 case MSP430CC::COND_E: return 1;
194 case MSP430CC::COND_LO: return 2;
195 case MSP430CC::COND_HS: return 3;
196 case MSP430CC::COND_N: return 4;
197 case MSP430CC::COND_GE: return 5;
198 case MSP430CC::COND_L: return 6;
199 default:
200 llvm_unreachable("Unknown condition code");
201 }
202}
203
204MCCodeEmitter *createMSP430MCCodeEmitter(const MCInstrInfo &MCII,
205 MCContext &Ctx) {
206 return new MSP430MCCodeEmitter(Ctx, MCII);
207}
208
209#include "MSP430GenMCCodeEmitter.inc"
210
211} // end of namespace llvm
212