1 //===-- M68kAsmBackend.cpp - M68k Assembler Backend -------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
10 /// This file contains definitions for M68k assembler backend.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/M68kBaseInfo.h"
15 #include "MCTargetDesc/M68kFixupKinds.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/BinaryFormat/ELF.h"
19 #include "llvm/BinaryFormat/MachO.h"
20 #include "llvm/MC/MCAsmBackend.h"
21 #include "llvm/MC/MCELFObjectWriter.h"
22 #include "llvm/MC/MCExpr.h"
23 #include "llvm/MC/MCFixupKindInfo.h"
24 #include "llvm/MC/MCInst.h"
25 #include "llvm/MC/MCMachObjectWriter.h"
26 #include "llvm/MC/MCObjectWriter.h"
27 #include "llvm/MC/MCRegisterInfo.h"
28 #include "llvm/MC/MCSectionCOFF.h"
29 #include "llvm/MC/MCSectionELF.h"
30 #include "llvm/MC/MCSectionMachO.h"
31 #include "llvm/MC/MCSubtargetInfo.h"
32 #include "llvm/MC/TargetRegistry.h"
33 #include "llvm/Support/ErrorHandling.h"
34 #include "llvm/Support/MathExtras.h"
35 #include "llvm/Support/raw_ostream.h"
41 class M68kAsmBackend
: public MCAsmBackend
{
44 M68kAsmBackend(const Target
&T
) : MCAsmBackend(llvm::endianness::big
) {}
46 unsigned getNumFixupKinds() const override
{ return 0; }
48 void applyFixup(const MCAssembler
&Asm
, const MCFixup
&Fixup
,
49 const MCValue
&Target
, MutableArrayRef
<char> Data
,
50 uint64_t Value
, bool IsResolved
,
51 const MCSubtargetInfo
*STI
) const override
{
52 unsigned Size
= 1 << getFixupKindLog2Size(Fixup
.getKind());
54 assert(Fixup
.getOffset() + Size
<= Data
.size() && "Invalid fixup offset!");
56 // Check that uppper bits are either all zeros or all ones.
57 // Specifically ignore overflow/underflow as long as the leakage is
58 // limited to the lower bits. This is to remain compatible with
60 assert(isIntN(Size
* 8 + 1, Value
) &&
61 "Value does not fit in the Fixup field");
63 // Write in Big Endian
64 for (unsigned i
= 0; i
!= Size
; ++i
)
65 Data
[Fixup
.getOffset() + i
] = uint8_t(Value
>> ((Size
- i
- 1) * 8));
68 bool mayNeedRelaxation(const MCInst
&Inst
,
69 const MCSubtargetInfo
&STI
) const override
;
71 bool fixupNeedsRelaxation(const MCFixup
&Fixup
, uint64_t Value
,
72 const MCRelaxableFragment
*DF
,
73 const MCAsmLayout
&Layout
) const override
;
75 void relaxInstruction(MCInst
&Inst
,
76 const MCSubtargetInfo
&STI
) const override
;
78 /// Returns the minimum size of a nop in bytes on this target. The assembler
79 /// will use this to emit excess padding in situations where the padding
80 /// required for simple alignment would be less than the minimum nop size.
81 unsigned getMinimumNopSize() const override
{ return 2; }
83 /// Write a sequence of optimal nops to the output, covering \p Count bytes.
84 /// \return - true on success, false on failure
85 bool writeNopData(raw_ostream
&OS
, uint64_t Count
,
86 const MCSubtargetInfo
*STI
) const override
;
88 } // end anonymous namespace
90 /// cc—Carry clear GE—Greater than or equal
91 /// LS—Lower or same PL—Plus
92 /// CS—Carry set GT—Greater than
94 /// EQ—Equal HI—Higher
95 /// MI—Minus VC—Overflow clear
96 /// LE—Less than or equal
97 /// NE—Not equal VS—Overflow set
98 static unsigned getRelaxedOpcodeBranch(const MCInst
&Inst
) {
99 unsigned Op
= Inst
.getOpcode();
136 static unsigned getRelaxedOpcodeArith(const MCInst
&Inst
) {
137 unsigned Op
= Inst
.getOpcode();
138 // NOTE there will be some relaxations for PCD and ARD mem for x20
142 static unsigned getRelaxedOpcode(const MCInst
&Inst
) {
143 unsigned R
= getRelaxedOpcodeArith(Inst
);
144 if (R
!= Inst
.getOpcode())
146 return getRelaxedOpcodeBranch(Inst
);
149 bool M68kAsmBackend::mayNeedRelaxation(const MCInst
&Inst
,
150 const MCSubtargetInfo
&STI
) const {
151 // Branches can always be relaxed in either mode.
152 if (getRelaxedOpcodeBranch(Inst
) != Inst
.getOpcode())
155 // Check if this instruction is ever relaxable.
156 if (getRelaxedOpcodeArith(Inst
) == Inst
.getOpcode())
159 // Check if the relaxable operand has an expression. For the current set of
160 // relaxable instructions, the relaxable operand is always the last operand.
161 // NOTE will change for x20 mem
162 unsigned RelaxableOp
= Inst
.getNumOperands() - 1;
163 if (Inst
.getOperand(RelaxableOp
).isExpr())
169 bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup
&Fixup
, uint64_t Value
,
170 const MCRelaxableFragment
*DF
,
171 const MCAsmLayout
&Layout
) const {
172 // TODO Newer CPU can use 32 bit offsets, so check for this when ready
173 if (!isInt
<16>(Value
)) {
174 llvm_unreachable("Cannot relax the instruction, value does not fit");
176 // Relax if the value is too big for a (signed) i8. This means that byte-wide
177 // instructions have to matched by default
180 // A branch to the immediately following instruction automatically
181 // uses the 16-bit displacement format because the 8-bit
182 // displacement field contains $00 (zero offset).
183 return Value
== 0 || !isInt
<8>(Value
);
186 // NOTE Can tblgen help at all here to verify there aren't other instructions
188 void M68kAsmBackend::relaxInstruction(MCInst
&Inst
,
189 const MCSubtargetInfo
&STI
) const {
190 // The only relaxations M68k does is from a 1byte pcrel to a 2byte PCRel.
191 unsigned RelaxedOp
= getRelaxedOpcode(Inst
);
193 if (RelaxedOp
== Inst
.getOpcode()) {
194 SmallString
<256> Tmp
;
195 raw_svector_ostream
OS(Tmp
);
196 Inst
.dump_pretty(OS
);
198 report_fatal_error("unexpected instruction to relax: " + OS
.str());
201 Inst
.setOpcode(RelaxedOp
);
204 bool M68kAsmBackend::writeNopData(raw_ostream
&OS
, uint64_t Count
,
205 const MCSubtargetInfo
*STI
) const {
206 // Cannot emit NOP with size being not multiple of 16 bits.
210 uint64_t NumNops
= Count
/ 2;
211 for (uint64_t i
= 0; i
!= NumNops
; ++i
) {
220 class M68kELFAsmBackend
: public M68kAsmBackend
{
223 M68kELFAsmBackend(const Target
&T
, uint8_t OSABI
)
224 : M68kAsmBackend(T
), OSABI(OSABI
) {}
226 std::unique_ptr
<MCObjectTargetWriter
>
227 createObjectTargetWriter() const override
{
228 return createM68kELFObjectWriter(OSABI
);
232 } // end anonymous namespace
234 MCAsmBackend
*llvm::createM68kAsmBackend(const Target
&T
,
235 const MCSubtargetInfo
&STI
,
236 const MCRegisterInfo
&MRI
,
237 const MCTargetOptions
&Options
) {
238 const Triple
&TheTriple
= STI
.getTargetTriple();
239 uint8_t OSABI
= MCELFObjectTargetWriter::getOSABI(TheTriple
.getOS());
240 return new M68kELFAsmBackend(T
, OSABI
);