Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kAsmBackend.cpp
35294 views
//===-- M68kAsmBackend.cpp - M68k Assembler Backend -------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file contains definitions for M68k assembler backend.10///11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/M68kBaseInfo.h"14#include "MCTargetDesc/M68kFixupKinds.h"1516#include "llvm/ADT/StringSwitch.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/BinaryFormat/MachO.h"19#include "llvm/MC/MCAsmBackend.h"20#include "llvm/MC/MCELFObjectWriter.h"21#include "llvm/MC/MCExpr.h"22#include "llvm/MC/MCFixupKindInfo.h"23#include "llvm/MC/MCInst.h"24#include "llvm/MC/MCMachObjectWriter.h"25#include "llvm/MC/MCObjectWriter.h"26#include "llvm/MC/MCRegisterInfo.h"27#include "llvm/MC/MCSectionCOFF.h"28#include "llvm/MC/MCSectionELF.h"29#include "llvm/MC/MCSectionMachO.h"30#include "llvm/MC/MCSubtargetInfo.h"31#include "llvm/MC/TargetRegistry.h"32#include "llvm/Support/ErrorHandling.h"33#include "llvm/Support/MathExtras.h"34#include "llvm/Support/raw_ostream.h"3536using namespace llvm;3738namespace {3940class M68kAsmBackend : public MCAsmBackend {4142public:43M68kAsmBackend(const Target &T) : MCAsmBackend(llvm::endianness::big) {}4445unsigned getNumFixupKinds() const override { return 0; }4647void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,48const MCValue &Target, MutableArrayRef<char> Data,49uint64_t Value, bool IsResolved,50const MCSubtargetInfo *STI) const override {51unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());5253assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");5455// Check that uppper bits are either all zeros or all ones.56// Specifically ignore overflow/underflow as long as the leakage is57// limited to the lower bits. This is to remain compatible with58// other assemblers.59assert(isIntN(Size * 8 + 1, Value) &&60"Value does not fit in the Fixup field");6162// Write in Big Endian63for (unsigned i = 0; i != Size; ++i)64Data[Fixup.getOffset() + i] = uint8_t(Value >> ((Size - i - 1) * 8));65}6667bool mayNeedRelaxation(const MCInst &Inst,68const MCSubtargetInfo &STI) const override;6970bool fixupNeedsRelaxation(const MCFixup &Fixup,71uint64_t Value) const override;7273void relaxInstruction(MCInst &Inst,74const MCSubtargetInfo &STI) const override;7576/// Returns the minimum size of a nop in bytes on this target. The assembler77/// will use this to emit excess padding in situations where the padding78/// required for simple alignment would be less than the minimum nop size.79unsigned getMinimumNopSize() const override { return 2; }8081/// Write a sequence of optimal nops to the output, covering \p Count bytes.82/// \return - true on success, false on failure83bool writeNopData(raw_ostream &OS, uint64_t Count,84const MCSubtargetInfo *STI) const override;85};86} // end anonymous namespace8788/// cc—Carry clear GE—Greater than or equal89/// LS—Lower or same PL—Plus90/// CS—Carry set GT—Greater than91/// LT—Less than92/// EQ—Equal HI—Higher93/// MI—Minus VC—Overflow clear94/// LE—Less than or equal95/// NE—Not equal VS—Overflow set96static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {97unsigned Op = Inst.getOpcode();98switch (Op) {99default:100return Op;101case M68k::BRA8:102return M68k::BRA16;103case M68k::Bcc8:104return M68k::Bcc16;105case M68k::Bls8:106return M68k::Bls16;107case M68k::Blt8:108return M68k::Blt16;109case M68k::Beq8:110return M68k::Beq16;111case M68k::Bmi8:112return M68k::Bmi16;113case M68k::Bne8:114return M68k::Bne16;115case M68k::Bge8:116return M68k::Bge16;117case M68k::Bcs8:118return M68k::Bcs16;119case M68k::Bpl8:120return M68k::Bpl16;121case M68k::Bgt8:122return M68k::Bgt16;123case M68k::Bhi8:124return M68k::Bhi16;125case M68k::Bvc8:126return M68k::Bvc16;127case M68k::Ble8:128return M68k::Ble16;129case M68k::Bvs8:130return M68k::Bvs16;131}132}133134static unsigned getRelaxedOpcodeArith(const MCInst &Inst) {135unsigned Op = Inst.getOpcode();136// NOTE there will be some relaxations for PCD and ARD mem for x20137return Op;138}139140static unsigned getRelaxedOpcode(const MCInst &Inst) {141unsigned R = getRelaxedOpcodeArith(Inst);142if (R != Inst.getOpcode())143return R;144return getRelaxedOpcodeBranch(Inst);145}146147bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,148const MCSubtargetInfo &STI) const {149// Branches can always be relaxed in either mode.150if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode())151return true;152153// Check if this instruction is ever relaxable.154if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode())155return false;156157// Check if the relaxable operand has an expression. For the current set of158// relaxable instructions, the relaxable operand is always the last operand.159// NOTE will change for x20 mem160unsigned RelaxableOp = Inst.getNumOperands() - 1;161if (Inst.getOperand(RelaxableOp).isExpr())162return true;163164return false;165}166167bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,168uint64_t Value) const {169// TODO Newer CPU can use 32 bit offsets, so check for this when ready170if (!isInt<16>(Value)) {171llvm_unreachable("Cannot relax the instruction, value does not fit");172}173// Relax if the value is too big for a (signed) i8. This means that byte-wide174// instructions have to matched by default175//176// NOTE177// A branch to the immediately following instruction automatically178// uses the 16-bit displacement format because the 8-bit179// displacement field contains $00 (zero offset).180return Value == 0 || !isInt<8>(Value);181}182183// NOTE Can tblgen help at all here to verify there aren't other instructions184// we can relax?185void M68kAsmBackend::relaxInstruction(MCInst &Inst,186const MCSubtargetInfo &STI) const {187// The only relaxations M68k does is from a 1byte pcrel to a 2byte PCRel.188unsigned RelaxedOp = getRelaxedOpcode(Inst);189190if (RelaxedOp == Inst.getOpcode()) {191SmallString<256> Tmp;192raw_svector_ostream OS(Tmp);193Inst.dump_pretty(OS);194OS << "\n";195report_fatal_error("unexpected instruction to relax: " + OS.str());196}197198Inst.setOpcode(RelaxedOp);199}200201bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,202const MCSubtargetInfo *STI) const {203// Cannot emit NOP with size being not multiple of 16 bits.204if (Count % 2 != 0)205return false;206207uint64_t NumNops = Count / 2;208for (uint64_t i = 0; i != NumNops; ++i) {209OS << "\x4E\x71";210}211212return true;213}214215namespace {216217class M68kELFAsmBackend : public M68kAsmBackend {218public:219uint8_t OSABI;220M68kELFAsmBackend(const Target &T, uint8_t OSABI)221: M68kAsmBackend(T), OSABI(OSABI) {}222223std::unique_ptr<MCObjectTargetWriter>224createObjectTargetWriter() const override {225return createM68kELFObjectWriter(OSABI);226}227};228229} // end anonymous namespace230231MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,232const MCSubtargetInfo &STI,233const MCRegisterInfo &MRI,234const MCTargetOptions &Options) {235const Triple &TheTriple = STI.getTargetTriple();236uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());237return new M68kELFAsmBackend(T, OSABI);238}239240241