xref: /aosp_15_r20/art/compiler/optimizing/licm_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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