blob: a96cd842978008d97d88ffbd862814ef831fbd42 [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 }
92 cu_.mir_graph->num_blocks_ = count;
Vladimir Markoe39c54e2014-09-22 14:50:02 +010093 ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
94 cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
Vladimir Marko55fff042014-07-10 12:42:52 +010095 ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
Vladimir Markoe39c54e2014-09-22 14:50:02 +010096 cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
Vladimir Marko55fff042014-07-10 12:42:52 +010097 ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
Razvan A Lupusoru8d0d03e2014-06-06 17:04:52 -070098
99 DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>(cu_.arena.Alloc(sizeof(DexFile::CodeItem),
100 kArenaAllocMisc));
Razvan A Lupusoru75035972014-09-11 15:24:59 -0700101 cu_.mir_graph->current_code_item_ = code_item;
Vladimir Marko55fff042014-07-10 12:42:52 +0100102 }
103
104 template <size_t count>
105 void PrepareBasicBlocks(const BBDef (&defs)[count]) {
106 DoPrepareBasicBlocks(defs, count);
107 }
108
109 void ComputeTopologicalSortOrder() {
110 cu_.mir_graph->SSATransformationStart();
111 cu_.mir_graph->ComputeDFSOrders();
112 cu_.mir_graph->ComputeDominators();
113 cu_.mir_graph->ComputeTopologicalSortOrder();
114 cu_.mir_graph->SSATransformationEnd();
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100115 ASSERT_FALSE(cu_.mir_graph->topological_order_.empty());
116 ASSERT_FALSE(cu_.mir_graph->topological_order_loop_ends_.empty());
117 ASSERT_FALSE(cu_.mir_graph->topological_order_indexes_.empty());
118 ASSERT_EQ(cu_.mir_graph->GetNumBlocks(), cu_.mir_graph->topological_order_indexes_.size());
119 for (size_t i = 0, size = cu_.mir_graph->GetTopologicalSortOrder().size(); i != size; ++i) {
120 ASSERT_LT(cu_.mir_graph->topological_order_[i], cu_.mir_graph->GetNumBlocks());
121 BasicBlockId id = cu_.mir_graph->topological_order_[i];
122 EXPECT_EQ(i, cu_.mir_graph->topological_order_indexes_[id]);
Vladimir Marko55fff042014-07-10 12:42:52 +0100123 }
124 }
125
126 void DoCheckOrder(const BasicBlockId* ids, size_t count) {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100127 ASSERT_EQ(count, cu_.mir_graph->GetTopologicalSortOrder().size());
Vladimir Marko55fff042014-07-10 12:42:52 +0100128 for (size_t i = 0; i != count; ++i) {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100129 EXPECT_EQ(ids[i], cu_.mir_graph->GetTopologicalSortOrder()[i]) << i;
Vladimir Marko55fff042014-07-10 12:42:52 +0100130 }
131 }
132
133 template <size_t count>
134 void CheckOrder(const BasicBlockId (&ids)[count]) {
135 DoCheckOrder(ids, count);
136 }
137
138 void DoCheckLoopEnds(const uint16_t* ends, size_t count) {
139 for (size_t i = 0; i != count; ++i) {
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100140 ASSERT_LT(i, cu_.mir_graph->GetTopologicalSortOrderLoopEnds().size());
141 EXPECT_EQ(ends[i], cu_.mir_graph->GetTopologicalSortOrderLoopEnds()[i]) << i;
Vladimir Marko55fff042014-07-10 12:42:52 +0100142 }
143 }
144
145 template <size_t count>
146 void CheckLoopEnds(const uint16_t (&ends)[count]) {
147 DoCheckLoopEnds(ends, count);
148 }
149
150 TopologicalSortOrderTest()
151 : pool_(),
152 cu_(&pool_) {
153 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
154 }
155
156 ArenaPool pool_;
157 CompilationUnit cu_;
158};
159
160TEST_F(TopologicalSortOrderTest, DoWhile) {
161 const BBDef bbs[] = {
162 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
163 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
164 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
165 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
166 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)), // "taken" loops to self.
167 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
168 };
169 const BasicBlockId expected_order[] = {
170 1, 3, 4, 5, 2
171 };
172 const uint16_t loop_ends[] = {
173 0, 0, 3, 0, 0
174 };
175
176 PrepareBasicBlocks(bbs);
177 ComputeTopologicalSortOrder();
178 CheckOrder(expected_order);
179 CheckLoopEnds(loop_ends);
180}
181
182TEST_F(TopologicalSortOrderTest, While) {
183 const BBDef bbs[] = {
184 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
185 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
186 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
187 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED2(1, 4)),
188 DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(3)), // Loops to 3.
189 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
190 };
191 const BasicBlockId expected_order[] = {
192 1, 3, 4, 5, 2
193 };
194 const uint16_t loop_ends[] = {
195 0, 3, 0, 0, 0
196 };
197
198 PrepareBasicBlocks(bbs);
199 ComputeTopologicalSortOrder();
200 CheckOrder(expected_order);
201 CheckLoopEnds(loop_ends);
202}
203
204TEST_F(TopologicalSortOrderTest, WhileWithTwoBackEdges) {
205 const BBDef bbs[] = {
206 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
207 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
208 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
209 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED3(1, 4, 5)),
210 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED1(3)), // Loops to 3.
211 DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)), // Loops to 3.
212 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
213 };
214 const BasicBlockId expected_order[] = {
215 1, 3, 4, 5, 6, 2
216 };
217 const uint16_t loop_ends[] = {
218 0, 4, 0, 0, 0, 0
219 };
220
221 PrepareBasicBlocks(bbs);
222 ComputeTopologicalSortOrder();
223 CheckOrder(expected_order);
224 CheckLoopEnds(loop_ends);
225}
226
227TEST_F(TopologicalSortOrderTest, NestedLoop) {
228 const BBDef bbs[] = {
229 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
230 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
231 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
232 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED2(1, 6)),
233 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED2(3, 5)),
234 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)), // Loops to 4.
235 DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)), // Loops to 3.
236 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
237 };
238 const BasicBlockId expected_order[] = {
239 1, 3, 4, 5, 6, 7, 2
240 };
241 const uint16_t loop_ends[] = {
242 0, 5, 4, 0, 0, 0, 0
243 };
244
245 PrepareBasicBlocks(bbs);
246 ComputeTopologicalSortOrder();
247 CheckOrder(expected_order);
248 CheckLoopEnds(loop_ends);
249}
250
251TEST_F(TopologicalSortOrderTest, NestedLoopHeadLoops) {
252 const BBDef bbs[] = {
253 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
254 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
255 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
256 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 4)),
257 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED2(3, 5)), // Nested head, loops to 3.
258 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)), // Loops to 4.
259 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
260 };
261 const BasicBlockId expected_order[] = {
262 1, 3, 4, 5, 6, 2
263 };
264 const uint16_t loop_ends[] = {
265 0, 4, 4, 0, 0, 0
266 };
267
268 PrepareBasicBlocks(bbs);
269 ComputeTopologicalSortOrder();
270 CheckOrder(expected_order);
271 CheckLoopEnds(loop_ends);
272}
273
274TEST_F(TopologicalSortOrderTest, NestedLoopSameBackBranchBlock) {
275 const BBDef bbs[] = {
276 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
277 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
278 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
279 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 5)),
280 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 5)),
281 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 3), DEF_PRED1(4)), // Loops to 4 and 3.
282 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
283 };
284 const BasicBlockId expected_order[] = {
285 1, 3, 4, 5, 6, 2
286 };
287 const uint16_t loop_ends[] = {
288 0, 4, 4, 0, 0, 0
289 };
290
291 PrepareBasicBlocks(bbs);
292 ComputeTopologicalSortOrder();
293 CheckOrder(expected_order);
294 CheckLoopEnds(loop_ends);
295}
296
297TEST_F(TopologicalSortOrderTest, TwoReorderedInnerLoops) {
298 // This is a simplified version of real code graph where the branch from 8 to 5 must prevent
299 // the block 5 from being considered a loop head before processing the loop 7-8.
300 const BBDef bbs[] = {
301 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
302 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
303 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(9)),
304 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 9), DEF_PRED2(1, 5)),
305 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 7), DEF_PRED1(3)), // Branch over loop in 5.
306 DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 3), DEF_PRED3(4, 6, 8)), // Loops to 4; inner loop.
307 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)), // Loops to 5.
308 DEF_BB(kDalvikByteCode, DEF_SUCC1(8), DEF_PRED2(4, 8)), // Loop head.
309 DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 5), DEF_PRED1(7)), // Loops to 7; branches to 5.
310 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
311 };
312 const BasicBlockId expected_order[] = {
313 1, 3, 4, 7, 8, 5, 6, 9, 2
314 };
315 const uint16_t loop_ends[] = {
316 0, 7, 0, 5, 0, 7, 0, 0, 0
317 };
318
319 PrepareBasicBlocks(bbs);
320 ComputeTopologicalSortOrder();
321 CheckOrder(expected_order);
322 CheckLoopEnds(loop_ends);
323}
324
325TEST_F(TopologicalSortOrderTest, NestedLoopWithBackEdgeAfterOuterLoopBackEdge) {
326 // This is a simplified version of real code graph. The back-edge from 7 to the inner
327 // loop head 4 comes after the back-edge from 6 to the outer loop head 3. To make this
328 // appear a bit more complex, there's also a back-edge from 5 to 4.
329 const BBDef bbs[] = {
330 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
331 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
332 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
333 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED2(1, 6)), // Outer loop head.
334 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED3(3, 5, 7)), // Inner loop head.
335 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)), // Loops to inner loop head 4.
336 DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 3), DEF_PRED1(4)), // Loops to outer loop head 3.
337 DEF_BB(kDalvikByteCode, DEF_SUCC2(2, 4), DEF_PRED1(6)), // Loops to inner loop head 4.
338 };
339 const BasicBlockId expected_order[] = {
340 // NOTE: The 5 goes before 6 only because 5 is a "fall-through" from 4 while 6 is "taken".
341 1, 3, 4, 5, 6, 7, 2
342 };
343 const uint16_t loop_ends[] = {
344 0, 6, 6, 0, 0, 0, 0
345 };
346
347 PrepareBasicBlocks(bbs);
348 ComputeTopologicalSortOrder();
349 CheckOrder(expected_order);
350 CheckLoopEnds(loop_ends);
351}
352
353TEST_F(TopologicalSortOrderTest, LoopWithTwoEntryPoints) {
354 const BBDef bbs[] = {
355 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
356 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
357 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
358 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED1(1)),
359 DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 6)), // Fall-back block is chosen as
360 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED2(3, 4)), // the earlier from these two.
361 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED1(5)),
362 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(6)),
363 };
364 const BasicBlockId expected_order[] = {
365 1, 3, 4, 5, 6, 7, 2
366 };
367 const uint16_t loop_ends[] = {
368 0, 0, 5, 0, 0, 0, 0
369 };
370
371 PrepareBasicBlocks(bbs);
372 ComputeTopologicalSortOrder();
373 CheckOrder(expected_order);
374 CheckLoopEnds(loop_ends);
375}
376
377} // namespace art