| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -passes='loop-mssa(simple-loop-unswitch),verify<loops>' -S < %s | FileCheck %s | |
| ; Check that an llvm.assume ahead of an invariant exiting branch does not block | |
| ; trivial unswitching. | |
| define void @assume_before_branch(ptr %p, i1 %c, i64 %n) { | |
| ; CHECK-LABEL: define void @assume_before_branch( | |
| ; CHECK-SAME: ptr [[P:%.*]], i1 [[C:%.*]], i64 [[N:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[EXIT_SPLIT:.*]], label %[[ENTRY_SPLIT:.*]] | |
| ; CHECK: [[ENTRY_SPLIT]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ] | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IV]], [[N]] | |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) | |
| ; CHECK-NEXT: br label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV]] | |
| ; CHECK-NEXT: store i32 0, ptr [[GEP]], align 4 | |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 1 | |
| ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] | |
| ; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT_SPLIT]] | |
| ; CHECK: [[EXIT_SPLIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] | |
| %cmp = icmp ult i64 %iv, %n | |
| call void @llvm.assume(i1 %cmp) | |
| br i1 %c, label %exit, label %latch | |
| latch: | |
| %gep = getelementptr i32, ptr %p, i64 %iv | |
| store i32 0, ptr %gep | |
| %iv.next = add nuw i64 %iv, 1 | |
| %done = icmp eq i64 %iv.next, %n | |
| br i1 %done, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Check that an llvm.assume with operand bundles ahead of an invariant exiting | |
| ; branch does not block trivial unswitching. | |
| define void @assume_bundle_before_branch(ptr %p, i1 %c, i64 %n) { | |
| ; CHECK-LABEL: define void @assume_bundle_before_branch( | |
| ; CHECK-SAME: ptr [[P:%.*]], i1 [[C:%.*]], i64 [[N:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[EXIT_SPLIT:.*]], label %[[ENTRY_SPLIT:.*]] | |
| ; CHECK: [[ENTRY_SPLIT]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ] | |
| ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 4) ] | |
| ; CHECK-NEXT: br label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV]] | |
| ; CHECK-NEXT: store i32 0, ptr [[GEP]], align 4 | |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 1 | |
| ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] | |
| ; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT_SPLIT]] | |
| ; CHECK: [[EXIT_SPLIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] | |
| call void @llvm.assume(i1 true) [ "align"(ptr %p, i64 4) ] | |
| br i1 %c, label %exit, label %latch | |
| latch: | |
| %gep = getelementptr i32, ptr %p, i64 %iv | |
| store i32 0, ptr %gep | |
| %iv.next = add nuw i64 %iv, 1 | |
| %done = icmp eq i64 %iv.next, %n | |
| br i1 %done, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Check that an llvm.experimental.noalias.scope.decl ahead of an invariant | |
| ; exiting branch does not block trivial unswitching. | |
| define void @noalias_scope_decl_before_branch(ptr %p, i1 %c, i64 %n) { | |
| ; CHECK-LABEL: define void @noalias_scope_decl_before_branch( | |
| ; CHECK-SAME: ptr [[P:%.*]], i1 [[C:%.*]], i64 [[N:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[EXIT_SPLIT:.*]], label %[[ENTRY_SPLIT:.*]] | |
| ; CHECK: [[ENTRY_SPLIT]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ] | |
| ; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META0:![0-9]+]]) | |
| ; CHECK-NEXT: br label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV]] | |
| ; CHECK-NEXT: store i32 0, ptr [[GEP]], align 4, !alias.scope [[META0]] | |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 1 | |
| ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] | |
| ; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT_SPLIT]] | |
| ; CHECK: [[EXIT_SPLIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] | |
| call void @llvm.experimental.noalias.scope.decl(metadata !0) | |
| br i1 %c, label %exit, label %latch | |
| latch: | |
| %gep = getelementptr i32, ptr %p, i64 %iv | |
| store i32 0, ptr %gep, !alias.scope !0 | |
| %iv.next = add nuw i64 %iv, 1 | |
| %done = icmp eq i64 %iv.next, %n | |
| br i1 %done, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Check that an llvm.pseudoprobe ahead of an invariant exiting branch does not | |
| ; block trivial unswitching. | |
| define void @pseudoprobe_before_branch(ptr %p, i1 %c, i64 %n) { | |
| ; CHECK-LABEL: define void @pseudoprobe_before_branch( | |
| ; CHECK-SAME: ptr [[P:%.*]], i1 [[C:%.*]], i64 [[N:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: br i1 [[C]], label %[[EXIT_SPLIT:.*]], label %[[ENTRY_SPLIT:.*]] | |
| ; CHECK: [[ENTRY_SPLIT]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ] | |
| ; CHECK-NEXT: call void @llvm.pseudoprobe(i64 123, i64 2, i32 0, i64 -1) | |
| ; CHECK-NEXT: br label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P]], i64 [[IV]] | |
| ; CHECK-NEXT: store i32 0, ptr [[GEP]], align 4 | |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw i64 [[IV]], 1 | |
| ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] | |
| ; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: br label %[[EXIT_SPLIT]] | |
| ; CHECK: [[EXIT_SPLIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] | |
| call void @llvm.pseudoprobe(i64 123, i64 2, i32 0, i64 -1) | |
| br i1 %c, label %exit, label %latch | |
| latch: | |
| %gep = getelementptr i32, ptr %p, i64 %iv | |
| store i32 0, ptr %gep | |
| %iv.next = add nuw i64 %iv, 1 | |
| %done = icmp eq i64 %iv.next, %n | |
| br i1 %done, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| declare void @llvm.assume(i1) | |
| declare void @llvm.experimental.noalias.scope.decl(metadata) | |
| declare void @llvm.pseudoprobe(i64, i64, i32, i64) | |
| !0 = !{!1} | |
| !1 = distinct !{!1, !2, !"scope"} | |
| !2 = distinct !{!2, i1 false, !"domain"} | |
| ;. | |
| ; CHECK: [[META0]] = !{[[META1:![0-9]+]]} | |
| ; CHECK: [[META1]] = distinct !{[[META1]], [[META2:![0-9]+]], !"scope"} | |
| ; CHECK: [[META2]] = distinct !{[[META2]], i1 false, !"domain"} | |
| ;. |