[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