264 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// 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/MCAssembler.h"22#include "llvm/MC/MCELFObjectWriter.h"23#include "llvm/MC/MCExpr.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 39using namespace llvm;40 41#define DEBUG_TYPE "M68k-asm-backend"42 43namespace {44 45class M68kAsmBackend : public MCAsmBackend {46 bool Allows32BitBranch;47 48public: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 void applyFixup(const MCFragment &, const MCFixup &, const MCValue &,56 uint8_t *Data, uint64_t Value, bool IsResolved) override;57 58 bool mayNeedRelaxation(unsigned Opcode, ArrayRef<MCOperand> Operands,59 const MCSubtargetInfo &STI) const override;60 61 bool fixupNeedsRelaxation(const MCFixup &Fixup,62 uint64_t Value) const override;63 64 void relaxInstruction(MCInst &Inst,65 const MCSubtargetInfo &STI) const override;66 67 /// Returns the minimum size of a nop in bytes on this target. The assembler68 /// will use this to emit excess padding in situations where the padding69 /// required for simple alignment would be less than the minimum nop size.70 unsigned getMinimumNopSize() const override { return 2; }71 72 /// Write a sequence of optimal nops to the output, covering \p Count bytes.73 /// \return - true on success, false on failure74 bool writeNopData(raw_ostream &OS, uint64_t Count,75 const MCSubtargetInfo *STI) const override;76};77} // end anonymous namespace78 79void M68kAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,80 const MCValue &Target, uint8_t *Data,81 uint64_t Value, bool IsResolved) {82 if (!IsResolved)83 Asm->getWriter().recordRelocation(F, Fixup, Target, Value);84 85 unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());86 assert(Fixup.getOffset() + Size <= F.getSize() && "Invalid fixup offset!");87 // Check that uppper bits are either all zeros or all ones.88 // Specifically ignore overflow/underflow as long as the leakage is89 // limited to the lower bits. This is to remain compatible with90 // other assemblers.91 assert(isIntN(Size * 8 + 1, static_cast<int64_t>(Value)) &&92 "Value does not fit in the Fixup field");93 94 // Write in Big Endian95 for (unsigned i = 0; i != Size; ++i)96 Data[i] = uint8_t(static_cast<int64_t>(Value) >> ((Size - i - 1) * 8));97}98 99/// cc—Carry clear GE—Greater than or equal100/// LS—Lower or same PL—Plus101/// CS—Carry set GT—Greater than102/// LT—Less than103/// EQ—Equal HI—Higher104/// MI—Minus VC—Overflow clear105/// LE—Less than or equal106/// NE—Not equal VS—Overflow set107static unsigned getRelaxedOpcodeBranch(unsigned Op) {108 switch (Op) {109 default:110 return Op;111 112 // 8 -> 16113 case M68k::BRA8:114 return M68k::BRA16;115 case M68k::Bcc8:116 return M68k::Bcc16;117 case M68k::Bls8:118 return M68k::Bls16;119 case M68k::Blt8:120 return M68k::Blt16;121 case M68k::Beq8:122 return M68k::Beq16;123 case M68k::Bmi8:124 return M68k::Bmi16;125 case M68k::Bne8:126 return M68k::Bne16;127 case M68k::Bge8:128 return M68k::Bge16;129 case M68k::Bcs8:130 return M68k::Bcs16;131 case M68k::Bpl8:132 return M68k::Bpl16;133 case M68k::Bgt8:134 return M68k::Bgt16;135 case M68k::Bhi8:136 return M68k::Bhi16;137 case M68k::Bvc8:138 return M68k::Bvc16;139 case M68k::Ble8:140 return M68k::Ble16;141 case M68k::Bvs8:142 return M68k::Bvs16;143 144 // 16 -> 32145 case M68k::BRA16:146 return M68k::BRA32;147 case M68k::Bcc16:148 return M68k::Bcc32;149 case M68k::Bls16:150 return M68k::Bls32;151 case M68k::Blt16:152 return M68k::Blt32;153 case M68k::Beq16:154 return M68k::Beq32;155 case M68k::Bmi16:156 return M68k::Bmi32;157 case M68k::Bne16:158 return M68k::Bne32;159 case M68k::Bge16:160 return M68k::Bge32;161 case M68k::Bcs16:162 return M68k::Bcs32;163 case M68k::Bpl16:164 return M68k::Bpl32;165 case M68k::Bgt16:166 return M68k::Bgt32;167 case M68k::Bhi16:168 return M68k::Bhi32;169 case M68k::Bvc16:170 return M68k::Bvc32;171 case M68k::Ble16:172 return M68k::Ble32;173 case M68k::Bvs16:174 return M68k::Bvs32;175 }176}177 178static unsigned getRelaxedOpcode(unsigned Opcode) {179 // NOTE there will be some relaxations for PCD and ARD mem for x20180 return getRelaxedOpcodeBranch(Opcode);181}182 183bool M68kAsmBackend::mayNeedRelaxation(unsigned Opcode, ArrayRef<MCOperand>,184 const MCSubtargetInfo &STI) const {185 // Branches can always be relaxed in either mode.186 return getRelaxedOpcode(Opcode) != Opcode;187 188 // NOTE will change for x20 mem189}190 191bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,192 uint64_t UnsignedValue) const {193 int64_t Value = static_cast<int64_t>(UnsignedValue);194 195 if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value)))196 llvm_unreachable("Cannot relax the instruction, value does not fit");197 198 // Relax if the value is too big for a (signed) i8199 // (or signed i16 if 32 bit branches can be used). This means200 // that byte-wide instructions have to matched by default201 unsigned KindLog2Size = getFixupKindLog2Size(Fixup.getKind());202 bool FixupFieldTooSmall = false;203 if (!isInt<8>(Value) && KindLog2Size == 0)204 FixupFieldTooSmall = true;205 else if (!isInt<16>(Value) && KindLog2Size <= 1)206 FixupFieldTooSmall = true;207 208 // NOTE209 // A branch to the immediately following instruction automatically210 // uses the 16-bit displacement format because the 8-bit211 // displacement field contains $00 (zero offset).212 bool ZeroDisplacementNeedsFixup = Value == 0 && KindLog2Size == 0;213 214 return ZeroDisplacementNeedsFixup || FixupFieldTooSmall;215}216 217// NOTE Can tblgen help at all here to verify there aren't other instructions218// we can relax?219void M68kAsmBackend::relaxInstruction(MCInst &Inst,220 const MCSubtargetInfo &STI) const {221 unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode());222 assert(RelaxedOp != Inst.getOpcode());223 Inst.setOpcode(RelaxedOp);224}225 226bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,227 const MCSubtargetInfo *STI) const {228 // Cannot emit NOP with size being not multiple of 16 bits.229 if (Count % 2 != 0)230 return false;231 232 uint64_t NumNops = Count / 2;233 for (uint64_t i = 0; i != NumNops; ++i) {234 OS << "\x4E\x71";235 }236 237 return true;238}239 240namespace {241 242class M68kELFAsmBackend : public M68kAsmBackend {243public:244 uint8_t OSABI;245 M68kELFAsmBackend(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI)246 : M68kAsmBackend(T, STI), OSABI(OSABI) {}247 248 std::unique_ptr<MCObjectTargetWriter>249 createObjectTargetWriter() const override {250 return createM68kELFObjectWriter(OSABI);251 }252};253 254} // end anonymous namespace255 256MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,257 const MCSubtargetInfo &STI,258 const MCRegisterInfo &MRI,259 const MCTargetOptions &Options) {260 const Triple &TheTriple = STI.getTargetTriple();261 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());262 return new M68kELFAsmBackend(T, STI, OSABI);263}264