blob: b5d712736f3264494e34b5e97606254334d50adb [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
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Vladimír Marko434d9682022-11-04 14:04:17 +000018#include "base/macros.h"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010019#include "builder.h"
20#include "nodes.h"
21#include "optimizing_unit_test.h"
22#include "pretty_printer.h"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010023
24#include "gtest/gtest.h"
25
Vladimír Marko434d9682022-11-04 14:04:17 +000026namespace art HIDDEN {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010027
Vladimir Markoca6fff82017-10-03 14:49:14 +010028class GraphTest : public OptimizingUnitTest {
29 protected:
30 HBasicBlock* CreateIfBlock(HGraph* graph);
31 HBasicBlock* CreateGotoBlock(HGraph* graph);
32 HBasicBlock* CreateEntryBlock(HGraph* graph);
33 HBasicBlock* CreateReturnBlock(HGraph* graph);
34 HBasicBlock* CreateExitBlock(HGraph* graph);
35};
36
37HBasicBlock* GraphTest::CreateIfBlock(HGraph* graph) {
38 HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010039 graph->AddBlock(if_block);
David Brazdil8d5b8b22015-03-24 10:51:52 +000040 HInstruction* instr = graph->GetIntConstant(4);
Vladimir Markoca6fff82017-10-03 14:49:14 +010041 HInstruction* equal = new (GetAllocator()) HEqual(instr, instr);
Dave Allison20dfc792014-06-16 20:44:29 -070042 if_block->AddInstruction(equal);
Vladimir Markoca6fff82017-10-03 14:49:14 +010043 instr = new (GetAllocator()) HIf(equal);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010044 if_block->AddInstruction(instr);
45 return if_block;
46}
47
Vladimir Markoca6fff82017-10-03 14:49:14 +010048HBasicBlock* GraphTest::CreateGotoBlock(HGraph* graph) {
49 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010050 graph->AddBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +010051 HInstruction* got = new (GetAllocator()) HGoto();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010052 block->AddInstruction(got);
53 return block;
54}
55
Vladimir Markoca6fff82017-10-03 14:49:14 +010056HBasicBlock* GraphTest::CreateEntryBlock(HGraph* graph) {
57 HBasicBlock* block = CreateGotoBlock(graph);
David Brazdil8d5b8b22015-03-24 10:51:52 +000058 graph->SetEntryBlock(block);
59 return block;
60}
61
Vladimir Markoca6fff82017-10-03 14:49:14 +010062HBasicBlock* GraphTest::CreateReturnBlock(HGraph* graph) {
63 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010064 graph->AddBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +010065 HInstruction* return_instr = new (GetAllocator()) HReturnVoid();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010066 block->AddInstruction(return_instr);
67 return block;
68}
69
Vladimir Markoca6fff82017-10-03 14:49:14 +010070HBasicBlock* GraphTest::CreateExitBlock(HGraph* graph) {
71 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010072 graph->AddBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +010073 HInstruction* exit_instr = new (GetAllocator()) HExit();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010074 block->AddInstruction(exit_instr);
75 return block;
76}
77
78
79// Test that the successors of an if block stay consistent after a SimplifyCFG.
80// This test sets the false block to be the return block.
Vladimir Markoca6fff82017-10-03 14:49:14 +010081TEST_F(GraphTest, IfSuccessorSimpleJoinBlock1) {
82 HGraph* graph = CreateGraph();
83 HBasicBlock* entry_block = CreateEntryBlock(graph);
84 HBasicBlock* if_block = CreateIfBlock(graph);
85 HBasicBlock* if_true = CreateGotoBlock(graph);
86 HBasicBlock* return_block = CreateReturnBlock(graph);
87 HBasicBlock* exit_block = CreateExitBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +010088
89 entry_block->AddSuccessor(if_block);
90 if_block->AddSuccessor(if_true);
91 if_true->AddSuccessor(return_block);
92 if_block->AddSuccessor(return_block);
93 return_block->AddSuccessor(exit_block);
94
95 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_true);
96 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
97
98 graph->SimplifyCFG();
99
100 // Ensure we still have the same if true block.
101 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_true);
102
103 // Ensure the critical edge has been removed.
104 HBasicBlock* false_block = if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor();
105 ASSERT_NE(false_block, return_block);
106
107 // Ensure the new block branches to the join block.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100108 ASSERT_EQ(false_block->GetSuccessors()[0], return_block);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100109}
110
111// Test that the successors of an if block stay consistent after a SimplifyCFG.
112// This test sets the true block to be the return block.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100113TEST_F(GraphTest, IfSuccessorSimpleJoinBlock2) {
114 HGraph* graph = CreateGraph();
115 HBasicBlock* entry_block = CreateEntryBlock(graph);
116 HBasicBlock* if_block = CreateIfBlock(graph);
117 HBasicBlock* if_false = CreateGotoBlock(graph);
118 HBasicBlock* return_block = CreateReturnBlock(graph);
119 HBasicBlock* exit_block = CreateExitBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100120
121 entry_block->AddSuccessor(if_block);
122 if_block->AddSuccessor(return_block);
123 if_false->AddSuccessor(return_block);
124 if_block->AddSuccessor(if_false);
125 return_block->AddSuccessor(exit_block);
126
127 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
128 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_false);
129
130 graph->SimplifyCFG();
131
132 // Ensure we still have the same if true block.
133 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_false);
134
135 // Ensure the critical edge has been removed.
136 HBasicBlock* true_block = if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor();
137 ASSERT_NE(true_block, return_block);
138
139 // Ensure the new block branches to the join block.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100140 ASSERT_EQ(true_block->GetSuccessors()[0], return_block);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100141}
142
143// Test that the successors of an if block stay consistent after a SimplifyCFG.
144// This test sets the true block to be the loop header.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100145TEST_F(GraphTest, IfSuccessorMultipleBackEdges1) {
146 HGraph* graph = CreateGraph();
147 HBasicBlock* entry_block = CreateEntryBlock(graph);
148 HBasicBlock* if_block = CreateIfBlock(graph);
149 HBasicBlock* return_block = CreateReturnBlock(graph);
150 HBasicBlock* exit_block = CreateExitBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100151
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100152 entry_block->AddSuccessor(if_block);
153 if_block->AddSuccessor(if_block);
154 if_block->AddSuccessor(return_block);
155 return_block->AddSuccessor(exit_block);
156
157 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_block);
158 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
159
160 graph->BuildDominatorTree();
161
162 // Ensure we still have the same if false block.
163 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
164
165 // Ensure there is only one back edge.
Vladimir Marko60584552015-09-03 13:35:12 +0000166 ASSERT_EQ(if_block->GetPredecessors().size(), 2u);
Nicolas Geoffray788f2f02016-01-22 12:41:38 +0000167 ASSERT_EQ(if_block->GetPredecessors()[0], entry_block->GetSingleSuccessor());
Vladimir Markoec7802a2015-10-01 20:57:57 +0100168 ASSERT_NE(if_block->GetPredecessors()[1], if_block);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100169
170 // Ensure the new block is the back edge.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100171 ASSERT_EQ(if_block->GetPredecessors()[1],
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100172 if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor());
173}
174
175// Test that the successors of an if block stay consistent after a SimplifyCFG.
176// This test sets the false block to be the loop header.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100177TEST_F(GraphTest, IfSuccessorMultipleBackEdges2) {
178 HGraph* graph = CreateGraph();
179 HBasicBlock* entry_block = CreateEntryBlock(graph);
180 HBasicBlock* if_block = CreateIfBlock(graph);
181 HBasicBlock* return_block = CreateReturnBlock(graph);
182 HBasicBlock* exit_block = CreateExitBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100183
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100184 entry_block->AddSuccessor(if_block);
185 if_block->AddSuccessor(return_block);
186 if_block->AddSuccessor(if_block);
187 return_block->AddSuccessor(exit_block);
188
189 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
190 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_block);
191
192 graph->BuildDominatorTree();
193
194 // Ensure we still have the same if true block.
195 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
196
197 // Ensure there is only one back edge.
Vladimir Marko60584552015-09-03 13:35:12 +0000198 ASSERT_EQ(if_block->GetPredecessors().size(), 2u);
Nicolas Geoffray788f2f02016-01-22 12:41:38 +0000199 ASSERT_EQ(if_block->GetPredecessors()[0], entry_block->GetSingleSuccessor());
Vladimir Markoec7802a2015-10-01 20:57:57 +0100200 ASSERT_NE(if_block->GetPredecessors()[1], if_block);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100201
202 // Ensure the new block is the back edge.
Vladimir Markoec7802a2015-10-01 20:57:57 +0100203 ASSERT_EQ(if_block->GetPredecessors()[1],
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100204 if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor());
205}
206
207// Test that the successors of an if block stay consistent after a SimplifyCFG.
208// This test sets the true block to be a loop header with multiple pre headers.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100209TEST_F(GraphTest, IfSuccessorMultiplePreHeaders1) {
210 HGraph* graph = CreateGraph();
211 HBasicBlock* entry_block = CreateEntryBlock(graph);
212 HBasicBlock* first_if_block = CreateIfBlock(graph);
213 HBasicBlock* if_block = CreateIfBlock(graph);
214 HBasicBlock* loop_block = CreateGotoBlock(graph);
215 HBasicBlock* return_block = CreateReturnBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100216
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100217 entry_block->AddSuccessor(first_if_block);
218 first_if_block->AddSuccessor(if_block);
219 first_if_block->AddSuccessor(loop_block);
220 loop_block->AddSuccessor(loop_block);
221 if_block->AddSuccessor(loop_block);
222 if_block->AddSuccessor(return_block);
223
224
225 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), loop_block);
226 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
227
228 graph->BuildDominatorTree();
229
230 HIf* if_instr = if_block->GetLastInstruction()->AsIf();
231 // Ensure we still have the same if false block.
232 ASSERT_EQ(if_instr->IfFalseSuccessor(), return_block);
233
234 // Ensure there is only one pre header..
Vladimir Marko60584552015-09-03 13:35:12 +0000235 ASSERT_EQ(loop_block->GetPredecessors().size(), 2u);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100236
237 // Ensure the new block is the successor of the true block.
Vladimir Marko60584552015-09-03 13:35:12 +0000238 ASSERT_EQ(if_instr->IfTrueSuccessor()->GetSuccessors().size(), 1u);
Vladimir Markoec7802a2015-10-01 20:57:57 +0100239 ASSERT_EQ(if_instr->IfTrueSuccessor()->GetSuccessors()[0],
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100240 loop_block->GetLoopInformation()->GetPreHeader());
241}
242
243// Test that the successors of an if block stay consistent after a SimplifyCFG.
244// This test sets the false block to be a loop header with multiple pre headers.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100245TEST_F(GraphTest, IfSuccessorMultiplePreHeaders2) {
246 HGraph* graph = CreateGraph();
247 HBasicBlock* entry_block = CreateEntryBlock(graph);
248 HBasicBlock* first_if_block = CreateIfBlock(graph);
249 HBasicBlock* if_block = CreateIfBlock(graph);
250 HBasicBlock* loop_block = CreateGotoBlock(graph);
251 HBasicBlock* return_block = CreateReturnBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100252
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100253 entry_block->AddSuccessor(first_if_block);
254 first_if_block->AddSuccessor(if_block);
255 first_if_block->AddSuccessor(loop_block);
256 loop_block->AddSuccessor(loop_block);
257 if_block->AddSuccessor(return_block);
258 if_block->AddSuccessor(loop_block);
259
260 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
261 ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), loop_block);
262
263 graph->BuildDominatorTree();
264
265 HIf* if_instr = if_block->GetLastInstruction()->AsIf();
266 // Ensure we still have the same if true block.
267 ASSERT_EQ(if_instr->IfTrueSuccessor(), return_block);
268
269 // Ensure there is only one pre header..
Vladimir Marko60584552015-09-03 13:35:12 +0000270 ASSERT_EQ(loop_block->GetPredecessors().size(), 2u);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100271
272 // Ensure the new block is the successor of the false block.
Vladimir Marko60584552015-09-03 13:35:12 +0000273 ASSERT_EQ(if_instr->IfFalseSuccessor()->GetSuccessors().size(), 1u);
Vladimir Markoec7802a2015-10-01 20:57:57 +0100274 ASSERT_EQ(if_instr->IfFalseSuccessor()->GetSuccessors()[0],
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100275 loop_block->GetLoopInformation()->GetPreHeader());
276}
277
Vladimir Markoca6fff82017-10-03 14:49:14 +0100278TEST_F(GraphTest, InsertInstructionBefore) {
279 HGraph* graph = CreateGraph();
280 HBasicBlock* block = CreateGotoBlock(graph);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100281 HInstruction* got = block->GetLastInstruction();
282 ASSERT_TRUE(got->IsControlFlow());
283
284 // Test at the beginning of the block.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100285 HInstruction* first_instruction = new (GetAllocator()) HIntConstant(4);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100286 block->InsertInstructionBefore(first_instruction, got);
287
288 ASSERT_NE(first_instruction->GetId(), -1);
289 ASSERT_EQ(first_instruction->GetBlock(), block);
290 ASSERT_EQ(block->GetFirstInstruction(), first_instruction);
291 ASSERT_EQ(block->GetLastInstruction(), got);
292 ASSERT_EQ(first_instruction->GetNext(), got);
293 ASSERT_EQ(first_instruction->GetPrevious(), nullptr);
294 ASSERT_EQ(got->GetNext(), nullptr);
295 ASSERT_EQ(got->GetPrevious(), first_instruction);
296
297 // Test in the middle of the block.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100298 HInstruction* second_instruction = new (GetAllocator()) HIntConstant(4);
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100299 block->InsertInstructionBefore(second_instruction, got);
300
301 ASSERT_NE(second_instruction->GetId(), -1);
302 ASSERT_EQ(second_instruction->GetBlock(), block);
303 ASSERT_EQ(block->GetFirstInstruction(), first_instruction);
304 ASSERT_EQ(block->GetLastInstruction(), got);
305 ASSERT_EQ(first_instruction->GetNext(), second_instruction);
306 ASSERT_EQ(first_instruction->GetPrevious(), nullptr);
307 ASSERT_EQ(second_instruction->GetNext(), got);
308 ASSERT_EQ(second_instruction->GetPrevious(), first_instruction);
309 ASSERT_EQ(got->GetNext(), nullptr);
310 ASSERT_EQ(got->GetPrevious(), second_instruction);
311}
312
313} // namespace art