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 | |
33 | namespace llvm { |
34 | |
35 | class 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 | |
73 | public: |
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 | |
82 | void 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 | |
103 | unsigned 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 | |
122 | unsigned 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 | |
154 | unsigned 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 | |
167 | unsigned 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 | |
186 | unsigned 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 | |
204 | MCCodeEmitter *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 | |