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