blob: b256fbb46da4b632215ea5859c8a0538d0d883ca [file] [log] [blame]
Roland Levillainccc07a92014-09-16 14:48:16 +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
Vladimír Marko434d9682022-11-04 14:04:17 +000017#include "base/macros.h"
Roland Levillainccc07a92014-09-16 14:48:16 +010018#include "graph_checker.h"
19#include "optimizing_unit_test.h"
20
Vladimír Marko434d9682022-11-04 14:04:17 +000021namespace art HIDDEN {
Roland Levillainccc07a92014-09-16 14:48:16 +010022
Santiago Aboy Solanes2c50b3a2023-02-10 10:25:31 +000023class GraphCheckerTest : public CommonCompilerTest, public OptimizingUnitTestHelper {
Vladimir Markoca6fff82017-10-03 14:49:14 +010024 protected:
25 HGraph* CreateSimpleCFG();
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080026 void TestCode(const std::vector<uint16_t>& data);
Vladimir Markoca6fff82017-10-03 14:49:14 +010027};
28
Roland Levillainccc07a92014-09-16 14:48:16 +010029/**
30 * Create a simple control-flow graph composed of two blocks:
31 *
32 * BasicBlock 0, succ: 1
David Brazdildbf5d752015-07-30 18:21:41 +010033 * 0: ReturnVoid 1
Roland Levillainccc07a92014-09-16 14:48:16 +010034 * BasicBlock 1, pred: 0
35 * 1: Exit
36 */
Vladimir Markoca6fff82017-10-03 14:49:14 +010037HGraph* GraphCheckerTest::CreateSimpleCFG() {
38 HGraph* graph = CreateGraph();
39 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
40 entry_block->AddInstruction(new (GetAllocator()) HReturnVoid());
Roland Levillainccc07a92014-09-16 14:48:16 +010041 graph->AddBlock(entry_block);
42 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +010043 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
44 exit_block->AddInstruction(new (GetAllocator()) HExit());
Roland Levillainccc07a92014-09-16 14:48:16 +010045 graph->AddBlock(exit_block);
46 graph->SetExitBlock(exit_block);
47 entry_block->AddSuccessor(exit_block);
David Brazdil8e73ac32016-02-15 18:20:01 +000048 graph->BuildDominatorTree();
Roland Levillainccc07a92014-09-16 14:48:16 +010049 return graph;
50}
51
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080052void GraphCheckerTest::TestCode(const std::vector<uint16_t>& data) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010053 HGraph* graph = CreateCFG(data);
Roland Levillainccc07a92014-09-16 14:48:16 +010054 ASSERT_NE(graph, nullptr);
55
Vladimir Marko655e5852015-10-12 10:38:28 +010056 GraphChecker graph_checker(graph);
Roland Levillain633021e2014-10-01 14:12:25 +010057 graph_checker.Run();
Roland Levillainccc07a92014-09-16 14:48:16 +010058 ASSERT_TRUE(graph_checker.IsValid());
59}
60
David Brazdilbadd8262016-02-02 16:28:56 +000061TEST_F(GraphCheckerTest, ReturnVoid) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080062 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Roland Levillainccc07a92014-09-16 14:48:16 +010063 Instruction::RETURN_VOID);
64
65 TestCode(data);
66}
67
David Brazdilbadd8262016-02-02 16:28:56 +000068TEST_F(GraphCheckerTest, CFG1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080069 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Roland Levillainccc07a92014-09-16 14:48:16 +010070 Instruction::GOTO | 0x100,
71 Instruction::RETURN_VOID);
72
73 TestCode(data);
74}
75
David Brazdilbadd8262016-02-02 16:28:56 +000076TEST_F(GraphCheckerTest, CFG2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080077 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Roland Levillainccc07a92014-09-16 14:48:16 +010078 Instruction::CONST_4 | 0 | 0,
79 Instruction::IF_EQ, 3,
80 Instruction::GOTO | 0x100,
81 Instruction::RETURN_VOID);
82
83 TestCode(data);
84}
85
David Brazdilbadd8262016-02-02 16:28:56 +000086TEST_F(GraphCheckerTest, CFG3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080087 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Roland Levillainccc07a92014-09-16 14:48:16 +010088 Instruction::CONST_4 | 0 | 0,
89 Instruction::IF_EQ, 3,
90 Instruction::GOTO | 0x100,
91 Instruction::GOTO | 0xFF00);
92
93 TestCode(data);
94}
95
96// Test case with an invalid graph containing inconsistent
97// predecessor/successor arcs in CFG.
David Brazdilbadd8262016-02-02 16:28:56 +000098TEST_F(GraphCheckerTest, InconsistentPredecessorsAndSuccessors) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010099 HGraph* graph = CreateSimpleCFG();
Vladimir Marko655e5852015-10-12 10:38:28 +0100100 GraphChecker graph_checker(graph);
Roland Levillain633021e2014-10-01 14:12:25 +0100101 graph_checker.Run();
Roland Levillainccc07a92014-09-16 14:48:16 +0100102 ASSERT_TRUE(graph_checker.IsValid());
103
104 // Remove the entry block from the exit block's predecessors, to create an
105 // inconsistent successor/predecessor relation.
106 graph->GetExitBlock()->RemovePredecessor(graph->GetEntryBlock());
Roland Levillain633021e2014-10-01 14:12:25 +0100107 graph_checker.Run();
Roland Levillainccc07a92014-09-16 14:48:16 +0100108 ASSERT_FALSE(graph_checker.IsValid());
109}
110
111// Test case with an invalid graph containing a non-branch last
112// instruction in a block.
David Brazdilbadd8262016-02-02 16:28:56 +0000113TEST_F(GraphCheckerTest, BlockEndingWithNonBranchInstruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100114 HGraph* graph = CreateSimpleCFG();
Vladimir Marko655e5852015-10-12 10:38:28 +0100115 GraphChecker graph_checker(graph);
Roland Levillain633021e2014-10-01 14:12:25 +0100116 graph_checker.Run();
Roland Levillainccc07a92014-09-16 14:48:16 +0100117 ASSERT_TRUE(graph_checker.IsValid());
118
119 // Remove the sole instruction of the exit block (composed of a
120 // single Exit instruction) to make it invalid (i.e. not ending by a
121 // branch instruction).
122 HBasicBlock* exit_block = graph->GetExitBlock();
123 HInstruction* last_inst = exit_block->GetLastInstruction();
124 exit_block->RemoveInstruction(last_inst);
125
Roland Levillain633021e2014-10-01 14:12:25 +0100126 graph_checker.Run();
Roland Levillainccc07a92014-09-16 14:48:16 +0100127 ASSERT_FALSE(graph_checker.IsValid());
128}
129
David Brazdilbadd8262016-02-02 16:28:56 +0000130TEST_F(GraphCheckerTest, SSAPhi) {
Roland Levillainccc07a92014-09-16 14:48:16 +0100131 // This code creates one Phi function during the conversion to SSA form.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800132 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Roland Levillainccc07a92014-09-16 14:48:16 +0100133 Instruction::CONST_4 | 0 | 0,
134 Instruction::IF_EQ, 3,
135 Instruction::CONST_4 | 4 << 12 | 0,
136 Instruction::RETURN | 0 << 8);
137
David Brazdilbadd8262016-02-02 16:28:56 +0000138 TestCode(data);
Roland Levillainccc07a92014-09-16 14:48:16 +0100139}
140
141} // namespace art