1; RUN: opt -passes='loop(simple-loop-unswitch),verify<loops>' -S < %s | FileCheck %s 2; RUN: opt -verify-memoryssa -passes='loop-mssa(simple-loop-unswitch),verify<loops>' -S < %s | FileCheck %s 3 4declare void @unknown() 5declare void @unknown2() 6 7@y = global i64 0, align 8 8 9; The following is approximately: 10; void f(bool *x) { 11; for (int i = 0; i < 1; ++i) { 12; if (*x) { 13; if (y) 14; unknown(); 15; else 16; break; 17; } 18; } 19; } 20; With MemorySanitizer, the loop can not be unswitched on "y", because "y" could 21; be uninitialized when x == false. 22; Test that the branch on "y" is inside the loop (after the first unconditional 23; branch). 24 25define void @may_not_execute_trivial(ptr %x) sanitize_memory { 26; CHECK-LABEL: @may_not_execute_trivial( 27entry: 28 %y = load i64, ptr @y, align 8 29 %y.cmp = icmp eq i64 %y, 0 30 br label %for.body 31; CHECK: %[[Y:.*]] = load i64, ptr @y 32; CHECK: %[[YCMP:.*]] = icmp eq i64 %[[Y]], 0 33; CHECK-NOT: br i1 34; CHECK: br label %for.body 35 36for.body: 37 %i = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 38 %x.load = load i1, ptr %x 39 br i1 %x.load, label %for.inc, label %if.then 40; CHECK: %[[XLOAD:.*]] = load i1, ptr %x 41; CHECK: br i1 %[[XLOAD]] 42 43if.then: 44 br i1 %y.cmp, label %for.end, label %if.then4 45; CHECK: br i1 %[[YCMP]] 46 47if.then4: 48 call void @unknown() 49 br label %for.inc 50 51for.inc: 52 %inc = add nsw i32 %i, 1 53 %cmp = icmp slt i32 %inc, 1 54 br i1 %cmp, label %for.body, label %for.end 55 56for.end: 57 ret void 58} 59 60 61; The same as above, but "y" is a function parameter instead of a global. 62; This shows that it is not enough to suppress hoisting of load instructions, 63; the actual problem is in the speculative branching. 64 65define void @may_not_execute2_trivial(ptr %x, i1 %y) sanitize_memory { 66; CHECK-LABEL: @may_not_execute2_trivial( 67entry: 68 br label %for.body 69; CHECK-NOT: br i1 70; CHECK: br label %for.body 71 72for.body: 73 %i = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 74 %x.load = load i1, ptr %x 75 br i1 %x.load, label %for.inc, label %if.then 76; CHECK: %[[XLOAD:.*]] = load i1, ptr %x 77; CHECK: br i1 %[[XLOAD]] 78 79if.then: 80 br i1 %y, label %for.end, label %if.then4 81; CHECK: br i1 %y 82 83if.then4: 84 call void @unknown() 85 br label %for.inc 86 87for.inc: 88 %inc = add nsw i32 %i, 1 89 %cmp = icmp slt i32 %inc, 1 90 br i1 %cmp, label %for.body, label %for.end 91 92for.end: 93 ret void 94} 95 96 97; The following is approximately: 98; void f() { 99; for (int i = 0; i < 1; ++i) { 100; if (y) 101; unknown(); 102; else 103; break; 104; } 105; } 106; "if (y)" is guaranteed to execute; the loop can be unswitched. 107 108define void @must_execute_trivial() sanitize_memory { 109; CHECK-LABEL: @must_execute_trivial( 110entry: 111 %y = load i64, ptr @y, align 8 112 %y.cmp = icmp eq i64 %y, 0 113 br label %for.body 114; CHECK: %[[Y:.*]] = load i64, ptr @y 115; CHECK: %[[YCMP:.*]] = icmp eq i64 %[[Y]], 0 116; CHECK: br i1 %[[YCMP]], label %[[EXIT_SPLIT:.*]], label %[[PH:.*]] 117; 118; CHECK: [[PH]]: 119; CHECK: br label %for.body 120 121for.body: 122 %i = phi i32 [ 0, %entry ], [ %inc, %for.inc ] 123 br i1 %y.cmp, label %for.end, label %if.then4 124; CHECK: br label %if.then4 125 126if.then4: 127 call void @unknown() 128 br label %for.inc 129 130for.inc: 131 %inc = add nsw i32 %i, 1 132 %cmp = icmp slt i32 %inc, 1 133 br i1 %cmp, label %for.body, label %for.end 134 135for.end: 136 ret void 137; CHECK: for.end: 138; CHECK: br label %[[EXIT_SPLIT]] 139; 140; CHECK: [[EXIT_SPLIT]]: 141; CHECK: ret void 142} 143