1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=mem2reg -S | FileCheck %s 3 4; This tests that mem2reg preserves the !nonnull metadata on loads 5; from allocas that get optimized out. 6 7; Check the case where the alloca in question has a single store. 8define ptr @single_store_noundef(ptr %arg) { 9; CHECK-LABEL: @single_store_noundef( 10; CHECK-NEXT: entry: 11; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 12; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null 13; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) 14; CHECK-NEXT: ret ptr [[ARG_LOAD]] 15; 16entry: 17 %buf = alloca ptr 18 %arg.load = load ptr, ptr %arg, align 8 19 store ptr %arg.load, ptr %buf, align 8 20 %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0 21 ret ptr %buf.load 22} 23 24define ptr @single_store_missing_noundef(ptr %arg) { 25; CHECK-LABEL: @single_store_missing_noundef( 26; CHECK-NEXT: entry: 27; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 28; CHECK-NEXT: ret ptr [[ARG_LOAD]] 29; 30entry: 31 %buf = alloca ptr 32 %arg.load = load ptr, ptr %arg, align 8 33 store ptr %arg.load, ptr %buf, align 8 34 %buf.load = load ptr, ptr %buf, !nonnull !0 35 ret ptr %buf.load 36} 37 38; Check the case where the alloca in question has more than one 39; store but still within one basic block. 40define ptr @single_block_noundef(ptr %arg) { 41; CHECK-LABEL: @single_block_noundef( 42; CHECK-NEXT: entry: 43; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 44; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null 45; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) 46; CHECK-NEXT: ret ptr [[ARG_LOAD]] 47; 48entry: 49 %buf = alloca ptr 50 %arg.load = load ptr, ptr %arg, align 8 51 store ptr null, ptr %buf, align 8 52 store ptr %arg.load, ptr %buf, align 8 53 %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0 54 ret ptr %buf.load 55} 56 57define ptr @single_block_missing_noundef(ptr %arg) { 58; CHECK-LABEL: @single_block_missing_noundef( 59; CHECK-NEXT: entry: 60; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 61; CHECK-NEXT: ret ptr [[ARG_LOAD]] 62; 63entry: 64 %buf = alloca ptr 65 %arg.load = load ptr, ptr %arg, align 8 66 store ptr null, ptr %buf, align 8 67 store ptr %arg.load, ptr %buf, align 8 68 %buf.load = load ptr, ptr %buf, !nonnull !0 69 ret ptr %buf.load 70} 71 72; Check the case where the alloca in question has more than one 73; store and also reads ands writes in multiple blocks. 74define ptr @multi_block_noundef(ptr %arg) { 75; CHECK-LABEL: @multi_block_noundef( 76; CHECK-NEXT: entry: 77; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 78; CHECK-NEXT: br label [[NEXT:%.*]] 79; CHECK: next: 80; CHECK-NEXT: [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null 81; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) 82; CHECK-NEXT: ret ptr [[ARG_LOAD]] 83; 84entry: 85 %buf = alloca ptr 86 %arg.load = load ptr, ptr %arg, align 8 87 store ptr null, ptr %buf, align 8 88 br label %next 89next: 90 store ptr %arg.load, ptr %buf, align 8 91 %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0 92 ret ptr %buf.load 93} 94 95define ptr @multi_block_missing_noundef(ptr %arg) { 96; CHECK-LABEL: @multi_block_missing_noundef( 97; CHECK-NEXT: entry: 98; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 99; CHECK-NEXT: br label [[NEXT:%.*]] 100; CHECK: next: 101; CHECK-NEXT: ret ptr [[ARG_LOAD]] 102; 103entry: 104 %buf = alloca ptr 105 %arg.load = load ptr, ptr %arg, align 8 106 store ptr null, ptr %buf, align 8 107 br label %next 108next: 109 store ptr %arg.load, ptr %buf, align 8 110 %buf.load = load ptr, ptr %buf, !nonnull !0 111 ret ptr %buf.load 112} 113 114; Check that we don't add an assume if it's not 115; necessary i.e. the value is already implied to be nonnull 116define ptr @no_assume(ptr %arg) { 117; CHECK-LABEL: @no_assume( 118; CHECK-NEXT: entry: 119; CHECK-NEXT: [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 120; CHECK-NEXT: [[CN:%.*]] = icmp ne ptr [[ARG_LOAD]], null 121; CHECK-NEXT: br i1 [[CN]], label [[NEXT:%.*]], label [[FIN:%.*]] 122; CHECK: next: 123; CHECK-NEXT: ret ptr [[ARG_LOAD]] 124; CHECK: fin: 125; CHECK-NEXT: ret ptr null 126; 127entry: 128 %buf = alloca ptr 129 %arg.load = load ptr, ptr %arg, align 8 130 %cn = icmp ne ptr %arg.load, null 131 br i1 %cn, label %next, label %fin 132next: 133; At this point the above nonnull check ensures that 134; the value %arg.load is nonnull in this block and thus 135; we need not add the assume. 136 store ptr %arg.load, ptr %buf, align 8 137 %buf.load = load ptr, ptr %buf, !nonnull !0 138 ret ptr %buf.load 139fin: 140 ret ptr null 141} 142 143define ptr @no_store_single_load_noundef() { 144; CHECK-LABEL: @no_store_single_load_noundef( 145; CHECK-NEXT: entry: 146; CHECK-NEXT: store i1 true, ptr poison, align 1 147; CHECK-NEXT: ret ptr undef 148; 149entry: 150 %buf = alloca ptr 151 %buf.load = load ptr, ptr %buf, !noundef !0 152 ret ptr %buf.load 153} 154 155define ptr @no_store_multiple_loads_noundef(i1 %c) { 156; CHECK-LABEL: @no_store_multiple_loads_noundef( 157; CHECK-NEXT: entry: 158; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 159; CHECK: if: 160; CHECK-NEXT: store i1 true, ptr poison, align 1 161; CHECK-NEXT: ret ptr undef 162; CHECK: else: 163; CHECK-NEXT: store i1 true, ptr poison, align 1 164; CHECK-NEXT: ret ptr undef 165; 166entry: 167 %buf = alloca ptr 168 br i1 %c, label %if, label %else 169 170if: 171 %buf.load = load ptr, ptr %buf, !noundef !0 172 ret ptr %buf.load 173 174 else: 175 %buf.load2 = load ptr, ptr %buf, !noundef !0 176 ret ptr %buf.load2 177} 178 179define ptr @no_store_single_load_nonnull_noundef() { 180; CHECK-LABEL: @no_store_single_load_nonnull_noundef( 181; CHECK-NEXT: entry: 182; CHECK-NEXT: store i1 true, ptr poison, align 1 183; CHECK-NEXT: ret ptr undef 184; 185entry: 186 %buf = alloca ptr 187 %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0 188 ret ptr %buf.load 189} 190 191define ptr @no_store_multiple_loads_nonnull_noundef(i1 %c) { 192; CHECK-LABEL: @no_store_multiple_loads_nonnull_noundef( 193; CHECK-NEXT: entry: 194; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] 195; CHECK: if: 196; CHECK-NEXT: store i1 true, ptr poison, align 1 197; CHECK-NEXT: ret ptr undef 198; CHECK: else: 199; CHECK-NEXT: store i1 true, ptr poison, align 1 200; CHECK-NEXT: ret ptr undef 201; 202entry: 203 %buf = alloca ptr 204 br i1 %c, label %if, label %else 205 206if: 207 %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0 208 ret ptr %buf.load 209 210 else: 211 %buf.load2 = load ptr, ptr %buf, !nonnull !0, !noundef !0 212 ret ptr %buf.load2 213} 214 215!0 = !{} 216