blob: 4599612db6c35adc065a5d90308dceabfba80cd4 [file] [log] [blame]
Vladimir Markof59f18b2014-02-17 15:53:57 +00001/*
2 * Copyright (C) 2014 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 <vector>
18
19#include "local_value_numbering.h"
20#include "compiler_internals.h"
21#include "gtest/gtest.h"
22
23namespace art {
24
25class LocalValueNumberingTest : public testing::Test {
26 protected:
27 struct IFieldDef {
28 uint16_t field_idx;
29 uintptr_t declaring_dex_file;
30 uint16_t declaring_field_idx;
31 bool is_volatile;
32 };
33
34 struct SFieldDef {
35 uint16_t field_idx;
36 uintptr_t declaring_dex_file;
37 uint16_t declaring_field_idx;
38 bool is_volatile;
39 };
40
41 struct MIRDef {
42 static constexpr size_t kMaxSsaDefs = 2;
43 static constexpr size_t kMaxSsaUses = 3;
44
45 Instruction::Code opcode;
46 int64_t value;
Vladimir Markobe0e5462014-02-26 11:24:15 +000047 uint32_t field_info;
Vladimir Markof59f18b2014-02-17 15:53:57 +000048 size_t num_uses;
49 int32_t uses[kMaxSsaUses];
50 size_t num_defs;
51 int32_t defs[kMaxSsaDefs];
52 };
53
54#define DEF_CONST(opcode, reg, value) \
55 { opcode, value, 0u, 0, { }, 1, { reg } }
56#define DEF_CONST_WIDE(opcode, reg, value) \
57 { opcode, value, 0u, 0, { }, 2, { reg, reg + 1 } }
Vladimir Markobe0e5462014-02-26 11:24:15 +000058#define DEF_IGET(opcode, reg, obj, field_info) \
59 { opcode, 0u, field_info, 1, { obj }, 1, { reg } }
60#define DEF_IGET_WIDE(opcode, reg, obj, field_info) \
61 { opcode, 0u, field_info, 1, { obj }, 2, { reg, reg + 1 } }
62#define DEF_IPUT(opcode, reg, obj, field_info) \
63 { opcode, 0u, field_info, 2, { reg, obj }, 0, { } }
64#define DEF_IPUT_WIDE(opcode, reg, obj, field_info) \
65 { opcode, 0u, field_info, 3, { reg, reg + 1, obj }, 0, { } }
66#define DEF_SGET(opcode, reg, field_info) \
67 { opcode, 0u, field_info, 0, { }, 1, { reg } }
68#define DEF_SGET_WIDE(opcode, reg, field_info) \
69 { opcode, 0u, field_info, 0, { }, 2, { reg, reg + 1 } }
70#define DEF_SPUT(opcode, reg, field_info) \
71 { opcode, 0u, field_info, 1, { reg }, 0, { } }
72#define DEF_SPUT_WIDE(opcode, reg, field_info) \
73 { opcode, 0u, field_info, 2, { reg, reg + 1 }, 0, { } }
Vladimir Markof59f18b2014-02-17 15:53:57 +000074#define DEF_INVOKE1(opcode, reg) \
75 { opcode, 0u, 0u, 1, { reg }, 0, { } }
76#define DEF_UNIQUE_REF(opcode, reg) \
77 { opcode, 0u, 0u, 0, { }, 1, { reg } } // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
78
79 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
Vladimir Markobe0e5462014-02-26 11:24:15 +000080 cu_.mir_graph->ifield_lowering_infos_.Reset();
81 cu_.mir_graph->ifield_lowering_infos_.Resize(count);
82 for (size_t i = 0u; i != count; ++i) {
83 const IFieldDef* def = &defs[i];
84 MirIFieldLoweringInfo field_info(def->field_idx);
85 if (def->declaring_dex_file != 0u) {
86 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
87 field_info.declaring_field_idx_ = def->declaring_field_idx;
88 field_info.flags_ = 0u | // Without kFlagIsStatic.
89 (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u);
90 }
91 cu_.mir_graph->ifield_lowering_infos_.Insert(field_info);
92 }
Vladimir Markof59f18b2014-02-17 15:53:57 +000093 }
94
95 template <size_t count>
96 void PrepareIFields(const IFieldDef (&defs)[count]) {
97 DoPrepareIFields(defs, count);
98 }
99
100 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
Vladimir Markobe0e5462014-02-26 11:24:15 +0000101 cu_.mir_graph->sfield_lowering_infos_.Reset();
102 cu_.mir_graph->sfield_lowering_infos_.Resize(count);
103 for (size_t i = 0u; i != count; ++i) {
104 const SFieldDef* def = &defs[i];
105 MirSFieldLoweringInfo field_info(def->field_idx);
106 if (def->declaring_dex_file != 0u) {
107 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
108 field_info.declaring_field_idx_ = def->declaring_field_idx;
109 field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic |
110 (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u);
111 }
112 cu_.mir_graph->sfield_lowering_infos_.Insert(field_info);
113 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000114 }
115
116 template <size_t count>
117 void PrepareSFields(const SFieldDef (&defs)[count]) {
118 DoPrepareSFields(defs, count);
119 }
120
121 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
122 mir_count_ = count;
123 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, ArenaAllocator::kAllocMIR));
124 ssa_reps_.resize(count);
125 for (size_t i = 0u; i != count; ++i) {
126 const MIRDef* def = &defs[i];
127 MIR* mir = &mirs_[i];
128 mir->dalvikInsn.opcode = def->opcode;
129 mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
130 mir->dalvikInsn.vB_wide = def->value;
Vladimir Markobe0e5462014-02-26 11:24:15 +0000131 if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
132 ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.Size());
133 mir->meta.ifield_lowering_info = def->field_info;
134 } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
135 ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.Size());
136 mir->meta.sfield_lowering_info = def->field_info;
137 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000138 mir->ssa_rep = &ssa_reps_[i];
139 mir->ssa_rep->num_uses = def->num_uses;
140 mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN.
141 mir->ssa_rep->fp_use = nullptr; // Not used by LVN.
142 mir->ssa_rep->num_defs = def->num_defs;
143 mir->ssa_rep->defs = const_cast<int32_t*>(def->defs); // Not modified by LVN.
144 mir->ssa_rep->fp_def = nullptr; // Not used by LVN.
145 mir->dalvikInsn.opcode = def->opcode;
146 mir->offset = i; // LVN uses offset only for debug output
147 mir->width = 1u; // Not used by LVN.
148 mir->optimization_flags = 0u;
149
150 if (i != 0u) {
151 mirs_[i - 1u].next = mir;
152 }
153 }
154 mirs_[count - 1u].next = nullptr;
155 }
156
157 template <size_t count>
158 void PrepareMIRs(const MIRDef (&defs)[count]) {
159 DoPrepareMIRs(defs, count);
160 }
161
162 void PerformLVN() {
163 value_names_.resize(mir_count_);
164 for (size_t i = 0; i != mir_count_; ++i) {
165 value_names_[i] = lvn_.GetValueNumber(&mirs_[i]);
166 }
167 }
168
169 LocalValueNumberingTest() : pool_(), cu_(&pool_), mir_count_(0u), mirs_(nullptr), lvn_(&cu_) {
170 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
171 }
172
173 ArenaPool pool_;
174 CompilationUnit cu_;
175 size_t mir_count_;
176 MIR* mirs_;
177 std::vector<SSARepresentation> ssa_reps_;
178 std::vector<uint16_t> value_names_;
179 LocalValueNumbering lvn_;
180};
181
182TEST_F(LocalValueNumberingTest, TestIGetIGetInvokeIGet) {
183 static const IFieldDef ifields[] = {
184 { 1u, 1u, 1u, false }
185 };
186 static const MIRDef mirs[] = {
187 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
188 DEF_IGET(Instruction::IGET, 1u, 10u, 0u),
189 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u),
190 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
191 };
192
193 PrepareIFields(ifields);
194 PrepareMIRs(mirs);
195 PerformLVN();
196 ASSERT_EQ(value_names_.size(), 4u);
197 EXPECT_EQ(value_names_[0], value_names_[1]);
198 EXPECT_NE(value_names_[0], value_names_[3]);
199 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
200 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
201 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
202 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
203}
204
205TEST_F(LocalValueNumberingTest, TestIGetIPutIGetIGetIGet) {
206 static const IFieldDef ifields[] = {
207 { 1u, 1u, 1u, false },
208 { 2u, 1u, 2u, false },
209 };
210 static const MIRDef mirs[] = {
211 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
212 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // May alias.
213 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
214 DEF_IGET(Instruction::IGET, 3u, 0u, 1u),
215 DEF_IGET(Instruction::IGET, 4u, 2u, 1u),
216 };
217
218 PrepareIFields(ifields);
219 PrepareMIRs(mirs);
220 PerformLVN();
221 ASSERT_EQ(value_names_.size(), 5u);
222 EXPECT_NE(value_names_[0], value_names_[2]);
223 EXPECT_NE(value_names_[3], value_names_[4]);
224 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
225 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
226 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
227 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
228 EXPECT_EQ(mirs_[4].optimization_flags, 0u);
229}
230
231TEST_F(LocalValueNumberingTest, TestUniquePreserve1) {
232 static const IFieldDef ifields[] = {
233 { 1u, 1u, 1u, false },
234 };
235 static const MIRDef mirs[] = {
236 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
237 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
238 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 10u is unique.
239 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
240 };
241
242 PrepareIFields(ifields);
243 PrepareMIRs(mirs);
244 PerformLVN();
245 ASSERT_EQ(value_names_.size(), 4u);
246 EXPECT_EQ(value_names_[1], value_names_[3]);
247 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
248 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
249 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
250}
251
252TEST_F(LocalValueNumberingTest, TestUniquePreserve2) {
253 static const IFieldDef ifields[] = {
254 { 1u, 1u, 1u, false },
255 };
256 static const MIRDef mirs[] = {
257 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u),
258 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
259 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 11u is unique.
260 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
261 };
262
263 PrepareIFields(ifields);
264 PrepareMIRs(mirs);
265 PerformLVN();
266 ASSERT_EQ(value_names_.size(), 4u);
267 EXPECT_EQ(value_names_[1], value_names_[3]);
268 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
269 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
270 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
271}
272
273TEST_F(LocalValueNumberingTest, TestUniquePreserveAndEscape) {
274 static const IFieldDef ifields[] = {
275 { 1u, 1u, 1u, false },
276 };
277 static const MIRDef mirs[] = {
278 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
279 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
280 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), // 10u still unique.
281 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
282 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 10u), // 10u not unique anymore.
283 DEF_IGET(Instruction::IGET, 3u, 10u, 0u),
284 };
285
286 PrepareIFields(ifields);
287 PrepareMIRs(mirs);
288 PerformLVN();
289 ASSERT_EQ(value_names_.size(), 6u);
290 EXPECT_EQ(value_names_[1], value_names_[3]);
291 EXPECT_NE(value_names_[1], value_names_[5]);
292 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
293 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
294 EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK);
295}
Vladimir Markof59f18b2014-02-17 15:53:57 +0000296
297TEST_F(LocalValueNumberingTest, TestVolatile) {
298 static const IFieldDef ifields[] = {
299 { 1u, 1u, 1u, false },
300 { 2u, 1u, 2u, true },
301 };
302 static const MIRDef mirs[] = {
303 DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile.
304 DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile.
305 DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile.
306 DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile.
307 };
308
309 PrepareIFields(ifields);
310 PrepareMIRs(mirs);
311 PerformLVN();
312 ASSERT_EQ(value_names_.size(), 4u);
313 EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name.
314 EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile.
315 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
316 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
317 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
318 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
319}
320
321} // namespace art