104eeddc0SDimitry Andric //===-- M68kAsmBackend.cpp - M68k Assembler Backend -------------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file
10fe6060f1SDimitry Andric /// This file contains definitions for M68k assembler backend.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric
14fe6060f1SDimitry Andric #include "MCTargetDesc/M68kBaseInfo.h"
15fe6060f1SDimitry Andric #include "MCTargetDesc/M68kFixupKinds.h"
16fe6060f1SDimitry Andric
17fe6060f1SDimitry Andric #include "llvm/ADT/StringSwitch.h"
18fe6060f1SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
19fe6060f1SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
20fe6060f1SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
21fe6060f1SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
22fe6060f1SDimitry Andric #include "llvm/MC/MCExpr.h"
23fe6060f1SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
24fe6060f1SDimitry Andric #include "llvm/MC/MCInst.h"
25fe6060f1SDimitry Andric #include "llvm/MC/MCMachObjectWriter.h"
26fe6060f1SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
27fe6060f1SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
28fe6060f1SDimitry Andric #include "llvm/MC/MCSectionCOFF.h"
29fe6060f1SDimitry Andric #include "llvm/MC/MCSectionELF.h"
30fe6060f1SDimitry Andric #include "llvm/MC/MCSectionMachO.h"
31fe6060f1SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
32349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
33fe6060f1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
34fe6060f1SDimitry Andric #include "llvm/Support/MathExtras.h"
35fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h"
36fe6060f1SDimitry Andric
37fe6060f1SDimitry Andric using namespace llvm;
38fe6060f1SDimitry Andric
39fe6060f1SDimitry Andric namespace {
40fe6060f1SDimitry Andric
41fe6060f1SDimitry Andric class M68kAsmBackend : public MCAsmBackend {
42fe6060f1SDimitry Andric
43fe6060f1SDimitry Andric public:
M68kAsmBackend(const Target & T)445f757f3fSDimitry Andric M68kAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::big) {}
45fe6060f1SDimitry Andric
getNumFixupKinds() const46fe6060f1SDimitry Andric unsigned getNumFixupKinds() const override { return 0; }
47fe6060f1SDimitry Andric
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const48fe6060f1SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
49fe6060f1SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data,
50fe6060f1SDimitry Andric uint64_t Value, bool IsResolved,
51fe6060f1SDimitry Andric const MCSubtargetInfo *STI) const override {
52fe6060f1SDimitry Andric unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
53fe6060f1SDimitry Andric
54fe6060f1SDimitry Andric assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
55fe6060f1SDimitry Andric
56fe6060f1SDimitry Andric // Check that uppper bits are either all zeros or all ones.
57fe6060f1SDimitry Andric // Specifically ignore overflow/underflow as long as the leakage is
58fe6060f1SDimitry Andric // limited to the lower bits. This is to remain compatible with
59fe6060f1SDimitry Andric // other assemblers.
60fe6060f1SDimitry Andric assert(isIntN(Size * 8 + 1, Value) &&
61fe6060f1SDimitry Andric "Value does not fit in the Fixup field");
62fe6060f1SDimitry Andric
63fe6060f1SDimitry Andric // Write in Big Endian
64fe6060f1SDimitry Andric for (unsigned i = 0; i != Size; ++i)
65fe6060f1SDimitry Andric Data[Fixup.getOffset() + i] = uint8_t(Value >> ((Size - i - 1) * 8));
66fe6060f1SDimitry Andric }
67fe6060f1SDimitry Andric
68fe6060f1SDimitry Andric bool mayNeedRelaxation(const MCInst &Inst,
69fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const override;
70fe6060f1SDimitry Andric
71*0fca6ea1SDimitry Andric bool fixupNeedsRelaxation(const MCFixup &Fixup,
72*0fca6ea1SDimitry Andric uint64_t Value) const override;
73fe6060f1SDimitry Andric
74fe6060f1SDimitry Andric void relaxInstruction(MCInst &Inst,
75fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const override;
76fe6060f1SDimitry Andric
77fe6060f1SDimitry Andric /// Returns the minimum size of a nop in bytes on this target. The assembler
78fe6060f1SDimitry Andric /// will use this to emit excess padding in situations where the padding
79fe6060f1SDimitry Andric /// required for simple alignment would be less than the minimum nop size.
getMinimumNopSize() const80fe6060f1SDimitry Andric unsigned getMinimumNopSize() const override { return 2; }
81fe6060f1SDimitry Andric
82fe6060f1SDimitry Andric /// Write a sequence of optimal nops to the output, covering \p Count bytes.
83fe6060f1SDimitry Andric /// \return - true on success, false on failure
84349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count,
85349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override;
86fe6060f1SDimitry Andric };
87fe6060f1SDimitry Andric } // end anonymous namespace
88fe6060f1SDimitry Andric
89fe6060f1SDimitry Andric /// cc—Carry clear GE—Greater than or equal
90fe6060f1SDimitry Andric /// LS—Lower or same PL—Plus
91fe6060f1SDimitry Andric /// CS—Carry set GT—Greater than
92fe6060f1SDimitry Andric /// LT—Less than
93fe6060f1SDimitry Andric /// EQ—Equal HI—Higher
94fe6060f1SDimitry Andric /// MI—Minus VC—Overflow clear
95fe6060f1SDimitry Andric /// LE—Less than or equal
96fe6060f1SDimitry Andric /// NE—Not equal VS—Overflow set
getRelaxedOpcodeBranch(const MCInst & Inst)97fe6060f1SDimitry Andric static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
98fe6060f1SDimitry Andric unsigned Op = Inst.getOpcode();
99fe6060f1SDimitry Andric switch (Op) {
100fe6060f1SDimitry Andric default:
101fe6060f1SDimitry Andric return Op;
102fe6060f1SDimitry Andric case M68k::BRA8:
103fe6060f1SDimitry Andric return M68k::BRA16;
104fe6060f1SDimitry Andric case M68k::Bcc8:
105fe6060f1SDimitry Andric return M68k::Bcc16;
106fe6060f1SDimitry Andric case M68k::Bls8:
107fe6060f1SDimitry Andric return M68k::Bls16;
108fe6060f1SDimitry Andric case M68k::Blt8:
109fe6060f1SDimitry Andric return M68k::Blt16;
110fe6060f1SDimitry Andric case M68k::Beq8:
111fe6060f1SDimitry Andric return M68k::Beq16;
112fe6060f1SDimitry Andric case M68k::Bmi8:
113fe6060f1SDimitry Andric return M68k::Bmi16;
114fe6060f1SDimitry Andric case M68k::Bne8:
115fe6060f1SDimitry Andric return M68k::Bne16;
116fe6060f1SDimitry Andric case M68k::Bge8:
117fe6060f1SDimitry Andric return M68k::Bge16;
118fe6060f1SDimitry Andric case M68k::Bcs8:
119fe6060f1SDimitry Andric return M68k::Bcs16;
120fe6060f1SDimitry Andric case M68k::Bpl8:
121fe6060f1SDimitry Andric return M68k::Bpl16;
122fe6060f1SDimitry Andric case M68k::Bgt8:
123fe6060f1SDimitry Andric return M68k::Bgt16;
124fe6060f1SDimitry Andric case M68k::Bhi8:
125fe6060f1SDimitry Andric return M68k::Bhi16;
126fe6060f1SDimitry Andric case M68k::Bvc8:
127fe6060f1SDimitry Andric return M68k::Bvc16;
128fe6060f1SDimitry Andric case M68k::Ble8:
129fe6060f1SDimitry Andric return M68k::Ble16;
130fe6060f1SDimitry Andric case M68k::Bvs8:
131fe6060f1SDimitry Andric return M68k::Bvs16;
132fe6060f1SDimitry Andric }
133fe6060f1SDimitry Andric }
134fe6060f1SDimitry Andric
getRelaxedOpcodeArith(const MCInst & Inst)135fe6060f1SDimitry Andric static unsigned getRelaxedOpcodeArith(const MCInst &Inst) {
136fe6060f1SDimitry Andric unsigned Op = Inst.getOpcode();
137fe6060f1SDimitry Andric // NOTE there will be some relaxations for PCD and ARD mem for x20
138fe6060f1SDimitry Andric return Op;
139fe6060f1SDimitry Andric }
140fe6060f1SDimitry Andric
getRelaxedOpcode(const MCInst & Inst)141fe6060f1SDimitry Andric static unsigned getRelaxedOpcode(const MCInst &Inst) {
142fe6060f1SDimitry Andric unsigned R = getRelaxedOpcodeArith(Inst);
143fe6060f1SDimitry Andric if (R != Inst.getOpcode())
144fe6060f1SDimitry Andric return R;
145fe6060f1SDimitry Andric return getRelaxedOpcodeBranch(Inst);
146fe6060f1SDimitry Andric }
147fe6060f1SDimitry Andric
mayNeedRelaxation(const MCInst & Inst,const MCSubtargetInfo & STI) const148fe6060f1SDimitry Andric bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,
149fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const {
150fe6060f1SDimitry Andric // Branches can always be relaxed in either mode.
151fe6060f1SDimitry Andric if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode())
152fe6060f1SDimitry Andric return true;
153fe6060f1SDimitry Andric
154fe6060f1SDimitry Andric // Check if this instruction is ever relaxable.
155fe6060f1SDimitry Andric if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode())
156fe6060f1SDimitry Andric return false;
157fe6060f1SDimitry Andric
158fe6060f1SDimitry Andric // Check if the relaxable operand has an expression. For the current set of
159fe6060f1SDimitry Andric // relaxable instructions, the relaxable operand is always the last operand.
160fe6060f1SDimitry Andric // NOTE will change for x20 mem
161fe6060f1SDimitry Andric unsigned RelaxableOp = Inst.getNumOperands() - 1;
162fe6060f1SDimitry Andric if (Inst.getOperand(RelaxableOp).isExpr())
163fe6060f1SDimitry Andric return true;
164fe6060f1SDimitry Andric
165fe6060f1SDimitry Andric return false;
166fe6060f1SDimitry Andric }
167fe6060f1SDimitry Andric
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value) const168*0fca6ea1SDimitry Andric bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
169*0fca6ea1SDimitry Andric uint64_t Value) const {
170fe6060f1SDimitry Andric // TODO Newer CPU can use 32 bit offsets, so check for this when ready
171fe6060f1SDimitry Andric if (!isInt<16>(Value)) {
172fe6060f1SDimitry Andric llvm_unreachable("Cannot relax the instruction, value does not fit");
173fe6060f1SDimitry Andric }
174fe6060f1SDimitry Andric // Relax if the value is too big for a (signed) i8. This means that byte-wide
175fe6060f1SDimitry Andric // instructions have to matched by default
176fe6060f1SDimitry Andric //
177fe6060f1SDimitry Andric // NOTE
178fe6060f1SDimitry Andric // A branch to the immediately following instruction automatically
179fe6060f1SDimitry Andric // uses the 16-bit displacement format because the 8-bit
180fe6060f1SDimitry Andric // displacement field contains $00 (zero offset).
181fe6060f1SDimitry Andric return Value == 0 || !isInt<8>(Value);
182fe6060f1SDimitry Andric }
183fe6060f1SDimitry Andric
184fe6060f1SDimitry Andric // NOTE Can tblgen help at all here to verify there aren't other instructions
185fe6060f1SDimitry Andric // we can relax?
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const186fe6060f1SDimitry Andric void M68kAsmBackend::relaxInstruction(MCInst &Inst,
187fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const {
188fe6060f1SDimitry Andric // The only relaxations M68k does is from a 1byte pcrel to a 2byte PCRel.
189fe6060f1SDimitry Andric unsigned RelaxedOp = getRelaxedOpcode(Inst);
190fe6060f1SDimitry Andric
191fe6060f1SDimitry Andric if (RelaxedOp == Inst.getOpcode()) {
192fe6060f1SDimitry Andric SmallString<256> Tmp;
193fe6060f1SDimitry Andric raw_svector_ostream OS(Tmp);
194fe6060f1SDimitry Andric Inst.dump_pretty(OS);
195fe6060f1SDimitry Andric OS << "\n";
196fe6060f1SDimitry Andric report_fatal_error("unexpected instruction to relax: " + OS.str());
197fe6060f1SDimitry Andric }
198fe6060f1SDimitry Andric
199fe6060f1SDimitry Andric Inst.setOpcode(RelaxedOp);
200fe6060f1SDimitry Andric }
201fe6060f1SDimitry Andric
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const202349cc55cSDimitry Andric bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
203349cc55cSDimitry Andric const MCSubtargetInfo *STI) const {
204fe6060f1SDimitry Andric // Cannot emit NOP with size being not multiple of 16 bits.
205fe6060f1SDimitry Andric if (Count % 2 != 0)
206fe6060f1SDimitry Andric return false;
207fe6060f1SDimitry Andric
208fe6060f1SDimitry Andric uint64_t NumNops = Count / 2;
209fe6060f1SDimitry Andric for (uint64_t i = 0; i != NumNops; ++i) {
210fe6060f1SDimitry Andric OS << "\x4E\x71";
211fe6060f1SDimitry Andric }
212fe6060f1SDimitry Andric
213fe6060f1SDimitry Andric return true;
214fe6060f1SDimitry Andric }
215fe6060f1SDimitry Andric
216fe6060f1SDimitry Andric namespace {
217fe6060f1SDimitry Andric
218fe6060f1SDimitry Andric class M68kELFAsmBackend : public M68kAsmBackend {
219fe6060f1SDimitry Andric public:
220fe6060f1SDimitry Andric uint8_t OSABI;
M68kELFAsmBackend(const Target & T,uint8_t OSABI)221fe6060f1SDimitry Andric M68kELFAsmBackend(const Target &T, uint8_t OSABI)
222fe6060f1SDimitry Andric : M68kAsmBackend(T), OSABI(OSABI) {}
223fe6060f1SDimitry Andric
224fe6060f1SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const225fe6060f1SDimitry Andric createObjectTargetWriter() const override {
226fe6060f1SDimitry Andric return createM68kELFObjectWriter(OSABI);
227fe6060f1SDimitry Andric }
228fe6060f1SDimitry Andric };
229fe6060f1SDimitry Andric
230fe6060f1SDimitry Andric } // end anonymous namespace
231fe6060f1SDimitry Andric
createM68kAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)232fe6060f1SDimitry Andric MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,
233fe6060f1SDimitry Andric const MCSubtargetInfo &STI,
234fe6060f1SDimitry Andric const MCRegisterInfo &MRI,
235fe6060f1SDimitry Andric const MCTargetOptions &Options) {
236fe6060f1SDimitry Andric const Triple &TheTriple = STI.getTargetTriple();
237fe6060f1SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
238fe6060f1SDimitry Andric return new M68kELFAsmBackend(T, OSABI);
239fe6060f1SDimitry Andric }
240