blob: 371478c9e79ecfe4d945d89c989002b8e7cb0b25 [file] [log] [blame]
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +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 "base/stringprintf.h"
18#include "builder.h"
19#include "nodes.h"
20#include "optimizing_unit_test.h"
21#include "pretty_printer.h"
22#include "utils/arena_allocator.h"
23
24#include "gtest/gtest.h"
25
26namespace art {
27
28static HBasicBlock* createIfBlock(HGraph* graph, ArenaAllocator* allocator) {
29 HBasicBlock* if_block = new (allocator) HBasicBlock(graph);
30 graph->AddBlock(if_block);
31 HInstruction* instr = new (allocator) HIntConstant(4);
32 if_block->AddInstruction(instr);
33 instr = new (allocator) HIf(instr);
34 if_block->AddInstruction(instr);
35 return if_block;
36}
37
38static HBasicBlock* createGotoBlock(HGraph* graph, ArenaAllocator* allocator) {
39 HBasicBlock* block = new (allocator) HBasicBlock(graph);
40 graph->AddBlock(block);
41 HInstruction* got = new (allocator) HGoto();
42 block->AddInstruction(got);
43 return block;
44}
45
46static HBasicBlock* createReturnBlock(HGraph* graph, ArenaAllocator* allocator) {
47 HBasicBlock* block = new (allocator) HBasicBlock(graph);
48 graph->AddBlock(block);
49 HInstruction* return_instr = new (allocator) HReturnVoid();
50 block->AddInstruction(return_instr);
51 return block;
52}
53
54static HBasicBlock* createExitBlock(HGraph* graph, ArenaAllocator* allocator) {
55 HBasicBlock* block = new (allocator) HBasicBlock(graph);
56 graph->AddBlock(block);
57 HInstruction* exit_instr = new (allocator) HExit();
58 block->AddInstruction(exit_instr);
59 return block;
60}
61
62
63// Test that the successors of an if block stay consistent after a SimplifyCFG.
64// This test sets the false block to be the return block.
65TEST(GraphTest, IfSuccessorSimpleJoinBlock1) {
66 ArenaPool pool;
67 ArenaAllocator allocator(&pool);
68
69 HGraph* graph = new (&allocator) HGraph(&allocator);
70 HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
71 HBasicBlock* if_block = createIfBlock(graph, &allocator);
72 HBasicBlock* if_true = createGotoBlock(graph, &allocator);
73 HBasicBlock* return_block = createReturnBlock(graph, &allocator);
74 HBasicBlock* exit_block = createExitBlock(graph, &allocator);
75
76 entry_block->AddSuccessor(if_block);
77 if_block->AddSuccessor(if_true);
78 if_true->AddSuccessor(return_block);
79 if_block->AddSuccessor(return_block);
80 return_block->AddSuccessor(exit_block);
81
82 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_true);
83 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
84
85 graph->SimplifyCFG();
86
87 // Ensure we still have the same if true block.
88 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_true);
89
90 // Ensure the critical edge has been removed.
91 HBasicBlock* false_block = if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor();
92 ASSERT_NE(false_block, return_block);
93
94 // Ensure the new block branches to the join block.
95 ASSERT_EQ(false_block->GetSuccessors().Get(0), return_block);
96}
97
98// Test that the successors of an if block stay consistent after a SimplifyCFG.
99// This test sets the true block to be the return block.
100TEST(GraphTest, IfSuccessorSimpleJoinBlock2) {
101 ArenaPool pool;
102 ArenaAllocator allocator(&pool);
103
104 HGraph* graph = new (&allocator) HGraph(&allocator);
105 HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
106 HBasicBlock* if_block = createIfBlock(graph, &allocator);
107 HBasicBlock* if_false = createGotoBlock(graph, &allocator);
108 HBasicBlock* return_block = createReturnBlock(graph, &allocator);
109 HBasicBlock* exit_block = createExitBlock(graph, &allocator);
110
111 entry_block->AddSuccessor(if_block);
112 if_block->AddSuccessor(return_block);
113 if_false->AddSuccessor(return_block);
114 if_block->AddSuccessor(if_false);
115 return_block->AddSuccessor(exit_block);
116
117 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
118 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_false);
119
120 graph->SimplifyCFG();
121
122 // Ensure we still have the same if true block.
123 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_false);
124
125 // Ensure the critical edge has been removed.
126 HBasicBlock* true_block = if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor();
127 ASSERT_NE(true_block, return_block);
128
129 // Ensure the new block branches to the join block.
130 ASSERT_EQ(true_block->GetSuccessors().Get(0), return_block);
131}
132
133// Test that the successors of an if block stay consistent after a SimplifyCFG.
134// This test sets the true block to be the loop header.
135TEST(GraphTest, IfSuccessorMultipleBackEdges1) {
136 ArenaPool pool;
137 ArenaAllocator allocator(&pool);
138
139 HGraph* graph = new (&allocator) HGraph(&allocator);
140 HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
141 HBasicBlock* if_block = createIfBlock(graph, &allocator);
142 HBasicBlock* return_block = createReturnBlock(graph, &allocator);
143 HBasicBlock* exit_block = createExitBlock(graph, &allocator);
144
145 graph->SetEntryBlock(entry_block);
146 entry_block->AddSuccessor(if_block);
147 if_block->AddSuccessor(if_block);
148 if_block->AddSuccessor(return_block);
149 return_block->AddSuccessor(exit_block);
150
151 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_block);
152 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
153
154 graph->BuildDominatorTree();
155
156 // Ensure we still have the same if false block.
157 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
158
159 // Ensure there is only one back edge.
160 ASSERT_EQ(if_block->GetPredecessors().Size(), 2u);
161 ASSERT_EQ(if_block->GetPredecessors().Get(0), entry_block);
162 ASSERT_NE(if_block->GetPredecessors().Get(1), if_block);
163
164 // Ensure the new block is the back edge.
165 ASSERT_EQ(if_block->GetPredecessors().Get(1),
166 if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor());
167}
168
169// Test that the successors of an if block stay consistent after a SimplifyCFG.
170// This test sets the false block to be the loop header.
171TEST(GraphTest, IfSuccessorMultipleBackEdges2) {
172 ArenaPool pool;
173 ArenaAllocator allocator(&pool);
174
175 HGraph* graph = new (&allocator) HGraph(&allocator);
176 HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
177 HBasicBlock* if_block = createIfBlock(graph, &allocator);
178 HBasicBlock* return_block = createReturnBlock(graph, &allocator);
179 HBasicBlock* exit_block = createExitBlock(graph, &allocator);
180
181 graph->SetEntryBlock(entry_block);
182 entry_block->AddSuccessor(if_block);
183 if_block->AddSuccessor(return_block);
184 if_block->AddSuccessor(if_block);
185 return_block->AddSuccessor(exit_block);
186
187 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
188 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_block);
189
190 graph->BuildDominatorTree();
191
192 // Ensure we still have the same if true block.
193 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
194
195 // Ensure there is only one back edge.
196 ASSERT_EQ(if_block->GetPredecessors().Size(), 2u);
197 ASSERT_EQ(if_block->GetPredecessors().Get(0), entry_block);
198 ASSERT_NE(if_block->GetPredecessors().Get(1), if_block);
199
200 // Ensure the new block is the back edge.
201 ASSERT_EQ(if_block->GetPredecessors().Get(1),
202 if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor());
203}
204
205// Test that the successors of an if block stay consistent after a SimplifyCFG.
206// This test sets the true block to be a loop header with multiple pre headers.
207TEST(GraphTest, IfSuccessorMultiplePreHeaders1) {
208 ArenaPool pool;
209 ArenaAllocator allocator(&pool);
210
211 HGraph* graph = new (&allocator) HGraph(&allocator);
212 HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
213 HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
214 HBasicBlock* if_block = createIfBlock(graph, &allocator);
215 HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
216 HBasicBlock* return_block = createReturnBlock(graph, &allocator);
217
218 graph->SetEntryBlock(entry_block);
219 entry_block->AddSuccessor(first_if_block);
220 first_if_block->AddSuccessor(if_block);
221 first_if_block->AddSuccessor(loop_block);
222 loop_block->AddSuccessor(loop_block);
223 if_block->AddSuccessor(loop_block);
224 if_block->AddSuccessor(return_block);
225
226
227 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), loop_block);
228 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
229
230 graph->BuildDominatorTree();
231
232 HIf* if_instr = if_block->GetLastInstruction()->AsIf();
233 // Ensure we still have the same if false block.
234 ASSERT_EQ(if_instr->IfFalseSuccessor(), return_block);
235
236 // Ensure there is only one pre header..
237 ASSERT_EQ(loop_block->GetPredecessors().Size(), 2u);
238
239 // Ensure the new block is the successor of the true block.
240 ASSERT_EQ(if_instr->IfTrueSuccessor()->GetSuccessors().Size(), 1u);
241 ASSERT_EQ(if_instr->IfTrueSuccessor()->GetSuccessors().Get(0),
242 loop_block->GetLoopInformation()->GetPreHeader());
243}
244
245// Test that the successors of an if block stay consistent after a SimplifyCFG.
246// This test sets the false block to be a loop header with multiple pre headers.
247TEST(GraphTest, IfSuccessorMultiplePreHeaders2) {
248 ArenaPool pool;
249 ArenaAllocator allocator(&pool);
250
251 HGraph* graph = new (&allocator) HGraph(&allocator);
252 HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
253 HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
254 HBasicBlock* if_block = createIfBlock(graph, &allocator);
255 HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
256 HBasicBlock* return_block = createReturnBlock(graph, &allocator);
257
258 graph->SetEntryBlock(entry_block);
259 entry_block->AddSuccessor(first_if_block);
260 first_if_block->AddSuccessor(if_block);
261 first_if_block->AddSuccessor(loop_block);
262 loop_block->AddSuccessor(loop_block);
263 if_block->AddSuccessor(return_block);
264 if_block->AddSuccessor(loop_block);
265
266 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
267 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), loop_block);
268
269 graph->BuildDominatorTree();
270
271 HIf* if_instr = if_block->GetLastInstruction()->AsIf();
272 // Ensure we still have the same if true block.
273 ASSERT_EQ(if_instr->IfTrueSuccessor(), return_block);
274
275 // Ensure there is only one pre header..
276 ASSERT_EQ(loop_block->GetPredecessors().Size(), 2u);
277
278 // Ensure the new block is the successor of the false block.
279 ASSERT_EQ(if_instr->IfFalseSuccessor()->GetSuccessors().Size(), 1u);
280 ASSERT_EQ(if_instr->IfFalseSuccessor()->GetSuccessors().Get(0),
281 loop_block->GetLoopInformation()->GetPreHeader());
282}
283
284TEST(GraphTest, InsertInstructionBefore) {
285 ArenaPool pool;
286 ArenaAllocator allocator(&pool);
287
288 HGraph* graph = new (&allocator) HGraph(&allocator);
289 HBasicBlock* block = createGotoBlock(graph, &allocator);
290 HInstruction* got = block->GetLastInstruction();
291 ASSERT_TRUE(got->IsControlFlow());
292
293 // Test at the beginning of the block.
294 HInstruction* first_instruction = new (&allocator) HIntConstant(4);
295 block->InsertInstructionBefore(first_instruction, got);
296
297 ASSERT_NE(first_instruction->GetId(), -1);
298 ASSERT_EQ(first_instruction->GetBlock(), block);
299 ASSERT_EQ(block->GetFirstInstruction(), first_instruction);
300 ASSERT_EQ(block->GetLastInstruction(), got);
301 ASSERT_EQ(first_instruction->GetNext(), got);
302 ASSERT_EQ(first_instruction->GetPrevious(), nullptr);
303 ASSERT_EQ(got->GetNext(), nullptr);
304 ASSERT_EQ(got->GetPrevious(), first_instruction);
305
306 // Test in the middle of the block.
307 HInstruction* second_instruction = new (&allocator) HIntConstant(4);
308 block->InsertInstructionBefore(second_instruction, got);
309
310 ASSERT_NE(second_instruction->GetId(), -1);
311 ASSERT_EQ(second_instruction->GetBlock(), block);
312 ASSERT_EQ(block->GetFirstInstruction(), first_instruction);
313 ASSERT_EQ(block->GetLastInstruction(), got);
314 ASSERT_EQ(first_instruction->GetNext(), second_instruction);
315 ASSERT_EQ(first_instruction->GetPrevious(), nullptr);
316 ASSERT_EQ(second_instruction->GetNext(), got);
317 ASSERT_EQ(second_instruction->GetPrevious(), first_instruction);
318 ASSERT_EQ(got->GetNext(), nullptr);
319 ASSERT_EQ(got->GetPrevious(), second_instruction);
320}
321
322} // namespace art