1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=instsimplify < %s | FileCheck %s 3 4declare void @bar(ptr %a, ptr nonnull noundef %b) 5declare void @bar_without_noundef(ptr %a, ptr nonnull %b) 6 7; 'y' must be nonnull. 8 9define i1 @caller1(ptr %x, ptr %y) { 10; CHECK-LABEL: @caller1( 11; CHECK-NEXT: call void @bar(ptr [[X:%.*]], ptr [[Y:%.*]]) 12; CHECK-NEXT: ret i1 false 13; 14 call void @bar(ptr %x, ptr %y) 15 %null_check = icmp eq ptr %y, null 16 ret i1 %null_check 17} 18 19; Don't know anything about 'y'. 20 21define i1 @caller1_maybepoison(ptr %x, ptr %y) { 22; CHECK-LABEL: @caller1_maybepoison( 23; CHECK-NEXT: call void @bar_without_noundef(ptr [[X:%.*]], ptr [[Y:%.*]]) 24; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[Y]], null 25; CHECK-NEXT: ret i1 [[NULL_CHECK]] 26; 27 call void @bar_without_noundef(ptr %x, ptr %y) 28 %null_check = icmp eq ptr %y, null 29 ret i1 %null_check 30} 31 32; Don't know anything about 'y'. 33 34define i1 @caller2(ptr %x, ptr %y) { 35; CHECK-LABEL: @caller2( 36; CHECK-NEXT: call void @bar(ptr [[Y:%.*]], ptr [[X:%.*]]) 37; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[Y]], null 38; CHECK-NEXT: ret i1 [[NULL_CHECK]] 39; 40 call void @bar(ptr %y, ptr %x) 41 %null_check = icmp eq ptr %y, null 42 ret i1 %null_check 43} 44 45; 'y' must be nonnull. 46 47define i1 @caller3(ptr %x, ptr %y) { 48; CHECK-LABEL: @caller3( 49; CHECK-NEXT: call void @bar(ptr [[X:%.*]], ptr [[Y:%.*]]) 50; CHECK-NEXT: ret i1 true 51; 52 call void @bar(ptr %x, ptr %y) 53 %null_check = icmp ne ptr %y, null 54 ret i1 %null_check 55} 56 57; FIXME: The call is guaranteed to execute, so 'y' must be nonnull throughout. 58 59define i1 @caller4(ptr %x, ptr %y) { 60; CHECK-LABEL: @caller4( 61; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp ne ptr [[Y:%.*]], null 62; CHECK-NEXT: call void @bar(ptr [[X:%.*]], ptr [[Y]]) 63; CHECK-NEXT: ret i1 [[NULL_CHECK]] 64; 65 %null_check = icmp ne ptr %y, null 66 call void @bar(ptr %x, ptr %y) 67 ret i1 %null_check 68} 69 70; The call to bar() does not dominate the null check, so no change. 71 72define i1 @caller5(ptr %x, ptr %y) { 73; CHECK-LABEL: @caller5( 74; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[Y:%.*]], null 75; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[T:%.*]], label [[F:%.*]] 76; CHECK: t: 77; CHECK-NEXT: ret i1 [[NULL_CHECK]] 78; CHECK: f: 79; CHECK-NEXT: call void @bar(ptr [[X:%.*]], ptr [[Y]]) 80; CHECK-NEXT: ret i1 [[NULL_CHECK]] 81; 82 %null_check = icmp eq ptr %y, null 83 br i1 %null_check, label %t, label %f 84t: 85 ret i1 %null_check 86f: 87 call void @bar(ptr %x, ptr %y) 88 ret i1 %null_check 89} 90 91; Make sure that an invoke works similarly to a call. 92 93declare i32 @esfp(...) 94 95define i1 @caller6(ptr %x, ptr %y) personality ptr @esfp{ 96; CHECK-LABEL: @caller6( 97; CHECK-NEXT: invoke void @bar(ptr [[X:%.*]], ptr nonnull [[Y:%.*]]) 98; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]] 99; CHECK: cont: 100; CHECK-NEXT: ret i1 false 101; CHECK: exc: 102; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 } 103; CHECK-NEXT: filter [0 x ptr] zeroinitializer 104; CHECK-NEXT: unreachable 105; 106 invoke void @bar(ptr %x, ptr nonnull %y) 107 to label %cont unwind label %exc 108 109cont: 110 %null_check = icmp eq ptr %y, null 111 ret i1 %null_check 112 113exc: 114 %lp = landingpad { ptr, i32 } 115 filter [0 x ptr] zeroinitializer 116 unreachable 117} 118 119declare ptr @returningPtr(ptr returned %p) 120 121define i1 @nonnullReturnTest(ptr nonnull %x) { 122; CHECK-LABEL: @nonnullReturnTest( 123; CHECK-NEXT: [[X2:%.*]] = call ptr @returningPtr(ptr [[X:%.*]]) 124; CHECK-NEXT: ret i1 false 125; 126 %x2 = call ptr @returningPtr(ptr %x) 127 %null_check = icmp eq ptr %x2, null 128 ret i1 %null_check 129} 130 131define i1 @unknownReturnTest(ptr %x) { 132; CHECK-LABEL: @unknownReturnTest( 133; CHECK-NEXT: [[X2:%.*]] = call ptr @returningPtr(ptr [[X:%.*]]) 134; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[X2]], null 135; CHECK-NEXT: ret i1 [[NULL_CHECK]] 136; 137 %x2 = call ptr @returningPtr(ptr %x) 138 %null_check = icmp eq ptr %x2, null 139 ret i1 %null_check 140} 141 142; Make sure that if load/store happened, the pointer is nonnull. 143 144define i32 @test_null_after_store(ptr %0) { 145; CHECK-LABEL: @test_null_after_store( 146; CHECK-NEXT: store i32 123, ptr [[TMP0:%.*]], align 4 147; CHECK-NEXT: ret i32 2 148; 149 store i32 123, ptr %0, align 4 150 %2 = icmp eq ptr %0, null 151 %3 = select i1 %2, i32 1, i32 2 152 ret i32 %3 153} 154 155define i32 @test_null_after_load(ptr %0) { 156; CHECK-LABEL: @test_null_after_load( 157; CHECK-NEXT: ret i32 1 158; 159 %2 = load i32, ptr %0, align 4 160 %3 = icmp eq ptr %0, null 161 %4 = select i1 %3, i32 %2, i32 1 162 ret i32 %4 163} 164 165; Make sure that different address space does not affect null pointer check. 166 167define i32 @test_null_after_store_addrspace(ptr addrspace(1) %0) { 168; CHECK-LABEL: @test_null_after_store_addrspace( 169; CHECK-NEXT: store i32 123, ptr addrspace(1) [[TMP0:%.*]], align 4 170; CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr addrspace(1) [[TMP0]], null 171; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 1, i32 2 172; CHECK-NEXT: ret i32 [[TMP3]] 173; 174 store i32 123, ptr addrspace(1) %0, align 4 175 %2 = icmp eq ptr addrspace(1) %0, null 176 %3 = select i1 %2, i32 1, i32 2 177 ret i32 %3 178} 179 180define i32 @test_null_after_load_addrspace(ptr addrspace(1) %0) { 181; CHECK-LABEL: @test_null_after_load_addrspace( 182; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(1) [[TMP0:%.*]], align 4 183; CHECK-NEXT: [[TMP3:%.*]] = icmp eq ptr addrspace(1) [[TMP0]], null 184; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 1 185; CHECK-NEXT: ret i32 [[TMP4]] 186; 187 %2 = load i32, ptr addrspace(1) %0, align 4 188 %3 = icmp eq ptr addrspace(1) %0, null 189 %4 = select i1 %3, i32 %2, i32 1 190 ret i32 %4 191} 192 193; Make sure if store happened after the check, nullptr check is not removed. 194 195declare ptr @func(i64) 196 197define ptr @test_load_store_after_check(ptr %0) { 198; CHECK-LABEL: @test_load_store_after_check( 199; CHECK-NEXT: entry: 200; CHECK-NEXT: [[TMP1:%.*]] = call ptr @func(i64 0) 201; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[TMP1]], null 202; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[RETURN:%.*]], label [[IF_END:%.*]] 203; CHECK: if.end: 204; CHECK-NEXT: store i8 7, ptr [[TMP1]], align 1 205; CHECK-NEXT: br label [[RETURN]] 206; CHECK: return: 207; CHECK-NEXT: [[RETVAL_0:%.*]] = phi ptr [ [[TMP1]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ] 208; CHECK-NEXT: ret ptr [[RETVAL_0]] 209; 210entry: 211 %1 = call ptr @func(i64 0) 212 %null_check = icmp eq ptr %1, null 213 br i1 %null_check, label %return, label %if.end 214 215if.end: 216 store i8 7, ptr %1 217 br label %return 218 219return: 220 %retval.0 = phi ptr [ %1, %if.end ], [ null, %entry ] 221 ret ptr %retval.0 222} 223 224define i1 @test_known_nonnull_at_callsite(ptr %src) { 225; CHECK-LABEL: @test_known_nonnull_at_callsite( 226; CHECK-NEXT: entry: 227; CHECK-NEXT: call void @callee(ptr noundef nonnull [[SRC:%.*]]) 228; CHECK-NEXT: ret i1 false 229; 230entry: 231 call void @callee(ptr noundef nonnull %src) 232 %nonnull = icmp eq ptr %src, null 233 ret i1 %nonnull 234} 235 236define i1 @test_known_nonnull_mixed(ptr %src) { 237; CHECK-LABEL: @test_known_nonnull_mixed( 238; CHECK-NEXT: entry: 239; CHECK-NEXT: call void @callee2(ptr nonnull [[SRC:%.*]]) 240; CHECK-NEXT: ret i1 false 241; 242entry: 243 call void @callee2(ptr nonnull %src) 244 %nonnull = icmp eq ptr %src, null 245 ret i1 %nonnull 246} 247 248define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) { 249; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable( 250; CHECK-NEXT: entry: 251; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]]) 252; CHECK-NEXT: ret i1 false 253; 254entry: 255 call void @callee(ptr dereferenceable(1) %src) 256 %nonnull = icmp eq ptr %src, null 257 ret i1 %nonnull 258} 259 260; Negative tests 261 262define i1 @test_known_nonnull_at_callsite_without_noundef(ptr %src) { 263; CHECK-LABEL: @test_known_nonnull_at_callsite_without_noundef( 264; CHECK-NEXT: entry: 265; CHECK-NEXT: call void @callee(ptr nonnull [[SRC:%.*]]) 266; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null 267; CHECK-NEXT: ret i1 [[NONNULL]] 268; 269entry: 270 call void @callee(ptr nonnull %src) 271 %nonnull = icmp eq ptr %src, null 272 ret i1 %nonnull 273} 274 275define i1 @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(ptr %src) null_pointer_is_valid { 276; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable_null_is_defined( 277; CHECK-NEXT: entry: 278; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]]) 279; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null 280; CHECK-NEXT: ret i1 [[NONNULL]] 281; 282entry: 283 call void @callee(ptr dereferenceable(1) %src) 284 %nonnull = icmp eq ptr %src, null 285 ret i1 %nonnull 286} 287 288declare void @callee(ptr) 289declare void @callee2(ptr noundef) 290