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