| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s | |
| declare void @f0() | |
| declare void @f1() | |
| declare void @f2() | |
| ;; Folding a chain of unpredictable equality comparisons into a switch keeps the | |
| ;; switch unpredictable. | |
| define void @fold_into_pred_unpredictable(i32 %x) { | |
| ; CHECK-LABEL: define void @fold_into_pred_unpredictable( | |
| ; CHECK-SAME: i32 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: switch i32 [[X]], label %[[C:.*]] [ | |
| ; CHECK-NEXT: i32 0, label %[[A:.*]] | |
| ; CHECK-NEXT: i32 1, label %[[B:.*]] | |
| ; CHECK-NEXT: ], !unpredictable [[META0:![0-9]+]] | |
| ; CHECK: [[A]]: | |
| ; CHECK-NEXT: call void @f0() | |
| ; CHECK-NEXT: br label %[[EXIT:.*]] | |
| ; CHECK: [[B]]: | |
| ; CHECK-NEXT: call void @f1() | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[C]]: | |
| ; CHECK-NEXT: call void @f2() | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %c0 = icmp eq i32 %x, 0 | |
| br i1 %c0, label %a, label %next, !unpredictable !0 | |
| next: | |
| %c1 = icmp eq i32 %x, 1 | |
| br i1 %c1, label %b, label %c, !unpredictable !0 | |
| a: | |
| call void @f0() | |
| br label %exit | |
| b: | |
| call void @f1() | |
| br label %exit | |
| c: | |
| call void @f2() | |
| br label %exit | |
| exit: | |
| ret void | |
| } | |
| ;; If only one of the folded comparisons is unpredictable, nothing is known | |
| ;; about the resulting switch. | |
| define void @fold_into_pred_partly_unpredictable(i32 %x) { | |
| ; CHECK-LABEL: define void @fold_into_pred_partly_unpredictable( | |
| ; CHECK-SAME: i32 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: switch i32 [[X]], label %[[C:.*]] [ | |
| ; CHECK-NEXT: i32 0, label %[[A:.*]] | |
| ; CHECK-NEXT: i32 1, label %[[B:.*]] | |
| ; CHECK-NEXT: ]{{$}} | |
| ; CHECK: [[A]]: | |
| ; CHECK-NEXT: call void @f0() | |
| ; CHECK-NEXT: br label %[[EXIT:.*]] | |
| ; CHECK: [[B]]: | |
| ; CHECK-NEXT: call void @f1() | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[C]]: | |
| ; CHECK-NEXT: call void @f2() | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %c0 = icmp eq i32 %x, 0 | |
| br i1 %c0, label %a, label %next, !unpredictable !0 | |
| next: | |
| %c1 = icmp eq i32 %x, 1 | |
| br i1 %c1, label %b, label %c | |
| a: | |
| call void @f0() | |
| br label %exit | |
| b: | |
| call void @f1() | |
| br label %exit | |
| c: | |
| call void @f2() | |
| br label %exit | |
| exit: | |
| ret void | |
| } | |
| ;; An unpredictable branch on a chain of equality comparisons becomes an | |
| ;; unpredictable switch. | |
| define void @icmp_chain_to_switch(i32 %x) { | |
| ; CHECK-LABEL: define void @icmp_chain_to_switch( | |
| ; CHECK-SAME: i32 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: switch i32 [[X]], label %[[B:.*]] [ | |
| ; CHECK-NEXT: i32 9, label %[[A:.*]] | |
| ; CHECK-NEXT: i32 5, label %[[A]] | |
| ; CHECK-NEXT: i32 1, label %[[A]] | |
| ; CHECK-NEXT: ], !unpredictable [[META0]] | |
| ; CHECK: [[A]]: | |
| ; CHECK-NEXT: call void @f0() | |
| ; CHECK-NEXT: br label %[[EXIT:.*]] | |
| ; CHECK: [[B]]: | |
| ; CHECK-NEXT: call void @f1() | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %c0 = icmp eq i32 %x, 1 | |
| %c1 = icmp eq i32 %x, 5 | |
| %c2 = icmp eq i32 %x, 9 | |
| %o0 = or i1 %c0, %c1 | |
| %o1 = or i1 %o0, %c2 | |
| br i1 %o1, label %a, label %b, !unpredictable !0 | |
| a: | |
| call void @f0() | |
| br label %exit | |
| b: | |
| call void @f1() | |
| br label %exit | |
| exit: | |
| ret void | |
| } | |
| ;; The same chain over a contiguous range becomes an unpredictable range check. | |
| define void @icmp_chain_to_range_check(i32 %x) { | |
| ; CHECK-LABEL: define void @icmp_chain_to_range_check( | |
| ; CHECK-SAME: i32 [[X:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], -1 | |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 3 | |
| ; CHECK-NEXT: br i1 [[TMP1]], label %[[A:.*]], label %[[B:.*]], !unpredictable [[META0]] | |
| ; CHECK: [[A]]: | |
| ; CHECK-NEXT: call void @f0() | |
| ; CHECK-NEXT: br label %[[EXIT:.*]] | |
| ; CHECK: [[B]]: | |
| ; CHECK-NEXT: call void @f1() | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| %c0 = icmp eq i32 %x, 1 | |
| %c1 = icmp eq i32 %x, 2 | |
| %c2 = icmp eq i32 %x, 3 | |
| %o0 = or i1 %c0, %c1 | |
| %o1 = or i1 %o0, %c2 | |
| br i1 %o1, label %a, label %b, !unpredictable !0 | |
| a: | |
| call void @f0() | |
| br label %exit | |
| b: | |
| call void @f1() | |
| br label %exit | |
| exit: | |
| ret void | |
| } | |
| !0 = !{} | |
| ;. | |
| ; CHECK: [[META0]] = !{} | |
| ;. |