Simon Pilgrim 08d153d806 [ValueTracking] computeKnownBits - attempt to use a branch condition feeding a phi to improve known bits range (PR38280)
If computeKnownBits encounters a phi node, and we fail to determine any known bits through direct analysis, see if the incoming value is part of a branch condition feeding the phi.

Handle cases where icmp(IncomingValue PRED Constant) is driving a branch instruction feeding that phi node - at the moment this only handles EQ/ULT/ULE predicate cases as they are the most straightforward to handle and most likely for branch-loop 'max upper bound' cases - we can extend this if/when necessary.

I investigated a more general icmp(LHS PRED RHS) KnownBits system, but the hard limits we put on value tracking depth through phi nodes meant that we were mainly catching constants anyhow.

Fixes the pointless vectorization in PR38280 / Issue #37628 (excessive unrolling still needs handling though)

Differential Revision: https://reviews.llvm.org/D131838
2022-08-16 16:54:44 +01:00

209 lines
5.9 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
;
; Tests to show cases where computeKnownBits should be able to determine
; the known bits of a phi edge based off a conditional branch feeding the phi.
;
; %x either eq 7 or is set to 7
define i64 @limit_i64_eq_7(i64 %x) {
; CHECK-LABEL: @limit_i64_eq_7(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], 7
; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[BODY:%.*]]
; CHECK: body:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: ret i64 7
;
entry:
%cmp = icmp eq i64 %x, 7
br i1 %cmp, label %end, label %body
body:
br label %end
end:
%res = phi i64 [ %x, %entry ], [ 7, %body ]
ret i64 %res
}
; %x either eq 255 or is set to 255
define i64 @limit_i64_ne_255(i64 %x) {
; CHECK-LABEL: @limit_i64_ne_255(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[X:%.*]], 255
; CHECK-NEXT: call void @use(i1 [[CMP]])
; CHECK-NEXT: br i1 [[CMP]], label [[BODY:%.*]], label [[END:%.*]]
; CHECK: body:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: ret i64 255
;
entry:
%cmp = icmp ne i64 %x, 255
call void @use(i1 %cmp)
br i1 %cmp, label %body, label %end
body:
br label %end
end:
%res = phi i64 [ %x, %entry ], [ 255, %body ]
ret i64 %res
}
declare void @use(i1)
; %x either ule 15 or is masked with 15
define i64 @limit_i64_ule_15(i64 %x) {
; CHECK-LABEL: @limit_i64_ule_15(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X:%.*]], 16
; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[BODY:%.*]]
; CHECK: body:
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], 15
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[X_MASK:%.*]] = phi i64 [ [[X]], [[ENTRY:%.*]] ], [ [[MASK]], [[BODY]] ]
; CHECK-NEXT: ret i64 [[X_MASK]]
;
entry:
%cmp = icmp ule i64 %x, 15
br i1 %cmp, label %end, label %body
body:
%mask = and i64 %x, 15
br label %end
end:
%x.mask = phi i64 [ %x, %entry ], [ %mask, %body ]
%res = and i64 %x.mask, 15
ret i64 %res
}
; %x either uge 8 or is masked with 7
define i64 @limit_i64_uge_8(i64 %x) {
; CHECK-LABEL: @limit_i64_uge_8(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], 7
; CHECK-NEXT: br i1 [[CMP]], label [[BODY:%.*]], label [[END:%.*]]
; CHECK: body:
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], 7
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[X_MASK:%.*]] = phi i64 [ [[X]], [[ENTRY:%.*]] ], [ [[MASK]], [[BODY]] ]
; CHECK-NEXT: ret i64 [[X_MASK]]
;
entry:
%cmp = icmp uge i64 %x, 8
br i1 %cmp, label %body, label %end
body:
%mask = and i64 %x, 7
br label %end
end:
%x.mask = phi i64 [ %x, %entry ], [ %mask, %body ]
%res = and i64 %x.mask, 7
ret i64 %res
}
; %x either ult 8 or is masked with 7
define i64 @limit_i64_ult_8(i64 %x) {
; CHECK-LABEL: @limit_i64_ult_8(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X:%.*]], 8
; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[BODY:%.*]]
; CHECK: body:
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], 7
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[X_MASK:%.*]] = phi i64 [ [[X]], [[ENTRY:%.*]] ], [ [[MASK]], [[BODY]] ]
; CHECK-NEXT: ret i64 [[X_MASK]]
;
entry:
%cmp = icmp ult i64 %x, 8
br i1 %cmp, label %end, label %body
body:
%mask = and i64 %x, 7
br label %end
end:
%x.mask = phi i64 [ %x, %entry ], [ %mask, %body ]
%res = and i64 %x.mask, 7
ret i64 %res
}
; %x either ugt 7 or is masked with 7
define i64 @limit_i64_ugt_7(i64 %x) {
; CHECK-LABEL: @limit_i64_ugt_7(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], 7
; CHECK-NEXT: br i1 [[CMP]], label [[BODY:%.*]], label [[END:%.*]]
; CHECK: body:
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], 7
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[X_MASK:%.*]] = phi i64 [ [[X]], [[ENTRY:%.*]] ], [ [[MASK]], [[BODY]] ]
; CHECK-NEXT: ret i64 [[X_MASK]]
;
entry:
%cmp = icmp ugt i64 %x, 7
br i1 %cmp, label %body, label %end
body:
%mask = and i64 %x, 7
br label %end
end:
%x.mask = phi i64 [ %x, %entry ], [ %mask, %body ]
%res = and i64 %x.mask, 7
ret i64 %res
}
;
; negative tests
;
; %x either ule 15 or is masked with 15
define i64 @limit_i64_ule_15_mask3(i64 %x) {
; CHECK-LABEL: @limit_i64_ule_15_mask3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X:%.*]], 16
; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[BODY:%.*]]
; CHECK: body:
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], 15
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[X_MASK:%.*]] = phi i64 [ [[X]], [[ENTRY:%.*]] ], [ [[MASK]], [[BODY]] ]
; CHECK-NEXT: [[RES:%.*]] = and i64 [[X_MASK]], 3
; CHECK-NEXT: ret i64 [[RES]]
;
entry:
%cmp = icmp ule i64 %x, 15
br i1 %cmp, label %end, label %body
body:
%mask = and i64 %x, 15
br label %end
end:
%x.mask = phi i64 [ %x, %entry ], [ %mask, %body ]
%res = and i64 %x.mask, 3
ret i64 %res
}
; %x either ult 8 or is masked with 7
define i64 @limit_i64_ult_8_mask1(i64 %x) {
; CHECK-LABEL: @limit_i64_ult_8_mask1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X:%.*]], 8
; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[BODY:%.*]]
; CHECK: body:
; CHECK-NEXT: [[MASK:%.*]] = and i64 [[X]], 7
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[X_MASK:%.*]] = phi i64 [ [[X]], [[ENTRY:%.*]] ], [ [[MASK]], [[BODY]] ]
; CHECK-NEXT: [[RES:%.*]] = and i64 [[X_MASK]], 1
; CHECK-NEXT: ret i64 [[RES]]
;
entry:
%cmp = icmp ult i64 %x, 8
br i1 %cmp, label %end, label %body
body:
%mask = and i64 %x, 7
br label %end
end:
%x.mask = phi i64 [ %x, %entry ], [ %mask, %body ]
%res = and i64 %x.mask, 1
ret i64 %res
}