137 lines
3.3 KiB
LLVM
137 lines
3.3 KiB
LLVM
|
; Test if the !invariant.load metadata is maintained by GVN.
|
||
|
; RUN: opt -basic-aa -gvn -S < %s | FileCheck %s
|
||
|
|
||
|
define i32 @test1(i32* nocapture %p, i8* nocapture %q) {
|
||
|
; CHECK-LABEL: test1
|
||
|
; CHECK: %x = load i32, i32* %p, align 4, !invariant.load !0
|
||
|
; CHECK-NOT: %y = load
|
||
|
entry:
|
||
|
%x = load i32, i32* %p, align 4, !invariant.load !0
|
||
|
%conv = trunc i32 %x to i8
|
||
|
store i8 %conv, i8* %q, align 1
|
||
|
%y = load i32, i32* %p, align 4, !invariant.load !0
|
||
|
%add = add i32 %y, 1
|
||
|
ret i32 %add
|
||
|
}
|
||
|
|
||
|
define i32 @test2(i32* nocapture %p, i8* nocapture %q) {
|
||
|
; CHECK-LABEL: test2
|
||
|
; CHECK-NOT: !invariant.load
|
||
|
; CHECK-NOT: %y = load
|
||
|
entry:
|
||
|
%x = load i32, i32* %p, align 4
|
||
|
%conv = trunc i32 %x to i8
|
||
|
store i8 %conv, i8* %q, align 1
|
||
|
%y = load i32, i32* %p, align 4, !invariant.load !0
|
||
|
%add = add i32 %y, 1
|
||
|
ret i32 %add
|
||
|
}
|
||
|
|
||
|
; With the invariant.load metadata, what would otherwise
|
||
|
; be a case for PRE becomes a full redundancy.
|
||
|
define i32 @test3(i1 %cnd, i32* %p, i32* %q) {
|
||
|
; CHECK-LABEL: test3
|
||
|
; CHECK-NOT: load
|
||
|
entry:
|
||
|
%v1 = load i32, i32* %p
|
||
|
br i1 %cnd, label %bb1, label %bb2
|
||
|
|
||
|
bb1:
|
||
|
store i32 5, i32* %q
|
||
|
br label %bb2
|
||
|
|
||
|
bb2:
|
||
|
%v2 = load i32, i32* %p, !invariant.load !0
|
||
|
%res = sub i32 %v1, %v2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; This test is here to document a case which doesn't optimize
|
||
|
; as well as it could.
|
||
|
define i32 @test4(i1 %cnd, i32* %p, i32* %q) {
|
||
|
; CHECK-LABEL: test4
|
||
|
; %v2 is redundant, but GVN currently doesn't catch that
|
||
|
entry:
|
||
|
%v1 = load i32, i32* %p, !invariant.load !0
|
||
|
br i1 %cnd, label %bb1, label %bb2
|
||
|
|
||
|
bb1:
|
||
|
store i32 5, i32* %q
|
||
|
br label %bb2
|
||
|
|
||
|
bb2:
|
||
|
%v2 = load i32, i32* %p
|
||
|
%res = sub i32 %v1, %v2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; Checks that we return the mustalias store as a def
|
||
|
; so that it contributes to value forwarding. Note
|
||
|
; that we could and should remove the store too.
|
||
|
define i32 @test5(i1 %cnd, i32* %p) {
|
||
|
; CHECK-LABEL: test5
|
||
|
; CHECK-LABEL: entry:
|
||
|
; CHECK-NEXT: store i32 5, i32* %p
|
||
|
; CHECK-NEXT: ret i32 5
|
||
|
entry:
|
||
|
%v1 = load i32, i32* %p, !invariant.load !0
|
||
|
store i32 5, i32* %p ;; must alias store, want to exploit
|
||
|
%v2 = load i32, i32* %p, !invariant.load !0
|
||
|
ret i32 %v2
|
||
|
}
|
||
|
|
||
|
|
||
|
declare void @foo()
|
||
|
|
||
|
; Clobbering (mayalias) stores, even in function calls, can be ignored
|
||
|
define i32 @test6(i1 %cnd, i32* %p) {
|
||
|
; CHECK-LABEL: test6
|
||
|
; CHECK-LABEL: entry:
|
||
|
; CHECK-NEXT: @foo
|
||
|
; CHECK-NEXT: ret i32 0
|
||
|
entry:
|
||
|
%v1 = load i32, i32* %p, !invariant.load !0
|
||
|
call void @foo()
|
||
|
%v2 = load i32, i32* %p, !invariant.load !0
|
||
|
%res = sub i32 %v1, %v2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare noalias i32* @bar(...)
|
||
|
|
||
|
; Same as previous, but a function with a noalias result (since they're handled
|
||
|
; differently in MDA)
|
||
|
define i32 @test7(i1 %cnd, i32* %p) {
|
||
|
; CHECK-LABEL: test7
|
||
|
; CHECK-LABEL: entry:
|
||
|
; CHECK-NEXT: @bar
|
||
|
; CHECK-NEXT: ret i32 0
|
||
|
entry:
|
||
|
%v1 = load i32, i32* %p, !invariant.load !0
|
||
|
call i32* (...) @bar(i32* %p)
|
||
|
%v2 = load i32, i32* %p, !invariant.load !0
|
||
|
%res = sub i32 %v1, %v2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define i32 @test8(i1 %cnd, i32* %p) {
|
||
|
; CHECK-LABEL: test8
|
||
|
; CHECK: @bar
|
||
|
; CHECK: load i32, i32* %p2, align 4, !invariant.load
|
||
|
; CHECK: br label %merge
|
||
|
entry:
|
||
|
%v1 = load i32, i32* %p, !invariant.load !0
|
||
|
br i1 %cnd, label %taken, label %merge
|
||
|
taken:
|
||
|
%p2 = call i32* (...) @bar(i32* %p)
|
||
|
br label %merge
|
||
|
merge:
|
||
|
%p3 = phi i32* [%p, %entry], [%p2, %taken]
|
||
|
%v2 = load i32, i32* %p3, !invariant.load !0
|
||
|
%res = sub i32 %v1, %v2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
!0 = !{ }
|
||
|
|