[indvars] Use loop guards when canonicalizing exit conditions

This extends the logic in canonicalizeExitConditions to use loop guards to specialize the SCEV of the loop invariant term before quering it's range.
This commit is contained in:
Philip Reames 2021-11-04 15:21:39 -07:00
parent 13317286f8
commit dec15d9a0a
2 changed files with 66 additions and 2 deletions

View File

@ -1456,7 +1456,8 @@ bool IndVarSimplify::canonicalizeExitCondition(Loop *L) {
const unsigned OuterBitWidth = DL.getTypeSizeInBits(RHS->getType());
auto FullCR = ConstantRange::getFull(InnerBitWidth);
FullCR = FullCR.zeroExtend(OuterBitWidth);
if (FullCR.contains(SE->getUnsignedRange(SE->getSCEV(RHS)))) {
auto RHSCR = SE->getUnsignedRange(SE->applyLoopGuards(SE->getSCEV(RHS), L));
if (FullCR.contains(RHSCR)) {
// We have now matched icmp signed-cond zext(X), zext(Y'), and can thus
// replace the signed condition with the unsigned version.
ICmp->setPredicate(ICmp->getUnsignedPredicate());
@ -1530,7 +1531,8 @@ bool IndVarSimplify::canonicalizeExitCondition(Loop *L) {
const unsigned OuterBitWidth = DL.getTypeSizeInBits(RHS->getType());
auto FullCR = ConstantRange::getFull(InnerBitWidth);
FullCR = FullCR.zeroExtend(OuterBitWidth);
if (FullCR.contains(SE->getUnsignedRange(SE->getSCEV(RHS)))) {
auto RHSCR = SE->getUnsignedRange(SE->applyLoopGuards(SE->getSCEV(RHS), L));
if (FullCR.contains(RHSCR)) {
doRotateTransform();
Changed = true;
// Note, we are leaving SCEV in an unfortunately imprecise case here

View File

@ -989,3 +989,65 @@ for.end: ; preds = %for.body, %entry
ret i16 %iv2
}
define void @slt_restricted_rhs(i16 %n.raw) mustprogress {
; CHECK-LABEL: @slt_restricted_rhs(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = and i16 [[N_RAW:%.*]], 255
; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N]] to i8
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
%n = and i16 %n.raw, 255
br label %for.body
for.body: ; preds = %entry, %for.body
%iv = phi i8 [ %iv.next, %for.body ], [ 0, %entry ]
%iv.next = add i8 %iv, 1
%zext = zext i8 %iv.next to i16
%cmp = icmp slt i16 %zext, %n
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body, %entry
ret void
}
define void @slt_guarded_rhs(i16 %n) mustprogress {
; CHECK-LABEL: @slt_guarded_rhs(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[IN_RANGE:%.*]] = icmp ult i16 [[N:%.*]], 256
; CHECK-NEXT: br i1 [[IN_RANGE]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N]] to i8
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
%in_range = icmp ult i16 %n, 256
br i1 %in_range, label %for.body, label %for.end
for.body: ; preds = %entry, %for.body
%iv = phi i8 [ %iv.next, %for.body ], [ 0, %entry ]
%iv.next = add i8 %iv, 1
%zext = zext i8 %iv.next to i16
%cmp = icmp slt i16 %zext, %n
br i1 %cmp, label %for.body, label %for.end
for.end: ; preds = %for.body, %entry
ret void
}