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