brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 51bafe4 Raw
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