xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp (revision 02e9120893770924227138ba49df1edb3896112a)
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(support::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(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>(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>(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("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(TheTriple.getOS());
240   return new M68kELFAsmBackend(T, OSABI);
241 }
242