/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "licm.h" #include "base/arena_allocator.h" #include "base/macros.h" #include "builder.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "side_effects_analysis.h" namespace art HIDDEN { /** * Fixture class for the LICM tests. */ class LICMTest : public OptimizingUnitTest { public: LICMTest() : loop_preheader_(nullptr), loop_header_(nullptr), loop_body_(nullptr), parameter_(nullptr), int_constant_(nullptr), float_constant_(nullptr) { graph_ = CreateGraph(); } ~LICMTest() { } // Builds a singly-nested loop structure in CFG. Tests can further populate // the basic blocks with instructions to set up interesting scenarios. void BuildLoop() { HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid(); std::tie(loop_preheader_, loop_header_, loop_body_) = CreateWhileLoop(return_block); loop_header_->SwapSuccessors(); // Move the loop exit to the "else" successor. // Provide boiler-plate instructions. parameter_ = MakeParam(DataType::Type::kReference); int_constant_ = graph_->GetIntConstant(42); float_constant_ = graph_->GetFloatConstant(42.0f); MakeIf(loop_header_, parameter_); } // Performs LICM optimizations (after proper set up). void PerformLICM() { graph_->BuildDominatorTree(); SideEffectsAnalysis side_effects(graph_); side_effects.Run(); LICM(graph_, side_effects, nullptr).Run(); } // Specific basic blocks. HBasicBlock* loop_preheader_; HBasicBlock* loop_header_; HBasicBlock* loop_body_; HInstruction* parameter_; // "this" HInstruction* int_constant_; HInstruction* float_constant_; }; // // The actual LICM tests. // TEST_F(LICMTest, FieldHoisting) { BuildLoop(); // Populate the loop with instructions: set/get field with different types. HInstruction* get_field = MakeIFieldGet(loop_body_, parameter_, DataType::Type::kInt64, MemberOffset(10)); HInstruction* set_field = MakeIFieldSet(loop_body_, parameter_, int_constant_, DataType::Type::kInt32, MemberOffset(20)); EXPECT_EQ(get_field->GetBlock(), loop_body_); EXPECT_EQ(set_field->GetBlock(), loop_body_); PerformLICM(); EXPECT_EQ(get_field->GetBlock(), loop_preheader_); EXPECT_EQ(set_field->GetBlock(), loop_body_); } TEST_F(LICMTest, NoFieldHoisting) { BuildLoop(); // Populate the loop with instructions: set/get field with same types. ScopedNullHandle dex_cache; HInstruction* get_field = MakeIFieldGet(loop_body_, parameter_, DataType::Type::kInt64, MemberOffset(10)); HInstruction* set_field = MakeIFieldSet(loop_body_, parameter_, get_field, MemberOffset(10)); EXPECT_EQ(get_field->GetBlock(), loop_body_); EXPECT_EQ(set_field->GetBlock(), loop_body_); PerformLICM(); EXPECT_EQ(get_field->GetBlock(), loop_body_); EXPECT_EQ(set_field->GetBlock(), loop_body_); } TEST_F(LICMTest, ArrayHoisting) { BuildLoop(); // Populate the loop with instructions: set/get array with different types. HInstruction* get_array = MakeArrayGet(loop_body_, parameter_, int_constant_, DataType::Type::kInt32); HInstruction* set_array = MakeArraySet( loop_body_, parameter_, int_constant_, float_constant_, DataType::Type::kFloat32); EXPECT_EQ(get_array->GetBlock(), loop_body_); EXPECT_EQ(set_array->GetBlock(), loop_body_); PerformLICM(); EXPECT_EQ(get_array->GetBlock(), loop_preheader_); EXPECT_EQ(set_array->GetBlock(), loop_body_); } TEST_F(LICMTest, NoArrayHoisting) { BuildLoop(); // Populate the loop with instructions: set/get array with same types. HInstruction* get_array = MakeArrayGet(loop_body_, parameter_, int_constant_, DataType::Type::kFloat32); HInstruction* set_array = MakeArraySet(loop_body_, parameter_, get_array, float_constant_, DataType::Type::kFloat32); EXPECT_EQ(get_array->GetBlock(), loop_body_); EXPECT_EQ(set_array->GetBlock(), loop_body_); PerformLICM(); EXPECT_EQ(get_array->GetBlock(), loop_body_); EXPECT_EQ(set_array->GetBlock(), loop_body_); } } // namespace art