diff options
| author | Jinyang He <hejinyang@loongson.cn> | 2024-01-24 09:17:49 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-24 09:17:49 +0800 |
| commit | c51ab483e6c2d991a01179584705b83fbea1940d (patch) | |
| tree | 5abd1d5ffabdc9842e776243715ebab449eca637 /llvm/lib | |
| parent | c41472dbafd0dcacd943a95a9a099c1942d50394 (diff) | |
| download | llvm-c51ab483e6c2d991a01179584705b83fbea1940d.zip llvm-c51ab483e6c2d991a01179584705b83fbea1940d.tar.gz llvm-c51ab483e6c2d991a01179584705b83fbea1940d.tar.bz2 | |
[LoongArch] Insert nops and emit align reloc when handle alignment directive (#72962)
Refer to RISCV, we will fix up the alignment if linker relaxation
changes code size and breaks alignment. Insert enough Nops and emit
R_LARCH_ALIGN relocation type so that linker could satisfy the alignment
by removing Nops.
It does so only in sections with the SHF_EXECINSTR flag.
In LoongArch psABI v2.30, R_LARCH_ALIGN requires symbol index. The
lowest 8 bits of addend represent alignment and the other bits of addend
represent the maximum number of bytes to emit.
Diffstat (limited to 'llvm/lib')
3 files changed, 84 insertions, 0 deletions
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp index a6630d1..de492f2 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp @@ -17,9 +17,12 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/MathExtras.h" #define DEBUG_TYPE "loongarch-asmbackend" @@ -176,6 +179,70 @@ void LoongArchAsmBackend::applyFixup(const MCAssembler &Asm, } } +// Linker relaxation may change code size. We have to insert Nops +// for .align directive when linker relaxation enabled. So then Linker +// could satisfy alignment by removing Nops. +// The function returns the total Nops Size we need to insert. +bool LoongArchAsmBackend::shouldInsertExtraNopBytesForCodeAlign( + const MCAlignFragment &AF, unsigned &Size) { + // Calculate Nops Size only when linker relaxation enabled. + if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) + return false; + + // Ignore alignment if MaxBytesToEmit is less than the minimum Nop size. + const unsigned MinNopLen = 4; + if (AF.getMaxBytesToEmit() < MinNopLen) + return false; + Size = AF.getAlignment().value() - MinNopLen; + return AF.getAlignment() > MinNopLen; +} + +// We need to insert R_LARCH_ALIGN relocation type to indicate the +// position of Nops and the total bytes of the Nops have been inserted +// when linker relaxation enabled. +// The function inserts fixup_loongarch_align fixup which eventually will +// transfer to R_LARCH_ALIGN relocation type. +// The improved R_LARCH_ALIGN requires symbol index. The lowest 8 bits of +// addend represent alignment and the other bits of addend represent the +// maximum number of bytes to emit. The maximum number of bytes is zero +// means ignore the emit limit. +bool LoongArchAsmBackend::shouldInsertFixupForCodeAlign( + MCAssembler &Asm, const MCAsmLayout &Layout, MCAlignFragment &AF) { + // Insert the fixup only when linker relaxation enabled. + if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax)) + return false; + + // Calculate total Nops we need to insert. If there are none to insert + // then simply return. + unsigned Count; + if (!shouldInsertExtraNopBytesForCodeAlign(AF, Count)) + return false; + + MCSection *Sec = AF.getParent(); + MCContext &Ctx = Asm.getContext(); + const MCExpr *Dummy = MCConstantExpr::create(0, Ctx); + // Create fixup_loongarch_align fixup. + MCFixup Fixup = + MCFixup::create(0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_align)); + const MCSymbolRefExpr *MCSym = getSecToAlignSym()[Sec]; + if (MCSym == nullptr) { + // Create a symbol and make the value of symbol is zero. + MCSymbol *Sym = Ctx.createNamedTempSymbol("la-relax-align"); + Sym->setFragment(&*Sec->getBeginSymbol()->getFragment()); + Asm.registerSymbol(*Sym); + MCSym = MCSymbolRefExpr::create(Sym, Ctx); + getSecToAlignSym()[Sec] = MCSym; + } + + uint64_t FixedValue = 0; + unsigned Lo = Log2_64(Count) + 1; + unsigned Hi = AF.getMaxBytesToEmit() >= Count ? 0 : AF.getMaxBytesToEmit(); + MCValue Value = MCValue::get(MCSym, nullptr, Hi << 8 | Lo); + Asm.getWriter().recordRelocation(Asm, Layout, &AF, Fixup, Value, FixedValue); + + return true; +} + bool LoongArchAsmBackend::shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h index 518766d..9d81781 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h @@ -17,7 +17,9 @@ #include "MCTargetDesc/LoongArchFixupKinds.h" #include "MCTargetDesc/LoongArchMCTargetDesc.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCSubtargetInfo.h" namespace llvm { @@ -27,6 +29,7 @@ class LoongArchAsmBackend : public MCAsmBackend { uint8_t OSABI; bool Is64Bit; const MCTargetOptions &TargetOptions; + DenseMap<MCSection *, const MCSymbolRefExpr *> SecToAlignSym; public: LoongArchAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit, @@ -45,6 +48,15 @@ public: uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const override; + // Return Size with extra Nop Bytes for alignment directive in code section. + bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF, + unsigned &Size) override; + + // Insert target specific fixup type for alignment directive in code section. + bool shouldInsertFixupForCodeAlign(MCAssembler &Asm, + const MCAsmLayout &Layout, + MCAlignFragment &AF) override; + bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, const MCSubtargetInfo *STI) override; @@ -80,6 +92,9 @@ public: std::unique_ptr<MCObjectTargetWriter> createObjectTargetWriter() const override; const MCTargetOptions &getTargetOptions() const { return TargetOptions; } + DenseMap<MCSection *, const MCSymbolRefExpr *> &getSecToAlignSym() { + return SecToAlignSym; + } }; } // end namespace llvm diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h index e827bae..0d19d2b 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h @@ -109,6 +109,8 @@ enum Fixups { fixup_loongarch_tls_gd_hi20, // Generate an R_LARCH_RELAX which indicates the linker may relax here. fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX, + // Generate an R_LARCH_ALIGN which indicates the linker may fixup align here. + fixup_loongarch_align = FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN, // 36-bit fixup corresponding to %call36(foo) for a pair instructions: // pcaddu18i+jirl. fixup_loongarch_call36 = FirstLiteralRelocationKind + ELF::R_LARCH_CALL36, |
