1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --version 2 2; RUN: opt -passes=gvn -S < %s | FileCheck %s 3 4declare void @use.ptr(ptr) memory(none) 5declare void @use.i64(i64) memory(none) 6declare void @use.i32(i32) memory(none) 7 8define i32 @test1(ptr %p) { 9; CHECK-LABEL: define i32 @test1 10; CHECK-SAME: (ptr [[P:%.*]]) { 11; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0:![0-9]+]] 12; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 13; CHECK-NEXT: ret i32 [[C]] 14; 15 %a = load i32, ptr %p, !range !0 16 %b = load i32, ptr %p, !range !0 17 %c = add i32 %a, %b 18 ret i32 %c 19} 20 21define i32 @test2(ptr %p) { 22; CHECK-LABEL: define i32 @test2 23; CHECK-SAME: (ptr [[P:%.*]]) { 24; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4 25; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 26; CHECK-NEXT: ret i32 [[C]] 27; 28 %a = load i32, ptr %p, !range !0 29 %b = load i32, ptr %p 30 %c = add i32 %a, %b 31 ret i32 %c 32} 33 34define i32 @test3(ptr %p) { 35; CHECK-LABEL: define i32 @test3 36; CHECK-SAME: (ptr [[P:%.*]]) { 37; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG1:![0-9]+]] 38; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 39; CHECK-NEXT: ret i32 [[C]] 40; 41 %a = load i32, ptr %p, !range !0 42 %b = load i32, ptr %p, !range !1 43 %c = add i32 %a, %b 44 ret i32 %c 45} 46 47define i32 @test4(ptr %p) { 48; CHECK-LABEL: define i32 @test4 49; CHECK-SAME: (ptr [[P:%.*]]) { 50; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG2:![0-9]+]] 51; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 52; CHECK-NEXT: ret i32 [[C]] 53; 54 %a = load i32, ptr %p, !range !0 55 %b = load i32, ptr %p, !range !2 56 %c = add i32 %a, %b 57 ret i32 %c 58} 59 60define i32 @test5(ptr %p) { 61; CHECK-LABEL: define i32 @test5 62; CHECK-SAME: (ptr [[P:%.*]]) { 63; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG3:![0-9]+]] 64; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 65; CHECK-NEXT: ret i32 [[C]] 66; 67 %a = load i32, ptr %p, !range !3 68 %b = load i32, ptr %p, !range !4 69 %c = add i32 %a, %b 70 ret i32 %c 71} 72 73define i32 @test6(ptr %p) { 74; CHECK-LABEL: define i32 @test6 75; CHECK-SAME: (ptr [[P:%.*]]) { 76; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG4:![0-9]+]] 77; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 78; CHECK-NEXT: ret i32 [[C]] 79; 80 %a = load i32, ptr %p, !range !5 81 %b = load i32, ptr %p, !range !6 82 %c = add i32 %a, %b 83 ret i32 %c 84} 85 86define i32 @test7(ptr %p) { 87; CHECK-LABEL: define i32 @test7 88; CHECK-SAME: (ptr [[P:%.*]]) { 89; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG5:![0-9]+]] 90; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 91; CHECK-NEXT: ret i32 [[C]] 92; 93 %a = load i32, ptr %p, !range !7 94 %b = load i32, ptr %p, !range !8 95 %c = add i32 %a, %b 96 ret i32 %c 97} 98 99define i32 @test8(ptr %p) { 100; CHECK-LABEL: define i32 @test8 101; CHECK-SAME: (ptr [[P:%.*]]) { 102; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4 103; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 104; CHECK-NEXT: ret i32 [[C]] 105; 106 %a = load i32, ptr %p, !range !9 107 %b = load i32, ptr %p, !range !10 108 %c = add i32 %a, %b 109 ret i32 %c 110} 111 112define i32 @load_noundef_load(ptr %p) { 113; CHECK-LABEL: define i32 @load_noundef_load 114; CHECK-SAME: (ptr [[P:%.*]]) { 115; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0]], !noundef !6 116; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 117; CHECK-NEXT: ret i32 [[C]] 118; 119 %a = load i32, ptr %p, !range !0, !noundef !11 120 %b = load i32, ptr %p, !range !1 121 %c = add i32 %a, %b 122 ret i32 %c 123} 124 125define i32 @load_load_noundef(ptr %p) { 126; CHECK-LABEL: define i32 @load_load_noundef 127; CHECK-SAME: (ptr [[P:%.*]]) { 128; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG1]] 129; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[A]] 130; CHECK-NEXT: ret i32 [[C]] 131; 132 %a = load i32, ptr %p, !range !0 133 %b = load i32, ptr %p, !range !1, !noundef !11 134 %c = add i32 %a, %b 135 ret i32 %c 136} 137 138define void @load_dereferenceable_dominating(ptr %p) { 139; CHECK-LABEL: define void @load_dereferenceable_dominating 140; CHECK-SAME: (ptr [[P:%.*]]) { 141; CHECK-NEXT: [[A:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable !7 142; CHECK-NEXT: call void @use.ptr(ptr [[A]]) 143; CHECK-NEXT: call void @use.ptr(ptr [[A]]) 144; CHECK-NEXT: ret void 145; 146 %a = load ptr, ptr %p, !dereferenceable !{i64 10} 147 %b = load ptr, ptr %p 148 call void @use.ptr(ptr %a) 149 call void @use.ptr(ptr %b) 150 ret void 151} 152 153define void @load_dereferenceable_not_dominating(ptr %p) { 154; CHECK-LABEL: define void @load_dereferenceable_not_dominating 155; CHECK-SAME: (ptr [[P:%.*]]) { 156; CHECK-NEXT: [[A:%.*]] = load ptr, ptr [[P]], align 8 157; CHECK-NEXT: call void @use.ptr(ptr [[A]]) 158; CHECK-NEXT: call void @use.ptr(ptr [[A]]) 159; CHECK-NEXT: ret void 160; 161 %a = load ptr, ptr %p 162 %b = load ptr, ptr %p, !dereferenceable !{i64 10} 163 call void @use.ptr(ptr %a) 164 call void @use.ptr(ptr %b) 165 ret void 166} 167 168define void @load_ptr_nonnull_to_i64(ptr %p) { 169; CHECK-LABEL: define void @load_ptr_nonnull_to_i64 170; CHECK-SAME: (ptr [[P:%.*]]) { 171; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8 172; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 173; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 174; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 175; CHECK-NEXT: ret void 176; 177 %val = load ptr, ptr %p, align 8, !nonnull !{} 178 %val.int = ptrtoint ptr %val to i64 179 %val2 = load i64, ptr %p, align 8 180 call void @use.i64(i64 %val.int) 181 call void @use.i64(i64 %val2) 182 ret void 183} 184 185define void @load_ptr_nonnull_noundef_to_i64(ptr %p) { 186; CHECK-LABEL: define void @load_ptr_nonnull_noundef_to_i64 187; CHECK-SAME: (ptr [[P:%.*]]) { 188; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !nonnull !6, !noundef !6 189; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 190; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 191; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 192; CHECK-NEXT: ret void 193; 194 %val = load ptr, ptr %p, align 8, !nonnull !{}, !noundef !{} 195 %val.int = ptrtoint ptr %val to i64 196 %val2 = load i64, ptr %p, align 8 197 call void @use.i64(i64 %val.int) 198 call void @use.i64(i64 %val2) 199 ret void 200} 201 202define void @load_ptr_invariant_load_to_i64(ptr %p) { 203; CHECK-LABEL: define void @load_ptr_invariant_load_to_i64 204; CHECK-SAME: (ptr [[P:%.*]]) { 205; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !invariant.load !6 206; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 207; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 208; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 209; CHECK-NEXT: ret void 210; 211 %val = load ptr, ptr %p, align 8, !invariant.load !{} 212 %val.int = ptrtoint ptr %val to i64 213 %val2 = load i64, ptr %p, align 8 214 call void @use.i64(i64 %val.int) 215 call void @use.i64(i64 %val2) 216 ret void 217} 218 219define void @load_ptr_dereferenceable_to_i64(ptr %p) { 220; CHECK-LABEL: define void @load_ptr_dereferenceable_to_i64 221; CHECK-SAME: (ptr [[P:%.*]]) { 222; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable !7 223; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 224; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 225; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 226; CHECK-NEXT: ret void 227; 228 %val = load ptr, ptr %p, align 8, !dereferenceable !{i64 10} 229 %val.int = ptrtoint ptr %val to i64 230 %val2 = load i64, ptr %p, align 8 231 call void @use.i64(i64 %val.int) 232 call void @use.i64(i64 %val2) 233 ret void 234} 235 236define void @load_ptr_dereferenceable_or_null_to_i64(ptr %p) { 237; CHECK-LABEL: define void @load_ptr_dereferenceable_or_null_to_i64 238; CHECK-SAME: (ptr [[P:%.*]]) { 239; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable_or_null !7 240; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 241; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 242; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 243; CHECK-NEXT: ret void 244; 245 %val = load ptr, ptr %p, align 8, !dereferenceable_or_null !{i64 10} 246 %val.int = ptrtoint ptr %val to i64 247 %val2 = load i64, ptr %p, align 8 248 call void @use.i64(i64 %val.int) 249 call void @use.i64(i64 %val2) 250 ret void 251} 252 253define void @load_ptr_nonnull_to_i32(ptr %p) { 254; CHECK-LABEL: define void @load_ptr_nonnull_to_i32 255; CHECK-SAME: (ptr [[P:%.*]]) { 256; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8 257; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 258; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[VAL_INT]] to i32 259; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) 260; CHECK-NEXT: call void @use.i32(i32 [[TMP1]]) 261; CHECK-NEXT: ret void 262; 263 %val = load ptr, ptr %p, align 8, !nonnull !{} 264 %val.int = ptrtoint ptr %val to i64 265 %val2 = load i32, ptr %p, align 8 266 call void @use.i64(i64 %val.int) 267 call void @use.i32(i32 %val2) 268 ret void 269} 270 271define void @load_i64_range_to_i32_range(ptr %p) { 272; CHECK-LABEL: define void @load_i64_range_to_i32_range 273; CHECK-SAME: (ptr [[P:%.*]]) { 274; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[P]], align 8 275; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[VAL]] to i32 276; CHECK-NEXT: call void @use.i64(i64 [[VAL]]) 277; CHECK-NEXT: call void @use.i32(i32 [[TMP1]]) 278; CHECK-NEXT: ret void 279; 280 %val = load i64, ptr %p, align 8, !range !{i64 0, i64 10} 281 %val2 = load i32, ptr %p, align 8, !range !{i32 0, i32 10} 282 call void @use.i64(i64 %val) 283 call void @use.i32(i32 %val2) 284 ret void 285} 286 287define i64 @load_is_stored(ptr %p, ptr %p2) { 288; CHECK-LABEL: define i64 @load_is_stored 289; CHECK-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) { 290; CHECK-NEXT: [[V1:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG8:![0-9]+]] 291; CHECK-NEXT: store i64 [[V1]], ptr [[P2]], align 4 292; CHECK-NEXT: ret i64 [[V1]] 293; 294 %v1 = load i64, ptr %p, !range !{i64 0, i64 10} 295 store i64 %v1, ptr %p2 296 %v2 = load i64, ptr %p2 297 ret i64 %v2 298} 299 300define void @non_local_dominating(i1 %c, ptr %p) { 301; CHECK-LABEL: define void @non_local_dominating 302; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 303; CHECK-NEXT: [[V1:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG9:![0-9]+]] 304; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 305; CHECK: if: 306; CHECK-NEXT: br label [[JOIN]] 307; CHECK: join: 308; CHECK-NEXT: call void @use.i64(i64 [[V1]]) 309; CHECK-NEXT: call void @use.i64(i64 [[V1]]) 310; CHECK-NEXT: ret void 311; 312 %v1 = load i64, ptr %p, !range !{i64 0, i64 10} 313 br i1 %c, label %if, label %join 314 315if: 316 br label %join 317 318join: 319 %v2 = load i64, ptr %p, !range !{i64 20, i64 30} 320 call void @use.i64(i64 %v1) 321 call void @use.i64(i64 %v2) 322 ret void 323} 324 325define void @non_local_non_dominating(i1 %c, ptr %p) { 326; CHECK-LABEL: define void @non_local_non_dominating 327; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 328; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 329; CHECK: if: 330; CHECK-NEXT: [[V1:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG9]] 331; CHECK-NEXT: call void @use.i64(i64 [[V1]]) 332; CHECK-NEXT: br label [[JOIN:%.*]] 333; CHECK: else: 334; CHECK-NEXT: [[V2:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG10:![0-9]+]] 335; CHECK-NEXT: call void @use.i64(i64 [[V2]]) 336; CHECK-NEXT: br label [[JOIN]] 337; CHECK: join: 338; CHECK-NEXT: [[V3:%.*]] = phi i64 [ [[V2]], [[ELSE]] ], [ [[V1]], [[IF]] ] 339; CHECK-NEXT: call void @use.i64(i64 [[V3]]) 340; CHECK-NEXT: ret void 341; 342 br i1 %c, label %if, label %else 343 344if: 345 %v1 = load i64, ptr %p, !range !{i64 0, i64 10} 346 call void @use.i64(i64 %v1) 347 br label %join 348 349else: 350 %v2 = load i64, ptr %p, !range !{i64 10, i64 20} 351 call void @use.i64(i64 %v2) 352 br label %join 353 354join: 355 %v3 = load i64, ptr %p, !range !{i64 20, i64 30} 356 call void @use.i64(i64 %v3) 357 ret void 358} 359 360define void @non_local_coerced(i1 %c, ptr %p) { 361; CHECK-LABEL: define void @non_local_coerced 362; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 363; CHECK-NEXT: [[V1_PTR:%.*]] = load ptr, ptr [[P]], align 8 364; CHECK-NEXT: [[V1:%.*]] = ptrtoint ptr [[V1_PTR]] to i64 365; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 366; CHECK: if: 367; CHECK-NEXT: br label [[JOIN]] 368; CHECK: join: 369; CHECK-NEXT: call void @use.i64(i64 [[V1]]) 370; CHECK-NEXT: call void @use.i64(i64 [[V1]]) 371; CHECK-NEXT: ret void 372; 373 %v1.ptr = load ptr, ptr %p, !nonnull !{} 374 %v1 = ptrtoint ptr %v1.ptr to i64 375 br i1 %c, label %if, label %join 376 377if: 378 br label %join 379 380join: 381 %v2 = load i64, ptr %p, !range !{i64 20, i64 30} 382 call void @use.i64(i64 %v1) 383 call void @use.i64(i64 %v2) 384 ret void 385} 386 387define void @non_local_pre(i1 %c, ptr %p) { 388; CHECK-LABEL: define void @non_local_pre 389; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 390; CHECK-NEXT: [[V2_PRE:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG9]] 391; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 392; CHECK: if: 393; CHECK-NEXT: call void @use.i64(i64 [[V2_PRE]]) 394; CHECK-NEXT: br label [[JOIN]] 395; CHECK: join: 396; CHECK-NEXT: call void @use.i64(i64 [[V2_PRE]]) 397; CHECK-NEXT: ret void 398; 399 br i1 %c, label %if, label %join 400 401if: 402 %v1 = load i64, ptr %p, !range !{i64 0, i64 10} 403 call void @use.i64(i64 %v1) 404 br label %join 405 406join: 407 %v2 = load i64, ptr %p, !range !{i64 20, i64 30} 408 call void @use.i64(i64 %v2) 409 ret void 410} 411 412!0 = !{i32 0, i32 2} 413!1 = !{i32 3, i32 5} 414!2 = !{i32 2, i32 5} 415!3 = !{i32 -5, i32 -2} 416!4 = !{i32 1, i32 5} 417!5 = !{i32 10, i32 1} 418!6 = !{i32 12, i32 16} 419!7 = !{i32 1, i32 2, i32 3, i32 4} 420!8 = !{i32 5, i32 1} 421!9 = !{i32 1, i32 5} 422!10 = !{i32 5, i32 1} 423!11 = !{} 424;. 425; CHECK: attributes #[[ATTR0:[0-9]+]] = { memory(none) } 426;. 427; CHECK: [[RNG0]] = !{i32 0, i32 2} 428; CHECK: [[RNG1]] = !{i32 0, i32 2, i32 3, i32 5} 429; CHECK: [[RNG2]] = !{i32 0, i32 5} 430; CHECK: [[RNG3]] = !{i32 -5, i32 -2, i32 1, i32 5} 431; CHECK: [[RNG4]] = !{i32 10, i32 1} 432; CHECK: [[RNG5]] = !{i32 3, i32 4, i32 5, i32 2} 433; CHECK: [[META6:![0-9]+]] = !{} 434; CHECK: [[META7:![0-9]+]] = !{i64 10} 435; CHECK: [[RNG8]] = !{i64 0, i64 10} 436; CHECK: [[RNG9]] = !{i64 0, i64 10, i64 20, i64 30} 437; CHECK: [[RNG10]] = !{i64 10, i64 30} 438;. 439