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