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/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 39 using namespace llvm; 40 41 #define DEBUG_TYPE "M68k-asm-backend" 42 43 namespace { 44 45 class M68kAsmBackend : public MCAsmBackend { 46 bool Allows32BitBranch; 47 48 public: 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 unsigned getNumFixupKinds() const override { return 0; } 56 57 void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 58 const MCValue &Target, MutableArrayRef<char> Data, 59 uint64_t Value, bool IsResolved, 60 const MCSubtargetInfo *STI) const override { 61 unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind()); 62 63 if (Fixup.getOffset() + Size > Data.size()) { 64 LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n'); 65 LLVM_DEBUG(dbgs() << "Size: " << Size << '\n'); 66 LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n'); 67 assert(Fixup.getOffset() + Size <= Data.size() && 68 "Invalid fixup offset!"); 69 } 70 71 // Check that uppper bits are either all zeros or all ones. 72 // Specifically ignore overflow/underflow as long as the leakage is 73 // limited to the lower bits. This is to remain compatible with 74 // other assemblers. 75 if (!(isIntN(Size * 8 + 1, static_cast<int64_t>(Value)) || IsResolved)) { 76 LLVM_DEBUG(dbgs() << "Fixup.getOffset(): " << Fixup.getOffset() << '\n'); 77 LLVM_DEBUG(dbgs() << "Size: " << Size << '\n'); 78 LLVM_DEBUG(dbgs() << "Data.size(): " << Data.size() << '\n'); 79 LLVM_DEBUG(dbgs() << "Value: " << Value << '\n'); 80 LLVM_DEBUG(dbgs() << "Target: "); 81 LLVM_DEBUG(Target.print(dbgs())); 82 LLVM_DEBUG(dbgs() << '\n'); 83 assert(isIntN(Size * 8 + 1, static_cast<int64_t>(Value)) && 84 "Value does not fit in the Fixup field"); 85 } 86 87 // Write in Big Endian 88 for (unsigned i = 0; i != Size; ++i) 89 Data[Fixup.getOffset() + i] = 90 uint8_t(static_cast<int64_t>(Value) >> ((Size - i - 1) * 8)); 91 } 92 93 bool mayNeedRelaxation(const MCInst &Inst, 94 const MCSubtargetInfo &STI) const override; 95 96 bool fixupNeedsRelaxation(const MCFixup &Fixup, 97 uint64_t Value) const override; 98 99 void relaxInstruction(MCInst &Inst, 100 const MCSubtargetInfo &STI) const override; 101 102 /// Returns the minimum size of a nop in bytes on this target. The assembler 103 /// will use this to emit excess padding in situations where the padding 104 /// required for simple alignment would be less than the minimum nop size. 105 unsigned getMinimumNopSize() const override { return 2; } 106 107 /// Write a sequence of optimal nops to the output, covering \p Count bytes. 108 /// \return - true on success, false on failure 109 bool writeNopData(raw_ostream &OS, uint64_t Count, 110 const MCSubtargetInfo *STI) const override; 111 }; 112 } // end anonymous namespace 113 114 /// cc—Carry clear GE—Greater than or equal 115 /// LS—Lower or same PL—Plus 116 /// CS—Carry set GT—Greater than 117 /// LT—Less than 118 /// EQ—Equal HI—Higher 119 /// MI—Minus VC—Overflow clear 120 /// LE—Less than or equal 121 /// NE—Not equal VS—Overflow set 122 static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) { 123 unsigned Op = Inst.getOpcode(); 124 switch (Op) { 125 default: 126 return Op; 127 128 // 8 -> 16 129 case M68k::BRA8: 130 return M68k::BRA16; 131 case M68k::Bcc8: 132 return M68k::Bcc16; 133 case M68k::Bls8: 134 return M68k::Bls16; 135 case M68k::Blt8: 136 return M68k::Blt16; 137 case M68k::Beq8: 138 return M68k::Beq16; 139 case M68k::Bmi8: 140 return M68k::Bmi16; 141 case M68k::Bne8: 142 return M68k::Bne16; 143 case M68k::Bge8: 144 return M68k::Bge16; 145 case M68k::Bcs8: 146 return M68k::Bcs16; 147 case M68k::Bpl8: 148 return M68k::Bpl16; 149 case M68k::Bgt8: 150 return M68k::Bgt16; 151 case M68k::Bhi8: 152 return M68k::Bhi16; 153 case M68k::Bvc8: 154 return M68k::Bvc16; 155 case M68k::Ble8: 156 return M68k::Ble16; 157 case M68k::Bvs8: 158 return M68k::Bvs16; 159 160 // 16 -> 32 161 case M68k::BRA16: 162 return M68k::BRA32; 163 case M68k::Bcc16: 164 return M68k::Bcc32; 165 case M68k::Bls16: 166 return M68k::Bls32; 167 case M68k::Blt16: 168 return M68k::Blt32; 169 case M68k::Beq16: 170 return M68k::Beq32; 171 case M68k::Bmi16: 172 return M68k::Bmi32; 173 case M68k::Bne16: 174 return M68k::Bne32; 175 case M68k::Bge16: 176 return M68k::Bge32; 177 case M68k::Bcs16: 178 return M68k::Bcs32; 179 case M68k::Bpl16: 180 return M68k::Bpl32; 181 case M68k::Bgt16: 182 return M68k::Bgt32; 183 case M68k::Bhi16: 184 return M68k::Bhi32; 185 case M68k::Bvc16: 186 return M68k::Bvc32; 187 case M68k::Ble16: 188 return M68k::Ble32; 189 case M68k::Bvs16: 190 return M68k::Bvs32; 191 } 192 } 193 194 static unsigned getRelaxedOpcodeArith(const MCInst &Inst) { 195 unsigned Op = Inst.getOpcode(); 196 // NOTE there will be some relaxations for PCD and ARD mem for x20 197 return Op; 198 } 199 200 static unsigned getRelaxedOpcode(const MCInst &Inst) { 201 unsigned R = getRelaxedOpcodeArith(Inst); 202 if (R != Inst.getOpcode()) 203 return R; 204 return getRelaxedOpcodeBranch(Inst); 205 } 206 207 bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst, 208 const MCSubtargetInfo &STI) const { 209 // Branches can always be relaxed in either mode. 210 if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode()) 211 return true; 212 213 // Check if this instruction is ever relaxable. 214 if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode()) 215 return false; 216 217 // Check if the relaxable operand has an expression. For the current set of 218 // relaxable instructions, the relaxable operand is always the last operand. 219 // NOTE will change for x20 mem 220 unsigned RelaxableOp = Inst.getNumOperands() - 1; 221 if (Inst.getOperand(RelaxableOp).isExpr()) 222 return true; 223 224 return false; 225 } 226 227 bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, 228 uint64_t UnsignedValue) const { 229 int64_t Value = static_cast<int64_t>(UnsignedValue); 230 231 if (!isInt<32>(Value) || (!Allows32BitBranch && !isInt<16>(Value))) 232 llvm_unreachable("Cannot relax the instruction, value does not fit"); 233 234 // Relax if the value is too big for a (signed) i8 235 // (or signed i16 if 32 bit branches can be used). This means 236 // that byte-wide instructions have to matched by default 237 unsigned KindLog2Size = getFixupKindLog2Size(Fixup.getKind()); 238 bool FixupFieldTooSmall = false; 239 if (!isInt<8>(Value) && KindLog2Size == 0) 240 FixupFieldTooSmall = true; 241 else if (!isInt<16>(Value) && KindLog2Size <= 1) 242 FixupFieldTooSmall = true; 243 244 // NOTE 245 // A branch to the immediately following instruction automatically 246 // uses the 16-bit displacement format because the 8-bit 247 // displacement field contains $00 (zero offset). 248 bool ZeroDisplacementNeedsFixup = Value == 0 && KindLog2Size == 0; 249 250 return ZeroDisplacementNeedsFixup || FixupFieldTooSmall; 251 } 252 253 // NOTE Can tblgen help at all here to verify there aren't other instructions 254 // we can relax? 255 void M68kAsmBackend::relaxInstruction(MCInst &Inst, 256 const MCSubtargetInfo &STI) const { 257 unsigned RelaxedOp = getRelaxedOpcode(Inst); 258 259 if (RelaxedOp == Inst.getOpcode()) { 260 SmallString<256> Tmp; 261 raw_svector_ostream OS(Tmp); 262 Inst.dump_pretty(OS); 263 OS << "\n"; 264 report_fatal_error("unexpected instruction to relax: " + OS.str()); 265 } 266 267 Inst.setOpcode(RelaxedOp); 268 } 269 270 bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 271 const MCSubtargetInfo *STI) const { 272 // Cannot emit NOP with size being not multiple of 16 bits. 273 if (Count % 2 != 0) 274 return false; 275 276 uint64_t NumNops = Count / 2; 277 for (uint64_t i = 0; i != NumNops; ++i) { 278 OS << "\x4E\x71"; 279 } 280 281 return true; 282 } 283 284 namespace { 285 286 class M68kELFAsmBackend : public M68kAsmBackend { 287 public: 288 uint8_t OSABI; 289 M68kELFAsmBackend(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI) 290 : M68kAsmBackend(T, STI), OSABI(OSABI) {} 291 292 std::unique_ptr<MCObjectTargetWriter> 293 createObjectTargetWriter() const override { 294 return createM68kELFObjectWriter(OSABI); 295 } 296 }; 297 298 } // end anonymous namespace 299 300 MCAsmBackend *llvm::createM68kAsmBackend(const Target &T, 301 const MCSubtargetInfo &STI, 302 const MCRegisterInfo &MRI, 303 const MCTargetOptions &Options) { 304 const Triple &TheTriple = STI.getTargetTriple(); 305 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); 306 return new M68kELFAsmBackend(T, STI, OSABI); 307 } 308