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: 445f757f3fSDimitry Andric M68kAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::big) {} 45fe6060f1SDimitry Andric 46fe6060f1SDimitry Andric unsigned getNumFixupKinds() const override { return 0; } 47fe6060f1SDimitry Andric 48fe6060f1SDimitry 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. 80fe6060f1SDimitry 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 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 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 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 148fe6060f1SDimitry 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 168*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? 186fe6060f1SDimitry 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 202349cc55cSDimitry 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; 221fe6060f1SDimitry Andric M68kELFAsmBackend(const Target &T, uint8_t OSABI) 222fe6060f1SDimitry Andric : M68kAsmBackend(T), OSABI(OSABI) {} 223fe6060f1SDimitry Andric 224fe6060f1SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 225fe6060f1SDimitry Andric createObjectTargetWriter() const override { 226fe6060f1SDimitry Andric return createM68kELFObjectWriter(OSABI); 227fe6060f1SDimitry Andric } 228fe6060f1SDimitry Andric }; 229fe6060f1SDimitry Andric 230fe6060f1SDimitry Andric } // end anonymous namespace 231fe6060f1SDimitry Andric 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