[llvm] [ConstraintElim] Do not model negative nuw-only GEP offset as signed. (PR #203620)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 13:03:28 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

decomposeGEP added the GEP's constant offset to the unsigned decomposition using its signed value (getSExtValue()). For a GEP that only carries nuw (without nusw/inbounds), the indices must be interpreted as unsigned.

Alive2 Proof of mis-compile https://alive2.llvm.org/ce/z/7G8uE3

---
Full diff: https://github.com/llvm/llvm-project/pull/203620.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (+6) 
- (modified) llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll (+2-2) 


``````````diff
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 4bb49d61f3617..4974764163c4c 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -462,6 +462,12 @@ static Decomposition decomposeGEP(GEPOperator &GEP,
   if (!BasePtr || NW == GEPNoWrapFlags::none())
     return &GEP;
 
+  // For a nuw-only GEP (nuw without nusw/inbounds), the offset must be
+  // interpreted as unsigned.
+  if (NW.hasNoUnsignedWrap() && !NW.hasNoUnsignedSignedWrap() &&
+      ConstantOffset.isNegative())
+    return &GEP;
+
   Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
   for (auto [Index, Scale] : VariableOffsets) {
     auto IdxResult = decompose(Index, Preconditions, IsSigned, DL);
diff --git a/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll b/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
index 28266857085bc..612bf2f0a8337 100644
--- a/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
+++ b/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
@@ -650,11 +650,11 @@ trap:
 
 declare void @use(i1)
 
-; FIXME: Currently incorrectly simplified to true.
 define i1 @gep_nuw_negative_offset_unsigned(ptr %p) {
 ; CHECK-LABEL: @gep_nuw_negative_offset_unsigned(
 ; CHECK-NEXT:    [[P2:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 -100
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[C:%.*]] = icmp ult ptr [[P2]], [[P]]
+; CHECK-NEXT:    ret i1 [[C]]
 ;
   %p2 = getelementptr nuw i8, ptr %p, i64 -100
   %c = icmp ult ptr %p2, %p

``````````

</details>


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


More information about the llvm-commits mailing list