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/arena_allocator.h"
     18 #include "builder.h"
     19 #include "nodes.h"
     20 #include "optimizing_unit_test.h"
     21 #include "pretty_printer.h"
     22 
     23 #include "gtest/gtest.h"
     24 
     25 namespace art {
     26 
     27 static HBasicBlock* createIfBlock(HGraph* graph, ArenaAllocator* allocator) {
     28   HBasicBlock* if_block = new (allocator) HBasicBlock(graph);
     29   graph->AddBlock(if_block);
     30   HInstruction* instr = graph->GetIntConstant(4);
     31   HInstruction* equal = new (allocator) HEqual(instr, instr);
     32   if_block->AddInstruction(equal);
     33   instr = new (allocator) HIf(equal);
     34   if_block->AddInstruction(instr);
     35   return if_block;
     36 }
     37 
     38 static HBasicBlock* createGotoBlock(HGraph* graph, ArenaAllocator* allocator) {
     39   HBasicBlock* block = new (allocator) HBasicBlock(graph);
     40   graph->AddBlock(block);
     41   HInstruction* got = new (allocator) HGoto();
     42   block->AddInstruction(got);
     43   return block;
     44 }
     45 
     46 static HBasicBlock* createEntryBlock(HGraph* graph, ArenaAllocator* allocator) {
     47   HBasicBlock* block = createGotoBlock(graph, allocator);
     48   graph->SetEntryBlock(block);
     49   return block;
     50 }
     51 
     52 static HBasicBlock* createReturnBlock(HGraph* graph, ArenaAllocator* allocator) {
     53   HBasicBlock* block = new (allocator) HBasicBlock(graph);
     54   graph->AddBlock(block);
     55   HInstruction* return_instr = new (allocator) HReturnVoid();
     56   block->AddInstruction(return_instr);
     57   return block;
     58 }
     59 
     60 static HBasicBlock* createExitBlock(HGraph* graph, ArenaAllocator* allocator) {
     61   HBasicBlock* block = new (allocator) HBasicBlock(graph);
     62   graph->AddBlock(block);
     63   HInstruction* exit_instr = new (allocator) HExit();
     64   block->AddInstruction(exit_instr);
     65   return block;
     66 }
     67 
     68 
     69 // Test that the successors of an if block stay consistent after a SimplifyCFG.
     70 // This test sets the false block to be the return block.
     71 TEST(GraphTest, IfSuccessorSimpleJoinBlock1) {
     72   ArenaPool pool;
     73   ArenaAllocator allocator(&pool);
     74 
     75   HGraph* graph = CreateGraph(&allocator);
     76   HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
     77   HBasicBlock* if_block = createIfBlock(graph, &allocator);
     78   HBasicBlock* if_true = createGotoBlock(graph, &allocator);
     79   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
     80   HBasicBlock* exit_block = createExitBlock(graph, &allocator);
     81 
     82   entry_block->AddSuccessor(if_block);
     83   if_block->AddSuccessor(if_true);
     84   if_true->AddSuccessor(return_block);
     85   if_block->AddSuccessor(return_block);
     86   return_block->AddSuccessor(exit_block);
     87 
     88   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_true);
     89   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
     90 
     91   graph->SimplifyCFG();
     92 
     93   // Ensure we still have the same if true block.
     94   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_true);
     95 
     96   // Ensure the critical edge has been removed.
     97   HBasicBlock* false_block = if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor();
     98   ASSERT_NE(false_block, return_block);
     99 
    100   // Ensure the new block branches to the join block.
    101   ASSERT_EQ(false_block->GetSuccessors()[0], return_block);
    102 }
    103 
    104 // Test that the successors of an if block stay consistent after a SimplifyCFG.
    105 // This test sets the true block to be the return block.
    106 TEST(GraphTest, IfSuccessorSimpleJoinBlock2) {
    107   ArenaPool pool;
    108   ArenaAllocator allocator(&pool);
    109 
    110   HGraph* graph = CreateGraph(&allocator);
    111   HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
    112   HBasicBlock* if_block = createIfBlock(graph, &allocator);
    113   HBasicBlock* if_false = createGotoBlock(graph, &allocator);
    114   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
    115   HBasicBlock* exit_block = createExitBlock(graph, &allocator);
    116 
    117   entry_block->AddSuccessor(if_block);
    118   if_block->AddSuccessor(return_block);
    119   if_false->AddSuccessor(return_block);
    120   if_block->AddSuccessor(if_false);
    121   return_block->AddSuccessor(exit_block);
    122 
    123   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
    124   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_false);
    125 
    126   graph->SimplifyCFG();
    127 
    128   // Ensure we still have the same if true block.
    129   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_false);
    130 
    131   // Ensure the critical edge has been removed.
    132   HBasicBlock* true_block = if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor();
    133   ASSERT_NE(true_block, return_block);
    134 
    135   // Ensure the new block branches to the join block.
    136   ASSERT_EQ(true_block->GetSuccessors()[0], return_block);
    137 }
    138 
    139 // Test that the successors of an if block stay consistent after a SimplifyCFG.
    140 // This test sets the true block to be the loop header.
    141 TEST(GraphTest, IfSuccessorMultipleBackEdges1) {
    142   ArenaPool pool;
    143   ArenaAllocator allocator(&pool);
    144 
    145   HGraph* graph = CreateGraph(&allocator);
    146   HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
    147   HBasicBlock* if_block = createIfBlock(graph, &allocator);
    148   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
    149   HBasicBlock* exit_block = createExitBlock(graph, &allocator);
    150 
    151   entry_block->AddSuccessor(if_block);
    152   if_block->AddSuccessor(if_block);
    153   if_block->AddSuccessor(return_block);
    154   return_block->AddSuccessor(exit_block);
    155 
    156   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), if_block);
    157   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
    158 
    159   graph->BuildDominatorTree();
    160 
    161   // Ensure we still have the same if false block.
    162   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
    163 
    164   // Ensure there is only one back edge.
    165   ASSERT_EQ(if_block->GetPredecessors().size(), 2u);
    166   ASSERT_EQ(if_block->GetPredecessors()[0], entry_block->GetSingleSuccessor());
    167   ASSERT_NE(if_block->GetPredecessors()[1], if_block);
    168 
    169   // Ensure the new block is the back edge.
    170   ASSERT_EQ(if_block->GetPredecessors()[1],
    171             if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor());
    172 }
    173 
    174 // Test that the successors of an if block stay consistent after a SimplifyCFG.
    175 // This test sets the false block to be the loop header.
    176 TEST(GraphTest, IfSuccessorMultipleBackEdges2) {
    177   ArenaPool pool;
    178   ArenaAllocator allocator(&pool);
    179 
    180   HGraph* graph = CreateGraph(&allocator);
    181   HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
    182   HBasicBlock* if_block = createIfBlock(graph, &allocator);
    183   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
    184   HBasicBlock* exit_block = createExitBlock(graph, &allocator);
    185 
    186   entry_block->AddSuccessor(if_block);
    187   if_block->AddSuccessor(return_block);
    188   if_block->AddSuccessor(if_block);
    189   return_block->AddSuccessor(exit_block);
    190 
    191   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
    192   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), if_block);
    193 
    194   graph->BuildDominatorTree();
    195 
    196   // Ensure we still have the same if true block.
    197   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), return_block);
    198 
    199   // Ensure there is only one back edge.
    200   ASSERT_EQ(if_block->GetPredecessors().size(), 2u);
    201   ASSERT_EQ(if_block->GetPredecessors()[0], entry_block->GetSingleSuccessor());
    202   ASSERT_NE(if_block->GetPredecessors()[1], if_block);
    203 
    204   // Ensure the new block is the back edge.
    205   ASSERT_EQ(if_block->GetPredecessors()[1],
    206             if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor());
    207 }
    208 
    209 // Test that the successors of an if block stay consistent after a SimplifyCFG.
    210 // This test sets the true block to be a loop header with multiple pre headers.
    211 TEST(GraphTest, IfSuccessorMultiplePreHeaders1) {
    212   ArenaPool pool;
    213   ArenaAllocator allocator(&pool);
    214 
    215   HGraph* graph = CreateGraph(&allocator);
    216   HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
    217   HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
    218   HBasicBlock* if_block = createIfBlock(graph, &allocator);
    219   HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
    220   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
    221 
    222   entry_block->AddSuccessor(first_if_block);
    223   first_if_block->AddSuccessor(if_block);
    224   first_if_block->AddSuccessor(loop_block);
    225   loop_block->AddSuccessor(loop_block);
    226   if_block->AddSuccessor(loop_block);
    227   if_block->AddSuccessor(return_block);
    228 
    229 
    230   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfTrueSuccessor(), loop_block);
    231   ASSERT_EQ(if_block->GetLastInstruction()->AsIf()->IfFalseSuccessor(), return_block);
    232 
    233   graph->BuildDominatorTree();
    234 
    235   HIf* if_instr = if_block->GetLastInstruction()->AsIf();
    236   // Ensure we still have the same if false block.
    237   ASSERT_EQ(if_instr->IfFalseSuccessor(), return_block);
    238 
    239   // Ensure there is only one pre header..
    240   ASSERT_EQ(loop_block->GetPredecessors().size(), 2u);
    241 
    242   // Ensure the new block is the successor of the true block.
    243   ASSERT_EQ(if_instr->IfTrueSuccessor()->GetSuccessors().size(), 1u);
    244   ASSERT_EQ(if_instr->IfTrueSuccessor()->GetSuccessors()[0],
    245             loop_block->GetLoopInformation()->GetPreHeader());
    246 }
    247 
    248 // Test that the successors of an if block stay consistent after a SimplifyCFG.
    249 // This test sets the false block to be a loop header with multiple pre headers.
    250 TEST(GraphTest, IfSuccessorMultiplePreHeaders2) {
    251   ArenaPool pool;
    252   ArenaAllocator allocator(&pool);
    253 
    254   HGraph* graph = CreateGraph(&allocator);
    255   HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
    256   HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
    257   HBasicBlock* if_block = createIfBlock(graph, &allocator);
    258   HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
    259   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
    260 
    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()[0],
    283             loop_block->GetLoopInformation()->GetPreHeader());
    284 }
    285 
    286 TEST(GraphTest, InsertInstructionBefore) {
    287   ArenaPool pool;
    288   ArenaAllocator allocator(&pool);
    289 
    290   HGraph* graph = CreateGraph(&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