[llvm] [LoongArch] Insert nops and emit align reloc when handle alignment directive (PR #72962)

Jinyang He via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 20 23:05:11 PST 2023


https://github.com/MQ-mengqing created https://github.com/llvm/llvm-project/pull/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.

>From 8e63c73c919767c0cce3bd20bc517d14ed9852da Mon Sep 17 00:00:00 2001
From: Jinyang He <hejinyang at loongson.cn>
Date: Thu, 16 Nov 2023 15:42:40 +0800
Subject: [PATCH] [LoongArch] Insert nops and emit align reloc when handle
 alignment directive

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.
---
 .../MCTargetDesc/LoongArchAsmBackend.cpp      | 48 +++++++++++++++++++
 .../MCTargetDesc/LoongArchAsmBackend.h        |  9 ++++
 .../MCTargetDesc/LoongArchFixupKinds.h        |  4 +-
 .../MC/LoongArch/Relocations/relax-align.s    | 28 +++++++++++
 4 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/MC/LoongArch/Relocations/relax-align.s

diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
index a35916d2ad2197d..6625ad6bc94d188 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
@@ -160,6 +160,54 @@ 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.
+  const MCSubtargetInfo *STI = AF.getSubtargetInfo();
+  if (!STI->hasFeature(LoongArch::FeatureRelax))
+    return false;
+
+  const unsigned MinNopLen = 4;
+  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.
+bool LoongArchAsmBackend::shouldInsertFixupForCodeAlign(
+    MCAssembler &Asm, const MCAsmLayout &Layout, MCAlignFragment &AF) {
+  // Insert the fixup only when linker relaxation enabled.
+  const MCSubtargetInfo *STI = AF.getSubtargetInfo();
+  if (!STI->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;
+
+  const MCExpr *Dummy = MCConstantExpr::create(0, Asm.getContext());
+  // Create fixup_loongarch_align fixup.
+  MCFixup Fixup = MCFixup::create(
+      0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_align), SMLoc());
+
+  uint64_t FixedValue = 0;
+  MCValue NopBytes = MCValue::get(Count);
+
+  Asm.getWriter().recordRelocation(Asm, Layout, &AF, Fixup, NopBytes,
+                                   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 f840f9fa2b6a007..1f4743f34dad2a7 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h
@@ -40,6 +40,15 @@ class LoongArchAsmBackend : public MCAsmBackend {
                   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) override;
 
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
index ba2d6718cdf9a27..8d773b649107ed6 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
@@ -106,7 +106,9 @@ enum Fixups {
   // 20-bit fixup corresponding to %gd_pc_hi20(foo) for instruction pcalau12i.
   fixup_loongarch_tls_gd_pc_hi20,
   // 20-bit fixup corresponding to %gd_hi20(foo) for instruction lu12i.w.
-  fixup_loongarch_tls_gd_hi20
+  fixup_loongarch_tls_gd_hi20,
+  // Generate an R_LARCH_ALIGN which indicates the linker may fixup align here.
+  fixup_loongarch_align = FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN
 };
 } // end namespace LoongArch
 } // end namespace llvm
diff --git a/llvm/test/MC/LoongArch/Relocations/relax-align.s b/llvm/test/MC/LoongArch/Relocations/relax-align.s
new file mode 100644
index 000000000000000..36524182777cb02
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Relocations/relax-align.s
@@ -0,0 +1,28 @@
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=CHECKR
+
+# CHECKR:       Relocations [
+# CHECKR-NEXT:    Section ({{.*}}) .rela.text {
+# CHECKR-NEXT:      0x0 R_LARCH_ALIGN - 0xC
+# CHECKR-NEXT:      0x10 R_LARCH_ALIGN - 0x1C
+# CHECKR-NEXT:      0x2C R_LARCH_ALIGN - 0xC
+# CHECKR-NEXT:    }
+# CHECKR-NEXT:  ]
+
+# CHECK:       Relocations [
+# CHECK-NEXT:  ]
+
+.text
+.p2align 4
+nop
+.p2align 5
+.p2align 4
+nop
+## Not emit R_LARCH_ALIGN if code alignment great than alignment directive.
+.p2align 2
+.p2align 1
+.p2align 0
+## Not emit R_LARCH_ALIGN if alignment directive with specific padding value.
+.p2align 4, 1



More information about the llvm-commits mailing list