blob: 48f1ea9e1554efb0f2c5a62c1f3c4ced468e44db [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 Geoffrayd31cf3d2014-09-08 17:30:24 +010067 GlobalValueNumberer(&allocator, graph).Run();
68
69 ASSERT_TRUE(to_remove->GetBlock() == nullptr);
70 ASSERT_EQ(different_offset->GetBlock(), block);
71 ASSERT_EQ(use_after_kill->GetBlock(), block);
72}
73
74TEST(GVNTest, GlobalFieldElimination) {
75 ArenaPool pool;
76 ArenaAllocator allocator(&pool);
77
78 HGraph* graph = new (&allocator) HGraph(&allocator);
79 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
80 graph->AddBlock(entry);
81 graph->SetEntryBlock(entry);
82 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
83 entry->AddInstruction(parameter);
84
85 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
86 graph->AddBlock(block);
87 entry->AddSuccessor(block);
88 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +000089 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
90 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +010091
92 block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
93 HBasicBlock* then = new (&allocator) HBasicBlock(graph);
94 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
95 HBasicBlock* join = new (&allocator) HBasicBlock(graph);
96 graph->AddBlock(then);
97 graph->AddBlock(else_);
98 graph->AddBlock(join);
99
100 block->AddSuccessor(then);
101 block->AddSuccessor(else_);
102 then->AddSuccessor(join);
103 else_->AddSuccessor(join);
104
105 then->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000106 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
107 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100108 then->AddInstruction(new (&allocator) HGoto());
109 else_->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000110 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
111 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100112 else_->AddInstruction(new (&allocator) HGoto());
113 join->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000114 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
115 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100116 join->AddInstruction(new (&allocator) HExit());
117
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000118 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100119 GlobalValueNumberer(&allocator, graph).Run();
120
121 // Check that all field get instructions have been GVN'ed.
122 ASSERT_TRUE(then->GetFirstInstruction()->IsGoto());
123 ASSERT_TRUE(else_->GetFirstInstruction()->IsGoto());
124 ASSERT_TRUE(join->GetFirstInstruction()->IsExit());
125}
126
127TEST(GVNTest, LoopFieldElimination) {
128 ArenaPool pool;
129 ArenaAllocator allocator(&pool);
130
131 HGraph* graph = new (&allocator) HGraph(&allocator);
132 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
133 graph->AddBlock(entry);
134 graph->SetEntryBlock(entry);
135
136 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
137 entry->AddInstruction(parameter);
138
139 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
140 graph->AddBlock(block);
141 entry->AddSuccessor(block);
142 block->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000143 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
144 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100145 block->AddInstruction(new (&allocator) HGoto());
146
147 HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
148 HBasicBlock* loop_body = new (&allocator) HBasicBlock(graph);
149 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
150
151 graph->AddBlock(loop_header);
152 graph->AddBlock(loop_body);
153 graph->AddBlock(exit);
154 block->AddSuccessor(loop_header);
155 loop_header->AddSuccessor(loop_body);
156 loop_header->AddSuccessor(exit);
157 loop_body->AddSuccessor(loop_header);
158
159 loop_header->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000160 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
161 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100162 HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
163 loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
164
165 // Kill inside the loop body to prevent field gets inside the loop header
166 // and the body to be GVN'ed.
167 loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000168 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100169 HInstruction* field_set = loop_body->GetLastInstruction();
170 loop_body->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000171 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
172 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100173 HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
174 loop_body->AddInstruction(new (&allocator) HGoto());
175
176 exit->AddInstruction(
Calin Juravle52c48962014-12-16 17:02:57 +0000177 new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
178 MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100179 HInstruction* field_get_in_exit = exit->GetLastInstruction();
180 exit->AddInstruction(new (&allocator) HExit());
181
182 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
183 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
184 ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
185
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000186 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100187 GlobalValueNumberer(&allocator, graph).Run();
188
189 // Check that all field get instructions are still there.
190 ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
191 ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
192 // The exit block is dominated by the loop header, whose field get
193 // does not get killed by the loop flags.
194 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
195
196 // Now remove the field set, and check that all field get instructions have been GVN'ed.
197 loop_body->RemoveInstruction(field_set);
198 GlobalValueNumberer(&allocator, graph).Run();
199
200 ASSERT_TRUE(field_get_in_loop_header->GetBlock() == nullptr);
201 ASSERT_TRUE(field_get_in_loop_body->GetBlock() == nullptr);
202 ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
203}
204
205// Test that inner loops affect the side effects of the outer loop.
206TEST(GVNTest, LoopSideEffects) {
207 ArenaPool pool;
208 ArenaAllocator allocator(&pool);
209
210 HGraph* graph = new (&allocator) HGraph(&allocator);
211 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
212 graph->AddBlock(entry);
213 graph->SetEntryBlock(entry);
214
215 HBasicBlock* outer_loop_header = new (&allocator) HBasicBlock(graph);
216 HBasicBlock* outer_loop_body = new (&allocator) HBasicBlock(graph);
217 HBasicBlock* outer_loop_exit = new (&allocator) HBasicBlock(graph);
218 HBasicBlock* inner_loop_header = new (&allocator) HBasicBlock(graph);
219 HBasicBlock* inner_loop_body = new (&allocator) HBasicBlock(graph);
220 HBasicBlock* inner_loop_exit = new (&allocator) HBasicBlock(graph);
221
222 graph->AddBlock(outer_loop_header);
223 graph->AddBlock(outer_loop_body);
224 graph->AddBlock(outer_loop_exit);
225 graph->AddBlock(inner_loop_header);
226 graph->AddBlock(inner_loop_body);
227 graph->AddBlock(inner_loop_exit);
228
229 entry->AddSuccessor(outer_loop_header);
230 outer_loop_header->AddSuccessor(outer_loop_body);
231 outer_loop_header->AddSuccessor(outer_loop_exit);
232 outer_loop_body->AddSuccessor(inner_loop_header);
233 inner_loop_header->AddSuccessor(inner_loop_body);
234 inner_loop_header->AddSuccessor(inner_loop_exit);
235 inner_loop_body->AddSuccessor(inner_loop_header);
236 inner_loop_exit->AddSuccessor(outer_loop_header);
237
238 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimBoolean);
239 entry->AddInstruction(parameter);
240 entry->AddInstruction(new (&allocator) HGoto());
241 outer_loop_header->AddInstruction(new (&allocator) HIf(parameter));
242 outer_loop_body->AddInstruction(new (&allocator) HGoto());
243 inner_loop_header->AddInstruction(new (&allocator) HIf(parameter));
244 inner_loop_body->AddInstruction(new (&allocator) HGoto());
245 inner_loop_exit->AddInstruction(new (&allocator) HGoto());
246 outer_loop_exit->AddInstruction(new (&allocator) HExit());
247
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000248 graph->TryBuildingSsa();
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100249
250 ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
251 *outer_loop_header->GetLoopInformation()));
252
253 // Check that the loops don't have side effects.
254 {
255 // Make one block with a side effect.
256 entry->AddInstruction(new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000257 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100258
259 GlobalValueNumberer gvn(&allocator, graph);
260 gvn.Run();
261
262 ASSERT_TRUE(gvn.GetBlockEffects(entry).HasSideEffects());
263 ASSERT_FALSE(gvn.GetLoopEffects(outer_loop_header).HasSideEffects());
264 ASSERT_FALSE(gvn.GetLoopEffects(inner_loop_header).HasSideEffects());
265 }
266
267 // Check that the side effects of the outer loop does not affect the inner loop.
268 {
269 outer_loop_body->InsertInstructionBefore(
270 new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000271 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100272 outer_loop_body->GetLastInstruction());
273
274 GlobalValueNumberer gvn(&allocator, graph);
275 gvn.Run();
276
277 ASSERT_TRUE(gvn.GetBlockEffects(entry).HasSideEffects());
278 ASSERT_TRUE(gvn.GetBlockEffects(outer_loop_body).HasSideEffects());
279 ASSERT_TRUE(gvn.GetLoopEffects(outer_loop_header).HasSideEffects());
280 ASSERT_FALSE(gvn.GetLoopEffects(inner_loop_header).HasSideEffects());
281 }
282
283 // Check that the side effects of the inner loop affects the outer loop.
284 {
285 outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
286 inner_loop_body->InsertInstructionBefore(
287 new (&allocator) HInstanceFieldSet(
Calin Juravle52c48962014-12-16 17:02:57 +0000288 parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
Nicolas Geoffrayd31cf3d2014-09-08 17:30:24 +0100289 inner_loop_body->GetLastInstruction());
290
291 GlobalValueNumberer gvn(&allocator, graph);
292 gvn.Run();
293
294 ASSERT_TRUE(gvn.GetBlockEffects(entry).HasSideEffects());
295 ASSERT_FALSE(gvn.GetBlockEffects(outer_loop_body).HasSideEffects());
296 ASSERT_TRUE(gvn.GetLoopEffects(outer_loop_header).HasSideEffects());
297 ASSERT_TRUE(gvn.GetLoopEffects(inner_loop_header).HasSideEffects());
298 }
299}
300} // namespace art