| ; 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 | |
| } |