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