[llvm] [RISCV] Vendor Relocations for Xqci extension (PR #135400)

Sam Elliott via llvm-commits llvm-commits at lists.llvm.org
Fri May 16 18:45:36 PDT 2025


https://github.com/lenary updated https://github.com/llvm/llvm-project/pull/135400

>From df04e3169e6dc7f38376f713892e4040b5fa7052 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Fri, 16 May 2025 16:23:49 -0700
Subject: [PATCH 1/2] [RISCV] Vendor Relocations for Xqci extension

This patch implements vendor relocation support for RISC-V, starting
with the Xqci extensions.

This is done by re-organising `RISCVAsmBackend::evaluateTargetFixup`, to
also handle emitting the vendor relocation when the fixup is unresolved.

An extra parameter `bool RecordReloc` is added to `evaluateTargetFixup`,
so that the relocation is only emitted when it should be, as
`evaluateTargetFixup` works the same way.

This adds tests showing resolveable and unresolvable symbols for the
xqci fixups (some of which are absolute and some of which are
pc-relative), including tests when relaxation is enabled which forces
relocations that might otherwise not be needed.

Co-authored-by: Sudharsan Veeravalli <quic_svs at quicinc.com>
---
 llvm/include/llvm/MC/MCAsmBackend.h           |   4 +-
 llvm/lib/MC/MCAssembler.cpp                   |   4 +-
 .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp    | 171 ++++++++++++++----
 .../RISCV/MCTargetDesc/RISCVAsmBackend.h      |  15 +-
 llvm/test/MC/RISCV/xqcibi-relocations-relax.s |  38 ++++
 llvm/test/MC/RISCV/xqcibi-relocations.s       |  90 ++++++---
 llvm/test/MC/RISCV/xqcilb-relocations-relax.s |  38 ++++
 llvm/test/MC/RISCV/xqcilb-relocations.s       |  92 ++++++----
 llvm/test/MC/RISCV/xqcili-relocations-relax.s |  51 ++++++
 llvm/test/MC/RISCV/xqcili-relocations.s       | 106 +++++++----
 10 files changed, 472 insertions(+), 137 deletions(-)
 create mode 100644 llvm/test/MC/RISCV/xqcibi-relocations-relax.s
 create mode 100644 llvm/test/MC/RISCV/xqcilb-relocations-relax.s
 create mode 100644 llvm/test/MC/RISCV/xqcili-relocations-relax.s

diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h
index 691988ae1f1df..02a001b2a6ab1 100644
--- a/llvm/include/llvm/MC/MCAsmBackend.h
+++ b/llvm/include/llvm/MC/MCAsmBackend.h
@@ -111,8 +111,8 @@ class MCAsmBackend {
 
   virtual bool evaluateTargetFixup(const MCAssembler &Asm, const MCFixup &Fixup,
                                    const MCFragment *DF, const MCValue &Target,
-                                   const MCSubtargetInfo *STI,
-                                   uint64_t &Value) {
+                                   const MCSubtargetInfo *STI, uint64_t &Value,
+                                   bool RecordReloc) {
     llvm_unreachable("Need to implement hook if target has custom fixups");
   }
 
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
index 73c3a3a00b5c6..2c046f6ad4bee 100644
--- a/llvm/lib/MC/MCAssembler.cpp
+++ b/llvm/lib/MC/MCAssembler.cpp
@@ -158,8 +158,8 @@ bool MCAssembler::evaluateFixup(const MCFixup &Fixup, const MCFragment *DF,
   bool IsResolved = false;
   unsigned FixupFlags = getBackend().getFixupKindInfo(Fixup.getKind()).Flags;
   if (FixupFlags & MCFixupKindInfo::FKF_IsTarget) {
-    IsResolved =
-        getBackend().evaluateTargetFixup(*this, Fixup, DF, Target, STI, Value);
+    IsResolved = getBackend().evaluateTargetFixup(*this, Fixup, DF, Target, STI,
+                                                  Value, RecordReloc);
   } else {
     const MCSymbol *Add = Target.getAddSym();
     const MCSymbol *Sub = Target.getSubSym();
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index d8cfeb07e52b6..d45fb8efcc8f1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVAsmBackend.h"
+#include "RISCVFixupKinds.h"
 #include "RISCVMCExpr.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/MC/MCAsmInfo.h"
@@ -37,7 +38,7 @@ static cl::opt<bool> ULEB128Reloc(
 RISCVAsmBackend::RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI,
                                  bool Is64Bit, const MCTargetOptions &Options)
     : MCAsmBackend(llvm::endianness::little, ELF::R_RISCV_RELAX), STI(STI),
-      OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options) {
+      OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options), VendorSymbols() {
   RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits());
 }
 
@@ -84,10 +85,12 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
       {"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
       {"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
 
-      {"fixup_riscv_qc_e_branch", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
-      {"fixup_riscv_qc_e_32", 16, 32, 0},
-      {"fixup_riscv_qc_abs20_u", 12, 20, 0},
-      {"fixup_riscv_qc_e_jump_plt", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
+      {"fixup_riscv_qc_e_branch", 0, 48,
+       MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget},
+      {"fixup_riscv_qc_e_32", 16, 32, MCFixupKindInfo::FKF_IsTarget},
+      {"fixup_riscv_qc_abs20_u", 12, 20, MCFixupKindInfo::FKF_IsTarget},
+      {"fixup_riscv_qc_e_jump_plt", 0, 48,
+       MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget},
   };
   static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
                 "Not all fixup kinds added to Infos array");
@@ -571,37 +574,10 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
   }
 }
 
-bool RISCVAsmBackend::evaluateTargetFixup(
-    const MCAssembler &Asm, const MCFixup &Fixup, const MCFragment *DF,
-    const MCValue &Target, const MCSubtargetInfo *STI, uint64_t &Value) {
-  const MCFixup *AUIPCFixup;
-  const MCFragment *AUIPCDF;
-  MCValue AUIPCTarget;
-  switch (Fixup.getTargetKind()) {
-  default:
-    llvm_unreachable("Unexpected fixup kind!");
-  case RISCV::fixup_riscv_pcrel_hi20:
-    AUIPCFixup = &Fixup;
-    AUIPCDF = DF;
-    AUIPCTarget = Target;
-    break;
-  case RISCV::fixup_riscv_pcrel_lo12_i:
-  case RISCV::fixup_riscv_pcrel_lo12_s: {
-    AUIPCFixup = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
-    if (!AUIPCFixup) {
-      Asm.getContext().reportError(Fixup.getLoc(),
-                                   "could not find corresponding %pcrel_hi");
-      return true;
-    }
-
-    // MCAssembler::evaluateFixup will emit an error for this case when it sees
-    // the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo.
-    const MCExpr *AUIPCExpr = AUIPCFixup->getValue();
-    if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Asm))
-      return true;
-    break;
-  }
-  }
+static bool evaluateAUIPCFixup(const MCAssembler &Asm,
+                               const MCFixup *AUIPCFixup,
+                               const MCFragment *AUIPCDF, MCValue AUIPCTarget,
+                               uint64_t &Value) {
 
   if (!AUIPCTarget.getAddSym())
     return false;
@@ -622,6 +598,129 @@ bool RISCVAsmBackend::evaluateTargetFixup(
   return AUIPCFixup->getTargetKind() == RISCV::fixup_riscv_pcrel_hi20;
 }
 
+StringRef
+RISCVAsmBackend::getVendorSymbolNameForRelocation(unsigned FixupKind) const {
+  switch (FixupKind) {
+  case RISCV::fixup_riscv_qc_e_branch:
+  case RISCV::fixup_riscv_qc_abs20_u:
+  case RISCV::fixup_riscv_qc_e_32:
+  case RISCV::fixup_riscv_qc_e_jump_plt:
+    return "QUALCOMM";
+  }
+
+  return "";
+}
+
+bool RISCVAsmBackend::evaluateVendorFixup(const MCAssembler &Asm,
+                                          const MCFixup &Fixup,
+                                          const MCFragment *DF,
+                                          const MCValue &Target,
+                                          const MCSubtargetInfo *STI,
+                                          uint64_t &Value, bool RecordReloc) {
+  // This is a copy of the target-independent branch of
+  // MCAssembler::evaluateFixup
+  bool IsResolved = false;
+  const MCSymbol *Add = Target.getAddSym();
+  const MCSymbol *Sub = Target.getSubSym();
+  Value = Target.getConstant();
+  if (Add && Add->isDefined())
+    Value += Asm.getSymbolOffset(*Add);
+  if (Sub && Sub->isDefined())
+    Value -= Asm.getSymbolOffset(*Sub);
+
+  unsigned FixupFlags = getFixupKindInfo(Fixup.getKind()).Flags;
+  if (FixupFlags & MCFixupKindInfo::FKF_IsPCRel) {
+    Value -= Asm.getFragmentOffset(*DF) + Fixup.getOffset();
+
+    if (Add && !Sub && !Add->isUndefined() && !Add->isAbsolute()) {
+      IsResolved = Asm.getWriter().isSymbolRefDifferenceFullyResolvedImpl(
+          Asm, *Add, *DF, false, true);
+    }
+  } else {
+    IsResolved = Target.isAbsolute();
+  }
+  // End copy of MCAssembler::evaluateFixup
+
+  // If we failed to resolve, or we need to force relocations (relaxations), then
+  // record a vendor relocation too.
+  if ((!IsResolved || shouldForceRelocation(Asm, Fixup, Target, STI)) &&
+      RecordReloc) {
+    // Here are the additions to emit a vendor relocation for fixups that need
+    // them.
+    MCContext &Ctx = Asm.getContext();
+
+    StringRef VendorIdentifier =
+        getVendorSymbolNameForRelocation(Fixup.getTargetKind());
+
+    auto It = VendorSymbols.find(VendorIdentifier);
+    if (It == VendorSymbols.end()) {
+      auto *VendorSymbol =
+          cast<MCSymbolELF>(Ctx.createLocalSymbol(VendorIdentifier));
+
+      // Vendor Symbols are Absolute, Local, NOTYPE.
+      VendorSymbol->setType(ELF::STT_NOTYPE);
+      VendorSymbol->setBinding(ELF::STB_LOCAL);
+      VendorSymbol->setVariableValue(MCConstantExpr::create(0, Ctx));
+      const_cast<MCAssembler &>(Asm).registerSymbol(*VendorSymbol);
+
+      It = VendorSymbols.try_emplace(VendorIdentifier, VendorSymbol).first;
+    }
+
+    MCSymbolELF *VendorSymbol = It->getValue();
+    const MCExpr *VendorExpr = MCSymbolRefExpr::create(VendorSymbol, Ctx);
+    MCFixup VendorFixup =
+        MCFixup::create(Fixup.getOffset(), VendorExpr,
+                        FirstLiteralRelocationKind + ELF::R_RISCV_VENDOR);
+    // Explicitly create MCValue so that the absolute symbol is not evaluated to
+    // a constant.
+    MCValue VendorTarget = MCValue::get(VendorSymbol);
+    uint64_t VendorValue;
+    Asm.getWriter().recordRelocation(const_cast<MCAssembler &>(Asm), DF,
+                                     VendorFixup, VendorTarget, VendorValue);
+  }
+
+  return IsResolved;
+}
+
+bool RISCVAsmBackend::evaluateTargetFixup(const MCAssembler &Asm,
+                                          const MCFixup &Fixup,
+                                          const MCFragment *DF,
+                                          const MCValue &Target,
+                                          const MCSubtargetInfo *STI,
+                                          uint64_t &Value, bool RecordReloc) {
+  switch (Fixup.getTargetKind()) {
+  case RISCV::fixup_riscv_pcrel_hi20:
+    return evaluateAUIPCFixup(Asm, &Fixup, DF, Target, Value);
+  case RISCV::fixup_riscv_pcrel_lo12_i:
+  case RISCV::fixup_riscv_pcrel_lo12_s: {
+    const MCFragment *AUIPCDF;
+    const MCFixup *AUIPCFixup =
+        cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
+    if (!AUIPCFixup) {
+      Asm.getContext().reportError(Fixup.getLoc(),
+                                   "could not find corresponding %pcrel_hi");
+      return true;
+    }
+
+    // MCAssembler::evaluateFixup will emit an error for this case when it sees
+    // the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo.
+    const MCExpr *AUIPCExpr = AUIPCFixup->getValue();
+    MCValue AUIPCTarget;
+    if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Asm))
+      return true;
+
+    return evaluateAUIPCFixup(Asm, AUIPCFixup, AUIPCDF, AUIPCTarget, Value);
+  }
+  case RISCV::fixup_riscv_qc_e_branch:
+  case RISCV::fixup_riscv_qc_abs20_u:
+  case RISCV::fixup_riscv_qc_e_32:
+  case RISCV::fixup_riscv_qc_e_jump_plt:
+    return evaluateVendorFixup(Asm, Fixup, DF, Target, STI, Value, RecordReloc);
+  }
+
+  llvm_unreachable("Unexpected target fixup kind!");
+}
+
 bool RISCVAsmBackend::handleAddSubRelocations(const MCAssembler &Asm,
                                               const MCFragment &F,
                                               const MCFixup &Fixup,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
index 5db55ad0b8567..9ef2adb06a1ef 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
@@ -12,6 +12,7 @@
 #include "MCTargetDesc/RISCVBaseInfo.h"
 #include "MCTargetDesc/RISCVFixupKinds.h"
 #include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCFixupKindInfo.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -20,6 +21,7 @@ namespace llvm {
 class MCAssembler;
 class MCObjectTargetWriter;
 class raw_ostream;
+class MCSymbolELF;
 
 class RISCVAsmBackend : public MCAsmBackend {
   const MCSubtargetInfo &STI;
@@ -28,6 +30,8 @@ class RISCVAsmBackend : public MCAsmBackend {
   bool ForceRelocs = false;
   const MCTargetOptions &TargetOptions;
 
+  StringMap<MCSymbolELF *> VendorSymbols;
+
 public:
   RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
                   const MCTargetOptions &Options);
@@ -45,8 +49,15 @@ class RISCVAsmBackend : public MCAsmBackend {
 
   bool evaluateTargetFixup(const MCAssembler &Asm, const MCFixup &Fixup,
                            const MCFragment *DF, const MCValue &Target,
-                           const MCSubtargetInfo *STI,
-                           uint64_t &Value) override;
+                           const MCSubtargetInfo *STI, uint64_t &Value,
+                           bool RecordReloc) override;
+
+  bool evaluateVendorFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                           const MCFragment *DF, const MCValue &Target,
+                           const MCSubtargetInfo *STI, uint64_t &Value,
+                           bool RecordReloc);
+
+  StringRef getVendorSymbolNameForRelocation(unsigned TargetFixupKind) const;
 
   bool handleAddSubRelocations(const MCAssembler &Asm, const MCFragment &F,
                                const MCFixup &Fixup, const MCValue &Target,
diff --git a/llvm/test/MC/RISCV/xqcibi-relocations-relax.s b/llvm/test/MC/RISCV/xqcibi-relocations-relax.s
new file mode 100644
index 0000000000000..ae1398499cba4
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcibi-relocations-relax.s
@@ -0,0 +1,38 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
+# RUN:     | FileCheck -check-prefix=ASM %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
+# RUN:     -filetype=obj -o - \
+# RUN:     | llvm-objdump -dr --mattr=+experimental-xqcibi - \
+# RUN:     | FileCheck -check-prefix=OBJ %s
+
+## This test checks that we emit the right relocations for Xqcibi
+## relative branches, when relaxations are enabled. These require a relocation.
+## The QC.E.B<op>I instructions also require a vendor relocation.
+
+# These are required to turn off autocompression, but to re-enable
+# linker relaxation.
+.option exact
+.option relax
+
+# ASM-LABEL: this_section:
+# OBJ-LABEL: <this_section>:
+this_section:
+
+# ASM: qc.bnei t2, 11, same_section
+# OBJ: qc.bnei t2, 0xb, 0x0 <this_section>
+# OBJ-NEXT: R_RISCV_BRANCH same_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.bnei t2, 11, same_section
+
+# ASM: qc.e.bgeui s1, 21, same_section
+# OBJ: qc.e.bgeui s1, 0x15, 0x4 <this_section+0x4>
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM193 same_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.bgeui s1, 21, same_section
+
+# ASM-LABEL: same_section:
+# OBJ-LABEL: <same_section>:
+same_section:
+nop
+
diff --git a/llvm/test/MC/RISCV/xqcibi-relocations.s b/llvm/test/MC/RISCV/xqcibi-relocations.s
index 054a890a4b5e5..6d2349e43eabe 100644
--- a/llvm/test/MC/RISCV/xqcibi-relocations.s
+++ b/llvm/test/MC/RISCV/xqcibi-relocations.s
@@ -1,38 +1,70 @@
-# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s -show-encoding \
-# RUN:     | FileCheck -check-prefix=INSTR %s
-# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcibi %s -o %t.o
-# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
+# RUN:     | FileCheck -check-prefix=ASM %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
+# RUN:     -filetype=obj -o - \
+# RUN:     | llvm-objdump -dr --mattr=+experimental-xqcibi - \
+# RUN:     | FileCheck -check-prefix=OBJ %s
 
-# Check prefixes:
-# RELOC - Check the relocation in the object.
-# INSTR - Check the instruction is handled properly by the ASMPrinter.
+## This test checks that we emit the right relocations for Xqcibi
+## relative branches. These can be resolved within the same section
+## (when relaxations are disabled) but otherwise require a relocation.
+## The QC.E.B<op>I instructions also require a vendor relocation.
 
-.text
+# This is required so that the conditional branches requiring relocations
+# are not converted into inverted branches with long jumps by the assembler.
+.option exact
 
-# Since foo is undefined, this will be relaxed to (qc.beqi + jal)
-qc.bnei x6, 10, foo
-# RELOC: R_RISCV_JAL foo 0x0
-# INSTR: qc.bnei t1, 10, foo
+# ASM-LABEL: this_section:
+# OBJ-LABEL: <this_section>:
+this_section:
 
-# Since foo is undefined, this will be relaxed to (qc.e.bltui + jal)
-qc.e.bgeui x8, 12, foo
-# RELOC: R_RISCV_JAL foo 0x0
-# INSTR: qc.e.bgeui s0, 12, foo
+# ASM: qc.bnei t1, 10, undef
+# OBJ: qc.bnei t1, 0xa, 0x0 <this_section>
+# OBJ-NEXT: R_RISCV_BRANCH undef{{$}}
+# OBJ-NOT: R_RISCV
+qc.bnei t1, 10, undef
 
-# Check that a label in a different section is handled similar to an undefined
-# symbol and gets relaxed to (qc.e.bgeui + jal)
-qc.e.bltui x4, 9, .bar
-# RELOC: R_RISCV_JAL .bar 0x0
-# INSTR: qc.e.bltui tp, 9, .bar
+# ASM: qc.e.bgeui s0, 20, undef
+# OBJ: qc.e.bgeui s0, 0x14, 0x4 <this_section+0x4>
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM193 undef{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.bgeui s0, 20, undef
 
-# Check that branches to a defined symbol are handled correctly
-qc.e.beqi x7, 8, .L1
-# INSTR: qc.e.beqi t2, 8, .L1
 
-.L1:
-  ret
+# ASM: qc.bnei t2, 11, same_section
+# OBJ: qc.bnei t2, 0xb, 0x1e <same_section>
+# OBJ-NOT: R_RISCV
+qc.bnei t2, 11, same_section
 
-.section .t2
+# ASM: qc.e.bgeui s1, 21, same_section
+# OBJ: qc.e.bgeui s1, 0x15, 0x1e <same_section>
+# OBJ-NOT: R_RISCV
+qc.e.bgeui s1, 21, same_section
 
-.bar:
-  ret
+
+# ASM: qc.bnei t3, 12, other_section
+# OBJ: qc.bnei t3, 0xc, 0x14 <this_section+0x14>
+# OBJ-NEXT: R_RISCV_BRANCH other_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.bnei t3, 12, other_section
+
+# ASM: qc.e.bgeui s2, 22, other_section
+# OBJ: qc.e.bgeui s2, 0x16, 0x18 <this_section+0x18>
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM193 other_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.bgeui s2, 22, other_section
+
+
+# ASM-LABEL: same_section:
+# OBJ-LABEL: <same_section>:
+same_section:
+  nop
+
+.section .text.second, "ax", @progbits
+
+# ASM-LABEL: other_section:
+# OBJ-LABEL: <other_section>:
+other_section:
+  nop
diff --git a/llvm/test/MC/RISCV/xqcilb-relocations-relax.s b/llvm/test/MC/RISCV/xqcilb-relocations-relax.s
new file mode 100644
index 0000000000000..7de048d78c8e1
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcilb-relocations-relax.s
@@ -0,0 +1,38 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s \
+# RUN:     | FileCheck -check-prefix=ASM %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s \
+# RUN:     -filetype=obj -o - \
+# RUN:     | llvm-objdump -dr --mattr=+experimental-xqcilb - \
+# RUN:     | FileCheck -check-prefix=OBJ %s
+
+## This test checks that we emit the right relocations for Xqcilb
+## relative jumps when relocations are enabled. These require a
+## vendor-specific relocation pair.
+
+# These are required to turn off autocompression, but to re-enable
+# linker relaxation.
+.option exact
+.option relax
+
+# ASM-LABEL: this_section:
+# OBJ-LABEL: <this_section>:
+this_section:
+
+# ASM: qc.e.j same_section
+# OBJ: qc.e.j 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM195 same_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.j same_section
+
+# ASM: qc.e.jal same_section
+# OBJ: qc.e.jal 0x6
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM195 same_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.jal same_section
+
+# ASM-LABEL: same_section:
+# OBJ-LABEL: <same_section>:
+same_section:
+nop
diff --git a/llvm/test/MC/RISCV/xqcilb-relocations.s b/llvm/test/MC/RISCV/xqcilb-relocations.s
index 0a5b788a110da..97cdca3d53944 100644
--- a/llvm/test/MC/RISCV/xqcilb-relocations.s
+++ b/llvm/test/MC/RISCV/xqcilb-relocations.s
@@ -1,46 +1,72 @@
-# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s -show-encoding \
-# RUN:     | FileCheck -check-prefix=INSTR %s
-# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcilb %s -o %t.o
-# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s \
+# RUN:     | FileCheck -check-prefix=ASM %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s \
+# RUN:     -filetype=obj -o - \
+# RUN:     | llvm-objdump -dr --mattr=+experimental-xqcilb - \
+# RUN:     | FileCheck -check-prefix=OBJ %s
 
-# Check prefixes:
-# RELOC - Check the relocation in the object.
-# INSTR - Check the instruction is handled properly by the ASMPrinter.
-
-.text
+## This test checks that we emit the right relocations for Xqcilb
+## relative jumps. These can be resolved within the same section
+## (when relaxations are disabled) but otherwise require a
+## vendor-specific relocation pair.
 
+# This is required so that the conditional jumps are not compressed
+# by the assembler
 .option exact
 
-qc.e.j foo
-# RELOC: R_RISCV_CUSTOM195 foo 0x0
-# INSTR: qc.e.j foo
+# ASM-LABEL: this_section:
+# OBJ-LABEL: <this_section>:
+this_section:
+
+# ASM: qc.e.j undef
+# OBJ: qc.e.j 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.j undef
+
+# ASM: qc.e.jal undef
+# OBJ: qc.e.jal 0x6
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.jal undef
+
 
-qc.e.jal foo
-# RELOC: R_RISCV_CUSTOM195 foo 0x0
-# INSTR: qc.e.jal foo
+# ASM: qc.e.j same_section
+# OBJ: qc.e.j 0x24
+# OBJ-NOT: R_RISCV
+qc.e.j same_section
 
-# Check that a label in a different section is handled similar to an undefined symbol
-qc.e.j .bar
-# RELOC: R_RISCV_CUSTOM195 .bar 0x0
-# INSTR: qc.e.j .bar
+# ASM: qc.e.jal same_section
+# OBJ: qc.e.jal 0x24
+# OBJ-NOT: R_RISCV
+qc.e.jal same_section
 
-qc.e.jal .bar
-# RELOC: R_RISCV_CUSTOM195 .bar 0x0
-# INSTR: qc.e.jal .bar
 
-# Check that jumps to a defined symbol are handled correctly
-qc.e.j .L1
-# INSTR:qc.e.j .L1
+# ASM: qc.e.j other_section
+# OBJ: qc.e.j 0x18
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM195 other_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.j other_section
 
-qc.e.jal .L1
-# INSTR:qc.e.jal .L1
+# ASM: qc.e.jal other_section
+# OBJ: qc.e.jal 0x1e
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM195 other_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.jal other_section
 
-.option noexact
 
-.L1:
-  ret
+# ASM-LABEL: same_section:
+# OBJ-LABEL: <same_section>:
+same_section:
+  nop
 
-.section .t2
+.section .text.other, "ax", @progbits
 
-.bar:
-  ret
+# ASM-LABEL: other_section:
+# OBJ-LABEL: <other_section>:
+other_section:
+  nop
diff --git a/llvm/test/MC/RISCV/xqcili-relocations-relax.s b/llvm/test/MC/RISCV/xqcili-relocations-relax.s
new file mode 100644
index 0000000000000..ade3d4fb661be
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcili-relocations-relax.s
@@ -0,0 +1,51 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcili %s \
+# RUN:     | FileCheck -check-prefix=ASM %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcili %s \
+# RUN:     -filetype=obj -o - \
+# RUN:     | llvm-objdump -dr --mattr=+experimental-xqcili - \
+# RUN:     | FileCheck -check-prefix=OBJ %s
+
+## This test checks that we emit the right relocations for Xqcili
+## immediates, when relaxations are enabled. These don't require
+## relocations, but the behaviour is different depending on whether
+## there is a target-specific symbol specifier or not (there is 
+## one for `qc.li`).
+
+## It might be more obvious if both of these did the same thing,
+## either both emitting relocations, or both not emitting relocations.
+
+# These are required to turn off autocompression, but to re-enable
+# linker relaxation.
+.option exact
+.option relax
+
+.set abs_symbol, 0x0
+
+# ASM-LABEL: this_section:
+# OBJ-LABEL: <this_section>:
+this_section:
+
+
+# ASM: qc.li a1, %qc.abs20(0)
+# OBJ: qc.li a1, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM192 *ABS*{{$}}
+# OBJ-NOT: R_RISCV
+qc.li a1, %qc.abs20(abs_symbol)
+
+# ASM: qc.e.li s1, 0
+# OBJ: qc.e.li s1, 0x0
+# OBJ-NOT: R_RISCV
+qc.e.li s1, abs_symbol
+
+# ASM-LABEL: same_section:
+# OBJ-LABEL: <same_section>:
+same_section:
+  nop
+
+.section .text.other, "ax", @progbits
+
+# ASM-LABEL: other_section:
+# OBJ-LABEL: <other_section>:
+other_section:
+  nop
diff --git a/llvm/test/MC/RISCV/xqcili-relocations.s b/llvm/test/MC/RISCV/xqcili-relocations.s
index 9c709e68334cd..3e7d3487b65f8 100644
--- a/llvm/test/MC/RISCV/xqcili-relocations.s
+++ b/llvm/test/MC/RISCV/xqcili-relocations.s
@@ -1,46 +1,86 @@
-# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcili %s -show-encoding \
-# RUN:     | FileCheck -check-prefix=INSTR %s
-# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcili %s -o %t.o
-# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcili %s \
+# RUN:     | FileCheck -check-prefix=ASM %s
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcili %s \
+# RUN:     -filetype=obj -o - \
+# RUN:     | llvm-objdump -dr --mattr=+experimental-xqcili - \
+# RUN:     | FileCheck -check-prefix=OBJ %s
 
-# Check prefixes:
-# RELOC - Check the relocation in the object.
-# INSTR - Check the instruction is handled properly by the ASMPrinter.
-
-.text
+## This test checks that we emit the right relocations for Xqcili
+## immediates. These always require a relocation pair, unless the
+## target is absolute.
 
+# This is required so that the conditional branches requiring relocations
+# are not converted into inverted branches with long jumps by the assembler.
 .option exact
 
-qc.li x4, %qc.abs20(foo)
-# RELOC: R_RISCV_CUSTOM192 foo 0x0
-# INSTR: qc.li tp, %qc.abs20(foo)
+.set abs_symbol, 0x0
+
+# ASM-LABEL: this_section:
+# OBJ-LABEL: <this_section>:
+this_section:
+
+# ASM: qc.li a0, %qc.abs20(undef)
+# OBJ: qc.li a0, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM192 undef{{$}}
+# OBJ-NOT: R_RISCV
+qc.li a0, %qc.abs20(undef)
+
+# ASM: qc.e.li s0, undef
+# OBJ: qc.e.li s0, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM194 undef{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.li s0, undef
+
+
+# ASM: qc.li a1, %qc.abs20(0)
+# OBJ: qc.li a1, 0x0
+# OBJ-NOT: R_RISCV
+qc.li a1, %qc.abs20(abs_symbol)
 
-qc.e.li x5, foo
-# RELOC: R_RISCV_CUSTOM194 foo 0x0
-# INSTR: qc.e.li t0, foo
+# ASM: qc.e.li s1, 0
+# OBJ: qc.e.li s1, 0x0
+# OBJ-NOT: R_RISCV
+qc.e.li s1, abs_symbol
 
-# Check that a label in a different section is handled similar to an undefined symbol
-qc.li x9, %qc.abs20(.bar)
-# RELOC: R_RISCV_CUSTOM192 .bar 0x0
-# INSTR: qc.li s1, %qc.abs20(.bar)
 
-qc.e.li x8, .bar
-# RELOC: R_RISCV_CUSTOM194 .bar 0x0
-# INSTR: qc.e.li s0, .bar
+# ASM: qc.li a2, %qc.abs20(same_section)
+# OBJ: qc.li a2, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM192 same_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.li a2, %qc.abs20(same_section)
 
-# Check that branches to a defined symbol are handled correctly
-qc.li x7, %qc.abs20(.L1)
-# INSTR: qc.li t2, %qc.abs20(.L1)
+# ASM: qc.e.li s2, same_section
+# OBJ: qc.e.li s2, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM194 same_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.li s2, same_section
 
-qc.e.li x6, .L1
-# INSTR: qc.e.li t1, .L1
+# ASM: qc.li a3, %qc.abs20(other_section)
+# OBJ: qc.li a3, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM192 other_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.li a3, %qc.abs20(other_section)
 
-.option noexact
+# ASM: qc.e.li s3, other_section
+# OBJ: qc.e.li s3, 0x0
+# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
+# OBJ-NEXT: R_RISCV_CUSTOM194 other_section{{$}}
+# OBJ-NOT: R_RISCV
+qc.e.li s3, other_section
 
-.L1:
-  ret
+# ASM-LABEL: same_section:
+# OBJ-LABEL: <same_section>:
+same_section:
+  nop
 
-.section .t2
+.section .text.other, "ax", @progbits
 
-.bar:
-  ret
+# ASM-LABEL: other_section:
+# OBJ-LABEL: <other_section>:
+other_section:
+  nop

>From 1e430858f26e0ce6786e31383accb1ab3c00b759 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Fri, 16 May 2025 18:45:28 -0700
Subject: [PATCH 2/2] clang-format

---
 llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index d45fb8efcc8f1..87aeacf28b7da 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -641,8 +641,8 @@ bool RISCVAsmBackend::evaluateVendorFixup(const MCAssembler &Asm,
   }
   // End copy of MCAssembler::evaluateFixup
 
-  // If we failed to resolve, or we need to force relocations (relaxations), then
-  // record a vendor relocation too.
+  // If we failed to resolve, or we need to force relocations (relaxations),
+  // then record a vendor relocation too.
   if ((!IsResolved || shouldForceRelocation(Asm, Fixup, Target, STI)) &&
       RecordReloc) {
     // Here are the additions to emit a vendor relocation for fixups that need



More information about the llvm-commits mailing list