From 6f135b13769c64a6942b4b232a350b6a6207f2b2 Mon Sep 17 00:00:00 2001
From: Jinyang He <hejinyang@loongson.cn>
Date: Thu, 16 Nov 2023 11:01:26 +0800
Subject: [PATCH 02/14] [LoongArch] Add relax feature and keep relocations
 (#72191)

Add relax feature. To support linker relocation, we should make
relocation with a symbol rather than section plus offset, and keep all
relocations with non-abs symbol.

(cherry picked from commit f5bfc833fcbf17a5876911783d1adaca7028d20c)
Change-Id: Ief38b480016175f2cc9939b74a84d9444559ffd6
---
 llvm/lib/Target/LoongArch/LoongArch.td        |  4 +++
 .../lib/Target/LoongArch/LoongArchSubtarget.h |  2 ++
 .../MCTargetDesc/LoongArchAsmBackend.cpp      |  5 +--
 .../MCTargetDesc/LoongArchELFObjectWriter.cpp | 18 ++++++++---
 .../MCTargetDesc/LoongArchMCTargetDesc.h      |  2 +-
 .../MC/LoongArch/Relocations/relax-attr.s     | 32 +++++++++++++++++++
 6 files changed, 55 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/MC/LoongArch/Relocations/relax-attr.s

diff --git a/llvm/lib/Target/LoongArch/LoongArch.td b/llvm/lib/Target/LoongArch/LoongArch.td
index 0675caa3b601..75b65fe69f26 100644
--- a/llvm/lib/Target/LoongArch/LoongArch.td
+++ b/llvm/lib/Target/LoongArch/LoongArch.td
@@ -102,6 +102,10 @@ def FeatureUAL
     : SubtargetFeature<"ual", "HasUAL", "true",
                        "Allow memory accesses to be unaligned">;
 
+def FeatureRelax
+    : SubtargetFeature<"relax", "HasLinkerRelax", "true",
+                       "Enable Linker relaxation">;
+
 //===----------------------------------------------------------------------===//
 // Registers, instruction descriptions ...
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/LoongArch/LoongArchSubtarget.h b/llvm/lib/Target/LoongArch/LoongArchSubtarget.h
index 0fbe23f2f62d..5c173675cca4 100644
--- a/llvm/lib/Target/LoongArch/LoongArchSubtarget.h
+++ b/llvm/lib/Target/LoongArch/LoongArchSubtarget.h
@@ -43,6 +43,7 @@ class LoongArchSubtarget : public LoongArchGenSubtargetInfo {
   bool HasLaGlobalWithAbs = false;
   bool HasLaLocalWithAbs = false;
   bool HasUAL = false;
+  bool HasLinkerRelax = false;
   unsigned GRLen = 32;
   MVT GRLenVT = MVT::i32;
   LoongArchABI::ABI TargetABI = LoongArchABI::ABI_Unknown;
@@ -100,6 +101,7 @@ public:
   bool hasLaGlobalWithAbs() const { return HasLaGlobalWithAbs; }
   bool hasLaLocalWithAbs() const { return HasLaLocalWithAbs; }
   bool hasUAL() const { return HasUAL; }
+  bool hasLinkerRelax() const { return HasLinkerRelax; }
   MVT getGRLenVT() const { return GRLenVT; }
   unsigned getGRLen() const { return GRLen; }
   LoongArchABI::ABI getTargetABI() const { return TargetABI; }
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
index ecb68ff401e9..aae3e544d326 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp
@@ -168,7 +168,7 @@ bool LoongArchAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
     return true;
   switch (Fixup.getTargetKind()) {
   default:
-    return false;
+    return STI.hasFeature(LoongArch::FeatureRelax);
   case FK_Data_1:
   case FK_Data_2:
   case FK_Data_4:
@@ -193,7 +193,8 @@ bool LoongArchAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
 
 std::unique_ptr<MCObjectTargetWriter>
 LoongArchAsmBackend::createObjectTargetWriter() const {
-  return createLoongArchELFObjectWriter(OSABI, Is64Bit);
+  return createLoongArchELFObjectWriter(
+      OSABI, Is64Bit, STI.hasFeature(LoongArch::FeatureRelax));
 }
 
 MCAsmBackend *llvm::createLoongArchAsmBackend(const Target &T,
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
index a6b9c0652639..e60b9c2cfd97 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
@@ -20,19 +20,27 @@ using namespace llvm;
 namespace {
 class LoongArchELFObjectWriter : public MCELFObjectTargetWriter {
 public:
-  LoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit);
+  LoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit, bool EnableRelax);
 
   ~LoongArchELFObjectWriter() override;
 
+  bool needsRelocateWithSymbol(const MCSymbol &Sym,
+                               unsigned Type) const override {
+    return EnableRelax;
+  }
+
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
+  bool EnableRelax;
 };
 } // end namespace
 
-LoongArchELFObjectWriter::LoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit)
+LoongArchELFObjectWriter::LoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit,
+                                                   bool EnableRelax)
     : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_LOONGARCH,
-                              /*HasRelocationAddend*/ true) {}
+                              /*HasRelocationAddend=*/true),
+      EnableRelax(EnableRelax) {}
 
 LoongArchELFObjectWriter::~LoongArchELFObjectWriter() {}
 
@@ -87,6 +95,6 @@ unsigned LoongArchELFObjectWriter::getRelocType(MCContext &Ctx,
 }
 
 std::unique_ptr<MCObjectTargetWriter>
-llvm::createLoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit) {
-  return std::make_unique<LoongArchELFObjectWriter>(OSABI, Is64Bit);
+llvm::createLoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit, bool Relax) {
+  return std::make_unique<LoongArchELFObjectWriter>(OSABI, Is64Bit, Relax);
 }
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h
index ab35a0096c8a..bb05baa9b717 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.h
@@ -36,7 +36,7 @@ MCAsmBackend *createLoongArchAsmBackend(const Target &T,
                                         const MCTargetOptions &Options);
 
 std::unique_ptr<MCObjectTargetWriter>
-createLoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit);
+createLoongArchELFObjectWriter(uint8_t OSABI, bool Is64Bit, bool Relax);
 
 } // end namespace llvm
 
diff --git a/llvm/test/MC/LoongArch/Relocations/relax-attr.s b/llvm/test/MC/LoongArch/Relocations/relax-attr.s
new file mode 100644
index 000000000000..b1e648d850bb
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Relocations/relax-attr.s
@@ -0,0 +1,32 @@
+# 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
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.data {
+# CHECK-NEXT:     0x0 R_LARCH_64 .text 0x4
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECKR:      Relocations [
+# CHECKR-NEXT:   Section ({{.*}}) .rela.text {
+# CHECKR-NEXT:     0x8 R_LARCH_B21 .L1 0x0
+# CHECKR-NEXT:     0xC R_LARCH_B16 .L1 0x0
+# CHECKR-NEXT:     0x10 R_LARCH_B26 .L1 0x0
+# CHECKR-NEXT:   }
+# CHECKR-NEXT:   Section ({{.*}}) .rela.data {
+# CHECKR-NEXT:     0x0 R_LARCH_64 .L1 0x0
+# CHECKR-NEXT:   }
+# CHECKR-NEXT: ]
+
+.text
+  nop
+.L1:
+  nop
+  beqz $a0, .L1
+  blt  $a0, $a1, .L1
+  b    .L1
+
+.data
+.dword .L1
-- 
2.20.1

