[llvm] 2472cdc - [InstCombine] Refine nuw propagation in `OptimizePointerDifference` (#147059)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 4 08:34:36 PDT 2025
Author: Yingwei Zheng
Date: 2025-07-04T23:34:33+08:00
New Revision: 2472cdcb69d2fe0ff3573403be1bd49eb2d62dd8
URL: https://github.com/llvm/llvm-project/commit/2472cdcb69d2fe0ff3573403be1bd49eb2d62dd8
DIFF: https://github.com/llvm/llvm-project/commit/2472cdcb69d2fe0ff3573403be1bd49eb2d62dd8.diff
LOG: [InstCombine] Refine nuw propagation in `OptimizePointerDifference` (#147059)
After https://github.com/llvm/llvm-project/pull/146100, the offset may
be generated by a previous call to `EmitGEPOffsets`, causing the nuw
flag on shl to be lost. This patch handles the `shl+ptradd` case as
well. It also fixes a miscompilation in the case of `mul + ptradd`.
Alive2: https://alive2.llvm.org/ce/z/BeaNzE
This patch removes many unnecessary masking operations in Rust programs
with the `ptr_offset_from_unsigned` intrinsic :
https://github.com/dtcxzyw/llvm-opt-benchmark/pull/2538/files
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/sub-gep.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index f727eb0a63e05..1ba548b6ff062 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2164,10 +2164,14 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS,
// If this is a single inbounds GEP and the original sub was nuw,
// then the final multiplication is also nuw.
- if (auto *I = dyn_cast<Instruction>(Result))
+ if (auto *I = dyn_cast<OverflowingBinaryOperator>(Result))
if (IsNUW && match(Offset2, m_Zero()) && Base.LHSNW.isInBounds() &&
- I->getOpcode() == Instruction::Mul)
- I->setHasNoUnsignedWrap();
+ (I->use_empty() || I->hasOneUse()) && I->hasNoSignedWrap() &&
+ !I->hasNoUnsignedWrap() &&
+ ((I->getOpcode() == Instruction::Mul &&
+ match(I->getOperand(1), m_NonNegative())) ||
+ I->getOpcode() == Instruction::Shl))
+ cast<Instruction>(I)->setHasNoUnsignedWrap();
// If we have a 2nd GEP of the same base pointer, subtract the offsets.
// If both GEPs are inbounds, then the subtract does not have signed overflow.
diff --git a/llvm/test/Transforms/InstCombine/sub-gep.ll b/llvm/test/Transforms/InstCombine/sub-gep.ll
index 993a06ad1780f..11af6b4a0197f 100644
--- a/llvm/test/Transforms/InstCombine/sub-gep.ll
+++ b/llvm/test/Transforms/InstCombine/sub-gep.ll
@@ -1089,3 +1089,72 @@ define <2 x i64> @splat_geps_multiple(ptr %base, i64 %idx0, <2 x i64> %idx1, <2
%d = sub <2 x i64> %gep2.int, %gep1.int
ret <2 x i64> %d
}
+
+define i64 @nuw_ptr
diff _shl_nsw(ptr %base, i64 %idx) {
+; CHECK-LABEL: @nuw_ptr
diff _shl_nsw(
+; CHECK-NEXT: [[OFFSET:%.*]] = shl nuw nsw i64 [[IDX:%.*]], 3
+; CHECK-NEXT: ret i64 [[OFFSET]]
+;
+ %offset = shl nsw i64 %idx, 3
+ %gep = getelementptr inbounds i8, ptr %base, i64 %offset
+ %lhs = ptrtoint ptr %gep to i64
+ %rhs = ptrtoint ptr %base to i64
+ %
diff = sub nuw i64 %lhs, %rhs
+ ret i64 %
diff
+}
+
+define i64 @nuw_ptr
diff _shl_nonsw(ptr %base, i64 %idx) {
+; CHECK-LABEL: @nuw_ptr
diff _shl_nonsw(
+; CHECK-NEXT: [[OFFSET:%.*]] = shl i64 [[IDX:%.*]], 3
+; CHECK-NEXT: ret i64 [[OFFSET]]
+;
+ %offset = shl i64 %idx, 3
+ %gep = getelementptr inbounds i8, ptr %base, i64 %offset
+ %lhs = ptrtoint ptr %gep to i64
+ %rhs = ptrtoint ptr %base to i64
+ %
diff = sub nuw i64 %lhs, %rhs
+ ret i64 %
diff
+}
+
+define i64 @nuw_ptr
diff _mul_nsw_nneg_scale(ptr %base, i64 %idx) {
+; CHECK-LABEL: @nuw_ptr
diff _mul_nsw_nneg_scale(
+; CHECK-NEXT: [[OFFSET:%.*]] = mul nuw nsw i64 [[IDX:%.*]], 3
+; CHECK-NEXT: ret i64 [[OFFSET]]
+;
+ %offset = mul nsw i64 %idx, 3
+ %gep = getelementptr inbounds i8, ptr %base, i64 %offset
+ %lhs = ptrtoint ptr %gep to i64
+ %rhs = ptrtoint ptr %base to i64
+ %
diff = sub nuw i64 %lhs, %rhs
+ ret i64 %
diff
+}
+
+define i64 @nuw_ptr
diff _mul_nsw_unknown_scale(ptr %base, i64 %idx, i64 %scale) {
+; CHECK-LABEL: @nuw_ptr
diff _mul_nsw_unknown_scale(
+; CHECK-NEXT: [[OFFSET:%.*]] = mul nsw i64 [[IDX:%.*]], [[SCALE:%.*]]
+; CHECK-NEXT: ret i64 [[OFFSET]]
+;
+ %offset = mul nsw i64 %idx, %scale
+ %gep = getelementptr inbounds i8, ptr %base, i64 %offset
+ %lhs = ptrtoint ptr %gep to i64
+ %rhs = ptrtoint ptr %base to i64
+ %
diff = sub nuw i64 %lhs, %rhs
+ ret i64 %
diff
+}
+
+declare void @usei64(i64)
+
+define i64 @nuw_ptr
diff _mul_nsw_nneg_scale_multiuse(ptr %base, i64 %idx) {
+; CHECK-LABEL: @nuw_ptr
diff _mul_nsw_nneg_scale_multiuse(
+; CHECK-NEXT: [[OFFSET:%.*]] = mul nsw i64 [[IDX:%.*]], 3
+; CHECK-NEXT: call void @usei64(i64 [[OFFSET]])
+; CHECK-NEXT: ret i64 [[OFFSET]]
+;
+ %offset = mul nsw i64 %idx, 3
+ call void @usei64(i64 %offset)
+ %gep = getelementptr inbounds i8, ptr %base, i64 %offset
+ %lhs = ptrtoint ptr %gep to i64
+ %rhs = ptrtoint ptr %base to i64
+ %
diff = sub nuw i64 %lhs, %rhs
+ ret i64 %
diff
+}
More information about the llvm-commits
mailing list