1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt < %s -passes=newgvn -S | FileCheck %s 3 4%struct.A = type { ptr } 5@_ZTV1A = available_externally unnamed_addr constant [3 x ptr] [ptr null, ptr @_ZTI1A, ptr @_ZN1A3fooEv], align 8 6@_ZTI1A = external constant ptr 7 8@unknownPtr = external global i8 9 10define i8 @simple() { 11; CHECK-LABEL: define i8 @simple() { 12; CHECK-NEXT: entry: 13; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 14; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0:![0-9]+]] 15; CHECK-NEXT: call void @foo(ptr [[PTR]]) 16; CHECK-NEXT: ret i8 42 17; 18entry: 19 %ptr = alloca i8 20 store i8 42, ptr %ptr, !invariant.group !0 21 call void @foo(ptr %ptr) 22 23 %a = load i8, ptr %ptr, !invariant.group !0 24 %b = load i8, ptr %ptr, !invariant.group !0 25 %c = load i8, ptr %ptr, !invariant.group !0 26 ret i8 %a 27} 28 29define i8 @optimizable1() { 30; CHECK-LABEL: define i8 @optimizable1() { 31; CHECK-NEXT: entry: 32; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 33; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] 34; CHECK-NEXT: [[PTR2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[PTR]]) 35; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 36; CHECK-NEXT: ret i8 42 37; 38entry: 39 %ptr = alloca i8 40 store i8 42, ptr %ptr, !invariant.group !0 41 %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) 42 %a = load i8, ptr %ptr, !invariant.group !0 43 44 call void @foo(ptr %ptr2); call to use %ptr2 45 ret i8 %a 46} 47 48define i8 @optimizable2() { 49; CHECK-LABEL: define i8 @optimizable2() { 50; CHECK-NEXT: entry: 51; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 52; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] 53; CHECK-NEXT: call void @foo(ptr [[PTR]]) 54; CHECK-NEXT: store i8 13, ptr [[PTR]], align 1 55; CHECK-NEXT: call void @bar(i8 13) 56; CHECK-NEXT: call void @foo(ptr [[PTR]]) 57; CHECK-NEXT: ret i8 42 58; 59entry: 60 %ptr = alloca i8 61 store i8 42, ptr %ptr, !invariant.group !0 62 call void @foo(ptr %ptr) 63 64 store i8 13, ptr %ptr ; can't use this store with invariant.group 65 %a = load i8, ptr %ptr 66 call void @bar(i8 %a) ; call to use %a 67 68 call void @foo(ptr %ptr) 69 %b = load i8, ptr %ptr, !invariant.group !0 70 71 ret i8 %b 72} 73 74define i1 @proveEqualityForStrip(ptr %a) { 75; CHECK-LABEL: define i1 @proveEqualityForStrip( 76; CHECK-SAME: ptr [[A:%.*]]) { 77; CHECK-NEXT: ret i1 true 78; 79 %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a) 80 %b2 = call ptr @llvm.strip.invariant.group.p0(ptr %a) 81 %r = icmp eq ptr %b1, %b2 82 ret i1 %r 83} 84 85define i8 @unoptimizable1() { 86; CHECK-LABEL: define i8 @unoptimizable1() { 87; CHECK-NEXT: entry: 88; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 89; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 90; CHECK-NEXT: call void @foo(ptr [[PTR]]) 91; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 92; CHECK-NEXT: ret i8 [[A]] 93; 94entry: 95 %ptr = alloca i8 96 store i8 42, ptr %ptr 97 call void @foo(ptr %ptr) 98 %a = load i8, ptr %ptr, !invariant.group !0 99 ret i8 %a 100} 101 102; NewGVN doesn't support assumes. 103define void @indirectLoads() { 104; CHECK-LABEL: define void @indirectLoads() { 105; CHECK-NEXT: entry: 106; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 107; CHECK-NEXT: [[CALL:%.*]] = call ptr @getPointer(ptr null) 108; CHECK-NEXT: call void @_ZN1AC1Ev(ptr [[CALL]]) 109; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[CALL]], align 8, !invariant.group [[META0]] 110; CHECK-NEXT: [[CMP_VTABLES:%.*]] = icmp eq ptr [[VTABLE]], getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) 111; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_VTABLES]]) 112; CHECK-NEXT: store ptr [[CALL]], ptr [[A]], align 8 113; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VTABLE]], align 8 114; CHECK-NEXT: call void [[TMP0]](ptr [[CALL]]) 115; CHECK-NEXT: [[VTABLE2:%.*]] = load ptr, ptr [[CALL]], align 8, !invariant.group [[META0]] 116; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[VTABLE2]], align 8 117; CHECK-NEXT: call void [[TMP1]](ptr [[CALL]]) 118; CHECK-NEXT: [[VTABLE4:%.*]] = load ptr, ptr [[CALL]], align 8, !invariant.group [[META0]] 119; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[VTABLE4]], align 8 120; CHECK-NEXT: call void [[TMP2]](ptr [[CALL]]) 121; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[VTABLE]], align 8 122; CHECK-NEXT: call void [[TMP3]](ptr [[CALL]]) 123; CHECK-NEXT: ret void 124; 125entry: 126 %a = alloca ptr, align 8 127 128 %call = call ptr @getPointer(ptr null) 129 call void @_ZN1AC1Ev(ptr %call) 130 131 %vtable = load ptr, ptr %call, align 8, !invariant.group !0 132 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) 133 call void @llvm.assume(i1 %cmp.vtables) 134 135 store ptr %call, ptr %a, align 8 136 %0 = load ptr, ptr %a, align 8 137 138; FIXME: call void @_ZN1A3fooEv( 139 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0 140 %1 = load ptr, ptr %vtable1, align 8 141 call void %1(ptr %0) 142 %2 = load ptr, ptr %a, align 8 143 144; FIXME: call void @_ZN1A3fooEv( 145 %vtable2 = load ptr, ptr %2, align 8, !invariant.group !0 146 %3 = load ptr, ptr %vtable2, align 8 147 148 call void %3(ptr %2) 149 %4 = load ptr, ptr %a, align 8 150 151 %vtable4 = load ptr, ptr %4, align 8, !invariant.group !0 152 %5 = load ptr, ptr %vtable4, align 8 153; FIXME: call void @_ZN1A3fooEv( 154 call void %5(ptr %4) 155 156 %vtable5 = load ptr, ptr %call, align 8, !invariant.group !0 157 %6 = load ptr, ptr %vtable5, align 8 158; FIXME: call void @_ZN1A3fooEv( 159 call void %6(ptr %4) 160 161 ret void 162} 163 164; NewGVN won't CSE loads with different pointee types. 165define void @combiningBitCastWithLoad() { 166; CHECK-LABEL: define void @combiningBitCastWithLoad() { 167; CHECK-NEXT: entry: 168; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 169; CHECK-NEXT: [[CALL:%.*]] = call ptr @getPointer(ptr null) 170; CHECK-NEXT: call void @_ZN1AC1Ev(ptr [[CALL]]) 171; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[CALL]], align 8, !invariant.group [[META0]] 172; CHECK-NEXT: store ptr [[CALL]], ptr [[A]], align 8 173; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VTABLE]], align 8 174; CHECK-NEXT: call void [[TMP0]](ptr [[CALL]]) 175; CHECK-NEXT: ret void 176; 177entry: 178 %a = alloca ptr, align 8 179 180 %call = call ptr @getPointer(ptr null) 181 call void @_ZN1AC1Ev(ptr %call) 182 183 %vtable = load ptr, ptr %call, align 8, !invariant.group !0 184 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) 185 186 store ptr %call, ptr %a, align 8 187; FIXME-NOT: !invariant.group 188 %0 = load ptr, ptr %a, align 8 189 190 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0 191 %1 = load ptr, ptr %vtable1, align 8 192 call void %1(ptr %0) 193 194 ret void 195} 196 197define void @loadCombine() { 198; CHECK-LABEL: define void @loadCombine() { 199; CHECK-NEXT: enter: 200; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 201; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 202; CHECK-NEXT: call void @foo(ptr [[PTR]]) 203; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 204; CHECK-NEXT: call void @bar(i8 [[A]]) 205; CHECK-NEXT: call void @bar(i8 [[A]]) 206; CHECK-NEXT: ret void 207; 208enter: 209 %ptr = alloca i8 210 store i8 42, ptr %ptr 211 call void @foo(ptr %ptr) 212 %a = load i8, ptr %ptr, !invariant.group !0 213 %b = load i8, ptr %ptr, !invariant.group !0 214 call void @bar(i8 %a) 215 call void @bar(i8 %b) 216 ret void 217} 218 219define void @loadCombine1() { 220; CHECK-LABEL: define void @loadCombine1() { 221; CHECK-NEXT: enter: 222; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 223; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 224; CHECK-NEXT: call void @foo(ptr [[PTR]]) 225; CHECK-NEXT: [[C:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 226; CHECK-NEXT: call void @bar(i8 [[C]]) 227; CHECK-NEXT: call void @bar(i8 [[C]]) 228; CHECK-NEXT: ret void 229; 230enter: 231 %ptr = alloca i8 232 store i8 42, ptr %ptr 233 call void @foo(ptr %ptr) 234 %c = load i8, ptr %ptr 235 %d = load i8, ptr %ptr, !invariant.group !0 236 call void @bar(i8 %c) 237 call void @bar(i8 %d) 238 ret void 239} 240 241define void @loadCombine2() { 242; CHECK-LABEL: define void @loadCombine2() { 243; CHECK-NEXT: enter: 244; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 245; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 246; CHECK-NEXT: call void @foo(ptr [[PTR]]) 247; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 248; CHECK-NEXT: call void @bar(i8 [[E]]) 249; CHECK-NEXT: call void @bar(i8 [[E]]) 250; CHECK-NEXT: ret void 251; 252enter: 253 %ptr = alloca i8 254 store i8 42, ptr %ptr 255 call void @foo(ptr %ptr) 256 %e = load i8, ptr %ptr, !invariant.group !0 257 %f = load i8, ptr %ptr 258 call void @bar(i8 %e) 259 call void @bar(i8 %f) 260 ret void 261} 262 263define void @loadCombine3() { 264; CHECK-LABEL: define void @loadCombine3() { 265; CHECK-NEXT: enter: 266; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 267; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 268; CHECK-NEXT: call void @foo(ptr [[PTR]]) 269; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 270; CHECK-NEXT: call void @bar(i8 [[E]]) 271; CHECK-NEXT: call void @bar(i8 [[E]]) 272; CHECK-NEXT: ret void 273; 274enter: 275 %ptr = alloca i8 276 store i8 42, ptr %ptr 277 call void @foo(ptr %ptr) 278 %e = load i8, ptr %ptr, !invariant.group !0 279 %f = load i8, ptr %ptr, !invariant.group !0 280 call void @bar(i8 %e) 281 call void @bar(i8 %f) 282 ret void 283} 284 285define i8 @unoptimizable2() { 286; CHECK-LABEL: define i8 @unoptimizable2() { 287; CHECK-NEXT: entry: 288; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 289; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 290; CHECK-NEXT: call void @foo(ptr [[PTR]]) 291; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR]], align 1 292; CHECK-NEXT: call void @foo(ptr [[PTR]]) 293; CHECK-NEXT: ret i8 [[A]] 294; 295entry: 296 %ptr = alloca i8 297 store i8 42, ptr %ptr 298 call void @foo(ptr %ptr) 299 %a = load i8, ptr %ptr 300 call void @foo(ptr %ptr) 301 %b = load i8, ptr %ptr, !invariant.group !0 302 303 ret i8 %a 304} 305 306define i8 @unoptimizable3() { 307; CHECK-LABEL: define i8 @unoptimizable3() { 308; CHECK-NEXT: entry: 309; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 310; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] 311; CHECK-NEXT: [[PTR2:%.*]] = call ptr @getPointer(ptr [[PTR]]) 312; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR2]], align 1, !invariant.group [[META0]] 313; CHECK-NEXT: ret i8 [[A]] 314; 315entry: 316 %ptr = alloca i8 317 store i8 42, ptr %ptr, !invariant.group !0 318 %ptr2 = call ptr @getPointer(ptr %ptr) 319 %a = load i8, ptr %ptr2, !invariant.group !0 320 321 ret i8 %a 322} 323 324; NewGVN cares about the launder for some reason. 325define i8 @optimizable4() { 326; CHECK-LABEL: define i8 @optimizable4() { 327; CHECK-NEXT: entry: 328; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 329; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 330; CHECK-NEXT: [[PTR2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[PTR]]) 331; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR2]], align 1 332; CHECK-NEXT: ret i8 [[A]] 333; 334entry: 335 %ptr = alloca i8 336 store i8 42, ptr %ptr 337 %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) 338; FIXME-NOT: load 339 %a = load i8, ptr %ptr2 340 341; FIXME: ret i8 42 342 ret i8 %a 343} 344 345define i8 @volatile1() { 346; CHECK-LABEL: define i8 @volatile1() { 347; CHECK-NEXT: entry: 348; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 349; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] 350; CHECK-NEXT: call void @foo(ptr [[PTR]]) 351; CHECK-NEXT: [[B:%.*]] = load volatile i8, ptr [[PTR]], align 1 352; CHECK-NEXT: call void @bar(i8 [[B]]) 353; CHECK-NEXT: [[C:%.*]] = load volatile i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 354; CHECK-NEXT: call void @bar(i8 [[C]]) 355; CHECK-NEXT: ret i8 42 356; 357entry: 358 %ptr = alloca i8 359 store i8 42, ptr %ptr, !invariant.group !0 360 call void @foo(ptr %ptr) 361 %a = load i8, ptr %ptr, !invariant.group !0 362 %b = load volatile i8, ptr %ptr 363 call void @bar(i8 %b) 364 365 %c = load volatile i8, ptr %ptr, !invariant.group !0 366; We might be able to optimize this, but nobody cares 367 call void @bar(i8 %c) 368 ret i8 %a 369} 370 371define i8 @volatile2() { 372; CHECK-LABEL: define i8 @volatile2() { 373; CHECK-NEXT: entry: 374; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 375; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] 376; CHECK-NEXT: call void @foo(ptr [[PTR]]) 377; CHECK-NEXT: [[B:%.*]] = load volatile i8, ptr [[PTR]], align 1 378; CHECK-NEXT: call void @bar(i8 [[B]]) 379; CHECK-NEXT: [[C:%.*]] = load volatile i8, ptr [[PTR]], align 1, !invariant.group [[META0]] 380; CHECK-NEXT: call void @bar(i8 [[C]]) 381; CHECK-NEXT: ret i8 42 382; 383entry: 384 %ptr = alloca i8 385 store i8 42, ptr %ptr, !invariant.group !0 386 call void @foo(ptr %ptr) 387 %a = load i8, ptr %ptr, !invariant.group !0 388 %b = load volatile i8, ptr %ptr 389 call void @bar(i8 %b) 390 391 %c = load volatile i8, ptr %ptr, !invariant.group !0 392; We might be able to optimize this, but nobody cares 393 call void @bar(i8 %c) 394 ret i8 %a 395} 396 397define void @fun() { 398; CHECK-LABEL: define void @fun() { 399; CHECK-NEXT: entry: 400; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 401; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] 402; CHECK-NEXT: call void @foo(ptr [[PTR]]) 403; CHECK-NEXT: call void @bar(i8 42) 404; CHECK-NEXT: ret void 405; 406entry: 407 %ptr = alloca i8 408 store i8 42, ptr %ptr, !invariant.group !0 409 call void @foo(ptr %ptr) 410 411 %a = load i8, ptr %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change 412 call void @bar(i8 %a) 413 414 ret void 415} 416 417; FIXME: NewGVN doesn't run instsimplify on a load from a vtable definition? 418; This test checks if invariant.group understands gep with zeros 419define void @testGEP0() { 420; CHECK-LABEL: define void @testGEP0() { 421; CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 8 422; CHECK-NEXT: store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr [[A]], align 8, !invariant.group [[META0]] 423; CHECK-NEXT: call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) [[A]]) 424; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @unknownPtr, align 4 425; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0 426; CHECK-NEXT: br i1 [[TMP2]], label [[_Z1GR1A_EXIT:%.*]], label [[TMP3:%.*]] 427; CHECK: 3: 428; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), align 8 429; CHECK-NEXT: call void [[TMP4]](ptr nonnull [[A]]) 430; CHECK-NEXT: br label [[_Z1GR1A_EXIT]] 431; CHECK: _Z1gR1A.exit: 432; CHECK-NEXT: ret void 433; 434 %a = alloca %struct.A, align 8 435 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0 436 call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) ; This call may change vptr 437 %1 = load i8, ptr @unknownPtr, align 4 438 %2 = icmp eq i8 %1, 0 439 br i1 %2, label %_Z1gR1A.exit, label %3 440 441; This should be devirtualized by invariant.group 442 %4 = load ptr, ptr %a, align 8, !invariant.group !0 443 %5 = load ptr, ptr %4, align 8 444; FIXME: call void @_ZN1A3fooEv(ptr nonnull %a) 445 call void %5(ptr nonnull %a) 446 br label %_Z1gR1A.exit 447 448_Z1gR1A.exit: ; preds = %0, %3 449 ret void 450} 451 452; Check if no optimizations are performed with global pointers. 453; FIXME: we could do the optimizations if we would check if dependency comes 454; from the same function. 455define void @testGlobal() { 456; CHECK-LABEL: define void @testGlobal() { 457; CHECK-NEXT: [[A:%.*]] = load i8, ptr @unknownPtr, align 1, !invariant.group [[META0]] 458; CHECK-NEXT: call void @foo2(ptr @unknownPtr, i8 [[A]]) 459; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @unknownPtr, align 1, !invariant.group [[META0]] 460; CHECK-NEXT: call void @bar(i8 [[TMP1]]) 461; CHECK-NEXT: call void @fooBit(ptr @unknownPtr, i1 true) 462; CHECK-NEXT: [[TMP2:%.*]] = load i1, ptr @unknownPtr, align 1, !invariant.group [[META0]] 463; CHECK-NEXT: call void @fooBit(ptr @unknownPtr, i1 [[TMP2]]) 464; CHECK-NEXT: [[TMP3:%.*]] = load i1, ptr @unknownPtr, align 1, !invariant.group [[META0]] 465; CHECK-NEXT: call void @fooBit(ptr @unknownPtr, i1 [[TMP3]]) 466; CHECK-NEXT: ret void 467; 468 %a = load i8, ptr @unknownPtr, !invariant.group !0 469 call void @foo2(ptr @unknownPtr, i8 %a) 470 %1 = load i8, ptr @unknownPtr, !invariant.group !0 471 call void @bar(i8 %1) 472 473 call void @fooBit(ptr @unknownPtr, i1 1) 474; Adding regex because of canonicalization of bitcasts 475 %2 = load i1, ptr @unknownPtr, !invariant.group !0 476 call void @fooBit(ptr @unknownPtr, i1 %2) 477 %3 = load i1, ptr @unknownPtr, !invariant.group !0 478 call void @fooBit(ptr @unknownPtr, i1 %3) 479 ret void 480} 481 482; Might be similar to above where NewGVN doesn't handle loads of different types from the same location. 483; Not super important anyway. 484define void @testTrunc() { 485; CHECK-LABEL: define void @testTrunc() { 486; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 487; CHECK-NEXT: call void @foo(ptr [[A]]) 488; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[A]], align 1, !invariant.group [[META0]] 489; CHECK-NEXT: call void @foo2(ptr [[A]], i8 [[B]]) 490; CHECK-NEXT: call void @bar(i8 [[B]]) 491; CHECK-NEXT: call void @fooBit(ptr [[A]], i1 true) 492; CHECK-NEXT: [[TMP1:%.*]] = load i1, ptr [[A]], align 1, !invariant.group [[META0]] 493; CHECK-NEXT: call void @fooBit(ptr [[A]], i1 [[TMP1]]) 494; CHECK-NEXT: call void @fooBit(ptr [[A]], i1 [[TMP1]]) 495; CHECK-NEXT: ret void 496; 497 %a = alloca i8 498 call void @foo(ptr %a) 499 %b = load i8, ptr %a, !invariant.group !0 500 call void @foo2(ptr %a, i8 %b) 501 502 %1 = load i8, ptr %a, !invariant.group !0 503 call void @bar(i8 %1) 504 505 call void @fooBit(ptr %a, i1 1) 506; FIXME: %1 = trunc i8 %b to i1 507 %2 = load i1, ptr %a, !invariant.group !0 508; FIXME-NEXT: call void @fooBit(ptr %a, i1 %1) 509 call void @fooBit(ptr %a, i1 %2) 510 %3 = load i1, ptr %a, !invariant.group !0 511; FIXME-NEXT: call void @fooBit(ptr %a, i1 %1) 512 call void @fooBit(ptr %a, i1 %3) 513 ret void 514} 515 516; See comment in @testGEP0 on what NewGVN is lacking. 517define void @handling_loops() { 518; CHECK-LABEL: define void @handling_loops() { 519; CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 8 520; CHECK-NEXT: store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr [[A]], align 8, !invariant.group [[META0]] 521; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @unknownPtr, align 4 522; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0 523; CHECK-NEXT: br i1 [[TMP2]], label [[DOTLR_PH_I:%.*]], label [[_Z2G2R1A_EXIT:%.*]] 524; CHECK: .lr.ph.i: 525; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i8 [[TMP1]], 1 526; CHECK-NEXT: br i1 [[TMP3]], label [[DOT_CRIT_EDGE_PREHEADER:%.*]], label [[_Z2G2R1A_EXIT]] 527; CHECK: ._crit_edge.preheader: 528; CHECK-NEXT: br label [[DOT_CRIT_EDGE:%.*]] 529; CHECK: ._crit_edge: 530; CHECK-NEXT: [[TMP4:%.*]] = phi i8 [ [[TMP6:%.*]], [[DOT_CRIT_EDGE]] ], [ 1, [[DOT_CRIT_EDGE_PREHEADER]] ] 531; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), align 8 532; CHECK-NEXT: call void [[TMP5]](ptr nonnull [[A]]) 533; CHECK-NEXT: [[TMP6]] = add nuw nsw i8 [[TMP4]], 1 534; CHECK-NEXT: [[TMP7:%.*]] = load i8, ptr @unknownPtr, align 4 535; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i8 [[TMP6]], [[TMP7]] 536; CHECK-NEXT: br i1 [[TMP8]], label [[DOT_CRIT_EDGE]], label [[_Z2G2R1A_EXIT_LOOPEXIT:%.*]] 537; CHECK: _Z2g2R1A.exit.loopexit: 538; CHECK-NEXT: br label [[_Z2G2R1A_EXIT]] 539; CHECK: _Z2g2R1A.exit: 540; CHECK-NEXT: ret void 541; 542 %a = alloca %struct.A, align 8 543 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0 544 %1 = load i8, ptr @unknownPtr, align 4 545 %2 = icmp sgt i8 %1, 0 546 br i1 %2, label %.lr.ph.i, label %_Z2g2R1A.exit 547 548.lr.ph.i: ; preds = %0 549 %3 = load i8, ptr @unknownPtr, align 4 550 %4 = icmp sgt i8 %3, 1 551 br i1 %4, label %._crit_edge.preheader, label %_Z2g2R1A.exit 552 553._crit_edge.preheader: ; preds = %.lr.ph.i 554 br label %._crit_edge 555 556._crit_edge: ; preds = %._crit_edge.preheader, %._crit_edge 557 %5 = phi i8 [ %7, %._crit_edge ], [ 1, %._crit_edge.preheader ] 558 %.pre = load ptr, ptr %a, align 8, !invariant.group !0 559 %6 = load ptr, ptr %.pre, align 8 560 ; FIXME: call void @_ZN1A3fooEv(ptr nonnull %a) 561 call void %6(ptr nonnull %a) #3 562 ; FIXME-NOT: call void % 563 %7 = add nuw nsw i8 %5, 1 564 %8 = load i8, ptr @unknownPtr, align 4 565 %9 = icmp slt i8 %7, %8 566 br i1 %9, label %._crit_edge, label %_Z2g2R1A.exit.loopexit 567 568_Z2g2R1A.exit.loopexit: ; preds = %._crit_edge 569 br label %_Z2g2R1A.exit 570 571_Z2g2R1A.exit: ; preds = %_Z2g2R1A.exit.loopexit, %.lr.ph.i, %0 572 ret void 573} 574 575 576declare void @foo(ptr) 577declare void @foo2(ptr, i8) 578declare void @bar(i8) 579declare ptr @getPointer(ptr) 580declare void @_ZN1A3fooEv(ptr) 581declare void @_ZN1AC1Ev(ptr) 582declare void @fooBit(ptr, i1) 583 584declare ptr @llvm.launder.invariant.group.p0(ptr) 585declare ptr @llvm.strip.invariant.group.p0(ptr) 586 587; Function Attrs: nounwind 588declare void @llvm.assume(i1 %cmp.vtables) #0 589 590 591attributes #0 = { nounwind } 592!0 = !{} 593;. 594; CHECK: [[META0]] = !{} 595;. 596