[llvm] [BOLT][RISCV] Add RV32 bare-metal support (PR #193913)

Kito Cheng via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 24 01:01:22 PDT 2026


https://github.com/kito-cheng updated https://github.com/llvm/llvm-project/pull/193913

>From 073e91e0a2b2974ecbb9da9865705a90733f9fac Mon Sep 17 00:00:00 2001
From: Kito Cheng <kito.cheng at sifive.com>
Date: Fri, 24 Apr 2026 15:01:00 +0800
Subject: [PATCH] [BOLT][RISCV] Add RV32 bare-metal support

Enable BOLT to read, analyze, and rewrite 32-bit RISC-V (RV32) ELF
binaries. This lets us use BOLT as the core of our internal binary
analysis tooling for RV32 targets.

Scope is limited to bare-metal, statically linked, non-PIE programs.
PLT, GOT, dynamic relocations, TLS, and the instrumentation runtime
are out of scope for this change yet, and we plan to support those stuff
in future changes.
---
 bolt/include/bolt/Core/BinaryContext.h        |  5 ++-
 bolt/lib/Core/BinaryContext.cpp               |  5 ++-
 bolt/lib/Core/Relocation.cpp                  | 26 ++++++++++-
 bolt/lib/Rewrite/RewriteInstance.cpp          |  4 +-
 bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp  | 24 ++++++----
 bolt/test/RISCV/branch-no-secondary-entry.s   |  2 +-
 bolt/test/RISCV/fake-label-no-entry.c         |  2 +-
 bolt/test/RISCV/function-alignment.s          | 10 +++++
 bolt/test/RISCV/internal-func-reloc.s         |  4 ++
 bolt/test/RISCV/lit.local.cfg                 |  9 ++--
 bolt/test/RISCV/load-store.s                  |  2 +-
 bolt/test/RISCV/mapping-syms.s                |  3 ++
 bolt/test/RISCV/reloc-32.s                    | 23 ++++++++++
 bolt/test/RISCV/reloc-abs.s                   | 10 +++--
 bolt/test/RISCV/reloc-bb-split-rv32.s         | 45 +++++++++++++++++++
 bolt/test/RISCV/reloc-bb-split.s              |  2 +-
 bolt/test/RISCV/reloc-branch.s                |  6 ++-
 bolt/test/RISCV/reloc-call.s                  |  7 ++-
 bolt/test/RISCV/reloc-got.s                   |  2 +-
 bolt/test/RISCV/reloc-jal.s                   |  6 ++-
 bolt/test/RISCV/reloc-jt.s                    |  2 +-
 bolt/test/RISCV/reloc-label-diff.s            |  6 ++-
 bolt/test/RISCV/reloc-lohi-rv32.s             | 28 ++++++++++++
 bolt/test/RISCV/reloc-pcrel-rv32.s            | 27 +++++++++++
 bolt/test/RISCV/reloc-pcrel.s                 |  2 +-
 bolt/test/RISCV/reloc-rvc-branch.s            |  8 +++-
 bolt/test/RISCV/reloc-rvc-jump.s              |  8 +++-
 bolt/test/RISCV/reorder-blocks-reverse.s      |  6 ++-
 .../RISCV/validate-secondary-entry-point.s    |  2 +-
 29 files changed, 249 insertions(+), 37 deletions(-)
 create mode 100644 bolt/test/RISCV/reloc-32.s
 create mode 100644 bolt/test/RISCV/reloc-bb-split-rv32.s
 create mode 100644 bolt/test/RISCV/reloc-lohi-rv32.s
 create mode 100644 bolt/test/RISCV/reloc-pcrel-rv32.s

diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 30fcf072a6875..9c6b3007d33ad 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -894,7 +894,10 @@ class BinaryContext {
            TheTriple->getArch() == llvm::Triple::x86_64;
   }
 
-  bool isRISCV() const { return TheTriple->getArch() == llvm::Triple::riscv64; }
+  bool isRISCV() const {
+    return TheTriple->getArch() == llvm::Triple::riscv64 ||
+           TheTriple->getArch() == llvm::Triple::riscv32;
+  }
 
   // AArch64/RISC-V functions to check if symbol is used to delimit
   // code/data in .text. Code is marked by $x, data by $d.
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index 51fe292acae69..794c182a5d504 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -197,8 +197,9 @@ Expected<std::unique_ptr<BinaryContext>> BinaryContext::createBinaryContext(
     ArchName = "aarch64";
     FeaturesStr = "+all";
     break;
-  case llvm::Triple::riscv64: {
-    ArchName = "riscv64";
+  case llvm::Triple::riscv64:
+  case llvm::Triple::riscv32: {
+    ArchName = TheTriple.getArchName();
     if (!Features)
       return createFatalBOLTError("RISCV target needs SubtargetFeatures");
     // We rely on relaxation for some transformations (e.g., promoting all calls
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index f872db2cae0ce..8788482675a46 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -120,6 +120,7 @@ static bool isSupportedRISCV(uint32_t Type) {
   case ELF::R_RISCV_HI20:
   case ELF::R_RISCV_LO12_I:
   case ELF::R_RISCV_LO12_S:
+  case ELF::R_RISCV_32:
   case ELF::R_RISCV_64:
   case ELF::R_RISCV_TLS_GOT_HI20:
   case ELF::R_RISCV_TLS_GD_HI20:
@@ -231,6 +232,7 @@ static size_t getSizeForTypeRISCV(uint32_t Type) {
   case ELF::R_RISCV_HI20:
   case ELF::R_RISCV_LO12_I:
   case ELF::R_RISCV_LO12_S:
+  case ELF::R_RISCV_32:
     return 4;
   case ELF::R_RISCV_64:
   case ELF::R_RISCV_GOT_HI20:
@@ -327,6 +329,7 @@ static uint64_t canEncodeValueRISCV(uint32_t Type, uint64_t Value,
   switch (Type) {
   default:
     llvm_unreachable("unsupported relocation");
+  case ELF::R_RISCV_32:
   case ELF::R_RISCV_64:
     return true;
   }
@@ -336,6 +339,7 @@ static uint64_t encodeValueRISCV(uint32_t Type, uint64_t Value, uint64_t PC) {
   switch (Type) {
   default:
     llvm_unreachable("unsupported relocation");
+  case ELF::R_RISCV_32:
   case ELF::R_RISCV_64:
     break;
   }
@@ -519,6 +523,7 @@ static uint64_t extractValueRISCV(uint32_t Type, uint64_t Contents,
     return SignExtend64<8>(((Contents >> 2) & 0x1f) | ((Contents >> 5) & 0xe0));
   case ELF::R_RISCV_ADD32:
   case ELF::R_RISCV_SUB32:
+  case ELF::R_RISCV_32:
   case ELF::R_RISCV_64:
     return Contents;
   }
@@ -697,6 +702,7 @@ static bool isPCRelativeRISCV(uint32_t Type) {
   case ELF::R_RISCV_HI20:
   case ELF::R_RISCV_LO12_I:
   case ELF::R_RISCV_LO12_S:
+  case ELF::R_RISCV_32:
   case ELF::R_RISCV_64:
     return false;
   case ELF::R_RISCV_JAL:
@@ -723,6 +729,7 @@ bool Relocation::isSupported(uint32_t Type) {
   case Triple::aarch64:
     return isSupportedAArch64(Type);
   case Triple::riscv64:
+  case Triple::riscv32:
     return isSupportedRISCV(Type);
   case Triple::x86_64:
     return isSupportedX86(Type);
@@ -736,6 +743,7 @@ size_t Relocation::getSizeForType(uint32_t Type) {
   case Triple::aarch64:
     return getSizeForTypeAArch64(Type);
   case Triple::riscv64:
+  case Triple::riscv32:
     return getSizeForTypeRISCV(Type);
   case Triple::x86_64:
     return getSizeForTypeX86(Type);
@@ -749,6 +757,7 @@ bool Relocation::skipRelocationType(uint32_t Type) {
   case Triple::aarch64:
     return skipRelocationTypeAArch64(Type);
   case Triple::riscv64:
+  case Triple::riscv32:
     return skipRelocationTypeRISCV(Type);
   case Triple::x86_64:
     return skipRelocationTypeX86(Type);
@@ -762,6 +771,7 @@ uint64_t Relocation::encodeValue(uint32_t Type, uint64_t Value, uint64_t PC) {
   case Triple::aarch64:
     return encodeValueAArch64(Type, Value, PC);
   case Triple::riscv64:
+  case Triple::riscv32:
     return encodeValueRISCV(Type, Value, PC);
   case Triple::x86_64:
     return encodeValueX86(Type, Value, PC);
@@ -775,6 +785,7 @@ bool Relocation::canEncodeValue(uint32_t Type, uint64_t Value, uint64_t PC) {
   case Triple::aarch64:
     return canEncodeValueAArch64(Type, Value, PC);
   case Triple::riscv64:
+  case Triple::riscv32:
     return canEncodeValueRISCV(Type, Value, PC);
   case Triple::x86_64:
     return true;
@@ -789,6 +800,7 @@ uint64_t Relocation::extractValue(uint32_t Type, uint64_t Contents,
   case Triple::aarch64:
     return extractValueAArch64(Type, Contents, PC);
   case Triple::riscv64:
+  case Triple::riscv32:
     return extractValueRISCV(Type, Contents, PC);
   case Triple::x86_64:
     return extractValueX86(Type, Contents, PC);
@@ -802,6 +814,7 @@ bool Relocation::isGOT(uint32_t Type) {
   case Triple::aarch64:
     return isGOTAArch64(Type);
   case Triple::riscv64:
+  case Triple::riscv32:
     return isGOTRISCV(Type);
   case Triple::x86_64:
     return isGOTX86(Type);
@@ -829,6 +842,7 @@ bool Relocation::isRelative(uint32_t Type) {
   case Triple::aarch64:
     return Type == ELF::R_AARCH64_RELATIVE;
   case Triple::riscv64:
+  case Triple::riscv32:
     return Type == ELF::R_RISCV_RELATIVE;
   case Triple::x86_64:
     return Type == ELF::R_X86_64_RELATIVE;
@@ -842,6 +856,7 @@ bool Relocation::isIRelative(uint32_t Type) {
   case Triple::aarch64:
     return Type == ELF::R_AARCH64_IRELATIVE;
   case Triple::riscv64:
+  case Triple::riscv32:
     llvm_unreachable("not implemented");
   case Triple::x86_64:
     return Type == ELF::R_X86_64_IRELATIVE;
@@ -855,6 +870,7 @@ bool Relocation::isTLS(uint32_t Type) {
   case Triple::aarch64:
     return isTLSAArch64(Type);
   case Triple::riscv64:
+  case Triple::riscv32:
     return isTLSRISCV(Type);
   case Triple::x86_64:
     return isTLSX86(Type);
@@ -881,6 +897,7 @@ uint32_t Relocation::getNone() {
   case Triple::aarch64:
     return ELF::R_AARCH64_NONE;
   case Triple::riscv64:
+  case Triple::riscv32:
     return ELF::R_RISCV_NONE;
   case Triple::x86_64:
     return ELF::R_X86_64_NONE;
@@ -894,6 +911,7 @@ uint32_t Relocation::getPC32() {
   case Triple::aarch64:
     return ELF::R_AARCH64_PREL32;
   case Triple::riscv64:
+  case Triple::riscv32:
     return ELF::R_RISCV_32_PCREL;
   case Triple::x86_64:
     return ELF::R_X86_64_PC32;
@@ -907,6 +925,7 @@ uint32_t Relocation::getPC64() {
   case Triple::aarch64:
     return ELF::R_AARCH64_PREL64;
   case Triple::riscv64:
+  case Triple::riscv32:
     llvm_unreachable("not implemented");
   case Triple::x86_64:
     return ELF::R_X86_64_PC64;
@@ -926,6 +945,7 @@ bool Relocation::isPCRelative(uint32_t Type) {
   case Triple::aarch64:
     return isPCRelativeAArch64(Type);
   case Triple::riscv64:
+  case Triple::riscv32:
     return isPCRelativeRISCV(Type);
   case Triple::x86_64:
     return isPCRelativeX86(Type);
@@ -939,6 +959,7 @@ uint32_t Relocation::getAbs64() {
   case Triple::aarch64:
     return ELF::R_AARCH64_ABS64;
   case Triple::riscv64:
+  case Triple::riscv32:
     return ELF::R_RISCV_64;
   case Triple::x86_64:
     return ELF::R_X86_64_64;
@@ -952,6 +973,7 @@ uint32_t Relocation::getRelative() {
   case Triple::aarch64:
     return ELF::R_AARCH64_RELATIVE;
   case Triple::riscv64:
+  case Triple::riscv32:
     llvm_unreachable("not implemented");
   case Triple::x86_64:
     return ELF::R_X86_64_RELATIVE;
@@ -1001,7 +1023,8 @@ const MCExpr *Relocation::createExpr(MCStreamer *Streamer,
 }
 
 MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint32_t Type) {
-  assert(Arch == Triple::riscv64 && "only implemented for RISC-V");
+  assert((Arch == Triple::riscv32 || Arch == Triple::riscv64) &&
+         "only implemented for RISC-V");
 
   switch (Type) {
   default:
@@ -1022,6 +1045,7 @@ void Relocation::print(raw_ostream &OS) const {
     OS << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type);
     break;
   case Triple::riscv64:
+  case Triple::riscv32:
     OS << object::getELFRelocationTypeName(ELF::EM_RISCV, Type);
     break;
   case Triple::x86_64:
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 43d4421e06928..9bec061e87fd6 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -365,7 +365,7 @@ MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
 #endif
 
 #ifdef RISCV_AVAILABLE
-  if (Arch == Triple::riscv64)
+  if (Arch == Triple::riscv64 || Arch == Triple::riscv32)
     return createRISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
 #endif
 
@@ -427,7 +427,7 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
   // Read RISCV subtarget features from input file
   std::unique_ptr<SubtargetFeatures> Features;
   Triple TheTriple = File->makeTriple();
-  if (TheTriple.getArch() == llvm::Triple::riscv64) {
+  if (TheTriple.isRISCV()) {
     Expected<SubtargetFeatures> FeaturesOrErr = File->getFeatures();
     if (auto E = FeaturesOrErr.takeError()) {
       Err = std::move(E);
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index af662f5571b20..d1a0572277874 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -28,6 +28,14 @@ using namespace bolt;
 namespace {
 
 class RISCVMCPlusBuilder : public MCPlusBuilder {
+  bool isRV64() const { return STI->hasFeature(RISCV::Feature64Bit); }
+  unsigned regSize() const { return isRV64() ? 8 : 4; }
+  unsigned loadOpc() const { return isRV64() ? RISCV::LD : RISCV::LW; }
+  unsigned storeOpc() const { return isRV64() ? RISCV::SD : RISCV::SW; }
+  unsigned atomicAddOpc() const {
+    return isRV64() ? RISCV::AMOADD_D : RISCV::AMOADD_W;
+  }
+
 public:
   using MCPlusBuilder::MCPlusBuilder;
 
@@ -378,7 +386,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
 
     assert(I != End);
     auto &LD = *I++;
-    assert(LD.getOpcode() == RISCV::LD);
+    assert(LD.getOpcode() == loadOpc());
     assert(LD.getOperand(0).getReg() == RISCV::X28);
     assert(LD.getOperand(1).getReg() == RISCV::X28);
 
@@ -511,24 +519,24 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
 
   void loadReg(MCInst &Inst, MCPhysReg To, MCPhysReg From,
                int64_t offset) const {
-    Inst = MCInstBuilder(RISCV::LD).addReg(To).addReg(From).addImm(offset);
+    Inst = MCInstBuilder(loadOpc()).addReg(To).addReg(From).addImm(offset);
   }
 
   void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To,
                 int64_t offset) const {
-    Inst = MCInstBuilder(RISCV::SD).addReg(From).addReg(To).addImm(offset);
+    Inst = MCInstBuilder(storeOpc()).addReg(From).addReg(To).addImm(offset);
   }
 
   void spillRegs(InstructionListType &Insts,
                  const SmallVector<unsigned> &Regs) const {
     Insts.emplace_back();
-    createStackPointerIncrement(Insts.back(), Regs.size() * 8);
+    createStackPointerIncrement(Insts.back(), Regs.size() * regSize());
 
     int64_t Offset = 0;
     for (auto Reg : Regs) {
       Insts.emplace_back();
       storeReg(Insts.back(), Reg, RISCV::X2, Offset);
-      Offset += 8;
+      Offset += regSize();
     }
   }
 
@@ -538,16 +546,16 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
     for (auto Reg : Regs) {
       Insts.emplace_back();
       loadReg(Insts.back(), Reg, RISCV::X2, Offset);
-      Offset += 8;
+      Offset += regSize();
     }
 
     Insts.emplace_back();
-    createStackPointerDecrement(Insts.back(), Regs.size() * 8);
+    createStackPointerDecrement(Insts.back(), Regs.size() * regSize());
   }
 
   void atomicAdd(MCInst &Inst, MCPhysReg RegAtomic, MCPhysReg RegTo,
                  MCPhysReg RegCnt) const {
-    Inst = MCInstBuilder(RISCV::AMOADD_D)
+    Inst = MCInstBuilder(atomicAddOpc())
                .addReg(RegAtomic)
                .addReg(RegTo)
                .addReg(RegCnt);
diff --git a/bolt/test/RISCV/branch-no-secondary-entry.s b/bolt/test/RISCV/branch-no-secondary-entry.s
index f83ca51579156..9a61f9a5e5e42 100644
--- a/bolt/test/RISCV/branch-no-secondary-entry.s
+++ b/bolt/test/RISCV/branch-no-secondary-entry.s
@@ -1,6 +1,6 @@
 /// Test that no secondary entry points are created for basic block labels used
 /// by branches.
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt -print-cfg -o %t.null %t 2>&1 | FileCheck %s
 
 // CHECK: Binary Function "_start" after building cfg {
diff --git a/bolt/test/RISCV/fake-label-no-entry.c b/bolt/test/RISCV/fake-label-no-entry.c
index bd125263101bb..624b952096c82 100644
--- a/bolt/test/RISCV/fake-label-no-entry.c
+++ b/bolt/test/RISCV/fake-label-no-entry.c
@@ -3,7 +3,7 @@
 
 // clang-format off
 
-// RUN: %clang %cflags -g -Wl,-q -o %t %s
+// RUN: %clang %cflags64 -g -Wl,-q -o %t %s
 
 /// Verify that the binary indeed contains a fake label ".L0 " at _start.
 // RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=CHECK-ELF
diff --git a/bolt/test/RISCV/function-alignment.s b/bolt/test/RISCV/function-alignment.s
index c52cff9e2347a..99587f7477331 100644
--- a/bolt/test/RISCV/function-alignment.s
+++ b/bolt/test/RISCV/function-alignment.s
@@ -10,6 +10,16 @@
 # RUN: llvm-bolt --align-functions=1 --use-old-text=0 -o %t-c.bolt %t-c
 # RUN: llvm-nm -n %t-c.bolt | FileCheck --check-prefix=CHECK-C %s
 
+# RUN: llvm-mc -triple=riscv32 -filetype=obj -o %t.rv32.o %s
+# RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+# RUN: llvm-bolt --align-functions=1 --use-old-text=0 -o %t.rv32.bolt %t.rv32
+# RUN: llvm-nm -n %t.rv32.bolt | FileCheck %s
+
+# RUN: llvm-mc -triple=riscv32 -mattr=+c -filetype=obj -o %t.rv32-c.o %s
+# RUN: ld.lld -q -o %t.rv32-c %t.rv32-c.o
+# RUN: llvm-bolt --align-functions=1 --use-old-text=0 -o %t.rv32-c.bolt %t.rv32-c
+# RUN: llvm-nm -n %t.rv32-c.bolt | FileCheck --check-prefix=CHECK-C %s
+
 # CHECK:      {{[048c]}} T _start
 # CHECK-NEXT: {{[048c]}} T dummy
 
diff --git a/bolt/test/RISCV/internal-func-reloc.s b/bolt/test/RISCV/internal-func-reloc.s
index c6c74bed92efe..0a200150e9b0b 100644
--- a/bolt/test/RISCV/internal-func-reloc.s
+++ b/bolt/test/RISCV/internal-func-reloc.s
@@ -6,6 +6,10 @@
 // RUN: ld.lld --emit-relocs -o %t %t.o
 // RUN: llvm-bolt -o %t.bolt %t
 // RUN: llvm-objdump -d %t.bolt | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld --emit-relocs -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt -o %t.rv32.bolt %t.rv32
+// RUN: llvm-objdump -d %t.rv32.bolt | FileCheck %s
 
   .text
   .globl _start
diff --git a/bolt/test/RISCV/lit.local.cfg b/bolt/test/RISCV/lit.local.cfg
index ffc9939c98f36..4206030dd0773 100644
--- a/bolt/test/RISCV/lit.local.cfg
+++ b/bolt/test/RISCV/lit.local.cfg
@@ -1,7 +1,10 @@
 if 'RISCV' not in config.root.targets:
     config.unsupported = True
 
-flags = '--target=riscv64 -nostdlib -ffreestanding -Wl,--emit-relocs'
+flags64 = '--target=riscv64 -nostdlib -ffreestanding -Wl,--emit-relocs'
+flags32 = '--target=riscv32 -march=rv32imac -mabi=ilp32 -nostdlib -ffreestanding -Wl,--emit-relocs'
 
-config.substitutions.insert(0, ('%cflags', f'%cflags {flags}'))
-config.substitutions.insert(0, ('%cxxflags', f'%cxxflags {flags}'))
+config.substitutions.insert(0, ('%cflags64', f'%cflags {flags64}'))
+config.substitutions.insert(0, ('%cflags32', f'%cflags {flags32}'))
+config.substitutions.insert(0, ('%cxxflags64', f'%cxxflags {flags64}'))
+config.substitutions.insert(0, ('%cxxflags32', f'%cxxflags {flags32}'))
diff --git a/bolt/test/RISCV/load-store.s b/bolt/test/RISCV/load-store.s
index 052c5a3879a44..e44187194fff7 100644
--- a/bolt/test/RISCV/load-store.s
+++ b/bolt/test/RISCV/load-store.s
@@ -1,4 +1,4 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: link_fdata --no-lbr %s %t %t.fdata
 // RUN: llvm-bolt %t -o %t.null --data=%t.fdata --dyno-stats | FileCheck %s
 
diff --git a/bolt/test/RISCV/mapping-syms.s b/bolt/test/RISCV/mapping-syms.s
index e8fdeb0c7572d..97d2a1ad255f6 100644
--- a/bolt/test/RISCV/mapping-syms.s
+++ b/bolt/test/RISCV/mapping-syms.s
@@ -5,6 +5,9 @@
 // RUN: ld.lld -o %t %t.o
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.bolt %t 2>&1 | FileCheck %s
 // RUN: llvm-objdump -d %t.bolt | FileCheck --check-prefix=CHECK-OBJDUMP %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype obj -o %t.rv32.o %s
+// RUN: ld.lld -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o /dev/null %t.rv32 2>&1 | FileCheck %s
 
 // CHECK-NOT: BOLT-WARNING
 
diff --git a/bolt/test/RISCV/reloc-32.s b/bolt/test/RISCV/reloc-32.s
new file mode 100644
index 0000000000000..0f336e2cb6506
--- /dev/null
+++ b/bolt/test/RISCV/reloc-32.s
@@ -0,0 +1,23 @@
+/// RV32 counterpart of reloc-64.s — tests R_RISCV_32 relocation parsing.
+/// Verifies BOLT can read an RV32 ELF with R_RISCV_32 data relocations.
+
+// RUN: llvm-mc -triple riscv32 -filetype=obj -o %t.o %s
+// RUN: ld.lld -q -o %t %t.o
+// RUN: llvm-bolt -o %t.bolt %t 2>&1 | FileCheck %s
+
+// CHECK: BOLT-INFO: Target architecture: riscv32
+// CHECK: BOLT-INFO: enabling relocation mode
+
+  .data
+  .globl d
+  .p2align 2
+d:
+  .word _start
+
+  .text
+  .globl _start
+  .p2align 1
+_start:
+  ret
+  .reloc 0, R_RISCV_NONE
+  .size _start, .-_start
diff --git a/bolt/test/RISCV/reloc-abs.s b/bolt/test/RISCV/reloc-abs.s
index 956e0410ece42..0cae35449f4ee 100644
--- a/bolt/test/RISCV/reloc-abs.s
+++ b/bolt/test/RISCV/reloc-abs.s
@@ -1,5 +1,9 @@
-// RUN: %clang %cflags -Wl,--defsym='__global_pointer$'=0x2800 -o %t %s
+// RUN: %clang %cflags64 -Wl,--defsym='__global_pointer$'=0x2800 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q --defsym='__global_pointer$'=0x2800 -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.rv32.null %t.rv32 \
 // RUN:    | FileCheck %s
 
   .data
@@ -17,8 +21,8 @@ _start:
   .option push
   .option norelax
 1:
-// CHECK: auipc gp, %pcrel_hi(__global_pointer$) # Label: .Ltmp0
-// CHECK-NEXT: addi gp, gp, %pcrel_lo(.Ltmp0)
+// CHECK: auipc gp, %pcrel_hi(__global_pointer$)
+// CHECK-NEXT: addi gp, gp, %pcrel_lo(
   auipc gp, %pcrel_hi(__global_pointer$)
   addi  gp, gp, %pcrel_lo(1b)
   .option pop
diff --git a/bolt/test/RISCV/reloc-bb-split-rv32.s b/bolt/test/RISCV/reloc-bb-split-rv32.s
new file mode 100644
index 0000000000000..0ad3168fb983d
--- /dev/null
+++ b/bolt/test/RISCV/reloc-bb-split-rv32.s
@@ -0,0 +1,45 @@
+/// RV32 variant of reloc-bb-split.s — uses lw instead of ld.
+
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.o %s
+// RUN: ld.lld -q -o %t %t.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+
+  .data
+  .globl d
+  .p2align 2
+d:
+  .word 0
+
+  .text
+  .globl _start
+  .p2align 1
+// CHECK-LABEL: Binary Function "_start" after building cfg {
+_start:
+/// The local label is used for %pcrel_lo as well as a jump target so a new
+/// basic block should start there.
+// CHECK-LABEL: {{^}}.LBB00
+// CHECK: nop
+// CHECK-LABEL: {{^}}.Ltmp0
+// CHECK: auipc t0, %pcrel_hi(d)
+// CHECK-NEXT: lw t0, %pcrel_lo({{.*}})(t0)
+// CHECK-NEXT: j .Ltmp0
+  nop
+1:
+  auipc t0, %pcrel_hi(d)
+  lw t0, %pcrel_lo(1b)(t0)
+  j 1b
+
+/// The local label is used only for %pcrel_lo so no new basic block should
+/// start there.
+// CHECK-LABEL: {{^}}.LFT0
+// CHECK: nop
+// CHECK: auipc t0, %pcrel_hi(d)
+// CHECK-NEXT: lw t0, %pcrel_lo({{.*}})(t0)
+// CHECK-NEXT: ret
+  nop
+1:
+  auipc t0, %pcrel_hi(d)
+  lw t0, %pcrel_lo(1b)(t0)
+  ret
+  .size _start, .-_start
diff --git a/bolt/test/RISCV/reloc-bb-split.s b/bolt/test/RISCV/reloc-bb-split.s
index 450c763944529..23439ee2b8367 100644
--- a/bolt/test/RISCV/reloc-bb-split.s
+++ b/bolt/test/RISCV/reloc-bb-split.s
@@ -1,4 +1,4 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
 // RUN:    | FileCheck %s
 
diff --git a/bolt/test/RISCV/reloc-branch.s b/bolt/test/RISCV/reloc-branch.s
index 780d978f36f44..3d1512978078e 100644
--- a/bolt/test/RISCV/reloc-branch.s
+++ b/bolt/test/RISCV/reloc-branch.s
@@ -1,5 +1,9 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.rv32.null %t.rv32 \
 // RUN:    | FileCheck %s
 
   .text
diff --git a/bolt/test/RISCV/reloc-call.s b/bolt/test/RISCV/reloc-call.s
index 37cfd993b95d2..1b9eac376d9b0 100644
--- a/bolt/test/RISCV/reloc-call.s
+++ b/bolt/test/RISCV/reloc-call.s
@@ -1,7 +1,12 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-fix-riscv-calls --print-only=_start -o %t.null %t \
 // RUN:    | FileCheck %s
 
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-fix-riscv-calls --print-only=_start \
+// RUN:    -o %t.rv32.null %t.rv32 | FileCheck %s
+
   .text
 
   .global f
diff --git a/bolt/test/RISCV/reloc-got.s b/bolt/test/RISCV/reloc-got.s
index e7e85fddfb1cb..7b04aefafdbf3 100644
--- a/bolt/test/RISCV/reloc-got.s
+++ b/bolt/test/RISCV/reloc-got.s
@@ -1,4 +1,4 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
 // RUN:    | FileCheck %s
 
diff --git a/bolt/test/RISCV/reloc-jal.s b/bolt/test/RISCV/reloc-jal.s
index 62a2f1dbea03a..852af886c431d 100644
--- a/bolt/test/RISCV/reloc-jal.s
+++ b/bolt/test/RISCV/reloc-jal.s
@@ -1,5 +1,9 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.rv32.null %t.rv32 \
 // RUN:    | FileCheck %s
 
   .text
diff --git a/bolt/test/RISCV/reloc-jt.s b/bolt/test/RISCV/reloc-jt.s
index a1fc854f036da..2f7ad33b2afbe 100644
--- a/bolt/test/RISCV/reloc-jt.s
+++ b/bolt/test/RISCV/reloc-jt.s
@@ -1,6 +1,6 @@
 /// NOTE: assign section addresses explicitly to make the symbol difference
 /// calculation below less fragile.
-// RUN: %clang %cflags -Wl,--image-base=0,--section-start=.text=0x1000,--section-start=.data=0x2000 -o %t %s
+// RUN: %clang %cflags64 -Wl,--image-base=0,--section-start=.text=0x1000,--section-start=.data=0x2000 -o %t %s
 // RUN: llvm-bolt -o %t.bolt %t
 // RUN: llvm-readelf -x .data %t.bolt | FileCheck %s
 
diff --git a/bolt/test/RISCV/reloc-label-diff.s b/bolt/test/RISCV/reloc-label-diff.s
index 4f2eb00322c6a..60cd0a88aa45e 100644
--- a/bolt/test/RISCV/reloc-label-diff.s
+++ b/bolt/test/RISCV/reloc-label-diff.s
@@ -1,6 +1,10 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt -o %t.bolt %t
 // RUN: llvm-readelf -x .data %t.bolt | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt -o %t.rv32.bolt %t.rv32
+// RUN: llvm-readelf -x .data %t.rv32.bolt | FileCheck %s
 
   .text
   .option norvc
diff --git a/bolt/test/RISCV/reloc-lohi-rv32.s b/bolt/test/RISCV/reloc-lohi-rv32.s
new file mode 100644
index 0000000000000..78cf7692ef304
--- /dev/null
+++ b/bolt/test/RISCV/reloc-lohi-rv32.s
@@ -0,0 +1,28 @@
+/// RV32 variant of reloc-lohi.s — uses lw/sw instead of ld/sd.
+
+// RUN: llvm-mc -triple riscv32 -filetype=obj -o %t.o %s
+// RUN: ld.lld -q -o %t %t.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+
+  .data
+  .globl d
+  .p2align 2
+d:
+  .word 0
+
+// CHECK-LABEL: Binary Function "_start" after building cfg {
+// CHECK:      lui t0, %hi(d)
+// CHECK-NEXT: lw t0, %lo(d)(t0)
+// CHECK-NEXT: lui t0, %hi(d)
+// CHECK-NEXT: sw t0, %lo(d)(t0)
+  .text
+  .globl _start
+  .p2align 1
+_start:
+  lui t0, %hi(d)
+  lw t0, %lo(d)(t0)
+  lui t0, %hi(d)
+  sw t0, %lo(d)(t0)
+  ret
+  .size _start, .-_start
diff --git a/bolt/test/RISCV/reloc-pcrel-rv32.s b/bolt/test/RISCV/reloc-pcrel-rv32.s
new file mode 100644
index 0000000000000..2e386b022b8f8
--- /dev/null
+++ b/bolt/test/RISCV/reloc-pcrel-rv32.s
@@ -0,0 +1,27 @@
+/// RV32 variant of reloc-pcrel.s — uses lw/sw instead of ld/sd.
+
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.o %s
+// RUN: ld.lld -q -o %t %t.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+
+  .data
+  .globl d
+  .p2align 2
+d:
+  .word 0
+
+  .text
+  .globl _start
+  .p2align 1
+// CHECK: Binary Function "_start" after building cfg {
+_start:
+  nop // Here to not make the _start and .Ltmp0 symbols coincide
+// CHECK: auipc t0, %pcrel_hi(d)
+// CHECK-NEXT: lw t0, %pcrel_lo({{.*}})(t0)
+  lw t0, d
+// CHECK: auipc t1, %pcrel_hi(d)
+// CHECK-NEXT: sw t0, %pcrel_lo({{.*}})(t1)
+  sw t0, d, t1
+  ret
+  .size _start, .-_start
diff --git a/bolt/test/RISCV/reloc-pcrel.s b/bolt/test/RISCV/reloc-pcrel.s
index c7e41747b4db9..5320c6d12e5cd 100644
--- a/bolt/test/RISCV/reloc-pcrel.s
+++ b/bolt/test/RISCV/reloc-pcrel.s
@@ -1,4 +1,4 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
 // RUN:    | FileCheck %s
 
diff --git a/bolt/test/RISCV/reloc-rvc-branch.s b/bolt/test/RISCV/reloc-rvc-branch.s
index 87c16d8023faf..8ba7b39ee2b96 100644
--- a/bolt/test/RISCV/reloc-rvc-branch.s
+++ b/bolt/test/RISCV/reloc-rvc-branch.s
@@ -1,5 +1,9 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.rv32.null %t.rv32 \
 // RUN:    | FileCheck %s
 
   .text
@@ -7,7 +11,7 @@
   .p2align 1
 // CHECK: Binary Function "_start" after building cfg {
 _start:
-// CHECK: beqz a0, .Ltmp0
+// CHECK: {{(c.)?}}beqz a0, .Ltmp0
   c.beqz a0, 1f
   nop
 // CHECK: .Ltmp0
diff --git a/bolt/test/RISCV/reloc-rvc-jump.s b/bolt/test/RISCV/reloc-rvc-jump.s
index 2aae9c3c8e8e5..c7b7a78dbac01 100644
--- a/bolt/test/RISCV/reloc-rvc-jump.s
+++ b/bolt/test/RISCV/reloc-rvc-jump.s
@@ -1,5 +1,9 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --print-cfg --print-only=_start -o %t.null %t \
+// RUN:    | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.rv32.null %t.rv32 \
 // RUN:    | FileCheck %s
 
   .text
@@ -7,7 +11,7 @@
   .p2align 1
 // CHECK: Binary Function "_start" after building cfg {
 _start:
-// CHECK: j .Ltmp0
+// CHECK: {{(c.)?}}j .Ltmp0
   c.j 1f
   nop
 // CHECK: .Ltmp0
diff --git a/bolt/test/RISCV/reorder-blocks-reverse.s b/bolt/test/RISCV/reorder-blocks-reverse.s
index 6a9c879128278..c97409f3cc604 100644
--- a/bolt/test/RISCV/reorder-blocks-reverse.s
+++ b/bolt/test/RISCV/reorder-blocks-reverse.s
@@ -1,6 +1,10 @@
-// RUN: %clang %cflags -o %t %s
+// RUN: %clang %cflags64 -o %t %s
 // RUN: llvm-bolt --reorder-blocks=reverse -o %t.bolt %t
 // RUN: llvm-objdump -d --no-show-raw-insn %t.bolt | FileCheck %s
+// RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj -o %t.rv32.o %s
+// RUN: ld.lld -q -o %t.rv32 %t.rv32.o
+// RUN: llvm-bolt --reorder-blocks=reverse -o %t.rv32.bolt %t.rv32
+// RUN: llvm-objdump -d --no-show-raw-insn %t.rv32.bolt | FileCheck %s
 
   .text
   .globl _start
diff --git a/bolt/test/RISCV/validate-secondary-entry-point.s b/bolt/test/RISCV/validate-secondary-entry-point.s
index 0c29f5c97c689..da3f12737c1a3 100644
--- a/bolt/test/RISCV/validate-secondary-entry-point.s
+++ b/bolt/test/RISCV/validate-secondary-entry-point.s
@@ -2,7 +2,7 @@
 # island as a secondary entry point (function `_start` doesn't have ELF size
 # set originally) and the function won't otherwise be mistaken as non-simple.
 
-# RUN: %clang %cflags -pie %s -o %t.so -Wl,-q -Wl,--init=_foo -Wl,--fini=_foo
+# RUN: %clang %cflags64 -pie %s -o %t.so -Wl,-q -Wl,--init=_foo -Wl,--fini=_foo
 # RUN: llvm-bolt %t.so -o %t.bolt.so --print-cfg 2>&1 | FileCheck %s
 # CHECK-NOT: BOLT-WARNING: reference in the middle of instruction detected \
 # CHECK-NOT:   function _start at offset 0x{{[0-9a-f]+}}



More information about the llvm-commits mailing list