blob: 94ff192264cfe7d23d70548c76d74ed364ce93a2 [file] [log] [blame]
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "builder.h"
18#include "gvn.h"
19#include "nodes.h"
20#include "optimizing_unit_test.h"
21#include "utils/arena_allocator.h"
22
23#include "gtest/gtest.h"
24
25namespace art {
26
27TEST(GVNTest, LocalFieldElimination) {
28 ArenaPool pool;
29 ArenaAllocator allocator(&pool);
30
31 HGraph* graph = new (&allocator) HGraph(&allocator);
32 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
33 graph->AddBlock(entry);
34 graph->SetEntryBlock(entry);
35 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
36 entry->AddInstruction(parameter);
37
38 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
39 graph->AddBlock(block);
40 entry->AddSuccessor(block);
41
42 block->AddInstruction(
43 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(42)));
44 block->AddInstruction(
45 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(42)));
46 HInstruction* to_remove = block->GetLastInstruction();
47 block->AddInstruction(
48 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(43)));
49 HInstruction* different_offset = block->GetLastInstruction();
50 // Kill the value.
51 block->AddInstruction(new (&allocator) HInstanceFieldSet(
52 parameter, parameter, Primitive::kPrimNot, MemberOffset(42)));
53 block->AddInstruction(
54 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(42)));
55 HInstruction* use_after_kill = block->GetLastInstruction();
56 block->AddInstruction(new (&allocator) HExit());
57
58 ASSERT_EQ(to_remove->GetBlock(), block);
59 ASSERT_EQ(different_offset->GetBlock(), block);
60 ASSERT_EQ(use_after_kill->GetBlock(), block);
61
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000062 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010063 GlobalValueNumberer(&allocator, graph).Run();
64
65 ASSERT_TRUE(to_remove->GetBlock() == nullptr);
66 ASSERT_EQ(different_offset->GetBlock(), block);
67 ASSERT_EQ(use_after_kill->GetBlock(), block);
68}
69
70TEST(GVNTest, GlobalFieldElimination) {
71 ArenaPool pool;
72 ArenaAllocator allocator(&pool);
73
74 HGraph* graph = new (&allocator) HGraph(&allocator);
75 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
76 graph->AddBlock(entry);
77 graph->SetEntryBlock(entry);
78 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
79 entry->AddInstruction(parameter);
80
81 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
82 graph->AddBlock(block);
83 entry->AddSuccessor(block);
84 block->AddInstruction(
85 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
86
87 block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
88 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
89 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
90 HBasicBlock* join = new (&allocator) HBasicBlock(graph);
91 graph->AddBlock(then);
92 graph->AddBlock(else_);
93 graph->AddBlock(join);
94
95 block->AddSuccessor(then);
96 block->AddSuccessor(else_);
97 then->AddSuccessor(join);
98 else_->AddSuccessor(join);
99
100 then->AddInstruction(
101 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
102 then->AddInstruction(new (&allocator) HGoto());
103 else_->AddInstruction(
104 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
105 else_->AddInstruction(new (&allocator) HGoto());
106 join->AddInstruction(
107 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
108 join->AddInstruction(new (&allocator) HExit());
109
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000110 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100111 GlobalValueNumberer(&allocator, graph).Run();
112
113 // Check that all field get instructions have been GVN'ed.
114 ASSERT_TRUE(then->GetFirstInstruction()->IsGoto());
115 ASSERT_TRUE(else_->GetFirstInstruction()->IsGoto());
116 ASSERT_TRUE(join->GetFirstInstruction()->IsExit());
117}
118
119TEST(GVNTest, LoopFieldElimination) {
120 ArenaPool pool;
121 ArenaAllocator allocator(&pool);
122
123 HGraph* graph = new (&allocator) HGraph(&allocator);
124 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
125 graph->AddBlock(entry);
126 graph->SetEntryBlock(entry);
127
128 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
129 entry->AddInstruction(parameter);
130
131 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
132 graph->AddBlock(block);
133 entry->AddSuccessor(block);
134 block->AddInstruction(
135 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
136 block->AddInstruction(new (&allocator) HGoto());
137
138 HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
139 HBasicBlock* loop_body = new (&allocator) HBasicBlock(graph);
140 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
141
142 graph->AddBlock(loop_header);
143 graph->AddBlock(loop_body);
144 graph->AddBlock(exit);
145 block->AddSuccessor(loop_header);
146 loop_header->AddSuccessor(loop_body);
147 loop_header->AddSuccessor(exit);
148 loop_body->AddSuccessor(loop_header);
149
150 loop_header->AddInstruction(
151 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
152 HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
153 loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
154
155 // Kill inside the loop body to prevent field gets inside the loop header
156 // and the body to be GVN'ed.
157 loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(
158 parameter, parameter, Primitive::kPrimNot, MemberOffset(42)));
159 HInstruction* field_set = loop_body->GetLastInstruction();
160 loop_body->AddInstruction(
161 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
162 HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
163 loop_body->AddInstruction(new (&allocator) HGoto());
164
165 exit->AddInstruction(
166 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
167 HInstruction* field_get_in_exit = exit->GetLastInstruction();
168 exit->AddInstruction(new (&allocator) HExit());
169
170 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
171 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
172 ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
173
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000174 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100175 GlobalValueNumberer(&allocator, graph).Run();
176
177 // Check that all field get instructions are still there.
178 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
179 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
180 // The exit block is dominated by the loop header, whose field get
181 // does not get killed by the loop flags.
182 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
183
184 // Now remove the field set, and check that all field get instructions have been GVN'ed.
185 loop_body->RemoveInstruction(field_set);
186 GlobalValueNumberer(&allocator, graph).Run();
187
188 ASSERT_TRUE(field_get_in_loop_header->GetBlock() == nullptr);
189 ASSERT_TRUE(field_get_in_loop_body->GetBlock() == nullptr);
190 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
191}
192
193// Test that inner loops affect the side effects of the outer loop.
194TEST(GVNTest, LoopSideEffects) {
195 ArenaPool pool;
196 ArenaAllocator allocator(&pool);
197
198 HGraph* graph = new (&allocator) HGraph(&allocator);
199 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
200 graph->AddBlock(entry);
201 graph->SetEntryBlock(entry);
202
203 HBasicBlock* outer_loop_header = new (&allocator) HBasicBlock(graph);
204 HBasicBlock* outer_loop_body = new (&allocator) HBasicBlock(graph);
205 HBasicBlock* outer_loop_exit = new (&allocator) HBasicBlock(graph);
206 HBasicBlock* inner_loop_header = new (&allocator) HBasicBlock(graph);
207 HBasicBlock* inner_loop_body = new (&allocator) HBasicBlock(graph);
208 HBasicBlock* inner_loop_exit = new (&allocator) HBasicBlock(graph);
209
210 graph->AddBlock(outer_loop_header);
211 graph->AddBlock(outer_loop_body);
212 graph->AddBlock(outer_loop_exit);
213 graph->AddBlock(inner_loop_header);
214 graph->AddBlock(inner_loop_body);
215 graph->AddBlock(inner_loop_exit);
216
217 entry->AddSuccessor(outer_loop_header);
218 outer_loop_header->AddSuccessor(outer_loop_body);
219 outer_loop_header->AddSuccessor(outer_loop_exit);
220 outer_loop_body->AddSuccessor(inner_loop_header);
221 inner_loop_header->AddSuccessor(inner_loop_body);
222 inner_loop_header->AddSuccessor(inner_loop_exit);
223 inner_loop_body->AddSuccessor(inner_loop_header);
224 inner_loop_exit->AddSuccessor(outer_loop_header);
225
226 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimBoolean);
227 entry->AddInstruction(parameter);
228 entry->AddInstruction(new (&allocator) HGoto());
229 outer_loop_header->AddInstruction(new (&allocator) HIf(parameter));
230 outer_loop_body->AddInstruction(new (&allocator) HGoto());
231 inner_loop_header->AddInstruction(new (&allocator) HIf(parameter));
232 inner_loop_body->AddInstruction(new (&allocator) HGoto());
233 inner_loop_exit->AddInstruction(new (&allocator) HGoto());
234 outer_loop_exit->AddInstruction(new (&allocator) HExit());
235
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000236 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100237
238 ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
239 *outer_loop_header->GetLoopInformation()));
240
241 // Check that the loops don't have side effects.
242 {
243 // Make one block with a side effect.
244 entry->AddInstruction(new (&allocator) HInstanceFieldSet(
245 parameter, parameter, Primitive::kPrimNot, MemberOffset(42)));
246
247 GlobalValueNumberer gvn(&allocator, graph);
248 gvn.Run();
249
250 ASSERT_TRUE(gvn.GetBlockEffects(entry).HasSideEffects());
251 ASSERT_FALSE(gvn.GetLoopEffects(outer_loop_header).HasSideEffects());
252 ASSERT_FALSE(gvn.GetLoopEffects(inner_loop_header).HasSideEffects());
253 }
254
255 // Check that the side effects of the outer loop does not affect the inner loop.
256 {
257 outer_loop_body->InsertInstructionBefore(
258 new (&allocator) HInstanceFieldSet(
259 parameter, parameter, Primitive::kPrimNot, MemberOffset(42)),
260 outer_loop_body->GetLastInstruction());
261
262 GlobalValueNumberer gvn(&allocator, graph);
263 gvn.Run();
264
265 ASSERT_TRUE(gvn.GetBlockEffects(entry).HasSideEffects());
266 ASSERT_TRUE(gvn.GetBlockEffects(outer_loop_body).HasSideEffects());
267 ASSERT_TRUE(gvn.GetLoopEffects(outer_loop_header).HasSideEffects());
268 ASSERT_FALSE(gvn.GetLoopEffects(inner_loop_header).HasSideEffects());
269 }
270
271 // Check that the side effects of the inner loop affects the outer loop.
272 {
273 outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
274 inner_loop_body->InsertInstructionBefore(
275 new (&allocator) HInstanceFieldSet(
276 parameter, parameter, Primitive::kPrimNot, MemberOffset(42)),
277 inner_loop_body->GetLastInstruction());
278
279 GlobalValueNumberer gvn(&allocator, graph);
280 gvn.Run();
281
282 ASSERT_TRUE(gvn.GetBlockEffects(entry).HasSideEffects());
283 ASSERT_FALSE(gvn.GetBlockEffects(outer_loop_body).HasSideEffects());
284 ASSERT_TRUE(gvn.GetLoopEffects(outer_loop_header).HasSideEffects());
285 ASSERT_TRUE(gvn.GetLoopEffects(inner_loop_header).HasSideEffects());
286 }
287}
288} // namespace art