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