Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2016 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 "loop_optimization.h"
     18 #include "optimizing_unit_test.h"
     19 
     20 namespace art {
     21 
     22 /**
     23  * Fixture class for the loop optimization tests. These unit tests focus
     24  * constructing the loop hierarchy. Actual optimizations are tested
     25  * through the checker tests.
     26  */
     27 class LoopOptimizationTest : public OptimizingUnitTest {
     28  public:
     29   LoopOptimizationTest()
     30       : graph_(CreateGraph()),
     31         iva_(new (GetAllocator()) HInductionVarAnalysis(graph_)),
     32         loop_opt_(new (GetAllocator()) HLoopOptimization(
     33             graph_, /* compiler_options= */ nullptr, iva_, /* stats= */ nullptr)) {
     34     BuildGraph();
     35   }
     36 
     37   ~LoopOptimizationTest() { }
     38 
     39   /** Constructs bare minimum graph. */
     40   void BuildGraph() {
     41     graph_->SetNumberOfVRegs(1);
     42     entry_block_ = new (GetAllocator()) HBasicBlock(graph_);
     43     return_block_ = new (GetAllocator()) HBasicBlock(graph_);
     44     exit_block_ = new (GetAllocator()) HBasicBlock(graph_);
     45     graph_->AddBlock(entry_block_);
     46     graph_->AddBlock(return_block_);
     47     graph_->AddBlock(exit_block_);
     48     graph_->SetEntryBlock(entry_block_);
     49     graph_->SetExitBlock(exit_block_);
     50     parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
     51                                                       dex::TypeIndex(0),
     52                                                       0,
     53                                                       DataType::Type::kInt32);
     54     entry_block_->AddInstruction(parameter_);
     55     return_block_->AddInstruction(new (GetAllocator()) HReturnVoid());
     56     exit_block_->AddInstruction(new (GetAllocator()) HExit());
     57     entry_block_->AddSuccessor(return_block_);
     58     return_block_->AddSuccessor(exit_block_);
     59   }
     60 
     61   /** Adds a loop nest at given position before successor. */
     62   HBasicBlock* AddLoop(HBasicBlock* position, HBasicBlock* successor) {
     63     HBasicBlock* header = new (GetAllocator()) HBasicBlock(graph_);
     64     HBasicBlock* body = new (GetAllocator()) HBasicBlock(graph_);
     65     graph_->AddBlock(header);
     66     graph_->AddBlock(body);
     67     // Control flow.
     68     position->ReplaceSuccessor(successor, header);
     69     header->AddSuccessor(body);
     70     header->AddSuccessor(successor);
     71     header->AddInstruction(new (GetAllocator()) HIf(parameter_));
     72     body->AddSuccessor(header);
     73     body->AddInstruction(new (GetAllocator()) HGoto());
     74     return header;
     75   }
     76 
     77   /** Performs analysis. */
     78   void PerformAnalysis() {
     79     graph_->BuildDominatorTree();
     80     iva_->Run();
     81     // Do not release the loop hierarchy.
     82     ScopedArenaAllocator loop_allocator(GetArenaStack());
     83     loop_opt_->loop_allocator_ = &loop_allocator;
     84     loop_opt_->LocalRun();
     85   }
     86 
     87   /** Constructs string representation of computed loop hierarchy. */
     88   std::string LoopStructure() {
     89     return LoopStructureRecurse(loop_opt_->top_loop_);
     90   }
     91 
     92   // Helper method
     93   std::string LoopStructureRecurse(HLoopOptimization::LoopNode* node) {
     94     std::string s;
     95     for ( ; node != nullptr; node = node->next) {
     96       s.append("[");
     97       s.append(LoopStructureRecurse(node->inner));
     98       s.append("]");
     99     }
    100     return s;
    101   }
    102 
    103   // General building fields.
    104   HGraph* graph_;
    105   HInductionVarAnalysis* iva_;
    106   HLoopOptimization* loop_opt_;
    107 
    108   HBasicBlock* entry_block_;
    109   HBasicBlock* return_block_;
    110   HBasicBlock* exit_block_;
    111 
    112   HInstruction* parameter_;
    113 };
    114 
    115 //
    116 // The actual tests.
    117 //
    118 
    119 TEST_F(LoopOptimizationTest, NoLoops) {
    120   PerformAnalysis();
    121   EXPECT_EQ("", LoopStructure());
    122 }
    123 
    124 TEST_F(LoopOptimizationTest, SingleLoop) {
    125   AddLoop(entry_block_, return_block_);
    126   PerformAnalysis();
    127   EXPECT_EQ("[]", LoopStructure());
    128 }
    129 
    130 TEST_F(LoopOptimizationTest, LoopNest10) {
    131   HBasicBlock* b = entry_block_;
    132   HBasicBlock* s = return_block_;
    133   for (int i = 0; i < 10; i++) {
    134     s = AddLoop(b, s);
    135     b = s->GetSuccessors()[0];
    136   }
    137   PerformAnalysis();
    138   EXPECT_EQ("[[[[[[[[[[]]]]]]]]]]", LoopStructure());
    139 }
    140 
    141 TEST_F(LoopOptimizationTest, LoopSequence10) {
    142   HBasicBlock* b = entry_block_;
    143   HBasicBlock* s = return_block_;
    144   for (int i = 0; i < 10; i++) {
    145     b = AddLoop(b, s);
    146     s = b->GetSuccessors()[1];
    147   }
    148   PerformAnalysis();
    149   EXPECT_EQ("[][][][][][][][][][]", LoopStructure());
    150 }
    151 
    152 TEST_F(LoopOptimizationTest, LoopSequenceOfNests) {
    153   HBasicBlock* b = entry_block_;
    154   HBasicBlock* s = return_block_;
    155   for (int i = 0; i < 10; i++) {
    156     b = AddLoop(b, s);
    157     s = b->GetSuccessors()[1];
    158     HBasicBlock* bi = b->GetSuccessors()[0];
    159     HBasicBlock* si = b;
    160     for (int j = 0; j < i; j++) {
    161       si = AddLoop(bi, si);
    162       bi = si->GetSuccessors()[0];
    163     }
    164   }
    165   PerformAnalysis();
    166   EXPECT_EQ("[]"
    167             "[[]]"
    168             "[[[]]]"
    169             "[[[[]]]]"
    170             "[[[[[]]]]]"
    171             "[[[[[[]]]]]]"
    172             "[[[[[[[]]]]]]]"
    173             "[[[[[[[[]]]]]]]]"
    174             "[[[[[[[[[]]]]]]]]]"
    175             "[[[[[[[[[[]]]]]]]]]]",
    176             LoopStructure());
    177 }
    178 
    179 TEST_F(LoopOptimizationTest, LoopNestWithSequence) {
    180   HBasicBlock* b = entry_block_;
    181   HBasicBlock* s = return_block_;
    182   for (int i = 0; i < 10; i++) {
    183     s = AddLoop(b, s);
    184     b = s->GetSuccessors()[0];
    185   }
    186   b = s;
    187   s = b->GetSuccessors()[1];
    188   for (int i = 0; i < 9; i++) {
    189     b = AddLoop(b, s);
    190     s = b->GetSuccessors()[1];
    191   }
    192   PerformAnalysis();
    193   EXPECT_EQ("[[[[[[[[[[][][][][][][][][][]]]]]]]]]]", LoopStructure());
    194 }
    195 
    196 // Check that SimplifyLoop() doesn't invalidate data flow when ordering loop headers'
    197 // predecessors.
    198 //
    199 // This is a test for nodes.cc functionality - HGraph::SimplifyLoop.
    200 TEST_F(LoopOptimizationTest, SimplifyLoopReoderPredecessors) {
    201   // Can't use AddLoop as we want special order for blocks predecessors.
    202   HBasicBlock* header = new (GetAllocator()) HBasicBlock(graph_);
    203   HBasicBlock* body = new (GetAllocator()) HBasicBlock(graph_);
    204   graph_->AddBlock(header);
    205   graph_->AddBlock(body);
    206 
    207   // Control flow: make a loop back edge first in the list of predecessors.
    208   entry_block_->RemoveSuccessor(return_block_);
    209   body->AddSuccessor(header);
    210   entry_block_->AddSuccessor(header);
    211   header->AddSuccessor(body);
    212   header->AddSuccessor(return_block_);
    213   DCHECK(header->GetSuccessors()[1] == return_block_);
    214 
    215   // Data flow.
    216   header->AddInstruction(new (GetAllocator()) HIf(parameter_));
    217   body->AddInstruction(new (GetAllocator()) HGoto());
    218 
    219   HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
    220   HInstruction* add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi, parameter_);
    221   header->AddPhi(phi);
    222   body->AddInstruction(add);
    223 
    224   phi->AddInput(add);
    225   phi->AddInput(parameter_);
    226 
    227   graph_->ClearLoopInformation();
    228   graph_->ClearDominanceInformation();
    229   graph_->BuildDominatorTree();
    230 
    231   // BuildDominatorTree inserts a block beetween loop header and entry block.
    232   EXPECT_EQ(header->GetPredecessors()[0]->GetSinglePredecessor(), entry_block_);
    233 
    234   // Check that after optimizations in BuildDominatorTree()/SimplifyCFG() phi inputs
    235   // are still mapped correctly to the block predecessors.
    236   for (size_t i = 0, e = phi->InputCount(); i < e; i++) {
    237     HInstruction* input = phi->InputAt(i);
    238     EXPECT_TRUE(input->GetBlock()->Dominates(header->GetPredecessors()[i]));
    239   }
    240 }
    241 
    242 // Test that SimplifyLoop() processes the multiple-preheaders loops correctly.
    243 //
    244 // This is a test for nodes.cc functionality - HGraph::SimplifyLoop.
    245 TEST_F(LoopOptimizationTest, SimplifyLoopSinglePreheader) {
    246   HBasicBlock* header = AddLoop(entry_block_, return_block_);
    247 
    248   header->InsertInstructionBefore(
    249       new (GetAllocator()) HSuspendCheck(), header->GetLastInstruction());
    250 
    251   // Insert an if construct before the loop so it will have two preheaders.
    252   HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph_);
    253   HBasicBlock* preheader0 = new (GetAllocator()) HBasicBlock(graph_);
    254   HBasicBlock* preheader1 = new (GetAllocator()) HBasicBlock(graph_);
    255 
    256   graph_->AddBlock(if_block);
    257   graph_->AddBlock(preheader0);
    258   graph_->AddBlock(preheader1);
    259 
    260   // Fix successors/predecessors.
    261   entry_block_->ReplaceSuccessor(header, if_block);
    262   if_block->AddSuccessor(preheader0);
    263   if_block->AddSuccessor(preheader1);
    264   preheader0->AddSuccessor(header);
    265   preheader1->AddSuccessor(header);
    266 
    267   if_block->AddInstruction(new (GetAllocator()) HIf(parameter_));
    268   preheader0->AddInstruction(new (GetAllocator()) HGoto());
    269   preheader1->AddInstruction(new (GetAllocator()) HGoto());
    270 
    271   HBasicBlock* body = header->GetSuccessors()[0];
    272   DCHECK(body != return_block_);
    273 
    274   // Add some data flow.
    275   HIntConstant* const_0 = graph_->GetIntConstant(0);
    276   HIntConstant* const_1 = graph_->GetIntConstant(1);
    277   HIntConstant* const_2 = graph_->GetIntConstant(2);
    278 
    279   HAdd* preheader0_add = new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter_, const_0);
    280   preheader0->AddInstruction(preheader0_add);
    281   HAdd* preheader1_add = new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter_, const_1);
    282   preheader1->AddInstruction(preheader1_add);
    283 
    284   HPhi* header_phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
    285   header->AddPhi(header_phi);
    286 
    287   HAdd* body_add = new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter_, const_2);
    288   body->AddInstruction(body_add);
    289 
    290   DCHECK(header->GetPredecessors()[0] == body);
    291   DCHECK(header->GetPredecessors()[1] == preheader0);
    292   DCHECK(header->GetPredecessors()[2] == preheader1);
    293 
    294   header_phi->AddInput(body_add);
    295   header_phi->AddInput(preheader0_add);
    296   header_phi->AddInput(preheader1_add);
    297 
    298   graph_->ClearLoopInformation();
    299   graph_->ClearDominanceInformation();
    300   graph_->BuildDominatorTree();
    301 
    302   EXPECT_EQ(header->GetPredecessors().size(), 2u);
    303   EXPECT_EQ(header->GetPredecessors()[1], body);
    304 
    305   HBasicBlock* new_preheader = header->GetLoopInformation()->GetPreHeader();
    306   EXPECT_EQ(preheader0->GetSingleSuccessor(), new_preheader);
    307   EXPECT_EQ(preheader1->GetSingleSuccessor(), new_preheader);
    308 
    309   EXPECT_EQ(new_preheader->GetPhis().CountSize(), 1u);
    310   HPhi* new_preheader_phi = new_preheader->GetFirstPhi()->AsPhi();
    311   EXPECT_EQ(new_preheader_phi->InputCount(), 2u);
    312   EXPECT_EQ(new_preheader_phi->InputAt(0), preheader0_add);
    313   EXPECT_EQ(new_preheader_phi->InputAt(1), preheader1_add);
    314 
    315   EXPECT_EQ(header_phi->InputCount(), 2u);
    316   EXPECT_EQ(header_phi->InputAt(0), new_preheader_phi);
    317   EXPECT_EQ(header_phi->InputAt(1), body_add);
    318 }
    319 
    320 }  // namespace art
    321