blob: 7d93809be63aea68520b2d7489ff739d09b19647 [file] [log] [blame]
Alex Light74328052021-03-29 18:11:23 -07001/*
2 * Copyright (C) 2021 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 "instruction_simplifier.h"
18
19#include <initializer_list>
20#include <tuple>
21
22#include "gtest/gtest.h"
23#include "nodes.h"
24#include "optimizing/data_type.h"
25#include "optimizing_unit_test.h"
26
27namespace art {
28
29class InstructionSimplifierTest : public CommonCompilerTest, public OptimizingUnitTestHelper {
30 public:
31 void SetUp() override {
32 CommonCompilerTest::SetUp();
33 gLogVerbosity.compiler = true;
34 }
35
36 void TearDown() override {
37 CommonCompilerTest::TearDown();
38 gLogVerbosity.compiler = false;
39 }
40};
41
42// // ENTRY
43// switch (param) {
44// case 1:
45// obj1 = param2; break;
46// case 2:
47// obj1 = param3; break;
48// default:
49// obj2 = new Obj();
50// }
51// val_phi = PHI[3,4,10]
52// target_phi = PHI[param2, param3, obj2]
53// return PredFieldGet[val_phi, target_phi] => PredFieldGet[val_phi, target_phi]
54TEST_F(InstructionSimplifierTest, SimplifyPredicatedFieldGetNoMerge) {
55 VariableSizedHandleScope vshs(Thread::Current());
56 CreateGraph(&vshs);
57 AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
58 "exit",
59 {{"entry", "case1"},
60 {"entry", "case2"},
61 {"entry", "case3"},
62 {"case1", "breturn"},
63 {"case2", "breturn"},
64 {"case3", "breturn"},
65 {"breturn", "exit"}}));
66#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
67 GET_BLOCK(entry);
68 GET_BLOCK(exit);
69 GET_BLOCK(case1);
70 GET_BLOCK(case2);
71 GET_BLOCK(case3);
72 GET_BLOCK(breturn);
73#undef GET_BLOCK
74
75 HInstruction* bool_value = MakeParam(DataType::Type::kInt32);
76 HInstruction* obj1_param = MakeParam(DataType::Type::kReference);
77 HInstruction* obj2_param = MakeParam(DataType::Type::kReference);
78 HInstruction* c3 = graph_->GetIntConstant(3);
79 HInstruction* c4 = graph_->GetIntConstant(4);
80 HInstruction* c10 = graph_->GetIntConstant(10);
81
82 HInstruction* cls = MakeClassLoad();
83 HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, bool_value);
84 entry->AddInstruction(cls);
85 entry->AddInstruction(switch_inst);
86 ManuallyBuildEnvFor(cls, {});
87
88 HInstruction* goto_c1 = new (GetAllocator()) HGoto();
89 case1->AddInstruction(goto_c1);
90
91 HInstruction* goto_c2 = new (GetAllocator()) HGoto();
92 case2->AddInstruction(goto_c2);
93
94 HInstruction* obj3 = MakeNewInstance(cls);
95 HInstruction* goto_c3 = new (GetAllocator()) HGoto();
96 case3->AddInstruction(obj3);
97 case3->AddInstruction(goto_c3);
98
99 HPhi* val_phi = MakePhi({c3, c4, c10});
100 HPhi* obj_phi = MakePhi({obj1_param, obj2_param, obj3});
101 HPredicatedInstanceFieldGet* read_end =
102 new (GetAllocator()) HPredicatedInstanceFieldGet(obj_phi,
103 nullptr,
104 val_phi,
105 val_phi->GetType(),
106 MemberOffset(10),
107 false,
108 42,
109 0,
110 graph_->GetDexFile(),
111 0);
112 HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
113 breturn->AddPhi(val_phi);
114 breturn->AddPhi(obj_phi);
115 breturn->AddInstruction(read_end);
116 breturn->AddInstruction(return_exit);
117
118 SetupExit(exit);
119
120 LOG(INFO) << "Pre simplification " << blks;
121 graph_->ClearDominanceInformation();
122 graph_->BuildDominatorTree();
123 InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
124 simp.Run();
125
126 LOG(INFO) << "Post simplify " << blks;
127
128 EXPECT_INS_RETAINED(read_end);
129
130 EXPECT_INS_EQ(read_end->GetTarget(), obj_phi);
131 EXPECT_INS_EQ(read_end->GetDefaultValue(), val_phi);
132}
133
134// // ENTRY
135// switch (param) {
136// case 1:
137// obj1 = param2; break;
138// case 2:
139// obj1 = param3; break;
140// default:
141// obj2 = new Obj();
142// }
143// val_phi = PHI[3,3,10]
144// target_phi = PHI[param2, param3, obj2]
145// return PredFieldGet[val_phi, target_phi] => PredFieldGet[3, target_phi]
146TEST_F(InstructionSimplifierTest, SimplifyPredicatedFieldGetMerge) {
147 VariableSizedHandleScope vshs(Thread::Current());
148 CreateGraph(&vshs);
149 AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
150 "exit",
151 {{"entry", "case1"},
152 {"entry", "case2"},
153 {"entry", "case3"},
154 {"case1", "breturn"},
155 {"case2", "breturn"},
156 {"case3", "breturn"},
157 {"breturn", "exit"}}));
158#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
159 GET_BLOCK(entry);
160 GET_BLOCK(exit);
161 GET_BLOCK(case1);
162 GET_BLOCK(case2);
163 GET_BLOCK(case3);
164 GET_BLOCK(breturn);
165#undef GET_BLOCK
166
167 HInstruction* bool_value = MakeParam(DataType::Type::kInt32);
168 HInstruction* obj1_param = MakeParam(DataType::Type::kReference);
169 HInstruction* obj2_param = MakeParam(DataType::Type::kReference);
170 HInstruction* c3 = graph_->GetIntConstant(3);
171 HInstruction* c10 = graph_->GetIntConstant(10);
172
173 HInstruction* cls = MakeClassLoad();
174 HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, bool_value);
175 entry->AddInstruction(cls);
176 entry->AddInstruction(switch_inst);
177 ManuallyBuildEnvFor(cls, {});
178
179 HInstruction* goto_c1 = new (GetAllocator()) HGoto();
180 case1->AddInstruction(goto_c1);
181
182 HInstruction* goto_c2 = new (GetAllocator()) HGoto();
183 case2->AddInstruction(goto_c2);
184
185 HInstruction* obj3 = MakeNewInstance(cls);
186 HInstruction* goto_c3 = new (GetAllocator()) HGoto();
187 case3->AddInstruction(obj3);
188 case3->AddInstruction(goto_c3);
189
190 HPhi* val_phi = MakePhi({c3, c3, c10});
191 HPhi* obj_phi = MakePhi({obj1_param, obj2_param, obj3});
192 HPredicatedInstanceFieldGet* read_end =
193 new (GetAllocator()) HPredicatedInstanceFieldGet(obj_phi,
194 nullptr,
195 val_phi,
196 val_phi->GetType(),
197 MemberOffset(10),
198 false,
199 42,
200 0,
201 graph_->GetDexFile(),
202 0);
203 HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
204 breturn->AddPhi(val_phi);
205 breturn->AddPhi(obj_phi);
206 breturn->AddInstruction(read_end);
207 breturn->AddInstruction(return_exit);
208
209 SetupExit(exit);
210
211 LOG(INFO) << "Pre simplification " << blks;
212 graph_->ClearDominanceInformation();
213 graph_->BuildDominatorTree();
214 InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
215 simp.Run();
216
217 LOG(INFO) << "Post simplify " << blks;
218
219 EXPECT_FALSE(obj3->CanBeNull());
220 EXPECT_INS_RETAINED(read_end);
221
222 EXPECT_INS_EQ(read_end->GetTarget(), obj_phi);
223 EXPECT_INS_EQ(read_end->GetDefaultValue(), c3);
224}
225
226// // ENTRY
227// if (param) {
228// obj1 = new Obj();
229// } else {
230// obj2 = new Obj();
231// }
232// val_phi = PHI[3,10]
233// target_phi = PHI[obj1, obj2]
234// return PredFieldGet[val_phi, target_phi] => FieldGet[target_phi]
235TEST_F(InstructionSimplifierTest, SimplifyPredicatedFieldGetNoNull) {
236 VariableSizedHandleScope vshs(Thread::Current());
237 CreateGraph(&vshs);
238 AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
239 "exit",
240 {{"entry", "left"},
241 {"entry", "right"},
242 {"left", "breturn"},
243 {"right", "breturn"},
244 {"breturn", "exit"}}));
245#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
246 GET_BLOCK(entry);
247 GET_BLOCK(exit);
248 GET_BLOCK(left);
249 GET_BLOCK(right);
250 GET_BLOCK(breturn);
251#undef GET_BLOCK
252
253 HInstruction* bool_value = MakeParam(DataType::Type::kBool);
254 HInstruction* c3 = graph_->GetIntConstant(3);
255 HInstruction* c10 = graph_->GetIntConstant(10);
256
257 HInstruction* cls = MakeClassLoad();
258 HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
259 entry->AddInstruction(cls);
260 entry->AddInstruction(if_inst);
261 ManuallyBuildEnvFor(cls, {});
262
263 HInstruction* obj1 = MakeNewInstance(cls);
264 HInstruction* goto_left = new (GetAllocator()) HGoto();
265 left->AddInstruction(obj1);
266 left->AddInstruction(goto_left);
267
268 HInstruction* obj2 = MakeNewInstance(cls);
269 HInstruction* goto_right = new (GetAllocator()) HGoto();
270 right->AddInstruction(obj2);
271 right->AddInstruction(goto_right);
272
273 HPhi* val_phi = MakePhi({c3, c10});
274 HPhi* obj_phi = MakePhi({obj1, obj2});
275 HInstruction* read_end = new (GetAllocator()) HPredicatedInstanceFieldGet(obj_phi,
276 nullptr,
277 val_phi,
278 val_phi->GetType(),
279 MemberOffset(10),
280 false,
281 42,
282 0,
283 graph_->GetDexFile(),
284 0);
285 HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
286 breturn->AddPhi(val_phi);
287 breturn->AddPhi(obj_phi);
288 breturn->AddInstruction(read_end);
289 breturn->AddInstruction(return_exit);
290
291 SetupExit(exit);
292
293 LOG(INFO) << "Pre simplification " << blks;
294 graph_->ClearDominanceInformation();
295 graph_->BuildDominatorTree();
296 InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
297 simp.Run();
298
299 LOG(INFO) << "Post simplify " << blks;
300
301 EXPECT_FALSE(obj1->CanBeNull());
302 EXPECT_FALSE(obj2->CanBeNull());
303 EXPECT_INS_REMOVED(read_end);
304
305 HInstanceFieldGet* ifget = FindSingleInstruction<HInstanceFieldGet>(graph_, breturn);
306 ASSERT_NE(ifget, nullptr);
307 EXPECT_INS_EQ(ifget->InputAt(0), obj_phi);
308}
309
310} // namespace art