| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt -passes='loop(simple-loop-unswitch),verify<loops>' -S < %s | FileCheck %s | |
| ; RUN: opt -verify-memoryssa -passes='loop-mssa(simple-loop-unswitch),verify<loops>' -S < %s | FileCheck %s | |
| ; Trivially unswitchable header branch whose exit LCSSA phi uses a header phi. | |
| define i32 @test_unswitch_header_phi(i1 %c) { | |
| ; CHECK-LABEL: @test_unswitch_header_phi( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[ENTRY_SPLIT:%.*]], label [[EXIT:%.*]] | |
| ; CHECK: entry.split: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: br label [[HEADER]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ] | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| entry: | |
| br label %header | |
| header: | |
| %acc = phi i32 [ 0, %entry ], [ %next, %latch ] | |
| br i1 %c, label %latch, label %exit | |
| latch: | |
| %next = add i32 %acc, 1 | |
| br label %header | |
| exit: | |
| %r = phi i32 [ %acc, %header ] | |
| ret i32 %r | |
| } | |
| ; Header branch whose exit LCSSA phi uses a non-phi header value: not trivially | |
| ; unswitchable, so the loop is left unchanged. | |
| define i32 @test_no_unswitch_header_nonphi(i1 %c) { | |
| ; CHECK-LABEL: @test_no_unswitch_header_nonphi( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: [[SUM:%.*]] = add i32 [[ACC]], 5 | |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[LATCH]], label [[EXIT:%.*]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: br label [[HEADER]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUM]], [[HEADER]] ] | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| entry: | |
| br label %header | |
| header: | |
| %acc = phi i32 [ 0, %entry ], [ %next, %latch ] | |
| %sum = add i32 %acc, 5 | |
| br i1 %c, label %latch, label %exit | |
| latch: | |
| %next = add i32 %acc, 1 | |
| br label %header | |
| exit: | |
| %r = phi i32 [ %sum, %header ] | |
| ret i32 %r | |
| } | |
| ; Trivially unswitchable header branch whose exit has two LCSSA phis: one with a | |
| ; loop-invariant incoming, one with a header phi incoming. | |
| define i32 @test_unswitch_header_phi_mixed(i1 %c, i32 %inv) { | |
| ; CHECK-LABEL: @test_unswitch_header_phi_mixed( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[ENTRY_SPLIT:%.*]], label [[EXIT:%.*]] | |
| ; CHECK: entry.split: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: br label [[HEADER]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ] | |
| ; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[INV:%.*]], [[ENTRY]] ] | |
| ; CHECK-NEXT: [[SUM:%.*]] = add i32 [[R]], [[S]] | |
| ; CHECK-NEXT: ret i32 [[SUM]] | |
| ; | |
| entry: | |
| br label %header | |
| header: | |
| %acc = phi i32 [ 0, %entry ], [ %next, %latch ] | |
| br i1 %c, label %latch, label %exit | |
| latch: | |
| %next = add i32 %acc, 1 | |
| br label %header | |
| exit: | |
| %r = phi i32 [ %acc, %header ] | |
| %s = phi i32 [ %inv, %header ] | |
| %sum = add i32 %r, %s | |
| ret i32 %sum | |
| } | |
| ; Trivially unswitchable header branch whose exit LCSSA phi uses a header phi | |
| ; whose entry value is defined in the preheader, not a constant. | |
| define i32 @test_unswitch_header_phi_nonconst(i1 %c, i32 %x) { | |
| ; CHECK-LABEL: @test_unswitch_header_phi_nonconst( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[INIT:%.*]] = add i32 [[X:%.*]], 3 | |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[ENTRY_SPLIT:%.*]], label [[EXIT:%.*]] | |
| ; CHECK: entry.split: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ [[INIT]], [[ENTRY_SPLIT]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: br label [[HEADER]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[INIT]], [[ENTRY:%.*]] ] | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| entry: | |
| %init = add i32 %x, 3 | |
| br label %header | |
| header: | |
| %acc = phi i32 [ %init, %entry ], [ %next, %latch ] | |
| br i1 %c, label %latch, label %exit | |
| latch: | |
| %next = add i32 %acc, 1 | |
| br label %header | |
| exit: | |
| %r = phi i32 [ %acc, %header ] | |
| ret i32 %r | |
| } | |
| ; Trivially unswitchable branch that is not in the header but dominates the | |
| ; latch, whose exit LCSSA phi uses a header phi. The header branch unswitches | |
| ; first, then %mid is reached and also unswitches. | |
| define i32 @test_unswitch_nonheader_phi(i1 %c1, i1 %c2) { | |
| ; CHECK-LABEL: @test_unswitch_nonheader_phi( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[C1:%.*]], label [[EXIT1:%.*]], label [[ENTRY_SPLIT:%.*]] | |
| ; CHECK: entry.split: | |
| ; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT2:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]] | |
| ; CHECK: entry.split.split: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_SPLIT]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: br label [[MID:%.*]] | |
| ; CHECK: mid: | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: br label [[HEADER]] | |
| ; CHECK: exit1: | |
| ; CHECK-NEXT: ret i32 100 | |
| ; CHECK: exit2: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ] | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| entry: | |
| br label %header | |
| header: | |
| %acc = phi i32 [ 0, %entry ], [ %next, %latch ] | |
| br i1 %c1, label %exit1, label %mid | |
| mid: | |
| br i1 %c2, label %exit2, label %latch | |
| latch: | |
| %next = add i32 %acc, 1 | |
| br label %header | |
| exit1: | |
| ret i32 100 | |
| exit2: | |
| %r = phi i32 [ %acc, %mid ] | |
| ret i32 %r | |
| } | |
| ; Trivially unswitchable header branch whose exit LCSSA reads header phi %acc. | |
| ; The exit is also reached from the latch, so it is split on unswitch. | |
| define i32 @test_unswitch_header_phi_split_exit(i1 %c, i32 %n) { | |
| ; CHECK-LABEL: @test_unswitch_header_phi_split_exit( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] | |
| ; CHECK: entry.split: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: br label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NEXT]], [[N:%.*]] | |
| ; CHECK-NEXT: br i1 [[CMP]], label [[HEADER]], label [[EXIT:%.*]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[NEXT]], [[LATCH]] ] | |
| ; CHECK-NEXT: br label [[EXIT_SPLIT]] | |
| ; CHECK: exit.split: | |
| ; CHECK-NEXT: [[R_SPLIT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R]], [[EXIT]] ] | |
| ; CHECK-NEXT: ret i32 [[R_SPLIT]] | |
| ; | |
| entry: | |
| br label %header | |
| header: | |
| %acc = phi i32 [ 0, %entry ], [ %next, %latch ] | |
| br i1 %c, label %exit, label %latch | |
| latch: | |
| %next = add i32 %acc, 1 | |
| %cmp = icmp slt i32 %next, %n | |
| br i1 %cmp, label %header, label %exit | |
| exit: | |
| %r = phi i32 [ %acc, %header ], [ %next, %latch ] | |
| ret i32 %r | |
| } | |
| ; Trivially unswitchable header branch whose exit LCSSA reads header phi %acc. | |
| ; The condition is an OR of invariant %a and variant %b, so only %a is peeled. | |
| define i32 @test_unswitch_header_phi_partial(i1 %a) { | |
| ; CHECK-LABEL: @test_unswitch_header_phi_partial( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[A_FR:%.*]] = freeze i1 [[A:%.*]] | |
| ; CHECK-NEXT: br i1 [[A_FR]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] | |
| ; CHECK: entry.split: | |
| ; CHECK-NEXT: br label [[HEADER:%.*]] | |
| ; CHECK: header: | |
| ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[NEXT:%.*]], [[LATCH:%.*]] ] | |
| ; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[ACC]], 5 | |
| ; CHECK-NEXT: [[OR:%.*]] = or i1 false, [[B]] | |
| ; CHECK-NEXT: br i1 [[OR]], label [[EXIT:%.*]], label [[LATCH]] | |
| ; CHECK: latch: | |
| ; CHECK-NEXT: [[NEXT]] = add i32 [[ACC]], 1 | |
| ; CHECK-NEXT: br label [[HEADER]] | |
| ; CHECK: exit: | |
| ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[ACC]], [[HEADER]] ] | |
| ; CHECK-NEXT: br label [[EXIT_SPLIT]] | |
| ; CHECK: exit.split: | |
| ; CHECK-NEXT: [[R_SPLIT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R]], [[EXIT]] ] | |
| ; CHECK-NEXT: ret i32 [[R_SPLIT]] | |
| ; | |
| entry: | |
| br label %header | |
| header: | |
| %acc = phi i32 [ 0, %entry ], [ %next, %latch ] | |
| %b = icmp eq i32 %acc, 5 | |
| %or = or i1 %a, %b | |
| br i1 %or, label %exit, label %latch | |
| latch: | |
| %next = add i32 %acc, 1 | |
| br label %header | |
| exit: | |
| %r = phi i32 [ %acc, %header ] | |
| ret i32 %r | |
| } |