Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
35294 views
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
37
using namespace llvm;
38
39
namespace {
40
41
class M68kAsmBackend : public MCAsmBackend {
42
43
public:
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,
72
uint64_t Value) const override;
73
74
void relaxInstruction(MCInst &Inst,
75
const MCSubtargetInfo &STI) const override;
76
77
/// Returns the minimum size of a nop in bytes on this target. The assembler
78
/// will use this to emit excess padding in situations where the padding
79
/// required for simple alignment would be less than the minimum nop size.
80
unsigned getMinimumNopSize() const override { return 2; }
81
82
/// Write a sequence of optimal nops to the output, covering \p Count bytes.
83
/// \return - true on success, false on failure
84
bool writeNopData(raw_ostream &OS, uint64_t Count,
85
const MCSubtargetInfo *STI) const override;
86
};
87
} // end anonymous namespace
88
89
/// cc—Carry clear GE—Greater than or equal
90
/// LS—Lower or same PL—Plus
91
/// CS—Carry set GT—Greater than
92
/// LT—Less than
93
/// EQ—Equal HI—Higher
94
/// MI—Minus VC—Overflow clear
95
/// LE—Less than or equal
96
/// NE—Not equal VS—Overflow set
97
static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
98
unsigned Op = Inst.getOpcode();
99
switch (Op) {
100
default:
101
return Op;
102
case M68k::BRA8:
103
return M68k::BRA16;
104
case M68k::Bcc8:
105
return M68k::Bcc16;
106
case M68k::Bls8:
107
return M68k::Bls16;
108
case M68k::Blt8:
109
return M68k::Blt16;
110
case M68k::Beq8:
111
return M68k::Beq16;
112
case M68k::Bmi8:
113
return M68k::Bmi16;
114
case M68k::Bne8:
115
return M68k::Bne16;
116
case M68k::Bge8:
117
return M68k::Bge16;
118
case M68k::Bcs8:
119
return M68k::Bcs16;
120
case M68k::Bpl8:
121
return M68k::Bpl16;
122
case M68k::Bgt8:
123
return M68k::Bgt16;
124
case M68k::Bhi8:
125
return M68k::Bhi16;
126
case M68k::Bvc8:
127
return M68k::Bvc16;
128
case M68k::Ble8:
129
return M68k::Ble16;
130
case M68k::Bvs8:
131
return M68k::Bvs16;
132
}
133
}
134
135
static unsigned getRelaxedOpcodeArith(const MCInst &Inst) {
136
unsigned Op = Inst.getOpcode();
137
// NOTE there will be some relaxations for PCD and ARD mem for x20
138
return Op;
139
}
140
141
static unsigned getRelaxedOpcode(const MCInst &Inst) {
142
unsigned R = getRelaxedOpcodeArith(Inst);
143
if (R != Inst.getOpcode())
144
return R;
145
return getRelaxedOpcodeBranch(Inst);
146
}
147
148
bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,
149
const MCSubtargetInfo &STI) const {
150
// Branches can always be relaxed in either mode.
151
if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode())
152
return true;
153
154
// Check if this instruction is ever relaxable.
155
if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode())
156
return false;
157
158
// Check if the relaxable operand has an expression. For the current set of
159
// relaxable instructions, the relaxable operand is always the last operand.
160
// NOTE will change for x20 mem
161
unsigned RelaxableOp = Inst.getNumOperands() - 1;
162
if (Inst.getOperand(RelaxableOp).isExpr())
163
return true;
164
165
return false;
166
}
167
168
bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
169
uint64_t Value) const {
170
// TODO Newer CPU can use 32 bit offsets, so check for this when ready
171
if (!isInt<16>(Value)) {
172
llvm_unreachable("Cannot relax the instruction, value does not fit");
173
}
174
// Relax if the value is too big for a (signed) i8. This means that byte-wide
175
// instructions have to matched by default
176
//
177
// NOTE
178
// A branch to the immediately following instruction automatically
179
// uses the 16-bit displacement format because the 8-bit
180
// displacement field contains $00 (zero offset).
181
return Value == 0 || !isInt<8>(Value);
182
}
183
184
// NOTE Can tblgen help at all here to verify there aren't other instructions
185
// we can relax?
186
void M68kAsmBackend::relaxInstruction(MCInst &Inst,
187
const MCSubtargetInfo &STI) const {
188
// The only relaxations M68k does is from a 1byte pcrel to a 2byte PCRel.
189
unsigned RelaxedOp = getRelaxedOpcode(Inst);
190
191
if (RelaxedOp == Inst.getOpcode()) {
192
SmallString<256> Tmp;
193
raw_svector_ostream OS(Tmp);
194
Inst.dump_pretty(OS);
195
OS << "\n";
196
report_fatal_error("unexpected instruction to relax: " + OS.str());
197
}
198
199
Inst.setOpcode(RelaxedOp);
200
}
201
202
bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
203
const MCSubtargetInfo *STI) const {
204
// Cannot emit NOP with size being not multiple of 16 bits.
205
if (Count % 2 != 0)
206
return false;
207
208
uint64_t NumNops = Count / 2;
209
for (uint64_t i = 0; i != NumNops; ++i) {
210
OS << "\x4E\x71";
211
}
212
213
return true;
214
}
215
216
namespace {
217
218
class M68kELFAsmBackend : public M68kAsmBackend {
219
public:
220
uint8_t OSABI;
221
M68kELFAsmBackend(const Target &T, uint8_t OSABI)
222
: M68kAsmBackend(T), OSABI(OSABI) {}
223
224
std::unique_ptr<MCObjectTargetWriter>
225
createObjectTargetWriter() const override {
226
return createM68kELFObjectWriter(OSABI);
227
}
228
};
229
230
} // end anonymous namespace
231
232
MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,
233
const MCSubtargetInfo &STI,
234
const MCRegisterInfo &MRI,
235
const MCTargetOptions &Options) {
236
const Triple &TheTriple = STI.getTargetTriple();
237
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
238
return new M68kELFAsmBackend(T, OSABI);
239
}
240
241