blob: 0617e60cfe43463c0425e9eeb022a22e48aa2b97 [file] [log] [blame]
Aart Bik3f307f32015-07-21 18:30:18 -07001/*
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
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070017#include "licm.h"
18
Aart Bik3f307f32015-07-21 18:30:18 -070019#include "base/arena_allocator.h"
20#include "builder.h"
Aart Bik3f307f32015-07-21 18:30:18 -070021#include "nodes.h"
22#include "optimizing_unit_test.h"
23#include "side_effects_analysis.h"
24
25namespace art {
26
27/**
28 * Fixture class for the LICM tests.
29 */
David Brazdil4833f5a2015-12-16 10:37:39 +000030class LICMTest : public CommonCompilerTest {
Aart Bik3f307f32015-07-21 18:30:18 -070031 public:
Andreas Gamped9911ee2017-03-27 13:27:24 -070032 LICMTest()
33 : pool_(),
34 allocator_(&pool_),
35 entry_(nullptr),
36 loop_preheader_(nullptr),
37 loop_header_(nullptr),
38 loop_body_(nullptr),
39 return_(nullptr),
40 exit_(nullptr),
41 parameter_(nullptr),
42 int_constant_(nullptr),
43 float_constant_(nullptr) {
Aart Bik3f307f32015-07-21 18:30:18 -070044 graph_ = CreateGraph(&allocator_);
45 }
46
47 ~LICMTest() { }
48
49 // Builds a singly-nested loop structure in CFG. Tests can further populate
50 // the basic blocks with instructions to set up interesting scenarios.
51 void BuildLoop() {
52 entry_ = new (&allocator_) HBasicBlock(graph_);
53 loop_preheader_ = new (&allocator_) HBasicBlock(graph_);
54 loop_header_ = new (&allocator_) HBasicBlock(graph_);
55 loop_body_ = new (&allocator_) HBasicBlock(graph_);
David Brazdildb51efb2015-11-06 01:36:20 +000056 return_ = new (&allocator_) HBasicBlock(graph_);
Aart Bik3f307f32015-07-21 18:30:18 -070057 exit_ = new (&allocator_) HBasicBlock(graph_);
58
59 graph_->AddBlock(entry_);
60 graph_->AddBlock(loop_preheader_);
61 graph_->AddBlock(loop_header_);
62 graph_->AddBlock(loop_body_);
David Brazdildb51efb2015-11-06 01:36:20 +000063 graph_->AddBlock(return_);
Aart Bik3f307f32015-07-21 18:30:18 -070064 graph_->AddBlock(exit_);
65
66 graph_->SetEntryBlock(entry_);
67 graph_->SetExitBlock(exit_);
68
69 // Set up loop flow in CFG.
70 entry_->AddSuccessor(loop_preheader_);
71 loop_preheader_->AddSuccessor(loop_header_);
72 loop_header_->AddSuccessor(loop_body_);
David Brazdildb51efb2015-11-06 01:36:20 +000073 loop_header_->AddSuccessor(return_);
Aart Bik3f307f32015-07-21 18:30:18 -070074 loop_body_->AddSuccessor(loop_header_);
David Brazdildb51efb2015-11-06 01:36:20 +000075 return_->AddSuccessor(exit_);
Aart Bik3f307f32015-07-21 18:30:18 -070076
77 // Provide boiler-plate instructions.
Andreas Gampea5b09a62016-11-17 15:21:22 -080078 parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
79 dex::TypeIndex(0),
80 0,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010081 DataType::Type::kReference);
Aart Bik3f307f32015-07-21 18:30:18 -070082 entry_->AddInstruction(parameter_);
David Brazdil15693bf2015-12-16 10:30:45 +000083 int_constant_ = graph_->GetIntConstant(42);
84 float_constant_ = graph_->GetFloatConstant(42.0f);
David Brazdil77a48ae2015-09-15 12:34:04 +000085 loop_preheader_->AddInstruction(new (&allocator_) HGoto());
Aart Bik3f307f32015-07-21 18:30:18 -070086 loop_header_->AddInstruction(new (&allocator_) HIf(parameter_));
87 loop_body_->AddInstruction(new (&allocator_) HGoto());
David Brazdil4833f5a2015-12-16 10:37:39 +000088 return_->AddInstruction(new (&allocator_) HReturnVoid());
Aart Bik3f307f32015-07-21 18:30:18 -070089 exit_->AddInstruction(new (&allocator_) HExit());
90 }
91
92 // Performs LICM optimizations (after proper set up).
93 void PerformLICM() {
David Brazdilbadd8262016-02-02 16:28:56 +000094 graph_->BuildDominatorTree();
Aart Bik3f307f32015-07-21 18:30:18 -070095 SideEffectsAnalysis side_effects(graph_);
96 side_effects.Run();
Jean-Philippe Halimi38e9e802016-02-18 16:42:03 +010097 LICM(graph_, side_effects, nullptr).Run();
Aart Bik3f307f32015-07-21 18:30:18 -070098 }
99
100 // General building fields.
101 ArenaPool pool_;
102 ArenaAllocator allocator_;
103 HGraph* graph_;
104
105 // Specific basic blocks.
106 HBasicBlock* entry_;
107 HBasicBlock* loop_preheader_;
108 HBasicBlock* loop_header_;
109 HBasicBlock* loop_body_;
David Brazdildb51efb2015-11-06 01:36:20 +0000110 HBasicBlock* return_;
Aart Bik3f307f32015-07-21 18:30:18 -0700111 HBasicBlock* exit_;
112
113 HInstruction* parameter_; // "this"
David Brazdil15693bf2015-12-16 10:30:45 +0000114 HInstruction* int_constant_;
115 HInstruction* float_constant_;
Aart Bik3f307f32015-07-21 18:30:18 -0700116};
117
118//
119// The actual LICM tests.
120//
121
Aart Bik3f307f32015-07-21 18:30:18 -0700122TEST_F(LICMTest, FieldHoisting) {
123 BuildLoop();
124
125 // Populate the loop with instructions: set/get field with different types.
Mingyao Yang8df69d42015-10-22 15:40:58 -0700126 HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000127 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100128 DataType::Type::kInt64,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700129 MemberOffset(10),
130 false,
131 kUnknownFieldIndex,
132 kUnknownClassDefIndex,
133 graph_->GetDexFile(),
Mingyao Yang8df69d42015-10-22 15:40:58 -0700134 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700135 loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
136 HInstruction* set_field = new (&allocator_) HInstanceFieldSet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100137 parameter_, int_constant_, nullptr, DataType::Type::kInt32, MemberOffset(20),
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000138 false, kUnknownFieldIndex, kUnknownClassDefIndex, graph_->GetDexFile(), 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700139 loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
140
Aart Bik8f08f9e2015-07-22 11:27:39 -0700141 EXPECT_EQ(get_field->GetBlock(), loop_body_);
142 EXPECT_EQ(set_field->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700143 PerformLICM();
Aart Bik8f08f9e2015-07-22 11:27:39 -0700144 EXPECT_EQ(get_field->GetBlock(), loop_preheader_);
145 EXPECT_EQ(set_field->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700146}
147
148TEST_F(LICMTest, NoFieldHoisting) {
149 BuildLoop();
150
151 // Populate the loop with instructions: set/get field with same types.
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800152 ScopedNullHandle<mirror::DexCache> dex_cache;
Mingyao Yang8df69d42015-10-22 15:40:58 -0700153 HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000154 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100155 DataType::Type::kInt64,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700156 MemberOffset(10),
157 false,
158 kUnknownFieldIndex,
159 kUnknownClassDefIndex,
160 graph_->GetDexFile(),
Mingyao Yang8df69d42015-10-22 15:40:58 -0700161 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700162 loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
Mingyao Yang8df69d42015-10-22 15:40:58 -0700163 HInstruction* set_field = new (&allocator_) HInstanceFieldSet(parameter_,
164 get_field,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000165 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100166 DataType::Type::kInt64,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700167 MemberOffset(10),
168 false,
169 kUnknownFieldIndex,
170 kUnknownClassDefIndex,
171 graph_->GetDexFile(),
Mingyao Yang8df69d42015-10-22 15:40:58 -0700172 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700173 loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
174
Aart Bik8f08f9e2015-07-22 11:27:39 -0700175 EXPECT_EQ(get_field->GetBlock(), loop_body_);
176 EXPECT_EQ(set_field->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700177 PerformLICM();
Aart Bik8f08f9e2015-07-22 11:27:39 -0700178 EXPECT_EQ(get_field->GetBlock(), loop_body_);
179 EXPECT_EQ(set_field->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700180}
181
182TEST_F(LICMTest, ArrayHoisting) {
183 BuildLoop();
184
185 // Populate the loop with instructions: set/get array with different types.
186 HInstruction* get_array = new (&allocator_) HArrayGet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100187 parameter_, int_constant_, DataType::Type::kInt32, 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700188 loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
189 HInstruction* set_array = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100190 parameter_, int_constant_, float_constant_, DataType::Type::kFloat32, 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700191 loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
192
Aart Bik8f08f9e2015-07-22 11:27:39 -0700193 EXPECT_EQ(get_array->GetBlock(), loop_body_);
194 EXPECT_EQ(set_array->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700195 PerformLICM();
Aart Bik8f08f9e2015-07-22 11:27:39 -0700196 EXPECT_EQ(get_array->GetBlock(), loop_preheader_);
197 EXPECT_EQ(set_array->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700198}
199
200TEST_F(LICMTest, NoArrayHoisting) {
201 BuildLoop();
202
203 // Populate the loop with instructions: set/get array with same types.
204 HInstruction* get_array = new (&allocator_) HArrayGet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100205 parameter_, int_constant_, DataType::Type::kFloat32, 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700206 loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
207 HInstruction* set_array = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100208 parameter_, get_array, float_constant_, DataType::Type::kFloat32, 0);
Aart Bik3f307f32015-07-21 18:30:18 -0700209 loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
210
Aart Bik8f08f9e2015-07-22 11:27:39 -0700211 EXPECT_EQ(get_array->GetBlock(), loop_body_);
212 EXPECT_EQ(set_array->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700213 PerformLICM();
Aart Bik8f08f9e2015-07-22 11:27:39 -0700214 EXPECT_EQ(get_array->GetBlock(), loop_body_);
215 EXPECT_EQ(set_array->GetBlock(), loop_body_);
Aart Bik3f307f32015-07-21 18:30:18 -0700216}
217
218} // namespace art