blob: e21d3f05fc08aca7190aefbce7a9e968014050df [file] [log] [blame] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes='loop(loop-rotate<header-duplication>)' %s | FileCheck %s --check-prefixes=CHECK,NO-EXIT-COUNT
; RUN: opt -S -passes='loop(loop-rotate<header-duplication;check-exit-count>)' %s | FileCheck %s --check-prefixes=CHECK,EXIT-COUNT
; Computable header exit, data-dependent latch exit. Rotated with check-exit-count.
define ptr @search_loop(ptr %begin, ptr %end, i8 %val) {
; NO-EXIT-COUNT-LABEL: @search_loop(
; NO-EXIT-COUNT-NEXT: entry:
; NO-EXIT-COUNT-NEXT: [[CMP_ENTRY:%.*]] = icmp eq ptr [[BEGIN:%.*]], [[END:%.*]]
; NO-EXIT-COUNT-NEXT: br i1 [[CMP_ENTRY]], label [[EXIT:%.*]], label [[FOR_COND_PREHEADER:%.*]]
; NO-EXIT-COUNT: for.cond.preheader:
; NO-EXIT-COUNT-NEXT: br label [[FOR_COND:%.*]]
; NO-EXIT-COUNT: for.cond:
; NO-EXIT-COUNT-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_DEC:%.*]], [[FOR_BODY:%.*]] ], [ [[END]], [[FOR_COND_PREHEADER]] ]
; NO-EXIT-COUNT-NEXT: [[PTR_DEC]] = getelementptr inbounds i8, ptr [[PTR]], i64 -1
; NO-EXIT-COUNT-NEXT: [[CMP_END:%.*]] = icmp eq ptr [[PTR_DEC]], [[BEGIN]]
; NO-EXIT-COUNT-NEXT: br i1 [[CMP_END]], label [[NOT_FOUND:%.*]], label [[FOR_BODY]]
; NO-EXIT-COUNT: for.body:
; NO-EXIT-COUNT-NEXT: [[LOAD:%.*]] = load i8, ptr [[PTR_DEC]], align 1
; NO-EXIT-COUNT-NEXT: [[CMP_VAL:%.*]] = icmp eq i8 [[LOAD]], [[VAL:%.*]]
; NO-EXIT-COUNT-NEXT: br i1 [[CMP_VAL]], label [[FOUND:%.*]], label [[FOR_COND]]
; NO-EXIT-COUNT: found:
; NO-EXIT-COUNT-NEXT: [[PTR_DEC_LCSSA1:%.*]] = phi ptr [ [[PTR_DEC]], [[FOR_BODY]] ]
; NO-EXIT-COUNT-NEXT: ret ptr [[PTR_DEC_LCSSA1]]
; NO-EXIT-COUNT: not.found:
; NO-EXIT-COUNT-NEXT: br label [[EXIT]]
; NO-EXIT-COUNT: exit:
; NO-EXIT-COUNT-NEXT: ret ptr [[END]]
;
; EXIT-COUNT-LABEL: @search_loop(
; EXIT-COUNT-NEXT: entry:
; EXIT-COUNT-NEXT: [[CMP_ENTRY:%.*]] = icmp eq ptr [[BEGIN:%.*]], [[END:%.*]]
; EXIT-COUNT-NEXT: br i1 [[CMP_ENTRY]], label [[EXIT:%.*]], label [[FOR_COND_PREHEADER:%.*]]
; EXIT-COUNT: for.cond.preheader:
; EXIT-COUNT-NEXT: [[PTR_DEC2:%.*]] = getelementptr inbounds i8, ptr [[END]], i64 -1
; EXIT-COUNT-NEXT: [[CMP_END3:%.*]] = icmp eq ptr [[PTR_DEC2]], [[BEGIN]]
; EXIT-COUNT-NEXT: br i1 [[CMP_END3]], label [[NOT_FOUND:%.*]], label [[FOR_BODY_LR_PH:%.*]]
; EXIT-COUNT: for.body.lr.ph:
; EXIT-COUNT-NEXT: br label [[FOR_BODY:%.*]]
; EXIT-COUNT: for.cond:
; EXIT-COUNT-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_DEC4:%.*]], [[FOR_BODY]] ]
; EXIT-COUNT-NEXT: [[PTR_DEC:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 -1
; EXIT-COUNT-NEXT: [[CMP_END:%.*]] = icmp eq ptr [[PTR_DEC]], [[BEGIN]]
; EXIT-COUNT-NEXT: br i1 [[CMP_END]], label [[FOR_COND_NOT_FOUND_CRIT_EDGE:%.*]], label [[FOR_BODY]]
; EXIT-COUNT: for.body:
; EXIT-COUNT-NEXT: [[PTR_DEC4]] = phi ptr [ [[PTR_DEC2]], [[FOR_BODY_LR_PH]] ], [ [[PTR_DEC]], [[FOR_COND:%.*]] ]
; EXIT-COUNT-NEXT: [[LOAD:%.*]] = load i8, ptr [[PTR_DEC4]], align 1
; EXIT-COUNT-NEXT: [[CMP_VAL:%.*]] = icmp eq i8 [[LOAD]], [[VAL:%.*]]
; EXIT-COUNT-NEXT: br i1 [[CMP_VAL]], label [[FOUND:%.*]], label [[FOR_COND]]
; EXIT-COUNT: found:
; EXIT-COUNT-NEXT: [[PTR_DEC_LCSSA1:%.*]] = phi ptr [ [[PTR_DEC4]], [[FOR_BODY]] ]
; EXIT-COUNT-NEXT: ret ptr [[PTR_DEC_LCSSA1]]
; EXIT-COUNT: for.cond.not.found_crit_edge:
; EXIT-COUNT-NEXT: br label [[NOT_FOUND]]
; EXIT-COUNT: not.found:
; EXIT-COUNT-NEXT: br label [[EXIT]]
; EXIT-COUNT: exit:
; EXIT-COUNT-NEXT: ret ptr [[END]]
;
entry:
%cmp.entry = icmp eq ptr %begin, %end
br i1 %cmp.entry, label %exit, label %for.cond
for.cond:
%ptr = phi ptr [ %end, %entry ], [ %ptr.dec, %for.body ]
%ptr.dec = getelementptr inbounds i8, ptr %ptr, i64 -1
%cmp.end = icmp eq ptr %ptr.dec, %begin
br i1 %cmp.end, label %not.found, label %for.body
for.body:
%load = load i8, ptr %ptr.dec, align 1
%cmp.val = icmp eq i8 %load, %val
br i1 %cmp.val, label %found, label %for.cond
found:
ret ptr %ptr.dec
not.found:
br label %exit
exit:
ret ptr %end
}
; Both exits are memory-dependent (not computable). Not rotated.
define i32 @both_mem_dependent(ptr %p, ptr %q, i32 %n) {
; CHECK-LABEL: @both_mem_dependent(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BODY:%.*]] ]
; CHECK-NEXT: [[LOAD1:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[LOAD1]], 0
; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT1:%.*]], label [[BODY]]
; CHECK: body:
; CHECK-NEXT: [[LOAD2:%.*]] = load i32, ptr [[Q:%.*]], align 4
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[LOAD2]], 0
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: br i1 [[CMP2]], label [[EXIT2:%.*]], label [[LOOP]]
; CHECK: exit1:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
; CHECK-NEXT: ret i32 [[IV_LCSSA]]
; CHECK: exit2:
; CHECK-NEXT: [[IV_LCSSA1:%.*]] = phi i32 [ [[IV]], [[BODY]] ]
; CHECK-NEXT: ret i32 [[IV_LCSSA1]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %body ]
%load1 = load i32, ptr %p, align 4
%cmp1 = icmp eq i32 %load1, 0
br i1 %cmp1, label %exit1, label %body
body:
%load2 = load i32, ptr %q, align 4
%cmp2 = icmp eq i32 %load2, 0
%iv.next = add i32 %iv, 1
br i1 %cmp2, label %exit2, label %loop
exit1:
ret i32 %iv
exit2:
ret i32 %iv
}
; Latch is unconditional, already properly structured.
define void @already_rotated(ptr %p, i32 %n) {
; CHECK-LABEL: @already_rotated(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: store i32 [[IV]], ptr [[P:%.*]], align 4
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[IV_NEXT]], [[N:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
store i32 %iv, ptr %p, align 4
%iv.next = add nuw i32 %iv, 1
%cmp = icmp eq i32 %iv.next, %n
br i1 %cmp, label %exit, label %loop
exit:
ret void
}