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/EndianStream.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 // Get the index of the pointer register operand.
77 if (Opcode
== AVR::LDRdPtrPd
|| Opcode
== AVR::LDRdPtrPi
||
78 Opcode
== AVR::LDRdPtr
)
81 // Check if we need to set the inconsistent bit
82 bool IsPredec
= Opcode
== AVR::LDRdPtrPd
|| Opcode
== AVR::STPtrPdRr
;
83 bool IsPostinc
= Opcode
== AVR::LDRdPtrPi
|| Opcode
== AVR::STPtrPiRr
;
84 if (MI
.getOperand(Idx
).getReg() == AVR::R27R26
|| IsPredec
|| IsPostinc
)
85 EncodedValue
|= (1 << 12);
87 // Encode the pointer register.
88 switch (MI
.getOperand(Idx
).getReg()) {
98 llvm_unreachable("invalid pointer register");
105 template <AVR::Fixups Fixup
>
107 AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst
&MI
, unsigned OpNo
,
108 SmallVectorImpl
<MCFixup
> &Fixups
,
109 const MCSubtargetInfo
&STI
) const {
110 const MCOperand
&MO
= MI
.getOperand(OpNo
);
114 MCFixup::create(0, MO
.getExpr(), MCFixupKind(Fixup
), MI
.getLoc()));
120 // Take the size of the current instruction away.
121 // With labels, this is implicitly done.
122 auto target
= MO
.getImm();
123 AVR::fixups::adjustBranchTarget(target
);
127 /// Encodes a `memri` operand.
128 /// The operand is 7-bits.
129 /// * The lower 6 bits is the immediate
130 /// * The upper bit is the pointer register bit (Z=0,Y=1)
131 unsigned AVRMCCodeEmitter::encodeMemri(const MCInst
&MI
, unsigned OpNo
,
132 SmallVectorImpl
<MCFixup
> &Fixups
,
133 const MCSubtargetInfo
&STI
) const {
134 auto RegOp
= MI
.getOperand(OpNo
);
135 auto OffsetOp
= MI
.getOperand(OpNo
+ 1);
137 assert(RegOp
.isReg() && "Expected register operand");
141 switch (RegOp
.getReg().id()) {
143 Ctx
.reportError(MI
.getLoc(), "Expected either Y or Z register");
155 if (OffsetOp
.isImm()) {
156 OffsetBits
= OffsetOp
.getImm();
157 } else if (OffsetOp
.isExpr()) {
159 Fixups
.push_back(MCFixup::create(0, OffsetOp
.getExpr(),
160 MCFixupKind(AVR::fixup_6
), MI
.getLoc()));
162 llvm_unreachable("Invalid value for offset");
165 return (RegBit
<< 6) | OffsetBits
;
168 unsigned AVRMCCodeEmitter::encodeComplement(const MCInst
&MI
, unsigned OpNo
,
169 SmallVectorImpl
<MCFixup
> &Fixups
,
170 const MCSubtargetInfo
&STI
) const {
171 // The operand should be an immediate.
172 assert(MI
.getOperand(OpNo
).isImm());
174 auto Imm
= MI
.getOperand(OpNo
).getImm();
178 template <AVR::Fixups Fixup
, unsigned Offset
>
179 unsigned AVRMCCodeEmitter::encodeImm(const MCInst
&MI
, unsigned OpNo
,
180 SmallVectorImpl
<MCFixup
> &Fixups
,
181 const MCSubtargetInfo
&STI
) const {
182 auto MO
= MI
.getOperand(OpNo
);
185 if (isa
<AVRMCExpr
>(MO
.getExpr())) {
186 // If the expression is already an AVRMCExpr (i.e. a lo8(symbol),
187 // we shouldn't perform any more fixups. Without this check, we would
188 // instead create a fixup to the symbol named 'lo8(symbol)' which
190 return getExprOpValue(MO
.getExpr(), Fixups
, STI
);
193 MCFixupKind FixupKind
= static_cast<MCFixupKind
>(Fixup
);
195 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 {
254 return Ctx
.getRegisterInfo()->getEncodingValue(MO
.getReg());
256 return static_cast<unsigned>(MO
.getImm());
259 return static_cast<unsigned>(bit_cast
<double>(MO
.getDFPImm()));
261 // MO must be an Expr.
264 return getExprOpValue(MO
.getExpr(), Fixups
, STI
);
267 void AVRMCCodeEmitter::encodeInstruction(const MCInst
&MI
,
268 SmallVectorImpl
<char> &CB
,
269 SmallVectorImpl
<MCFixup
> &Fixups
,
270 const MCSubtargetInfo
&STI
) const {
271 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
273 // Get byte count of instruction
274 unsigned Size
= Desc
.getSize();
276 assert(Size
> 0 && "Instruction size cannot be zero");
278 uint64_t BinaryOpCode
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
280 for (int64_t i
= Size
/ 2 - 1; i
>= 0; --i
) {
281 uint16_t Word
= (BinaryOpCode
>> (i
* 16)) & 0xFFFF;
282 support::endian::write(CB
, Word
, llvm::endianness::little
);
286 MCCodeEmitter
*createAVRMCCodeEmitter(const MCInstrInfo
&MCII
, MCContext
&Ctx
) {
287 return new AVRMCCodeEmitter(MCII
, Ctx
);
290 #include "AVRGenMCCodeEmitter.inc"
292 } // end of namespace llvm