diff options
Diffstat (limited to 'compiler/optimizing/graph_checker_test.cc')
-rw-r--r-- | compiler/optimizing/graph_checker_test.cc | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/compiler/optimizing/graph_checker_test.cc b/compiler/optimizing/graph_checker_test.cc new file mode 100644 index 0000000000..ea0692088d --- /dev/null +++ b/compiler/optimizing/graph_checker_test.cc @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graph_checker.h" +#include "optimizing_unit_test.h" + +#include "gtest/gtest.h" + +namespace art { + +/** + * Create a simple control-flow graph composed of two blocks: + * + * BasicBlock 0, succ: 1 + * 0: Goto 1 + * BasicBlock 1, pred: 0 + * 1: Exit + */ +HGraph* CreateSimpleCFG(ArenaAllocator* allocator) { + HGraph* graph = new (allocator) HGraph(allocator); + HBasicBlock* entry_block = new (allocator) HBasicBlock(graph); + entry_block->AddInstruction(new (allocator) HGoto()); + graph->AddBlock(entry_block); + graph->SetEntryBlock(entry_block); + HBasicBlock* exit_block = new (allocator) HBasicBlock(graph); + exit_block->AddInstruction(new (allocator) HExit()); + graph->AddBlock(exit_block); + graph->SetExitBlock(exit_block); + entry_block->AddSuccessor(exit_block); + return graph; +} + + +static void TestCode(const uint16_t* data) { + ArenaPool pool; + ArenaAllocator allocator(&pool); + HGraph* graph = CreateCFG(&allocator, data); + ASSERT_NE(graph, nullptr); + + GraphChecker graph_checker(&allocator, graph); + graph_checker.VisitInsertionOrder(); + ASSERT_TRUE(graph_checker.IsValid()); +} + +static void TestCodeSSA(const uint16_t* data) { + ArenaPool pool; + ArenaAllocator allocator(&pool); + HGraph* graph = CreateCFG(&allocator, data); + ASSERT_NE(graph, nullptr); + + graph->BuildDominatorTree(); + graph->TransformToSSA(); + + SSAChecker ssa_checker(&allocator, graph); + ssa_checker.VisitInsertionOrder(); + ASSERT_TRUE(ssa_checker.IsValid()); +} + + +TEST(GraphChecker, ReturnVoid) { + const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( + Instruction::RETURN_VOID); + + TestCode(data); +} + +TEST(GraphChecker, CFG1) { + const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( + Instruction::GOTO | 0x100, + Instruction::RETURN_VOID); + + TestCode(data); +} + +TEST(GraphChecker, CFG2) { + const uint16_t data[] = ONE_REGISTER_CODE_ITEM( + Instruction::CONST_4 | 0 | 0, + Instruction::IF_EQ, 3, + Instruction::GOTO | 0x100, + Instruction::RETURN_VOID); + + TestCode(data); +} + +TEST(GraphChecker, CFG3) { + const uint16_t data[] = ONE_REGISTER_CODE_ITEM( + Instruction::CONST_4 | 0 | 0, + Instruction::IF_EQ, 3, + Instruction::GOTO | 0x100, + Instruction::GOTO | 0xFF00); + + TestCode(data); +} + +// Test case with an invalid graph containing inconsistent +// predecessor/successor arcs in CFG. +TEST(GraphChecker, InconsistentPredecessorsAndSuccessors) { + ArenaPool pool; + ArenaAllocator allocator(&pool); + + HGraph* graph = CreateSimpleCFG(&allocator); + GraphChecker graph_checker(&allocator, graph); + graph_checker.VisitInsertionOrder(); + ASSERT_TRUE(graph_checker.IsValid()); + + // Remove the entry block from the exit block's predecessors, to create an + // inconsistent successor/predecessor relation. + graph->GetExitBlock()->RemovePredecessor(graph->GetEntryBlock()); + graph_checker.VisitInsertionOrder(); + ASSERT_FALSE(graph_checker.IsValid()); +} + +// Test case with an invalid graph containing a non-branch last +// instruction in a block. +TEST(GraphChecker, BlockEndingWithNonBranchInstruction) { + ArenaPool pool; + ArenaAllocator allocator(&pool); + + HGraph* graph = CreateSimpleCFG(&allocator); + GraphChecker graph_checker(&allocator, graph); + graph_checker.VisitInsertionOrder(); + ASSERT_TRUE(graph_checker.IsValid()); + + // Remove the sole instruction of the exit block (composed of a + // single Exit instruction) to make it invalid (i.e. not ending by a + // branch instruction). + HBasicBlock* exit_block = graph->GetExitBlock(); + HInstruction* last_inst = exit_block->GetLastInstruction(); + exit_block->RemoveInstruction(last_inst); + + graph_checker.VisitInsertionOrder(); + ASSERT_FALSE(graph_checker.IsValid()); +} + +TEST(SSAChecker, SSAPhi) { + // This code creates one Phi function during the conversion to SSA form. + const uint16_t data[] = ONE_REGISTER_CODE_ITEM( + Instruction::CONST_4 | 0 | 0, + Instruction::IF_EQ, 3, + Instruction::CONST_4 | 4 << 12 | 0, + Instruction::RETURN | 0 << 8); + + TestCodeSSA(data); +} + +} // namespace art |