xref: /llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp (revision 44c05a627ffb4bdd63b477d2d74b2b6db2f87c74)
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/MCValue.h"
33 #include "llvm/MC/TargetRegistry.h"
34 #include "llvm/Support/Debug.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/MathExtras.h"
37 #include "llvm/Support/raw_ostream.h"
38 
39 using namespace llvm;
40 
41 #define DEBUG_TYPE "M68k-asm-backend"
42 
43 namespace {
44 
45 class M68kAsmBackend : public MCAsmBackend {
46   bool Allows32BitBranch;
47 
48 public:
49   M68kAsmBackend(const Target &T, const MCSubtargetInfo &STI)
50       : MCAsmBackend(llvm::endianness::big),
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,
58                   const MCValue &Target, MutableArrayRef<char> Data,
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 
96   bool fixupNeedsRelaxation(const MCFixup &Fixup,
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
122 static 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 
194 static 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 
200 static unsigned getRelaxedOpcode(const MCInst &Inst) {
201   unsigned R = getRelaxedOpcodeArith(Inst);
202   if (R != Inst.getOpcode())
203     return R;
204   return getRelaxedOpcodeBranch(Inst);
205 }
206 
207 bool 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 
227 bool 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?
255 void M68kAsmBackend::relaxInstruction(MCInst &Inst,
256                                       const MCSubtargetInfo &STI) const {
257   unsigned RelaxedOp = getRelaxedOpcode(Inst);
258 
259   if (RelaxedOp == Inst.getOpcode()) {
260     SmallString<256> Tmp;
261     raw_svector_ostream OS(Tmp);
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 
270 bool 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 
284 namespace {
285 
286 class M68kELFAsmBackend : public M68kAsmBackend {
287 public:
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 
300 MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,
301                                          const MCSubtargetInfo &STI,
302                                          const MCRegisterInfo &MRI,
303                                          const MCTargetOptions &Options) {
304   const Triple &TheTriple = STI.getTargetTriple();
305   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
306   return new M68kELFAsmBackend(T, STI, OSABI);
307 }
308