1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=instcombine -S %s | FileCheck %s 3target datalayout = "p:32:32" 4 5 6define i1 @alloca_argument_compare(ptr %arg) { 7; CHECK-LABEL: @alloca_argument_compare( 8; CHECK-NEXT: ret i1 false 9; 10 %alloc = alloca i64 11 %cmp = icmp eq ptr %arg, %alloc 12 ret i1 %cmp 13} 14 15define i1 @alloca_argument_compare_swapped(ptr %arg) { 16; CHECK-LABEL: @alloca_argument_compare_swapped( 17; CHECK-NEXT: ret i1 false 18; 19 %alloc = alloca i64 20 %cmp = icmp eq ptr %alloc, %arg 21 ret i1 %cmp 22} 23 24define i1 @alloca_argument_compare_ne(ptr %arg) { 25; CHECK-LABEL: @alloca_argument_compare_ne( 26; CHECK-NEXT: ret i1 true 27; 28 %alloc = alloca i64 29 %cmp = icmp ne ptr %arg, %alloc 30 ret i1 %cmp 31} 32 33define i1 @alloca_argument_compare_derived_ptrs(ptr %arg, i64 %x) { 34; CHECK-LABEL: @alloca_argument_compare_derived_ptrs( 35; CHECK-NEXT: ret i1 false 36; 37 %alloc = alloca i64, i64 8 38 %p = getelementptr i64, ptr %arg, i64 %x 39 %q = getelementptr i64, ptr %alloc, i64 3 40 %cmp = icmp eq ptr %p, %q 41 ret i1 %cmp 42} 43 44declare void @escape(ptr) 45define i1 @alloca_argument_compare_escaped_alloca(ptr %arg) { 46; CHECK-LABEL: @alloca_argument_compare_escaped_alloca( 47; CHECK-NEXT: [[ALLOC:%.*]] = alloca i64, align 8 48; CHECK-NEXT: call void @escape(ptr nonnull [[ALLOC]]) 49; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[ALLOC]], [[ARG:%.*]] 50; CHECK-NEXT: ret i1 [[CMP]] 51; 52 %alloc = alloca i64 53 call void @escape(ptr %alloc) 54 %cmp = icmp eq ptr %alloc, %arg 55 ret i1 %cmp 56} 57 58declare void @check_compares(i1, i1) 59define void @alloca_argument_compare_two_compares(ptr %p) { 60; CHECK-LABEL: @alloca_argument_compare_two_compares( 61; CHECK-NEXT: call void @check_compares(i1 false, i1 false) 62; CHECK-NEXT: ret void 63; 64 %q = alloca i64, i64 8 65 %r = getelementptr i64, ptr %p, i64 1 66 %s = getelementptr i64, ptr %q, i64 2 67 %cmp1 = icmp eq ptr %p, %q 68 %cmp2 = icmp eq ptr %r, %s 69 call void @check_compares(i1 %cmp1, i1 %cmp2) 70 ret void 71 ; We will only fold if there is a single cmp. 72} 73 74define i1 @alloca_argument_compare_escaped_through_store(ptr %arg, ptr %ptr) { 75; CHECK-LABEL: @alloca_argument_compare_escaped_through_store( 76; CHECK-NEXT: [[ALLOC:%.*]] = alloca i64, align 8 77; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[ALLOC]], [[ARG:%.*]] 78; CHECK-NEXT: [[P:%.*]] = getelementptr inbounds nuw i8, ptr [[ALLOC]], i32 8 79; CHECK-NEXT: store ptr [[P]], ptr [[PTR:%.*]], align 4 80; CHECK-NEXT: ret i1 [[CMP]] 81; 82 %alloc = alloca i64 83 %cmp = icmp eq ptr %alloc, %arg 84 %p = getelementptr i64, ptr %alloc, i64 1 85 store ptr %p, ptr %ptr 86 ret i1 %cmp 87} 88 89declare void @llvm.lifetime.start.p0(i64, ptr nocapture) 90declare void @llvm.lifetime.end.p0(i64, ptr nocapture) 91define i1 @alloca_argument_compare_benign_instrs(ptr %arg) { 92; CHECK-LABEL: @alloca_argument_compare_benign_instrs( 93; CHECK-NEXT: ret i1 false 94; 95 %alloc = alloca i8 96 call void @llvm.lifetime.start.p0(i64 1, ptr %alloc) 97 %cmp = icmp eq ptr %arg, %alloc 98 %x = load i8, ptr %arg 99 store i8 %x, ptr %alloc 100 call void @llvm.lifetime.end.p0(i64 1, ptr %alloc) 101 ret i1 %cmp 102} 103 104declare ptr @allocator() 105define i1 @alloca_call_compare() { 106; CHECK-LABEL: @alloca_call_compare( 107; CHECK-NEXT: [[Q:%.*]] = call ptr @allocator() 108; CHECK-NEXT: ret i1 false 109; 110 %p = alloca i64 111 %q = call ptr @allocator() 112 %cmp = icmp eq ptr %p, %q 113 ret i1 %cmp 114} 115 116 117; The next block of tests demonstrate a very subtle correctness requirement. 118; We can generally assume any *single* stack layout we chose for the result of 119; an alloca, but we can't simultanious assume two different ones. As a 120; result, we must make sure that we only fold conditions if we can ensure that 121; we fold *all* potentially address capturing compares the same. 122 123; These two functions represents either a) forging a pointer via inttoptr or 124; b) indexing off an adjacent allocation. In either case, the operation is 125; obscured by an uninlined helper and not visible to instcombine. 126declare ptr @hidden_inttoptr() 127declare ptr @hidden_offset(ptr %other) 128 129define i1 @ptrtoint_single_cmp() { 130; CHECK-LABEL: @ptrtoint_single_cmp( 131; CHECK-NEXT: ret i1 false 132; 133 %m = alloca i8, i32 4 134 %rhs = inttoptr i64 2048 to ptr 135 %cmp = icmp eq ptr %m, %rhs 136 ret i1 %cmp 137} 138 139define i1 @offset_single_cmp() { 140; CHECK-LABEL: @offset_single_cmp( 141; CHECK-NEXT: ret i1 false 142; 143 %m = alloca i8, i32 4 144 %n = alloca i8, i32 4 145 %rhs = getelementptr i8, ptr %n, i32 4 146 %cmp = icmp eq ptr %m, %rhs 147 ret i1 %cmp 148} 149 150declare void @witness(i1, i1) 151 152define void @consistent_fold1() { 153; CHECK-LABEL: @consistent_fold1( 154; CHECK-NEXT: [[RHS2:%.*]] = call ptr @hidden_inttoptr() 155; CHECK-NEXT: call void @witness(i1 false, i1 false) 156; CHECK-NEXT: ret void 157; 158 %m = alloca i8, i32 4 159 %rhs = inttoptr i64 2048 to ptr 160 %rhs2 = call ptr @hidden_inttoptr() 161 %cmp1 = icmp eq ptr %m, %rhs 162 %cmp2 = icmp eq ptr %m, %rhs2 163 call void @witness(i1 %cmp1, i1 %cmp2) 164 ret void 165} 166 167define void @consistent_fold2() { 168; CHECK-LABEL: @consistent_fold2( 169; CHECK-NEXT: [[N2:%.*]] = alloca [4 x i8], align 1 170; CHECK-NEXT: [[RHS2:%.*]] = call ptr @hidden_offset(ptr nonnull [[N2]]) 171; CHECK-NEXT: call void @witness(i1 false, i1 false) 172; CHECK-NEXT: ret void 173; 174 %m = alloca i8, i32 4 175 %n = alloca i8, i32 4 176 %rhs = getelementptr i8, ptr %n, i32 4 177 %rhs2 = call ptr @hidden_offset(ptr %n) 178 %cmp1 = icmp eq ptr %m, %rhs 179 %cmp2 = icmp eq ptr %m, %rhs2 180 call void @witness(i1 %cmp1, i1 %cmp2) 181 ret void 182} 183 184define void @consistent_fold3() { 185; CHECK-LABEL: @consistent_fold3( 186; CHECK-NEXT: [[RHS2:%.*]] = call ptr @hidden_inttoptr() 187; CHECK-NEXT: call void @witness(i1 false, i1 false) 188; CHECK-NEXT: ret void 189; 190 %m = alloca i8, i32 4 191 %lgp = load ptr, ptr @gp, align 8 192 %rhs2 = call ptr @hidden_inttoptr() 193 %cmp1 = icmp eq ptr %m, %lgp 194 %cmp2 = icmp eq ptr %m, %rhs2 195 call void @witness(i1 %cmp1, i1 %cmp2) 196 ret void 197} 198 199define void @neg_consistent_fold4() { 200; CHECK-LABEL: @neg_consistent_fold4( 201; CHECK-NEXT: call void @witness(i1 false, i1 false) 202; CHECK-NEXT: ret void 203; 204 %m = alloca i8, i32 4 205 %lgp = load ptr, ptr @gp, align 8 206 %cmp1 = icmp eq ptr %m, %lgp 207 %cmp2 = icmp eq ptr %m, %lgp 208 call void @witness(i1 %cmp1, i1 %cmp2) 209 ret void 210} 211 212; A nocapture call can't cause a consistent result issue as it is (by 213; assumption) not able to contain a comparison which might capture the 214; address. 215 216declare void @unknown(ptr) 217 218define i1 @consistent_nocapture_inttoptr() { 219; CHECK-LABEL: @consistent_nocapture_inttoptr( 220; CHECK-NEXT: [[M1:%.*]] = alloca [4 x i8], align 1 221; CHECK-NEXT: call void @unknown(ptr nonnull captures(none) [[M1]]) 222; CHECK-NEXT: ret i1 false 223; 224 %m = alloca i8, i32 4 225 call void @unknown(ptr nocapture %m) 226 %rhs = inttoptr i64 2048 to ptr 227 %cmp = icmp eq ptr %m, %rhs 228 ret i1 %cmp 229} 230 231define i1 @consistent_nocapture_offset() { 232; CHECK-LABEL: @consistent_nocapture_offset( 233; CHECK-NEXT: [[M1:%.*]] = alloca [4 x i8], align 1 234; CHECK-NEXT: call void @unknown(ptr nonnull captures(none) [[M1]]) 235; CHECK-NEXT: ret i1 false 236; 237 %m = alloca i8, i32 4 238 call void @unknown(ptr nocapture %m) 239 %n = alloca i8, i32 4 240 %rhs = getelementptr i8, ptr %n, i32 4 241 %cmp = icmp eq ptr %m, %rhs 242 ret i1 %cmp 243} 244 245@gp = global ptr null, align 8 246 247define i1 @consistent_nocapture_through_global() { 248; CHECK-LABEL: @consistent_nocapture_through_global( 249; CHECK-NEXT: [[M1:%.*]] = alloca [4 x i8], align 1 250; CHECK-NEXT: call void @unknown(ptr nonnull captures(none) [[M1]]) 251; CHECK-NEXT: ret i1 false 252; 253 %m = alloca i8, i32 4 254 call void @unknown(ptr nocapture %m) 255 %lgp = load ptr, ptr @gp, align 8, !nonnull !{} 256 %cmp = icmp eq ptr %m, %lgp 257 ret i1 %cmp 258} 259 260define void @select_alloca_unrelated_ptr(i1 %c, ptr %p, ptr %p2) { 261; CHECK-LABEL: @select_alloca_unrelated_ptr( 262; CHECK-NEXT: [[M:%.*]] = alloca i8, align 1 263; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[M]], [[P:%.*]] 264; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], ptr [[M]], ptr [[P2:%.*]] 265; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr [[S]], [[P]] 266; CHECK-NEXT: call void @witness(i1 [[CMP1]], i1 [[CMP2]]) 267; CHECK-NEXT: ret void 268; 269 %m = alloca i8 270 %cmp1 = icmp eq ptr %m, %p 271 %s = select i1 %c, ptr %m, ptr %p2 272 %cmp2 = icmp eq ptr %s, %p 273 call void @witness(i1 %cmp1, i1 %cmp2) 274 ret void 275} 276 277define void @alloca_offset_icmp(ptr %p, i32 %offset) { 278; CHECK-LABEL: @alloca_offset_icmp( 279; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[OFFSET:%.*]], 0 280; CHECK-NEXT: call void @witness(i1 false, i1 [[CMP2]]) 281; CHECK-NEXT: ret void 282; 283 %m = alloca [4 x i8] 284 %g = getelementptr i8, ptr %m, i32 %offset 285 %cmp1 = icmp eq ptr %m, %p 286 %cmp2 = icmp eq ptr %m, %g 287 call void @witness(i1 %cmp1, i1 %cmp2) 288 ret void 289} 290