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