blob: efc4fc8a34ae99720be44cccc5907c145fed0f1e [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;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010043 static constexpr size_t kMaxSsaUses = 4;
Vladimir Markof59f18b2014-02-17 15:53:57 +000044
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 Marko2ac01fc2014-05-22 12:09:08 +010058#define DEF_CONST_STRING(opcode, reg, index) \
59 { opcode, index, 0u, 0, { }, 1, { reg } }
Vladimir Markobe0e5462014-02-26 11:24:15 +000060#define DEF_IGET(opcode, reg, obj, field_info) \
61 { opcode, 0u, field_info, 1, { obj }, 1, { reg } }
62#define DEF_IGET_WIDE(opcode, reg, obj, field_info) \
63 { opcode, 0u, field_info, 1, { obj }, 2, { reg, reg + 1 } }
64#define DEF_IPUT(opcode, reg, obj, field_info) \
65 { opcode, 0u, field_info, 2, { reg, obj }, 0, { } }
66#define DEF_IPUT_WIDE(opcode, reg, obj, field_info) \
67 { opcode, 0u, field_info, 3, { reg, reg + 1, obj }, 0, { } }
68#define DEF_SGET(opcode, reg, field_info) \
69 { opcode, 0u, field_info, 0, { }, 1, { reg } }
70#define DEF_SGET_WIDE(opcode, reg, field_info) \
71 { opcode, 0u, field_info, 0, { }, 2, { reg, reg + 1 } }
72#define DEF_SPUT(opcode, reg, field_info) \
73 { opcode, 0u, field_info, 1, { reg }, 0, { } }
74#define DEF_SPUT_WIDE(opcode, reg, field_info) \
75 { opcode, 0u, field_info, 2, { reg, reg + 1 }, 0, { } }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010076#define DEF_AGET(opcode, reg, obj, idx) \
77 { opcode, 0u, 0u, 2, { obj, idx }, 1, { reg } }
78#define DEF_AGET_WIDE(opcode, reg, obj, idx) \
79 { opcode, 0u, 0u, 2, { obj, idx }, 2, { reg, reg + 1 } }
80#define DEF_APUT(opcode, reg, obj, idx) \
81 { opcode, 0u, 0u, 3, { reg, obj, idx }, 0, { } }
82#define DEF_APUT_WIDE(opcode, reg, obj, idx) \
83 { opcode, 0u, 0u, 4, { reg, reg + 1, obj, idx }, 0, { } }
Vladimir Markof59f18b2014-02-17 15:53:57 +000084#define DEF_INVOKE1(opcode, reg) \
85 { opcode, 0u, 0u, 1, { reg }, 0, { } }
86#define DEF_UNIQUE_REF(opcode, reg) \
87 { opcode, 0u, 0u, 0, { }, 1, { reg } } // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
88
89 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
Vladimir Markobe0e5462014-02-26 11:24:15 +000090 cu_.mir_graph->ifield_lowering_infos_.Reset();
91 cu_.mir_graph->ifield_lowering_infos_.Resize(count);
92 for (size_t i = 0u; i != count; ++i) {
93 const IFieldDef* def = &defs[i];
94 MirIFieldLoweringInfo field_info(def->field_idx);
95 if (def->declaring_dex_file != 0u) {
96 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
97 field_info.declaring_field_idx_ = def->declaring_field_idx;
98 field_info.flags_ = 0u | // Without kFlagIsStatic.
99 (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u);
100 }
101 cu_.mir_graph->ifield_lowering_infos_.Insert(field_info);
102 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000103 }
104
105 template <size_t count>
106 void PrepareIFields(const IFieldDef (&defs)[count]) {
107 DoPrepareIFields(defs, count);
108 }
109
110 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
Vladimir Markobe0e5462014-02-26 11:24:15 +0000111 cu_.mir_graph->sfield_lowering_infos_.Reset();
112 cu_.mir_graph->sfield_lowering_infos_.Resize(count);
113 for (size_t i = 0u; i != count; ++i) {
114 const SFieldDef* def = &defs[i];
115 MirSFieldLoweringInfo field_info(def->field_idx);
116 if (def->declaring_dex_file != 0u) {
117 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
118 field_info.declaring_field_idx_ = def->declaring_field_idx;
119 field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic |
120 (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u);
121 }
122 cu_.mir_graph->sfield_lowering_infos_.Insert(field_info);
123 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000124 }
125
126 template <size_t count>
127 void PrepareSFields(const SFieldDef (&defs)[count]) {
128 DoPrepareSFields(defs, count);
129 }
130
131 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
132 mir_count_ = count;
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000133 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
Vladimir Markof59f18b2014-02-17 15:53:57 +0000134 ssa_reps_.resize(count);
135 for (size_t i = 0u; i != count; ++i) {
136 const MIRDef* def = &defs[i];
137 MIR* mir = &mirs_[i];
138 mir->dalvikInsn.opcode = def->opcode;
139 mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
140 mir->dalvikInsn.vB_wide = def->value;
Vladimir Markobe0e5462014-02-26 11:24:15 +0000141 if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
142 ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.Size());
143 mir->meta.ifield_lowering_info = def->field_info;
144 } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
145 ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.Size());
146 mir->meta.sfield_lowering_info = def->field_info;
147 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000148 mir->ssa_rep = &ssa_reps_[i];
149 mir->ssa_rep->num_uses = def->num_uses;
150 mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN.
151 mir->ssa_rep->fp_use = nullptr; // Not used by LVN.
152 mir->ssa_rep->num_defs = def->num_defs;
153 mir->ssa_rep->defs = const_cast<int32_t*>(def->defs); // Not modified by LVN.
154 mir->ssa_rep->fp_def = nullptr; // Not used by LVN.
155 mir->dalvikInsn.opcode = def->opcode;
156 mir->offset = i; // LVN uses offset only for debug output
Vladimir Markof59f18b2014-02-17 15:53:57 +0000157 mir->optimization_flags = 0u;
158
159 if (i != 0u) {
160 mirs_[i - 1u].next = mir;
161 }
162 }
163 mirs_[count - 1u].next = nullptr;
164 }
165
166 template <size_t count>
167 void PrepareMIRs(const MIRDef (&defs)[count]) {
168 DoPrepareMIRs(defs, count);
169 }
170
171 void PerformLVN() {
172 value_names_.resize(mir_count_);
173 for (size_t i = 0; i != mir_count_; ++i) {
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000174 value_names_[i] = lvn_->GetValueNumber(&mirs_[i]);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000175 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100176 EXPECT_TRUE(lvn_->Good());
Vladimir Markof59f18b2014-02-17 15:53:57 +0000177 }
178
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000179 LocalValueNumberingTest()
180 : pool_(),
181 cu_(&pool_),
182 mir_count_(0u),
183 mirs_(nullptr),
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100184 allocator_(),
185 lvn_() {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000186 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100187 allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack));
188 lvn_.reset(new (allocator_.get()) LocalValueNumbering(&cu_, allocator_.get()));
Vladimir Markof59f18b2014-02-17 15:53:57 +0000189 }
190
191 ArenaPool pool_;
192 CompilationUnit cu_;
193 size_t mir_count_;
194 MIR* mirs_;
195 std::vector<SSARepresentation> ssa_reps_;
196 std::vector<uint16_t> value_names_;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100197 std::unique_ptr<ScopedArenaAllocator> allocator_;
Ian Rogers700a4022014-05-19 16:49:03 -0700198 std::unique_ptr<LocalValueNumbering> lvn_;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000199};
200
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100201TEST_F(LocalValueNumberingTest, IGetIGetInvokeIGet) {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000202 static const IFieldDef ifields[] = {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100203 { 1u, 1u, 1u, false },
Vladimir Markof59f18b2014-02-17 15:53:57 +0000204 };
205 static const MIRDef mirs[] = {
206 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
207 DEF_IGET(Instruction::IGET, 1u, 10u, 0u),
208 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u),
209 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
210 };
211
212 PrepareIFields(ifields);
213 PrepareMIRs(mirs);
214 PerformLVN();
215 ASSERT_EQ(value_names_.size(), 4u);
216 EXPECT_EQ(value_names_[0], value_names_[1]);
217 EXPECT_NE(value_names_[0], value_names_[3]);
218 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
219 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
220 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
221 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
222}
223
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100224TEST_F(LocalValueNumberingTest, IGetIPutIGetIGetIGet) {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000225 static const IFieldDef ifields[] = {
226 { 1u, 1u, 1u, false },
227 { 2u, 1u, 2u, false },
228 };
229 static const MIRDef mirs[] = {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100230 DEF_IGET(Instruction::IGET_OBJECT, 0u, 10u, 0u),
231 DEF_IPUT(Instruction::IPUT_OBJECT, 1u, 11u, 0u), // May alias.
232 DEF_IGET(Instruction::IGET_OBJECT, 2u, 10u, 0u),
Vladimir Markof59f18b2014-02-17 15:53:57 +0000233 DEF_IGET(Instruction::IGET, 3u, 0u, 1u),
234 DEF_IGET(Instruction::IGET, 4u, 2u, 1u),
235 };
236
237 PrepareIFields(ifields);
238 PrepareMIRs(mirs);
239 PerformLVN();
240 ASSERT_EQ(value_names_.size(), 5u);
241 EXPECT_NE(value_names_[0], value_names_[2]);
242 EXPECT_NE(value_names_[3], value_names_[4]);
243 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
244 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
245 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
246 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
247 EXPECT_EQ(mirs_[4].optimization_flags, 0u);
248}
249
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100250TEST_F(LocalValueNumberingTest, UniquePreserve1) {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000251 static const IFieldDef ifields[] = {
252 { 1u, 1u, 1u, false },
253 };
254 static const MIRDef mirs[] = {
255 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
256 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
257 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 10u is unique.
258 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
259 };
260
261 PrepareIFields(ifields);
262 PrepareMIRs(mirs);
263 PerformLVN();
264 ASSERT_EQ(value_names_.size(), 4u);
265 EXPECT_EQ(value_names_[1], value_names_[3]);
266 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
267 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
268 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
269}
270
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100271TEST_F(LocalValueNumberingTest, UniquePreserve2) {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000272 static const IFieldDef ifields[] = {
273 { 1u, 1u, 1u, false },
274 };
275 static const MIRDef mirs[] = {
276 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u),
277 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
278 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 11u is unique.
279 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
280 };
281
282 PrepareIFields(ifields);
283 PrepareMIRs(mirs);
284 PerformLVN();
285 ASSERT_EQ(value_names_.size(), 4u);
286 EXPECT_EQ(value_names_[1], value_names_[3]);
287 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
288 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
289 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
290}
291
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100292TEST_F(LocalValueNumberingTest, UniquePreserveAndEscape) {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000293 static const IFieldDef ifields[] = {
294 { 1u, 1u, 1u, false },
295 };
296 static const MIRDef mirs[] = {
297 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
298 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
299 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), // 10u still unique.
300 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
301 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 10u), // 10u not unique anymore.
302 DEF_IGET(Instruction::IGET, 3u, 10u, 0u),
303 };
304
305 PrepareIFields(ifields);
306 PrepareMIRs(mirs);
307 PerformLVN();
308 ASSERT_EQ(value_names_.size(), 6u);
309 EXPECT_EQ(value_names_[1], value_names_[3]);
310 EXPECT_NE(value_names_[1], value_names_[5]);
311 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
312 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
313 EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK);
314}
Vladimir Markof59f18b2014-02-17 15:53:57 +0000315
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100316TEST_F(LocalValueNumberingTest, Volatile) {
Vladimir Markof59f18b2014-02-17 15:53:57 +0000317 static const IFieldDef ifields[] = {
318 { 1u, 1u, 1u, false },
319 { 2u, 1u, 2u, true },
320 };
321 static const MIRDef mirs[] = {
322 DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile.
323 DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile.
324 DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile.
325 DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile.
326 };
327
328 PrepareIFields(ifields);
329 PrepareMIRs(mirs);
330 PerformLVN();
331 ASSERT_EQ(value_names_.size(), 4u);
332 EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name.
333 EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile.
334 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
335 EXPECT_EQ(mirs_[1].optimization_flags, 0u);
336 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
337 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
338}
339
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100340TEST_F(LocalValueNumberingTest, UnresolvedIField) {
341 static const IFieldDef ifields[] = {
342 { 1u, 1u, 1u, false }, // Resolved field #1.
343 { 2u, 1u, 2u, false }, // Resolved field #2.
344 { 3u, 0u, 0u, false }, // Unresolved field.
345 };
346 static const MIRDef mirs[] = {
347 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u),
348 DEF_IGET(Instruction::IGET, 1u, 20u, 0u), // Resolved field #1, unique object.
349 DEF_IGET(Instruction::IGET, 2u, 21u, 0u), // Resolved field #1.
350 DEF_IGET_WIDE(Instruction::IGET_WIDE, 3u, 21u, 1u), // Resolved field #2.
351 DEF_IGET(Instruction::IGET, 4u, 22u, 2u), // IGET doesn't clobber anything.
352 DEF_IGET(Instruction::IGET, 5u, 20u, 0u), // Resolved field #1, unique object.
353 DEF_IGET(Instruction::IGET, 6u, 21u, 0u), // Resolved field #1.
354 DEF_IGET_WIDE(Instruction::IGET_WIDE, 7u, 21u, 1u), // Resolved field #2.
355 DEF_IPUT(Instruction::IPUT, 8u, 22u, 2u), // IPUT clobbers field #1 (#2 if wide).
356 DEF_IGET(Instruction::IGET, 9u, 20u, 0u), // Resolved field #1, unique object.
357 DEF_IGET(Instruction::IGET, 10u, 21u, 0u), // Resolved field #1, new value name.
358 DEF_IGET_WIDE(Instruction::IGET_WIDE, 11u, 21u, 1u), // Resolved field #2.
359 };
360
361 PrepareIFields(ifields);
362 PrepareMIRs(mirs);
363 PerformLVN();
364 ASSERT_EQ(value_names_.size(), 12u);
365 EXPECT_EQ(value_names_[1], value_names_[5]);
366 EXPECT_EQ(value_names_[2], value_names_[6]);
367 EXPECT_EQ(value_names_[3], value_names_[7]);
368 EXPECT_EQ(value_names_[1], value_names_[9]);
369 EXPECT_NE(value_names_[2], value_names_[10]); // This aliased with unresolved IPUT.
370 EXPECT_EQ(value_names_[3], value_names_[11]);
371 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
372 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
373 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
374 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
375 EXPECT_EQ(mirs_[4].optimization_flags, 0u);
376 for (size_t i = 5u; i != mir_count_; ++i) {
377 EXPECT_EQ(mirs_[i].optimization_flags, MIR_IGNORE_NULL_CHECK);
378 }
379}
380
381TEST_F(LocalValueNumberingTest, UnresolvedSField) {
382 static const SFieldDef sfields[] = {
383 { 1u, 1u, 1u, false }, // Resolved field #1.
384 { 2u, 1u, 2u, false }, // Resolved field #2.
385 { 3u, 0u, 0u, false }, // Unresolved field.
386 };
387 static const MIRDef mirs[] = {
388 DEF_SGET(Instruction::SGET, 0u, 0u), // Resolved field #1.
389 DEF_SGET_WIDE(Instruction::SGET_WIDE, 1u, 1u), // Resolved field #2.
390 DEF_SGET(Instruction::SGET, 2u, 2u), // SGET doesn't clobber anything.
391 DEF_SGET(Instruction::SGET, 3u, 0u), // Resolved field #1.
392 DEF_SGET_WIDE(Instruction::SGET_WIDE, 4u, 1u), // Resolved field #2.
393 DEF_SPUT(Instruction::SPUT, 5u, 2u), // SPUT clobbers field #1 (#2 is wide).
394 DEF_SGET(Instruction::SGET, 6u, 0u), // Resolved field #1.
395 DEF_SGET_WIDE(Instruction::SGET_WIDE, 7u, 1u), // Resolved field #2.
396 };
397
398 PrepareSFields(sfields);
399 PrepareMIRs(mirs);
400 PerformLVN();
401 ASSERT_EQ(value_names_.size(), 8u);
402 EXPECT_EQ(value_names_[0], value_names_[3]);
403 EXPECT_EQ(value_names_[1], value_names_[4]);
404 EXPECT_NE(value_names_[0], value_names_[6]); // This aliased with unresolved IPUT.
405 EXPECT_EQ(value_names_[1], value_names_[7]);
406 for (size_t i = 0u; i != mir_count_; ++i) {
407 EXPECT_EQ(mirs_[i].optimization_flags, 0u) << i;
408 }
409}
410
411TEST_F(LocalValueNumberingTest, ConstString) {
412 static const MIRDef mirs[] = {
413 DEF_CONST_STRING(Instruction::CONST_STRING, 0u, 0u),
414 DEF_CONST_STRING(Instruction::CONST_STRING, 1u, 0u),
415 DEF_CONST_STRING(Instruction::CONST_STRING, 2u, 2u),
416 DEF_CONST_STRING(Instruction::CONST_STRING, 3u, 0u),
417 DEF_INVOKE1(Instruction::INVOKE_DIRECT, 2u),
418 DEF_CONST_STRING(Instruction::CONST_STRING, 4u, 2u),
419 };
420
421 PrepareMIRs(mirs);
422 PerformLVN();
423 ASSERT_EQ(value_names_.size(), 6u);
424 EXPECT_EQ(value_names_[1], value_names_[0]);
425 EXPECT_NE(value_names_[2], value_names_[0]);
426 EXPECT_EQ(value_names_[3], value_names_[0]);
427 EXPECT_EQ(value_names_[5], value_names_[2]);
428}
429
430TEST_F(LocalValueNumberingTest, SameValueInDifferentMemoryLocations) {
431 static const IFieldDef ifields[] = {
432 { 1u, 1u, 1u, false },
433 { 2u, 1u, 2u, false },
434 };
435 static const SFieldDef sfields[] = {
436 { 3u, 1u, 3u, false },
437 };
438 static const MIRDef mirs[] = {
439 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
440 DEF_IPUT(Instruction::IPUT, 0u, 10u, 1u),
441 DEF_SPUT(Instruction::SPUT, 0u, 0u),
442 DEF_APUT(Instruction::APUT, 0u, 11u, 12u),
443 DEF_IGET(Instruction::IGET, 1u, 10u, 0u),
444 DEF_IGET(Instruction::IGET, 2u, 10u, 1u),
445 DEF_AGET(Instruction::AGET, 3u, 11u, 12u),
446 DEF_SGET(Instruction::SGET, 4u, 0u),
447 };
448
449 PrepareIFields(ifields);
450 PrepareSFields(sfields);
451 PrepareMIRs(mirs);
452 PerformLVN();
453 ASSERT_EQ(value_names_.size(), 8u);
454 EXPECT_EQ(value_names_[4], value_names_[0]);
455 EXPECT_EQ(value_names_[5], value_names_[0]);
456 EXPECT_EQ(value_names_[6], value_names_[0]);
457 EXPECT_EQ(value_names_[7], value_names_[0]);
458 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
459 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
460 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
461 EXPECT_EQ(mirs_[3].optimization_flags, 0u);
462 EXPECT_EQ(mirs_[4].optimization_flags, MIR_IGNORE_NULL_CHECK);
463 EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK);
464 EXPECT_EQ(mirs_[6].optimization_flags, MIR_IGNORE_NULL_CHECK | MIR_IGNORE_RANGE_CHECK);
465 EXPECT_EQ(mirs_[7].optimization_flags, 0u);
466}
467
468TEST_F(LocalValueNumberingTest, UniqueArrayAliasing) {
469 static const MIRDef mirs[] = {
470 DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 20u),
471 DEF_AGET(Instruction::AGET, 1u, 20u, 40u),
472 DEF_APUT(Instruction::APUT, 2u, 20u, 41u), // May alias with index for sreg 40u.
473 DEF_AGET(Instruction::AGET, 3u, 20u, 40u),
474 };
475
476 PrepareMIRs(mirs);
477 PerformLVN();
478 ASSERT_EQ(value_names_.size(), 4u);
479 EXPECT_NE(value_names_[1], value_names_[3]);
480 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
481 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
482 EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
483 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK | MIR_IGNORE_RANGE_CHECK);
484}
485
486TEST_F(LocalValueNumberingTest, EscapingRefs) {
487 static const IFieldDef ifields[] = {
488 { 1u, 1u, 1u, false }, // Field #1.
489 { 2u, 1u, 2u, false }, // Field #2.
490 { 3u, 1u, 3u, false }, // Reference field for storing escaping refs.
491 { 4u, 1u, 4u, false }, // Wide.
492 { 5u, 0u, 0u, false }, // Unresolved field, int.
493 { 6u, 0u, 0u, false }, // Unresolved field, wide.
494 };
495 static const MIRDef mirs[] = {
496 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u),
497 DEF_IGET(Instruction::IGET, 1u, 20u, 0u),
498 DEF_IGET(Instruction::IGET, 2u, 20u, 1u),
499 DEF_IPUT(Instruction::IPUT_OBJECT, 20u, 30u, 2u), // Ref escapes.
500 DEF_IGET(Instruction::IGET, 4u, 20u, 0u),
501 DEF_IGET(Instruction::IGET, 5u, 20u, 1u),
502 DEF_IPUT(Instruction::IPUT, 6u, 31u, 0u), // May alias with field #1.
503 DEF_IGET(Instruction::IGET, 7u, 20u, 0u), // New value.
504 DEF_IGET(Instruction::IGET, 8u, 20u, 1u), // Still the same.
505 DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 9u, 31u, 3u), // No aliasing, different type.
506 DEF_IGET(Instruction::IGET, 10u, 20u, 0u),
507 DEF_IGET(Instruction::IGET, 11u, 20u, 1u),
508 DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 12u, 31u, 5u), // No aliasing, different type.
509 DEF_IGET(Instruction::IGET, 13u, 20u, 0u),
510 DEF_IGET(Instruction::IGET, 14u, 20u, 1u),
511 DEF_IPUT(Instruction::IPUT, 15u, 31u, 4u), // Aliasing, same type.
512 DEF_IGET(Instruction::IGET, 16u, 20u, 0u),
513 DEF_IGET(Instruction::IGET, 17u, 20u, 1u),
514 };
515
516 PrepareIFields(ifields);
517 PrepareMIRs(mirs);
518 PerformLVN();
519 ASSERT_EQ(value_names_.size(), 18u);
520 EXPECT_EQ(value_names_[1], value_names_[4]);
521 EXPECT_EQ(value_names_[2], value_names_[5]);
522 EXPECT_NE(value_names_[4], value_names_[7]); // New value.
523 EXPECT_EQ(value_names_[5], value_names_[8]);
524 EXPECT_EQ(value_names_[7], value_names_[10]);
525 EXPECT_EQ(value_names_[8], value_names_[11]);
526 EXPECT_EQ(value_names_[10], value_names_[13]);
527 EXPECT_EQ(value_names_[11], value_names_[14]);
528 EXPECT_NE(value_names_[13], value_names_[16]); // New value.
529 EXPECT_NE(value_names_[14], value_names_[17]); // New value.
530 for (size_t i = 0u; i != mir_count_; ++i) {
531 int expected = (i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0u;
532 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
533 }
534}
535
536TEST_F(LocalValueNumberingTest, EscapingArrayRefs) {
537 static const MIRDef mirs[] = {
538 DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 20u),
539 DEF_AGET(Instruction::AGET, 1u, 20u, 40u),
540 DEF_AGET(Instruction::AGET, 2u, 20u, 41u),
541 DEF_APUT(Instruction::APUT_OBJECT, 20u, 30u, 42u), // Array ref escapes.
542 DEF_AGET(Instruction::AGET, 4u, 20u, 40u),
543 DEF_AGET(Instruction::AGET, 5u, 20u, 41u),
544 DEF_APUT_WIDE(Instruction::APUT_WIDE, 6u, 31u, 43u), // No aliasing, different type.
545 DEF_AGET(Instruction::AGET, 7u, 20u, 40u),
546 DEF_AGET(Instruction::AGET, 8u, 20u, 41u),
547 DEF_APUT(Instruction::APUT, 9u, 32u, 40u), // May alias with all elements.
548 DEF_AGET(Instruction::AGET, 10u, 20u, 40u), // New value (same index name).
549 DEF_AGET(Instruction::AGET, 11u, 20u, 41u), // New value (different index name).
550 };
551
552 PrepareMIRs(mirs);
553 PerformLVN();
554 ASSERT_EQ(value_names_.size(), 12u);
555 EXPECT_EQ(value_names_[1], value_names_[4]);
556 EXPECT_EQ(value_names_[2], value_names_[5]);
557 EXPECT_EQ(value_names_[4], value_names_[7]);
558 EXPECT_EQ(value_names_[5], value_names_[8]);
559 EXPECT_NE(value_names_[7], value_names_[10]); // New value.
560 EXPECT_NE(value_names_[8], value_names_[11]); // New value.
561 for (size_t i = 0u; i != mir_count_; ++i) {
562 int expected =
563 ((i != 0u && i != 3u && i != 6u && i != 9u) ? MIR_IGNORE_NULL_CHECK : 0u) |
564 ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u);
565 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
566 }
567}
568
569TEST_F(LocalValueNumberingTest, StoringSameValueKeepsMemoryVersion) {
570 static const IFieldDef ifields[] = {
571 { 1u, 1u, 1u, false },
572 };
573 static const MIRDef mirs[] = {
574 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
575 DEF_IGET(Instruction::IGET, 1u, 11u, 0u),
576 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // Store the same value.
577 DEF_IGET(Instruction::IGET, 3u, 10u, 0u),
578 DEF_AGET(Instruction::AGET, 4u, 12u, 40u),
579 DEF_AGET(Instruction::AGET, 5u, 13u, 40u),
580 DEF_APUT(Instruction::APUT, 5u, 13u, 40u), // Store the same value.
581 DEF_AGET(Instruction::AGET, 7u, 12u, 40u),
582 };
583
584 PrepareIFields(ifields);
585 PrepareMIRs(mirs);
586 PerformLVN();
587 ASSERT_EQ(value_names_.size(), 8u);
588 EXPECT_NE(value_names_[0], value_names_[1]);
589 EXPECT_EQ(value_names_[0], value_names_[3]);
590 EXPECT_NE(value_names_[4], value_names_[5]);
591 EXPECT_EQ(value_names_[4], value_names_[7]);
592 for (size_t i = 0u; i != mir_count_; ++i) {
593 int expected =
594 ((i == 2u || i == 3u || i == 6u || i == 7u) ? MIR_IGNORE_NULL_CHECK : 0u) |
595 ((i == 6u || i == 7u) ? MIR_IGNORE_RANGE_CHECK : 0u);
596 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
597 }
598}
599
Vladimir Markof59f18b2014-02-17 15:53:57 +0000600} // namespace art