blob: 5c6239b3f9d8db8924da952fd322bdb08995d790 [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
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010018#include "builder.h"
19#include "gvn.h"
20#include "nodes.h"
21#include "optimizing_unit_test.h"
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000022#include "side_effects_analysis.h"
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010023
24#include "gtest/gtest.h"
25
26namespace art {
27
28TEST(GVNTest, LocalFieldElimination) {
29 ArenaPool pool;
30 ArenaAllocator allocator(&pool);
31
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010032 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010033 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
34 graph->AddBlock(entry);
35 graph->SetEntryBlock(entry);
36 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
37 entry->AddInstruction(parameter);
38
39 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
40 graph->AddBlock(block);
41 entry->AddSuccessor(block);
42
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +010043 block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
44 Primitive::kPrimNot,
45 MemberOffset(42),
46 false,
47 kUnknownFieldIndex,
48 graph->GetDexFile()));
49 block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
50 Primitive::kPrimNot,
51 MemberOffset(42),
52 false,
53 kUnknownFieldIndex,
54 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010055 HInstruction* to_remove = block->GetLastInstruction();
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +010056 block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
57 Primitive::kPrimNot,
58 MemberOffset(43),
59 false,
60 kUnknownFieldIndex,
61 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010062 HInstruction* different_offset = block->GetLastInstruction();
63 // Kill the value.
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +010064 block->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
65 parameter,
66 Primitive::kPrimNot,
67 MemberOffset(42),
68 false,
69 kUnknownFieldIndex,
70 graph->GetDexFile()));
71 block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
72 Primitive::kPrimNot,
73 MemberOffset(42),
74 false,
75 kUnknownFieldIndex,
76 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010077 HInstruction* use_after_kill = block->GetLastInstruction();
78 block->AddInstruction(new (&allocator) HExit());
79
80 ASSERT_EQ(to_remove->GetBlock(), block);
81 ASSERT_EQ(different_offset->GetBlock(), block);
82 ASSERT_EQ(use_after_kill->GetBlock(), block);
83
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000084 graph->TryBuildingSsa();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000085 SideEffectsAnalysis side_effects(graph);
86 side_effects.Run();
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000087 GVNOptimization(graph, side_effects).Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010088
89 ASSERT_TRUE(to_remove->GetBlock() == nullptr);
90 ASSERT_EQ(different_offset->GetBlock(), block);
91 ASSERT_EQ(use_after_kill->GetBlock(), block);
92}
93
94TEST(GVNTest, GlobalFieldElimination) {
95 ArenaPool pool;
96 ArenaAllocator allocator(&pool);
97
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010098 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010099 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
100 graph->AddBlock(entry);
101 graph->SetEntryBlock(entry);
102 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
103 entry->AddInstruction(parameter);
104
105 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
106 graph->AddBlock(block);
107 entry->AddSuccessor(block);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100108 block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
109 Primitive::kPrimBoolean,
110 MemberOffset(42),
111 false,
112 kUnknownFieldIndex,
113 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100114
115 block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
116 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
117 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
118 HBasicBlock* join = new (&allocator) HBasicBlock(graph);
119 graph->AddBlock(then);
120 graph->AddBlock(else_);
121 graph->AddBlock(join);
122
123 block->AddSuccessor(then);
124 block->AddSuccessor(else_);
125 then->AddSuccessor(join);
126 else_->AddSuccessor(join);
127
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100128 then->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
129 Primitive::kPrimBoolean,
130 MemberOffset(42),
131 false,
132 kUnknownFieldIndex,
133 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100134 then->AddInstruction(new (&allocator) HGoto());
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100135 else_->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
136 Primitive::kPrimBoolean,
137 MemberOffset(42),
138 false,
139 kUnknownFieldIndex,
140 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100141 else_->AddInstruction(new (&allocator) HGoto());
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100142 join->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
143 Primitive::kPrimBoolean,
144 MemberOffset(42),
145 false,
146 kUnknownFieldIndex,
147 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100148 join->AddInstruction(new (&allocator) HExit());
149
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000150 graph->TryBuildingSsa();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000151 SideEffectsAnalysis side_effects(graph);
152 side_effects.Run();
Nicolas Geoffray827eedb2015-01-26 15:18:36 +0000153 GVNOptimization(graph, side_effects).Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100154
155 // Check that all field get instructions have been GVN'ed.
156 ASSERT_TRUE(then->GetFirstInstruction()->IsGoto());
157 ASSERT_TRUE(else_->GetFirstInstruction()->IsGoto());
158 ASSERT_TRUE(join->GetFirstInstruction()->IsExit());
159}
160
161TEST(GVNTest, LoopFieldElimination) {
162 ArenaPool pool;
163 ArenaAllocator allocator(&pool);
164
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100165 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100166 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
167 graph->AddBlock(entry);
168 graph->SetEntryBlock(entry);
169
170 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
171 entry->AddInstruction(parameter);
172
173 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
174 graph->AddBlock(block);
175 entry->AddSuccessor(block);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100176 block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
177 Primitive::kPrimBoolean,
178 MemberOffset(42),
179 false,
180 kUnknownFieldIndex,
181 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100182 block->AddInstruction(new (&allocator) HGoto());
183
184 HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
185 HBasicBlock* loop_body = new (&allocator) HBasicBlock(graph);
186 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
187
188 graph->AddBlock(loop_header);
189 graph->AddBlock(loop_body);
190 graph->AddBlock(exit);
191 block->AddSuccessor(loop_header);
192 loop_header->AddSuccessor(loop_body);
193 loop_header->AddSuccessor(exit);
194 loop_body->AddSuccessor(loop_header);
195
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100196 loop_header->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
197 Primitive::kPrimBoolean,
198 MemberOffset(42),
199 false,
200 kUnknownFieldIndex,
201 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100202 HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
203 loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
204
205 // Kill inside the loop body to prevent field gets inside the loop header
206 // and the body to be GVN'ed.
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100207 loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
208 parameter,
Aart Bik854a02b2015-07-14 16:07:00 -0700209 Primitive::kPrimBoolean,
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100210 MemberOffset(42),
211 false,
212 kUnknownFieldIndex,
213 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100214 HInstruction* field_set = loop_body->GetLastInstruction();
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100215 loop_body->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
216 Primitive::kPrimBoolean,
217 MemberOffset(42),
218 false,
219 kUnknownFieldIndex,
220 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100221 HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
222 loop_body->AddInstruction(new (&allocator) HGoto());
223
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100224 exit->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
225 Primitive::kPrimBoolean,
226 MemberOffset(42),
227 false,
228 kUnknownFieldIndex,
229 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100230 HInstruction* field_get_in_exit = exit->GetLastInstruction();
231 exit->AddInstruction(new (&allocator) HExit());
232
233 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
234 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
235 ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
236
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000237 graph->TryBuildingSsa();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000238 {
239 SideEffectsAnalysis side_effects(graph);
240 side_effects.Run();
Nicolas Geoffray827eedb2015-01-26 15:18:36 +0000241 GVNOptimization(graph, side_effects).Run();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000242 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100243
244 // Check that all field get instructions are still there.
245 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
246 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
247 // The exit block is dominated by the loop header, whose field get
248 // does not get killed by the loop flags.
249 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
250
251 // Now remove the field set, and check that all field get instructions have been GVN'ed.
252 loop_body->RemoveInstruction(field_set);
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000253 {
254 SideEffectsAnalysis side_effects(graph);
255 side_effects.Run();
Nicolas Geoffray827eedb2015-01-26 15:18:36 +0000256 GVNOptimization(graph, side_effects).Run();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000257 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100258
259 ASSERT_TRUE(field_get_in_loop_header->GetBlock() == nullptr);
260 ASSERT_TRUE(field_get_in_loop_body->GetBlock() == nullptr);
261 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
262}
263
264// Test that inner loops affect the side effects of the outer loop.
265TEST(GVNTest, LoopSideEffects) {
266 ArenaPool pool;
267 ArenaAllocator allocator(&pool);
268
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100269 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100270 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
271 graph->AddBlock(entry);
272 graph->SetEntryBlock(entry);
273
274 HBasicBlock* outer_loop_header = new (&allocator) HBasicBlock(graph);
275 HBasicBlock* outer_loop_body = new (&allocator) HBasicBlock(graph);
276 HBasicBlock* outer_loop_exit = new (&allocator) HBasicBlock(graph);
277 HBasicBlock* inner_loop_header = new (&allocator) HBasicBlock(graph);
278 HBasicBlock* inner_loop_body = new (&allocator) HBasicBlock(graph);
279 HBasicBlock* inner_loop_exit = new (&allocator) HBasicBlock(graph);
280
281 graph->AddBlock(outer_loop_header);
282 graph->AddBlock(outer_loop_body);
283 graph->AddBlock(outer_loop_exit);
284 graph->AddBlock(inner_loop_header);
285 graph->AddBlock(inner_loop_body);
286 graph->AddBlock(inner_loop_exit);
287
288 entry->AddSuccessor(outer_loop_header);
289 outer_loop_header->AddSuccessor(outer_loop_body);
290 outer_loop_header->AddSuccessor(outer_loop_exit);
291 outer_loop_body->AddSuccessor(inner_loop_header);
292 inner_loop_header->AddSuccessor(inner_loop_body);
293 inner_loop_header->AddSuccessor(inner_loop_exit);
294 inner_loop_body->AddSuccessor(inner_loop_header);
295 inner_loop_exit->AddSuccessor(outer_loop_header);
296
297 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimBoolean);
298 entry->AddInstruction(parameter);
299 entry->AddInstruction(new (&allocator) HGoto());
300 outer_loop_header->AddInstruction(new (&allocator) HIf(parameter));
301 outer_loop_body->AddInstruction(new (&allocator) HGoto());
302 inner_loop_header->AddInstruction(new (&allocator) HIf(parameter));
303 inner_loop_body->AddInstruction(new (&allocator) HGoto());
304 inner_loop_exit->AddInstruction(new (&allocator) HGoto());
305 outer_loop_exit->AddInstruction(new (&allocator) HExit());
306
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000307 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100308
309 ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
310 *outer_loop_header->GetLoopInformation()));
311
312 // Check that the loops don't have side effects.
313 {
314 // Make one block with a side effect.
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100315 entry->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
316 parameter,
317 Primitive::kPrimNot,
318 MemberOffset(42),
319 false,
320 kUnknownFieldIndex,
321 graph->GetDexFile()));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100322
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000323 SideEffectsAnalysis side_effects(graph);
324 side_effects.Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100325
Aart Bik854a02b2015-07-14 16:07:00 -0700326 ASSERT_TRUE(side_effects.GetBlockEffects(entry).DoesAnyWrite());
327 ASSERT_FALSE(side_effects.GetBlockEffects(outer_loop_body).DoesAnyWrite());
328 ASSERT_FALSE(side_effects.GetLoopEffects(outer_loop_header).DoesAnyWrite());
329 ASSERT_FALSE(side_effects.GetLoopEffects(inner_loop_header).DoesAnyWrite());
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100330 }
331
332 // Check that the side effects of the outer loop does not affect the inner loop.
333 {
334 outer_loop_body->InsertInstructionBefore(
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100335 new (&allocator) HInstanceFieldSet(parameter,
336 parameter,
337 Primitive::kPrimNot,
338 MemberOffset(42),
339 false,
340 kUnknownFieldIndex,
341 graph->GetDexFile()),
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100342 outer_loop_body->GetLastInstruction());
343
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000344 SideEffectsAnalysis side_effects(graph);
345 side_effects.Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100346
Aart Bik854a02b2015-07-14 16:07:00 -0700347 ASSERT_TRUE(side_effects.GetBlockEffects(entry).DoesAnyWrite());
348 ASSERT_TRUE(side_effects.GetBlockEffects(outer_loop_body).DoesAnyWrite());
349 ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).DoesAnyWrite());
350 ASSERT_FALSE(side_effects.GetLoopEffects(inner_loop_header).DoesAnyWrite());
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100351 }
352
353 // Check that the side effects of the inner loop affects the outer loop.
354 {
355 outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
356 inner_loop_body->InsertInstructionBefore(
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100357 new (&allocator) HInstanceFieldSet(parameter,
358 parameter,
359 Primitive::kPrimNot,
360 MemberOffset(42),
361 false,
362 kUnknownFieldIndex,
363 graph->GetDexFile()),
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100364 inner_loop_body->GetLastInstruction());
365
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000366 SideEffectsAnalysis side_effects(graph);
367 side_effects.Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100368
Aart Bik854a02b2015-07-14 16:07:00 -0700369 ASSERT_TRUE(side_effects.GetBlockEffects(entry).DoesAnyWrite());
370 ASSERT_FALSE(side_effects.GetBlockEffects(outer_loop_body).DoesAnyWrite());
371 ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).DoesAnyWrite());
372 ASSERT_TRUE(side_effects.GetLoopEffects(inner_loop_header).DoesAnyWrite());
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100373 }
374}
375} // namespace art