1 | //===-- AVRMCCodeEmitter.cpp - Convert AVR 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 AVRMCCodeEmitter class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "AVRMCCodeEmitter.h" |
14 | |
15 | #include "MCTargetDesc/AVRMCExpr.h" |
16 | #include "MCTargetDesc/AVRMCTargetDesc.h" |
17 | |
18 | #include "llvm/ADT/APFloat.h" |
19 | #include "llvm/ADT/SmallVector.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/Casting.h" |
28 | #include "llvm/Support/EndianStream.h" |
29 | #include "llvm/Support/raw_ostream.h" |
30 | |
31 | #define DEBUG_TYPE "mccodeemitter" |
32 | |
33 | #define GET_INSTRMAP_INFO |
34 | #include "AVRGenInstrInfo.inc" |
35 | #undef GET_INSTRMAP_INFO |
36 | |
37 | namespace llvm { |
38 | |
39 | /// Performs a post-encoding step on a `LD` or `ST` instruction. |
40 | /// |
41 | /// The encoding of the LD/ST family of instructions is inconsistent w.r.t |
42 | /// the pointer register and the addressing mode. |
43 | /// |
44 | /// The permutations of the format are as followed: |
45 | /// ld Rd, X `1001 000d dddd 1100` |
46 | /// ld Rd, X+ `1001 000d dddd 1101` |
47 | /// ld Rd, -X `1001 000d dddd 1110` |
48 | /// |
49 | /// ld Rd, Y `1000 000d dddd 1000` |
50 | /// ld Rd, Y+ `1001 000d dddd 1001` |
51 | /// ld Rd, -Y `1001 000d dddd 1010` |
52 | /// |
53 | /// ld Rd, Z `1000 000d dddd 0000` |
54 | /// ld Rd, Z+ `1001 000d dddd 0001` |
55 | /// ld Rd, -Z `1001 000d dddd 0010` |
56 | /// ^ |
57 | /// | |
58 | /// Note this one inconsistent bit - it is 1 sometimes and 0 at other times. |
59 | /// There is no logical pattern. Looking at a truth table, the following |
60 | /// formula can be derived to fit the pattern: |
61 | // |
62 | /// ``` |
63 | /// inconsistent_bit = is_predec OR is_postinc OR is_reg_x |
64 | /// ``` |
65 | // |
66 | /// We manually set this bit in this post encoder method. |
67 | unsigned |
68 | AVRMCCodeEmitter::loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue, |
69 | const MCSubtargetInfo &STI) const { |
70 | |
71 | assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() && |
72 | "the load/store operands must be registers" ); |
73 | |
74 | unsigned Opcode = MI.getOpcode(); |
75 | |
76 | // check whether either of the registers are the X pointer register. |
77 | bool IsRegX = MI.getOperand(i: 0).getReg() == AVR::R27R26 || |
78 | MI.getOperand(i: 1).getReg() == AVR::R27R26; |
79 | |
80 | bool IsPredec = Opcode == AVR::LDRdPtrPd || Opcode == AVR::STPtrPdRr; |
81 | bool IsPostinc = Opcode == AVR::LDRdPtrPi || Opcode == AVR::STPtrPiRr; |
82 | |
83 | // Check if we need to set the inconsistent bit |
84 | if (IsRegX || IsPredec || IsPostinc) { |
85 | EncodedValue |= (1 << 12); |
86 | } |
87 | |
88 | return EncodedValue; |
89 | } |
90 | |
91 | template <AVR::Fixups Fixup> |
92 | unsigned |
93 | AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo, |
94 | SmallVectorImpl<MCFixup> &Fixups, |
95 | const MCSubtargetInfo &STI) const { |
96 | const MCOperand &MO = MI.getOperand(i: OpNo); |
97 | |
98 | if (MO.isExpr()) { |
99 | Fixups.push_back( |
100 | Elt: MCFixup::create(Offset: 0, Value: MO.getExpr(), Kind: MCFixupKind(Fixup), Loc: MI.getLoc())); |
101 | return 0; |
102 | } |
103 | |
104 | assert(MO.isImm()); |
105 | |
106 | // Take the size of the current instruction away. |
107 | // With labels, this is implicitly done. |
108 | auto target = MO.getImm(); |
109 | AVR::fixups::adjustBranchTarget(val&: target); |
110 | return target; |
111 | } |
112 | |
113 | unsigned AVRMCCodeEmitter::encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo, |
114 | SmallVectorImpl<MCFixup> &Fixups, |
115 | const MCSubtargetInfo &STI) const { |
116 | auto MO = MI.getOperand(i: OpNo); |
117 | |
118 | // The operand should be a pointer register. |
119 | assert(MO.isReg()); |
120 | |
121 | switch (MO.getReg()) { |
122 | case AVR::R27R26: |
123 | return 0x03; // X: 0b11 |
124 | case AVR::R29R28: |
125 | return 0x02; // Y: 0b10 |
126 | case AVR::R31R30: |
127 | return 0x00; // Z: 0b00 |
128 | default: |
129 | llvm_unreachable("invalid pointer register" ); |
130 | } |
131 | } |
132 | |
133 | /// Encodes a `memri` operand. |
134 | /// The operand is 7-bits. |
135 | /// * The lower 6 bits is the immediate |
136 | /// * The upper bit is the pointer register bit (Z=0,Y=1) |
137 | unsigned AVRMCCodeEmitter::encodeMemri(const MCInst &MI, unsigned OpNo, |
138 | SmallVectorImpl<MCFixup> &Fixups, |
139 | const MCSubtargetInfo &STI) const { |
140 | auto RegOp = MI.getOperand(i: OpNo); |
141 | auto OffsetOp = MI.getOperand(i: OpNo + 1); |
142 | |
143 | assert(RegOp.isReg() && "Expected register operand" ); |
144 | |
145 | uint8_t RegBit = 0; |
146 | |
147 | switch (RegOp.getReg()) { |
148 | default: |
149 | Ctx.reportError(L: MI.getLoc(), Msg: "Expected either Y or Z register" ); |
150 | return 0; |
151 | case AVR::R31R30: |
152 | RegBit = 0; |
153 | break; // Z register |
154 | case AVR::R29R28: |
155 | RegBit = 1; |
156 | break; // Y register |
157 | } |
158 | |
159 | int8_t OffsetBits; |
160 | |
161 | if (OffsetOp.isImm()) { |
162 | OffsetBits = OffsetOp.getImm(); |
163 | } else if (OffsetOp.isExpr()) { |
164 | OffsetBits = 0; |
165 | Fixups.push_back(Elt: MCFixup::create(Offset: 0, Value: OffsetOp.getExpr(), |
166 | Kind: MCFixupKind(AVR::fixup_6), Loc: MI.getLoc())); |
167 | } else { |
168 | llvm_unreachable("Invalid value for offset" ); |
169 | } |
170 | |
171 | return (RegBit << 6) | OffsetBits; |
172 | } |
173 | |
174 | unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo, |
175 | SmallVectorImpl<MCFixup> &Fixups, |
176 | const MCSubtargetInfo &STI) const { |
177 | // The operand should be an immediate. |
178 | assert(MI.getOperand(OpNo).isImm()); |
179 | |
180 | auto Imm = MI.getOperand(i: OpNo).getImm(); |
181 | return (~0) - Imm; |
182 | } |
183 | |
184 | template <AVR::Fixups Fixup, unsigned Offset> |
185 | unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo, |
186 | SmallVectorImpl<MCFixup> &Fixups, |
187 | const MCSubtargetInfo &STI) const { |
188 | auto MO = MI.getOperand(i: OpNo); |
189 | |
190 | if (MO.isExpr()) { |
191 | if (isa<AVRMCExpr>(Val: MO.getExpr())) { |
192 | // If the expression is already an AVRMCExpr (i.e. a lo8(symbol), |
193 | // we shouldn't perform any more fixups. Without this check, we would |
194 | // instead create a fixup to the symbol named 'lo8(symbol)' which |
195 | // is not correct. |
196 | return getExprOpValue(Expr: MO.getExpr(), Fixups, STI); |
197 | } |
198 | |
199 | MCFixupKind FixupKind = static_cast<MCFixupKind>(Fixup); |
200 | Fixups.push_back( |
201 | Elt: MCFixup::create(Offset, Value: MO.getExpr(), Kind: FixupKind, Loc: MI.getLoc())); |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | assert(MO.isImm()); |
207 | return MO.getImm(); |
208 | } |
209 | |
210 | unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo, |
211 | SmallVectorImpl<MCFixup> &Fixups, |
212 | const MCSubtargetInfo &STI) const { |
213 | auto MO = MI.getOperand(i: OpNo); |
214 | |
215 | if (MO.isExpr()) { |
216 | MCFixupKind FixupKind = static_cast<MCFixupKind>(AVR::fixup_call); |
217 | Fixups.push_back(Elt: MCFixup::create(Offset: 0, Value: MO.getExpr(), Kind: FixupKind, Loc: MI.getLoc())); |
218 | return 0; |
219 | } |
220 | |
221 | assert(MO.isImm()); |
222 | |
223 | auto Target = MO.getImm(); |
224 | AVR::fixups::adjustBranchTarget(val&: Target); |
225 | return Target; |
226 | } |
227 | |
228 | unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr, |
229 | SmallVectorImpl<MCFixup> &Fixups, |
230 | const MCSubtargetInfo &STI) const { |
231 | |
232 | MCExpr::ExprKind Kind = Expr->getKind(); |
233 | |
234 | if (Kind == MCExpr::Binary) { |
235 | Expr = static_cast<const MCBinaryExpr *>(Expr)->getLHS(); |
236 | Kind = Expr->getKind(); |
237 | } |
238 | |
239 | if (Kind == MCExpr::Target) { |
240 | AVRMCExpr const *AVRExpr = cast<AVRMCExpr>(Val: Expr); |
241 | int64_t Result; |
242 | if (AVRExpr->evaluateAsConstant(Result)) { |
243 | return Result; |
244 | } |
245 | |
246 | MCFixupKind FixupKind = static_cast<MCFixupKind>(AVRExpr->getFixupKind()); |
247 | Fixups.push_back(Elt: MCFixup::create(Offset: 0, Value: AVRExpr, Kind: FixupKind)); |
248 | return 0; |
249 | } |
250 | |
251 | assert(Kind == MCExpr::SymbolRef); |
252 | return 0; |
253 | } |
254 | |
255 | unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI, |
256 | const MCOperand &MO, |
257 | SmallVectorImpl<MCFixup> &Fixups, |
258 | const MCSubtargetInfo &STI) const { |
259 | if (MO.isReg()) |
260 | return Ctx.getRegisterInfo()->getEncodingValue(RegNo: MO.getReg()); |
261 | if (MO.isImm()) |
262 | return static_cast<unsigned>(MO.getImm()); |
263 | |
264 | if (MO.isDFPImm()) |
265 | return static_cast<unsigned>(bit_cast<double>(from: MO.getDFPImm())); |
266 | |
267 | // MO must be an Expr. |
268 | assert(MO.isExpr()); |
269 | |
270 | return getExprOpValue(Expr: MO.getExpr(), Fixups, STI); |
271 | } |
272 | |
273 | void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI, |
274 | SmallVectorImpl<char> &CB, |
275 | SmallVectorImpl<MCFixup> &Fixups, |
276 | const MCSubtargetInfo &STI) const { |
277 | const MCInstrDesc &Desc = MCII.get(Opcode: MI.getOpcode()); |
278 | |
279 | // Get byte count of instruction |
280 | unsigned Size = Desc.getSize(); |
281 | |
282 | assert(Size > 0 && "Instruction size cannot be zero" ); |
283 | |
284 | uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI); |
285 | |
286 | for (int64_t i = Size / 2 - 1; i >= 0; --i) { |
287 | uint16_t Word = (BinaryOpCode >> (i * 16)) & 0xFFFF; |
288 | support::endian::write(Out&: CB, V: Word, E: llvm::endianness::little); |
289 | } |
290 | } |
291 | |
292 | MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII, |
293 | MCContext &Ctx) { |
294 | return new AVRMCCodeEmitter(MCII, Ctx); |
295 | } |
296 | |
297 | #include "AVRGenMCCodeEmitter.inc" |
298 | |
299 | } // end of namespace llvm |
300 | |