1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature 2; RUN: opt -passes=ipsccp -S %s | FileCheck %s 3 4%t1 = type opaque 5 6@e = common global i32 0, align 4 7 8; Test that we a skip unknown values depending on a unknown tracked call, until the call gets resolved. The @test1 and @test2 variants are very similar, they just check 2 different kinds of users (icmp and zext) 9 10define i32 @test1_m(i32 %h) { 11; CHECK-LABEL: define {{[^@]+}}@test1_m 12; CHECK-SAME: (i32 [[H:%.*]]) { 13; CHECK-NEXT: entry: 14; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[H]] to i8 15; CHECK-NEXT: [[CALL:%.*]] = call i32 @test1_k(i8 [[CONV]], i32 0) 16; CHECK-NEXT: [[CONV1:%.*]] = sext i32 [[H]] to i64 17; CHECK-NEXT: [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr 18; CHECK-NEXT: [[CALL2:%.*]] = call i1 @test1_g(ptr [[TMP0]], i32 1) 19; CHECK-NEXT: ret i32 undef 20; 21entry: 22 %conv = trunc i32 %h to i8 23 %call = call i32 @test1_k(i8 %conv, i32 0) 24 %conv1 = sext i32 %h to i64 25 %0 = inttoptr i64 %conv1 to ptr 26 %call2 = call i1 @test1_g(ptr %0, i32 1) 27 ret i32 undef 28 29; uselistorder directives 30 uselistorder i32 %h, { 1, 0 } 31} 32 33declare void @use.1(i1) 34 35define internal i32 @test1_k(i8 %h, i32 %i) { 36; CHECK-LABEL: define {{[^@]+}}@test1_k 37; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) { 38; CHECK-NEXT: entry: 39; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @e, align 4 40; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP0]] to i64 41; CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr 42; CHECK-NEXT: [[CALL:%.*]] = call i1 @test1_g(ptr [[TMP1]], i32 0) 43; CHECK-NEXT: call void @use.1(i1 false) 44; CHECK-NEXT: ret i32 undef 45; 46entry: 47 %0 = load i32, ptr @e, align 4 48 %conv = sext i32 %0 to i64 49 %1 = inttoptr i64 %conv to ptr 50 %call = call i1 @test1_g(ptr %1, i32 %i) 51 %frombool.1 = zext i1 %call to i8 52 %tobool.1 = trunc i8 %frombool.1 to i1 53 call void @use.1(i1 %tobool.1) 54 ret i32 undef 55} 56 57define internal i1 @test1_g(ptr %h, i32 %i) #0 { 58; CHECK-LABEL: define {{[^@]+}}@test1_g 59; CHECK-SAME: (ptr [[H:%.*]], i32 range(i32 0, 2) [[I:%.*]]) { 60; CHECK-NEXT: entry: 61; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[I]], 0 62; CHECK-NEXT: br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]] 63; CHECK: land.rhs: 64; CHECK-NEXT: [[CALL:%.*]] = call i32 (...) @test1_j() 65; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0 66; CHECK-NEXT: br label [[LAND_END]] 67; CHECK: land.end: 68; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ] 69; CHECK-NEXT: ret i1 poison 70; 71entry: 72 %tobool = icmp ne i32 %i, 0 73 br i1 %tobool, label %land.rhs, label %land.end 74 75land.rhs: ; preds = %entry 76 %call = call i32 (...) @test1_j() 77 %tobool1 = icmp ne i32 %call, 0 78 br label %land.end 79 80land.end: ; preds = %land.rhs, %entry 81 %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ] 82 ret i1 false 83} 84 85declare i32 @test1_j(...) 86 87define i32 @test2_m(i32 %h) #0 { 88; CHECK-LABEL: define {{[^@]+}}@test2_m 89; CHECK-SAME: (i32 [[H:%.*]]) { 90; CHECK-NEXT: entry: 91; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[H]] to i8 92; CHECK-NEXT: [[CALL:%.*]] = call i32 @test2_k(i8 [[CONV]], i32 0) 93; CHECK-NEXT: [[CONV1:%.*]] = sext i32 [[H]] to i64 94; CHECK-NEXT: [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr 95; CHECK-NEXT: [[CALL2:%.*]] = call i1 @test2_g(ptr [[TMP0]], i32 1) 96; CHECK-NEXT: ret i32 undef 97; 98entry: 99 %conv = trunc i32 %h to i8 100 %call = call i32 @test2_k(i8 %conv, i32 0) 101 %conv1 = sext i32 %h to i64 102 %0 = inttoptr i64 %conv1 to ptr 103 %call2 = call i1 @test2_g(ptr %0, i32 1) 104 ret i32 undef 105 106; uselistorder directives 107 uselistorder i32 %h, { 1, 0 } 108} 109 110; TODO: We could do better for the return value of call i1 @test3_g, if we 111; resolve the unknown values there first. 112define internal i32 @test2_k(i8 %h, i32 %i) { 113; CHECK-LABEL: define {{[^@]+}}@test2_k 114; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) { 115; CHECK-NEXT: entry: 116; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @e, align 4 117; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP0]] to i64 118; CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr 119; CHECK-NEXT: [[CALL:%.*]] = call i1 @test3_g(ptr [[TMP1]], i32 0) 120; CHECK-NEXT: call void @use.1(i1 false) 121; CHECK-NEXT: ret i32 undef 122; 123entry: 124 %0 = load i32, ptr @e, align 4 125 %conv = sext i32 %0 to i64 126 %1 = inttoptr i64 %conv to ptr 127 %call = call i1 @test3_g(ptr %1, i32 %i) 128 %frombool = icmp slt i1 %call, 1 129 %add = add i1 %frombool, %frombool 130 call void @use.1(i1 %frombool) 131 ret i32 undef 132 133} 134 135define internal i1 @test2_g(ptr %h, i32 %i) { 136; CHECK-LABEL: define {{[^@]+}}@test2_g 137; CHECK-SAME: (ptr [[H:%.*]], i32 [[I:%.*]]) { 138; CHECK-NEXT: entry: 139; CHECK-NEXT: br label [[LAND_RHS:%.*]] 140; CHECK: land.rhs: 141; CHECK-NEXT: [[CALL:%.*]] = call i32 (...) @test2_j() 142; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0 143; CHECK-NEXT: br label [[LAND_END:%.*]] 144; CHECK: land.end: 145; CHECK-NEXT: ret i1 poison 146; 147entry: 148 %tobool = icmp ne i32 %i, 0 149 br i1 %tobool, label %land.rhs, label %land.end 150 151land.rhs: ; preds = %entry 152 %call = call i32 (...) @test2_j() 153 %tobool1 = icmp ne i32 %call, 0 154 br label %land.end 155 156land.end: ; preds = %land.rhs, %entry 157 %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ] 158 ret i1 false 159} 160 161declare i32 @test2_j(...) 162 163 164 165; Same as test_2*, but with a PHI node depending on a tracked call result. 166define i32 @test3_m(i32 %h) #0 { 167; CHECK-LABEL: define {{[^@]+}}@test3_m 168; CHECK-SAME: (i32 [[H:%.*]]) { 169; CHECK-NEXT: entry: 170; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[H]] to i8 171; CHECK-NEXT: [[CALL:%.*]] = call i32 @test3_k(i8 [[CONV]], i32 0) 172; CHECK-NEXT: [[CONV1:%.*]] = sext i32 [[H]] to i64 173; CHECK-NEXT: [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr 174; CHECK-NEXT: [[CALL2:%.*]] = call i1 @test3_g(ptr [[TMP0]], i32 1) 175; CHECK-NEXT: ret i32 undef 176; 177entry: 178 %conv = trunc i32 %h to i8 179 %call = call i32 @test3_k(i8 %conv, i32 0) 180 %conv1 = sext i32 %h to i64 181 %0 = inttoptr i64 %conv1 to ptr 182 %call2 = call i1 @test3_g(ptr %0, i32 1) 183 ret i32 undef 184 185; uselistorder directives 186 uselistorder i32 %h, { 1, 0 } 187} 188 189define internal i32 @test3_k(i8 %h, i32 %i) { 190; CHECK-LABEL: define {{[^@]+}}@test3_k 191; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) { 192; CHECK-NEXT: entry: 193; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @e, align 4 194; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP0]] to i64 195; CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr 196; CHECK-NEXT: br label [[LOOP:%.*]] 197; CHECK: loop: 198; CHECK-NEXT: [[CALL:%.*]] = call i1 @test3_g(ptr [[TMP1]], i32 0) 199; CHECK-NEXT: call void @use.1(i1 false) 200; CHECK-NEXT: br label [[EXIT:%.*]] 201; CHECK: exit: 202; CHECK-NEXT: ret i32 undef 203; 204entry: 205 %0 = load i32, ptr @e, align 4 206 %conv = sext i32 %0 to i64 207 %1 = inttoptr i64 %conv to ptr 208 br label %loop 209 210loop: 211 %phi = phi i1 [ undef, %entry], [ %call, %loop ] 212 %call = call i1 @test3_g(ptr %1, i32 %i) 213 %frombool = icmp slt i1 %call, 1 214 %add = add i1 %frombool, %frombool 215 call void @use.1(i1 %frombool) 216 br i1 %call, label %loop, label %exit 217 218exit: 219 ret i32 undef 220} 221 222define internal i1 @test3_g(ptr %h, i32 %i) { 223; CHECK-LABEL: define {{[^@]+}}@test3_g 224; CHECK-SAME: (ptr [[H:%.*]], i32 range(i32 0, 2) [[I:%.*]]) { 225; CHECK-NEXT: entry: 226; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[I]], 0 227; CHECK-NEXT: br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]] 228; CHECK: land.rhs: 229; CHECK-NEXT: [[CALL:%.*]] = call i32 (...) @test3_j() 230; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0 231; CHECK-NEXT: br label [[LAND_END]] 232; CHECK: land.end: 233; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ] 234; CHECK-NEXT: ret i1 poison 235; 236entry: 237 %tobool = icmp ne i32 %i, 0 238 br i1 %tobool, label %land.rhs, label %land.end 239 240land.rhs: ; preds = %entry 241 %call = call i32 (...) @test3_j() 242 %tobool1 = icmp ne i32 %call, 0 243 br label %land.end 244 245land.end: ; preds = %land.rhs, %entry 246 %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ] 247 ret i1 false 248} 249 250declare i32 @test3_j(...) 251 252 253; TODO: We can eliminate the bitcast, if we resolve the unknown argument of 254; @test4_b first. 255 256declare void @use.16(ptr) 257declare void @use.8(ptr) 258 259define void @test4_a() { 260; CHECK-LABEL: define {{[^@]+}}@test4_a() { 261; CHECK-NEXT: bb: 262; CHECK-NEXT: [[TMP:%.*]] = call ptr @test4_c(ptr null) 263; CHECK-NEXT: call void @test4_b(ptr null) 264; CHECK-NEXT: ret void 265; 266bb: 267 %tmp = call ptr @test4_c(ptr null) 268 call void @test4_b(ptr %tmp) 269 ret void 270} 271 272define internal void @test4_b(ptr %arg) { 273; CHECK-LABEL: define {{[^@]+}}@test4_b 274; CHECK-SAME: (ptr [[ARG:%.*]]) { 275; CHECK-NEXT: bb: 276; CHECK-NEXT: [[SEL:%.*]] = select i1 false, ptr null, ptr null 277; CHECK-NEXT: call void @use.16(ptr null) 278; CHECK-NEXT: call void @use.8(ptr [[SEL]]) 279; CHECK-NEXT: ret void 280; 281bb: 282 %sel = select i1 false, ptr %arg, ptr %arg 283 call void @use.16(ptr %arg) 284 call void @use.8(ptr %sel) 285 ret void 286} 287 288define internal ptr @test4_c(ptr %arg) { 289; CHECK-LABEL: define {{[^@]+}}@test4_c 290; CHECK-SAME: (ptr [[ARG:%.*]]) { 291; CHECK-NEXT: bb1: 292; CHECK-NEXT: [[TMP:%.*]] = and i1 undef, undef 293; CHECK-NEXT: br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]] 294; CHECK: bb2: 295; CHECK-NEXT: unreachable 296; CHECK: bb3: 297; CHECK-NEXT: ret ptr poison 298; 299bb1: ; preds = %bb 300 %tmp = and i1 undef, undef 301 br i1 %tmp, label %bb3, label %bb2 302 303bb2: ; preds = %bb1 304 unreachable 305 306bb3: ; preds = %bb1 307 ret ptr null 308} 309 310; TODO: Same as test4, but with a select instead of a bitcast. 311 312define void @test5_a() { 313; CHECK-LABEL: define {{[^@]+}}@test5_a() { 314; CHECK-NEXT: bb: 315; CHECK-NEXT: [[TMP:%.*]] = call ptr @test5_c(ptr null) 316; CHECK-NEXT: call void @test5_b(ptr null) 317; CHECK-NEXT: ret void 318; 319bb: 320 %tmp = call ptr @test5_c(ptr null) 321 call void @test5_b(ptr %tmp) 322 ret void 323} 324 325define internal void @test5_b(ptr %arg) { 326; CHECK-LABEL: define {{[^@]+}}@test5_b 327; CHECK-SAME: (ptr [[ARG:%.*]]) { 328; CHECK-NEXT: bb: 329; CHECK-NEXT: [[SEL:%.*]] = select i1 false, ptr null, ptr null 330; CHECK-NEXT: call void @use.8(ptr [[SEL]]) 331; CHECK-NEXT: ret void 332; 333bb: 334 %sel = select i1 false, ptr %arg, ptr %arg 335 call void @use.8(ptr %sel) 336 ret void 337} 338 339define internal ptr @test5_c(ptr %arg) { 340; CHECK-LABEL: define {{[^@]+}}@test5_c 341; CHECK-SAME: (ptr [[ARG:%.*]]) { 342; CHECK-NEXT: bb1: 343; CHECK-NEXT: [[TMP:%.*]] = and i1 undef, undef 344; CHECK-NEXT: br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]] 345; CHECK: bb2: 346; CHECK-NEXT: unreachable 347; CHECK: bb3: 348; CHECK-NEXT: ret ptr poison 349; 350bb1: ; preds = %bb 351 %tmp = and i1 undef, undef 352 br i1 %tmp, label %bb3, label %bb2 353 354bb2: ; preds = %bb1 355 unreachable 356 357bb3: ; preds = %bb1 358 ret ptr null 359} 360 361 362 363@contextsize = external dso_local local_unnamed_addr global i32, align 4 364@pcount = internal local_unnamed_addr global i32 0, align 4 365@maxposslen = external dso_local local_unnamed_addr global i32, align 4 366 367define void @test3() { 368; CHECK-LABEL: define {{[^@]+}}@test3() { 369; CHECK-NEXT: entry: 370; CHECK-NEXT: br label [[IF_END16:%.*]] 371; CHECK: if.end16: 372; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @contextsize, align 4 373; CHECK-NEXT: [[SUB18:%.*]] = sub i32 undef, [[TMP0]] 374; CHECK-NEXT: [[SUB19:%.*]] = sub i32 [[SUB18]], undef 375; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @maxposslen, align 4 376; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP1]], 8 377; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 undef, [[ADD]] 378; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @pcount, align 4 379; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], [[SUB19]] 380; CHECK-NEXT: [[CMP20:%.*]] = icmp sgt i32 [[TMP2]], [[MUL]] 381; CHECK-NEXT: br i1 [[CMP20]], label [[IF_THEN22:%.*]], label [[IF_END24:%.*]] 382; CHECK: if.then22: 383; CHECK-NEXT: store i32 [[MUL]], ptr @pcount, align 4 384; CHECK-NEXT: ret void 385; CHECK: if.end24: 386; CHECK-NEXT: [[CMP25474:%.*]] = icmp sgt i32 [[TMP2]], 0 387; CHECK-NEXT: br i1 [[CMP25474]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]] 388; CHECK: for.body: 389; CHECK-NEXT: ret void 390; CHECK: for.end: 391; CHECK-NEXT: ret void 392; 393entry: 394 br label %if.end16 395 396if.end16: ; preds = %entry 397 %0 = load i32, ptr @contextsize, align 4 398 %sub18 = sub i32 undef, %0 399 %sub19 = sub i32 %sub18, undef 400 %1 = load i32, ptr @maxposslen, align 4 401 %add = add nsw i32 %1, 8 402 %div = sdiv i32 undef, %add 403 %2 = load i32, ptr @pcount, align 4 404 %mul = mul nsw i32 %div, %sub19 405 %cmp20 = icmp sgt i32 %2, %mul 406 br i1 %cmp20, label %if.then22, label %if.end24 407 408if.then22: ; preds = %if.end16 409 store i32 %mul, ptr @pcount, align 4 410 ret void 411 412if.end24: ; preds = %if.end16 413 %cmp25474 = icmp sgt i32 %2, 0 414 br i1 %cmp25474, label %for.body, label %for.end 415 416for.body: ; preds = %if.end24 417 %3 = trunc i64 0 to i32 418 %div30 = sdiv i32 %3, %sub19 419 ret void 420 421for.end: ; preds = %if.end24 422 ret void 423} 424