[llvm] [LoopVersioningLICM] Do not let llvm.pseudoprobe block loop versioning (PR #209684)
chandan singh via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 23:53:04 PDT 2026
https://github.com/chandankds updated https://github.com/llvm/llvm-project/pull/209684
>From 53a16880763c0b57c74a093e26bec8a1ceef148e Mon Sep 17 00:00:00 2001
From: chandankds <chandankds at gmail.com>
Date: Thu, 16 Jul 2026 12:38:38 +0000
Subject: [PATCH] [LoopVersioningLICM] Do not let llvm.pseudoprobe block loop
versioning
LoopVersioningLICM::instructionSafeForVersioning() rejects any call that is
not proven to not access memory. llvm.pseudoprobe is declared
IntrInaccessibleMemOnly (so the optimizer will not delete or sink it), so
AA->doesNotAccessMemory() returns false and the probe is treated as an unsafe
call site. This disables loop-versioning LICM for essentially every hot loop
in a sample-based / CSSPGO profile-guided build (-fpseudo-probe-for-profiling),
since a pseudo probe is inserted on every basic block.
Pseudo probes are pure profiling placeholders with no observable effect on the
loop's memory accesses, so skip them in the call-safety check.
RFC: https://discourse.llvm.org/t/csspgo-unblocking-pseudo-probe-safe-optimizations/90946
---
.../Transforms/Scalar/LoopVersioningLICM.cpp | 14 +++++++
.../LoopVersioningLICM/pseudoprobe.ll | 40 +++++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 llvm/test/Transforms/LoopVersioningLICM/pseudoprobe.ll
diff --git a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
index 3aed643ee8065..7ed7714e23e19 100644
--- a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
@@ -303,11 +303,25 @@ bool LoopVersioningLICM::instructionSafeForVersioning(Instruction *I) {
assert(I != nullptr && "Null instruction found!");
// Check function call safety
if (auto *Call = dyn_cast<CallBase>(I)) {
+ // Debug info and pseudo-probe intrinsics are placeholders with no
+ // observable effect on the loop's memory accesses. Ignore them so that
+ // their presence (in the presence of -fpseudo-probe-for-profiling) does not
+ // block loop versioning.
+ if (Call->isDebugOrPseudoInst())
+ return true;
+
if (Call->isConvergent() || Call->cannotDuplicate()) {
LLVM_DEBUG(dbgs() << " Convergent call site found.\n");
return false;
}
+ // A call that may not return is not
+ // safe to version.
+ if (!Call->willReturn()) {
+ LLVM_DEBUG(dbgs() << " Call site that may not return found.\n");
+ return false;
+ }
+
if (!AA->doesNotAccessMemory(Call)) {
LLVM_DEBUG(dbgs() << " Unsafe call site found.\n");
return false;
diff --git a/llvm/test/Transforms/LoopVersioningLICM/pseudoprobe.ll b/llvm/test/Transforms/LoopVersioningLICM/pseudoprobe.ll
new file mode 100644
index 0000000000000..1146409fea716
--- /dev/null
+++ b/llvm/test/Transforms/LoopVersioningLICM/pseudoprobe.ll
@@ -0,0 +1,40 @@
+; RUN: opt %s -passes='loop(loop-versioning-licm)' -S | FileCheck %s
+;
+; LoopVersioningLICM must not refuse to version a loop solely because of a
+; llvm.pseudoprobe intrinsic call in the loop body. Pseudo probes are inserted
+; on every block under sample-based profiling (in the presence of
+; -fpseudo-probe-for-profiling); they are placeholders with no observable effect
+; on the loop's memory accesses, so they must not block versioning.
+
+; A loop containing an llvm.pseudoprobe intrinsic is still versioned.
+; CHECK-LABEL: @test_pseudoprobe_lvlicm(
+; CHECK: lver.check
+define double @test_pseudoprobe_lvlicm(ptr %x, ptr %y, i32 %n) {
+entry:
+ %cmp = icmp sgt i32 %n, 0
+ br i1 %cmp, label %ph, label %exit
+
+ph: ; preds = %entry
+ br label %body
+
+body: ; preds = %body, %ph
+ %i = phi i32 [ 0, %ph ], [ %inext, %body ]
+ %sum = phi double [ 0.000000e+00, %ph ], [ %sumnext, %body ]
+ %yidx = getelementptr inbounds double, ptr %y, i32 %i
+ %yv = load double, ptr %yidx, align 8
+ %add = fadd double %yv, 1.000000e+00
+ %xidx = getelementptr inbounds double, ptr %x, i32 %i
+ store double %add, ptr %xidx, align 8
+ %x0 = load double, ptr %x, align 8 ; loop-invariant load
+ %sumnext = fadd double %sum, %x0
+ call void @llvm.pseudoprobe(i64 1234, i64 1, i32 0, i64 -1)
+ %inext = add nuw nsw i32 %i, 1
+ %exitcond = icmp eq i32 %inext, %n
+ br i1 %exitcond, label %exit, label %body
+
+exit: ; preds = %body, %entry
+ %sumlcssa = phi double [ 0.000000e+00, %entry ], [ %sumnext, %body ]
+ ret double %sumlcssa
+}
+
+declare void @llvm.pseudoprobe(i64, i64, i32, i64)
More information about the llvm-commits
mailing list