[llvm] [NewPM] Extract logic for X86 SLH into a separate class (PR #175718)
Anshul Nigham via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 13 11:04:44 PST 2026
https://github.com/nigham updated https://github.com/llvm/llvm-project/pull/175718
>From 9422307d33f72977e8a1bb2a55b6907aa42c554c Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Mon, 12 Jan 2026 23:09:24 -0800
Subject: [PATCH 1/5] Extract logic for X86 SLH into a separate class to enable
New PM migration.
---
.../X86/X86SpeculativeLoadHardening.cpp | 77 +++++++++++--------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
index 829a32eb37118..4461091b0ba49 100644
--- a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
+++ b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
@@ -129,6 +129,18 @@ class X86SpeculativeLoadHardeningPass : public MachineFunctionPass {
/// Pass identification, replacement for typeid.
static char ID;
+};
+
+class X86SpeculativeLoadHardeningImpl {
+public:
+ X86SpeculativeLoadHardeningImpl(MachineFunction &MFn) : MF(MFn) {
+ Subtarget = &MF.getSubtarget<X86Subtarget>();
+ MRI = &MF.getRegInfo();
+ TII = Subtarget->getInstrInfo();
+ TRI = Subtarget->getRegisterInfo();
+ }
+
+ bool run();
private:
/// The information about a block's conditional terminators needed to trace
@@ -155,6 +167,8 @@ class X86SpeculativeLoadHardeningPass : public MachineFunctionPass {
: RC(RC), SSA(MF) {}
};
+ MachineFunction &MF;
+
const X86Subtarget *Subtarget = nullptr;
MachineRegisterInfo *MRI = nullptr;
const X86InstrInfo *TII = nullptr;
@@ -211,6 +225,18 @@ class X86SpeculativeLoadHardeningPass : public MachineFunctionPass {
} // end anonymous namespace
+bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
+ MachineFunction &MF) {
+ LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
+ << " **********\n");
+
+ X86SpeculativeLoadHardeningImpl impl(MF);
+ bool ret = impl.run();
+ LLVM_DEBUG(dbgs() << "Final speculative load hardened function:\n"; MF.dump();
+ dbgs() << "\n"; MF.verify(this));
+ return ret;
+}
+
char X86SpeculativeLoadHardeningPass::ID = 0;
void X86SpeculativeLoadHardeningPass::getAnalysisUsage(
@@ -392,22 +418,13 @@ static bool hasVulnerableLoad(MachineFunction &MF) {
return false;
}
-bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
- MachineFunction &MF) {
- LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
- << " **********\n");
-
+bool X86SpeculativeLoadHardeningImpl::run() {
// Only run if this pass is forced enabled or we detect the relevant function
// attribute requesting SLH.
if (!EnableSpeculativeLoadHardening &&
!MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening))
return false;
- Subtarget = &MF.getSubtarget<X86Subtarget>();
- MRI = &MF.getRegInfo();
- TII = Subtarget->getInstrInfo();
- TRI = Subtarget->getRegisterInfo();
-
// FIXME: Support for 32-bit.
PS.emplace(MF, &X86::GR64_NOSPRegClass);
@@ -549,8 +566,6 @@ bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
PS->SSA.RewriteUse(Op);
}
- LLVM_DEBUG(dbgs() << "Final speculative load hardened function:\n"; MF.dump();
- dbgs() << "\n"; MF.verify(this));
return true;
}
@@ -560,7 +575,7 @@ bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
/// We include this as an alternative mostly for the purpose of comparison. The
/// performance impact of this is expected to be extremely severe and not
/// practical for any real-world users.
-void X86SpeculativeLoadHardeningPass::hardenEdgesWithLFENCE(
+void X86SpeculativeLoadHardeningImpl::hardenEdgesWithLFENCE(
MachineFunction &MF) {
// First, we scan the function looking for blocks that are reached along edges
// that we might want to harden.
@@ -592,8 +607,8 @@ void X86SpeculativeLoadHardeningPass::hardenEdgesWithLFENCE(
}
}
-SmallVector<X86SpeculativeLoadHardeningPass::BlockCondInfo, 16>
-X86SpeculativeLoadHardeningPass::collectBlockCondInfo(MachineFunction &MF) {
+SmallVector<X86SpeculativeLoadHardeningImpl::BlockCondInfo, 16>
+X86SpeculativeLoadHardeningImpl::collectBlockCondInfo(MachineFunction &MF) {
SmallVector<BlockCondInfo, 16> Infos;
// Walk the function and build up a summary for each block's conditions that
@@ -685,7 +700,7 @@ X86SpeculativeLoadHardeningPass::collectBlockCondInfo(MachineFunction &MF) {
/// uses of the predicate state rewritten into proper SSA form once it is
/// complete.
SmallVector<MachineInstr *, 16>
-X86SpeculativeLoadHardeningPass::tracePredStateThroughCFG(
+X86SpeculativeLoadHardeningImpl::tracePredStateThroughCFG(
MachineFunction &MF, ArrayRef<BlockCondInfo> Infos) {
// Collect the inserted cmov instructions so we can rewrite their uses of the
// predicate state into SSA form.
@@ -843,7 +858,7 @@ getRegClassForUnfoldedLoad(const X86InstrInfo &TII, unsigned Opcode) {
return TII.getRegClass(MCID, Index);
}
-void X86SpeculativeLoadHardeningPass::unfoldCallAndJumpLoads(
+void X86SpeculativeLoadHardeningImpl::unfoldCallAndJumpLoads(
MachineFunction &MF) {
for (MachineBasicBlock &MBB : MF)
// We use make_early_inc_range here so we can remove instructions if needed
@@ -954,7 +969,7 @@ void X86SpeculativeLoadHardeningPass::unfoldCallAndJumpLoads(
/// calls, however, cannot be mitigated through this technique without changing
/// the ABI in a fundamental way.
SmallVector<MachineInstr *, 16>
-X86SpeculativeLoadHardeningPass::tracePredStateThroughIndirectBranches(
+X86SpeculativeLoadHardeningImpl::tracePredStateThroughIndirectBranches(
MachineFunction &MF) {
// We use the SSAUpdater to insert PHI nodes for the target addresses of
// indirect branches. We don't actually need the full power of the SSA updater
@@ -1258,7 +1273,7 @@ static bool isEFLAGSLive(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
///
/// These two passes are applied to each basic block. We operate one block at a
/// time to simplify reasoning about reachability and sequencing.
-void X86SpeculativeLoadHardeningPass::tracePredStateThroughBlocksAndHarden(
+void X86SpeculativeLoadHardeningImpl::tracePredStateThroughBlocksAndHarden(
MachineFunction &MF) {
SmallPtrSet<MachineInstr *, 16> HardenPostLoad;
SmallPtrSet<MachineInstr *, 16> HardenLoadAddr;
@@ -1487,7 +1502,7 @@ void X86SpeculativeLoadHardeningPass::tracePredStateThroughBlocksAndHarden(
/// Note that LLVM can only lower very simple patterns of saved and restored
/// EFLAGS registers. The restore should always be within the same basic block
/// as the save so that no PHI nodes are inserted.
-Register X86SpeculativeLoadHardeningPass::saveEFLAGS(
+Register X86SpeculativeLoadHardeningImpl::saveEFLAGS(
MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertPt,
const DebugLoc &Loc) {
// FIXME: Hard coding this to a 32-bit register class seems weird, but matches
@@ -1505,7 +1520,7 @@ Register X86SpeculativeLoadHardeningPass::saveEFLAGS(
///
/// This must be done within the same basic block as the save in order to
/// reliably lower.
-void X86SpeculativeLoadHardeningPass::restoreEFLAGS(
+void X86SpeculativeLoadHardeningImpl::restoreEFLAGS(
MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertPt,
const DebugLoc &Loc, Register Reg) {
BuildMI(MBB, InsertPt, Loc, TII->get(X86::COPY), X86::EFLAGS).addReg(Reg);
@@ -1516,7 +1531,7 @@ void X86SpeculativeLoadHardeningPass::restoreEFLAGS(
/// stack pointer. The state is essentially a single bit, but we merge this in
/// a way that won't form non-canonical pointers and also will be preserved
/// across normal stack adjustments.
-void X86SpeculativeLoadHardeningPass::mergePredStateIntoSP(
+void X86SpeculativeLoadHardeningImpl::mergePredStateIntoSP(
MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertPt,
const DebugLoc &Loc, Register PredStateReg) {
Register TmpReg = MRI->createVirtualRegister(PS->RC);
@@ -1536,7 +1551,7 @@ void X86SpeculativeLoadHardeningPass::mergePredStateIntoSP(
}
/// Extracts the predicate state stored in the high bits of the stack pointer.
-Register X86SpeculativeLoadHardeningPass::extractPredStateFromSP(
+Register X86SpeculativeLoadHardeningImpl::extractPredStateFromSP(
MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertPt,
const DebugLoc &Loc) {
Register PredStateReg = MRI->createVirtualRegister(PS->RC);
@@ -1557,7 +1572,7 @@ Register X86SpeculativeLoadHardeningPass::extractPredStateFromSP(
return PredStateReg;
}
-void X86SpeculativeLoadHardeningPass::hardenLoadAddr(
+void X86SpeculativeLoadHardeningImpl::hardenLoadAddr(
MachineInstr &MI, MachineOperand &BaseMO, MachineOperand &IndexMO,
SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg) {
MachineBasicBlock &MBB = *MI.getParent();
@@ -1759,7 +1774,7 @@ void X86SpeculativeLoadHardeningPass::hardenLoadAddr(
restoreEFLAGS(MBB, InsertPt, Loc, FlagsReg);
}
-MachineInstr *X86SpeculativeLoadHardeningPass::sinkPostLoadHardenedInst(
+MachineInstr *X86SpeculativeLoadHardeningImpl::sinkPostLoadHardenedInst(
MachineInstr &InitialMI, SmallPtrSetImpl<MachineInstr *> &HardenedInstrs) {
assert(X86InstrInfo::isDataInvariantLoad(InitialMI) &&
"Cannot get here with a non-invariant load!");
@@ -1849,7 +1864,7 @@ MachineInstr *X86SpeculativeLoadHardeningPass::sinkPostLoadHardenedInst(
return MI;
}
-bool X86SpeculativeLoadHardeningPass::canHardenRegister(Register Reg) {
+bool X86SpeculativeLoadHardeningImpl::canHardenRegister(Register Reg) {
// We only support hardening virtual registers.
if (!Reg.isVirtual())
return false;
@@ -1896,7 +1911,7 @@ bool X86SpeculativeLoadHardeningPass::canHardenRegister(Register Reg) {
///
/// The new, hardened virtual register is returned. It will have the same
/// register class as `Reg`.
-Register X86SpeculativeLoadHardeningPass::hardenValueInRegister(
+Register X86SpeculativeLoadHardeningImpl::hardenValueInRegister(
Register Reg, MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertPt,
const DebugLoc &Loc) {
assert(canHardenRegister(Reg) && "Cannot harden this register!");
@@ -1946,7 +1961,7 @@ Register X86SpeculativeLoadHardeningPass::hardenValueInRegister(
/// execution and coercing them to one is sufficient.
///
/// Returns the newly hardened register.
-Register X86SpeculativeLoadHardeningPass::hardenPostLoad(MachineInstr &MI) {
+Register X86SpeculativeLoadHardeningImpl::hardenPostLoad(MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
const DebugLoc &Loc = MI.getDebugLoc();
@@ -1997,7 +2012,7 @@ Register X86SpeculativeLoadHardeningPass::hardenPostLoad(MachineInstr &MI) {
/// speculatively even during a BCBS-attacked return until the steering takes
/// effect. Whenever this happens, the caller can recover the (poisoned)
/// predicate state from the stack pointer and continue to harden loads.
-void X86SpeculativeLoadHardeningPass::hardenReturnInstr(MachineInstr &MI) {
+void X86SpeculativeLoadHardeningImpl::hardenReturnInstr(MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
const DebugLoc &Loc = MI.getDebugLoc();
auto InsertPt = MI.getIterator();
@@ -2043,7 +2058,7 @@ void X86SpeculativeLoadHardeningPass::hardenReturnInstr(MachineInstr &MI) {
/// immediately following the call (the observed return address). If these
/// mismatch, we have detected misspeculation and can poison our predicate
/// state.
-void X86SpeculativeLoadHardeningPass::tracePredStateThroughCall(
+void X86SpeculativeLoadHardeningImpl::tracePredStateThroughCall(
MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MBB.getParent();
@@ -2203,7 +2218,7 @@ void X86SpeculativeLoadHardeningPass::tracePredStateThroughCall(
/// execution. We forcibly unfolded all relevant loads above and so will always
/// have an opportunity to post-load harden here, we just need to scan for cases
/// not already flagged and add them.
-void X86SpeculativeLoadHardeningPass::hardenIndirectCallOrJumpInstr(
+void X86SpeculativeLoadHardeningImpl::hardenIndirectCallOrJumpInstr(
MachineInstr &MI,
SmallDenseMap<Register, Register, 32> &AddrRegToHardenedReg) {
switch (MI.getOpcode()) {
>From 315951fa3bc8e51e183af68ceb16c8a13d4a7c78 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Tue, 13 Jan 2026 08:42:56 -0800
Subject: [PATCH 2/5] Fix case typo
---
llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
index 4461091b0ba49..095784643e38b 100644
--- a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
+++ b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
@@ -230,8 +230,8 @@ bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
<< " **********\n");
- X86SpeculativeLoadHardeningImpl impl(MF);
- bool ret = impl.run();
+ X86SpeculativeLoadHardeningImpl Impl(MF);
+ bool ret = Impl.run();
LLVM_DEBUG(dbgs() << "Final speculative load hardened function:\n"; MF.dump();
dbgs() << "\n"; MF.verify(this));
return ret;
>From be246dca8b9421c54308fe810fe742752c29be86 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Tue, 13 Jan 2026 08:48:51 -0800
Subject: [PATCH 3/5] Pass MF pointer to run function
---
.../X86/X86SpeculativeLoadHardening.cpp | 22 +++++++++----------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
index 095784643e38b..b29e34e4370c4 100644
--- a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
+++ b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
@@ -133,14 +133,9 @@ class X86SpeculativeLoadHardeningPass : public MachineFunctionPass {
class X86SpeculativeLoadHardeningImpl {
public:
- X86SpeculativeLoadHardeningImpl(MachineFunction &MFn) : MF(MFn) {
- Subtarget = &MF.getSubtarget<X86Subtarget>();
- MRI = &MF.getRegInfo();
- TII = Subtarget->getInstrInfo();
- TRI = Subtarget->getRegisterInfo();
- }
+ X86SpeculativeLoadHardeningImpl() = default;
- bool run();
+ bool run(MachineFunction &MF);
private:
/// The information about a block's conditional terminators needed to trace
@@ -167,8 +162,6 @@ class X86SpeculativeLoadHardeningImpl {
: RC(RC), SSA(MF) {}
};
- MachineFunction &MF;
-
const X86Subtarget *Subtarget = nullptr;
MachineRegisterInfo *MRI = nullptr;
const X86InstrInfo *TII = nullptr;
@@ -230,8 +223,8 @@ bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
<< " **********\n");
- X86SpeculativeLoadHardeningImpl Impl(MF);
- bool ret = Impl.run();
+ X86SpeculativeLoadHardeningImpl Impl;
+ bool ret = Impl.run(MF);
LLVM_DEBUG(dbgs() << "Final speculative load hardened function:\n"; MF.dump();
dbgs() << "\n"; MF.verify(this));
return ret;
@@ -418,13 +411,18 @@ static bool hasVulnerableLoad(MachineFunction &MF) {
return false;
}
-bool X86SpeculativeLoadHardeningImpl::run() {
+bool X86SpeculativeLoadHardeningImpl::run(MachineFunction &MF) {
// Only run if this pass is forced enabled or we detect the relevant function
// attribute requesting SLH.
if (!EnableSpeculativeLoadHardening &&
!MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening))
return false;
+ Subtarget = &MF.getSubtarget<X86Subtarget>();
+ MRI = &MF.getRegInfo();
+ TII = Subtarget->getInstrInfo();
+ TRI = Subtarget->getRegisterInfo();
+
// FIXME: Support for 32-bit.
PS.emplace(MF, &X86::GR64_NOSPRegClass);
>From 5b74aa808ad915256bb7f7f00886a22bce5887a9 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Tue, 13 Jan 2026 11:03:01 -0800
Subject: [PATCH 4/5] Addressed review and style comments
---
.../Target/X86/X86SpeculativeLoadHardening.cpp | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
index b29e34e4370c4..42a802d42040e 100644
--- a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
+++ b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
@@ -117,12 +117,16 @@ static cl::opt<bool> HardenIndirectCallsAndJumps(
namespace {
+StringRef getX86SLHPassName() {
+ return "X86 speculative load hardening";
+}
+
class X86SpeculativeLoadHardeningPass : public MachineFunctionPass {
public:
X86SpeculativeLoadHardeningPass() : MachineFunctionPass(ID) { }
StringRef getPassName() const override {
- return "X86 speculative load hardening";
+ return getX86SLHPassName();
}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
@@ -220,14 +224,11 @@ class X86SpeculativeLoadHardeningImpl {
bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
MachineFunction &MF) {
- LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
- << " **********\n");
-
X86SpeculativeLoadHardeningImpl Impl;
- bool ret = Impl.run(MF);
+ bool Result = Impl.run(MF);
LLVM_DEBUG(dbgs() << "Final speculative load hardened function:\n"; MF.dump();
dbgs() << "\n"; MF.verify(this));
- return ret;
+ return Result;
}
char X86SpeculativeLoadHardeningPass::ID = 0;
@@ -412,6 +413,9 @@ static bool hasVulnerableLoad(MachineFunction &MF) {
}
bool X86SpeculativeLoadHardeningImpl::run(MachineFunction &MF) {
+ LLVM_DEBUG(dbgs() << "********** " << getX86SLHPassName() << " : " << MF.getName()
+ << " **********\n");
+
// Only run if this pass is forced enabled or we detect the relevant function
// attribute requesting SLH.
if (!EnableSpeculativeLoadHardening &&
>From 295ef43bec27234dc4d83ad42e78cc2026da8512 Mon Sep 17 00:00:00 2001
From: Anshul Nigham <nigham at google.com>
Date: Tue, 13 Jan 2026 11:04:25 -0800
Subject: [PATCH 5/5] Update varname
---
llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
index 42a802d42040e..a167d58194e80 100644
--- a/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
+++ b/llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
@@ -225,10 +225,10 @@ class X86SpeculativeLoadHardeningImpl {
bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
MachineFunction &MF) {
X86SpeculativeLoadHardeningImpl Impl;
- bool Result = Impl.run(MF);
+ bool Changed = Impl.run(MF);
LLVM_DEBUG(dbgs() << "Final speculative load hardened function:\n"; MF.dump();
dbgs() << "\n"; MF.verify(this));
- return Result;
+ return Changed;
}
char X86SpeculativeLoadHardeningPass::ID = 0;
More information about the llvm-commits
mailing list