1//===-- M68kAsmBackend.cpp - M68k Assembler Backend -------------*- C++ -*-===//
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/// \file
10/// This file contains definitions for M68k assembler backend.
11///
12//===----------------------------------------------------------------------===//
13
14#include "MCTargetDesc/M68kBaseInfo.h"
15#include "MCTargetDesc/M68kFixupKinds.h"
16
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"
36
37using namespace llvm;
38
39namespace {
40
41class M68kAsmBackend : public MCAsmBackend {
42
43public:
44 M68kAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::big) {}
45
46 unsigned getNumFixupKinds() const override { return 0; }
47
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());
53
54 assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
55
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
59 // other assemblers.
60 assert(isIntN(Size * 8 + 1, Value) &&
61 "Value does not fit in the Fixup field");
62
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));
66 }
67
68 bool mayNeedRelaxation(const MCInst &Inst,
69 const MCSubtargetInfo &STI) const override;
70
71 bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
72 const MCRelaxableFragment *DF,
73 const MCAsmLayout &Layout) const override;
74
75 void relaxInstruction(MCInst &Inst,
76 const MCSubtargetInfo &STI) const override;
77
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; }
82
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;
87};
88} // end anonymous namespace
89
90/// cc—Carry clear GE—Greater than or equal
91/// LS—Lower or same PL—Plus
92/// CS—Carry set GT—Greater than
93/// LT—Less 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
98static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
99 unsigned Op = Inst.getOpcode();
100 switch (Op) {
101 default:
102 return Op;
103 case M68k::BRA8:
104 return M68k::BRA16;
105 case M68k::Bcc8:
106 return M68k::Bcc16;
107 case M68k::Bls8:
108 return M68k::Bls16;
109 case M68k::Blt8:
110 return M68k::Blt16;
111 case M68k::Beq8:
112 return M68k::Beq16;
113 case M68k::Bmi8:
114 return M68k::Bmi16;
115 case M68k::Bne8:
116 return M68k::Bne16;
117 case M68k::Bge8:
118 return M68k::Bge16;
119 case M68k::Bcs8:
120 return M68k::Bcs16;
121 case M68k::Bpl8:
122 return M68k::Bpl16;
123 case M68k::Bgt8:
124 return M68k::Bgt16;
125 case M68k::Bhi8:
126 return M68k::Bhi16;
127 case M68k::Bvc8:
128 return M68k::Bvc16;
129 case M68k::Ble8:
130 return M68k::Ble16;
131 case M68k::Bvs8:
132 return M68k::Bvs16;
133 }
134}
135
136static unsigned getRelaxedOpcodeArith(const MCInst &Inst) {
137 unsigned Op = Inst.getOpcode();
138 // NOTE there will be some relaxations for PCD and ARD mem for x20
139 return Op;
140}
141
142static unsigned getRelaxedOpcode(const MCInst &Inst) {
143 unsigned R = getRelaxedOpcodeArith(Inst);
144 if (R != Inst.getOpcode())
145 return R;
146 return getRelaxedOpcodeBranch(Inst);
147}
148
149bool 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())
153 return true;
154
155 // Check if this instruction is ever relaxable.
156 if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode())
157 return false;
158
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(i: RelaxableOp).isExpr())
164 return true;
165
166 return false;
167}
168
169bool 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>(x: Value)) {
174 llvm_unreachable("Cannot relax the instruction, value does not fit");
175 }
176 // Relax if the value is too big for a (signed) i8. This means that byte-wide
177 // instructions have to matched by default
178 //
179 // NOTE
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>(x: Value);
184}
185
186// NOTE Can tblgen help at all here to verify there aren't other instructions
187// we can relax?
188void 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);
192
193 if (RelaxedOp == Inst.getOpcode()) {
194 SmallString<256> Tmp;
195 raw_svector_ostream OS(Tmp);
196 Inst.dump_pretty(OS);
197 OS << "\n";
198 report_fatal_error(reason: "unexpected instruction to relax: " + OS.str());
199 }
200
201 Inst.setOpcode(RelaxedOp);
202}
203
204bool 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.
207 if (Count % 2 != 0)
208 return false;
209
210 uint64_t NumNops = Count / 2;
211 for (uint64_t i = 0; i != NumNops; ++i) {
212 OS << "\x4E\x71";
213 }
214
215 return true;
216}
217
218namespace {
219
220class M68kELFAsmBackend : public M68kAsmBackend {
221public:
222 uint8_t OSABI;
223 M68kELFAsmBackend(const Target &T, uint8_t OSABI)
224 : M68kAsmBackend(T), OSABI(OSABI) {}
225
226 std::unique_ptr<MCObjectTargetWriter>
227 createObjectTargetWriter() const override {
228 return createM68kELFObjectWriter(OSABI);
229 }
230};
231
232} // end anonymous namespace
233
234MCAsmBackend *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(OSType: TheTriple.getOS());
240 return new M68kELFAsmBackend(T, OSABI);
241}
242

source code of llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp