1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "licm.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "base/arena_allocator.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
21*795d594fSAndroid Build Coastguard Worker #include "builder.h"
22*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
23*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
24*795d594fSAndroid Build Coastguard Worker #include "side_effects_analysis.h"
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker /**
29*795d594fSAndroid Build Coastguard Worker * Fixture class for the LICM tests.
30*795d594fSAndroid Build Coastguard Worker */
31*795d594fSAndroid Build Coastguard Worker class LICMTest : public OptimizingUnitTest {
32*795d594fSAndroid Build Coastguard Worker public:
LICMTest()33*795d594fSAndroid Build Coastguard Worker LICMTest()
34*795d594fSAndroid Build Coastguard Worker : loop_preheader_(nullptr),
35*795d594fSAndroid Build Coastguard Worker loop_header_(nullptr),
36*795d594fSAndroid Build Coastguard Worker loop_body_(nullptr),
37*795d594fSAndroid Build Coastguard Worker parameter_(nullptr),
38*795d594fSAndroid Build Coastguard Worker int_constant_(nullptr),
39*795d594fSAndroid Build Coastguard Worker float_constant_(nullptr) {
40*795d594fSAndroid Build Coastguard Worker graph_ = CreateGraph();
41*795d594fSAndroid Build Coastguard Worker }
42*795d594fSAndroid Build Coastguard Worker
~LICMTest()43*795d594fSAndroid Build Coastguard Worker ~LICMTest() { }
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker // Builds a singly-nested loop structure in CFG. Tests can further populate
46*795d594fSAndroid Build Coastguard Worker // the basic blocks with instructions to set up interesting scenarios.
BuildLoop()47*795d594fSAndroid Build Coastguard Worker void BuildLoop() {
48*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
49*795d594fSAndroid Build Coastguard Worker std::tie(loop_preheader_, loop_header_, loop_body_) = CreateWhileLoop(return_block);
50*795d594fSAndroid Build Coastguard Worker loop_header_->SwapSuccessors(); // Move the loop exit to the "else" successor.
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker // Provide boiler-plate instructions.
53*795d594fSAndroid Build Coastguard Worker parameter_ = MakeParam(DataType::Type::kReference);
54*795d594fSAndroid Build Coastguard Worker int_constant_ = graph_->GetIntConstant(42);
55*795d594fSAndroid Build Coastguard Worker float_constant_ = graph_->GetFloatConstant(42.0f);
56*795d594fSAndroid Build Coastguard Worker MakeIf(loop_header_, parameter_);
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker // Performs LICM optimizations (after proper set up).
PerformLICM()60*795d594fSAndroid Build Coastguard Worker void PerformLICM() {
61*795d594fSAndroid Build Coastguard Worker graph_->BuildDominatorTree();
62*795d594fSAndroid Build Coastguard Worker SideEffectsAnalysis side_effects(graph_);
63*795d594fSAndroid Build Coastguard Worker side_effects.Run();
64*795d594fSAndroid Build Coastguard Worker LICM(graph_, side_effects, nullptr).Run();
65*795d594fSAndroid Build Coastguard Worker }
66*795d594fSAndroid Build Coastguard Worker
67*795d594fSAndroid Build Coastguard Worker // Specific basic blocks.
68*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_preheader_;
69*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_header_;
70*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_body_;
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker HInstruction* parameter_; // "this"
73*795d594fSAndroid Build Coastguard Worker HInstruction* int_constant_;
74*795d594fSAndroid Build Coastguard Worker HInstruction* float_constant_;
75*795d594fSAndroid Build Coastguard Worker };
76*795d594fSAndroid Build Coastguard Worker
77*795d594fSAndroid Build Coastguard Worker //
78*795d594fSAndroid Build Coastguard Worker // The actual LICM tests.
79*795d594fSAndroid Build Coastguard Worker //
80*795d594fSAndroid Build Coastguard Worker
TEST_F(LICMTest,FieldHoisting)81*795d594fSAndroid Build Coastguard Worker TEST_F(LICMTest, FieldHoisting) {
82*795d594fSAndroid Build Coastguard Worker BuildLoop();
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker // Populate the loop with instructions: set/get field with different types.
85*795d594fSAndroid Build Coastguard Worker HInstruction* get_field =
86*795d594fSAndroid Build Coastguard Worker MakeIFieldGet(loop_body_, parameter_, DataType::Type::kInt64, MemberOffset(10));
87*795d594fSAndroid Build Coastguard Worker HInstruction* set_field =
88*795d594fSAndroid Build Coastguard Worker MakeIFieldSet(loop_body_, parameter_, int_constant_, DataType::Type::kInt32, MemberOffset(20));
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_field->GetBlock(), loop_body_);
91*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_field->GetBlock(), loop_body_);
92*795d594fSAndroid Build Coastguard Worker PerformLICM();
93*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_field->GetBlock(), loop_preheader_);
94*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_field->GetBlock(), loop_body_);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
TEST_F(LICMTest,NoFieldHoisting)97*795d594fSAndroid Build Coastguard Worker TEST_F(LICMTest, NoFieldHoisting) {
98*795d594fSAndroid Build Coastguard Worker BuildLoop();
99*795d594fSAndroid Build Coastguard Worker
100*795d594fSAndroid Build Coastguard Worker // Populate the loop with instructions: set/get field with same types.
101*795d594fSAndroid Build Coastguard Worker ScopedNullHandle<mirror::DexCache> dex_cache;
102*795d594fSAndroid Build Coastguard Worker HInstruction* get_field =
103*795d594fSAndroid Build Coastguard Worker MakeIFieldGet(loop_body_, parameter_, DataType::Type::kInt64, MemberOffset(10));
104*795d594fSAndroid Build Coastguard Worker HInstruction* set_field = MakeIFieldSet(loop_body_, parameter_, get_field, MemberOffset(10));
105*795d594fSAndroid Build Coastguard Worker
106*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_field->GetBlock(), loop_body_);
107*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_field->GetBlock(), loop_body_);
108*795d594fSAndroid Build Coastguard Worker PerformLICM();
109*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_field->GetBlock(), loop_body_);
110*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_field->GetBlock(), loop_body_);
111*795d594fSAndroid Build Coastguard Worker }
112*795d594fSAndroid Build Coastguard Worker
TEST_F(LICMTest,ArrayHoisting)113*795d594fSAndroid Build Coastguard Worker TEST_F(LICMTest, ArrayHoisting) {
114*795d594fSAndroid Build Coastguard Worker BuildLoop();
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker // Populate the loop with instructions: set/get array with different types.
117*795d594fSAndroid Build Coastguard Worker HInstruction* get_array =
118*795d594fSAndroid Build Coastguard Worker MakeArrayGet(loop_body_, parameter_, int_constant_, DataType::Type::kInt32);
119*795d594fSAndroid Build Coastguard Worker HInstruction* set_array = MakeArraySet(
120*795d594fSAndroid Build Coastguard Worker loop_body_, parameter_, int_constant_, float_constant_, DataType::Type::kFloat32);
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_array->GetBlock(), loop_body_);
123*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_array->GetBlock(), loop_body_);
124*795d594fSAndroid Build Coastguard Worker PerformLICM();
125*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_array->GetBlock(), loop_preheader_);
126*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_array->GetBlock(), loop_body_);
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker
TEST_F(LICMTest,NoArrayHoisting)129*795d594fSAndroid Build Coastguard Worker TEST_F(LICMTest, NoArrayHoisting) {
130*795d594fSAndroid Build Coastguard Worker BuildLoop();
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker // Populate the loop with instructions: set/get array with same types.
133*795d594fSAndroid Build Coastguard Worker HInstruction* get_array =
134*795d594fSAndroid Build Coastguard Worker MakeArrayGet(loop_body_, parameter_, int_constant_, DataType::Type::kFloat32);
135*795d594fSAndroid Build Coastguard Worker HInstruction* set_array =
136*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body_, parameter_, get_array, float_constant_, DataType::Type::kFloat32);
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_array->GetBlock(), loop_body_);
139*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_array->GetBlock(), loop_body_);
140*795d594fSAndroid Build Coastguard Worker PerformLICM();
141*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(get_array->GetBlock(), loop_body_);
142*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(set_array->GetBlock(), loop_body_);
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker
145*795d594fSAndroid Build Coastguard Worker } // namespace art
146