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" 15*7a6dacacSDimitry Andric #include "llvm/MC/MCAsmInfo.h" 1681ad6265SDimitry Andric #include "llvm/MC/MCAsmLayout.h" 1781ad6265SDimitry Andric #include "llvm/MC/MCAssembler.h" 1881ad6265SDimitry Andric #include "llvm/MC/MCContext.h" 1981ad6265SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h" 20*7a6dacacSDimitry Andric #include "llvm/MC/MCExpr.h" 21*7a6dacacSDimitry Andric #include "llvm/MC/MCSection.h" 22bdd1243dSDimitry Andric #include "llvm/MC/MCValue.h" 2381ad6265SDimitry Andric #include "llvm/Support/EndianStream.h" 24*7a6dacacSDimitry Andric #include "llvm/Support/LEB128.h" 25*7a6dacacSDimitry Andric #include "llvm/Support/MathExtras.h" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-asmbackend" 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric using namespace llvm; 3081ad6265SDimitry Andric 31bdd1243dSDimitry Andric std::optional<MCFixupKind> 32bdd1243dSDimitry Andric LoongArchAsmBackend::getFixupKind(StringRef Name) const { 33bdd1243dSDimitry Andric if (STI.getTargetTriple().isOSBinFormatELF()) { 34bdd1243dSDimitry Andric auto Type = llvm::StringSwitch<unsigned>(Name) 35bdd1243dSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y) 36bdd1243dSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/LoongArch.def" 37bdd1243dSDimitry Andric #undef ELF_RELOC 38bdd1243dSDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_LARCH_NONE) 39bdd1243dSDimitry Andric .Case("BFD_RELOC_32", ELF::R_LARCH_32) 40bdd1243dSDimitry Andric .Case("BFD_RELOC_64", ELF::R_LARCH_64) 41bdd1243dSDimitry Andric .Default(-1u); 42bdd1243dSDimitry Andric if (Type != -1u) 43bdd1243dSDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); 44bdd1243dSDimitry Andric } 45bdd1243dSDimitry Andric return std::nullopt; 46bdd1243dSDimitry Andric } 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric const MCFixupKindInfo & 49bdd1243dSDimitry Andric LoongArchAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 50bdd1243dSDimitry Andric const static MCFixupKindInfo Infos[] = { 51bdd1243dSDimitry Andric // This table *must* be in the order that the fixup_* kinds are defined in 52bdd1243dSDimitry Andric // LoongArchFixupKinds.h. 53bdd1243dSDimitry Andric // 54bdd1243dSDimitry Andric // {name, offset, bits, flags} 55bdd1243dSDimitry Andric {"fixup_loongarch_b16", 10, 16, MCFixupKindInfo::FKF_IsPCRel}, 56bdd1243dSDimitry Andric {"fixup_loongarch_b21", 0, 26, MCFixupKindInfo::FKF_IsPCRel}, 57bdd1243dSDimitry Andric {"fixup_loongarch_b26", 0, 26, MCFixupKindInfo::FKF_IsPCRel}, 58bdd1243dSDimitry Andric {"fixup_loongarch_abs_hi20", 5, 20, 0}, 59bdd1243dSDimitry Andric {"fixup_loongarch_abs_lo12", 10, 12, 0}, 60bdd1243dSDimitry Andric {"fixup_loongarch_abs64_lo20", 5, 20, 0}, 61bdd1243dSDimitry Andric {"fixup_loongarch_abs64_hi12", 10, 12, 0}, 62bdd1243dSDimitry Andric {"fixup_loongarch_tls_le_hi20", 5, 20, 0}, 63bdd1243dSDimitry Andric {"fixup_loongarch_tls_le_lo12", 10, 12, 0}, 64bdd1243dSDimitry Andric {"fixup_loongarch_tls_le64_lo20", 5, 20, 0}, 65bdd1243dSDimitry Andric {"fixup_loongarch_tls_le64_hi12", 10, 12, 0}, 66bdd1243dSDimitry Andric // TODO: Add more fixup kinds. 67bdd1243dSDimitry Andric }; 68bdd1243dSDimitry Andric 69bdd1243dSDimitry Andric static_assert((std::size(Infos)) == LoongArch::NumTargetFixupKinds, 70bdd1243dSDimitry Andric "Not all fixup kinds added to Infos array"); 71bdd1243dSDimitry Andric 72bdd1243dSDimitry Andric // Fixup kinds from .reloc directive are like R_LARCH_NONE. They 73bdd1243dSDimitry Andric // do not require any extra processing. 74bdd1243dSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 75bdd1243dSDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE); 76bdd1243dSDimitry Andric 77bdd1243dSDimitry Andric if (Kind < FirstTargetFixupKind) 78bdd1243dSDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 79bdd1243dSDimitry Andric 80bdd1243dSDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 81bdd1243dSDimitry Andric "Invalid kind!"); 82bdd1243dSDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 83bdd1243dSDimitry Andric } 84bdd1243dSDimitry Andric 85bdd1243dSDimitry Andric static void reportOutOfRangeError(MCContext &Ctx, SMLoc Loc, unsigned N) { 86bdd1243dSDimitry Andric Ctx.reportError(Loc, "fixup value out of range [" + Twine(llvm::minIntN(N)) + 87bdd1243dSDimitry Andric ", " + Twine(llvm::maxIntN(N)) + "]"); 88bdd1243dSDimitry Andric } 89bdd1243dSDimitry Andric 90bdd1243dSDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 91bdd1243dSDimitry Andric MCContext &Ctx) { 92bdd1243dSDimitry Andric switch (Fixup.getTargetKind()) { 93bdd1243dSDimitry Andric default: 94bdd1243dSDimitry Andric llvm_unreachable("Unknown fixup kind"); 95bdd1243dSDimitry Andric case FK_Data_1: 96bdd1243dSDimitry Andric case FK_Data_2: 97bdd1243dSDimitry Andric case FK_Data_4: 98bdd1243dSDimitry Andric case FK_Data_8: 991db9f3b2SDimitry Andric case FK_Data_leb128: 100bdd1243dSDimitry Andric return Value; 101bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_b16: { 102bdd1243dSDimitry Andric if (!isInt<18>(Value)) 103bdd1243dSDimitry Andric reportOutOfRangeError(Ctx, Fixup.getLoc(), 18); 104bdd1243dSDimitry Andric if (Value % 4) 105bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 106bdd1243dSDimitry Andric return (Value >> 2) & 0xffff; 107bdd1243dSDimitry Andric } 108bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_b21: { 109bdd1243dSDimitry Andric if (!isInt<23>(Value)) 110bdd1243dSDimitry Andric reportOutOfRangeError(Ctx, Fixup.getLoc(), 23); 111bdd1243dSDimitry Andric if (Value % 4) 112bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 113bdd1243dSDimitry Andric return ((Value & 0x3fffc) << 8) | ((Value >> 18) & 0x1f); 114bdd1243dSDimitry Andric } 115bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_b26: { 116bdd1243dSDimitry Andric if (!isInt<28>(Value)) 117bdd1243dSDimitry Andric reportOutOfRangeError(Ctx, Fixup.getLoc(), 28); 118bdd1243dSDimitry Andric if (Value % 4) 119bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 120bdd1243dSDimitry Andric return ((Value & 0x3fffc) << 8) | ((Value >> 18) & 0x3ff); 121bdd1243dSDimitry Andric } 122bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs_hi20: 123bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le_hi20: 124bdd1243dSDimitry Andric return (Value >> 12) & 0xfffff; 125bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs_lo12: 126bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le_lo12: 127bdd1243dSDimitry Andric return Value & 0xfff; 128bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs64_lo20: 129bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le64_lo20: 130bdd1243dSDimitry Andric return (Value >> 32) & 0xfffff; 131bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_abs64_hi12: 132bdd1243dSDimitry Andric case LoongArch::fixup_loongarch_tls_le64_hi12: 133bdd1243dSDimitry Andric return (Value >> 52) & 0xfff; 134bdd1243dSDimitry Andric } 135bdd1243dSDimitry Andric } 136bdd1243dSDimitry Andric 1371db9f3b2SDimitry Andric static void fixupLeb128(MCContext &Ctx, const MCFixup &Fixup, 1381db9f3b2SDimitry Andric MutableArrayRef<char> Data, uint64_t Value) { 1391db9f3b2SDimitry Andric unsigned I; 1401db9f3b2SDimitry Andric for (I = 0; I != Data.size() && Value; ++I, Value >>= 7) 1411db9f3b2SDimitry Andric Data[I] |= uint8_t(Value & 0x7f); 1421db9f3b2SDimitry Andric if (Value) 1431db9f3b2SDimitry Andric Ctx.reportError(Fixup.getLoc(), "Invalid uleb128 value!"); 1441db9f3b2SDimitry Andric } 1451db9f3b2SDimitry Andric 14681ad6265SDimitry Andric void LoongArchAsmBackend::applyFixup(const MCAssembler &Asm, 14781ad6265SDimitry Andric const MCFixup &Fixup, 14881ad6265SDimitry Andric const MCValue &Target, 14981ad6265SDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 15081ad6265SDimitry Andric bool IsResolved, 15181ad6265SDimitry Andric const MCSubtargetInfo *STI) const { 152bdd1243dSDimitry Andric if (!Value) 153bdd1243dSDimitry Andric return; // Doesn't change encoding. 154bdd1243dSDimitry Andric 155bdd1243dSDimitry Andric MCFixupKind Kind = Fixup.getKind(); 156bdd1243dSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 15781ad6265SDimitry Andric return; 158bdd1243dSDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Kind); 159bdd1243dSDimitry Andric MCContext &Ctx = Asm.getContext(); 160bdd1243dSDimitry Andric 1611db9f3b2SDimitry Andric // Fixup leb128 separately. 1621db9f3b2SDimitry Andric if (Fixup.getTargetKind() == FK_Data_leb128) 1631db9f3b2SDimitry Andric return fixupLeb128(Ctx, Fixup, Data, Value); 1641db9f3b2SDimitry Andric 165bdd1243dSDimitry Andric // Apply any target-specific value adjustments. 166bdd1243dSDimitry Andric Value = adjustFixupValue(Fixup, Value, Ctx); 167bdd1243dSDimitry Andric 168bdd1243dSDimitry Andric // Shift the value into position. 169bdd1243dSDimitry Andric Value <<= Info.TargetOffset; 170bdd1243dSDimitry Andric 171bdd1243dSDimitry Andric unsigned Offset = Fixup.getOffset(); 172bdd1243dSDimitry Andric unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8; 173bdd1243dSDimitry Andric 174bdd1243dSDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 175bdd1243dSDimitry Andric // For each byte of the fragment that the fixup touches, mask in the 176bdd1243dSDimitry Andric // bits from the fixup value. 177bdd1243dSDimitry Andric for (unsigned I = 0; I != NumBytes; ++I) { 178bdd1243dSDimitry Andric Data[Offset + I] |= uint8_t((Value >> (I * 8)) & 0xff); 179bdd1243dSDimitry Andric } 18081ad6265SDimitry Andric } 18181ad6265SDimitry Andric 182*7a6dacacSDimitry Andric // Linker relaxation may change code size. We have to insert Nops 183*7a6dacacSDimitry Andric // for .align directive when linker relaxation enabled. So then Linker 184*7a6dacacSDimitry Andric // could satisfy alignment by removing Nops. 185*7a6dacacSDimitry Andric // The function returns the total Nops Size we need to insert. 186*7a6dacacSDimitry Andric bool LoongArchAsmBackend::shouldInsertExtraNopBytesForCodeAlign( 187*7a6dacacSDimitry Andric const MCAlignFragment &AF, unsigned &Size) { 188*7a6dacacSDimitry Andric // Calculate Nops Size only when linker relaxation enabled. 189*7a6dacacSDimitry Andric if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) 190*7a6dacacSDimitry Andric return false; 191*7a6dacacSDimitry Andric 192*7a6dacacSDimitry Andric // Ignore alignment if MaxBytesToEmit is less than the minimum Nop size. 193*7a6dacacSDimitry Andric const unsigned MinNopLen = 4; 194*7a6dacacSDimitry Andric if (AF.getMaxBytesToEmit() < MinNopLen) 195*7a6dacacSDimitry Andric return false; 196*7a6dacacSDimitry Andric Size = AF.getAlignment().value() - MinNopLen; 197*7a6dacacSDimitry Andric return AF.getAlignment() > MinNopLen; 198*7a6dacacSDimitry Andric } 199*7a6dacacSDimitry Andric 200*7a6dacacSDimitry Andric // We need to insert R_LARCH_ALIGN relocation type to indicate the 201*7a6dacacSDimitry Andric // position of Nops and the total bytes of the Nops have been inserted 202*7a6dacacSDimitry Andric // when linker relaxation enabled. 203*7a6dacacSDimitry Andric // The function inserts fixup_loongarch_align fixup which eventually will 204*7a6dacacSDimitry Andric // transfer to R_LARCH_ALIGN relocation type. 205*7a6dacacSDimitry Andric // The improved R_LARCH_ALIGN requires symbol index. The lowest 8 bits of 206*7a6dacacSDimitry Andric // addend represent alignment and the other bits of addend represent the 207*7a6dacacSDimitry Andric // maximum number of bytes to emit. The maximum number of bytes is zero 208*7a6dacacSDimitry Andric // means ignore the emit limit. 209*7a6dacacSDimitry Andric bool LoongArchAsmBackend::shouldInsertFixupForCodeAlign( 210*7a6dacacSDimitry Andric MCAssembler &Asm, const MCAsmLayout &Layout, MCAlignFragment &AF) { 211*7a6dacacSDimitry Andric // Insert the fixup only when linker relaxation enabled. 212*7a6dacacSDimitry Andric if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) 213*7a6dacacSDimitry Andric return false; 214*7a6dacacSDimitry Andric 215*7a6dacacSDimitry Andric // Calculate total Nops we need to insert. If there are none to insert 216*7a6dacacSDimitry Andric // then simply return. 217*7a6dacacSDimitry Andric unsigned Count; 218*7a6dacacSDimitry Andric if (!shouldInsertExtraNopBytesForCodeAlign(AF, Count)) 219*7a6dacacSDimitry Andric return false; 220*7a6dacacSDimitry Andric 221*7a6dacacSDimitry Andric MCSection *Sec = AF.getParent(); 222*7a6dacacSDimitry Andric MCContext &Ctx = Asm.getContext(); 223*7a6dacacSDimitry Andric const MCExpr *Dummy = MCConstantExpr::create(0, Ctx); 224*7a6dacacSDimitry Andric // Create fixup_loongarch_align fixup. 225*7a6dacacSDimitry Andric MCFixup Fixup = 226*7a6dacacSDimitry Andric MCFixup::create(0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_align)); 227*7a6dacacSDimitry Andric const MCSymbolRefExpr *MCSym = getSecToAlignSym()[Sec]; 228*7a6dacacSDimitry Andric if (MCSym == nullptr) { 229*7a6dacacSDimitry Andric // Create a symbol and make the value of symbol is zero. 230*7a6dacacSDimitry Andric MCSymbol *Sym = Ctx.createNamedTempSymbol("la-relax-align"); 231*7a6dacacSDimitry Andric Sym->setFragment(&*Sec->getBeginSymbol()->getFragment()); 232*7a6dacacSDimitry Andric Asm.registerSymbol(*Sym); 233*7a6dacacSDimitry Andric MCSym = MCSymbolRefExpr::create(Sym, Ctx); 234*7a6dacacSDimitry Andric getSecToAlignSym()[Sec] = MCSym; 235*7a6dacacSDimitry Andric } 236*7a6dacacSDimitry Andric 237*7a6dacacSDimitry Andric uint64_t FixedValue = 0; 238*7a6dacacSDimitry Andric unsigned Lo = Log2_64(Count) + 1; 239*7a6dacacSDimitry Andric unsigned Hi = AF.getMaxBytesToEmit() >= Count ? 0 : AF.getMaxBytesToEmit(); 240*7a6dacacSDimitry Andric MCValue Value = MCValue::get(MCSym, nullptr, Hi << 8 | Lo); 241*7a6dacacSDimitry Andric Asm.getWriter().recordRelocation(Asm, Layout, &AF, Fixup, Value, FixedValue); 242*7a6dacacSDimitry Andric 243*7a6dacacSDimitry Andric return true; 244*7a6dacacSDimitry Andric } 245*7a6dacacSDimitry Andric 24681ad6265SDimitry Andric bool LoongArchAsmBackend::shouldForceRelocation(const MCAssembler &Asm, 24781ad6265SDimitry Andric const MCFixup &Fixup, 2485f757f3fSDimitry Andric const MCValue &Target, 2495f757f3fSDimitry Andric const MCSubtargetInfo *STI) { 250bdd1243dSDimitry Andric if (Fixup.getKind() >= FirstLiteralRelocationKind) 251bdd1243dSDimitry Andric return true; 252bdd1243dSDimitry Andric switch (Fixup.getTargetKind()) { 253bdd1243dSDimitry Andric default: 2545f757f3fSDimitry Andric return STI->hasFeature(LoongArch::FeatureRelax); 255bdd1243dSDimitry Andric case FK_Data_1: 256bdd1243dSDimitry Andric case FK_Data_2: 257bdd1243dSDimitry Andric case FK_Data_4: 258bdd1243dSDimitry Andric case FK_Data_8: 2591db9f3b2SDimitry Andric case FK_Data_leb128: 260bdd1243dSDimitry Andric return !Target.isAbsolute(); 261bdd1243dSDimitry Andric } 26281ad6265SDimitry Andric } 26381ad6265SDimitry Andric 264cb14a3feSDimitry Andric static inline std::pair<MCFixupKind, MCFixupKind> 265cb14a3feSDimitry Andric getRelocPairForSize(unsigned Size) { 266cb14a3feSDimitry Andric switch (Size) { 267cb14a3feSDimitry Andric default: 268cb14a3feSDimitry Andric llvm_unreachable("unsupported fixup size"); 269cb14a3feSDimitry Andric case 6: 270cb14a3feSDimitry Andric return std::make_pair( 271cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD6), 272cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB6)); 273cb14a3feSDimitry Andric case 8: 274cb14a3feSDimitry Andric return std::make_pair( 275cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD8), 276cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB8)); 277cb14a3feSDimitry Andric case 16: 278cb14a3feSDimitry Andric return std::make_pair( 279cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD16), 280cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB16)); 281cb14a3feSDimitry Andric case 32: 282cb14a3feSDimitry Andric return std::make_pair( 283cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD32), 284cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB32)); 285cb14a3feSDimitry Andric case 64: 286cb14a3feSDimitry Andric return std::make_pair( 287cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD64), 288cb14a3feSDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB64)); 2891db9f3b2SDimitry Andric case 128: 2901db9f3b2SDimitry Andric return std::make_pair( 2911db9f3b2SDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_ADD_ULEB128), 2921db9f3b2SDimitry Andric MCFixupKind(FirstLiteralRelocationKind + ELF::R_LARCH_SUB_ULEB128)); 293cb14a3feSDimitry Andric } 294cb14a3feSDimitry Andric } 295cb14a3feSDimitry Andric 2961db9f3b2SDimitry Andric std::pair<bool, bool> LoongArchAsmBackend::relaxLEB128(MCLEBFragment &LF, 2971db9f3b2SDimitry Andric MCAsmLayout &Layout, 2981db9f3b2SDimitry Andric int64_t &Value) const { 2991db9f3b2SDimitry Andric const MCExpr &Expr = LF.getValue(); 3001db9f3b2SDimitry Andric if (LF.isSigned() || !Expr.evaluateKnownAbsolute(Value, Layout)) 3011db9f3b2SDimitry Andric return std::make_pair(false, false); 3021db9f3b2SDimitry Andric LF.getFixups().push_back( 3031db9f3b2SDimitry Andric MCFixup::create(0, &Expr, FK_Data_leb128, Expr.getLoc())); 3041db9f3b2SDimitry Andric return std::make_pair(true, true); 3051db9f3b2SDimitry Andric } 3061db9f3b2SDimitry Andric 307*7a6dacacSDimitry Andric bool LoongArchAsmBackend::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF, 308*7a6dacacSDimitry Andric MCAsmLayout &Layout, 309*7a6dacacSDimitry Andric bool &WasRelaxed) const { 310*7a6dacacSDimitry Andric MCContext &C = Layout.getAssembler().getContext(); 311*7a6dacacSDimitry Andric 312*7a6dacacSDimitry Andric int64_t LineDelta = DF.getLineDelta(); 313*7a6dacacSDimitry Andric const MCExpr &AddrDelta = DF.getAddrDelta(); 314*7a6dacacSDimitry Andric SmallVectorImpl<char> &Data = DF.getContents(); 315*7a6dacacSDimitry Andric SmallVectorImpl<MCFixup> &Fixups = DF.getFixups(); 316*7a6dacacSDimitry Andric size_t OldSize = Data.size(); 317*7a6dacacSDimitry Andric 318*7a6dacacSDimitry Andric int64_t Value; 319*7a6dacacSDimitry Andric if (AddrDelta.evaluateAsAbsolute(Value, Layout)) 320*7a6dacacSDimitry Andric return false; 321*7a6dacacSDimitry Andric bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout); 322*7a6dacacSDimitry Andric assert(IsAbsolute && "CFA with invalid expression"); 323*7a6dacacSDimitry Andric (void)IsAbsolute; 324*7a6dacacSDimitry Andric 325*7a6dacacSDimitry Andric Data.clear(); 326*7a6dacacSDimitry Andric Fixups.clear(); 327*7a6dacacSDimitry Andric raw_svector_ostream OS(Data); 328*7a6dacacSDimitry Andric 329*7a6dacacSDimitry Andric // INT64_MAX is a signal that this is actually a DW_LNE_end_sequence. 330*7a6dacacSDimitry Andric if (LineDelta != INT64_MAX) { 331*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_advance_line); 332*7a6dacacSDimitry Andric encodeSLEB128(LineDelta, OS); 333*7a6dacacSDimitry Andric } 334*7a6dacacSDimitry Andric 335*7a6dacacSDimitry Andric unsigned Offset; 336*7a6dacacSDimitry Andric std::pair<MCFixupKind, MCFixupKind> FK; 337*7a6dacacSDimitry Andric 338*7a6dacacSDimitry Andric // According to the DWARF specification, the `DW_LNS_fixed_advance_pc` opcode 339*7a6dacacSDimitry Andric // takes a single unsigned half (unencoded) operand. The maximum encodable 340*7a6dacacSDimitry Andric // value is therefore 65535. Set a conservative upper bound for relaxation. 341*7a6dacacSDimitry Andric if (Value > 60000) { 342*7a6dacacSDimitry Andric unsigned PtrSize = C.getAsmInfo()->getCodePointerSize(); 343*7a6dacacSDimitry Andric 344*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_extended_op); 345*7a6dacacSDimitry Andric encodeULEB128(PtrSize + 1, OS); 346*7a6dacacSDimitry Andric 347*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNE_set_address); 348*7a6dacacSDimitry Andric Offset = OS.tell(); 349*7a6dacacSDimitry Andric assert((PtrSize == 4 || PtrSize == 8) && "Unexpected pointer size"); 350*7a6dacacSDimitry Andric FK = getRelocPairForSize(PtrSize == 4 ? 32 : 64); 351*7a6dacacSDimitry Andric OS.write_zeros(PtrSize); 352*7a6dacacSDimitry Andric } else { 353*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc); 354*7a6dacacSDimitry Andric Offset = OS.tell(); 355*7a6dacacSDimitry Andric FK = getRelocPairForSize(16); 356*7a6dacacSDimitry Andric support::endian::write<uint16_t>(OS, 0, llvm::endianness::little); 357*7a6dacacSDimitry Andric } 358*7a6dacacSDimitry Andric 359*7a6dacacSDimitry Andric const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta); 360*7a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getLHS(), std::get<0>(FK))); 361*7a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getRHS(), std::get<1>(FK))); 362*7a6dacacSDimitry Andric 363*7a6dacacSDimitry Andric if (LineDelta == INT64_MAX) { 364*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_extended_op); 365*7a6dacacSDimitry Andric OS << uint8_t(1); 366*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNE_end_sequence); 367*7a6dacacSDimitry Andric } else { 368*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_LNS_copy); 369*7a6dacacSDimitry Andric } 370*7a6dacacSDimitry Andric 371*7a6dacacSDimitry Andric WasRelaxed = OldSize != Data.size(); 372*7a6dacacSDimitry Andric return true; 373*7a6dacacSDimitry Andric } 374*7a6dacacSDimitry Andric 375*7a6dacacSDimitry Andric bool LoongArchAsmBackend::relaxDwarfCFA(MCDwarfCallFrameFragment &DF, 376*7a6dacacSDimitry Andric MCAsmLayout &Layout, 377*7a6dacacSDimitry Andric bool &WasRelaxed) const { 378*7a6dacacSDimitry Andric const MCExpr &AddrDelta = DF.getAddrDelta(); 379*7a6dacacSDimitry Andric SmallVectorImpl<char> &Data = DF.getContents(); 380*7a6dacacSDimitry Andric SmallVectorImpl<MCFixup> &Fixups = DF.getFixups(); 381*7a6dacacSDimitry Andric size_t OldSize = Data.size(); 382*7a6dacacSDimitry Andric 383*7a6dacacSDimitry Andric int64_t Value; 384*7a6dacacSDimitry Andric if (AddrDelta.evaluateAsAbsolute(Value, Layout)) 385*7a6dacacSDimitry Andric return false; 386*7a6dacacSDimitry Andric bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout); 387*7a6dacacSDimitry Andric assert(IsAbsolute && "CFA with invalid expression"); 388*7a6dacacSDimitry Andric (void)IsAbsolute; 389*7a6dacacSDimitry Andric 390*7a6dacacSDimitry Andric Data.clear(); 391*7a6dacacSDimitry Andric Fixups.clear(); 392*7a6dacacSDimitry Andric raw_svector_ostream OS(Data); 393*7a6dacacSDimitry Andric 394*7a6dacacSDimitry Andric assert( 395*7a6dacacSDimitry Andric Layout.getAssembler().getContext().getAsmInfo()->getMinInstAlignment() == 396*7a6dacacSDimitry Andric 1 && 397*7a6dacacSDimitry Andric "expected 1-byte alignment"); 398*7a6dacacSDimitry Andric if (Value == 0) { 399*7a6dacacSDimitry Andric WasRelaxed = OldSize != Data.size(); 400*7a6dacacSDimitry Andric return true; 401*7a6dacacSDimitry Andric } 402*7a6dacacSDimitry Andric 403*7a6dacacSDimitry Andric auto AddFixups = [&Fixups, 404*7a6dacacSDimitry Andric &AddrDelta](unsigned Offset, 405*7a6dacacSDimitry Andric std::pair<MCFixupKind, MCFixupKind> FK) { 406*7a6dacacSDimitry Andric const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta); 407*7a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getLHS(), std::get<0>(FK))); 408*7a6dacacSDimitry Andric Fixups.push_back(MCFixup::create(Offset, MBE.getRHS(), std::get<1>(FK))); 409*7a6dacacSDimitry Andric }; 410*7a6dacacSDimitry Andric 411*7a6dacacSDimitry Andric if (isUIntN(6, Value)) { 412*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc); 413*7a6dacacSDimitry Andric AddFixups(0, getRelocPairForSize(6)); 414*7a6dacacSDimitry Andric } else if (isUInt<8>(Value)) { 415*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc1); 416*7a6dacacSDimitry Andric support::endian::write<uint8_t>(OS, 0, llvm::endianness::little); 417*7a6dacacSDimitry Andric AddFixups(1, getRelocPairForSize(8)); 418*7a6dacacSDimitry Andric } else if (isUInt<16>(Value)) { 419*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc2); 420*7a6dacacSDimitry Andric support::endian::write<uint16_t>(OS, 0, llvm::endianness::little); 421*7a6dacacSDimitry Andric AddFixups(1, getRelocPairForSize(16)); 422*7a6dacacSDimitry Andric } else if (isUInt<32>(Value)) { 423*7a6dacacSDimitry Andric OS << uint8_t(dwarf::DW_CFA_advance_loc4); 424*7a6dacacSDimitry Andric support::endian::write<uint32_t>(OS, 0, llvm::endianness::little); 425*7a6dacacSDimitry Andric AddFixups(1, getRelocPairForSize(32)); 426*7a6dacacSDimitry Andric } else { 427*7a6dacacSDimitry Andric llvm_unreachable("unsupported CFA encoding"); 428*7a6dacacSDimitry Andric } 429*7a6dacacSDimitry Andric 430*7a6dacacSDimitry Andric WasRelaxed = OldSize != Data.size(); 431*7a6dacacSDimitry Andric return true; 432*7a6dacacSDimitry Andric } 433*7a6dacacSDimitry Andric 43481ad6265SDimitry Andric bool LoongArchAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 43581ad6265SDimitry Andric const MCSubtargetInfo *STI) const { 436bdd1243dSDimitry Andric // We mostly follow binutils' convention here: align to 4-byte boundary with a 437bdd1243dSDimitry Andric // 0-fill padding. 438bdd1243dSDimitry Andric OS.write_zeros(Count % 4); 43981ad6265SDimitry Andric 440bdd1243dSDimitry Andric // The remainder is now padded with 4-byte nops. 441bdd1243dSDimitry Andric // nop: andi r0, r0, 0 44281ad6265SDimitry Andric for (; Count >= 4; Count -= 4) 443bdd1243dSDimitry Andric OS.write("\0\0\x40\x03", 4); 44481ad6265SDimitry Andric 44581ad6265SDimitry Andric return true; 44681ad6265SDimitry Andric } 44781ad6265SDimitry Andric 448cb14a3feSDimitry Andric bool LoongArchAsmBackend::handleAddSubRelocations(const MCAsmLayout &Layout, 449cb14a3feSDimitry Andric const MCFragment &F, 450cb14a3feSDimitry Andric const MCFixup &Fixup, 451cb14a3feSDimitry Andric const MCValue &Target, 452cb14a3feSDimitry Andric uint64_t &FixedValue) const { 453cb14a3feSDimitry Andric std::pair<MCFixupKind, MCFixupKind> FK; 454cb14a3feSDimitry Andric uint64_t FixedValueA, FixedValueB; 4551db9f3b2SDimitry Andric const MCSymbol &SA = Target.getSymA()->getSymbol(); 4561db9f3b2SDimitry Andric const MCSymbol &SB = Target.getSymB()->getSymbol(); 4571db9f3b2SDimitry Andric 4581db9f3b2SDimitry Andric bool force = !SA.isInSection() || !SB.isInSection(); 4591db9f3b2SDimitry Andric if (!force) { 4601db9f3b2SDimitry Andric const MCSection &SecA = SA.getSection(); 4611db9f3b2SDimitry Andric const MCSection &SecB = SB.getSection(); 462cb14a3feSDimitry Andric 463cb14a3feSDimitry Andric // We need record relocation if SecA != SecB. Usually SecB is same as the 464cb14a3feSDimitry Andric // section of Fixup, which will be record the relocation as PCRel. If SecB 465cb14a3feSDimitry Andric // is not same as the section of Fixup, it will report error. Just return 466cb14a3feSDimitry Andric // false and then this work can be finished by handleFixup. 467cb14a3feSDimitry Andric if (&SecA != &SecB) 468cb14a3feSDimitry Andric return false; 469cb14a3feSDimitry Andric 470cb14a3feSDimitry Andric // In SecA == SecB case. If the linker relaxation is enabled, we need record 4711db9f3b2SDimitry Andric // the ADD, SUB relocations. Otherwise the FixedValue has already been calc- 4721db9f3b2SDimitry Andric // ulated out in evaluateFixup, return true and avoid record relocations. 473cb14a3feSDimitry Andric if (!STI.hasFeature(LoongArch::FeatureRelax)) 474cb14a3feSDimitry Andric return true; 4751db9f3b2SDimitry Andric } 476cb14a3feSDimitry Andric 477cb14a3feSDimitry Andric switch (Fixup.getKind()) { 478cb14a3feSDimitry Andric case llvm::FK_Data_1: 479cb14a3feSDimitry Andric FK = getRelocPairForSize(8); 480cb14a3feSDimitry Andric break; 481cb14a3feSDimitry Andric case llvm::FK_Data_2: 482cb14a3feSDimitry Andric FK = getRelocPairForSize(16); 483cb14a3feSDimitry Andric break; 484cb14a3feSDimitry Andric case llvm::FK_Data_4: 485cb14a3feSDimitry Andric FK = getRelocPairForSize(32); 486cb14a3feSDimitry Andric break; 487cb14a3feSDimitry Andric case llvm::FK_Data_8: 488cb14a3feSDimitry Andric FK = getRelocPairForSize(64); 489cb14a3feSDimitry Andric break; 4901db9f3b2SDimitry Andric case llvm::FK_Data_leb128: 4911db9f3b2SDimitry Andric FK = getRelocPairForSize(128); 4921db9f3b2SDimitry Andric break; 493cb14a3feSDimitry Andric default: 494cb14a3feSDimitry Andric llvm_unreachable("unsupported fixup size"); 495cb14a3feSDimitry Andric } 496cb14a3feSDimitry Andric MCValue A = MCValue::get(Target.getSymA(), nullptr, Target.getConstant()); 497cb14a3feSDimitry Andric MCValue B = MCValue::get(Target.getSymB()); 498cb14a3feSDimitry Andric auto FA = MCFixup::create(Fixup.getOffset(), nullptr, std::get<0>(FK)); 499cb14a3feSDimitry Andric auto FB = MCFixup::create(Fixup.getOffset(), nullptr, std::get<1>(FK)); 500cb14a3feSDimitry Andric auto &Asm = Layout.getAssembler(); 501cb14a3feSDimitry Andric Asm.getWriter().recordRelocation(Asm, Layout, &F, FA, A, FixedValueA); 502cb14a3feSDimitry Andric Asm.getWriter().recordRelocation(Asm, Layout, &F, FB, B, FixedValueB); 503cb14a3feSDimitry Andric FixedValue = FixedValueA - FixedValueB; 504cb14a3feSDimitry Andric return true; 505cb14a3feSDimitry Andric } 506cb14a3feSDimitry Andric 50781ad6265SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 50881ad6265SDimitry Andric LoongArchAsmBackend::createObjectTargetWriter() const { 5095f757f3fSDimitry Andric return createLoongArchELFObjectWriter( 5105f757f3fSDimitry Andric OSABI, Is64Bit, STI.hasFeature(LoongArch::FeatureRelax)); 51181ad6265SDimitry Andric } 51281ad6265SDimitry Andric 51381ad6265SDimitry Andric MCAsmBackend *llvm::createLoongArchAsmBackend(const Target &T, 51481ad6265SDimitry Andric const MCSubtargetInfo &STI, 51581ad6265SDimitry Andric const MCRegisterInfo &MRI, 51681ad6265SDimitry Andric const MCTargetOptions &Options) { 51781ad6265SDimitry Andric const Triple &TT = STI.getTargetTriple(); 51881ad6265SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); 51906c3fb27SDimitry Andric return new LoongArchAsmBackend(STI, OSABI, TT.isArch64Bit(), Options); 52081ad6265SDimitry Andric } 521