[GuardWidening] Remove nuw/nsw flags for hoisted instructions

When we hoist instructions over guard we must clear flags due to these flags
might be implied using this guard, so they make sense only after the guard.

As an example of the bug due to current behavior.
L is known to be in range say [0, 100)
c1 = x u< L
guard (c1)
x1 = add x, 1
c2 = x1 u< L
guard(c2)

basing on guard(c1) we can say that x1 = add nuw nsw x, 1
after guard widening we get
c1 = x u< L
x1 = add nuw nsw x, 1
c2 = x1 u< L
c = and c1, c2
guard(c)

now, basing on fact that x + 1 < L and x >= 0 due to x + 1 is nuw
we can prove that x + 1 u< L implies that x u< L, so we can just remove c1
x1 = add nuw nsw x, 1
c2 = x1 u< L
guard(c2)

But that is not correct due to we will pass x == -1 value.

Reviewed By: mkazantsev
Subscribers: llvm-commits, nikic
Differential Revision: https://reviews.llvm.org/D126354
This commit is contained in:
Serguei Katkov
2022-05-25 13:37:06 +07:00
parent fb67d683db
commit c2eccc67ce
2 changed files with 4 additions and 1 deletions

View File

@@ -495,6 +495,9 @@ void GuardWideningImpl::makeAvailableAt(Value *V, Instruction *Loc) const {
makeAvailableAt(Op, Loc);
Inst->moveBefore(Loc);
// If we moved instruction before guard we must clean nuw, nsw flags.
Inst->setHasNoUnsignedWrap(false);
Inst->setHasNoSignedWrap(false);
}
bool GuardWideningImpl::widenCondCommon(Value *Cond0, Value *Cond1,

View File

@@ -340,7 +340,7 @@ define void @f_8(i32 %x, i32* %length_buf) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
; CHECK-NEXT: [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
; CHECK-NEXT: [[X_INC1:%.*]] = add nuw nsw i32 [[X]], 1
; CHECK-NEXT: [[X_INC1:%.*]] = add i32 [[X]], 1
; CHECK-NEXT: [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]