blob: 9e630a7db0025fd224b680dc95ccc19807acbdb7 [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(
Calin Juravle52c48962014-12-16 17:02:57 +000043 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
44 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010045 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +000046 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
47 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010048 HInstruction* to_remove = block->GetLastInstruction();
49 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +000050 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
51 MemberOffset(43), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010052 HInstruction* different_offset = block->GetLastInstruction();
53 // Kill the value.
54 block->AddInstruction(new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +000055 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010056 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +000057 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
58 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010059 HInstruction* use_after_kill = block->GetLastInstruction();
60 block->AddInstruction(new (&allocator) HExit());
61
62 ASSERT_EQ(to_remove->GetBlock(), block);
63 ASSERT_EQ(different_offset->GetBlock(), block);
64 ASSERT_EQ(use_after_kill->GetBlock(), block);
65
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000066 graph->TryBuildingSsa();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000067 SideEffectsAnalysis side_effects(graph);
68 side_effects.Run();
69 GlobalValueNumberer(&allocator, graph, side_effects).Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010070
71 ASSERT_TRUE(to_remove->GetBlock() == nullptr);
72 ASSERT_EQ(different_offset->GetBlock(), block);
73 ASSERT_EQ(use_after_kill->GetBlock(), block);
74}
75
76TEST(GVNTest, GlobalFieldElimination) {
77 ArenaPool pool;
78 ArenaAllocator allocator(&pool);
79
80 HGraph* graph = new (&allocator) HGraph(&allocator);
81 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
82 graph->AddBlock(entry);
83 graph->SetEntryBlock(entry);
84 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
85 entry->AddInstruction(parameter);
86
87 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
88 graph->AddBlock(block);
89 entry->AddSuccessor(block);
90 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +000091 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
92 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010093
94 block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
95 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
96 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
97 HBasicBlock* join = new (&allocator) HBasicBlock(graph);
98 graph->AddBlock(then);
99 graph->AddBlock(else_);
100 graph->AddBlock(join);
101
102 block->AddSuccessor(then);
103 block->AddSuccessor(else_);
104 then->AddSuccessor(join);
105 else_->AddSuccessor(join);
106
107 then->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000108 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
109 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100110 then->AddInstruction(new (&allocator) HGoto());
111 else_->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000112 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
113 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100114 else_->AddInstruction(new (&allocator) HGoto());
115 join->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000116 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
117 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100118 join->AddInstruction(new (&allocator) HExit());
119
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000120 graph->TryBuildingSsa();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000121 SideEffectsAnalysis side_effects(graph);
122 side_effects.Run();
123 GlobalValueNumberer(&allocator, graph, side_effects).Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100124
125 // Check that all field get instructions have been GVN'ed.
126 ASSERT_TRUE(then->GetFirstInstruction()->IsGoto());
127 ASSERT_TRUE(else_->GetFirstInstruction()->IsGoto());
128 ASSERT_TRUE(join->GetFirstInstruction()->IsExit());
129}
130
131TEST(GVNTest, LoopFieldElimination) {
132 ArenaPool pool;
133 ArenaAllocator allocator(&pool);
134
135 HGraph* graph = new (&allocator) HGraph(&allocator);
136 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
137 graph->AddBlock(entry);
138 graph->SetEntryBlock(entry);
139
140 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
141 entry->AddInstruction(parameter);
142
143 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
144 graph->AddBlock(block);
145 entry->AddSuccessor(block);
146 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000147 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
148 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100149 block->AddInstruction(new (&allocator) HGoto());
150
151 HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
152 HBasicBlock* loop_body = new (&allocator) HBasicBlock(graph);
153 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
154
155 graph->AddBlock(loop_header);
156 graph->AddBlock(loop_body);
157 graph->AddBlock(exit);
158 block->AddSuccessor(loop_header);
159 loop_header->AddSuccessor(loop_body);
160 loop_header->AddSuccessor(exit);
161 loop_body->AddSuccessor(loop_header);
162
163 loop_header->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000164 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
165 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100166 HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
167 loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
168
169 // Kill inside the loop body to prevent field gets inside the loop header
170 // and the body to be GVN'ed.
171 loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000172 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100173 HInstruction* field_set = loop_body->GetLastInstruction();
174 loop_body->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000175 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
176 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100177 HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
178 loop_body->AddInstruction(new (&allocator) HGoto());
179
180 exit->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000181 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
182 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100183 HInstruction* field_get_in_exit = exit->GetLastInstruction();
184 exit->AddInstruction(new (&allocator) HExit());
185
186 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
187 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
188 ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
189
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000190 graph->TryBuildingSsa();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000191 {
192 SideEffectsAnalysis side_effects(graph);
193 side_effects.Run();
194 GlobalValueNumberer(&allocator, graph, side_effects).Run();
195 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100196
197 // Check that all field get instructions are still there.
198 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
199 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
200 // The exit block is dominated by the loop header, whose field get
201 // does not get killed by the loop flags.
202 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
203
204 // Now remove the field set, and check that all field get instructions have been GVN'ed.
205 loop_body->RemoveInstruction(field_set);
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000206 {
207 SideEffectsAnalysis side_effects(graph);
208 side_effects.Run();
209 GlobalValueNumberer(&allocator, graph, side_effects).Run();
210 }
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100211
212 ASSERT_TRUE(field_get_in_loop_header->GetBlock() == nullptr);
213 ASSERT_TRUE(field_get_in_loop_body->GetBlock() == nullptr);
214 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
215}
216
217// Test that inner loops affect the side effects of the outer loop.
218TEST(GVNTest, LoopSideEffects) {
219 ArenaPool pool;
220 ArenaAllocator allocator(&pool);
221
222 HGraph* graph = new (&allocator) HGraph(&allocator);
223 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
224 graph->AddBlock(entry);
225 graph->SetEntryBlock(entry);
226
227 HBasicBlock* outer_loop_header = new (&allocator) HBasicBlock(graph);
228 HBasicBlock* outer_loop_body = new (&allocator) HBasicBlock(graph);
229 HBasicBlock* outer_loop_exit = new (&allocator) HBasicBlock(graph);
230 HBasicBlock* inner_loop_header = new (&allocator) HBasicBlock(graph);
231 HBasicBlock* inner_loop_body = new (&allocator) HBasicBlock(graph);
232 HBasicBlock* inner_loop_exit = new (&allocator) HBasicBlock(graph);
233
234 graph->AddBlock(outer_loop_header);
235 graph->AddBlock(outer_loop_body);
236 graph->AddBlock(outer_loop_exit);
237 graph->AddBlock(inner_loop_header);
238 graph->AddBlock(inner_loop_body);
239 graph->AddBlock(inner_loop_exit);
240
241 entry->AddSuccessor(outer_loop_header);
242 outer_loop_header->AddSuccessor(outer_loop_body);
243 outer_loop_header->AddSuccessor(outer_loop_exit);
244 outer_loop_body->AddSuccessor(inner_loop_header);
245 inner_loop_header->AddSuccessor(inner_loop_body);
246 inner_loop_header->AddSuccessor(inner_loop_exit);
247 inner_loop_body->AddSuccessor(inner_loop_header);
248 inner_loop_exit->AddSuccessor(outer_loop_header);
249
250 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimBoolean);
251 entry->AddInstruction(parameter);
252 entry->AddInstruction(new (&allocator) HGoto());
253 outer_loop_header->AddInstruction(new (&allocator) HIf(parameter));
254 outer_loop_body->AddInstruction(new (&allocator) HGoto());
255 inner_loop_header->AddInstruction(new (&allocator) HIf(parameter));
256 inner_loop_body->AddInstruction(new (&allocator) HGoto());
257 inner_loop_exit->AddInstruction(new (&allocator) HGoto());
258 outer_loop_exit->AddInstruction(new (&allocator) HExit());
259
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000260 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100261
262 ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
263 *outer_loop_header->GetLoopInformation()));
264
265 // Check that the loops don't have side effects.
266 {
267 // Make one block with a side effect.
268 entry->AddInstruction(new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000269 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100270
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000271 SideEffectsAnalysis side_effects(graph);
272 side_effects.Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100273
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000274 ASSERT_TRUE(side_effects.GetBlockEffects(entry).HasSideEffects());
275 ASSERT_FALSE(side_effects.GetLoopEffects(outer_loop_header).HasSideEffects());
276 ASSERT_FALSE(side_effects.GetLoopEffects(inner_loop_header).HasSideEffects());
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100277 }
278
279 // Check that the side effects of the outer loop does not affect the inner loop.
280 {
281 outer_loop_body->InsertInstructionBefore(
282 new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000283 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100284 outer_loop_body->GetLastInstruction());
285
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000286 SideEffectsAnalysis side_effects(graph);
287 side_effects.Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100288
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000289 ASSERT_TRUE(side_effects.GetBlockEffects(entry).HasSideEffects());
290 ASSERT_TRUE(side_effects.GetBlockEffects(outer_loop_body).HasSideEffects());
291 ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).HasSideEffects());
292 ASSERT_FALSE(side_effects.GetLoopEffects(inner_loop_header).HasSideEffects());
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100293 }
294
295 // Check that the side effects of the inner loop affects the outer loop.
296 {
297 outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
298 inner_loop_body->InsertInstructionBefore(
299 new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000300 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100301 inner_loop_body->GetLastInstruction());
302
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000303 SideEffectsAnalysis side_effects(graph);
304 side_effects.Run();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100305
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000306 ASSERT_TRUE(side_effects.GetBlockEffects(entry).HasSideEffects());
307 ASSERT_FALSE(side_effects.GetBlockEffects(outer_loop_body).HasSideEffects());
308 ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).HasSideEffects());
309 ASSERT_TRUE(side_effects.GetLoopEffects(inner_loop_header).HasSideEffects());
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100310 }
311}
312} // namespace art