1 /*
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 "dex/mir_field_info.h"
18 #include "global_value_numbering.h"
19 #include "local_value_numbering.h"
20 #include "gtest/gtest.h"
21
22 namespace art {
23
24 class LocalValueNumberingTest : public testing::Test {
25 protected:
26 struct IFieldDef {
27 uint16_t field_idx;
28 uintptr_t declaring_dex_file;
29 uint16_t declaring_field_idx;
30 bool is_volatile;
31 DexMemAccessType type;
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 DexMemAccessType type;
40 };
41
42 struct MIRDef {
43 static constexpr size_t kMaxSsaDefs = 2;
44 static constexpr size_t kMaxSsaUses = 4;
45
46 Instruction::Code opcode;
47 int64_t value;
48 uint32_t field_info;
49 size_t num_uses;
50 int32_t uses[kMaxSsaUses];
51 size_t num_defs;
52 int32_t defs[kMaxSsaDefs];
53 };
54
55 #define DEF_CONST(opcode, reg, value) \
56 { opcode, value, 0u, 0, { }, 1, { reg } }
57 #define DEF_CONST_WIDE(opcode, reg, value) \
58 { opcode, value, 0u, 0, { }, 2, { reg, reg + 1 } }
59 #define DEF_CONST_STRING(opcode, reg, index) \
60 { opcode, index, 0u, 0, { }, 1, { reg } }
61 #define DEF_IGET(opcode, reg, obj, field_info) \
62 { opcode, 0u, field_info, 1, { obj }, 1, { reg } }
63 #define DEF_IGET_WIDE(opcode, reg, obj, field_info) \
64 { opcode, 0u, field_info, 1, { obj }, 2, { reg, reg + 1 } }
65 #define DEF_IPUT(opcode, reg, obj, field_info) \
66 { opcode, 0u, field_info, 2, { reg, obj }, 0, { } }
67 #define DEF_IPUT_WIDE(opcode, reg, obj, field_info) \
68 { opcode, 0u, field_info, 3, { reg, reg + 1, obj }, 0, { } }
69 #define DEF_SGET(opcode, reg, field_info) \
70 { opcode, 0u, field_info, 0, { }, 1, { reg } }
71 #define DEF_SGET_WIDE(opcode, reg, field_info) \
72 { opcode, 0u, field_info, 0, { }, 2, { reg, reg + 1 } }
73 #define DEF_SPUT(opcode, reg, field_info) \
74 { opcode, 0u, field_info, 1, { reg }, 0, { } }
75 #define DEF_SPUT_WIDE(opcode, reg, field_info) \
76 { opcode, 0u, field_info, 2, { reg, reg + 1 }, 0, { } }
77 #define DEF_AGET(opcode, reg, obj, idx) \
78 { opcode, 0u, 0u, 2, { obj, idx }, 1, { reg } }
79 #define DEF_AGET_WIDE(opcode, reg, obj, idx) \
80 { opcode, 0u, 0u, 2, { obj, idx }, 2, { reg, reg + 1 } }
81 #define DEF_APUT(opcode, reg, obj, idx) \
82 { opcode, 0u, 0u, 3, { reg, obj, idx }, 0, { } }
83 #define DEF_APUT_WIDE(opcode, reg, obj, idx) \
84 { opcode, 0u, 0u, 4, { reg, reg + 1, obj, idx }, 0, { } }
85 #define DEF_INVOKE1(opcode, reg) \
86 { opcode, 0u, 0u, 1, { reg }, 0, { } }
87 #define DEF_UNIQUE_REF(opcode, reg) \
88 { opcode, 0u, 0u, 0, { }, 1, { reg } } // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
89 #define DEF_DIV_REM(opcode, result, dividend, divisor) \
90 { opcode, 0u, 0u, 2, { dividend, divisor }, 1, { result } }
91 #define DEF_DIV_REM_WIDE(opcode, result, dividend, divisor) \
92 { opcode, 0u, 0u, 4, { dividend, dividend + 1, divisor, divisor + 1 }, 2, { result, result + 1 } }
93
DoPrepareIFields(const IFieldDef * defs,size_t count)94 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
95 cu_.mir_graph->ifield_lowering_infos_.clear();
96 cu_.mir_graph->ifield_lowering_infos_.reserve(count);
97 for (size_t i = 0u; i != count; ++i) {
98 const IFieldDef* def = &defs[i];
99 MirIFieldLoweringInfo field_info(def->field_idx, def->type, false);
100 if (def->declaring_dex_file != 0u) {
101 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
102 field_info.declaring_field_idx_ = def->declaring_field_idx;
103 field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile);
104 }
105 cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
106 }
107 }
108
109 template <size_t count>
PrepareIFields(const IFieldDef (& defs)[count])110 void PrepareIFields(const IFieldDef (&defs)[count]) {
111 DoPrepareIFields(defs, count);
112 }
113
DoPrepareSFields(const SFieldDef * defs,size_t count)114 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
115 cu_.mir_graph->sfield_lowering_infos_.clear();
116 cu_.mir_graph->sfield_lowering_infos_.reserve(count);
117 for (size_t i = 0u; i != count; ++i) {
118 const SFieldDef* def = &defs[i];
119 MirSFieldLoweringInfo field_info(def->field_idx, def->type);
120 // Mark even unresolved fields as initialized.
121 field_info.flags_ |= MirSFieldLoweringInfo::kFlagClassIsInitialized;
122 // NOTE: MirSFieldLoweringInfo::kFlagClassIsInDexCache isn't used by LVN.
123 if (def->declaring_dex_file != 0u) {
124 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
125 field_info.declaring_field_idx_ = def->declaring_field_idx;
126 field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile);
127 }
128 cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
129 }
130 }
131
132 template <size_t count>
PrepareSFields(const SFieldDef (& defs)[count])133 void PrepareSFields(const SFieldDef (&defs)[count]) {
134 DoPrepareSFields(defs, count);
135 }
136
DoPrepareMIRs(const MIRDef * defs,size_t count)137 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
138 mir_count_ = count;
139 mirs_ = cu_.arena.AllocArray<MIR>(count, kArenaAllocMIR);
140 ssa_reps_.resize(count);
141 for (size_t i = 0u; i != count; ++i) {
142 const MIRDef* def = &defs[i];
143 MIR* mir = &mirs_[i];
144 mir->dalvikInsn.opcode = def->opcode;
145 mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
146 mir->dalvikInsn.vB_wide = def->value;
147 if (IsInstructionIGetOrIPut(def->opcode)) {
148 ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size());
149 mir->meta.ifield_lowering_info = def->field_info;
150 ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_info].MemAccessType(),
151 IGetOrIPutMemAccessType(def->opcode));
152 } else if (IsInstructionSGetOrSPut(def->opcode)) {
153 ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size());
154 mir->meta.sfield_lowering_info = def->field_info;
155 ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_info].MemAccessType(),
156 SGetOrSPutMemAccessType(def->opcode));
157 }
158 mir->ssa_rep = &ssa_reps_[i];
159 mir->ssa_rep->num_uses = def->num_uses;
160 mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN.
161 mir->ssa_rep->num_defs = def->num_defs;
162 mir->ssa_rep->defs = const_cast<int32_t*>(def->defs); // Not modified by LVN.
163 mir->dalvikInsn.opcode = def->opcode;
164 mir->offset = i; // LVN uses offset only for debug output
165 mir->optimization_flags = 0u;
166
167 if (i != 0u) {
168 mirs_[i - 1u].next = mir;
169 }
170 }
171 mirs_[count - 1u].next = nullptr;
172 }
173
174 template <size_t count>
PrepareMIRs(const MIRDef (& defs)[count])175 void PrepareMIRs(const MIRDef (&defs)[count]) {
176 DoPrepareMIRs(defs, count);
177 }
178
MakeSFieldUninitialized(uint32_t sfield_index)179 void MakeSFieldUninitialized(uint32_t sfield_index) {
180 CHECK_LT(sfield_index, cu_.mir_graph->sfield_lowering_infos_.size());
181 cu_.mir_graph->sfield_lowering_infos_[sfield_index].flags_ &=
182 ~MirSFieldLoweringInfo::kFlagClassIsInitialized;
183 }
184
185 template <size_t count>
MarkAsWideSRegs(const int32_t (& sregs)[count])186 void MarkAsWideSRegs(const int32_t (&sregs)[count]) {
187 for (int32_t sreg : sregs) {
188 cu_.mir_graph->reg_location_[sreg].wide = true;
189 cu_.mir_graph->reg_location_[sreg + 1].wide = true;
190 cu_.mir_graph->reg_location_[sreg + 1].high_word = true;
191 }
192 }
193
PerformLVN()194 void PerformLVN() {
195 cu_.mir_graph->temp_.gvn.ifield_ids = GlobalValueNumbering::PrepareGvnFieldIds(
196 allocator_.get(), cu_.mir_graph->ifield_lowering_infos_);
197 cu_.mir_graph->temp_.gvn.sfield_ids = GlobalValueNumbering::PrepareGvnFieldIds(
198 allocator_.get(), cu_.mir_graph->sfield_lowering_infos_);
199 gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(),
200 GlobalValueNumbering::kModeLvn));
201 lvn_.reset(new (allocator_.get()) LocalValueNumbering(gvn_.get(), 0u, allocator_.get()));
202 value_names_.resize(mir_count_);
203 for (size_t i = 0; i != mir_count_; ++i) {
204 value_names_[i] = lvn_->GetValueNumber(&mirs_[i]);
205 }
206 EXPECT_TRUE(gvn_->Good());
207 }
208
LocalValueNumberingTest()209 LocalValueNumberingTest()
210 : pool_(),
211 cu_(&pool_, kRuntimeISA, nullptr, nullptr),
212 mir_count_(0u),
213 mirs_(nullptr),
214 ssa_reps_(),
215 allocator_(),
216 gvn_(),
217 lvn_(),
218 value_names_() {
219 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
220 allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack));
221 // By default, the zero-initialized reg_location_[.] with ref == false tells LVN that
222 // 0 constants are integral, not references, and the values are all narrow.
223 // Nothing else is used by LVN/GVN. Tests can override the default values as needed.
224 cu_.mir_graph->reg_location_ = static_cast<RegLocation*>(cu_.arena.Alloc(
225 kMaxSsaRegs * sizeof(cu_.mir_graph->reg_location_[0]), kArenaAllocRegAlloc));
226 cu_.mir_graph->num_ssa_regs_ = kMaxSsaRegs;
227 }
228
229 static constexpr size_t kMaxSsaRegs = 16384u;
230
231 ArenaPool pool_;
232 CompilationUnit cu_;
233 size_t mir_count_;
234 MIR* mirs_;
235 std::vector<SSARepresentation> ssa_reps_;
236 std::unique_ptr<ScopedArenaAllocator> allocator_;
237 std::unique_ptr<GlobalValueNumbering> gvn_;
238 std::unique_ptr<LocalValueNumbering> lvn_;
239 std::vector<uint16_t> value_names_;
240 };
241
TEST_F(LocalValueNumberingTest,IGetIGetInvokeIGet)242 TEST_F(LocalValueNumberingTest, IGetIGetInvokeIGet) {
243 static const IFieldDef ifields[] = {
244 { 1u, 1u, 1u, false, kDexMemAccessWord },
245 };
246 static const MIRDef mirs[] = {
247 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
248 DEF_IGET(Instruction::IGET, 1u, 10u, 0u),
249 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u),
250 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
251 };
252
253 PrepareIFields(ifields);
254 PrepareMIRs(mirs);
255 PerformLVN();
256 ASSERT_EQ(value_names_.size(), 4u);
257 EXPECT_EQ(value_names_[0], value_names_[1]);
258 EXPECT_NE(value_names_[0], value_names_[3]);
259 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
260 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
261 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
262 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
263 }
264
TEST_F(LocalValueNumberingTest,IGetIPutIGetIGetIGet)265 TEST_F(LocalValueNumberingTest, IGetIPutIGetIGetIGet) {
266 static const IFieldDef ifields[] = {
267 { 1u, 1u, 1u, false, kDexMemAccessObject },
268 { 2u, 1u, 2u, false, kDexMemAccessWord },
269 };
270 static const MIRDef mirs[] = {
271 DEF_IGET(Instruction::IGET_OBJECT, 0u, 10u, 0u),
272 DEF_IPUT(Instruction::IPUT_OBJECT, 1u, 11u, 0u), // May alias.
273 DEF_IGET(Instruction::IGET_OBJECT, 2u, 10u, 0u),
274 DEF_IGET(Instruction::IGET, 3u, 0u, 1u),
275 DEF_IGET(Instruction::IGET, 4u, 2u, 1u),
276 };
277
278 PrepareIFields(ifields);
279 PrepareMIRs(mirs);
280 PerformLVN();
281 ASSERT_EQ(value_names_.size(), 5u);
282 EXPECT_NE(value_names_[0], value_names_[2]);
283 EXPECT_NE(value_names_[3], value_names_[4]);
284 for (size_t i = 0; i != arraysize(mirs); ++i) {
285 EXPECT_EQ((i == 2u) ? MIR_IGNORE_NULL_CHECK : 0,
286 mirs_[i].optimization_flags) << i;
287 }
288 }
289
TEST_F(LocalValueNumberingTest,UniquePreserve1)290 TEST_F(LocalValueNumberingTest, UniquePreserve1) {
291 static const IFieldDef ifields[] = {
292 { 1u, 1u, 1u, false, kDexMemAccessWord },
293 };
294 static const MIRDef mirs[] = {
295 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
296 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
297 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 10u is unique.
298 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
299 };
300
301 PrepareIFields(ifields);
302 PrepareMIRs(mirs);
303 PerformLVN();
304 ASSERT_EQ(value_names_.size(), 4u);
305 EXPECT_EQ(value_names_[1], value_names_[3]);
306 for (size_t i = 0; i != arraysize(mirs); ++i) {
307 EXPECT_EQ((i == 1u || i == 3u) ? MIR_IGNORE_NULL_CHECK : 0,
308 mirs_[i].optimization_flags) << i;
309 }
310 }
311
TEST_F(LocalValueNumberingTest,UniquePreserve2)312 TEST_F(LocalValueNumberingTest, UniquePreserve2) {
313 static const IFieldDef ifields[] = {
314 { 1u, 1u, 1u, false, kDexMemAccessWord },
315 };
316 static const MIRDef mirs[] = {
317 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u),
318 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
319 DEF_IPUT(Instruction::IPUT, 1u, 11u, 0u), // No aliasing since 11u is unique.
320 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
321 };
322
323 PrepareIFields(ifields);
324 PrepareMIRs(mirs);
325 PerformLVN();
326 ASSERT_EQ(value_names_.size(), 4u);
327 EXPECT_EQ(value_names_[1], value_names_[3]);
328 for (size_t i = 0; i != arraysize(mirs); ++i) {
329 EXPECT_EQ((i == 2u || i == 3u) ? MIR_IGNORE_NULL_CHECK : 0,
330 mirs_[i].optimization_flags) << i;
331 }
332 }
333
TEST_F(LocalValueNumberingTest,UniquePreserveAndEscape)334 TEST_F(LocalValueNumberingTest, UniquePreserveAndEscape) {
335 static const IFieldDef ifields[] = {
336 { 1u, 1u, 1u, false, kDexMemAccessWord },
337 };
338 static const MIRDef mirs[] = {
339 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
340 DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
341 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 11u), // 10u still unique.
342 DEF_IGET(Instruction::IGET, 2u, 10u, 0u),
343 DEF_INVOKE1(Instruction::INVOKE_VIRTUAL, 10u), // 10u not unique anymore.
344 DEF_IGET(Instruction::IGET, 3u, 10u, 0u),
345 };
346
347 PrepareIFields(ifields);
348 PrepareMIRs(mirs);
349 PerformLVN();
350 ASSERT_EQ(value_names_.size(), 6u);
351 EXPECT_EQ(value_names_[1], value_names_[3]);
352 EXPECT_NE(value_names_[1], value_names_[5]);
353 for (size_t i = 0; i != arraysize(mirs); ++i) {
354 EXPECT_EQ((i == 1u || i == 3u || i == 4u || i == 5u) ? MIR_IGNORE_NULL_CHECK : 0,
355 mirs_[i].optimization_flags) << i;
356 }
357 }
358
TEST_F(LocalValueNumberingTest,Volatile)359 TEST_F(LocalValueNumberingTest, Volatile) {
360 static const IFieldDef ifields[] = {
361 { 1u, 1u, 1u, false, kDexMemAccessWord },
362 { 2u, 1u, 2u, true, kDexMemAccessWord },
363 };
364 static const MIRDef mirs[] = {
365 DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile.
366 DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile.
367 DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile.
368 DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile.
369 DEF_IGET(Instruction::IGET, 4u, 0u, 0u), // Non-volatile.
370 };
371
372 PrepareIFields(ifields);
373 PrepareMIRs(mirs);
374 PerformLVN();
375 ASSERT_EQ(value_names_.size(), 5u);
376 EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name.
377 EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile.
378 EXPECT_NE(value_names_[1], value_names_[4]); // Not guaranteed to be the same after "acquire".
379
380 for (size_t i = 0; i != arraysize(mirs); ++i) {
381 EXPECT_EQ((i == 2u || i == 4u) ? MIR_IGNORE_NULL_CHECK : 0,
382 mirs_[i].optimization_flags) << i;
383 }
384 }
385
TEST_F(LocalValueNumberingTest,UnresolvedIField)386 TEST_F(LocalValueNumberingTest, UnresolvedIField) {
387 static const IFieldDef ifields[] = {
388 { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1.
389 { 2u, 1u, 2u, false, kDexMemAccessWide }, // Resolved field #2.
390 { 3u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field.
391 };
392 static const MIRDef mirs[] = {
393 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 30u),
394 DEF_IGET(Instruction::IGET, 1u, 30u, 0u), // Resolved field #1, unique object.
395 DEF_IGET(Instruction::IGET, 2u, 31u, 0u), // Resolved field #1.
396 DEF_IGET_WIDE(Instruction::IGET_WIDE, 3u, 31u, 1u), // Resolved field #2.
397 DEF_IGET(Instruction::IGET, 5u, 32u, 2u), // Unresolved IGET can be "acquire".
398 DEF_IGET(Instruction::IGET, 6u, 30u, 0u), // Resolved field #1, unique object.
399 DEF_IGET(Instruction::IGET, 7u, 31u, 0u), // Resolved field #1.
400 DEF_IGET_WIDE(Instruction::IGET_WIDE, 8u, 31u, 1u), // Resolved field #2.
401 DEF_IPUT(Instruction::IPUT, 10u, 32u, 2u), // IPUT clobbers field #1 (#2 is wide).
402 DEF_IGET(Instruction::IGET, 11u, 30u, 0u), // Resolved field #1, unique object.
403 DEF_IGET(Instruction::IGET, 12u, 31u, 0u), // Resolved field #1, new value name.
404 DEF_IGET_WIDE(Instruction::IGET_WIDE, 13u, 31u, 1u), // Resolved field #2.
405 DEF_IGET_WIDE(Instruction::IGET_WIDE, 15u, 30u, 1u), // Resolved field #2, unique object.
406 DEF_IPUT(Instruction::IPUT, 17u, 30u, 2u), // IPUT clobbers field #1 (#2 is wide).
407 DEF_IGET(Instruction::IGET, 18u, 30u, 0u), // Resolved field #1, unique object.
408 DEF_IGET_WIDE(Instruction::IGET_WIDE, 19u, 30u, 1u), // Resolved field #2, unique object.
409 };
410
411 PrepareIFields(ifields);
412 PrepareMIRs(mirs);
413 static const int32_t wide_sregs[] = { 3, 8, 13, 15, 19 };
414 MarkAsWideSRegs(wide_sregs);
415 PerformLVN();
416 ASSERT_EQ(value_names_.size(), 16u);
417 // Unresolved field is potentially volatile, so we need to adhere to the volatile semantics.
418 EXPECT_EQ(value_names_[1], value_names_[5]); // Unique object.
419 EXPECT_NE(value_names_[2], value_names_[6]); // Not guaranteed to be the same after "acquire".
420 EXPECT_NE(value_names_[3], value_names_[7]); // Not guaranteed to be the same after "acquire".
421 EXPECT_EQ(value_names_[1], value_names_[9]); // Unique object.
422 EXPECT_NE(value_names_[6], value_names_[10]); // This aliased with unresolved IPUT.
423 EXPECT_EQ(value_names_[7], value_names_[11]); // Still the same after "release".
424 EXPECT_EQ(value_names_[12], value_names_[15]); // Still the same after "release".
425 EXPECT_NE(value_names_[1], value_names_[14]); // This aliased with unresolved IPUT.
426 EXPECT_EQ(mirs_[0].optimization_flags, 0u);
427 EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
428 EXPECT_EQ(mirs_[2].optimization_flags, 0u);
429 EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
430 EXPECT_EQ(mirs_[4].optimization_flags, 0u);
431 for (size_t i = 5u; i != mir_count_; ++i) {
432 EXPECT_EQ((i == 1u || i == 3u || i >=5u) ? MIR_IGNORE_NULL_CHECK : 0,
433 mirs_[i].optimization_flags) << i;
434 }
435 }
436
TEST_F(LocalValueNumberingTest,UnresolvedSField)437 TEST_F(LocalValueNumberingTest, UnresolvedSField) {
438 static const SFieldDef sfields[] = {
439 { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1.
440 { 2u, 1u, 2u, false, kDexMemAccessWide }, // Resolved field #2.
441 { 3u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field.
442 };
443 static const MIRDef mirs[] = {
444 DEF_SGET(Instruction::SGET, 0u, 0u), // Resolved field #1.
445 DEF_SGET_WIDE(Instruction::SGET_WIDE, 1u, 1u), // Resolved field #2.
446 DEF_SGET(Instruction::SGET, 3u, 2u), // Unresolved SGET can be "acquire".
447 DEF_SGET(Instruction::SGET, 4u, 0u), // Resolved field #1.
448 DEF_SGET_WIDE(Instruction::SGET_WIDE, 5u, 1u), // Resolved field #2.
449 DEF_SPUT(Instruction::SPUT, 7u, 2u), // SPUT clobbers field #1 (#2 is wide).
450 DEF_SGET(Instruction::SGET, 8u, 0u), // Resolved field #1.
451 DEF_SGET_WIDE(Instruction::SGET_WIDE, 9u, 1u), // Resolved field #2.
452 };
453
454 PrepareSFields(sfields);
455 PrepareMIRs(mirs);
456 static const int32_t wide_sregs[] = { 1, 5, 9 };
457 MarkAsWideSRegs(wide_sregs);
458 PerformLVN();
459 ASSERT_EQ(value_names_.size(), 8u);
460 // Unresolved field is potentially volatile, so we need to adhere to the volatile semantics.
461 EXPECT_NE(value_names_[0], value_names_[3]); // Not guaranteed to be the same after "acquire".
462 EXPECT_NE(value_names_[1], value_names_[4]); // Not guaranteed to be the same after "acquire".
463 EXPECT_NE(value_names_[3], value_names_[6]); // This aliased with unresolved IPUT.
464 EXPECT_EQ(value_names_[4], value_names_[7]); // Still the same after "release".
465 for (size_t i = 0u; i != mir_count_; ++i) {
466 EXPECT_EQ(0, mirs_[i].optimization_flags) << i;
467 }
468 }
469
TEST_F(LocalValueNumberingTest,UninitializedSField)470 TEST_F(LocalValueNumberingTest, UninitializedSField) {
471 static const IFieldDef ifields[] = {
472 { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1.
473 };
474 static const SFieldDef sfields[] = {
475 { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1.
476 { 2u, 1u, 2u, false, kDexMemAccessWord }, // Resolved field #2; uninitialized.
477 };
478 static const MIRDef mirs[] = {
479 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 200u),
480 DEF_IGET(Instruction::IGET, 1u, 100u, 0u),
481 DEF_IGET(Instruction::IGET, 2u, 200u, 0u),
482 DEF_SGET(Instruction::SGET, 3u, 0u),
483 DEF_SGET(Instruction::SGET, 4u, 1u), // Can call <clinit>().
484 DEF_IGET(Instruction::IGET, 5u, 100u, 0u), // Differs from 1u.
485 DEF_IGET(Instruction::IGET, 6u, 200u, 0u), // Same as 2u.
486 DEF_SGET(Instruction::SGET, 7u, 0u), // Differs from 3u.
487 };
488
489 PrepareIFields(ifields);
490 PrepareSFields(sfields);
491 MakeSFieldUninitialized(1u);
492 PrepareMIRs(mirs);
493 PerformLVN();
494 ASSERT_EQ(value_names_.size(), 8u);
495 EXPECT_NE(value_names_[1], value_names_[5]);
496 EXPECT_EQ(value_names_[2], value_names_[6]);
497 EXPECT_NE(value_names_[3], value_names_[7]);
498 }
499
TEST_F(LocalValueNumberingTest,ConstString)500 TEST_F(LocalValueNumberingTest, ConstString) {
501 static const MIRDef mirs[] = {
502 DEF_CONST_STRING(Instruction::CONST_STRING, 0u, 0u),
503 DEF_CONST_STRING(Instruction::CONST_STRING, 1u, 0u),
504 DEF_CONST_STRING(Instruction::CONST_STRING, 2u, 2u),
505 DEF_CONST_STRING(Instruction::CONST_STRING, 3u, 0u),
506 DEF_INVOKE1(Instruction::INVOKE_DIRECT, 2u),
507 DEF_CONST_STRING(Instruction::CONST_STRING, 4u, 2u),
508 };
509
510 PrepareMIRs(mirs);
511 PerformLVN();
512 ASSERT_EQ(value_names_.size(), 6u);
513 EXPECT_EQ(value_names_[1], value_names_[0]);
514 EXPECT_NE(value_names_[2], value_names_[0]);
515 EXPECT_EQ(value_names_[3], value_names_[0]);
516 EXPECT_EQ(value_names_[5], value_names_[2]);
517 }
518
TEST_F(LocalValueNumberingTest,SameValueInDifferentMemoryLocations)519 TEST_F(LocalValueNumberingTest, SameValueInDifferentMemoryLocations) {
520 static const IFieldDef ifields[] = {
521 { 1u, 1u, 1u, false, kDexMemAccessWord },
522 { 2u, 1u, 2u, false, kDexMemAccessWord },
523 };
524 static const SFieldDef sfields[] = {
525 { 3u, 1u, 3u, false, kDexMemAccessWord },
526 };
527 static const MIRDef mirs[] = {
528 DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 201u),
529 DEF_IGET(Instruction::IGET, 0u, 100u, 0u),
530 DEF_IPUT(Instruction::IPUT, 0u, 100u, 1u),
531 DEF_IPUT(Instruction::IPUT, 0u, 101u, 1u),
532 DEF_APUT(Instruction::APUT, 0u, 200u, 300u),
533 DEF_APUT(Instruction::APUT, 0u, 200u, 301u),
534 DEF_APUT(Instruction::APUT, 0u, 201u, 300u),
535 DEF_APUT(Instruction::APUT, 0u, 201u, 301u),
536 DEF_SPUT(Instruction::SPUT, 0u, 0u),
537 DEF_IGET(Instruction::IGET, 9u, 100u, 0u),
538 DEF_IGET(Instruction::IGET, 10u, 100u, 1u),
539 DEF_IGET(Instruction::IGET, 11u, 101u, 1u),
540 DEF_AGET(Instruction::AGET, 12u, 200u, 300u),
541 DEF_AGET(Instruction::AGET, 13u, 200u, 301u),
542 DEF_AGET(Instruction::AGET, 14u, 201u, 300u),
543 DEF_AGET(Instruction::AGET, 15u, 201u, 301u),
544 DEF_SGET(Instruction::SGET, 16u, 0u),
545 };
546
547 PrepareIFields(ifields);
548 PrepareSFields(sfields);
549 PrepareMIRs(mirs);
550 PerformLVN();
551 ASSERT_EQ(value_names_.size(), 17u);
552 for (size_t i = 9; i != arraysize(mirs); ++i) {
553 EXPECT_EQ(value_names_[1], value_names_[i]) << i;
554 }
555 for (size_t i = 0; i != arraysize(mirs); ++i) {
556 int expected_flags =
557 ((i == 2u || (i >= 5u && i <= 7u) || (i >= 9u && i <= 15u)) ? MIR_IGNORE_NULL_CHECK : 0) |
558 ((i >= 12u && i <= 15u) ? MIR_IGNORE_RANGE_CHECK : 0);
559 EXPECT_EQ(expected_flags, mirs_[i].optimization_flags) << i;
560 }
561 }
562
TEST_F(LocalValueNumberingTest,UniqueArrayAliasing)563 TEST_F(LocalValueNumberingTest, UniqueArrayAliasing) {
564 static const MIRDef mirs[] = {
565 DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 20u),
566 DEF_AGET(Instruction::AGET, 1u, 20u, 40u),
567 DEF_APUT(Instruction::APUT, 2u, 20u, 41u), // May alias with index for sreg 40u.
568 DEF_AGET(Instruction::AGET, 3u, 20u, 40u),
569 };
570
571 PrepareMIRs(mirs);
572 PerformLVN();
573 ASSERT_EQ(value_names_.size(), 4u);
574 EXPECT_NE(value_names_[1], value_names_[3]);
575 for (size_t i = 0; i != arraysize(mirs); ++i) {
576 int expected_flags =
577 ((i >= 1u) ? MIR_IGNORE_NULL_CHECK : 0) |
578 ((i == 3u) ? MIR_IGNORE_RANGE_CHECK : 0);
579 EXPECT_EQ(expected_flags, mirs_[i].optimization_flags) << i;
580 }
581 }
582
TEST_F(LocalValueNumberingTest,EscapingRefs)583 TEST_F(LocalValueNumberingTest, EscapingRefs) {
584 static const IFieldDef ifields[] = {
585 { 1u, 1u, 1u, false, kDexMemAccessWord }, // Field #1.
586 { 2u, 1u, 2u, false, kDexMemAccessWord }, // Field #2.
587 { 3u, 1u, 3u, false, kDexMemAccessObject }, // For storing escaping refs.
588 { 4u, 1u, 4u, false, kDexMemAccessWide }, // Wide.
589 { 5u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field, int.
590 { 6u, 0u, 0u, false, kDexMemAccessWide }, // Unresolved field, wide.
591 };
592 static const MIRDef mirs[] = {
593 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u),
594 DEF_IGET(Instruction::IGET, 1u, 20u, 0u),
595 DEF_IGET(Instruction::IGET, 2u, 20u, 1u),
596 DEF_IPUT(Instruction::IPUT_OBJECT, 20u, 30u, 2u), // Ref escapes.
597 DEF_IGET(Instruction::IGET, 4u, 20u, 0u),
598 DEF_IGET(Instruction::IGET, 5u, 20u, 1u),
599 DEF_IPUT(Instruction::IPUT, 6u, 31u, 0u), // May alias with field #1.
600 DEF_IGET(Instruction::IGET, 7u, 20u, 0u), // New value.
601 DEF_IGET(Instruction::IGET, 8u, 20u, 1u), // Still the same.
602 DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 9u, 31u, 3u), // No aliasing, different type.
603 DEF_IGET(Instruction::IGET, 11u, 20u, 0u),
604 DEF_IGET(Instruction::IGET, 12u, 20u, 1u),
605 DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 13u, 31u, 5u), // No aliasing, different type.
606 DEF_IGET(Instruction::IGET, 15u, 20u, 0u),
607 DEF_IGET(Instruction::IGET, 16u, 20u, 1u),
608 DEF_IPUT(Instruction::IPUT, 17u, 31u, 4u), // Aliasing, same type.
609 DEF_IGET(Instruction::IGET, 18u, 20u, 0u),
610 DEF_IGET(Instruction::IGET, 19u, 20u, 1u),
611 };
612
613 PrepareIFields(ifields);
614 PrepareMIRs(mirs);
615 static const int32_t wide_sregs[] = { 9, 13 };
616 MarkAsWideSRegs(wide_sregs);
617 PerformLVN();
618 ASSERT_EQ(value_names_.size(), 18u);
619 EXPECT_EQ(value_names_[1], value_names_[4]);
620 EXPECT_EQ(value_names_[2], value_names_[5]);
621 EXPECT_NE(value_names_[4], value_names_[7]); // New value.
622 EXPECT_EQ(value_names_[5], value_names_[8]);
623 EXPECT_EQ(value_names_[7], value_names_[10]);
624 EXPECT_EQ(value_names_[8], value_names_[11]);
625 EXPECT_EQ(value_names_[10], value_names_[13]);
626 EXPECT_EQ(value_names_[11], value_names_[14]);
627 EXPECT_NE(value_names_[13], value_names_[16]); // New value.
628 EXPECT_NE(value_names_[14], value_names_[17]); // New value.
629 for (size_t i = 0u; i != mir_count_; ++i) {
630 int expected =
631 ((i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0) |
632 ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
633 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
634 }
635 }
636
TEST_F(LocalValueNumberingTest,EscapingArrayRefs)637 TEST_F(LocalValueNumberingTest, EscapingArrayRefs) {
638 static const MIRDef mirs[] = {
639 DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 20u),
640 DEF_AGET(Instruction::AGET, 1u, 20u, 40u),
641 DEF_AGET(Instruction::AGET, 2u, 20u, 41u),
642 DEF_APUT(Instruction::APUT_OBJECT, 20u, 30u, 42u), // Array ref escapes.
643 DEF_AGET(Instruction::AGET, 4u, 20u, 40u),
644 DEF_AGET(Instruction::AGET, 5u, 20u, 41u),
645 DEF_APUT_WIDE(Instruction::APUT_WIDE, 6u, 31u, 43u), // No aliasing, different type.
646 DEF_AGET(Instruction::AGET, 8u, 20u, 40u),
647 DEF_AGET(Instruction::AGET, 9u, 20u, 41u),
648 DEF_APUT(Instruction::APUT, 10u, 32u, 40u), // May alias with all elements.
649 DEF_AGET(Instruction::AGET, 11u, 20u, 40u), // New value (same index name).
650 DEF_AGET(Instruction::AGET, 12u, 20u, 41u), // New value (different index name).
651 };
652
653 PrepareMIRs(mirs);
654 static const int32_t wide_sregs[] = { 6 };
655 MarkAsWideSRegs(wide_sregs);
656 PerformLVN();
657 ASSERT_EQ(value_names_.size(), 12u);
658 EXPECT_EQ(value_names_[1], value_names_[4]);
659 EXPECT_EQ(value_names_[2], value_names_[5]);
660 EXPECT_EQ(value_names_[4], value_names_[7]);
661 EXPECT_EQ(value_names_[5], value_names_[8]);
662 EXPECT_NE(value_names_[7], value_names_[10]); // New value.
663 EXPECT_NE(value_names_[8], value_names_[11]); // New value.
664 for (size_t i = 0u; i != mir_count_; ++i) {
665 int expected =
666 ((i != 0u && i != 3u && i != 6u && i != 9u) ? MIR_IGNORE_NULL_CHECK : 0u) |
667 ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u) |
668 ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
669 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
670 }
671 }
672
TEST_F(LocalValueNumberingTest,StoringSameValueKeepsMemoryVersion)673 TEST_F(LocalValueNumberingTest, StoringSameValueKeepsMemoryVersion) {
674 static const IFieldDef ifields[] = {
675 { 1u, 1u, 1u, false, kDexMemAccessWord },
676 { 2u, 1u, 2u, false, kDexMemAccessWord },
677 };
678 static const SFieldDef sfields[] = {
679 { 2u, 1u, 2u, false, kDexMemAccessWord },
680 };
681 static const MIRDef mirs[] = {
682 DEF_IGET(Instruction::IGET, 0u, 30u, 0u),
683 DEF_IGET(Instruction::IGET, 1u, 31u, 0u),
684 DEF_IPUT(Instruction::IPUT, 1u, 31u, 0u), // Store the same value.
685 DEF_IGET(Instruction::IGET, 3u, 30u, 0u),
686 DEF_AGET(Instruction::AGET, 4u, 32u, 40u),
687 DEF_AGET(Instruction::AGET, 5u, 33u, 40u),
688 DEF_APUT(Instruction::APUT, 5u, 33u, 40u), // Store the same value.
689 DEF_AGET(Instruction::AGET, 7u, 32u, 40u),
690 DEF_SGET(Instruction::SGET, 8u, 0u),
691 DEF_SPUT(Instruction::SPUT, 8u, 0u), // Store the same value.
692 DEF_SGET(Instruction::SGET, 10u, 0u),
693 DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 50u), // Test with unique references.
694 { Instruction::FILLED_NEW_ARRAY, 0, 0u, 2, { 12u, 13u }, 0, { } },
695 DEF_UNIQUE_REF(Instruction::MOVE_RESULT_OBJECT, 51u),
696 DEF_IGET(Instruction::IGET, 14u, 50u, 0u),
697 DEF_IGET(Instruction::IGET, 15u, 50u, 1u),
698 DEF_IPUT(Instruction::IPUT, 15u, 50u, 1u), // Store the same value.
699 DEF_IGET(Instruction::IGET, 17u, 50u, 0u),
700 DEF_AGET(Instruction::AGET, 18u, 51u, 40u),
701 DEF_AGET(Instruction::AGET, 19u, 51u, 41u),
702 DEF_APUT(Instruction::APUT, 19u, 51u, 41u), // Store the same value.
703 DEF_AGET(Instruction::AGET, 21u, 51u, 40u),
704 };
705
706 PrepareIFields(ifields);
707 PrepareSFields(sfields);
708 PrepareMIRs(mirs);
709 PerformLVN();
710 ASSERT_EQ(value_names_.size(), 22u);
711 EXPECT_NE(value_names_[0], value_names_[1]);
712 EXPECT_EQ(value_names_[0], value_names_[3]);
713 EXPECT_NE(value_names_[4], value_names_[5]);
714 EXPECT_EQ(value_names_[4], value_names_[7]);
715 EXPECT_EQ(value_names_[8], value_names_[10]);
716 EXPECT_NE(value_names_[14], value_names_[15]);
717 EXPECT_EQ(value_names_[14], value_names_[17]);
718 EXPECT_NE(value_names_[18], value_names_[19]);
719 EXPECT_EQ(value_names_[18], value_names_[21]);
720 for (size_t i = 0u; i != mir_count_; ++i) {
721 int expected =
722 ((i == 2u || i == 3u || i == 6u || i == 7u || (i >= 14u)) ? MIR_IGNORE_NULL_CHECK : 0u) |
723 ((i == 6u || i == 7u || i >= 20u) ? MIR_IGNORE_RANGE_CHECK : 0u);
724 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
725 }
726 }
727
TEST_F(LocalValueNumberingTest,FilledNewArrayTracking)728 TEST_F(LocalValueNumberingTest, FilledNewArrayTracking) {
729 if (!kLocalValueNumberingEnableFilledNewArrayTracking) {
730 // Feature disabled.
731 return;
732 }
733 static const MIRDef mirs[] = {
734 DEF_CONST(Instruction::CONST, 0u, 100),
735 DEF_CONST(Instruction::CONST, 1u, 200),
736 { Instruction::FILLED_NEW_ARRAY, 0, 0u, 2, { 0u, 1u }, 0, { } },
737 DEF_UNIQUE_REF(Instruction::MOVE_RESULT_OBJECT, 10u),
738 DEF_CONST(Instruction::CONST, 20u, 0),
739 DEF_CONST(Instruction::CONST, 21u, 1),
740 DEF_AGET(Instruction::AGET, 6u, 10u, 20u),
741 DEF_AGET(Instruction::AGET, 7u, 10u, 21u),
742 };
743
744 PrepareMIRs(mirs);
745 PerformLVN();
746 ASSERT_EQ(value_names_.size(), 8u);
747 EXPECT_EQ(value_names_[0], value_names_[6]);
748 EXPECT_EQ(value_names_[1], value_names_[7]);
749 for (size_t i = 0u; i != mir_count_; ++i) {
750 int expected = (i == 6u || i == 7u) ? (MIR_IGNORE_NULL_CHECK | MIR_IGNORE_RANGE_CHECK) : 0u;
751 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
752 }
753 }
754
TEST_F(LocalValueNumberingTest,ClInitOnSget)755 TEST_F(LocalValueNumberingTest, ClInitOnSget) {
756 static const SFieldDef sfields[] = {
757 { 0u, 1u, 0u, false, kDexMemAccessObject },
758 { 1u, 2u, 1u, false, kDexMemAccessObject },
759 };
760 static const MIRDef mirs[] = {
761 DEF_SGET(Instruction::SGET_OBJECT, 0u, 0u),
762 DEF_AGET(Instruction::AGET, 1u, 0u, 100u),
763 DEF_SGET(Instruction::SGET_OBJECT, 2u, 1u),
764 DEF_SGET(Instruction::SGET_OBJECT, 3u, 0u),
765 DEF_AGET(Instruction::AGET, 4u, 3u, 100u),
766 };
767
768 PrepareSFields(sfields);
769 MakeSFieldUninitialized(1u);
770 PrepareMIRs(mirs);
771 PerformLVN();
772 ASSERT_EQ(value_names_.size(), 5u);
773 EXPECT_NE(value_names_[0], value_names_[3]);
774 }
775
TEST_F(LocalValueNumberingTest,DivZeroCheck)776 TEST_F(LocalValueNumberingTest, DivZeroCheck) {
777 static const MIRDef mirs[] = {
778 DEF_DIV_REM(Instruction::DIV_INT, 1u, 10u, 20u),
779 DEF_DIV_REM(Instruction::DIV_INT, 2u, 20u, 20u),
780 DEF_DIV_REM(Instruction::DIV_INT_2ADDR, 3u, 10u, 1u),
781 DEF_DIV_REM(Instruction::REM_INT, 4u, 30u, 20u),
782 DEF_DIV_REM_WIDE(Instruction::REM_LONG, 5u, 12u, 14u),
783 DEF_DIV_REM_WIDE(Instruction::DIV_LONG_2ADDR, 7u, 16u, 14u),
784 };
785
786 static const bool expected_ignore_div_zero_check[] = {
787 false, true, false, true, false, true,
788 };
789
790 PrepareMIRs(mirs);
791 static const int32_t wide_sregs[] = { 5, 7, 12, 14, 16 };
792 MarkAsWideSRegs(wide_sregs);
793 PerformLVN();
794 for (size_t i = 0u; i != mir_count_; ++i) {
795 int expected = expected_ignore_div_zero_check[i] ? MIR_IGNORE_DIV_ZERO_CHECK : 0u;
796 EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
797 }
798 }
799
TEST_F(LocalValueNumberingTest,ConstWide)800 TEST_F(LocalValueNumberingTest, ConstWide) {
801 static const MIRDef mirs[] = {
802 // Core reg constants.
803 DEF_CONST(Instruction::CONST_WIDE_16, 0u, 0),
804 DEF_CONST(Instruction::CONST_WIDE_16, 2u, 1),
805 DEF_CONST(Instruction::CONST_WIDE_16, 4u, -1),
806 DEF_CONST(Instruction::CONST_WIDE_32, 6u, 1 << 16),
807 DEF_CONST(Instruction::CONST_WIDE_32, 8u, -1 << 16),
808 DEF_CONST(Instruction::CONST_WIDE_32, 10u, (1 << 16) + 1),
809 DEF_CONST(Instruction::CONST_WIDE_32, 12u, (1 << 16) - 1),
810 DEF_CONST(Instruction::CONST_WIDE_32, 14u, -(1 << 16) + 1),
811 DEF_CONST(Instruction::CONST_WIDE_32, 16u, -(1 << 16) - 1),
812 DEF_CONST(Instruction::CONST_WIDE, 18u, INT64_C(1) << 32),
813 DEF_CONST(Instruction::CONST_WIDE, 20u, INT64_C(-1) << 32),
814 DEF_CONST(Instruction::CONST_WIDE, 22u, (INT64_C(1) << 32) + 1),
815 DEF_CONST(Instruction::CONST_WIDE, 24u, (INT64_C(1) << 32) - 1),
816 DEF_CONST(Instruction::CONST_WIDE, 26u, (INT64_C(-1) << 32) + 1),
817 DEF_CONST(Instruction::CONST_WIDE, 28u, (INT64_C(-1) << 32) - 1),
818 DEF_CONST(Instruction::CONST_WIDE_HIGH16, 30u, 1), // Effectively 1 << 48.
819 DEF_CONST(Instruction::CONST_WIDE_HIGH16, 32u, 0xffff), // Effectively -1 << 48.
820 DEF_CONST(Instruction::CONST_WIDE, 34u, (INT64_C(1) << 48) + 1),
821 DEF_CONST(Instruction::CONST_WIDE, 36u, (INT64_C(1) << 48) - 1),
822 DEF_CONST(Instruction::CONST_WIDE, 38u, (INT64_C(-1) << 48) + 1),
823 DEF_CONST(Instruction::CONST_WIDE, 40u, (INT64_C(-1) << 48) - 1),
824 // FP reg constants.
825 DEF_CONST(Instruction::CONST_WIDE_16, 42u, 0),
826 DEF_CONST(Instruction::CONST_WIDE_16, 44u, 1),
827 DEF_CONST(Instruction::CONST_WIDE_16, 46u, -1),
828 DEF_CONST(Instruction::CONST_WIDE_32, 48u, 1 << 16),
829 DEF_CONST(Instruction::CONST_WIDE_32, 50u, -1 << 16),
830 DEF_CONST(Instruction::CONST_WIDE_32, 52u, (1 << 16) + 1),
831 DEF_CONST(Instruction::CONST_WIDE_32, 54u, (1 << 16) - 1),
832 DEF_CONST(Instruction::CONST_WIDE_32, 56u, -(1 << 16) + 1),
833 DEF_CONST(Instruction::CONST_WIDE_32, 58u, -(1 << 16) - 1),
834 DEF_CONST(Instruction::CONST_WIDE, 60u, INT64_C(1) << 32),
835 DEF_CONST(Instruction::CONST_WIDE, 62u, INT64_C(-1) << 32),
836 DEF_CONST(Instruction::CONST_WIDE, 64u, (INT64_C(1) << 32) + 1),
837 DEF_CONST(Instruction::CONST_WIDE, 66u, (INT64_C(1) << 32) - 1),
838 DEF_CONST(Instruction::CONST_WIDE, 68u, (INT64_C(-1) << 32) + 1),
839 DEF_CONST(Instruction::CONST_WIDE, 70u, (INT64_C(-1) << 32) - 1),
840 DEF_CONST(Instruction::CONST_WIDE_HIGH16, 72u, 1), // Effectively 1 << 48.
841 DEF_CONST(Instruction::CONST_WIDE_HIGH16, 74u, 0xffff), // Effectively -1 << 48.
842 DEF_CONST(Instruction::CONST_WIDE, 76u, (INT64_C(1) << 48) + 1),
843 DEF_CONST(Instruction::CONST_WIDE, 78u, (INT64_C(1) << 48) - 1),
844 DEF_CONST(Instruction::CONST_WIDE, 80u, (INT64_C(-1) << 48) + 1),
845 DEF_CONST(Instruction::CONST_WIDE, 82u, (INT64_C(-1) << 48) - 1),
846 };
847
848 PrepareMIRs(mirs);
849 for (size_t i = 0; i != arraysize(mirs); ++i) {
850 const int32_t wide_sregs[] = { mirs_[i].ssa_rep->defs[0] };
851 MarkAsWideSRegs(wide_sregs);
852 }
853 for (size_t i = arraysize(mirs) / 2u; i != arraysize(mirs); ++i) {
854 cu_.mir_graph->reg_location_[mirs_[i].ssa_rep->defs[0]].fp = true;
855 }
856 PerformLVN();
857 for (size_t i = 0u; i != mir_count_; ++i) {
858 for (size_t j = i + 1u; j != mir_count_; ++j) {
859 EXPECT_NE(value_names_[i], value_names_[j]) << i << " " << j;
860 }
861 }
862 }
863
TEST_F(LocalValueNumberingTest,Const)864 TEST_F(LocalValueNumberingTest, Const) {
865 static const MIRDef mirs[] = {
866 // Core reg constants.
867 DEF_CONST(Instruction::CONST_4, 0u, 0),
868 DEF_CONST(Instruction::CONST_4, 1u, 1),
869 DEF_CONST(Instruction::CONST_4, 2u, -1),
870 DEF_CONST(Instruction::CONST_16, 3u, 1 << 4),
871 DEF_CONST(Instruction::CONST_16, 4u, -1 << 4),
872 DEF_CONST(Instruction::CONST_16, 5u, (1 << 4) + 1),
873 DEF_CONST(Instruction::CONST_16, 6u, (1 << 4) - 1),
874 DEF_CONST(Instruction::CONST_16, 7u, -(1 << 4) + 1),
875 DEF_CONST(Instruction::CONST_16, 8u, -(1 << 4) - 1),
876 DEF_CONST(Instruction::CONST_HIGH16, 9u, 1), // Effectively 1 << 16.
877 DEF_CONST(Instruction::CONST_HIGH16, 10u, 0xffff), // Effectively -1 << 16.
878 DEF_CONST(Instruction::CONST, 11u, (1 << 16) + 1),
879 DEF_CONST(Instruction::CONST, 12u, (1 << 16) - 1),
880 DEF_CONST(Instruction::CONST, 13u, (-1 << 16) + 1),
881 DEF_CONST(Instruction::CONST, 14u, (-1 << 16) - 1),
882 // FP reg constants.
883 DEF_CONST(Instruction::CONST_4, 15u, 0),
884 DEF_CONST(Instruction::CONST_4, 16u, 1),
885 DEF_CONST(Instruction::CONST_4, 17u, -1),
886 DEF_CONST(Instruction::CONST_16, 18u, 1 << 4),
887 DEF_CONST(Instruction::CONST_16, 19u, -1 << 4),
888 DEF_CONST(Instruction::CONST_16, 20u, (1 << 4) + 1),
889 DEF_CONST(Instruction::CONST_16, 21u, (1 << 4) - 1),
890 DEF_CONST(Instruction::CONST_16, 22u, -(1 << 4) + 1),
891 DEF_CONST(Instruction::CONST_16, 23u, -(1 << 4) - 1),
892 DEF_CONST(Instruction::CONST_HIGH16, 24u, 1), // Effectively 1 << 16.
893 DEF_CONST(Instruction::CONST_HIGH16, 25u, 0xffff), // Effectively -1 << 16.
894 DEF_CONST(Instruction::CONST, 26u, (1 << 16) + 1),
895 DEF_CONST(Instruction::CONST, 27u, (1 << 16) - 1),
896 DEF_CONST(Instruction::CONST, 28u, (-1 << 16) + 1),
897 DEF_CONST(Instruction::CONST, 29u, (-1 << 16) - 1),
898 // null reference constant.
899 DEF_CONST(Instruction::CONST_4, 30u, 0),
900 };
901
902 PrepareMIRs(mirs);
903 static_assert((arraysize(mirs) & 1) != 0, "missing null or unmatched fp/core");
904 cu_.mir_graph->reg_location_[arraysize(mirs) - 1].ref = true;
905 for (size_t i = arraysize(mirs) / 2u; i != arraysize(mirs) - 1; ++i) {
906 cu_.mir_graph->reg_location_[mirs_[i].ssa_rep->defs[0]].fp = true;
907 }
908 PerformLVN();
909 for (size_t i = 0u; i != mir_count_; ++i) {
910 for (size_t j = i + 1u; j != mir_count_; ++j) {
911 EXPECT_NE(value_names_[i], value_names_[j]) << i << " " << j;
912 }
913 }
914 }
915
916 } // namespace art
917