xref: /aosp_15_r20/art/compiler/optimizing/licm_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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 "base/macros.h"
21 #include "builder.h"
22 #include "nodes.h"
23 #include "optimizing_unit_test.h"
24 #include "side_effects_analysis.h"
25 
26 namespace art HIDDEN {
27 
28 /**
29  * Fixture class for the LICM tests.
30  */
31 class LICMTest : public OptimizingUnitTest {
32  public:
LICMTest()33   LICMTest()
34       : loop_preheader_(nullptr),
35         loop_header_(nullptr),
36         loop_body_(nullptr),
37         parameter_(nullptr),
38         int_constant_(nullptr),
39         float_constant_(nullptr) {
40     graph_ = CreateGraph();
41   }
42 
~LICMTest()43   ~LICMTest() { }
44 
45   // Builds a singly-nested loop structure in CFG. Tests can further populate
46   // the basic blocks with instructions to set up interesting scenarios.
BuildLoop()47   void BuildLoop() {
48     HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
49     std::tie(loop_preheader_, loop_header_, loop_body_) = CreateWhileLoop(return_block);
50     loop_header_->SwapSuccessors();  // Move the loop exit to the "else" successor.
51 
52     // Provide boiler-plate instructions.
53     parameter_ = MakeParam(DataType::Type::kReference);
54     int_constant_ = graph_->GetIntConstant(42);
55     float_constant_ = graph_->GetFloatConstant(42.0f);
56     MakeIf(loop_header_, parameter_);
57   }
58 
59   // Performs LICM optimizations (after proper set up).
PerformLICM()60   void PerformLICM() {
61     graph_->BuildDominatorTree();
62     SideEffectsAnalysis side_effects(graph_);
63     side_effects.Run();
64     LICM(graph_, side_effects, nullptr).Run();
65   }
66 
67   // Specific basic blocks.
68   HBasicBlock* loop_preheader_;
69   HBasicBlock* loop_header_;
70   HBasicBlock* loop_body_;
71 
72   HInstruction* parameter_;  // "this"
73   HInstruction* int_constant_;
74   HInstruction* float_constant_;
75 };
76 
77 //
78 // The actual LICM tests.
79 //
80 
TEST_F(LICMTest,FieldHoisting)81 TEST_F(LICMTest, FieldHoisting) {
82   BuildLoop();
83 
84   // Populate the loop with instructions: set/get field with different types.
85   HInstruction* get_field =
86       MakeIFieldGet(loop_body_, parameter_, DataType::Type::kInt64, MemberOffset(10));
87   HInstruction* set_field =
88      MakeIFieldSet(loop_body_, parameter_, int_constant_, DataType::Type::kInt32, MemberOffset(20));
89 
90   EXPECT_EQ(get_field->GetBlock(), loop_body_);
91   EXPECT_EQ(set_field->GetBlock(), loop_body_);
92   PerformLICM();
93   EXPECT_EQ(get_field->GetBlock(), loop_preheader_);
94   EXPECT_EQ(set_field->GetBlock(), loop_body_);
95 }
96 
TEST_F(LICMTest,NoFieldHoisting)97 TEST_F(LICMTest, NoFieldHoisting) {
98   BuildLoop();
99 
100   // Populate the loop with instructions: set/get field with same types.
101   ScopedNullHandle<mirror::DexCache> dex_cache;
102   HInstruction* get_field =
103       MakeIFieldGet(loop_body_, parameter_, DataType::Type::kInt64, MemberOffset(10));
104   HInstruction* set_field = MakeIFieldSet(loop_body_, parameter_, get_field, MemberOffset(10));
105 
106   EXPECT_EQ(get_field->GetBlock(), loop_body_);
107   EXPECT_EQ(set_field->GetBlock(), loop_body_);
108   PerformLICM();
109   EXPECT_EQ(get_field->GetBlock(), loop_body_);
110   EXPECT_EQ(set_field->GetBlock(), loop_body_);
111 }
112 
TEST_F(LICMTest,ArrayHoisting)113 TEST_F(LICMTest, ArrayHoisting) {
114   BuildLoop();
115 
116   // Populate the loop with instructions: set/get array with different types.
117   HInstruction* get_array =
118       MakeArrayGet(loop_body_, parameter_, int_constant_, DataType::Type::kInt32);
119   HInstruction* set_array = MakeArraySet(
120       loop_body_, parameter_, int_constant_, float_constant_, DataType::Type::kFloat32);
121 
122   EXPECT_EQ(get_array->GetBlock(), loop_body_);
123   EXPECT_EQ(set_array->GetBlock(), loop_body_);
124   PerformLICM();
125   EXPECT_EQ(get_array->GetBlock(), loop_preheader_);
126   EXPECT_EQ(set_array->GetBlock(), loop_body_);
127 }
128 
TEST_F(LICMTest,NoArrayHoisting)129 TEST_F(LICMTest, NoArrayHoisting) {
130   BuildLoop();
131 
132   // Populate the loop with instructions: set/get array with same types.
133   HInstruction* get_array =
134       MakeArrayGet(loop_body_, parameter_, int_constant_, DataType::Type::kFloat32);
135   HInstruction* set_array =
136       MakeArraySet(loop_body_, parameter_, get_array, float_constant_, DataType::Type::kFloat32);
137 
138   EXPECT_EQ(get_array->GetBlock(), loop_body_);
139   EXPECT_EQ(set_array->GetBlock(), loop_body_);
140   PerformLICM();
141   EXPECT_EQ(get_array->GetBlock(), loop_body_);
142   EXPECT_EQ(set_array->GetBlock(), loop_body_);
143 }
144 
145 }  // namespace art
146