1 //===-- AVRMCCodeEmitter.cpp - Convert AVR Code to Machine Code -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the AVRMCCodeEmitter class.
11 //===----------------------------------------------------------------------===//
13 #include "AVRMCCodeEmitter.h"
15 #include "MCTargetDesc/AVRMCExpr.h"
16 #include "MCTargetDesc/AVRMCTargetDesc.h"
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/raw_ostream.h"
30 #define DEBUG_TYPE "mccodeemitter"
32 #define GET_INSTRMAP_INFO
33 #include "AVRGenInstrInfo.inc"
34 #undef GET_INSTRMAP_INFO
38 /// Performs a post-encoding step on a `LD` or `ST` instruction.
40 /// The encoding of the LD/ST family of instructions is inconsistent w.r.t
41 /// the pointer register and the addressing mode.
43 /// The permutations of the format are as followed:
44 /// ld Rd, X `1001 000d dddd 1100`
45 /// ld Rd, X+ `1001 000d dddd 1101`
46 /// ld Rd, -X `1001 000d dddd 1110`
48 /// ld Rd, Y `1000 000d dddd 1000`
49 /// ld Rd, Y+ `1001 000d dddd 1001`
50 /// ld Rd, -Y `1001 000d dddd 1010`
52 /// ld Rd, Z `1000 000d dddd 0000`
53 /// ld Rd, Z+ `1001 000d dddd 0001`
54 /// ld Rd, -Z `1001 000d dddd 0010`
57 /// Note this one inconsistent bit - it is 1 sometimes and 0 at other times.
58 /// There is no logical pattern. Looking at a truth table, the following
59 /// formula can be derived to fit the pattern:
62 /// inconsistent_bit = is_predec OR is_postinc OR is_reg_x
65 /// We manually set this bit in this post encoder method.
67 AVRMCCodeEmitter::loadStorePostEncoder(const MCInst
&MI
, unsigned EncodedValue
,
68 const MCSubtargetInfo
&STI
) const {
70 assert(MI
.getOperand(0).isReg() && MI
.getOperand(1).isReg() &&
71 "the load/store operands must be registers");
73 unsigned Opcode
= MI
.getOpcode();
75 // check whether either of the registers are the X pointer register.
76 bool IsRegX
= MI
.getOperand(0).getReg() == AVR::R27R26
||
77 MI
.getOperand(1).getReg() == AVR::R27R26
;
79 bool IsPredec
= Opcode
== AVR::LDRdPtrPd
|| Opcode
== AVR::STPtrPdRr
;
80 bool IsPostinc
= Opcode
== AVR::LDRdPtrPi
|| Opcode
== AVR::STPtrPiRr
;
82 // Check if we need to set the inconsistent bit
83 if (IsRegX
|| IsPredec
|| IsPostinc
) {
84 EncodedValue
|= (1 << 12);
90 template <AVR::Fixups Fixup
>
92 AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst
&MI
, unsigned OpNo
,
93 SmallVectorImpl
<MCFixup
> &Fixups
,
94 const MCSubtargetInfo
&STI
) const {
95 const MCOperand
&MO
= MI
.getOperand(OpNo
);
98 Fixups
.push_back(MCFixup::create(0, MO
.getExpr(),
99 MCFixupKind(Fixup
), MI
.getLoc()));
105 // Take the size of the current instruction away.
106 // With labels, this is implicitly done.
107 auto target
= MO
.getImm();
108 AVR::fixups::adjustBranchTarget(target
);
112 unsigned AVRMCCodeEmitter::encodeLDSTPtrReg(const MCInst
&MI
, unsigned OpNo
,
113 SmallVectorImpl
<MCFixup
> &Fixups
,
114 const MCSubtargetInfo
&STI
) const {
115 auto MO
= MI
.getOperand(OpNo
);
117 // The operand should be a pointer register.
120 switch (MO
.getReg()) {
121 case AVR::R27R26
: return 0x03; // X: 0b11
122 case AVR::R29R28
: return 0x02; // Y: 0b10
123 case AVR::R31R30
: return 0x00; // Z: 0b00
125 llvm_unreachable("invalid pointer register");
129 /// Encodes a `memri` operand.
130 /// The operand is 7-bits.
131 /// * The lower 6 bits is the immediate
132 /// * The upper bit is the pointer register bit (Z=0,Y=1)
133 unsigned AVRMCCodeEmitter::encodeMemri(const MCInst
&MI
, unsigned OpNo
,
134 SmallVectorImpl
<MCFixup
> &Fixups
,
135 const MCSubtargetInfo
&STI
) const {
136 auto RegOp
= MI
.getOperand(OpNo
);
137 auto OffsetOp
= MI
.getOperand(OpNo
+ 1);
139 assert(RegOp
.isReg() && "Expected register operand");
143 switch (RegOp
.getReg()) {
145 llvm_unreachable("Expected either Y or Z register");
156 if (OffsetOp
.isImm()) {
157 OffsetBits
= OffsetOp
.getImm();
158 } else if (OffsetOp
.isExpr()) {
160 Fixups
.push_back(MCFixup::create(0, OffsetOp
.getExpr(),
161 MCFixupKind(AVR::fixup_6
), MI
.getLoc()));
163 llvm_unreachable("invalid value for offset");
166 return (RegBit
<< 6) | OffsetBits
;
169 unsigned AVRMCCodeEmitter::encodeComplement(const MCInst
&MI
, unsigned OpNo
,
170 SmallVectorImpl
<MCFixup
> &Fixups
,
171 const MCSubtargetInfo
&STI
) const {
172 // The operand should be an immediate.
173 assert(MI
.getOperand(OpNo
).isImm());
175 auto Imm
= MI
.getOperand(OpNo
).getImm();
179 template <AVR::Fixups Fixup
, unsigned Offset
>
180 unsigned AVRMCCodeEmitter::encodeImm(const MCInst
&MI
, unsigned OpNo
,
181 SmallVectorImpl
<MCFixup
> &Fixups
,
182 const MCSubtargetInfo
&STI
) const {
183 auto MO
= MI
.getOperand(OpNo
);
186 if (isa
<AVRMCExpr
>(MO
.getExpr())) {
187 // If the expression is already an AVRMCExpr (i.e. a lo8(symbol),
188 // we shouldn't perform any more fixups. Without this check, we would
189 // instead create a fixup to the symbol named 'lo8(symbol)' which
191 return getExprOpValue(MO
.getExpr(), Fixups
, STI
);
194 MCFixupKind FixupKind
= static_cast<MCFixupKind
>(Fixup
);
195 Fixups
.push_back(MCFixup::create(Offset
, MO
.getExpr(), FixupKind
, MI
.getLoc()));
204 unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst
&MI
, unsigned OpNo
,
205 SmallVectorImpl
<MCFixup
> &Fixups
,
206 const MCSubtargetInfo
&STI
) const {
207 auto MO
= MI
.getOperand(OpNo
);
210 MCFixupKind FixupKind
= static_cast<MCFixupKind
>(AVR::fixup_call
);
211 Fixups
.push_back(MCFixup::create(0, MO
.getExpr(), FixupKind
, MI
.getLoc()));
217 auto Target
= MO
.getImm();
218 AVR::fixups::adjustBranchTarget(Target
);
222 unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr
*Expr
,
223 SmallVectorImpl
<MCFixup
> &Fixups
,
224 const MCSubtargetInfo
&STI
) const {
226 MCExpr::ExprKind Kind
= Expr
->getKind();
228 if (Kind
== MCExpr::Binary
) {
229 Expr
= static_cast<const MCBinaryExpr
*>(Expr
)->getLHS();
230 Kind
= Expr
->getKind();
233 if (Kind
== MCExpr::Target
) {
234 AVRMCExpr
const *AVRExpr
= cast
<AVRMCExpr
>(Expr
);
236 if (AVRExpr
->evaluateAsConstant(Result
)) {
240 MCFixupKind FixupKind
= static_cast<MCFixupKind
>(AVRExpr
->getFixupKind());
241 Fixups
.push_back(MCFixup::create(0, AVRExpr
, FixupKind
));
245 assert(Kind
== MCExpr::SymbolRef
);
249 unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
251 SmallVectorImpl
<MCFixup
> &Fixups
,
252 const MCSubtargetInfo
&STI
) const {
253 if (MO
.isReg()) return Ctx
.getRegisterInfo()->getEncodingValue(MO
.getReg());
254 if (MO
.isImm()) return static_cast<unsigned>(MO
.getImm());
257 return static_cast<unsigned>(APFloat(MO
.getFPImm())
262 // MO must be an Expr.
265 return getExprOpValue(MO
.getExpr(), Fixups
, STI
);
268 void AVRMCCodeEmitter::emitInstruction(uint64_t Val
, unsigned Size
,
269 const MCSubtargetInfo
&STI
,
270 raw_ostream
&OS
) const {
271 const uint16_t *Words
= reinterpret_cast<uint16_t const *>(&Val
);
272 size_t WordCount
= Size
/ 2;
274 for (int64_t i
= WordCount
- 1; i
>= 0; --i
) {
275 uint16_t Word
= Words
[i
];
277 OS
<< (uint8_t) ((Word
& 0x00ff) >> 0);
278 OS
<< (uint8_t) ((Word
& 0xff00) >> 8);
282 void AVRMCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
283 SmallVectorImpl
<MCFixup
> &Fixups
,
284 const MCSubtargetInfo
&STI
) const {
285 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
287 // Get byte count of instruction
288 unsigned Size
= Desc
.getSize();
290 assert(Size
> 0 && "Instruction size cannot be zero");
292 uint64_t BinaryOpCode
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
293 emitInstruction(BinaryOpCode
, Size
, STI
, OS
);
296 MCCodeEmitter
*createAVRMCCodeEmitter(const MCInstrInfo
&MCII
,
297 const MCRegisterInfo
&MRI
,
299 return new AVRMCCodeEmitter(MCII
, Ctx
);
302 #include "AVRGenMCCodeEmitter.inc"
304 } // end of namespace llvm