[llvm] [VPlan] Lower safe uniform load to unconditional scalar load (PR #216767)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 04:22:37 PDT 2026


================
@@ -5499,6 +5480,29 @@ void VPlanTransforms::makeMemOpWideningDecisions(VPlan &Plan, VFRange &Range,
         return ReplaceWith(VPI, StoreR);
       });
 
+  // Lower safe uniform (potentially masked) loads to unconditional scalar
+  // loads.
+  VPlanTransforms::runPass(
+      "lowerSafeUniformLoads", ProcessSubset, Plan, [&](VPInstruction *VPI) {
+        if (VPI->getOpcode() != Instruction::Load)
+          return false;
+        VPValue *Addr = VPI->getOperand(0);
+        if (!vputils::isUniformAcrossVFsAndUFs(Addr))
+          return false;
+        auto &LI = cast<LoadInst>(*VPI->getUnderlyingInstr());
+        Value *Underlying = Addr->getUnderlyingValue();
+        if (!Underlying || !isSafeToLoadUnconditionally(
+                               Underlying, LI.getType(), LI.getAlign(),
+                               Plan.getDataLayout(), &LI,
+                               /*AC=*/nullptr, /*DT=*/nullptr, &CostCtx.TLI))
+          return false;
----------------
lukel97 wrote:

Is it safe to use this underlying value based analysis here? I think isSafeToLoadUnconditionally scans the underlying basic block to see if another load was already performed at that address and allows it if there is one. In this example it sees that `%a` is in the same block as `%b` so `%b` gets transformed to an unconditional load even though it needs to be masked by `%cmp`:

```llvm
define void @load_safe_only_via_predicated_load(ptr noalias %out, ptr noalias %cond, ptr %p, i64 %n) {
entry:
  br label %loop

loop:
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
  %cond.gep = getelementptr inbounds i32, ptr %cond, i64 %iv
  %c = load i32, ptr %cond.gep, align 4
  %cmp = icmp ne i32 %c, 0
  br i1 %cmp, label %if.then, label %latch

if.then:
  %a = load i32, ptr %p, align 4
  %b = load i32, ptr %p, align 4
  %sum = add i32 %a, %b
  %out.gep = getelementptr inbounds i32, ptr %out, i64 %iv
  store i32 %sum, ptr %out.gep, align 4
  br label %latch

latch:
  %iv.next = add nuw nsw i64 %iv, 1
  %ec = icmp eq i64 %iv.next, %n
  br i1 %ec, label %exit, label %loop

exit:
  ret void
}
```

I think we can probably use `isDereferenceableAndAlignedInLoop` since that operates on SCEVs only and doesn't check the underlying value

https://github.com/llvm/llvm-project/pull/216767


More information about the llvm-commits mailing list