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  |