llvm.org GIT mirror llvm / f69ccb7
[EarlyCSE] Teach about CSE'ing over invariant.start intrinsics Summary: Teach EarlyCSE about invariant.start intrinsic. Specifically, we can perform store-load, load-load forwarding over this call. Reviewers: majnemer, reames, dberlin, sanjoy Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D23268 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@278153 91177308-0d34-0410-b5e6-96231b3b80d8 Anna Thomas 3 years ago
2 changed file(s) with 84 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
561561 continue;
562562 }
563563
564 // Skip invariant.start intrinsics since they only read memory, and we can
565 // forward values across it. Also, we dont need to consume the last store
566 // since the semantics of invariant.start allow us to perform DSE of the
567 // last store, if there was a store following invariant.start. Consider:
568 //
569 // store 30, i8* p
570 // invariant.start(p)
571 // store 40, i8* p
572 // We can DSE the store to 30, since the store 40 to invariant location p
573 // causes undefined behaviour.
574 if (match(Inst, m_Intrinsic()))
575 continue;
576
564577 if (match(Inst, m_Intrinsic())) {
565578 if (auto *CondI =
566579 dyn_cast(cast(Inst)->getArgOperand(0))) {
0 ; RUN: opt < %s -S -early-cse | FileCheck %s
1 ; RUN: opt < %s -S -passes=early-cse | FileCheck %s
2
3 declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly
4 declare void @llvm.invariant.end.p0i8({}*, i64, i8* nocapture) nounwind
5
6 ; Check that we do load-load forwarding over invariant.start, since it does not
7 ; clobber memory
8 define i8 @test1(i8 *%P) {
9 ; CHECK-LABEL: @test1(
10 ; CHECK-NEXT: %V1 = load i8, i8* %P
11 ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
12 ; CHECK-NEXT: ret i8 0
13
14
15 %V1 = load i8, i8* %P
16 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
17 %V2 = load i8, i8* %P
18 %Diff = sub i8 %V1, %V2
19 ret i8 %Diff
20 }
21
22
23 ; Trivial Store->load forwarding over invariant.start
24 define i8 @test2(i8 *%P) {
25 ; CHECK-LABEL: @test2(
26 ; CHECK-NEXT: store i8 42, i8* %P
27 ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
28 ; CHECK-NEXT: ret i8 42
29
30
31 store i8 42, i8* %P
32 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
33 %V1 = load i8, i8* %P
34 ret i8 %V1
35 }
36
37 ; We can DSE over invariant.start calls, since the first store to
38 ; %P is valid, and the second store is actually unreachable based on semantics
39 ; of invariant.start.
40 define void @test3(i8* %P) {
41
42 ; CHECK-LABEL: @test3(
43 ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
44 ; CHECK-NEXT: store i8 60, i8* %P
45
46
47 store i8 50, i8* %P
48 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
49 store i8 60, i8* %P
50 ret void
51 }
52
53
54 ; FIXME: Now the first store can actually be eliminated, since there is no read within
55 ; the invariant region, between start and end.
56 define void @test4(i8* %P) {
57
58 ; CHECK-LABEL: @test4(
59 ; CHECK-NEXT: store i8 50, i8* %P
60 ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
61 ; CHECK-NEXT: call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
62 ; CHECK-NEXT: store i8 60, i8* %P
63
64
65 store i8 50, i8* %P
66 %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
67 call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
68 store i8 60, i8* %P
69 ret void
70 }