181ad6265SDimitry Andric //===-- LoongArchAsmBackend.cpp - LoongArch Assembler Backend -*- C++ -*---===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file implements the LoongArchAsmBackend class. 1081ad6265SDimitry Andric // 1181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include "LoongArchAsmBackend.h" 14bdd1243dSDimitry Andric #include "LoongArchFixupKinds.h" 157a6dacacSDimitry Andric #include "llvm/MC/MCAsmInfo.h" 1681ad6265SDimitry Andric #include "llvm/MC/MCAssembler.h" 1781ad6265SDimitry Andric #include "llvm/MC/MCContext.h" 1881ad6265SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h" 197a6dacacSDimitry Andric #include "llvm/MC/MCExpr.h" 207a6dacacSDimitry Andric #include "llvm/MC/MCSection.h" 21bdd1243dSDimitry Andric #include "llvm/MC/MCValue.h" 2281ad6265SDimitry Andric #include "llvm/Support/EndianStream.h" 237a6dacacSDimitry Andric #include "llvm/Support/LEB128.h" 247a6dacacSDimitry Andric #include "llvm/Support/MathExtras.h" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-asmbackend" 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric using namespace llvm; 2981ad6265SDimitry Andric 30bdd1243dSDimitry Andric std::optional<MCFixupKind> 31bdd1243dSDimitry Andric LoongArchAsmBackend::getFixupKind(StringRef Name) const { 32bdd1243dSDimitry Andric if (STI.getTargetTriple().isOSBinFormatELF()) { 33bdd1243dSDimitry Andric auto Type = llvm::StringSwitch<unsigned>(Name) 34bdd1243dSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y) 35bdd1243dSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/LoongArch.def" 36bdd1243dSDimitry Andric #undef ELF_RELOC 37bdd1243dSDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_LARCH_NONE) 38bdd1243dSDimitry Andric .Case("BFD_RELOC_32", ELF::R_LARCH_32) 39bdd1243dSDimitry Andric .Case("BFD_RELOC_64", ELF::R_LARCH_64) 40bdd1243dSDimitry Andric .Default(-1u); 41bdd1243dSDimitry Andric if (Type != -1u) 42bdd1243dSDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); 43bdd1243dSDimitry Andric } 44bdd1243dSDimitry Andric return std::nullopt; 45bdd1243dSDimitry Andric } 46bdd1243dSDimitry Andric 47bdd1243dSDimitry Andric const MCFixupKindInfo & 48bdd1243dSDimitry Andric LoongArchAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 49bdd1243dSDimitry Andric const static MCFixupKindInfo Infos[] = { 50bdd1243dSDimitry Andric // This table *must* be in the order that the fixup_* kinds are defined in 51bdd1243dSDimitry Andric // LoongArchFixupKinds.h. 52bdd1243dSDimitry Andric // 53bdd1243dSDimitry Andric // {name, offset, bits, flags} 54bdd1243dSDimitry Andric {"fixup_loongarch_b16", 10, 16, MCFixupKindInfo::FKF_IsPCRel}, 55bdd1243dSDimitry Andric {"fixup_loongarch_b21", 0, 26, MCFixupKindInfo::FKF_IsPCRel}, 56bdd1243dSDimitry Andric {"fixup_loongarch_b26", 0, 26, MCFixupKindInfo::FKF_IsPCRel}, 57bdd1243dSDimitry Andric {"fixup_loongarch_abs_hi20", 5, 20, 0}, 58bdd1243dSDimitry Andric {"fixup_loongarch_abs_lo12", 10, 12, 0}, 59bdd1243dSDimitry Andric {"fixup_loongarch_abs64_lo20", 5, 20, 0}, 60bdd1243dSDimitry Andric {"fixup_loongarch_abs64_hi12", 10, 12, 0}, 61bdd1243dSDimitry Andric {"fixup_loongarch_tls_le_hi20", 5, 20, 0}, 62bdd1243dSDimitry Andric {"fixup_loongarch_tls_le_lo12", 10, 12, 0}, 63bdd1243dSDimitry Andric {"fixup_loongarch_tls_le64_lo20", 5, 20, 0}, 64bdd1243dSDimitry Andric {"fixup_loongarch_tls_le64_hi12", 10, 12, 0}, 65bdd1243dSDimitry Andric // TODO: Add more fixup kinds. 66bdd1243dSDimitry Andric }; 67bdd1243dSDimitry Andric 68bdd1243dSDimitry Andric static_assert((std::size(Infos)) == LoongArch::NumTargetFixupKinds, 69bdd1243dSDimitry Andric "Not all fixup kinds added to Infos array"); 70bdd1243dSDimitry Andric 71bdd1243dSDimitry Andric // Fixup kinds from .reloc directive are like R_LARCH_NONE. They 72bdd1243dSDimitry Andric // do not require any extra processing. 73bdd1243dSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 74bdd1243dSDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE); 75bdd1243dSDimitry Andric 76bdd1243dSDimitry Andric if (Kind < FirstTargetFixupKind) 77bdd1243dSDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 78bdd1243dSDimitry Andric 79bdd1243dSDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 80bdd1243dSDimitry Andric "Invalid kind!"); 81bdd1243dSDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 82bdd1243dSDimitry Andric } 83bdd1243dSDimitry Andric 84bdd1243dSDimitry Andric static void reportOutOfRangeError(MCContext &Ctx, SMLoc Loc, unsigned N) { 85bdd1243dSDimitry Andric Ctx.reportError(Loc, "fixup value out of range [" + Twine(llvm::minIntN(N)) + 86bdd1243dSDimitry Andric ", " + Twine(llvm::maxIntN(N)) + "]"); 87bdd1243dSDimitry Andric } 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 90bdd1243dSDimitry Andric MCContext &Ctx) { 91bdd1243dSDimitry Andric switch (Fixup.getTargetKind()) { 92bdd1243dSDimitry Andric default: 93bdd1243dSDimitry Andric llvm_unreachable("Unknown fixup kind"); 94bdd1243dSDimitry Andric case FK_Data_1: 95bdd1243dSDimitry Andric case FK_Data_2: 96bdd1243dSDimitry Andric case FK_Data_4: 97bdd1243dSDimitry Andric case FK_Data_8: 981db9f3b2SDimitry Andric case FK_Data_leb128: 99bdd1243dSDimitry Andric return Value; 100bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_b16: { 101bdd1243dSDimitry Andric if (!isInt<18>(Value)) 102bdd1243dSDimitry Andric reportOutOfRangeError(Ctx, Fixup.getLoc(), 18); 103bdd1243dSDimitry Andric if (Value % 4) 104bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 105bdd1243dSDimitry Andric return (Value >> 2) & 0xffff; 106bdd1243dSDimitry Andric } 107bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_b21: { 108bdd1243dSDimitry Andric if (!isInt<23>(Value)) 109bdd1243dSDimitry Andric reportOutOfRangeError(Ctx, Fixup.getLoc(), 23); 110bdd1243dSDimitry Andric if (Value % 4) 111bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 112bdd1243dSDimitry Andric return ((Value & 0x3fffc) << 8) | ((Value >> 18) & 0x1f); 113bdd1243dSDimitry Andric } 114bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_b26: { 115bdd1243dSDimitry Andric if (!isInt<28>(Value)) 116bdd1243dSDimitry Andric reportOutOfRangeError(Ctx, Fixup.getLoc(), 28); 117bdd1243dSDimitry Andric if (Value % 4) 118bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 119bdd1243dSDimitry Andric return ((Value & 0x3fffc) << 8) | ((Value >> 18) & 0x3ff); 120bdd1243dSDimitry Andric } 121bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs_hi20: 122bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le_hi20: 123bdd1243dSDimitry Andric return (Value >> 12) & 0xfffff; 124bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs_lo12: 125bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le_lo12: 126bdd1243dSDimitry Andric return Value & 0xfff; 127bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs64_lo20: 128bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le64_lo20: 129bdd1243dSDimitry Andric return (Value >> 32) & 0xfffff; 130bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs64_hi12: 131bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le64_hi12: 132bdd1243dSDimitry Andric return (Value >> 52) & 0xfff; 133bdd1243dSDimitry Andric } 134bdd1243dSDimitry Andric } 135bdd1243dSDimitry Andric 1361db9f3b2SDimitry Andric static void fixupLeb128(MCContext &Ctx, const MCFixup &Fixup, 1371db9f3b2SDimitry Andric MutableArrayRef<char> Data, uint64_t Value) { 1381db9f3b2SDimitry Andric unsigned I; 1391db9f3b2SDimitry Andric for (I = 0; I != Data.size() && Value; ++I, Value >>= 7) 1401db9f3b2SDimitry Andric Data[I] |= uint8_t(Value & 0x7f); 1411db9f3b2SDimitry Andric if (Value) 1421db9f3b2SDimitry Andric Ctx.reportError(Fixup.getLoc(), "Invalid uleb128 value!"); 1431db9f3b2SDimitry Andric } 1441db9f3b2SDimitry Andric 14581ad6265SDimitry Andric void LoongArchAsmBackend::applyFixup(const MCAssembler &Asm, 14681ad6265SDimitry Andric const MCFixup &Fixup, 14781ad6265SDimitry Andric const MCValue &Target, 14881ad6265SDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 14981ad6265SDimitry Andric bool IsResolved, 15081ad6265SDimitry Andric const MCSubtargetInfo *STI) const { 151bdd1243dSDimitry Andric if (!Value) 152bdd1243dSDimitry Andric return; // Doesn't change encoding. 153bdd1243dSDimitry Andric 154bdd1243dSDimitry Andric MCFixupKind Kind = Fixup.getKind(); 155bdd1243dSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 15681ad6265SDimitry Andric return; 157bdd1243dSDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Kind); 158bdd1243dSDimitry Andric MCContext &Ctx = Asm.getContext(); 159bdd1243dSDimitry Andric 1601db9f3b2SDimitry Andric // Fixup leb128 separately. 1611db9f3b2SDimitry Andric if (Fixup.getTargetKind() == FK_Data_leb128) 1621db9f3b2SDimitry Andric return fixupLeb128(Ctx, Fixup, Data, Value); 1631db9f3b2SDimitry Andric 164bdd1243dSDimitry Andric // Apply any target-specific value adjustments. 165bdd1243dSDimitry Andric Value = adjustFixupValue(Fixup, Value, Ctx); 166bdd1243dSDimitry Andric 167bdd1243dSDimitry Andric // Shift the value into position. 168bdd1243dSDimitry Andric Value <<= Info.TargetOffset; 169bdd1243dSDimitry Andric 170bdd1243dSDimitry Andric unsigned Offset = Fixup.getOffset(); 171bdd1243dSDimitry Andric unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8; 172bdd1243dSDimitry Andric 173bdd1243dSDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 174bdd1243dSDimitry Andric // For each byte of the fragment that the fixup touches, mask in the 175bdd1243dSDimitry Andric // bits from the fixup value. 176bdd1243dSDimitry Andric for (unsigned I = 0; I != NumBytes; ++I) { 177bdd1243dSDimitry Andric Data[Offset + I] |= uint8_t((Value >> (I * 8)) & 0xff); 178bdd1243dSDimitry Andric } 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 1817a6dacacSDimitry Andric // Linker relaxation may change code size. We have to insert Nops 1827a6dacacSDimitry Andric // for .align directive when linker relaxation enabled. So then Linker 1837a6dacacSDimitry Andric // could satisfy alignment by removing Nops. 1847a6dacacSDimitry Andric // The function returns the total Nops Size we need to insert. 1857a6dacacSDimitry Andric bool LoongArchAsmBackend::shouldInsertExtraNopBytesForCodeAlign( 1867a6dacacSDimitry Andric const MCAlignFragment &AF, unsigned &Size) { 1877a6dacacSDimitry Andric // Calculate Nops Size only when linker relaxation enabled. 1887a6dacacSDimitry Andric if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) 1897a6dacacSDimitry Andric return false; 1907a6dacacSDimitry Andric 1917a6dacacSDimitry Andric // Ignore alignment if MaxBytesToEmit is less than the minimum Nop size. 1927a6dacacSDimitry Andric const unsigned MinNopLen = 4; 1937a6dacacSDimitry Andric if (AF.getMaxBytesToEmit() < MinNopLen) 1947a6dacacSDimitry Andric return false; 1957a6dacacSDimitry Andric Size = AF.getAlignment().value() - MinNopLen; 1967a6dacacSDimitry Andric return AF.getAlignment() > MinNopLen; 1977a6dacacSDimitry Andric } 1987a6dacacSDimitry Andric 1997a6dacacSDimitry Andric // We need to insert R_LARCH_ALIGN relocation type to indicate the 2007a6dacacSDimitry Andric // position of Nops and the total bytes of the Nops have been inserted 2017a6dacacSDimitry Andric // when linker relaxation enabled. 2027a6dacacSDimitry Andric // The function inserts fixup_loongarch_align fixup which eventually will 2037a6dacacSDimitry Andric // transfer to R_LARCH_ALIGN relocation type. 2047a6dacacSDimitry Andric // The improved R_LARCH_ALIGN requires symbol index. The lowest 8 bits of 2057a6dacacSDimitry Andric // addend represent alignment and the other bits of addend represent the 2067a6dacacSDimitry Andric // maximum number of bytes to emit. The maximum number of bytes is zero 2077a6dacacSDimitry Andric // means ignore the emit limit. 208*0fca6ea1SDimitry Andric bool LoongArchAsmBackend::shouldInsertFixupForCodeAlign(MCAssembler &Asm, 209*0fca6ea1SDimitry Andric MCAlignFragment &AF) { 2107a6dacacSDimitry Andric // Insert the fixup only when linker relaxation enabled. 2117a6dacacSDimitry Andric if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) 2127a6dacacSDimitry Andric return false; 2137a6dacacSDimitry Andric 2147a6dacacSDimitry Andric // Calculate total Nops we need to insert. If there are none to insert 2157a6dacacSDimitry Andric // then simply return. 216*0fca6ea1SDimitry Andric unsigned InsertedNopBytes; 217*0fca6ea1SDimitry Andric if (!shouldInsertExtraNopBytesForCodeAlign(AF, InsertedNopBytes)) 2187a6dacacSDimitry Andric return false; 2197a6dacacSDimitry Andric 2207a6dacacSDimitry Andric MCSection *Sec = AF.getParent(); 2217a6dacacSDimitry Andric MCContext &Ctx = Asm.getContext(); 2227a6dacacSDimitry Andric const MCExpr *Dummy = MCConstantExpr::create(0, Ctx); 2237a6dacacSDimitry Andric // Create fixup_loongarch_align fixup. 2247a6dacacSDimitry Andric MCFixup Fixup = 2257a6dacacSDimitry Andric MCFixup::create(0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_align)); 226*0fca6ea1SDimitry Andric unsigned MaxBytesToEmit = AF.getMaxBytesToEmit(); 227*0fca6ea1SDimitry Andric 228*0fca6ea1SDimitry Andric auto createExtendedValue = [&]() { 2297a6dacacSDimitry Andric const MCSymbolRefExpr *MCSym = getSecToAlignSym()[Sec]; 2307a6dacacSDimitry Andric if (MCSym == nullptr) { 231*0fca6ea1SDimitry Andric // Define a marker symbol at the section with an offset of 0. 2327a6dacacSDimitry Andric MCSymbol *Sym = Ctx.createNamedTempSymbol("la-relax-align"); 2337a6dacacSDimitry Andric Sym->setFragment(&*Sec->getBeginSymbol()->getFragment()); 2347a6dacacSDimitry Andric Asm.registerSymbol(*Sym); 2357a6dacacSDimitry Andric MCSym = MCSymbolRefExpr::create(Sym, Ctx); 2367a6dacacSDimitry Andric getSecToAlignSym()[Sec] = MCSym; 2377a6dacacSDimitry Andric } 238*0fca6ea1SDimitry Andric return MCValue::get(MCSym, nullptr, 239*0fca6ea1SDimitry Andric MaxBytesToEmit << 8 | Log2(AF.getAlignment())); 240*0fca6ea1SDimitry Andric }; 2417a6dacacSDimitry Andric 2427a6dacacSDimitry Andric uint64_t FixedValue = 0; 243*0fca6ea1SDimitry Andric MCValue Value = MaxBytesToEmit >= InsertedNopBytes 244*0fca6ea1SDimitry Andric ? MCValue::get(InsertedNopBytes) 245*0fca6ea1SDimitry Andric : createExtendedValue(); 246*0fca6ea1SDimitry Andric Asm.getWriter().recordRelocation(Asm, &AF, Fixup, Value, FixedValue); 2477a6dacacSDimitry Andric 2487a6dacacSDimitry Andric return true; 2497a6dacacSDimitry Andric } 2507a6dacacSDimitry Andric 25181ad6265SDimitry Andric bool LoongArchAsmBackend::shouldForceRelocation(const MCAssembler &Asm, 25281ad6265SDimitry Andric const MCFixup &Fixup, 2535f757f3fSDimitry Andric const MCValue &Target, 2545f757f3fSDimitry Andric const MCSubtargetInfo *STI) { 255bdd1243dSDimitry Andric if (Fixup.getKind() >= FirstLiteralRelocationKind) 256bdd1243dSDimitry Andric return true; 257bdd1243dSDimitry Andric switch (Fixup.getTargetKind()) { 258bdd1243dSDimitry Andric default: 2595f757f3fSDimitry Andric return STI->hasFeature(LoongArch::FeatureRelax); 260bdd1243dSDimitry Andric case FK_Data_1: 261bdd1243dSDimitry Andric case FK_Data_2: 262bdd1243dSDimitry Andric case FK_Data_4: 263bdd1243dSDimitry Andric case FK_Data_8: 2641db9f3b2SDimitry Andric case FK_Data_leb128: 265bdd1243dSDimitry Andric return !Target.isAbsolute(); 266bdd1243dSDimitry Andric } 26781ad6265SDimitry Andric } 26881ad6265SDimitry Andric 269cb14a3feSDimitry Andric static inline std::pair<MCFixupKind, MCFixupKind> 270cb14a3feSDimitry Andric getRelocPairForSize(unsigned Size) { 271cb14a3feSDimitry Andric switch (Size) { 272cb14a3feSDimitry Andric default: 273cb14a3feSDimitry Andric llvm_unreachable("unsupported fixup size"); 274cb14a3feSDimitry Andric case 6: 275cb14a3feSDimitry Andric return std::make_pair( 276cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD6), 277cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB6)); 278cb14a3feSDimitry Andric case 8: 279cb14a3feSDimitry Andric return std::make_pair( 280cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD8), 281cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB8)); 282cb14a3feSDimitry Andric case 16: 283cb14a3feSDimitry Andric return std::make_pair( 284cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD16), 285cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB16)); 286cb14a3feSDimitry Andric case 32: 287cb14a3feSDimitry Andric return std::make_pair( 288cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD32), 289cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB32)); 290cb14a3feSDimitry Andric case 64: 291cb14a3feSDimitry Andric return std::make_pair( 292cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD64), 293cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB64)); 2941db9f3b2SDimitry Andric case 128: 2951db9f3b2SDimitry Andric return std::make_pair( 2961db9f3b2SDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD_ULEB128), 2971db9f3b2SDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB_ULEB128)); 298cb14a3feSDimitry Andric } 299cb14a3feSDimitry Andric } 300cb14a3feSDimitry Andric 301*0fca6ea1SDimitry Andric std::pair<bool, bool> LoongArchAsmBackend::relaxLEB128(const MCAssembler &Asm, 302*0fca6ea1SDimitry Andric MCLEBFragment &LF, 3031db9f3b2SDimitry Andric int64_t &Value) const { 3041db9f3b2SDimitry Andric const MCExpr &Expr = LF.getValue(); 305*0fca6ea1SDimitry Andric if (LF.isSigned() || !Expr.evaluateKnownAbsolute(Value, Asm)) 3061db9f3b2SDimitry Andric return std::make_pair(false, false); 3071db9f3b2SDimitry Andric LF.getFixups().push_back( 3081db9f3b2SDimitry Andric MCFixup::create(0, &Expr, FK_Data_leb128, Expr.getLoc())); 3091db9f3b2SDimitry Andric return std::make_pair(true, true); 3101db9f3b2SDimitry Andric } 3111db9f3b2SDimitry Andric 312*0fca6ea1SDimitry Andric bool LoongArchAsmBackend::relaxDwarfLineAddr(const MCAssembler &Asm, 313*0fca6ea1SDimitry Andric MCDwarfLineAddrFragment &DF, 3147a6dacacSDimitry Andric bool &WasRelaxed) const { 315*0fca6ea1SDimitry Andric MCContext &C = Asm.getContext(); 3167a6dacacSDimitry Andric 3177a6dacacSDimitry Andric int64_t LineDelta = DF.getLineDelta(); 3187a6dacacSDimitry Andric const MCExpr &AddrDelta = DF.getAddrDelta(); 3197a6dacacSDimitry Andric SmallVectorImpl<char> &Data = DF.getContents(); 3207a6dacacSDimitry Andric SmallVectorImpl<MCFixup> &Fixups = DF.getFixups(); 3217a6dacacSDimitry Andric size_t OldSize = Data.size(); 3227a6dacacSDimitry Andric 3237a6dacacSDimitry Andric int64_t Value; 324*0fca6ea1SDimitry Andric if (AddrDelta.evaluateAsAbsolute(Value, Asm)) 3257a6dacacSDimitry Andric return false; 326*0fca6ea1SDimitry Andric bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Asm); 3277a6dacacSDimitry Andric assert(IsAbsolute && "CFA with invalid expression"); 3287a6dacacSDimitry Andric (void)IsAbsolute; 3297a6dacacSDimitry Andric 3307a6dacacSDimitry Andric Data.clear(); 3317a6dacacSDimitry Andric Fixups.clear(); 3327a6dacacSDimitry Andric raw_svector_ostream OS(Data); 3337a6dacacSDimitry Andric 3347a6dacacSDimitry Andric // INT64_MAX is a signal that this is actually a DW_LNE_end_sequence. 3357a6dacacSDimitry Andric if (LineDelta != INT64_MAX) { 3367a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_advance_line); 3377a6dacacSDimitry Andric encodeSLEB128(LineDelta, OS); 3387a6dacacSDimitry Andric } 3397a6dacacSDimitry Andric 3407a6dacacSDimitry Andric unsigned Offset; 3417a6dacacSDimitry Andric std::pair<MCFixupKind, MCFixupKind> FK; 3427a6dacacSDimitry Andric 3437a6dacacSDimitry Andric // According to the DWARF specification, the `DW_LNS_fixed_advance_pc` opcode 3447a6dacacSDimitry Andric // takes a single unsigned half (unencoded) operand. The maximum encodable 3457a6dacacSDimitry Andric // value is therefore 65535. Set a conservative upper bound for relaxation. 3467a6dacacSDimitry Andric if (Value > 60000) { 3477a6dacacSDimitry Andric unsigned PtrSize = C.getAsmInfo()->getCodePointerSize(); 3487a6dacacSDimitry Andric 3497a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_extended_op); 3507a6dacacSDimitry Andric encodeULEB128(PtrSize + 1, OS); 3517a6dacacSDimitry Andric 3527a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNE_set_address); 3537a6dacacSDimitry Andric Offset = OS.tell(); 3547a6dacacSDimitry Andric assert((PtrSize == 4 || PtrSize == 8) && "Unexpected pointer size"); 3557a6dacacSDimitry Andric FK = getRelocPairForSize(PtrSize == 4 ? 32 : 64); 3567a6dacacSDimitry Andric OS.write_zeros(PtrSize); 3577a6dacacSDimitry Andric } else { 3587a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc); 3597a6dacacSDimitry Andric Offset = OS.tell(); 3607a6dacacSDimitry Andric FK = getRelocPairForSize(16); 3617a6dacacSDimitry Andric support::endian::write<uint16_t>(OS, 0, llvm::endianness::little); 3627a6dacacSDimitry Andric } 3637a6dacacSDimitry Andric 3647a6dacacSDimitry Andric const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta); 3657a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getLHS(), std::get<0>(FK))); 3667a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getRHS(), std::get<1>(FK))); 3677a6dacacSDimitry Andric 3687a6dacacSDimitry Andric if (LineDelta == INT64_MAX) { 3697a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_extended_op); 3707a6dacacSDimitry Andric OS << uint8_t(1); 3717a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNE_end_sequence); 3727a6dacacSDimitry Andric } else { 3737a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_copy); 3747a6dacacSDimitry Andric } 3757a6dacacSDimitry Andric 3767a6dacacSDimitry Andric WasRelaxed = OldSize != Data.size(); 3777a6dacacSDimitry Andric return true; 3787a6dacacSDimitry Andric } 3797a6dacacSDimitry Andric 380*0fca6ea1SDimitry Andric bool LoongArchAsmBackend::relaxDwarfCFA(const MCAssembler &Asm, 381*0fca6ea1SDimitry Andric MCDwarfCallFrameFragment &DF, 3827a6dacacSDimitry Andric bool &WasRelaxed) const { 3837a6dacacSDimitry Andric const MCExpr &AddrDelta = DF.getAddrDelta(); 3847a6dacacSDimitry Andric SmallVectorImpl<char> &Data = DF.getContents(); 3857a6dacacSDimitry Andric SmallVectorImpl<MCFixup> &Fixups = DF.getFixups(); 3867a6dacacSDimitry Andric size_t OldSize = Data.size(); 3877a6dacacSDimitry Andric 3887a6dacacSDimitry Andric int64_t Value; 389*0fca6ea1SDimitry Andric if (AddrDelta.evaluateAsAbsolute(Value, Asm)) 3907a6dacacSDimitry Andric return false; 391*0fca6ea1SDimitry Andric bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Asm); 3927a6dacacSDimitry Andric assert(IsAbsolute && "CFA with invalid expression"); 3937a6dacacSDimitry Andric (void)IsAbsolute; 3947a6dacacSDimitry Andric 3957a6dacacSDimitry Andric Data.clear(); 3967a6dacacSDimitry Andric Fixups.clear(); 3977a6dacacSDimitry Andric raw_svector_ostream OS(Data); 3987a6dacacSDimitry Andric 399*0fca6ea1SDimitry Andric assert(Asm.getContext().getAsmInfo()->getMinInstAlignment() == 1 && 4007a6dacacSDimitry Andric "expected 1-byte alignment"); 4017a6dacacSDimitry Andric if (Value == 0) { 4027a6dacacSDimitry Andric WasRelaxed = OldSize != Data.size(); 4037a6dacacSDimitry Andric return true; 4047a6dacacSDimitry Andric } 4057a6dacacSDimitry Andric 4067a6dacacSDimitry Andric auto AddFixups = [&Fixups, 4077a6dacacSDimitry Andric &AddrDelta](unsigned Offset, 4087a6dacacSDimitry Andric std::pair<MCFixupKind, MCFixupKind> FK) { 4097a6dacacSDimitry Andric const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta); 4107a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getLHS(), std::get<0>(FK))); 4117a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getRHS(), std::get<1>(FK))); 4127a6dacacSDimitry Andric }; 4137a6dacacSDimitry Andric 4147a6dacacSDimitry Andric if (isUIntN(6, Value)) { 4157a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc); 4167a6dacacSDimitry Andric AddFixups(0, getRelocPairForSize(6)); 4177a6dacacSDimitry Andric } else if (isUInt<8>(Value)) { 4187a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc1); 4197a6dacacSDimitry Andric support::endian::write<uint8_t>(OS, 0, llvm::endianness::little); 4207a6dacacSDimitry Andric AddFixups(1, getRelocPairForSize(8)); 4217a6dacacSDimitry Andric } else if (isUInt<16>(Value)) { 4227a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc2); 4237a6dacacSDimitry Andric support::endian::write<uint16_t>(OS, 0, llvm::endianness::little); 4247a6dacacSDimitry Andric AddFixups(1, getRelocPairForSize(16)); 4257a6dacacSDimitry Andric } else if (isUInt<32>(Value)) { 4267a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc4); 4277a6dacacSDimitry Andric support::endian::write<uint32_t>(OS, 0, llvm::endianness::little); 4287a6dacacSDimitry Andric AddFixups(1, getRelocPairForSize(32)); 4297a6dacacSDimitry Andric } else { 4307a6dacacSDimitry Andric llvm_unreachable("unsupported CFA encoding"); 4317a6dacacSDimitry Andric } 4327a6dacacSDimitry Andric 4337a6dacacSDimitry Andric WasRelaxed = OldSize != Data.size(); 4347a6dacacSDimitry Andric return true; 4357a6dacacSDimitry Andric } 4367a6dacacSDimitry Andric 43781ad6265SDimitry Andric bool LoongArchAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 43881ad6265SDimitry Andric const MCSubtargetInfo *STI) const { 439bdd1243dSDimitry Andric // We mostly follow binutils' convention here: align to 4-byte boundary with a 440bdd1243dSDimitry Andric // 0-fill padding. 441bdd1243dSDimitry Andric OS.write_zeros(Count % 4); 44281ad6265SDimitry Andric 443bdd1243dSDimitry Andric // The remainder is now padded with 4-byte nops. 444bdd1243dSDimitry Andric // nop: andi r0, r0, 0 44581ad6265SDimitry Andric for (; Count >= 4; Count -= 4) 446bdd1243dSDimitry Andric OS.write("\0\0\x40\x03", 4); 44781ad6265SDimitry Andric 44881ad6265SDimitry Andric return true; 44981ad6265SDimitry Andric } 45081ad6265SDimitry Andric 451*0fca6ea1SDimitry Andric bool LoongArchAsmBackend::handleAddSubRelocations(const MCAssembler &Asm, 452cb14a3feSDimitry Andric const MCFragment &F, 453cb14a3feSDimitry Andric const MCFixup &Fixup, 454cb14a3feSDimitry Andric const MCValue &Target, 455cb14a3feSDimitry Andric uint64_t &FixedValue) const { 456cb14a3feSDimitry Andric std::pair<MCFixupKind, MCFixupKind> FK; 457cb14a3feSDimitry Andric uint64_t FixedValueA, FixedValueB; 4581db9f3b2SDimitry Andric const MCSymbol &SA = Target.getSymA()->getSymbol(); 4591db9f3b2SDimitry Andric const MCSymbol &SB = Target.getSymB()->getSymbol(); 4601db9f3b2SDimitry Andric 4611db9f3b2SDimitry Andric bool force = !SA.isInSection() || !SB.isInSection(); 4621db9f3b2SDimitry Andric if (!force) { 4631db9f3b2SDimitry Andric const MCSection &SecA = SA.getSection(); 4641db9f3b2SDimitry Andric const MCSection &SecB = SB.getSection(); 465cb14a3feSDimitry Andric 466cb14a3feSDimitry Andric // We need record relocation if SecA != SecB. Usually SecB is same as the 467cb14a3feSDimitry Andric // section of Fixup, which will be record the relocation as PCRel. If SecB 468cb14a3feSDimitry Andric // is not same as the section of Fixup, it will report error. Just return 469cb14a3feSDimitry Andric // false and then this work can be finished by handleFixup. 470cb14a3feSDimitry Andric if (&SecA != &SecB) 471cb14a3feSDimitry Andric return false; 472cb14a3feSDimitry Andric 473cb14a3feSDimitry Andric // In SecA == SecB case. If the linker relaxation is enabled, we need record 4741db9f3b2SDimitry Andric // the ADD, SUB relocations. Otherwise the FixedValue has already been calc- 4751db9f3b2SDimitry Andric // ulated out in evaluateFixup, return true and avoid record relocations. 476cb14a3feSDimitry Andric if (!STI.hasFeature(LoongArch::FeatureRelax)) 477cb14a3feSDimitry Andric return true; 4781db9f3b2SDimitry Andric } 479cb14a3feSDimitry Andric 480cb14a3feSDimitry Andric switch (Fixup.getKind()) { 481cb14a3feSDimitry Andric case llvm::FK_Data_1: 482cb14a3feSDimitry Andric FK = getRelocPairForSize(8); 483cb14a3feSDimitry Andric break; 484cb14a3feSDimitry Andric case llvm::FK_Data_2: 485cb14a3feSDimitry Andric FK = getRelocPairForSize(16); 486cb14a3feSDimitry Andric break; 487cb14a3feSDimitry Andric case llvm::FK_Data_4: 488cb14a3feSDimitry Andric FK = getRelocPairForSize(32); 489cb14a3feSDimitry Andric break; 490cb14a3feSDimitry Andric case llvm::FK_Data_8: 491cb14a3feSDimitry Andric FK = getRelocPairForSize(64); 492cb14a3feSDimitry Andric break; 4931db9f3b2SDimitry Andric case llvm::FK_Data_leb128: 4941db9f3b2SDimitry Andric FK = getRelocPairForSize(128); 4951db9f3b2SDimitry Andric break; 496cb14a3feSDimitry Andric default: 497cb14a3feSDimitry Andric llvm_unreachable("unsupported fixup size"); 498cb14a3feSDimitry Andric } 499cb14a3feSDimitry Andric MCValue A = MCValue::get(Target.getSymA(), nullptr, Target.getConstant()); 500cb14a3feSDimitry Andric MCValue B = MCValue::get(Target.getSymB()); 501cb14a3feSDimitry Andric auto FA = MCFixup::create(Fixup.getOffset(), nullptr, std::get<0>(FK)); 502cb14a3feSDimitry Andric auto FB = MCFixup::create(Fixup.getOffset(), nullptr, std::get<1>(FK)); 503*0fca6ea1SDimitry Andric auto &Assembler = const_cast<MCAssembler &>(Asm); 504*0fca6ea1SDimitry Andric Asm.getWriter().recordRelocation(Assembler, &F, FA, A, FixedValueA); 505*0fca6ea1SDimitry Andric Asm.getWriter().recordRelocation(Assembler, &F, FB, B, FixedValueB); 506cb14a3feSDimitry Andric FixedValue = FixedValueA - FixedValueB; 507cb14a3feSDimitry Andric return true; 508cb14a3feSDimitry Andric } 509cb14a3feSDimitry Andric 51081ad6265SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 51181ad6265SDimitry Andric LoongArchAsmBackend::createObjectTargetWriter() const { 5125f757f3fSDimitry Andric return createLoongArchELFObjectWriter( 5135f757f3fSDimitry Andric OSABI, Is64Bit, STI.hasFeature(LoongArch::FeatureRelax)); 51481ad6265SDimitry Andric } 51581ad6265SDimitry Andric 51681ad6265SDimitry Andric MCAsmBackend *llvm::createLoongArchAsmBackend(const Target &T, 51781ad6265SDimitry Andric const MCSubtargetInfo &STI, 51881ad6265SDimitry Andric const MCRegisterInfo &MRI, 51981ad6265SDimitry Andric const MCTargetOptions &Options) { 52081ad6265SDimitry Andric const Triple &TT = STI.getTargetTriple(); 52181ad6265SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); 52206c3fb27SDimitry Andric return new LoongArchAsmBackend(STI, OSABI, TT.isArch64Bit(), Options); 52381ad6265SDimitry Andric } 524