LLVM 20.0.0git
M68kAsmBackend.cpp
Go to the documentation of this file.
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
16
22#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCInst.h"
32#include "llvm/MC/MCValue.h"
34#include "llvm/Support/Debug.h"
38
39using namespace llvm;
40
41#define DEBUG_TYPE "M68k-asm-backend"
42
43namespace {
44
45class M68kAsmBackend : public MCAsmBackend {
46 bool Allows32BitBranch;
47
48public:
49 M68kAsmBackend(const Target &T, const MCSubtargetInfo &STI)
51 Allows32BitBranch(llvm::StringSwitch<bool>(STI.getCPU())
52 .CasesLower("m68020", "m68030", "m68040", true)
53 .Default(false)) {}
54
55 unsigned getNumFixupKinds() const override { return 0; }
56
57 void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
59 uint64_t Value, bool IsResolved,
60 const MCSubtargetInfo *STI) const override {
61 unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
62
63 if (Fixup.getOffset() + Size > Data.size()) {
64 LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n');
65 LLVM_DEBUG(dbgs() << "Size: " << Size << '\n');
66 LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n');
67 assert(Fixup.getOffset() + Size <= Data.size() &&
68 "Invalid fixup offset!");
69 }
70
71 // Check that uppper bits are either all zeros or all ones.
72 // Specifically ignore overflow/underflow as long as the leakage is
73 // limited to the lower bits. This is to remain compatible with
74 // other assemblers.
75 if (!(isIntN(Size * 8 + 1, static_cast<int64_t>(Value)) || IsResolved)) {
76 LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n');
77 LLVM_DEBUG(dbgs() << "Size: " << Size << '\n');
78 LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n');
79 LLVM_DEBUG(dbgs() << "Value: " << Value << '\n');
80 LLVM_DEBUG(dbgs() << "Target: ");
81 LLVM_DEBUG(Target.print(dbgs()));
82 LLVM_DEBUG(dbgs() << '\n');
83 assert(isIntN(Size * 8 + 1, static_cast<int64_t>(Value)) &&
84 "Value does not fit in the Fixup field");
85 }
86
87 // Write in Big Endian
88 for (unsigned i = 0; i != Size; ++i)
89 Data[Fixup.getOffset() + i] =
90 uint8_t(static_cast<int64_t>(Value) >> ((Size - i - 1) * 8));
91 }
92
93 bool mayNeedRelaxation(const MCInst &Inst,
94 const MCSubtargetInfo &STI) const override;
95
97 uint64_t Value) const override;
98
99 void relaxInstruction(MCInst &Inst,
100 const MCSubtargetInfo &STI) const override;
101
102 /// Returns the minimum size of a nop in bytes on this target. The assembler
103 /// will use this to emit excess padding in situations where the padding
104 /// required for simple alignment would be less than the minimum nop size.
105 unsigned getMinimumNopSize() const override { return 2; }
106
107 /// Write a sequence of optimal nops to the output, covering \p Count bytes.
108 /// \return - true on success, false on failure
109 bool writeNopData(raw_ostream &OS, uint64_t Count,
110 const MCSubtargetInfo *STI) const override;
111};
112} // end anonymous namespace
113
114/// cc—Carry clear GE—Greater than or equal
115/// LS—Lower or same PL—Plus
116/// CS—Carry set GT—Greater than
117/// LT—Less than
118/// EQ—Equal HI—Higher
119/// MI—Minus VC—Overflow clear
120/// LE—Less than or equal
121/// NE—Not equal VS—Overflow set
122static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
123 unsigned Op = Inst.getOpcode();
124 switch (Op) {
125 default:
126 return Op;
127
128 // 8 -> 16
129 case M68k::BRA8:
130 return M68k::BRA16;
131 case M68k::Bcc8:
132 return M68k::Bcc16;
133 case M68k::Bls8:
134 return M68k::Bls16;
135 case M68k::Blt8:
136 return M68k::Blt16;
137 case M68k::Beq8:
138 return M68k::Beq16;
139 case M68k::Bmi8:
140 return M68k::Bmi16;
141 case M68k::Bne8:
142 return M68k::Bne16;
143 case M68k::Bge8:
144 return M68k::Bge16;
145 case M68k::Bcs8:
146 return M68k::Bcs16;
147 case M68k::Bpl8:
148 return M68k::Bpl16;
149 case M68k::Bgt8:
150 return M68k::Bgt16;
151 case M68k::Bhi8:
152 return M68k::Bhi16;
153 case M68k::Bvc8:
154 return M68k::Bvc16;
155 case M68k::Ble8:
156 return M68k::Ble16;
157 case M68k::Bvs8:
158 return M68k::Bvs16;
159
160 // 16 -> 32
161 case M68k::BRA16:
162 return M68k::BRA32;
163 case M68k::Bcc16:
164 return M68k::Bcc32;
165 case M68k::Bls16:
166 return M68k::Bls32;
167 case M68k::Blt16:
168 return M68k::Blt32;
169 case M68k::Beq16:
170 return M68k::Beq32;
171 case M68k::Bmi16:
172 return M68k::Bmi32;
173 case M68k::Bne16:
174 return M68k::Bne32;
175 case M68k::Bge16:
176 return M68k::Bge32;
177 case M68k::Bcs16:
178 return M68k::Bcs32;
179 case M68k::Bpl16:
180 return M68k::Bpl32;
181 case M68k::Bgt16:
182 return M68k::Bgt32;
183 case M68k::Bhi16:
184 return M68k::Bhi32;
185 case M68k::Bvc16:
186 return M68k::Bvc32;
187 case M68k::Ble16:
188 return M68k::Ble32;
189 case M68k::Bvs16:
190 return M68k::Bvs32;
191 }
192}
193
194static unsigned getRelaxedOpcodeArith(const MCInst &Inst) {
195 unsigned Op = Inst.getOpcode();
196 // NOTE there will be some relaxations for PCD and ARD mem for x20
197 return Op;
198}
199
200static unsigned getRelaxedOpcode(const MCInst &Inst) {
201 unsigned R = getRelaxedOpcodeArith(Inst);
202 if (R != Inst.getOpcode())
203 return R;
204 return getRelaxedOpcodeBranch(Inst);
205}
206
207bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,
208 const MCSubtargetInfo &STI) const {
209 // Branches can always be relaxed in either mode.
210 if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode())
211 return true;
212
213 // Check if this instruction is ever relaxable.
214 if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode())
215 return false;
216
217 // Check if the relaxable operand has an expression. For the current set of
218 // relaxable instructions, the relaxable operand is always the last operand.
219 // NOTE will change for x20 mem
220 unsigned RelaxableOp = Inst.getNumOperands() - 1;
221 if (Inst.getOperand(RelaxableOp).isExpr())
222 return true;
223
224 return false;
225}
226
227bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
228 uint64_t UnsignedValue) const {
229 int64_t Value = static_cast<int64_t>(UnsignedValue);
230
231 if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value)))
232 llvm_unreachable("Cannot relax the instruction, value does not fit");
233
234 // Relax if the value is too big for a (signed) i8
235 // (or signed i16 if 32 bit branches can be used). This means
236 // that byte-wide instructions have to matched by default
237 unsigned KindLog2Size = getFixupKindLog2Size(Fixup.getKind());
238 bool FixupFieldTooSmall = false;
239 if (!isInt<8>(Value) && KindLog2Size == 0)
240 FixupFieldTooSmall = true;
241 else if (!isInt<16>(Value) && KindLog2Size <= 1)
242 FixupFieldTooSmall = true;
243
244 // NOTE
245 // A branch to the immediately following instruction automatically
246 // uses the 16-bit displacement format because the 8-bit
247 // displacement field contains $00 (zero offset).
248 bool ZeroDisplacementNeedsFixup = Value == 0 && KindLog2Size == 0;
249
250 return ZeroDisplacementNeedsFixup || FixupFieldTooSmall;
251}
252
253// NOTE Can tblgen help at all here to verify there aren't other instructions
254// we can relax?
255void M68kAsmBackend::relaxInstruction(MCInst &Inst,
256 const MCSubtargetInfo &STI) const {
257 unsigned RelaxedOp = getRelaxedOpcode(Inst);
258
259 if (RelaxedOp == Inst.getOpcode()) {
262 Inst.dump_pretty(OS);
263 OS << "\n";
264 report_fatal_error("unexpected instruction to relax: " + OS.str());
265 }
266
267 Inst.setOpcode(RelaxedOp);
268}
269
270bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
271 const MCSubtargetInfo *STI) const {
272 // Cannot emit NOP with size being not multiple of 16 bits.
273 if (Count % 2 != 0)
274 return false;
275
276 uint64_t NumNops = Count / 2;
277 for (uint64_t i = 0; i != NumNops; ++i) {
278 OS << "\x4E\x71";
279 }
280
281 return true;
282}
283
284namespace {
285
286class M68kELFAsmBackend : public M68kAsmBackend {
287public:
288 uint8_t OSABI;
289 M68kELFAsmBackend(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI)
290 : M68kAsmBackend(T, STI), OSABI(OSABI) {}
291
292 std::unique_ptr<MCObjectTargetWriter>
293 createObjectTargetWriter() const override {
294 return createM68kELFObjectWriter(OSABI);
295 }
296};
297
298} // end anonymous namespace
299
301 const MCSubtargetInfo &STI,
302 const MCRegisterInfo &MRI,
303 const MCTargetOptions &Options) {
304 const Triple &TheTriple = STI.getTargetTriple();
306 return new M68kELFAsmBackend(T, STI, OSABI);
307}
unsigned const MachineRegisterInfo * MRI
#define LLVM_DEBUG(...)
Definition: Debug.h:106
uint64_t Size
static LVOptions Options
Definition: LVOptions.cpp:25
static unsigned getRelaxedOpcodeBranch(const MCInst &Inst)
cc—Carry clear GE—Greater than or equal LS—Lower or same PL—Plus CS—Carry set GT—Greater than LT—Less...
static unsigned getRelaxedOpcodeArith(const MCInst &Inst)
static unsigned getRelaxedOpcode(const MCInst &Inst)
This file contains small standalone helper functions and enum definitions for the M68k target useful ...
This file contains M68k specific fixup entries.
PowerPC TLS Dynamic Call Fixup
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
This class represents an Operation in the Expression.
Generic interface to target specific assembler backends.
Definition: MCAsmBackend.h:42
virtual unsigned getMinimumNopSize() const
Returns the minimum size of a nop in bytes on this target.
Definition: MCAsmBackend.h:207
virtual bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const =0
Write an (optimal) nop sequence of Count bytes to the given output.
virtual void relaxInstruction(MCInst &Inst, const MCSubtargetInfo &STI) const
Relax the instruction in the given fragment to the next wider instruction.
Definition: MCAsmBackend.h:179
virtual bool mayNeedRelaxation(const MCInst &Inst, const MCSubtargetInfo &STI) const
Check whether the given instruction may need relaxation.
Definition: MCAsmBackend.h:155
virtual bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value) const
Simple predicate for targets where !Resolved implies requiring relaxation.
Definition: MCAsmBackend.h:169
virtual unsigned getNumFixupKinds() const =0
Get the number of target specific fixup kinds.
virtual void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef< char > Data, uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const =0
Apply the Value for given Fixup into the provided data fragment, at the offset specified by the fixup...
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition: MCFixup.h:71
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:185
void dump_pretty(raw_ostream &OS, const MCInstPrinter *Printer=nullptr, StringRef Separator=" ", const MCRegisterInfo *RegInfo=nullptr) const
Dump the MCInst as prettily as possible using the additional MC structures, if given.
Definition: MCInst.cpp:84
unsigned getNumOperands() const
Definition: MCInst.h:209
unsigned getOpcode() const
Definition: MCInst.h:199
void setOpcode(unsigned Op)
Definition: MCInst.h:198
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:207
bool isExpr() const
Definition: MCInst.h:66
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
Generic base class for all target subtargets.
const Triple & getTargetTriple() const
StringRef getCPU() const
This represents an "assembler immediate".
Definition: MCValue.h:36
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:310
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & CasesLower(StringLiteral S0, StringLiteral S1, T Value)
Definition: StringSwitch.h:163
R Default(T Value)
Definition: StringSwitch.h:182
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
OSType getOS() const
Get the parsed operating system type of this triple.
Definition: Triple.h:392
LLVM Value Representation.
Definition: Value.h:74
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:691
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
static unsigned getFixupKindLog2Size(unsigned Kind)
std::unique_ptr< MCObjectTargetWriter > createM68kELFObjectWriter(uint8_t OSABI)
Construct an M68k ELF object writer.
MCAsmBackend * createM68kAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition: MathExtras.h:260
DWARFExpression::Operation Op