Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 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 "licm.h"
     20 #include "nodes.h"
     21 #include "optimizing_unit_test.h"
     22 #include "side_effects_analysis.h"
     23 
     24 namespace art {
     25 
     26 /**
     27  * Fixture class for the LICM tests.
     28  */
     29 class LICMTest : public CommonCompilerTest {
     30  public:
     31   LICMTest()
     32       : pool_(),
     33         allocator_(&pool_),
     34         entry_(nullptr),
     35         loop_preheader_(nullptr),
     36         loop_header_(nullptr),
     37         loop_body_(nullptr),
     38         return_(nullptr),
     39         exit_(nullptr),
     40         parameter_(nullptr),
     41         int_constant_(nullptr),
     42         float_constant_(nullptr) {
     43     graph_ = CreateGraph(&allocator_);
     44   }
     45 
     46   ~LICMTest() { }
     47 
     48   // Builds a singly-nested loop structure in CFG. Tests can further populate
     49   // the basic blocks with instructions to set up interesting scenarios.
     50   void BuildLoop() {
     51     entry_ = new (&allocator_) HBasicBlock(graph_);
     52     loop_preheader_ = new (&allocator_) HBasicBlock(graph_);
     53     loop_header_ = new (&allocator_) HBasicBlock(graph_);
     54     loop_body_ = new (&allocator_) HBasicBlock(graph_);
     55     return_ = new (&allocator_) HBasicBlock(graph_);
     56     exit_ = new (&allocator_) HBasicBlock(graph_);
     57 
     58     graph_->AddBlock(entry_);
     59     graph_->AddBlock(loop_preheader_);
     60     graph_->AddBlock(loop_header_);
     61     graph_->AddBlock(loop_body_);
     62     graph_->AddBlock(return_);
     63     graph_->AddBlock(exit_);
     64 
     65     graph_->SetEntryBlock(entry_);
     66     graph_->SetExitBlock(exit_);
     67 
     68     // Set up loop flow in CFG.
     69     entry_->AddSuccessor(loop_preheader_);
     70     loop_preheader_->AddSuccessor(loop_header_);
     71     loop_header_->AddSuccessor(loop_body_);
     72     loop_header_->AddSuccessor(return_);
     73     loop_body_->AddSuccessor(loop_header_);
     74     return_->AddSuccessor(exit_);
     75 
     76     // Provide boiler-plate instructions.
     77     parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
     78                                                    dex::TypeIndex(0),
     79                                                    0,
     80                                                    Primitive::kPrimNot);
     81     entry_->AddInstruction(parameter_);
     82     int_constant_ = graph_->GetIntConstant(42);
     83     float_constant_ = graph_->GetFloatConstant(42.0f);
     84     loop_preheader_->AddInstruction(new (&allocator_) HGoto());
     85     loop_header_->AddInstruction(new (&allocator_) HIf(parameter_));
     86     loop_body_->AddInstruction(new (&allocator_) HGoto());
     87     return_->AddInstruction(new (&allocator_) HReturnVoid());
     88     exit_->AddInstruction(new (&allocator_) HExit());
     89   }
     90 
     91   // Performs LICM optimizations (after proper set up).
     92   void PerformLICM() {
     93     graph_->BuildDominatorTree();
     94     SideEffectsAnalysis side_effects(graph_);
     95     side_effects.Run();
     96     LICM(graph_, side_effects, nullptr).Run();
     97   }
     98 
     99   // General building fields.
    100   ArenaPool pool_;
    101   ArenaAllocator allocator_;
    102   HGraph* graph_;
    103 
    104   // Specific basic blocks.
    105   HBasicBlock* entry_;
    106   HBasicBlock* loop_preheader_;
    107   HBasicBlock* loop_header_;
    108   HBasicBlock* loop_body_;
    109   HBasicBlock* return_;
    110   HBasicBlock* exit_;
    111 
    112   HInstruction* parameter_;  // "this"
    113   HInstruction* int_constant_;
    114   HInstruction* float_constant_;
    115 };
    116 
    117 //
    118 // The actual LICM tests.
    119 //
    120 
    121 TEST_F(LICMTest, FieldHoisting) {
    122   BuildLoop();
    123 
    124   // Populate the loop with instructions: set/get field with different types.
    125   HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
    126                                                                 nullptr,
    127                                                                 Primitive::kPrimLong,
    128                                                                 MemberOffset(10),
    129                                                                 false,
    130                                                                 kUnknownFieldIndex,
    131                                                                 kUnknownClassDefIndex,
    132                                                                 graph_->GetDexFile(),
    133                                                                 0);
    134   loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
    135   HInstruction* set_field = new (&allocator_) HInstanceFieldSet(
    136       parameter_, int_constant_, nullptr, Primitive::kPrimInt, MemberOffset(20),
    137       false, kUnknownFieldIndex, kUnknownClassDefIndex, graph_->GetDexFile(), 0);
    138   loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
    139 
    140   EXPECT_EQ(get_field->GetBlock(), loop_body_);
    141   EXPECT_EQ(set_field->GetBlock(), loop_body_);
    142   PerformLICM();
    143   EXPECT_EQ(get_field->GetBlock(), loop_preheader_);
    144   EXPECT_EQ(set_field->GetBlock(), loop_body_);
    145 }
    146 
    147 TEST_F(LICMTest, NoFieldHoisting) {
    148   BuildLoop();
    149 
    150   // Populate the loop with instructions: set/get field with same types.
    151   ScopedNullHandle<mirror::DexCache> dex_cache;
    152   HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
    153                                                                 nullptr,
    154                                                                 Primitive::kPrimLong,
    155                                                                 MemberOffset(10),
    156                                                                 false,
    157                                                                 kUnknownFieldIndex,
    158                                                                 kUnknownClassDefIndex,
    159                                                                 graph_->GetDexFile(),
    160                                                                 0);
    161   loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
    162   HInstruction* set_field = new (&allocator_) HInstanceFieldSet(parameter_,
    163                                                                 get_field,
    164                                                                 nullptr,
    165                                                                 Primitive::kPrimLong,
    166                                                                 MemberOffset(10),
    167                                                                 false,
    168                                                                 kUnknownFieldIndex,
    169                                                                 kUnknownClassDefIndex,
    170                                                                 graph_->GetDexFile(),
    171                                                                 0);
    172   loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
    173 
    174   EXPECT_EQ(get_field->GetBlock(), loop_body_);
    175   EXPECT_EQ(set_field->GetBlock(), loop_body_);
    176   PerformLICM();
    177   EXPECT_EQ(get_field->GetBlock(), loop_body_);
    178   EXPECT_EQ(set_field->GetBlock(), loop_body_);
    179 }
    180 
    181 TEST_F(LICMTest, ArrayHoisting) {
    182   BuildLoop();
    183 
    184   // Populate the loop with instructions: set/get array with different types.
    185   HInstruction* get_array = new (&allocator_) HArrayGet(
    186       parameter_, int_constant_, Primitive::kPrimInt, 0);
    187   loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
    188   HInstruction* set_array = new (&allocator_) HArraySet(
    189       parameter_, int_constant_, float_constant_, Primitive::kPrimFloat, 0);
    190   loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
    191 
    192   EXPECT_EQ(get_array->GetBlock(), loop_body_);
    193   EXPECT_EQ(set_array->GetBlock(), loop_body_);
    194   PerformLICM();
    195   EXPECT_EQ(get_array->GetBlock(), loop_preheader_);
    196   EXPECT_EQ(set_array->GetBlock(), loop_body_);
    197 }
    198 
    199 TEST_F(LICMTest, NoArrayHoisting) {
    200   BuildLoop();
    201 
    202   // Populate the loop with instructions: set/get array with same types.
    203   HInstruction* get_array = new (&allocator_) HArrayGet(
    204       parameter_, int_constant_, Primitive::kPrimFloat, 0);
    205   loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
    206   HInstruction* set_array = new (&allocator_) HArraySet(
    207       parameter_, get_array, float_constant_, Primitive::kPrimFloat, 0);
    208   loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
    209 
    210   EXPECT_EQ(get_array->GetBlock(), loop_body_);
    211   EXPECT_EQ(set_array->GetBlock(), loop_body_);
    212   PerformLICM();
    213   EXPECT_EQ(get_array->GetBlock(), loop_body_);
    214   EXPECT_EQ(set_array->GetBlock(), loop_body_);
    215 }
    216 
    217 }  // namespace art
    218