[LICM] Handle disjoint or's in hoistAdd (#182915)

`disjoint or` is identical to addition and there is no reason not to
handle it in `hoistAdd`.
This commit is contained in:
Valeriy Savchenko 2026-02-24 14:11:32 +00:00 committed by GitHub
parent e6962bd1bb
commit 2e40d2bc7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 118 additions and 4 deletions

View File

@ -2587,11 +2587,11 @@ static bool hoistAdd(ICmpInst::Predicate Pred, Value *VariantLHS,
// Try to represent VariantLHS as sum of invariant and variant operands.
using namespace PatternMatch;
Value *VariantOp, *InvariantOp;
if (IsSigned &&
!match(VariantLHS, m_NSWAdd(m_Value(VariantOp), m_Value(InvariantOp))))
if (IsSigned && !match(VariantLHS, m_NSWAddLike(m_Value(VariantOp),
m_Value(InvariantOp))))
return false;
if (!IsSigned &&
!match(VariantLHS, m_NUWAdd(m_Value(VariantOp), m_Value(InvariantOp))))
if (!IsSigned && !match(VariantLHS, m_NUWAddLike(m_Value(VariantOp),
m_Value(InvariantOp))))
return false;
// LHS itself is a loop-variant, try to represent it in the form:

View File

@ -996,6 +996,120 @@ failed:
ret i32 -2
}
; iv | x < 100 ==> iv < 100 - x (signed)
define void @or_disjoint_signed(ptr %x_p) {
; CHECK-LABEL: define void @or_disjoint_signed
; CHECK-SAME: (ptr [[X_P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P]], align 4, !range [[RNG0]]
; CHECK-NEXT: [[INVARIANT_OP:%.*]] = sub nsw i32 100, [[X]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[X_CHECK:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_OP]]
; CHECK-NEXT: br i1 [[X_CHECK]], label [[OUT_OF_BOUNDS:%.*]], label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 4
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%x = load i32, ptr %x_p, !range !0
br label %loop
loop:
%iv = phi i32 [0, %entry], [%iv.next, %backedge]
%arith = or disjoint i32 %iv, %x
%x_check = icmp slt i32 %arith, 100
br i1 %x_check, label %exit, label %backedge
backedge:
%iv.next = add nuw nsw i32 %iv, 4
%loop_cond = icmp slt i32 %iv.next, 1000
br i1 %loop_cond, label %loop, label %exit
exit:
ret void
}
; iv | x < 100 ==> iv < 100 - x (unsigned)
define void @or_disjoint_unsigned(ptr %x_p) {
; CHECK-LABEL: define void @or_disjoint_unsigned
; CHECK-SAME: (ptr [[X_P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P]], align 4, !range [[RNG3]]
; CHECK-NEXT: [[INVARIANT_OP:%.*]] = sub nuw i32 100, [[X]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[X_CHECK:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_OP]]
; CHECK-NEXT: br i1 [[X_CHECK]], label [[OUT_OF_BOUNDS:%.*]], label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 4
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%x = load i32, ptr %x_p, !range !3
br label %loop
loop:
%iv = phi i32 [0, %entry], [%iv.next, %backedge]
%arith = or disjoint i32 %iv, %x
%x_check = icmp ult i32 %arith, 100
br i1 %x_check, label %exit, label %backedge
backedge:
%iv.next = add nuw nsw i32 %iv, 4
%loop_cond = icmp ult i32 %iv.next, 1000
br i1 %loop_cond, label %loop, label %exit
exit:
ret void
}
; Negative test: plain or (without disjoint) should NOT be hoisted.
define void @or_no_disjoint_neg(ptr %x_p) {
; CHECK-LABEL: define void @or_no_disjoint_neg
; CHECK-SAME: (ptr [[X_P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[X_P]], align 4, !range [[RNG0]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[ARITH:%.*]] = or i32 [[IV]], [[X]]
; CHECK-NEXT: [[X_CHECK:%.*]] = icmp slt i32 [[ARITH]], 100
; CHECK-NEXT: br i1 [[X_CHECK]], label [[OUT_OF_BOUNDS:%.*]], label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 4
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%x = load i32, ptr %x_p, !range !0
br label %loop
loop:
%iv = phi i32 [0, %entry], [%iv.next, %backedge]
%arith = or i32 %iv, %x
%x_check = icmp slt i32 %arith, 100
br i1 %x_check, label %exit, label %backedge
backedge:
%iv.next = add nuw nsw i32 %iv, 4
%loop_cond = icmp slt i32 %iv.next, 1000
br i1 %loop_cond, label %loop, label %exit
exit:
ret void
}
!0 = !{i32 0, i32 2147483648}
!1 = !{i32 0, i32 2147483640}
!2 = !{i32 256, i32 32768}