1
1
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2
- ; RUN: opt -S -passes=early-cse -earlycse-debug-hash < %s | FileCheck %s
2
+ ; RUN: opt -S -passes=early-cse -earlycse-debug-hash < %s | FileCheck %s --check-prefixes=CHECK,NO-MSSA
3
+ ; RUN: opt -S -passes='early-cse<memssa>' < %s | FileCheck %s --check-prefixes=CHECK,MSSA
3
4
4
5
@var = global i32 undef
5
6
declare void @foo () nounwind
@@ -15,3 +16,148 @@ define void @test() {
15
16
store i32 2 , ptr @var
16
17
ret void
17
18
}
19
+
20
+ declare void @writeonly_void () memory(write)
21
+
22
+ ; Can CSE writeonly calls, including non-nounwind/willreturn.
23
+ define void @writeonly_cse () {
24
+ ; CHECK-LABEL: @writeonly_cse(
25
+ ; CHECK-NEXT: call void @writeonly_void()
26
+ ; CHECK-NEXT: ret void
27
+ ;
28
+ call void @writeonly_void ()
29
+ call void @writeonly_void ()
30
+ ret void
31
+ }
32
+
33
+ ; Can CSE, loads do not matter.
34
+ define i32 @writeonly_cse_intervening_load (ptr %p ) {
35
+ ; CHECK-LABEL: @writeonly_cse_intervening_load(
36
+ ; CHECK-NEXT: call void @writeonly_void()
37
+ ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4
38
+ ; CHECK-NEXT: ret i32 [[V]]
39
+ ;
40
+ call void @writeonly_void ()
41
+ %v = load i32 , ptr %p
42
+ call void @writeonly_void ()
43
+ ret i32 %v
44
+ }
45
+
46
+ ; Cannot CSE, the store may be to the same memory.
47
+ define void @writeonly_cse_intervening_store (ptr %p ) {
48
+ ; CHECK-LABEL: @writeonly_cse_intervening_store(
49
+ ; CHECK-NEXT: call void @writeonly_void()
50
+ ; CHECK-NEXT: store i32 0, ptr [[P:%.*]], align 4
51
+ ; CHECK-NEXT: call void @writeonly_void()
52
+ ; CHECK-NEXT: ret void
53
+ ;
54
+ call void @writeonly_void ()
55
+ store i32 0 , ptr %p
56
+ call void @writeonly_void ()
57
+ ret void
58
+ }
59
+
60
+ ; Can CSE, the store does not alias the writeonly call.
61
+ define void @writeonly_cse_intervening_noalias_store (ptr noalias %p ) {
62
+ ; NO-MSSA-LABEL: @writeonly_cse_intervening_noalias_store(
63
+ ; NO-MSSA-NEXT: call void @writeonly_void()
64
+ ; NO-MSSA-NEXT: store i32 0, ptr [[P:%.*]], align 4
65
+ ; NO-MSSA-NEXT: call void @writeonly_void()
66
+ ; NO-MSSA-NEXT: ret void
67
+ ;
68
+ ; MSSA-LABEL: @writeonly_cse_intervening_noalias_store(
69
+ ; MSSA-NEXT: call void @writeonly_void()
70
+ ; MSSA-NEXT: store i32 0, ptr [[P:%.*]], align 4
71
+ ; MSSA-NEXT: ret void
72
+ ;
73
+ call void @writeonly_void ()
74
+ store i32 0 , ptr %p
75
+ call void @writeonly_void ()
76
+ ret void
77
+ }
78
+
79
+ ; Cannot CSE loads across writeonly call.
80
+ define i32 @load_cse_across_writeonly (ptr %p ) {
81
+ ; CHECK-LABEL: @load_cse_across_writeonly(
82
+ ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4
83
+ ; CHECK-NEXT: call void @writeonly_void()
84
+ ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4
85
+ ; CHECK-NEXT: [[RES:%.*]] = sub i32 [[V1]], [[V2]]
86
+ ; CHECK-NEXT: ret i32 [[RES]]
87
+ ;
88
+ %v1 = load i32 , ptr %p
89
+ call void @writeonly_void ()
90
+ %v2 = load i32 , ptr %p
91
+ %res = sub i32 %v1 , %v2
92
+ ret i32 %res
93
+ }
94
+
95
+ ; Can CSE loads across eliminated writeonly call.
96
+ define i32 @load_cse_across_csed_writeonly (ptr %p ) {
97
+ ; CHECK-LABEL: @load_cse_across_csed_writeonly(
98
+ ; CHECK-NEXT: call void @writeonly_void()
99
+ ; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P:%.*]], align 4
100
+ ; CHECK-NEXT: ret i32 0
101
+ ;
102
+ call void @writeonly_void ()
103
+ %v1 = load i32 , ptr %p
104
+ call void @writeonly_void ()
105
+ %v2 = load i32 , ptr %p
106
+ %res = sub i32 %v1 , %v2
107
+ ret i32 %res
108
+ }
109
+
110
+ declare i32 @writeonly (ptr %p ) memory(write)
111
+
112
+ ; Can CSE writeonly calls with arg and return.
113
+ define i32 @writeonly_ret_cse (ptr %p ) {
114
+ ; CHECK-LABEL: @writeonly_ret_cse(
115
+ ; CHECK-NEXT: [[V2:%.*]] = call i32 @writeonly(ptr [[P:%.*]])
116
+ ; CHECK-NEXT: ret i32 0
117
+ ;
118
+ %v1 = call i32 @writeonly (ptr %p )
119
+ %v2 = call i32 @writeonly (ptr %p )
120
+ %res = sub i32 %v1 , %v2
121
+ ret i32 %res
122
+ }
123
+
124
+ ; Cannot CSE writeonly calls with different arguments.
125
+ define i32 @writeonly_different_args (ptr %p1 , ptr %p2 ) {
126
+ ; CHECK-LABEL: @writeonly_different_args(
127
+ ; CHECK-NEXT: [[V1:%.*]] = call i32 @writeonly(ptr [[P1:%.*]])
128
+ ; CHECK-NEXT: [[V2:%.*]] = call i32 @writeonly(ptr [[P2:%.*]])
129
+ ; CHECK-NEXT: [[RES:%.*]] = sub i32 [[V1]], [[V2]]
130
+ ; CHECK-NEXT: ret i32 [[RES]]
131
+ ;
132
+ %v1 = call i32 @writeonly (ptr %p1 )
133
+ %v2 = call i32 @writeonly (ptr %p2 )
134
+ %res = sub i32 %v1 , %v2
135
+ ret i32 %res
136
+ }
137
+
138
+ declare void @callee ()
139
+
140
+ ; These are weird cases where the same call is both readonly and writeonly
141
+ ; based on call-site attributes. I believe this implies that both calls are
142
+ ; actually readnone and safe to CSE, but leave them alone to be conservative.
143
+ define void @readonly_and_writeonly () {
144
+ ; CHECK-LABEL: @readonly_and_writeonly(
145
+ ; CHECK-NEXT: call void @callee() #[[ATTR2:[0-9]+]]
146
+ ; CHECK-NEXT: call void @callee() #[[ATTR1]]
147
+ ; CHECK-NEXT: ret void
148
+ ;
149
+ call void @callee () memory(read)
150
+ call void @callee () memory(write)
151
+ ret void
152
+ }
153
+
154
+ define void @writeonly_and_readonly () {
155
+ ; CHECK-LABEL: @writeonly_and_readonly(
156
+ ; CHECK-NEXT: call void @callee() #[[ATTR1]]
157
+ ; CHECK-NEXT: call void @callee() #[[ATTR2]]
158
+ ; CHECK-NEXT: ret void
159
+ ;
160
+ call void @callee () memory(write)
161
+ call void @callee () memory(read)
162
+ ret void
163
+ }
0 commit comments