blob: 8a7e71f4af1d5d4162da42ad35b8c46b44b7edd1 [file] [log] [blame]
Vladimir Marko55fff042014-07-10 12:42:52 +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 "mir_graph.h"
18#include "gtest/gtest.h"
19
20namespace art {
21
22class TopologicalSortOrderTest : public testing::Test {
23 protected:
24 struct BBDef {
25 static constexpr size_t kMaxSuccessors = 4;
26 static constexpr size_t kMaxPredecessors = 4;
27
28 BBType type;
29 size_t num_successors;
30 BasicBlockId successors[kMaxPredecessors];
31 size_t num_predecessors;
32 BasicBlockId predecessors[kMaxPredecessors];
33 };
34
35#define DEF_SUCC0() \
36 0u, { }
37#define DEF_SUCC1(s1) \
38 1u, { s1 }
39#define DEF_SUCC2(s1, s2) \
40 2u, { s1, s2 }
41#define DEF_SUCC3(s1, s2, s3) \
42 3u, { s1, s2, s3 }
43#define DEF_SUCC4(s1, s2, s3, s4) \
44 4u, { s1, s2, s3, s4 }
45#define DEF_PRED0() \
46 0u, { }
47#define DEF_PRED1(p1) \
48 1u, { p1 }
49#define DEF_PRED2(p1, p2) \
50 2u, { p1, p2 }
51#define DEF_PRED3(p1, p2, p3) \
52 3u, { p1, p2, p3 }
53#define DEF_PRED4(p1, p2, p3, p4) \
54 4u, { p1, p2, p3, p4 }
55#define DEF_BB(type, succ, pred) \
56 { type, succ, pred }
57
58 void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
59 cu_.mir_graph->block_id_map_.clear();
Vladimir Markoe39c54e2014-09-22 14:50:02 +010060 cu_.mir_graph->block_list_.clear();
Vladimir Marko55fff042014-07-10 12:42:52 +010061 ASSERT_LT(3u, count); // null, entry, exit and at least one bytecode block.
62 ASSERT_EQ(kNullBlock, defs[0].type);
63 ASSERT_EQ(kEntryBlock, defs[1].type);
64 ASSERT_EQ(kExitBlock, defs[2].type);
65 for (size_t i = 0u; i != count; ++i) {
66 const BBDef* def = &defs[i];
Vladimir Markoe39c54e2014-09-22 14:50:02 +010067 BasicBlock* bb = cu_.mir_graph->CreateNewBB(def->type);
Vladimir Marko55fff042014-07-10 12:42:52 +010068 if (def->num_successors <= 2) {
69 bb->successor_block_list_type = kNotUsed;
Vladimir Marko55fff042014-07-10 12:42:52 +010070 bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
71 bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
72 } else {
73 bb->successor_block_list_type = kPackedSwitch;
74 bb->fall_through = 0u;
75 bb->taken = 0u;
Vladimir Markoe39c54e2014-09-22 14:50:02 +010076 bb->successor_blocks.reserve(def->num_successors);
Vladimir Marko55fff042014-07-10 12:42:52 +010077 for (size_t j = 0u; j != def->num_successors; ++j) {
78 SuccessorBlockInfo* successor_block_info =
79 static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
80 kArenaAllocSuccessor));
81 successor_block_info->block = j;
82 successor_block_info->key = 0u; // Not used by class init check elimination.
Vladimir Markoe39c54e2014-09-22 14:50:02 +010083 bb->successor_blocks.push_back(successor_block_info);
Vladimir Marko55fff042014-07-10 12:42:52 +010084 }
85 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +010086 bb->predecessors.assign(def->predecessors, def->predecessors + def->num_predecessors);
Vladimir Marko55fff042014-07-10 12:42:52 +010087 if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
88 bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
89 cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
90 }
91 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +010092 ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
93 cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
Vladimir Marko55fff042014-07-10 12:42:52 +010094 ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
Vladimir Markoe39c54e2014-09-22 14:50:02 +010095 cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
Vladimir Marko55fff042014-07-10 12:42:52 +010096 ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
Razvan A Lupusoru8d0d03e2014-06-06 17:04:52 -070097
98 DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>(cu_.arena.Alloc(sizeof(DexFile::CodeItem),
99 kArenaAllocMisc));
Razvan A Lupusoru75035972014-09-11 15:24:59 -0700100 cu_.mir_graph->current_code_item_ = code_item;
Vladimir Marko55fff042014-07-10 12:42:52 +0100101 }
102
103 template <size_t count>
104 void PrepareBasicBlocks(const BBDef (&defs)[count]) {
105 DoPrepareBasicBlocks(defs, count);
106 }
107
108 void ComputeTopologicalSortOrder() {
109 cu_.mir_graph->SSATransformationStart();
110 cu_.mir_graph->ComputeDFSOrders();
111 cu_.mir_graph->ComputeDominators();
112 cu_.mir_graph->ComputeTopologicalSortOrder();
113 cu_.mir_graph->SSATransformationEnd();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100114 ASSERT_FALSE(cu_.mir_graph->topological_order_.empty());
115 ASSERT_FALSE(cu_.mir_graph->topological_order_loop_ends_.empty());
116 ASSERT_FALSE(cu_.mir_graph->topological_order_indexes_.empty());
117 ASSERT_EQ(cu_.mir_graph->GetNumBlocks(), cu_.mir_graph->topological_order_indexes_.size());
118 for (size_t i = 0, size = cu_.mir_graph->GetTopologicalSortOrder().size(); i != size; ++i) {
119 ASSERT_LT(cu_.mir_graph->topological_order_[i], cu_.mir_graph->GetNumBlocks());
120 BasicBlockId id = cu_.mir_graph->topological_order_[i];
121 EXPECT_EQ(i, cu_.mir_graph->topological_order_indexes_[id]);
Vladimir Marko55fff042014-07-10 12:42:52 +0100122 }
123 }
124
125 void DoCheckOrder(const BasicBlockId* ids, size_t count) {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100126 ASSERT_EQ(count, cu_.mir_graph->GetTopologicalSortOrder().size());
Vladimir Marko55fff042014-07-10 12:42:52 +0100127 for (size_t i = 0; i != count; ++i) {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100128 EXPECT_EQ(ids[i], cu_.mir_graph->GetTopologicalSortOrder()[i]) << i;
Vladimir Marko55fff042014-07-10 12:42:52 +0100129 }
130 }
131
132 template <size_t count>
133 void CheckOrder(const BasicBlockId (&ids)[count]) {
134 DoCheckOrder(ids, count);
135 }
136
137 void DoCheckLoopEnds(const uint16_t* ends, size_t count) {
138 for (size_t i = 0; i != count; ++i) {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100139 ASSERT_LT(i, cu_.mir_graph->GetTopologicalSortOrderLoopEnds().size());
140 EXPECT_EQ(ends[i], cu_.mir_graph->GetTopologicalSortOrderLoopEnds()[i]) << i;
Vladimir Marko55fff042014-07-10 12:42:52 +0100141 }
142 }
143
144 template <size_t count>
145 void CheckLoopEnds(const uint16_t (&ends)[count]) {
146 DoCheckLoopEnds(ends, count);
147 }
148
149 TopologicalSortOrderTest()
150 : pool_(),
151 cu_(&pool_) {
152 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
153 }
154
155 ArenaPool pool_;
156 CompilationUnit cu_;
157};
158
159TEST_F(TopologicalSortOrderTest, DoWhile) {
160 const BBDef bbs[] = {
161 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
162 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
163 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
164 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
165 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)), // "taken" loops to self.
166 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
167 };
168 const BasicBlockId expected_order[] = {
169 1, 3, 4, 5, 2
170 };
171 const uint16_t loop_ends[] = {
172 0, 0, 3, 0, 0
173 };
174
175 PrepareBasicBlocks(bbs);
176 ComputeTopologicalSortOrder();
177 CheckOrder(expected_order);
178 CheckLoopEnds(loop_ends);
179}
180
181TEST_F(TopologicalSortOrderTest, While) {
182 const BBDef bbs[] = {
183 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
184 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
185 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
186 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED2(1, 4)),
187 DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(3)), // Loops to 3.
188 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
189 };
190 const BasicBlockId expected_order[] = {
191 1, 3, 4, 5, 2
192 };
193 const uint16_t loop_ends[] = {
194 0, 3, 0, 0, 0
195 };
196
197 PrepareBasicBlocks(bbs);
198 ComputeTopologicalSortOrder();
199 CheckOrder(expected_order);
200 CheckLoopEnds(loop_ends);
201}
202
203TEST_F(TopologicalSortOrderTest, WhileWithTwoBackEdges) {
204 const BBDef bbs[] = {
205 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
206 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
207 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
208 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED3(1, 4, 5)),
209 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED1(3)), // Loops to 3.
210 DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)), // Loops to 3.
211 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
212 };
213 const BasicBlockId expected_order[] = {
214 1, 3, 4, 5, 6, 2
215 };
216 const uint16_t loop_ends[] = {
217 0, 4, 0, 0, 0, 0
218 };
219
220 PrepareBasicBlocks(bbs);
221 ComputeTopologicalSortOrder();
222 CheckOrder(expected_order);
223 CheckLoopEnds(loop_ends);
224}
225
226TEST_F(TopologicalSortOrderTest, NestedLoop) {
227 const BBDef bbs[] = {
228 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
229 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
230 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
231 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED2(1, 6)),
232 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED2(3, 5)),
233 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)), // Loops to 4.
234 DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)), // Loops to 3.
235 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
236 };
237 const BasicBlockId expected_order[] = {
238 1, 3, 4, 5, 6, 7, 2
239 };
240 const uint16_t loop_ends[] = {
241 0, 5, 4, 0, 0, 0, 0
242 };
243
244 PrepareBasicBlocks(bbs);
245 ComputeTopologicalSortOrder();
246 CheckOrder(expected_order);
247 CheckLoopEnds(loop_ends);
248}
249
250TEST_F(TopologicalSortOrderTest, NestedLoopHeadLoops) {
251 const BBDef bbs[] = {
252 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
253 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
254 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
255 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 4)),
256 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED2(3, 5)), // Nested head, loops to 3.
257 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)), // Loops to 4.
258 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
259 };
260 const BasicBlockId expected_order[] = {
261 1, 3, 4, 5, 6, 2
262 };
263 const uint16_t loop_ends[] = {
264 0, 4, 4, 0, 0, 0
265 };
266
267 PrepareBasicBlocks(bbs);
268 ComputeTopologicalSortOrder();
269 CheckOrder(expected_order);
270 CheckLoopEnds(loop_ends);
271}
272
273TEST_F(TopologicalSortOrderTest, NestedLoopSameBackBranchBlock) {
274 const BBDef bbs[] = {
275 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
276 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
277 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
278 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 5)),
279 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 5)),
280 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 3), DEF_PRED1(4)), // Loops to 4 and 3.
281 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
282 };
283 const BasicBlockId expected_order[] = {
284 1, 3, 4, 5, 6, 2
285 };
286 const uint16_t loop_ends[] = {
287 0, 4, 4, 0, 0, 0
288 };
289
290 PrepareBasicBlocks(bbs);
291 ComputeTopologicalSortOrder();
292 CheckOrder(expected_order);
293 CheckLoopEnds(loop_ends);
294}
295
296TEST_F(TopologicalSortOrderTest, TwoReorderedInnerLoops) {
297 // This is a simplified version of real code graph where the branch from 8 to 5 must prevent
298 // the block 5 from being considered a loop head before processing the loop 7-8.
299 const BBDef bbs[] = {
300 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
301 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
302 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(9)),
303 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 9), DEF_PRED2(1, 5)),
304 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 7), DEF_PRED1(3)), // Branch over loop in 5.
305 DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 3), DEF_PRED3(4, 6, 8)), // Loops to 4; inner loop.
306 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)), // Loops to 5.
307 DEF_BB(kDalvikByteCode, DEF_SUCC1(8), DEF_PRED2(4, 8)), // Loop head.
308 DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 5), DEF_PRED1(7)), // Loops to 7; branches to 5.
309 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
310 };
311 const BasicBlockId expected_order[] = {
312 1, 3, 4, 7, 8, 5, 6, 9, 2
313 };
314 const uint16_t loop_ends[] = {
315 0, 7, 0, 5, 0, 7, 0, 0, 0
316 };
317
318 PrepareBasicBlocks(bbs);
319 ComputeTopologicalSortOrder();
320 CheckOrder(expected_order);
321 CheckLoopEnds(loop_ends);
322}
323
324TEST_F(TopologicalSortOrderTest, NestedLoopWithBackEdgeAfterOuterLoopBackEdge) {
325 // This is a simplified version of real code graph. The back-edge from 7 to the inner
326 // loop head 4 comes after the back-edge from 6 to the outer loop head 3. To make this
327 // appear a bit more complex, there's also a back-edge from 5 to 4.
328 const BBDef bbs[] = {
329 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
330 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
331 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
332 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED2(1, 6)), // Outer loop head.
333 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED3(3, 5, 7)), // Inner loop head.
334 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)), // Loops to inner loop head 4.
335 DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 3), DEF_PRED1(4)), // Loops to outer loop head 3.
336 DEF_BB(kDalvikByteCode, DEF_SUCC2(2, 4), DEF_PRED1(6)), // Loops to inner loop head 4.
337 };
338 const BasicBlockId expected_order[] = {
339 // NOTE: The 5 goes before 6 only because 5 is a "fall-through" from 4 while 6 is "taken".
340 1, 3, 4, 5, 6, 7, 2
341 };
342 const uint16_t loop_ends[] = {
343 0, 6, 6, 0, 0, 0, 0
344 };
345
346 PrepareBasicBlocks(bbs);
347 ComputeTopologicalSortOrder();
348 CheckOrder(expected_order);
349 CheckLoopEnds(loop_ends);
350}
351
352TEST_F(TopologicalSortOrderTest, LoopWithTwoEntryPoints) {
353 const BBDef bbs[] = {
354 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
355 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
356 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
357 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED1(1)),
358 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 6)), // Fall-back block is chosen as
359 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED2(3, 4)), // the earlier from these two.
360 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED1(5)),
361 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(6)),
362 };
363 const BasicBlockId expected_order[] = {
364 1, 3, 4, 5, 6, 7, 2
365 };
366 const uint16_t loop_ends[] = {
367 0, 0, 5, 0, 0, 0, 0
368 };
369
370 PrepareBasicBlocks(bbs);
371 ComputeTopologicalSortOrder();
372 CheckOrder(expected_order);
373 CheckLoopEnds(loop_ends);
374}
375
376} // namespace art