Skip to content

Commit 2472cdc

Browse files
authored
[InstCombine] Refine nuw propagation in OptimizePointerDifference (#147059)
After #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
1 parent fd5ed04 commit 2472cdc

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,10 +2164,14 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS,
21642164

21652165
// If this is a single inbounds GEP and the original sub was nuw,
21662166
// then the final multiplication is also nuw.
2167-
if (auto *I = dyn_cast<Instruction>(Result))
2167+
if (auto *I = dyn_cast<OverflowingBinaryOperator>(Result))
21682168
if (IsNUW && match(Offset2, m_Zero()) && Base.LHSNW.isInBounds() &&
2169-
I->getOpcode() == Instruction::Mul)
2170-
I->setHasNoUnsignedWrap();
2169+
(I->use_empty() || I->hasOneUse()) && I->hasNoSignedWrap() &&
2170+
!I->hasNoUnsignedWrap() &&
2171+
((I->getOpcode() == Instruction::Mul &&
2172+
match(I->getOperand(1), m_NonNegative())) ||
2173+
I->getOpcode() == Instruction::Shl))
2174+
cast<Instruction>(I)->setHasNoUnsignedWrap();
21712175

21722176
// If we have a 2nd GEP of the same base pointer, subtract the offsets.
21732177
// If both GEPs are inbounds, then the subtract does not have signed overflow.

llvm/test/Transforms/InstCombine/sub-gep.ll

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,3 +1089,72 @@ define <2 x i64> @splat_geps_multiple(ptr %base, i64 %idx0, <2 x i64> %idx1, <2
10891089
%d = sub <2 x i64> %gep2.int, %gep1.int
10901090
ret <2 x i64> %d
10911091
}
1092+
1093+
define i64 @nuw_ptrdiff_shl_nsw(ptr %base, i64 %idx) {
1094+
; CHECK-LABEL: @nuw_ptrdiff_shl_nsw(
1095+
; CHECK-NEXT: [[OFFSET:%.*]] = shl nuw nsw i64 [[IDX:%.*]], 3
1096+
; CHECK-NEXT: ret i64 [[OFFSET]]
1097+
;
1098+
%offset = shl nsw i64 %idx, 3
1099+
%gep = getelementptr inbounds i8, ptr %base, i64 %offset
1100+
%lhs = ptrtoint ptr %gep to i64
1101+
%rhs = ptrtoint ptr %base to i64
1102+
%diff = sub nuw i64 %lhs, %rhs
1103+
ret i64 %diff
1104+
}
1105+
1106+
define i64 @nuw_ptrdiff_shl_nonsw(ptr %base, i64 %idx) {
1107+
; CHECK-LABEL: @nuw_ptrdiff_shl_nonsw(
1108+
; CHECK-NEXT: [[OFFSET:%.*]] = shl i64 [[IDX:%.*]], 3
1109+
; CHECK-NEXT: ret i64 [[OFFSET]]
1110+
;
1111+
%offset = shl i64 %idx, 3
1112+
%gep = getelementptr inbounds i8, ptr %base, i64 %offset
1113+
%lhs = ptrtoint ptr %gep to i64
1114+
%rhs = ptrtoint ptr %base to i64
1115+
%diff = sub nuw i64 %lhs, %rhs
1116+
ret i64 %diff
1117+
}
1118+
1119+
define i64 @nuw_ptrdiff_mul_nsw_nneg_scale(ptr %base, i64 %idx) {
1120+
; CHECK-LABEL: @nuw_ptrdiff_mul_nsw_nneg_scale(
1121+
; CHECK-NEXT: [[OFFSET:%.*]] = mul nuw nsw i64 [[IDX:%.*]], 3
1122+
; CHECK-NEXT: ret i64 [[OFFSET]]
1123+
;
1124+
%offset = mul nsw i64 %idx, 3
1125+
%gep = getelementptr inbounds i8, ptr %base, i64 %offset
1126+
%lhs = ptrtoint ptr %gep to i64
1127+
%rhs = ptrtoint ptr %base to i64
1128+
%diff = sub nuw i64 %lhs, %rhs
1129+
ret i64 %diff
1130+
}
1131+
1132+
define i64 @nuw_ptrdiff_mul_nsw_unknown_scale(ptr %base, i64 %idx, i64 %scale) {
1133+
; CHECK-LABEL: @nuw_ptrdiff_mul_nsw_unknown_scale(
1134+
; CHECK-NEXT: [[OFFSET:%.*]] = mul nsw i64 [[IDX:%.*]], [[SCALE:%.*]]
1135+
; CHECK-NEXT: ret i64 [[OFFSET]]
1136+
;
1137+
%offset = mul nsw i64 %idx, %scale
1138+
%gep = getelementptr inbounds i8, ptr %base, i64 %offset
1139+
%lhs = ptrtoint ptr %gep to i64
1140+
%rhs = ptrtoint ptr %base to i64
1141+
%diff = sub nuw i64 %lhs, %rhs
1142+
ret i64 %diff
1143+
}
1144+
1145+
declare void @usei64(i64)
1146+
1147+
define i64 @nuw_ptrdiff_mul_nsw_nneg_scale_multiuse(ptr %base, i64 %idx) {
1148+
; CHECK-LABEL: @nuw_ptrdiff_mul_nsw_nneg_scale_multiuse(
1149+
; CHECK-NEXT: [[OFFSET:%.*]] = mul nsw i64 [[IDX:%.*]], 3
1150+
; CHECK-NEXT: call void @usei64(i64 [[OFFSET]])
1151+
; CHECK-NEXT: ret i64 [[OFFSET]]
1152+
;
1153+
%offset = mul nsw i64 %idx, 3
1154+
call void @usei64(i64 %offset)
1155+
%gep = getelementptr inbounds i8, ptr %base, i64 %offset
1156+
%lhs = ptrtoint ptr %gep to i64
1157+
%rhs = ptrtoint ptr %base to i64
1158+
%diff = sub nuw i64 %lhs, %rhs
1159+
ret i64 %diff
1160+
}

0 commit comments

Comments
 (0)