diff options
Diffstat (limited to 'llvm/test/Transforms/GVN/invariant.group.ll')
-rw-r--r-- | llvm/test/Transforms/GVN/invariant.group.ll | 563 |
1 files changed, 357 insertions, 206 deletions
diff --git a/llvm/test/Transforms/GVN/invariant.group.ll b/llvm/test/Transforms/GVN/invariant.group.ll index 9c673ba..aba20ee 100644 --- a/llvm/test/Transforms/GVN/invariant.group.ll +++ b/llvm/test/Transforms/GVN/invariant.group.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt < %s -passes=gvn -S | FileCheck %s %struct.A = type { ptr } @@ -6,130 +7,175 @@ @unknownPtr = external global i8 -; CHECK-LABEL: define i8 @simple() { define i8 @simple() { +; CHECK-LABEL: define i8 @simple() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0:![0-9]+]] +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: ret i8 42 +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - call void @foo(ptr %ptr) - - %a = load i8, ptr %ptr, !invariant.group !0 - %b = load i8, ptr %ptr, !invariant.group !0 - %c = load i8, ptr %ptr, !invariant.group !0 -; CHECK: ret i8 42 - ret i8 %a + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + call void @foo(ptr %ptr) + + %a = load i8, ptr %ptr, !invariant.group !0 + %b = load i8, ptr %ptr, !invariant.group !0 + %c = load i8, ptr %ptr, !invariant.group !0 + ret i8 %a } -; CHECK-LABEL: define i8 @optimizable1() { define i8 @optimizable1() { +; CHECK-LABEL: define i8 @optimizable1() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: [[PTR2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[PTR]]) +; CHECK-NEXT: call void @foo(ptr [[PTR2]]) +; CHECK-NEXT: ret i8 42 +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) - %a = load i8, ptr %ptr, !invariant.group !0 - - call void @foo(ptr %ptr2); call to use %ptr2 -; CHECK: ret i8 42 - ret i8 %a + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) + %a = load i8, ptr %ptr, !invariant.group !0 + + call void @foo(ptr %ptr2); call to use %ptr2 + ret i8 %a } -; CHECK-LABEL: define i8 @optimizable2() { define i8 @optimizable2() { +; CHECK-LABEL: define i8 @optimizable2() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: store i8 13, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @bar(i8 13) +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: ret i8 42 +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - call void @foo(ptr %ptr) - - store i8 13, ptr %ptr ; can't use this store with invariant.group - %a = load i8, ptr %ptr - call void @bar(i8 %a) ; call to use %a - - call void @foo(ptr %ptr) - %b = load i8, ptr %ptr, !invariant.group !0 - -; CHECK: ret i8 42 - ret i8 %b + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + call void @foo(ptr %ptr) + + store i8 13, ptr %ptr ; can't use this store with invariant.group + %a = load i8, ptr %ptr + call void @bar(i8 %a) ; call to use %a + + call void @foo(ptr %ptr) + %b = load i8, ptr %ptr, !invariant.group !0 + + ret i8 %b } -; CHECK-LABEL: define i1 @proveEqualityForStrip( -define i1 @proveEqualityForStrip(ptr %a) { ; FIXME: The first call could be also removed by GVN. Right now ; DCE removes it. The second call is CSE'd with the first one. -; CHECK: %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a) +define i1 @proveEqualityForStrip(ptr %a) { +; CHECK-LABEL: define i1 @proveEqualityForStrip( +; CHECK-SAME: ptr [[A:%.*]]) { +; CHECK-NEXT: [[B1:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[A]]) +; CHECK-NEXT: ret i1 true +; %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a) -; CHECK-NOT: llvm.strip.invariant.group %b2 = call ptr @llvm.strip.invariant.group.p0(ptr %a) %r = icmp eq ptr %b1, %b2 -; CHECK: ret i1 true ret i1 %r } -; CHECK-LABEL: define i8 @unoptimizable1() { + define i8 @unoptimizable1() { +; CHECK-LABEL: define i8 @unoptimizable1() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: ret i8 [[A]] +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr - call void @foo(ptr %ptr) - %a = load i8, ptr %ptr, !invariant.group !0 -; CHECK: ret i8 %a - ret i8 %a + %ptr = alloca i8 + store i8 42, ptr %ptr + call void @foo(ptr %ptr) + %a = load i8, ptr %ptr, !invariant.group !0 + ret i8 %a } -; CHECK-LABEL: define void @indirectLoads() { define void @indirectLoads() { +; CHECK-LABEL: define void @indirectLoads() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: [[CALL:%.*]] = call ptr @getPointer(ptr null) +; CHECK-NEXT: call void @_ZN1AC1Ev(ptr [[CALL]]) +; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[CALL]], align 8, !invariant.group [[META0]] +; CHECK-NEXT: [[CMP_VTABLES:%.*]] = icmp eq ptr [[VTABLE]], getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_VTABLES]]) +; CHECK-NEXT: store ptr [[CALL]], ptr [[A]], align 8 +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr [[CALL]]) +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr [[CALL]]) +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr [[CALL]]) +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr [[CALL]]) +; CHECK-NEXT: ret void +; entry: %a = alloca ptr, align 8 - - %call = call ptr @getPointer(ptr null) + + %call = call ptr @getPointer(ptr null) call void @_ZN1AC1Ev(ptr %call) - -; CHECK: %vtable = load {{.*}} !invariant.group + %vtable = load ptr, ptr %call, align 8, !invariant.group !0 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) call void @llvm.assume(i1 %cmp.vtables) - + store ptr %call, ptr %a, align 8 %0 = load ptr, ptr %a, align 8 -; CHECK: call void @_ZN1A3fooEv( %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0 %1 = load ptr, ptr %vtable1, align 8 call void %1(ptr %0) %2 = load ptr, ptr %a, align 8 -; CHECK: call void @_ZN1A3fooEv( %vtable2 = load ptr, ptr %2, align 8, !invariant.group !0 %3 = load ptr, ptr %vtable2, align 8 - + call void %3(ptr %2) %4 = load ptr, ptr %a, align 8 - + %vtable4 = load ptr, ptr %4, align 8, !invariant.group !0 %5 = load ptr, ptr %vtable4, align 8 -; CHECK: call void @_ZN1A3fooEv( call void %5(ptr %4) - + %vtable5 = load ptr, ptr %call, align 8, !invariant.group !0 %6 = load ptr, ptr %vtable5, align 8 -; CHECK: call void @_ZN1A3fooEv( call void %6(ptr %4) - + ret void } -; CHECK-LABEL: define void @combiningBitCastWithLoad() { define void @combiningBitCastWithLoad() { +; CHECK-LABEL: define void @combiningBitCastWithLoad() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: [[CALL:%.*]] = call ptr @getPointer(ptr null) +; CHECK-NEXT: call void @_ZN1AC1Ev(ptr [[CALL]]) +; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[CALL]], align 8, !invariant.group [[META0]] +; CHECK-NEXT: [[CMP_VTABLES:%.*]] = icmp eq ptr [[VTABLE]], getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) +; CHECK-NEXT: store ptr [[CALL]], ptr [[A]], align 8 +; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VTABLE]], align 8 +; CHECK-NEXT: call void [[TMP0]](ptr [[CALL]]) +; CHECK-NEXT: ret void +; entry: %a = alloca ptr, align 8 - - %call = call ptr @getPointer(ptr null) + + %call = call ptr @getPointer(ptr null) call void @_ZN1AC1Ev(ptr %call) - -; CHECK: %vtable = load {{.*}} !invariant.group + %vtable = load ptr, ptr %call, align 8, !invariant.group !0 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) - + store ptr %call, ptr %a, align 8 -; CHECK-NOT: !invariant.group %0 = load ptr, ptr %a, align 8 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0 @@ -139,185 +185,255 @@ entry: ret void } -; CHECK-LABEL:define void @loadCombine() { define void @loadCombine() { +; CHECK-LABEL: define void @loadCombine() { +; CHECK-NEXT: [[ENTER:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[A]]) +; CHECK-NEXT: call void @bar(i8 [[A]]) +; CHECK-NEXT: ret void +; enter: %ptr = alloca i8 store i8 42, ptr %ptr call void @foo(ptr %ptr) -; CHECK: %[[A:.*]] = load i8, ptr %ptr, align 1, !invariant.group %a = load i8, ptr %ptr, !invariant.group !0 -; CHECK-NOT: load %b = load i8, ptr %ptr, !invariant.group !0 -; CHECK: call void @bar(i8 %[[A]]) call void @bar(i8 %a) -; CHECK: call void @bar(i8 %[[A]]) call void @bar(i8 %b) ret void } -; CHECK-LABEL: define void @loadCombine1() { define void @loadCombine1() { +; CHECK-LABEL: define void @loadCombine1() { +; CHECK-NEXT: [[ENTER:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[C:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[C]]) +; CHECK-NEXT: call void @bar(i8 [[C]]) +; CHECK-NEXT: ret void +; enter: %ptr = alloca i8 store i8 42, ptr %ptr call void @foo(ptr %ptr) -; CHECK: %[[D:.*]] = load i8, ptr %ptr, align 1, !invariant.group %c = load i8, ptr %ptr -; CHECK-NOT: load %d = load i8, ptr %ptr, !invariant.group !0 -; CHECK: call void @bar(i8 %[[D]]) call void @bar(i8 %c) -; CHECK: call void @bar(i8 %[[D]]) call void @bar(i8 %d) ret void } -; CHECK-LABEL: define void @loadCombine2() { define void @loadCombine2() { +; CHECK-LABEL: define void @loadCombine2() { +; CHECK-NEXT: [[ENTER:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[E]]) +; CHECK-NEXT: call void @bar(i8 [[E]]) +; CHECK-NEXT: ret void +; enter: %ptr = alloca i8 store i8 42, ptr %ptr call void @foo(ptr %ptr) -; CHECK: %[[E:.*]] = load i8, ptr %ptr, align 1, !invariant.group %e = load i8, ptr %ptr, !invariant.group !0 -; CHECK-NOT: load %f = load i8, ptr %ptr -; CHECK: call void @bar(i8 %[[E]]) call void @bar(i8 %e) -; CHECK: call void @bar(i8 %[[E]]) call void @bar(i8 %f) ret void } -; CHECK-LABEL: define void @loadCombine3() { define void @loadCombine3() { +; CHECK-LABEL: define void @loadCombine3() { +; CHECK-NEXT: [[ENTER:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[E]]) +; CHECK-NEXT: call void @bar(i8 [[E]]) +; CHECK-NEXT: ret void +; enter: %ptr = alloca i8 store i8 42, ptr %ptr call void @foo(ptr %ptr) -; CHECK: %[[E:.*]] = load i8, ptr %ptr, align 1, !invariant.group %e = load i8, ptr %ptr, !invariant.group !0 -; CHECK-NOT: load %f = load i8, ptr %ptr, !invariant.group !0 -; CHECK: call void @bar(i8 %[[E]]) call void @bar(i8 %e) -; CHECK: call void @bar(i8 %[[E]]) call void @bar(i8 %f) ret void } -; CHECK-LABEL: define i8 @unoptimizable2() { define i8 @unoptimizable2() { +; CHECK-LABEL: define i8 @unoptimizable2() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: ret i8 [[A]] +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr - call void @foo(ptr %ptr) - %a = load i8, ptr %ptr - call void @foo(ptr %ptr) - %b = load i8, ptr %ptr, !invariant.group !0 - -; CHECK: ret i8 %a - ret i8 %a + %ptr = alloca i8 + store i8 42, ptr %ptr + call void @foo(ptr %ptr) + %a = load i8, ptr %ptr + call void @foo(ptr %ptr) + %b = load i8, ptr %ptr, !invariant.group !0 + + ret i8 %a } -; CHECK-LABEL: define i8 @unoptimizable3() { define i8 @unoptimizable3() { +; CHECK-LABEL: define i8 @unoptimizable3() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: [[PTR2:%.*]] = call ptr @getPointer(ptr [[PTR]]) +; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[PTR2]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: ret i8 [[A]] +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - %ptr2 = call ptr @getPointer(ptr %ptr) - %a = load i8, ptr %ptr2, !invariant.group !0 - -; CHECK: ret i8 %a - ret i8 %a + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + %ptr2 = call ptr @getPointer(ptr %ptr) + %a = load i8, ptr %ptr2, !invariant.group !0 + + ret i8 %a } -; CHECK-LABEL: define i8 @optimizable4() { define i8 @optimizable4() { +; CHECK-LABEL: define i8 @optimizable4() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: [[PTR2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[PTR]]) +; CHECK-NEXT: ret i8 42 +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) -; CHECK-NOT: load - %a = load i8, ptr %ptr2, !invariant.group !0 - -; CHECK: ret i8 42 - ret i8 %a + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) + %a = load i8, ptr %ptr2, !invariant.group !0 + + ret i8 %a } -; CHECK-LABEL: define i8 @volatile1() { define i8 @volatile1() { +; CHECK-LABEL: define i8 @volatile1() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[B:%.*]] = load volatile i8, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @bar(i8 [[B]]) +; CHECK-NEXT: [[C:%.*]] = load volatile i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[C]]) +; CHECK-NEXT: ret i8 42 +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - call void @foo(ptr %ptr) - %a = load i8, ptr %ptr, !invariant.group !0 - %b = load volatile i8, ptr %ptr -; CHECK: call void @bar(i8 %b) - call void @bar(i8 %b) - - %c = load volatile i8, ptr %ptr, !invariant.group !0 + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + call void @foo(ptr %ptr) + %a = load i8, ptr %ptr, !invariant.group !0 + %b = load volatile i8, ptr %ptr + call void @bar(i8 %b) + + %c = load volatile i8, ptr %ptr, !invariant.group !0 ; FIXME: we could change %c to 42, preserving volatile load -; CHECK: call void @bar(i8 %c) - call void @bar(i8 %c) -; CHECK: ret i8 42 - ret i8 %a + call void @bar(i8 %c) + ret i8 %a } -; CHECK-LABEL: define i8 @volatile2() { define i8 @volatile2() { +; CHECK-LABEL: define i8 @volatile2() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: [[B:%.*]] = load volatile i8, ptr [[PTR]], align 1 +; CHECK-NEXT: call void @bar(i8 [[B]]) +; CHECK-NEXT: [[C:%.*]] = load volatile i8, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[C]]) +; CHECK-NEXT: ret i8 42 +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - call void @foo(ptr %ptr) - %a = load i8, ptr %ptr, !invariant.group !0 - %b = load volatile i8, ptr %ptr -; CHECK: call void @bar(i8 %b) - call void @bar(i8 %b) - - %c = load volatile i8, ptr %ptr, !invariant.group !0 + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + call void @foo(ptr %ptr) + %a = load i8, ptr %ptr, !invariant.group !0 + %b = load volatile i8, ptr %ptr + call void @bar(i8 %b) + + %c = load volatile i8, ptr %ptr, !invariant.group !0 ; FIXME: we could change %c to 42, preserving volatile load -; CHECK: call void @bar(i8 %c) - call void @bar(i8 %c) -; CHECK: ret i8 42 - ret i8 %a + call void @bar(i8 %c) + ret i8 %a } -; CHECK-LABEL: define i8 @fun() { define i8 @fun() { +; CHECK-LABEL: define i8 @fun() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 42, ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @foo(ptr [[PTR]]) +; CHECK-NEXT: call void @bar(i8 42) +; CHECK-NEXT: [[NEWPTR:%.*]] = call ptr @getPointer(ptr [[PTR]]) +; CHECK-NEXT: [[C:%.*]] = load i8, ptr [[NEWPTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[C]]) +; CHECK-NEXT: [[UNKNOWNVALUE:%.*]] = load i8, ptr @unknownPtr, align 1 +; CHECK-NEXT: store i8 [[UNKNOWNVALUE]], ptr [[PTR]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: [[NEWPTR2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[PTR]]) +; CHECK-NEXT: ret i8 [[UNKNOWNVALUE]] +; entry: - %ptr = alloca i8 - store i8 42, ptr %ptr, !invariant.group !0 - call void @foo(ptr %ptr) - - %a = load i8, ptr %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change -; CHECK: call void @bar(i8 42) - call void @bar(i8 %a) - - %newPtr = call ptr @getPointer(ptr %ptr) - %c = load i8, ptr %newPtr, !invariant.group !0 ; Can't assume anything, because we only have information about %ptr -; CHECK: call void @bar(i8 %c) - call void @bar(i8 %c) - - %unknownValue = load i8, ptr @unknownPtr + %ptr = alloca i8 + store i8 42, ptr %ptr, !invariant.group !0 + call void @foo(ptr %ptr) + + %a = load i8, ptr %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change + call void @bar(i8 %a) + + %newPtr = call ptr @getPointer(ptr %ptr) + %c = load i8, ptr %newPtr, !invariant.group !0 ; Can't assume anything, because we only have information about %ptr + call void @bar(i8 %c) + + %unknownValue = load i8, ptr @unknownPtr ; FIXME: Can assume that %unknownValue == 42 -; CHECK: store i8 %unknownValue, ptr %ptr, align 1, !invariant.group !0 - store i8 %unknownValue, ptr %ptr, !invariant.group !0 - - %newPtr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) -; CHECK-NOT: load - %d = load i8, ptr %newPtr2, !invariant.group !0 -; CHECK: ret i8 %unknownValue - ret i8 %d + store i8 %unknownValue, ptr %ptr, !invariant.group !0 + + %newPtr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) + %d = load i8, ptr %newPtr2, !invariant.group !0 + ret i8 %d } ; This test checks if invariant.group understands gep with zeros -; CHECK-LABEL: define void @testGEP0() { define void @testGEP0() { +; CHECK-LABEL: define void @testGEP0() { +; CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 8 +; CHECK-NEXT: store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr [[A]], align 8, !invariant.group [[META0]] +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) [[A]]) +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @unknownPtr, align 4 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0 +; CHECK-NEXT: br i1 [[TMP2]], label %[[_Z1GR1A_EXIT:.*]], label %[[BB3:.*]] +; CHECK: [[BB3]]: +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr nonnull [[A]]) +; CHECK-NEXT: br label %[[_Z1GR1A_EXIT]] +; CHECK: [[_Z1GR1A_EXIT]]: +; CHECK-NEXT: ret void +; %a = alloca %struct.A, align 8 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0 -; CHECK: call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) ; This call may change vptr %1 = load i8, ptr @unknownPtr, align 4 %2 = icmp eq i8 %1, 0 @@ -326,7 +442,6 @@ define void @testGEP0() { ; This should be devirtualized by invariant.group %4 = load ptr, ptr %a, align 8, !invariant.group !0 %5 = load ptr, ptr %4, align 8 -; CHECK: call void @_ZN1A3fooEv(ptr nonnull %a) call void %5(ptr nonnull %a) br label %_Z1gR1A.exit @@ -337,51 +452,86 @@ _Z1gR1A.exit: ; preds = %0, %3 ; Check if no optimizations are performed with global pointers. ; FIXME: we could do the optimizations if we would check if dependency comes ; from the same function. -; CHECK-LABEL: define void @testGlobal() { define void @testGlobal() { -; CHECK: %a = load i8, ptr @unknownPtr, align 1, !invariant.group !0 - %a = load i8, ptr @unknownPtr, !invariant.group !0 - call void @foo2(ptr @unknownPtr, i8 %a) -; CHECK: %1 = load i8, ptr @unknownPtr, align 1, !invariant.group !0 - %1 = load i8, ptr @unknownPtr, !invariant.group !0 - call void @bar(i8 %1) - - call void @fooBit(ptr @unknownPtr, i1 1) +; CHECK-LABEL: define void @testGlobal() { +; CHECK-NEXT: [[A:%.*]] = load i8, ptr @unknownPtr, align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @foo2(ptr @unknownPtr, i8 [[A]]) +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @unknownPtr, align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @bar(i8 [[TMP1]]) +; CHECK-NEXT: call void @fooBit(ptr @unknownPtr, i1 true) +; CHECK-NEXT: [[TMP2:%.*]] = load i1, ptr @unknownPtr, align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @fooBit(ptr @unknownPtr, i1 [[TMP2]]) +; CHECK-NEXT: [[TMP3:%.*]] = load i1, ptr @unknownPtr, align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @fooBit(ptr @unknownPtr, i1 [[TMP3]]) +; CHECK-NEXT: ret void +; + %a = load i8, ptr @unknownPtr, !invariant.group !0 + call void @foo2(ptr @unknownPtr, i8 %a) + %1 = load i8, ptr @unknownPtr, !invariant.group !0 + call void @bar(i8 %1) + + call void @fooBit(ptr @unknownPtr, i1 1) ; Adding regex because of canonicalization of bitcasts -; CHECK: %2 = load i1, ptr {{.*}}, !invariant.group !0 - %2 = load i1, ptr @unknownPtr, !invariant.group !0 - call void @fooBit(ptr @unknownPtr, i1 %2) -; CHECK: %3 = load i1, ptr {{.*}}, !invariant.group !0 - %3 = load i1, ptr @unknownPtr, !invariant.group !0 - call void @fooBit(ptr @unknownPtr, i1 %3) - ret void + %2 = load i1, ptr @unknownPtr, !invariant.group !0 + call void @fooBit(ptr @unknownPtr, i1 %2) + %3 = load i1, ptr @unknownPtr, !invariant.group !0 + call void @fooBit(ptr @unknownPtr, i1 %3) + ret void } ; And in the case it is not global -; CHECK-LABEL: define void @testNotGlobal() { define void @testNotGlobal() { - %a = alloca i8 - call void @foo(ptr %a) -; CHECK: %b = load i8, ptr %a, align 1, !invariant.group !0 - %b = load i8, ptr %a, !invariant.group !0 - call void @foo2(ptr %a, i8 %b) - - %1 = load i8, ptr %a, !invariant.group !0 -; CHECK: call void @bar(i8 %b) - call void @bar(i8 %1) - - call void @fooBit(ptr %a, i1 1) -; CHECK: %1 = trunc i8 %b to i1 - %2 = load i1, ptr %a, !invariant.group !0 -; CHECK-NEXT: call void @fooBit(ptr %a, i1 %1) - call void @fooBit(ptr %a, i1 %2) - %3 = load i1, ptr %a, !invariant.group !0 -; CHECK-NEXT: call void @fooBit(ptr %a, i1 %1) - call void @fooBit(ptr %a, i1 %3) - ret void +; CHECK-LABEL: define void @testNotGlobal() { +; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 +; CHECK-NEXT: call void @foo(ptr [[A]]) +; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[A]], align 1, !invariant.group [[META0]] +; CHECK-NEXT: call void @foo2(ptr [[A]], i8 [[B]]) +; CHECK-NEXT: call void @bar(i8 [[B]]) +; CHECK-NEXT: call void @fooBit(ptr [[A]], i1 true) +; CHECK-NEXT: [[TMP1:%.*]] = trunc i8 [[B]] to i1 +; CHECK-NEXT: call void @fooBit(ptr [[A]], i1 [[TMP1]]) +; CHECK-NEXT: call void @fooBit(ptr [[A]], i1 [[TMP1]]) +; CHECK-NEXT: ret void +; + %a = alloca i8 + call void @foo(ptr %a) + %b = load i8, ptr %a, !invariant.group !0 + call void @foo2(ptr %a, i8 %b) + + %1 = load i8, ptr %a, !invariant.group !0 + call void @bar(i8 %1) + + call void @fooBit(ptr %a, i1 1) + %2 = load i1, ptr %a, !invariant.group !0 + call void @fooBit(ptr %a, i1 %2) + %3 = load i1, ptr %a, !invariant.group !0 + call void @fooBit(ptr %a, i1 %3) + ret void } -; CHECK-LABEL: define void @handling_loops() define void @handling_loops() { +; CHECK-LABEL: define void @handling_loops() { +; CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 8 +; CHECK-NEXT: store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr [[A]], align 8, !invariant.group [[META0]] +; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @unknownPtr, align 4 +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0 +; CHECK-NEXT: br i1 [[TMP2]], [[DOTLR_PH_I:label %.*]], label %[[_Z2G2R1A_EXIT:.*]] +; CHECK: [[_LR_PH_I:.*:]] +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i8 [[TMP1]], 1 +; CHECK-NEXT: br i1 [[TMP3]], label %[[DOT_CRIT_EDGE_PREHEADER:.*]], label %[[_Z2G2R1A_EXIT]] +; CHECK: [[__CRIT_EDGE_PREHEADER:.*:]] +; CHECK-NEXT: br label %[[DOT_CRIT_EDGE:.*]] +; CHECK: [[__CRIT_EDGE:.*:]] +; CHECK-NEXT: [[TMP4:%.*]] = phi i8 [ [[TMP5:%.*]], %[[DOT_CRIT_EDGE]] ], [ 1, %[[DOT_CRIT_EDGE_PREHEADER]] ] +; CHECK-NEXT: call void @_ZN1A3fooEv(ptr nonnull [[A]]) +; CHECK-NEXT: [[TMP5]] = add nuw nsw i8 [[TMP4]], 1 +; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr @unknownPtr, align 4 +; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i8 [[TMP5]], [[TMP6]] +; CHECK-NEXT: br i1 [[TMP7]], label %[[DOT_CRIT_EDGE]], label %[[_Z2G2R1A_EXIT_LOOPEXIT:.*]] +; CHECK: [[_Z2G2R1A_EXIT_LOOPEXIT]]: +; CHECK-NEXT: br label %[[_Z2G2R1A_EXIT]] +; CHECK: [[_Z2G2R1A_EXIT]]: +; CHECK-NEXT: ret void +; %a = alloca %struct.A, align 8 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0 %1 = load i8, ptr @unknownPtr, align 4 @@ -400,9 +550,7 @@ define void @handling_loops() { %5 = phi i8 [ %7, %._crit_edge ], [ 1, %._crit_edge.preheader ] %.pre = load ptr, ptr %a, align 8, !invariant.group !0 %6 = load ptr, ptr %.pre, align 8 - ; CHECK: call void @_ZN1A3fooEv(ptr nonnull %a) call void %6(ptr nonnull %a) #3 - ; CHECK-NOT: call void % %7 = add nuw nsw i8 %5, 1 %8 = load i8, ptr @unknownPtr, align 4 %9 = icmp slt i8 %7, %8 @@ -432,3 +580,6 @@ declare void @llvm.assume(i1 %cmp.vtables) !0 = !{} +;. +; CHECK: [[META0]] = !{} +;. |