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