[llvm] [BOLT][RISCV] Implement register analysis hooks (PR #220581)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 7 19:56:21 PDT 2026
https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/220581
>From 67c21aaea056fc389cfbf95752acd084427ea903 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 2 Sep 2026 20:39:28 +0800
Subject: [PATCH 1/4] [BOLT][RISCV] Implement register analysis hooks
---
bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 46 +++++++
bolt/unittests/Core/MCPlusBuilder.cpp | 130 ++++++++++++++++++-
2 files changed, 171 insertions(+), 5 deletions(-)
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index 349f38cb11b26..bd792b4346bf2 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -40,6 +40,25 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
public:
using MCPlusBuilder::MCPlusBuilder;
+ MCPhysReg getFlagsReg() const override { return RISCV::NoRegister; }
+
+ bool isCleanRegXOR(const MCInst &Inst) const override {
+ switch (Inst.getOpcode()) {
+ case RISCV::XOR:
+ case RISCV::C_XOR:
+ return Inst.getOperand(1).getReg() == Inst.getOperand(2).getReg();
+ default:
+ return false;
+ }
+ }
+
+ BitVector getRegsUsedAsParams() const override {
+ BitVector Regs(RegInfo->getNumRegs(), false);
+ for (MCPhysReg Reg = RISCV::X10; Reg <= RISCV::X17; ++Reg)
+ Regs |= getAliases(Reg);
+ return Regs;
+ }
+
std::unique_ptr<MCSymbolizer>
createTargetSymbolizer(BinaryFunction &Function,
bool CreateNewSymbols) const override {
@@ -73,6 +92,33 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
Regs |= getAliases(RISCV::X27);
}
+ void getDefaultLiveOut(BitVector &Regs) const override {
+ // The RISC-V psABI uses a0 (x10) and a1 (x11) to return integer and pointer
+ // values.
+ Regs |= getAliases(RISCV::X10);
+ Regs |= getAliases(RISCV::X11);
+ }
+
+ void getGPRegs(BitVector &Regs, bool IncludeAlias = true) const override {
+ for (MCPhysReg Reg = RISCV::X1; Reg <= RISCV::X31; ++Reg) {
+ if (IncludeAlias)
+ Regs |= getAliases(Reg);
+ else
+ Regs.set(Reg);
+ }
+ }
+
+ void removeNonScavengeableRegs(BitVector &Regs) const override {
+ BitVector ExclusionMask(RegInfo->getNumRegs(), false);
+ ExclusionMask |= getAliases(RISCV::X1); // return address
+ ExclusionMask |= getAliases(RISCV::X2); // stack pointer
+ ExclusionMask |= getAliases(RISCV::X3); // global pointer
+ ExclusionMask |= getAliases(RISCV::X4); // thread pointer
+ ExclusionMask |= getAliases(RISCV::X8); // frame pointer
+ ExclusionMask.flip();
+ Regs &= ExclusionMask;
+ }
+
bool shouldRecordCodeRelocation(uint32_t RelType) const override {
switch (RelType) {
case ELF::R_RISCV_JAL:
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index a692f45f551eb..17dc7f6a8473f 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -16,6 +16,11 @@
#include "X86Subtarget.h"
#endif // X86_AVAILABLE
+#ifdef RISCV_AVAILABLE
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "RISCVSubtarget.h"
+#endif // RISCV_AVAILABLE
+
#include "bolt/Core/BinaryBasicBlock.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Rewrite/RewriteInstance.h"
@@ -23,6 +28,7 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -56,17 +62,34 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
- EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
+ switch (GetParam()) {
+ case Triple::aarch64:
+ EHdr->e_machine = EM_AARCH64;
+ break;
+ case Triple::riscv64:
+ EHdr->e_machine = EM_RISCV;
+ break;
+ case Triple::x86_64:
+ EHdr->e_machine = EM_X86_64;
+ break;
+ default:
+ llvm_unreachable("Unsupported architecture");
+ break;
+ }
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
}
void initializeBolt() {
- Relocation::Arch = ObjFile->makeTriple().getArch();
+ const Triple TheTriple = GetParam();
+ Relocation::Arch = TheTriple.getArch();
+ // Minimal test ELFs have no RISC-V attributes. Pass an empty feature set so
+ // createBinaryContext() can add the +relax feature required by BOLT.
+ SubtargetFeatures Features;
BC = cantFail(BinaryContext::createBinaryContext(
- ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
- ObjFile->getFileName(), nullptr, true, DWARFContext::create(*ObjFile),
- {llvm::outs(), llvm::errs()}));
+ TheTriple, std::make_shared<orc::SymbolStringPool>(),
+ ObjFile->getFileName(), TheTriple.isRISCV() ? &Features : nullptr, true,
+ DWARFContext::create(*ObjFile), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(),
@@ -87,6 +110,13 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
assertRegMask(RegMask, ExpectedRegs);
}
+ BitVector getAliasMask(std::initializer_list<MCPhysReg> Registers) {
+ BitVector RegMask(BC->MRI->getNumRegs());
+ for (MCPhysReg Reg : Registers)
+ RegMask |= BC->MIB->getAliases(Reg);
+ return RegMask;
+ }
+
void testRegAliases(Triple::ArchType Arch, uint64_t Register,
std::initializer_list<MCPhysReg> ExpectedAliases,
bool OnlySmaller = false) {
@@ -892,6 +922,96 @@ TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
#endif // AARCH64_AVAILABLE
+#ifdef RISCV_AVAILABLE
+
+INSTANTIATE_TEST_SUITE_P(RISCV, MCPlusBuilderTester,
+ ::testing::Values(Triple::riscv64));
+
+TEST_P(MCPlusBuilderTester, RISCV_NoFlagsRegister) {
+ if (GetParam() != Triple::riscv64)
+ GTEST_SKIP();
+
+ EXPECT_EQ(BC->MIB->getFlagsReg(), RISCV::NoRegister);
+}
+
+TEST_P(MCPlusBuilderTester, RISCV_isCleanRegXOR) {
+ if (GetParam() != Triple::riscv64)
+ GTEST_SKIP();
+
+ MCInst XOR = MCInstBuilder(RISCV::XOR)
+ .addReg(RISCV::X5)
+ .addReg(RISCV::X6)
+ .addReg(RISCV::X6);
+ EXPECT_TRUE(BC->MIB->isCleanRegXOR(XOR));
+
+ MCInst NonCleanXOR = MCInstBuilder(RISCV::XOR)
+ .addReg(RISCV::X5)
+ .addReg(RISCV::X6)
+ .addReg(RISCV::X7);
+ EXPECT_FALSE(BC->MIB->isCleanRegXOR(NonCleanXOR));
+
+ MCInst CompressedXOR = MCInstBuilder(RISCV::C_XOR)
+ .addReg(RISCV::X8)
+ .addReg(RISCV::X8)
+ .addReg(RISCV::X8);
+ EXPECT_TRUE(BC->MIB->isCleanRegXOR(CompressedXOR));
+
+ MCInst ADD = MCInstBuilder(RISCV::ADD)
+ .addReg(RISCV::X5)
+ .addReg(RISCV::X6)
+ .addReg(RISCV::X6);
+ EXPECT_FALSE(BC->MIB->isCleanRegXOR(ADD));
+}
+
+TEST_P(MCPlusBuilderTester, RISCV_ABIRegisterMasks) {
+ if (GetParam() != Triple::riscv64)
+ GTEST_SKIP();
+
+ BitVector ExpectedParams(BC->MRI->getNumRegs());
+ for (MCPhysReg Reg = RISCV::X10; Reg <= RISCV::X17; ++Reg)
+ ExpectedParams |= BC->MIB->getAliases(Reg);
+ EXPECT_EQ(BC->MIB->getRegsUsedAsParams(), ExpectedParams);
+
+ BitVector LiveOut(BC->MRI->getNumRegs());
+ BC->MIB->getDefaultLiveOut(LiveOut);
+ EXPECT_EQ(LiveOut, getAliasMask({RISCV::X10, RISCV::X11}));
+}
+
+TEST_P(MCPlusBuilderTester, RISCV_GPRegisterMasks) {
+ if (GetParam() != Triple::riscv64)
+ GTEST_SKIP();
+
+ BitVector ExpectedWithAliases(BC->MRI->getNumRegs());
+ BitVector ExpectedWithoutAliases(BC->MRI->getNumRegs());
+ for (MCPhysReg Reg = RISCV::X1; Reg <= RISCV::X31; ++Reg) {
+ ExpectedWithAliases |= BC->MIB->getAliases(Reg);
+ ExpectedWithoutAliases.set(Reg);
+ }
+
+ BitVector GPRegs(BC->MRI->getNumRegs());
+ BC->MIB->getGPRegs(GPRegs);
+ EXPECT_EQ(GPRegs, ExpectedWithAliases);
+
+ GPRegs.reset();
+ BC->MIB->getGPRegs(GPRegs, /*IncludeAlias=*/false);
+ EXPECT_EQ(GPRegs, ExpectedWithoutAliases);
+}
+
+TEST_P(MCPlusBuilderTester, RISCV_removeNonScavengeableRegs) {
+ if (GetParam() != Triple::riscv64)
+ GTEST_SKIP();
+
+ BitVector Regs(BC->MRI->getNumRegs(), true);
+ BitVector Expected = Regs;
+ for (MCPhysReg Reg : {RISCV::X1, RISCV::X2, RISCV::X3, RISCV::X4, RISCV::X8})
+ Expected.reset(BC->MIB->getAliases(Reg));
+
+ BC->MIB->removeNonScavengeableRegs(Regs);
+ EXPECT_EQ(Regs, Expected);
+}
+
+#endif // RISCV_AVAILABLE
+
#ifdef X86_AVAILABLE
INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester,
>From f3ac72d8dd36b97278034413bc961607b1e02414 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 3 Sep 2026 14:47:48 +0800
Subject: [PATCH 2/4] fix
---
bolt/unittests/Core/MCPlusBuilder.cpp | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index 17dc7f6a8473f..14291e6f0ece7 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -83,8 +83,8 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
void initializeBolt() {
const Triple TheTriple = GetParam();
Relocation::Arch = TheTriple.getArch();
- // Minimal test ELFs have no RISC-V attributes. Pass an empty feature set so
- // createBinaryContext() can add the +relax feature required by BOLT.
+ // Minimal test ELFs have no RISC-V attributes. RISC-V needs an empty
+ // feature set for +relax, while other targets reject a non-null one.
SubtargetFeatures Features;
BC = cantFail(BinaryContext::createBinaryContext(
TheTriple, std::make_shared<orc::SymbolStringPool>(),
@@ -92,7 +92,7 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
DWARFContext::create(*ObjFile), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
- createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(),
+ createMCPlusBuilder(TheTriple.getArch(), BC->MIA.get(), BC->MII.get(),
BC->MRI.get(), BC->STI.get())));
}
@@ -110,13 +110,6 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
assertRegMask(RegMask, ExpectedRegs);
}
- BitVector getAliasMask(std::initializer_list<MCPhysReg> Registers) {
- BitVector RegMask(BC->MRI->getNumRegs());
- for (MCPhysReg Reg : Registers)
- RegMask |= BC->MIB->getAliases(Reg);
- return RegMask;
- }
-
void testRegAliases(Triple::ArchType Arch, uint64_t Register,
std::initializer_list<MCPhysReg> ExpectedAliases,
bool OnlySmaller = false) {
@@ -974,7 +967,9 @@ TEST_P(MCPlusBuilderTester, RISCV_ABIRegisterMasks) {
BitVector LiveOut(BC->MRI->getNumRegs());
BC->MIB->getDefaultLiveOut(LiveOut);
- EXPECT_EQ(LiveOut, getAliasMask({RISCV::X10, RISCV::X11}));
+ BitVector ExpectedLiveOut = BC->MIB->getAliases(RISCV::X10);
+ ExpectedLiveOut |= BC->MIB->getAliases(RISCV::X11);
+ EXPECT_EQ(LiveOut, ExpectedLiveOut);
}
TEST_P(MCPlusBuilderTester, RISCV_GPRegisterMasks) {
>From 53422aa7b86766a637f6b3122dddaa1953a1dc27 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 3 Sep 2026 15:34:21 +0800
Subject: [PATCH 3/4] fix XOR function name
---
bolt/include/bolt/Core/MCPlusBuilder.h | 2 +-
bolt/include/bolt/Passes/LivenessAnalysis.h | 2 +-
.../Target/AArch64/AArch64MCPlusBuilder.cpp | 2 +-
bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 12 ++---
bolt/lib/Target/X86/X86MCPlusBuilder.cpp | 2 +-
bolt/unittests/Core/MCPlusBuilder.cpp | 46 ++++++++-----------
6 files changed, 28 insertions(+), 38 deletions(-)
diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index be0d58af14fc4..e55db33834ee8 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -897,7 +897,7 @@ class MCPlusBuilder {
return false;
}
- virtual bool isCleanRegXOR(const MCInst &Inst) const {
+ virtual bool isCleanReg(const MCInst &Inst) const {
llvm_unreachable("not implemented");
return false;
}
diff --git a/bolt/include/bolt/Passes/LivenessAnalysis.h b/bolt/include/bolt/Passes/LivenessAnalysis.h
index 6fcb66957f028..5d5bcd29a0ca3 100644
--- a/bolt/include/bolt/Passes/LivenessAnalysis.h
+++ b/bolt/include/bolt/Passes/LivenessAnalysis.h
@@ -137,7 +137,7 @@ class LivenessAnalysis : public DataflowAnalysis<LivenessAnalysis, BitVector,
Next &= Written;
// Gen
if (!this->BC.MIB->isCFI(Point)) {
- if (BC.MIB->isCleanRegXOR(Point))
+ if (BC.MIB->isCleanReg(Point))
return Next;
BitVector Used = BitVector(NumRegs, false);
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 8d7fee733b9c3..20731cf0c28d8 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -2658,7 +2658,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
isAArch64ExclusiveStore(Inst);
}
- bool isCleanRegXOR(const MCInst &Inst) const override {
+ bool isCleanReg(const MCInst &Inst) const override {
switch (Inst.getOpcode()) {
case AArch64::EORXrs:
case AArch64::EORWrs:
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index bd792b4346bf2..3e013fc79c733 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -42,14 +42,10 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
MCPhysReg getFlagsReg() const override { return RISCV::NoRegister; }
- bool isCleanRegXOR(const MCInst &Inst) const override {
- switch (Inst.getOpcode()) {
- case RISCV::XOR:
- case RISCV::C_XOR:
- return Inst.getOperand(1).getReg() == Inst.getOperand(2).getReg();
- default:
- return false;
- }
+ bool isCleanReg(const MCInst &Inst) const override {
+ return Inst.getOpcode() == RISCV::ADDI && Inst.getOperand(1).isReg() &&
+ Inst.getOperand(1).getReg() == RISCV::X0 &&
+ Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == 0;
}
BitVector getRegsUsedAsParams() const override {
diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
index 20eacd88e9735..9bbbd87f53da3 100644
--- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
+++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp
@@ -379,7 +379,7 @@ class X86MCPlusBuilder : public MCPlusBuilder {
return MCII.mayStore();
}
- bool isCleanRegXOR(const MCInst &Inst) const override {
+ bool isCleanReg(const MCInst &Inst) const override {
switch (Inst.getOpcode()) {
case X86::XOR16rr:
case X86::XOR32rr:
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index 14291e6f0ece7..aaaa25444839d 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -854,7 +854,7 @@ TEST_P(MCPlusBuilderTester, AArch64_Psign_Pauth_variants) {
ASSERT_TRUE(BC->MIB->isPAuthAndRet(Retab));
}
-TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
+TEST_P(MCPlusBuilderTester, AArch64_isCleanReg) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
@@ -867,7 +867,7 @@ TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
.addReg(AArch64::X0)
.addReg(AArch64::X0)
.addImm(0);
- ASSERT_TRUE(BC->MIB->isCleanRegXOR(EORXrs));
+ ASSERT_TRUE(BC->MIB->isCleanReg(EORXrs));
// eor w0, w0, w0
MCInst EORWrs = MCInstBuilder(AArch64::EORWrs)
@@ -875,7 +875,7 @@ TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
.addReg(AArch64::W0)
.addReg(AArch64::W0)
.addImm(0);
- ASSERT_TRUE(BC->MIB->isCleanRegXOR(EORWrs));
+ ASSERT_TRUE(BC->MIB->isCleanReg(EORWrs));
// mov x0, xzr
MCInst ORRXrs = MCInstBuilder(AArch64::ORRXrs)
@@ -883,7 +883,7 @@ TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
.addReg(AArch64::XZR)
.addReg(AArch64::XZR)
.addImm(0);
- ASSERT_TRUE(BC->MIB->isCleanRegXOR(ORRXrs));
+ ASSERT_TRUE(BC->MIB->isCleanReg(ORRXrs));
// mov w0, wzr
MCInst ORRWrs = MCInstBuilder(AArch64::ORRWrs)
@@ -891,17 +891,17 @@ TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
.addReg(AArch64::WZR)
.addReg(AArch64::WZR)
.addImm(0);
- ASSERT_TRUE(BC->MIB->isCleanRegXOR(ORRWrs));
+ ASSERT_TRUE(BC->MIB->isCleanReg(ORRWrs));
// mov x0, #0
MCInst MOVZXi =
MCInstBuilder(AArch64::MOVZXi).addReg(AArch64::X0).addImm(0).addImm(0);
- ASSERT_TRUE(BC->MIB->isCleanRegXOR(MOVZXi));
+ ASSERT_TRUE(BC->MIB->isCleanReg(MOVZXi));
// mov w0, #0
MCInst MOVZWi =
MCInstBuilder(AArch64::MOVZWi).addReg(AArch64::W0).addImm(0).addImm(0);
- ASSERT_TRUE(BC->MIB->isCleanRegXOR(MOVZWi));
+ ASSERT_TRUE(BC->MIB->isCleanReg(MOVZWi));
// movz x0, #:abs_g3:symbol
MCInst MOVZXiWithExpr =
@@ -910,7 +910,7 @@ TEST_P(MCPlusBuilderTester, AArch64_isCleanRegXOR) {
.addExpr(MCSpecifierExpr::create(BB->getLabel(), AArch64::S_ABS_G3,
*BC->Ctx.get()))
.addImm(48);
- ASSERT_FALSE(BC->MIB->isCleanRegXOR(MOVZXiWithExpr));
+ ASSERT_FALSE(BC->MIB->isCleanReg(MOVZXiWithExpr));
}
#endif // AARCH64_AVAILABLE
@@ -927,33 +927,27 @@ TEST_P(MCPlusBuilderTester, RISCV_NoFlagsRegister) {
EXPECT_EQ(BC->MIB->getFlagsReg(), RISCV::NoRegister);
}
-TEST_P(MCPlusBuilderTester, RISCV_isCleanRegXOR) {
+TEST_P(MCPlusBuilderTester, RISCV_isCleanReg) {
if (GetParam() != Triple::riscv64)
GTEST_SKIP();
- MCInst XOR = MCInstBuilder(RISCV::XOR)
- .addReg(RISCV::X5)
- .addReg(RISCV::X6)
- .addReg(RISCV::X6);
- EXPECT_TRUE(BC->MIB->isCleanRegXOR(XOR));
+ MCInst ADDI =
+ MCInstBuilder(RISCV::ADDI).addReg(RISCV::X5).addReg(RISCV::X0).addImm(0);
+ EXPECT_TRUE(BC->MIB->isCleanReg(ADDI));
- MCInst NonCleanXOR = MCInstBuilder(RISCV::XOR)
- .addReg(RISCV::X5)
- .addReg(RISCV::X6)
- .addReg(RISCV::X7);
- EXPECT_FALSE(BC->MIB->isCleanRegXOR(NonCleanXOR));
+ MCInst NonZeroSource =
+ MCInstBuilder(RISCV::ADDI).addReg(RISCV::X5).addReg(RISCV::X6).addImm(0);
+ EXPECT_FALSE(BC->MIB->isCleanReg(NonZeroSource));
- MCInst CompressedXOR = MCInstBuilder(RISCV::C_XOR)
- .addReg(RISCV::X8)
- .addReg(RISCV::X8)
- .addReg(RISCV::X8);
- EXPECT_TRUE(BC->MIB->isCleanRegXOR(CompressedXOR));
+ MCInst NonZeroImmediate =
+ MCInstBuilder(RISCV::ADDI).addReg(RISCV::X5).addReg(RISCV::X0).addImm(1);
+ EXPECT_FALSE(BC->MIB->isCleanReg(NonZeroImmediate));
- MCInst ADD = MCInstBuilder(RISCV::ADD)
+ MCInst XOR = MCInstBuilder(RISCV::XOR)
.addReg(RISCV::X5)
.addReg(RISCV::X6)
.addReg(RISCV::X6);
- EXPECT_FALSE(BC->MIB->isCleanRegXOR(ADD));
+ EXPECT_FALSE(BC->MIB->isCleanReg(XOR));
}
TEST_P(MCPlusBuilderTester, RISCV_ABIRegisterMasks) {
>From 0df4e923114c00170d6b81e056ac622e63c8e39e Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 8 Sep 2026 10:55:50 +0800
Subject: [PATCH 4/4] [BOLT][RISCV] Recognize C.LI zero as a register-clearing
instruction
---
bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 13 ++++++++++---
bolt/unittests/Core/MCPlusBuilder.cpp | 19 +++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index 3e013fc79c733..3fa0572e35fcd 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -43,9 +43,16 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
MCPhysReg getFlagsReg() const override { return RISCV::NoRegister; }
bool isCleanReg(const MCInst &Inst) const override {
- return Inst.getOpcode() == RISCV::ADDI && Inst.getOperand(1).isReg() &&
- Inst.getOperand(1).getReg() == RISCV::X0 &&
- Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == 0;
+ switch (Inst.getOpcode()) {
+ case RISCV::ADDI:
+ return Inst.getOperand(1).isReg() &&
+ Inst.getOperand(1).getReg() == RISCV::X0 &&
+ Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == 0;
+ case RISCV::C_LI:
+ return Inst.getOperand(1).isImm() && Inst.getOperand(1).getImm() == 0;
+ default:
+ return false;
+ }
}
BitVector getRegsUsedAsParams() const override {
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index aaaa25444839d..4e666d4ac3399 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -943,6 +943,25 @@ TEST_P(MCPlusBuilderTester, RISCV_isCleanReg) {
MCInstBuilder(RISCV::ADDI).addReg(RISCV::X5).addReg(RISCV::X0).addImm(1);
EXPECT_FALSE(BC->MIB->isCleanReg(NonZeroImmediate));
+ MCInst CompressedLI = MCInstBuilder(RISCV::C_LI).addReg(RISCV::X5).addImm(0);
+ EXPECT_TRUE(BC->MIB->isCleanReg(CompressedLI));
+
+ for (int64_t Imm : {-32, -1, 1, 31}) {
+ MCInst NonZeroCompressedLI =
+ MCInstBuilder(RISCV::C_LI).addReg(RISCV::X5).addImm(Imm);
+ EXPECT_FALSE(BC->MIB->isCleanReg(NonZeroCompressedLI));
+ }
+
+ MCInst CompressedLIWithExpr =
+ MCInstBuilder(RISCV::C_LI)
+ .addReg(RISCV::X5)
+ .addExpr(MCSymbolRefExpr::create(BB->getLabel(), *BC->Ctx));
+ EXPECT_FALSE(BC->MIB->isCleanReg(CompressedLIWithExpr));
+
+ MCInst CompressedMV =
+ MCInstBuilder(RISCV::C_MV).addReg(RISCV::X5).addReg(RISCV::X6);
+ EXPECT_FALSE(BC->MIB->isCleanReg(CompressedMV));
+
MCInst XOR = MCInstBuilder(RISCV::XOR)
.addReg(RISCV::X5)
.addReg(RISCV::X6)
More information about the llvm-commits
mailing list