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, 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 |
98 | static 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 | |
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 |
139 | return Op; |
140 | } |
141 | |
142 | static unsigned getRelaxedOpcode(const MCInst &Inst) { |
143 | unsigned R = getRelaxedOpcodeArith(Inst); |
144 | if (R != Inst.getOpcode()) |
145 | return R; |
146 | return getRelaxedOpcodeBranch(Inst); |
147 | } |
148 | |
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()) |
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 | |
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>(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? |
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); |
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 | |
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. |
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 | |
218 | namespace { |
219 | |
220 | class M68kELFAsmBackend : public M68kAsmBackend { |
221 | public: |
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 | |
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(OSType: TheTriple.getOS()); |
240 | return new M68kELFAsmBackend(T, OSABI); |
241 | } |
242 | |