blob: 4f8127338cc31900953d5176230e29bd825f3d9b [file] [log] [blame]
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001/*
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
17#include "dataflow_iterator-inl.h"
18#include "dex/mir_field_info.h"
19#include "global_value_numbering.h"
20#include "gvn_dead_code_elimination.h"
21#include "local_value_numbering.h"
22#include "gtest/gtest.h"
23
24namespace art {
25
26class GvnDeadCodeEliminationTest : public testing::Test {
27 protected:
28 static constexpr uint16_t kNoValue = GlobalValueNumbering::kNoValue;
29
30 struct IFieldDef {
31 uint16_t field_idx;
32 uintptr_t declaring_dex_file;
33 uint16_t declaring_field_idx;
34 bool is_volatile;
35 DexMemAccessType type;
36 };
37
38 struct SFieldDef {
39 uint16_t field_idx;
40 uintptr_t declaring_dex_file;
41 uint16_t declaring_field_idx;
42 bool is_volatile;
43 DexMemAccessType type;
44 };
45
46 struct BBDef {
47 static constexpr size_t kMaxSuccessors = 4;
48 static constexpr size_t kMaxPredecessors = 4;
49
50 BBType type;
51 size_t num_successors;
52 BasicBlockId successors[kMaxPredecessors];
53 size_t num_predecessors;
54 BasicBlockId predecessors[kMaxPredecessors];
55 };
56
57 struct MIRDef {
58 static constexpr size_t kMaxSsaDefs = 2;
59 static constexpr size_t kMaxSsaUses = 4;
60
61 BasicBlockId bbid;
62 Instruction::Code opcode;
63 int64_t value;
64 uint32_t field_info;
65 size_t num_uses;
66 int32_t uses[kMaxSsaUses];
67 size_t num_defs;
68 int32_t defs[kMaxSsaDefs];
69 };
70
71#define DEF_SUCC0() \
72 0u, { }
73#define DEF_SUCC1(s1) \
74 1u, { s1 }
75#define DEF_SUCC2(s1, s2) \
76 2u, { s1, s2 }
77#define DEF_SUCC3(s1, s2, s3) \
78 3u, { s1, s2, s3 }
79#define DEF_SUCC4(s1, s2, s3, s4) \
80 4u, { s1, s2, s3, s4 }
81#define DEF_PRED0() \
82 0u, { }
83#define DEF_PRED1(p1) \
84 1u, { p1 }
85#define DEF_PRED2(p1, p2) \
86 2u, { p1, p2 }
87#define DEF_PRED3(p1, p2, p3) \
88 3u, { p1, p2, p3 }
89#define DEF_PRED4(p1, p2, p3, p4) \
90 4u, { p1, p2, p3, p4 }
91#define DEF_BB(type, succ, pred) \
92 { type, succ, pred }
93
94#define DEF_CONST(bb, opcode, reg, value) \
95 { bb, opcode, value, 0u, 0, { }, 1, { reg } }
96#define DEF_CONST_WIDE(bb, opcode, reg, value) \
97 { bb, opcode, value, 0u, 0, { }, 2, { reg, reg + 1 } }
98#define DEF_CONST_STRING(bb, opcode, reg, index) \
99 { bb, opcode, index, 0u, 0, { }, 1, { reg } }
100#define DEF_IGET(bb, opcode, reg, obj, field_info) \
101 { bb, opcode, 0u, field_info, 1, { obj }, 1, { reg } }
102#define DEF_IGET_WIDE(bb, opcode, reg, obj, field_info) \
103 { bb, opcode, 0u, field_info, 1, { obj }, 2, { reg, reg + 1 } }
104#define DEF_IPUT(bb, opcode, reg, obj, field_info) \
105 { bb, opcode, 0u, field_info, 2, { reg, obj }, 0, { } }
106#define DEF_IPUT_WIDE(bb, opcode, reg, obj, field_info) \
107 { bb, opcode, 0u, field_info, 3, { reg, reg + 1, obj }, 0, { } }
108#define DEF_SGET(bb, opcode, reg, field_info) \
109 { bb, opcode, 0u, field_info, 0, { }, 1, { reg } }
110#define DEF_SGET_WIDE(bb, opcode, reg, field_info) \
111 { bb, opcode, 0u, field_info, 0, { }, 2, { reg, reg + 1 } }
112#define DEF_SPUT(bb, opcode, reg, field_info) \
113 { bb, opcode, 0u, field_info, 1, { reg }, 0, { } }
114#define DEF_SPUT_WIDE(bb, opcode, reg, field_info) \
115 { bb, opcode, 0u, field_info, 2, { reg, reg + 1 }, 0, { } }
116#define DEF_AGET(bb, opcode, reg, obj, idx) \
117 { bb, opcode, 0u, 0u, 2, { obj, idx }, 1, { reg } }
118#define DEF_AGET_WIDE(bb, opcode, reg, obj, idx) \
119 { bb, opcode, 0u, 0u, 2, { obj, idx }, 2, { reg, reg + 1 } }
120#define DEF_APUT(bb, opcode, reg, obj, idx) \
121 { bb, opcode, 0u, 0u, 3, { reg, obj, idx }, 0, { } }
122#define DEF_APUT_WIDE(bb, opcode, reg, obj, idx) \
123 { bb, opcode, 0u, 0u, 4, { reg, reg + 1, obj, idx }, 0, { } }
124#define DEF_INVOKE1(bb, opcode, reg) \
125 { bb, opcode, 0u, 0u, 1, { reg }, 0, { } }
126#define DEF_UNIQUE_REF(bb, opcode, reg) \
127 { bb, opcode, 0u, 0u, 0, { }, 1, { reg } } // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
128#define DEF_IFZ(bb, opcode, reg) \
129 { bb, opcode, 0u, 0u, 1, { reg }, 0, { } }
130#define DEF_MOVE(bb, opcode, reg, src) \
131 { bb, opcode, 0u, 0u, 1, { src }, 1, { reg } }
132#define DEF_MOVE_WIDE(bb, opcode, reg, src) \
133 { bb, opcode, 0u, 0u, 2, { src, src + 1 }, 2, { reg, reg + 1 } }
134#define DEF_PHI2(bb, reg, src1, src2) \
135 { bb, static_cast<Instruction::Code>(kMirOpPhi), 0, 0u, 2u, { src1, src2 }, 1, { reg } }
136#define DEF_UNOP(bb, opcode, result, src1) \
137 { bb, opcode, 0u, 0u, 1, { src1 }, 1, { result } }
138#define DEF_BINOP(bb, opcode, result, src1, src2) \
139 { bb, opcode, 0u, 0u, 2, { src1, src2 }, 1, { result } }
140
141 void DoPrepareIFields(const IFieldDef* defs, size_t count) {
142 cu_.mir_graph->ifield_lowering_infos_.clear();
143 cu_.mir_graph->ifield_lowering_infos_.reserve(count);
144 for (size_t i = 0u; i != count; ++i) {
145 const IFieldDef* def = &defs[i];
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800146 MirIFieldLoweringInfo field_info(def->field_idx, def->type, false);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000147 if (def->declaring_dex_file != 0u) {
148 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
149 field_info.declaring_field_idx_ = def->declaring_field_idx;
150 field_info.flags_ =
151 MirIFieldLoweringInfo::kFlagFastGet | MirIFieldLoweringInfo::kFlagFastPut |
152 (field_info.flags_ & ~(def->is_volatile ? 0u : MirIFieldLoweringInfo::kFlagIsVolatile));
153 }
154 cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
155 }
156 }
157
158 template <size_t count>
159 void PrepareIFields(const IFieldDef (&defs)[count]) {
160 DoPrepareIFields(defs, count);
161 }
162
163 void DoPrepareSFields(const SFieldDef* defs, size_t count) {
164 cu_.mir_graph->sfield_lowering_infos_.clear();
165 cu_.mir_graph->sfield_lowering_infos_.reserve(count);
166 for (size_t i = 0u; i != count; ++i) {
167 const SFieldDef* def = &defs[i];
168 MirSFieldLoweringInfo field_info(def->field_idx, def->type);
169 // Mark even unresolved fields as initialized.
170 field_info.flags_ |= MirSFieldLoweringInfo::kFlagClassIsInitialized;
171 // NOTE: MirSFieldLoweringInfo::kFlagClassIsInDexCache isn't used by GVN.
172 if (def->declaring_dex_file != 0u) {
173 field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
174 field_info.declaring_field_idx_ = def->declaring_field_idx;
175 field_info.flags_ =
176 MirSFieldLoweringInfo::kFlagFastGet | MirSFieldLoweringInfo::kFlagFastPut |
177 (field_info.flags_ & ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile));
178 }
179 cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
180 }
181 }
182
183 template <size_t count>
184 void PrepareSFields(const SFieldDef (&defs)[count]) {
185 DoPrepareSFields(defs, count);
186 }
187
188 void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
189 cu_.mir_graph->block_id_map_.clear();
190 cu_.mir_graph->block_list_.clear();
191 ASSERT_LT(3u, count); // null, entry, exit and at least one bytecode block.
192 ASSERT_EQ(kNullBlock, defs[0].type);
193 ASSERT_EQ(kEntryBlock, defs[1].type);
194 ASSERT_EQ(kExitBlock, defs[2].type);
195 for (size_t i = 0u; i != count; ++i) {
196 const BBDef* def = &defs[i];
197 BasicBlock* bb = cu_.mir_graph->CreateNewBB(def->type);
198 if (def->num_successors <= 2) {
199 bb->successor_block_list_type = kNotUsed;
200 bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
201 bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
202 } else {
203 bb->successor_block_list_type = kPackedSwitch;
204 bb->fall_through = 0u;
205 bb->taken = 0u;
206 bb->successor_blocks.reserve(def->num_successors);
207 for (size_t j = 0u; j != def->num_successors; ++j) {
208 SuccessorBlockInfo* successor_block_info =
209 static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
210 kArenaAllocSuccessor));
211 successor_block_info->block = j;
212 successor_block_info->key = 0u; // Not used by class init check elimination.
213 bb->successor_blocks.push_back(successor_block_info);
214 }
215 }
216 bb->predecessors.assign(def->predecessors, def->predecessors + def->num_predecessors);
217 if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
218 bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
219 cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
220 bb->data_flow_info->live_in_v = live_in_v_;
221 bb->data_flow_info->vreg_to_ssa_map_exit = nullptr;
222 }
223 }
224 ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
225 cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
226 ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
227 cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
228 ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
229 }
230
231 template <size_t count>
232 void PrepareBasicBlocks(const BBDef (&defs)[count]) {
233 DoPrepareBasicBlocks(defs, count);
234 }
235
236 int SRegToVReg(int32_t s_reg, bool wide) {
237 int v_reg = cu_.mir_graph->SRegToVReg(s_reg);
238 CHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
239 if (wide) {
240 CHECK_LT(static_cast<size_t>(v_reg + 1), num_vregs_);
241 }
242 return v_reg;
243 }
244
245 int SRegToVReg(int32_t* uses, size_t* use, bool wide) {
246 int v_reg = SRegToVReg(uses[*use], wide);
247 if (wide) {
248 CHECK_EQ(uses[*use] + 1, uses[*use + 1]);
249 *use += 2u;
250 } else {
251 *use += 1u;
252 }
253 return v_reg;
254 }
255
256 void DoPrepareMIRs(const MIRDef* defs, size_t count) {
257 mir_count_ = count;
258 mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
259 ssa_reps_.resize(count);
260 for (size_t i = 0u; i != count; ++i) {
261 const MIRDef* def = &defs[i];
262 MIR* mir = &mirs_[i];
263 ASSERT_LT(def->bbid, cu_.mir_graph->block_list_.size());
264 BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid];
265 bb->AppendMIR(mir);
266 mir->dalvikInsn.opcode = def->opcode;
267 mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
268 mir->dalvikInsn.vB_wide = def->value;
269 if (IsInstructionIGetOrIPut(def->opcode)) {
270 ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size());
271 mir->meta.ifield_lowering_info = def->field_info;
272 ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_info].MemAccessType(),
273 IGetOrIPutMemAccessType(def->opcode));
274 } else if (IsInstructionSGetOrSPut(def->opcode)) {
275 ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size());
276 mir->meta.sfield_lowering_info = def->field_info;
277 ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_info].MemAccessType(),
278 SGetOrSPutMemAccessType(def->opcode));
279 } else if (def->opcode == static_cast<Instruction::Code>(kMirOpPhi)) {
280 mir->meta.phi_incoming =
281 allocator_->AllocArray<BasicBlockId>(def->num_uses, kArenaAllocDFInfo);
282 ASSERT_EQ(def->num_uses, bb->predecessors.size());
283 std::copy(bb->predecessors.begin(), bb->predecessors.end(), mir->meta.phi_incoming);
284 }
285 mir->ssa_rep = &ssa_reps_[i];
286 cu_.mir_graph->AllocateSSAUseData(mir, def->num_uses);
287 std::copy_n(def->uses, def->num_uses, mir->ssa_rep->uses);
288 // Keep mir->ssa_rep->fp_use[.] zero-initialized (false). Not used by DCE, only copied.
289 cu_.mir_graph->AllocateSSADefData(mir, def->num_defs);
290 std::copy_n(def->defs, def->num_defs, mir->ssa_rep->defs);
291 // Keep mir->ssa_rep->fp_def[.] zero-initialized (false). Not used by DCE, only copied.
292 mir->dalvikInsn.opcode = def->opcode;
293 mir->offset = i; // LVN uses offset only for debug output
294 mir->optimization_flags = 0u;
295 uint64_t df_attrs = MIRGraph::GetDataFlowAttributes(mir);
296 if ((df_attrs & DF_DA) != 0) {
297 CHECK_NE(def->num_defs, 0u);
298 mir->dalvikInsn.vA = SRegToVReg(def->defs[0], (df_attrs & DF_A_WIDE) != 0);
299 bb->data_flow_info->vreg_to_ssa_map_exit[mir->dalvikInsn.vA] = def->defs[0];
300 if ((df_attrs & DF_A_WIDE) != 0) {
301 CHECK_EQ(def->defs[0] + 1, def->defs[1]);
302 bb->data_flow_info->vreg_to_ssa_map_exit[mir->dalvikInsn.vA + 1u] = def->defs[0] + 1;
303 }
304 }
305 if ((df_attrs & (DF_UA | DF_UB | DF_UC)) != 0) {
306 size_t use = 0;
307 if ((df_attrs & DF_UA) != 0) {
308 mir->dalvikInsn.vA = SRegToVReg(mir->ssa_rep->uses, &use, (df_attrs & DF_A_WIDE) != 0);
309 }
310 if ((df_attrs & DF_UB) != 0) {
311 mir->dalvikInsn.vB = SRegToVReg(mir->ssa_rep->uses, &use, (df_attrs & DF_B_WIDE) != 0);
312 }
313 if ((df_attrs & DF_UC) != 0) {
314 mir->dalvikInsn.vC = SRegToVReg(mir->ssa_rep->uses, &use, (df_attrs & DF_C_WIDE) != 0);
315 }
316 DCHECK_EQ(def->num_uses, use);
317 }
318 }
319 DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>(
320 cu_.arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
321 code_item->insns_size_in_code_units_ = 2u * count;
322 code_item->registers_size_ = kMaxVRegs;
323 cu_.mir_graph->current_code_item_ = code_item;
324 }
325
326 template <size_t count>
327 void PrepareMIRs(const MIRDef (&defs)[count]) {
328 DoPrepareMIRs(defs, count);
329 }
330
331 template <size_t count>
332 void PrepareSRegToVRegMap(const int (&map)[count]) {
333 cu_.mir_graph->ssa_base_vregs_.assign(map, map + count);
334 num_vregs_ = *std::max_element(map, map + count) + 1u;
335 AllNodesIterator iterator(cu_.mir_graph.get());
336 for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
337 if (bb->data_flow_info != nullptr) {
338 bb->data_flow_info->vreg_to_ssa_map_exit = static_cast<int32_t*>(
339 cu_.arena.Alloc(sizeof(int32_t) * num_vregs_, kArenaAllocDFInfo));
340 std::fill_n(bb->data_flow_info->vreg_to_ssa_map_exit, num_vregs_, INVALID_SREG);
341 }
342 }
343 }
344
345 void PerformGVN() {
346 cu_.mir_graph->SSATransformationStart();
347 cu_.mir_graph->ComputeDFSOrders();
348 cu_.mir_graph->ComputeDominators();
349 cu_.mir_graph->ComputeTopologicalSortOrder();
350 cu_.mir_graph->SSATransformationEnd();
351 cu_.mir_graph->temp_.gvn.ifield_ids = GlobalValueNumbering::PrepareGvnFieldIds(
352 allocator_.get(), cu_.mir_graph->ifield_lowering_infos_);
353 cu_.mir_graph->temp_.gvn.sfield_ids = GlobalValueNumbering::PrepareGvnFieldIds(
354 allocator_.get(), cu_.mir_graph->sfield_lowering_infos_);
355 ASSERT_TRUE(gvn_ == nullptr);
356 gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(),
357 GlobalValueNumbering::kModeGvn));
358 value_names_.resize(mir_count_, 0xffffu);
359 LoopRepeatingTopologicalSortIterator iterator(cu_.mir_graph.get());
360 bool change = false;
361 for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
362 LocalValueNumbering* lvn = gvn_->PrepareBasicBlock(bb);
363 if (lvn != nullptr) {
364 for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
365 value_names_[mir - mirs_] = lvn->GetValueNumber(mir);
366 }
367 }
368 change = (lvn != nullptr) && gvn_->FinishBasicBlock(bb);
369 ASSERT_TRUE(gvn_->Good());
370 }
371 }
372
373 void PerformGVNCodeModifications() {
374 ASSERT_TRUE(gvn_ != nullptr);
375 ASSERT_TRUE(gvn_->Good());
376 gvn_->StartPostProcessing();
377 TopologicalSortIterator iterator(cu_.mir_graph.get());
378 for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
379 LocalValueNumbering* lvn = gvn_->PrepareBasicBlock(bb);
380 if (lvn != nullptr) {
381 for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
382 uint16_t value_name = lvn->GetValueNumber(mir);
383 ASSERT_EQ(value_name, value_names_[mir - mirs_]);
384 }
385 }
386 bool change = (lvn != nullptr) && gvn_->FinishBasicBlock(bb);
387 ASSERT_FALSE(change);
388 ASSERT_TRUE(gvn_->Good());
389 }
390 }
391
392 void FillVregToSsaRegExitMaps() {
393 // Fill in vreg_to_ssa_map_exit for each BB.
394 PreOrderDfsIterator iterator(cu_.mir_graph.get());
395 for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
396 if (bb->block_type == kDalvikByteCode) {
397 CHECK(!bb->predecessors.empty());
398 BasicBlock* pred_bb = cu_.mir_graph->GetBasicBlock(bb->predecessors[0]);
399 for (size_t v_reg = 0; v_reg != num_vregs_; ++v_reg) {
400 if (bb->data_flow_info->vreg_to_ssa_map_exit[v_reg] == INVALID_SREG) {
401 bb->data_flow_info->vreg_to_ssa_map_exit[v_reg] =
402 pred_bb->data_flow_info->vreg_to_ssa_map_exit[v_reg];
403 }
404 }
405 }
406 }
407 }
408
Vladimir Markoa5e69e82015-04-24 19:03:51 +0100409 template <size_t count>
410 void MarkAsWideSRegs(const int32_t (&sregs)[count]) {
411 for (int32_t sreg : sregs) {
412 cu_.mir_graph->reg_location_[sreg].wide = true;
413 cu_.mir_graph->reg_location_[sreg + 1].wide = true;
414 cu_.mir_graph->reg_location_[sreg + 1].high_word = true;
415 }
416 }
417
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000418 void PerformDCE() {
419 FillVregToSsaRegExitMaps();
420 cu_.mir_graph->GetNumOfCodeAndTempVRs();
421 dce_.reset(new (allocator_.get()) GvnDeadCodeElimination(gvn_.get(), allocator_.get()));
422 PreOrderDfsIterator iterator(cu_.mir_graph.get());
423 for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
424 if (bb->block_type == kDalvikByteCode) {
425 dce_->Apply(bb);
426 }
427 }
428 }
429
430 void PerformGVN_DCE() {
431 PerformGVN();
432 PerformGVNCodeModifications(); // Eliminate null/range checks.
433 PerformDCE();
434 }
435
436 template <size_t count>
437 void ExpectValueNamesNE(const size_t (&indexes)[count]) {
438 for (size_t i1 = 0; i1 != count; ++i1) {
439 size_t idx1 = indexes[i1];
440 for (size_t i2 = i1 + 1; i2 != count; ++i2) {
441 size_t idx2 = indexes[i2];
442 EXPECT_NE(value_names_[idx1], value_names_[idx2]) << idx1 << " " << idx2;
443 }
444 }
445 }
446
447 template <size_t count>
448 void ExpectNoNullCheck(const size_t (&indexes)[count]) {
449 for (size_t i = 0; i != count; ++i) {
450 size_t idx = indexes[i];
451 EXPECT_EQ(MIR_IGNORE_NULL_CHECK, mirs_[idx].optimization_flags & MIR_IGNORE_NULL_CHECK)
452 << idx;
453 }
454 size_t num_no_null_ck = 0u;
455 for (size_t i = 0; i != mir_count_; ++i) {
456 if ((mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) {
457 ++num_no_null_ck;
458 }
459 }
460 EXPECT_EQ(count, num_no_null_ck);
461 }
462
463 GvnDeadCodeEliminationTest()
464 : pool_(),
465 cu_(&pool_, kRuntimeISA, nullptr, nullptr),
466 num_vregs_(0u),
467 mir_count_(0u),
468 mirs_(nullptr),
469 ssa_reps_(),
470 allocator_(),
471 gvn_(),
472 dce_(),
473 value_names_(),
474 live_in_v_(new (&cu_.arena) ArenaBitVector(&cu_.arena, kMaxSsaRegs, false, kBitMapMisc)) {
475 cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
476 cu_.access_flags = kAccStatic; // Don't let "this" interfere with this test.
477 allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack));
478 // By default, the zero-initialized reg_location_[.] with ref == false tells LVN that
Vladimir Markoa5e69e82015-04-24 19:03:51 +0100479 // 0 constants are integral, not references, and the values are all narrow.
480 // Nothing else is used by LVN/GVN. Tests can override the default values as needed.
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000481 cu_.mir_graph->reg_location_ = static_cast<RegLocation*>(cu_.arena.Alloc(
482 kMaxSsaRegs * sizeof(cu_.mir_graph->reg_location_[0]), kArenaAllocRegAlloc));
Vladimir Markoa5e69e82015-04-24 19:03:51 +0100483 cu_.mir_graph->num_ssa_regs_ = kMaxSsaRegs;
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000484 // Bind all possible sregs to live vregs for test purposes.
485 live_in_v_->SetInitialBits(kMaxSsaRegs);
486 cu_.mir_graph->ssa_base_vregs_.reserve(kMaxSsaRegs);
487 cu_.mir_graph->ssa_subscripts_.reserve(kMaxSsaRegs);
488 for (unsigned int i = 0; i < kMaxSsaRegs; i++) {
489 cu_.mir_graph->ssa_base_vregs_.push_back(i);
490 cu_.mir_graph->ssa_subscripts_.push_back(0);
491 }
492 // Set shorty for a void-returning method without arguments.
493 cu_.shorty = "V";
494 }
495
496 static constexpr size_t kMaxSsaRegs = 16384u;
497 static constexpr size_t kMaxVRegs = 256u;
498
499 ArenaPool pool_;
500 CompilationUnit cu_;
501 size_t num_vregs_;
502 size_t mir_count_;
503 MIR* mirs_;
504 std::vector<SSARepresentation> ssa_reps_;
505 std::unique_ptr<ScopedArenaAllocator> allocator_;
506 std::unique_ptr<GlobalValueNumbering> gvn_;
507 std::unique_ptr<GvnDeadCodeElimination> dce_;
508 std::vector<uint16_t> value_names_;
509 ArenaBitVector* live_in_v_;
510};
511
512constexpr uint16_t GvnDeadCodeEliminationTest::kNoValue;
513
514class GvnDeadCodeEliminationTestSimple : public GvnDeadCodeEliminationTest {
515 public:
516 GvnDeadCodeEliminationTestSimple();
517
518 private:
519 static const BBDef kSimpleBbs[];
520};
521
522const GvnDeadCodeEliminationTest::BBDef GvnDeadCodeEliminationTestSimple::kSimpleBbs[] = {
523 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
524 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
525 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(3)),
526 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(1)),
527};
528
529GvnDeadCodeEliminationTestSimple::GvnDeadCodeEliminationTestSimple()
530 : GvnDeadCodeEliminationTest() {
531 PrepareBasicBlocks(kSimpleBbs);
532}
533
534class GvnDeadCodeEliminationTestDiamond : public GvnDeadCodeEliminationTest {
535 public:
536 GvnDeadCodeEliminationTestDiamond();
537
538 private:
539 static const BBDef kDiamondBbs[];
540};
541
542const GvnDeadCodeEliminationTest::BBDef GvnDeadCodeEliminationTestDiamond::kDiamondBbs[] = {
543 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
544 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
545 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
546 DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)), // Block #3, top of the diamond.
547 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // Block #4, left side.
548 DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // Block #5, right side.
549 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)), // Block #6, bottom.
550};
551
552GvnDeadCodeEliminationTestDiamond::GvnDeadCodeEliminationTestDiamond()
553 : GvnDeadCodeEliminationTest() {
554 PrepareBasicBlocks(kDiamondBbs);
555}
556
557class GvnDeadCodeEliminationTestLoop : public GvnDeadCodeEliminationTest {
558 public:
559 GvnDeadCodeEliminationTestLoop();
560
561 private:
562 static const BBDef kLoopBbs[];
563};
564
565const GvnDeadCodeEliminationTest::BBDef GvnDeadCodeEliminationTestLoop::kLoopBbs[] = {
566 DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
567 DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
568 DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
569 DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
570 DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)), // "taken" loops to self.
571 DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
572};
573
574GvnDeadCodeEliminationTestLoop::GvnDeadCodeEliminationTestLoop()
575 : GvnDeadCodeEliminationTest() {
576 PrepareBasicBlocks(kLoopBbs);
577}
578
579TEST_F(GvnDeadCodeEliminationTestSimple, Rename1) {
580 static const IFieldDef ifields[] = {
581 { 0u, 1u, 0u, false, kDexMemAccessWord },
582 { 1u, 1u, 1u, false, kDexMemAccessWord },
583 };
584 static const MIRDef mirs[] = {
585 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
586 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
587 DEF_MOVE(3, Instruction::MOVE_OBJECT, 2u, 0u),
588 DEF_IGET(3, Instruction::IGET, 3u, 2u, 1u),
589 };
590
591 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 2 };
592 PrepareSRegToVRegMap(sreg_to_vreg_map);
593
594 PrepareIFields(ifields);
595 PrepareMIRs(mirs);
596 PerformGVN_DCE();
597
598 ASSERT_EQ(arraysize(mirs), value_names_.size());
599 static const size_t diff_indexes[] = { 0, 1, 3 };
600 ExpectValueNamesNE(diff_indexes);
601 EXPECT_EQ(value_names_[0], value_names_[2]);
602
603 const size_t no_null_ck_indexes[] = { 1, 3 };
604 ExpectNoNullCheck(no_null_ck_indexes);
605
606 static const bool eliminated[] = {
607 false, false, true, false
608 };
609 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
610 for (size_t i = 0; i != arraysize(eliminated); ++i) {
611 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
612 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
613 }
614 // Check that the IGET uses the s_reg 0, v_reg 0, defined by mirs_[0].
615 ASSERT_EQ(1, mirs_[3].ssa_rep->num_uses);
616 EXPECT_EQ(0, mirs_[3].ssa_rep->uses[0]);
617 EXPECT_EQ(0u, mirs_[3].dalvikInsn.vB);
618}
619
620TEST_F(GvnDeadCodeEliminationTestSimple, Rename2) {
621 static const IFieldDef ifields[] = {
622 { 0u, 1u, 0u, false, kDexMemAccessWord },
623 { 1u, 1u, 1u, false, kDexMemAccessWord },
624 };
625 static const MIRDef mirs[] = {
626 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
627 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
628 DEF_MOVE(3, Instruction::MOVE_OBJECT, 2u, 0u),
629 DEF_IGET(3, Instruction::IGET, 3u, 2u, 1u),
630 DEF_CONST(3, Instruction::CONST, 4u, 1000),
631 };
632
633 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 2 };
634 PrepareSRegToVRegMap(sreg_to_vreg_map);
635
636 PrepareIFields(ifields);
637 PrepareMIRs(mirs);
638 PerformGVN_DCE();
639
640 ASSERT_EQ(arraysize(mirs), value_names_.size());
641 static const size_t diff_indexes[] = { 0, 1, 3, 4 };
642 ExpectValueNamesNE(diff_indexes);
643 EXPECT_EQ(value_names_[0], value_names_[2]);
644
645 const size_t no_null_ck_indexes[] = { 1, 3 };
646 ExpectNoNullCheck(no_null_ck_indexes);
647
648 static const bool eliminated[] = {
649 false, false, true, false, false
650 };
651 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
652 for (size_t i = 0; i != arraysize(eliminated); ++i) {
653 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
654 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
655 }
656 // Check that the IGET uses the s_reg 0, v_reg 0, defined by mirs_[0].
657 ASSERT_EQ(1, mirs_[3].ssa_rep->num_uses);
658 EXPECT_EQ(0, mirs_[3].ssa_rep->uses[0]);
659 EXPECT_EQ(0u, mirs_[3].dalvikInsn.vB);
660}
661
662TEST_F(GvnDeadCodeEliminationTestSimple, Rename3) {
663 static const IFieldDef ifields[] = {
664 { 0u, 1u, 0u, false, kDexMemAccessWord },
665 { 1u, 1u, 1u, false, kDexMemAccessWord },
666 };
667 static const MIRDef mirs[] = {
668 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
669 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
670 DEF_MOVE(3, Instruction::MOVE_OBJECT, 2u, 0u),
671 DEF_IGET(3, Instruction::IGET, 3u, 2u, 1u),
672 };
673
674 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 0 };
675 PrepareSRegToVRegMap(sreg_to_vreg_map);
676
677 PrepareIFields(ifields);
678 PrepareMIRs(mirs);
679 PerformGVN_DCE();
680
681 ASSERT_EQ(arraysize(mirs), value_names_.size());
682 static const size_t diff_indexes[] = { 0, 1, 3 };
683 ExpectValueNamesNE(diff_indexes);
684 EXPECT_EQ(value_names_[0], value_names_[2]);
685
686 const size_t no_null_ck_indexes[] = { 1, 3 };
687 ExpectNoNullCheck(no_null_ck_indexes);
688
689 static const bool eliminated[] = {
690 false, false, true, false
691 };
692 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
693 for (size_t i = 0; i != arraysize(eliminated); ++i) {
694 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
695 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
696 }
697 // Check that the NEW_INSTANCE defines the s_reg 2, v_reg 2, originally defined by the move.
698 ASSERT_EQ(1, mirs_[0].ssa_rep->num_defs);
699 EXPECT_EQ(2, mirs_[0].ssa_rep->defs[0]);
700 EXPECT_EQ(2u, mirs_[0].dalvikInsn.vA);
701 // Check that the first IGET is using the s_reg 2, v_reg 2.
702 ASSERT_EQ(1, mirs_[1].ssa_rep->num_uses);
703 EXPECT_EQ(2, mirs_[1].ssa_rep->uses[0]);
704 EXPECT_EQ(2u, mirs_[1].dalvikInsn.vB);
705}
706
707TEST_F(GvnDeadCodeEliminationTestSimple, Rename4) {
708 static const MIRDef mirs[] = {
709 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
710 DEF_MOVE(3, Instruction::MOVE_OBJECT, 1u, 0u),
711 DEF_MOVE(3, Instruction::MOVE_OBJECT, 2u, 1u),
712 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 3u, 1000u),
713 };
714
715 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 0, 1 /* high word */ };
716 PrepareSRegToVRegMap(sreg_to_vreg_map);
717
718 PrepareMIRs(mirs);
Vladimir Markoa5e69e82015-04-24 19:03:51 +0100719 static const int32_t wide_sregs[] = { 3 };
720 MarkAsWideSRegs(wide_sregs);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000721 PerformGVN_DCE();
722
723 ASSERT_EQ(arraysize(mirs), value_names_.size());
724 static const size_t diff_indexes[] = { 0, 3 };
725 ExpectValueNamesNE(diff_indexes);
726 EXPECT_EQ(value_names_[0], value_names_[1]);
727 EXPECT_EQ(value_names_[0], value_names_[2]);
728
729 static const bool eliminated[] = {
730 false, true, true, false
731 };
732 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
733 for (size_t i = 0; i != arraysize(eliminated); ++i) {
734 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
735 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
736 }
737 // Check that the NEW_INSTANCE defines the s_reg 2, v_reg 2, originally defined by the move 2u.
738 ASSERT_EQ(1, mirs_[0].ssa_rep->num_defs);
739 EXPECT_EQ(2, mirs_[0].ssa_rep->defs[0]);
740 EXPECT_EQ(2u, mirs_[0].dalvikInsn.vA);
741}
742
743TEST_F(GvnDeadCodeEliminationTestSimple, Rename5) {
744 static const IFieldDef ifields[] = {
745 { 0u, 1u, 0u, false, kDexMemAccessWord },
746 };
747 static const MIRDef mirs[] = {
748 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
749 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
750 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 2u, 1u),
751 DEF_MOVE(3, Instruction::MOVE_OBJECT, 3u, 0u),
752 DEF_MOVE(3, Instruction::MOVE_OBJECT, 4u, 3u),
753 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 5u, 1000u),
754 };
755
756 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 1, 3, 0, 1 /* high word */ };
757 PrepareSRegToVRegMap(sreg_to_vreg_map);
758
759 PrepareIFields(ifields);
760 PrepareMIRs(mirs);
Vladimir Markoa5e69e82015-04-24 19:03:51 +0100761 static const int32_t wide_sregs[] = { 5 };
762 MarkAsWideSRegs(wide_sregs);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000763 PerformGVN_DCE();
764
765 ASSERT_EQ(arraysize(mirs), value_names_.size());
766 static const size_t diff_indexes[] = { 0, 1, 2, 5 };
767 ExpectValueNamesNE(diff_indexes);
768 EXPECT_EQ(value_names_[0], value_names_[3]);
769 EXPECT_EQ(value_names_[0], value_names_[4]);
770
771 static const bool eliminated[] = {
772 false, false, false, true, true, false
773 };
774 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
775 for (size_t i = 0; i != arraysize(eliminated); ++i) {
776 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
777 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
778 }
779 // Check that the NEW_INSTANCE defines the s_reg 4, v_reg 3, originally defined by the move 4u.
780 ASSERT_EQ(1, mirs_[0].ssa_rep->num_defs);
781 EXPECT_EQ(4, mirs_[0].ssa_rep->defs[0]);
782 EXPECT_EQ(3u, mirs_[0].dalvikInsn.vA);
783}
784
785TEST_F(GvnDeadCodeEliminationTestSimple, Rename6) {
786 static const MIRDef mirs[] = {
787 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 0u, 1000u),
788 DEF_MOVE_WIDE(3, Instruction::MOVE_WIDE, 2u, 0u),
789 };
790
791 static const int32_t sreg_to_vreg_map[] = { 0, 1 /* high word */, 1, 2 /* high word */ };
792 PrepareSRegToVRegMap(sreg_to_vreg_map);
793
794 PrepareMIRs(mirs);
Vladimir Markoa5e69e82015-04-24 19:03:51 +0100795 static const int32_t wide_sregs[] = { 0, 2 };
796 MarkAsWideSRegs(wide_sregs);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000797 PerformGVN_DCE();
798
799 ASSERT_EQ(arraysize(mirs), value_names_.size());
800 EXPECT_EQ(value_names_[0], value_names_[1]);
801
802 static const bool eliminated[] = {
803 false, true
804 };
805 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
806 for (size_t i = 0; i != arraysize(eliminated); ++i) {
807 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
808 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
809 }
810 // Check that the CONST_WIDE defines the s_reg 2, v_reg 1, originally defined by the move 2u.
811 ASSERT_EQ(2, mirs_[0].ssa_rep->num_defs);
812 EXPECT_EQ(2, mirs_[0].ssa_rep->defs[0]);
813 EXPECT_EQ(3, mirs_[0].ssa_rep->defs[1]);
814 EXPECT_EQ(1u, mirs_[0].dalvikInsn.vA);
815}
816
817TEST_F(GvnDeadCodeEliminationTestSimple, Rename7) {
818 static const MIRDef mirs[] = {
819 DEF_CONST(3, Instruction::CONST, 0u, 1000u),
820 DEF_MOVE(3, Instruction::MOVE, 1u, 0u),
821 DEF_BINOP(3, Instruction::ADD_INT, 2u, 0u, 1u),
822 };
823
824 static const int32_t sreg_to_vreg_map[] = { 0, 1, 0 };
825 PrepareSRegToVRegMap(sreg_to_vreg_map);
826
827 PrepareMIRs(mirs);
828 PerformGVN_DCE();
829
830 ASSERT_EQ(arraysize(mirs), value_names_.size());
831 EXPECT_NE(value_names_[0], value_names_[2]);
832 EXPECT_EQ(value_names_[0], value_names_[1]);
833
834 static const bool eliminated[] = {
835 false, true, false
836 };
837 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
838 for (size_t i = 0; i != arraysize(eliminated); ++i) {
839 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
840 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
841 }
842 // Check that the CONST defines the s_reg 1, v_reg 1, originally defined by the move 1u.
843 ASSERT_EQ(1, mirs_[0].ssa_rep->num_defs);
844 EXPECT_EQ(1, mirs_[0].ssa_rep->defs[0]);
845 EXPECT_EQ(1u, mirs_[0].dalvikInsn.vA);
846 // Check that the ADD_INT inputs are both s_reg1, vreg 1.
847 ASSERT_EQ(2, mirs_[2].ssa_rep->num_uses);
848 EXPECT_EQ(1, mirs_[2].ssa_rep->uses[0]);
849 EXPECT_EQ(1, mirs_[2].ssa_rep->uses[1]);
850 EXPECT_EQ(1u, mirs_[2].dalvikInsn.vB);
851 EXPECT_EQ(1u, mirs_[2].dalvikInsn.vC);
852}
853
854TEST_F(GvnDeadCodeEliminationTestSimple, Rename8) {
855 static const MIRDef mirs[] = {
856 DEF_CONST(3, Instruction::CONST, 0u, 1000u),
857 DEF_MOVE(3, Instruction::MOVE, 1u, 0u),
858 DEF_BINOP(3, Instruction::ADD_INT_2ADDR, 2u, 0u, 1u),
859 };
860
861 static const int32_t sreg_to_vreg_map[] = { 0, 1, 0 };
862 PrepareSRegToVRegMap(sreg_to_vreg_map);
863
864 PrepareMIRs(mirs);
865 PerformGVN_DCE();
866
867 ASSERT_EQ(arraysize(mirs), value_names_.size());
868 EXPECT_NE(value_names_[0], value_names_[2]);
869 EXPECT_EQ(value_names_[0], value_names_[1]);
870
871 static const bool eliminated[] = {
872 false, true, false
873 };
874 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
875 for (size_t i = 0; i != arraysize(eliminated); ++i) {
876 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
877 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
878 }
879 // Check that the CONST defines the s_reg 1, v_reg 1, originally defined by the move 1u.
880 ASSERT_EQ(1, mirs_[0].ssa_rep->num_defs);
881 EXPECT_EQ(1, mirs_[0].ssa_rep->defs[0]);
882 EXPECT_EQ(1u, mirs_[0].dalvikInsn.vA);
883 // Check that the ADD_INT_2ADDR was replaced by ADD_INT and inputs are both s_reg 1, vreg 1.
884 EXPECT_EQ(Instruction::ADD_INT, mirs_[2].dalvikInsn.opcode);
885 ASSERT_EQ(2, mirs_[2].ssa_rep->num_uses);
886 EXPECT_EQ(1, mirs_[2].ssa_rep->uses[0]);
887 EXPECT_EQ(1, mirs_[2].ssa_rep->uses[1]);
888 EXPECT_EQ(1u, mirs_[2].dalvikInsn.vB);
889 EXPECT_EQ(1u, mirs_[2].dalvikInsn.vC);
890}
891
892TEST_F(GvnDeadCodeEliminationTestSimple, Rename9) {
893 static const MIRDef mirs[] = {
894 DEF_CONST(3, Instruction::CONST, 0u, 1000u),
895 DEF_BINOP(3, Instruction::ADD_INT_2ADDR, 1u, 0u, 0u),
896 DEF_MOVE(3, Instruction::MOVE, 2u, 1u),
897 DEF_CONST(3, Instruction::CONST, 3u, 3000u),
898 };
899
900 static const int32_t sreg_to_vreg_map[] = { 0, 0, 1, 0 };
901 PrepareSRegToVRegMap(sreg_to_vreg_map);
902
903 PrepareMIRs(mirs);
904 PerformGVN_DCE();
905
906 ASSERT_EQ(arraysize(mirs), value_names_.size());
907 static const size_t diff_indexes[] = { 0, 1, 3 };
908 ExpectValueNamesNE(diff_indexes);
909 EXPECT_EQ(value_names_[1], value_names_[2]);
910
911 static const bool eliminated[] = {
912 false, false, true, false
913 };
914 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
915 for (size_t i = 0; i != arraysize(eliminated); ++i) {
916 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
917 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
918 }
919 // Check that the ADD_INT_2ADDR was replaced by ADD_INT and output is in s_reg 2, vreg 1.
920 EXPECT_EQ(Instruction::ADD_INT, mirs_[1].dalvikInsn.opcode);
921 ASSERT_EQ(2, mirs_[1].ssa_rep->num_uses);
922 EXPECT_EQ(0, mirs_[1].ssa_rep->uses[0]);
923 EXPECT_EQ(0, mirs_[1].ssa_rep->uses[1]);
924 EXPECT_EQ(0u, mirs_[1].dalvikInsn.vB);
925 EXPECT_EQ(0u, mirs_[1].dalvikInsn.vC);
926 ASSERT_EQ(1, mirs_[1].ssa_rep->num_defs);
927 EXPECT_EQ(2, mirs_[1].ssa_rep->defs[0]);
928 EXPECT_EQ(1u, mirs_[1].dalvikInsn.vA);
929}
930
931TEST_F(GvnDeadCodeEliminationTestSimple, NoRename1) {
932 static const IFieldDef ifields[] = {
933 { 0u, 1u, 0u, false, kDexMemAccessWord },
934 { 1u, 1u, 1u, false, kDexMemAccessWord },
935 };
936 static const MIRDef mirs[] = {
937 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
938 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
939 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 2u, 1u),
940 DEF_MOVE(3, Instruction::MOVE_OBJECT, 3u, 0u),
941 DEF_CONST(3, Instruction::CONST, 4u, 1000),
942 DEF_IGET(3, Instruction::IGET, 5u, 3u, 1u),
943 };
944
945 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 1, 0, 1 };
946 PrepareSRegToVRegMap(sreg_to_vreg_map);
947
948 PrepareIFields(ifields);
949 PrepareMIRs(mirs);
950 PerformGVN_DCE();
951
952 ASSERT_EQ(arraysize(mirs), value_names_.size());
953 static const size_t diff_indexes[] = { 0, 1, 2, 4, 5 };
954 ExpectValueNamesNE(diff_indexes);
955 EXPECT_EQ(value_names_[0], value_names_[3]);
956
957 const size_t no_null_ck_indexes[] = { 1, 5 };
958 ExpectNoNullCheck(no_null_ck_indexes);
959
960 static const bool eliminated[] = {
961 false, false, false, false, false, false
962 };
963 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
964 for (size_t i = 0; i != arraysize(eliminated); ++i) {
965 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
966 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
967 }
968}
969
970TEST_F(GvnDeadCodeEliminationTestSimple, NoRename2) {
971 static const IFieldDef ifields[] = {
972 { 0u, 1u, 0u, false, kDexMemAccessWord },
973 { 1u, 1u, 1u, false, kDexMemAccessWord },
974 };
975 static const MIRDef mirs[] = {
976 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
977 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
978 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 2u),
979 DEF_MOVE(3, Instruction::MOVE_OBJECT, 3u, 0u),
980 DEF_CONST(3, Instruction::CONST, 4u, 1000),
981 DEF_IGET(3, Instruction::IGET, 5u, 3u, 1u),
982 DEF_CONST(3, Instruction::CONST, 6u, 2000),
983 };
984
985 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 2, 0, 3, 2 };
986 PrepareSRegToVRegMap(sreg_to_vreg_map);
987
988 PrepareIFields(ifields);
989 PrepareMIRs(mirs);
990 PerformGVN_DCE();
991
992 ASSERT_EQ(arraysize(mirs), value_names_.size());
993 static const size_t diff_indexes[] = { 0, 1, 2, 4, 5, 6 };
994 ExpectValueNamesNE(diff_indexes);
995 EXPECT_EQ(value_names_[0], value_names_[3]);
996
997 const size_t no_null_ck_indexes[] = { 1, 5 };
998 ExpectNoNullCheck(no_null_ck_indexes);
999
1000 static const bool eliminated[] = {
1001 false, false, false, false, false, false, false
1002 };
1003 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1004 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1005 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1006 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1007 }
1008}
1009
1010TEST_F(GvnDeadCodeEliminationTestSimple, NoRename3) {
1011 static const IFieldDef ifields[] = {
1012 { 0u, 1u, 0u, false, kDexMemAccessWord },
1013 { 1u, 1u, 1u, false, kDexMemAccessWord },
1014 { 2u, 1u, 2u, false, kDexMemAccessWord },
1015 };
1016 static const MIRDef mirs[] = {
1017 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1018 DEF_IGET(3, Instruction::IGET, 1u, 0u, 0u),
1019 DEF_IGET(3, Instruction::IGET, 2u, 0u, 2u),
1020 DEF_BINOP(3, Instruction::ADD_INT, 3u, 1u, 2u),
1021 DEF_MOVE(3, Instruction::MOVE_OBJECT, 4u, 0u),
1022 DEF_IGET(3, Instruction::IGET, 5u, 4u, 1u),
1023 };
1024
1025 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 2, 0 };
1026 PrepareSRegToVRegMap(sreg_to_vreg_map);
1027
1028 PrepareIFields(ifields);
1029 PrepareMIRs(mirs);
1030 PerformGVN_DCE();
1031
1032 ASSERT_EQ(arraysize(mirs), value_names_.size());
1033 static const size_t diff_indexes[] = { 0, 1, 2, 3, 5 };
1034 ExpectValueNamesNE(diff_indexes);
1035 EXPECT_EQ(value_names_[0], value_names_[4]);
1036
1037 const size_t no_null_ck_indexes[] = { 1, 2, 5 };
1038 ExpectNoNullCheck(no_null_ck_indexes);
1039
1040 static const bool eliminated[] = {
1041 false, false, false, false, false, false
1042 };
1043 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1044 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1045 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1046 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1047 }
1048}
1049
Vladimir Markoad677272015-04-20 10:48:13 +01001050TEST_F(GvnDeadCodeEliminationTestSimple, NoRename4) {
1051 static const MIRDef mirs[] = {
1052 DEF_CONST(3, Instruction::CONST, 0u, 1000u),
1053 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 1u),
1054 DEF_CONST(3, Instruction::CONST, 2u, 100u),
1055 DEF_CONST(3, Instruction::CONST, 3u, 200u),
1056 DEF_BINOP(3, Instruction::OR_INT_2ADDR, 4u, 2u, 3u), // 3. Find definition of the move src.
1057 DEF_MOVE(3, Instruction::MOVE, 5u, 0u), // 4. Uses move dest vreg.
1058 DEF_MOVE(3, Instruction::MOVE, 6u, 4u), // 2. Find overwritten move src.
1059 DEF_CONST(3, Instruction::CONST, 7u, 2000u), // 1. Overwrites 4u, look for moves.
1060 };
1061
1062 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 2, 4, 0, 2 };
1063 PrepareSRegToVRegMap(sreg_to_vreg_map);
1064
1065 PrepareMIRs(mirs);
1066 PerformGVN_DCE();
1067
1068 ASSERT_EQ(arraysize(mirs), value_names_.size());
1069 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 7 };
1070 ExpectValueNamesNE(diff_indexes);
1071 EXPECT_EQ(value_names_[0], value_names_[5]);
1072 EXPECT_EQ(value_names_[4], value_names_[6]);
1073
1074 static const bool eliminated[] = {
1075 false, false, false, false, false, false, false, false
1076 };
1077 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1078 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1079 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1080 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1081 }
1082}
1083
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001084TEST_F(GvnDeadCodeEliminationTestSimple, Simple1) {
1085 static const IFieldDef ifields[] = {
1086 { 0u, 1u, 0u, false, kDexMemAccessObject },
1087 { 1u, 1u, 1u, false, kDexMemAccessObject },
1088 { 2u, 1u, 2u, false, kDexMemAccessWord },
1089 };
1090 static const MIRDef mirs[] = {
1091 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1092 DEF_IGET(3, Instruction::IGET_OBJECT, 1u, 0u, 0u),
1093 DEF_IGET(3, Instruction::IGET_OBJECT, 2u, 1u, 1u),
1094 DEF_IGET(3, Instruction::IGET, 3u, 2u, 2u),
1095 DEF_IGET(3, Instruction::IGET_OBJECT, 4u, 0u, 0u),
1096 DEF_IGET(3, Instruction::IGET_OBJECT, 5u, 4u, 1u),
1097 };
1098
1099 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 1, 2 };
1100 PrepareSRegToVRegMap(sreg_to_vreg_map);
1101
1102 PrepareIFields(ifields);
1103 PrepareMIRs(mirs);
1104 PerformGVN_DCE();
1105
1106 ASSERT_EQ(arraysize(mirs), value_names_.size());
1107 EXPECT_NE(value_names_[0], value_names_[1]);
1108 EXPECT_NE(value_names_[0], value_names_[2]);
1109 EXPECT_NE(value_names_[0], value_names_[3]);
1110 EXPECT_NE(value_names_[1], value_names_[2]);
1111 EXPECT_NE(value_names_[1], value_names_[3]);
1112 EXPECT_NE(value_names_[2], value_names_[3]);
1113 EXPECT_EQ(value_names_[1], value_names_[4]);
1114 EXPECT_EQ(value_names_[2], value_names_[5]);
1115
1116 EXPECT_EQ(MIR_IGNORE_NULL_CHECK, mirs_[4].optimization_flags & MIR_IGNORE_NULL_CHECK);
1117 EXPECT_EQ(MIR_IGNORE_NULL_CHECK, mirs_[5].optimization_flags & MIR_IGNORE_NULL_CHECK);
1118
1119 static const bool eliminated[] = {
1120 false, false, false, false, true, true
1121 };
1122 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1123 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1124 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1125 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1126 }
1127 // Check that the sregs have been renamed correctly.
1128 ASSERT_EQ(1, mirs_[1].ssa_rep->num_defs);
1129 EXPECT_EQ(4, mirs_[1].ssa_rep->defs[0]);
1130 ASSERT_EQ(1, mirs_[1].ssa_rep->num_uses);
1131 EXPECT_EQ(0, mirs_[1].ssa_rep->uses[0]);
1132 ASSERT_EQ(1, mirs_[2].ssa_rep->num_defs);
1133 EXPECT_EQ(5, mirs_[2].ssa_rep->defs[0]);
1134 ASSERT_EQ(1, mirs_[2].ssa_rep->num_uses);
1135 EXPECT_EQ(4, mirs_[2].ssa_rep->uses[0]);
1136 ASSERT_EQ(1, mirs_[3].ssa_rep->num_defs);
1137 EXPECT_EQ(3, mirs_[3].ssa_rep->defs[0]);
1138 ASSERT_EQ(1, mirs_[3].ssa_rep->num_uses);
1139 EXPECT_EQ(5, mirs_[3].ssa_rep->uses[0]);
1140}
1141
1142TEST_F(GvnDeadCodeEliminationTestSimple, Simple2) {
1143 static const IFieldDef ifields[] = {
1144 { 0u, 1u, 0u, false, kDexMemAccessWord },
1145 };
1146 static const MIRDef mirs[] = {
1147 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1148 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1149 DEF_IGET(3, Instruction::IGET, 2u, 0u, 0u),
1150 DEF_BINOP(3, Instruction::ADD_INT_2ADDR, 3u, 2u, 1u),
1151 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 4u, 3u),
1152 DEF_IGET(3, Instruction::IGET, 5u, 0u, 0u),
1153 DEF_BINOP(3, Instruction::ADD_INT_2ADDR, 6u, 5u, 1u),
1154 };
1155
1156 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 2, 3, 2, 2 };
1157 PrepareSRegToVRegMap(sreg_to_vreg_map);
1158
1159 PrepareIFields(ifields);
1160 PrepareMIRs(mirs);
1161 PerformGVN_DCE();
1162
1163 ASSERT_EQ(arraysize(mirs), value_names_.size());
1164 static const size_t diff_indexes[] = { 0, 1, 2, 3 };
1165 ExpectValueNamesNE(diff_indexes);
1166 EXPECT_EQ(value_names_[2], value_names_[5]);
1167 EXPECT_EQ(value_names_[3], value_names_[6]);
1168
1169 const size_t no_null_ck_indexes[] = { 2, 5 };
1170 ExpectNoNullCheck(no_null_ck_indexes);
1171
1172 static const bool eliminated[] = {
1173 false, false, false, false, false, true, true
1174 };
1175 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1176 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1177 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1178 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1179 }
1180 // Check that the sregs have been renamed correctly.
1181 ASSERT_EQ(1, mirs_[3].ssa_rep->num_defs);
1182 EXPECT_EQ(6, mirs_[3].ssa_rep->defs[0]);
1183 ASSERT_EQ(2, mirs_[3].ssa_rep->num_uses);
1184 EXPECT_EQ(2, mirs_[3].ssa_rep->uses[0]);
1185 EXPECT_EQ(1, mirs_[3].ssa_rep->uses[1]);
1186 ASSERT_EQ(1, mirs_[4].ssa_rep->num_defs);
1187 EXPECT_EQ(4, mirs_[4].ssa_rep->defs[0]);
1188 ASSERT_EQ(1, mirs_[4].ssa_rep->num_uses);
1189 EXPECT_EQ(6, mirs_[4].ssa_rep->uses[0]);
1190}
1191
1192TEST_F(GvnDeadCodeEliminationTestSimple, Simple3) {
1193 static const IFieldDef ifields[] = {
1194 { 0u, 1u, 0u, false, kDexMemAccessWord },
1195 };
1196 static const MIRDef mirs[] = {
1197 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1198 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1199 DEF_CONST(3, Instruction::CONST, 2u, 2000),
1200 DEF_CONST(3, Instruction::CONST, 3u, 3000),
1201 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1202 DEF_BINOP(3, Instruction::ADD_INT, 5u, 4u, 1u),
1203 DEF_BINOP(3, Instruction::MUL_INT, 6u, 5u, 2u),
1204 DEF_BINOP(3, Instruction::SUB_INT, 7u, 6u, 3u),
1205 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 8u, 7u),
1206 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1207 DEF_BINOP(3, Instruction::ADD_INT, 10u, 9u, 1u),
1208 DEF_BINOP(3, Instruction::MUL_INT, 11u, 10u, 2u), // Simple elimination of ADD+MUL
1209 DEF_BINOP(3, Instruction::SUB_INT, 12u, 11u, 3u), // allows simple elimination of IGET+SUB.
1210 };
1211
1212 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 4, 5, 5, 4, 6, 4, 5, 5, 4 };
1213 PrepareSRegToVRegMap(sreg_to_vreg_map);
1214
1215 PrepareIFields(ifields);
1216 PrepareMIRs(mirs);
1217 PerformGVN_DCE();
1218
1219 ASSERT_EQ(arraysize(mirs), value_names_.size());
1220 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
1221 ExpectValueNamesNE(diff_indexes);
1222 EXPECT_EQ(value_names_[4], value_names_[9]);
1223 EXPECT_EQ(value_names_[5], value_names_[10]);
1224 EXPECT_EQ(value_names_[6], value_names_[11]);
1225 EXPECT_EQ(value_names_[7], value_names_[12]);
1226
1227 const size_t no_null_ck_indexes[] = { 4, 9 };
1228 ExpectNoNullCheck(no_null_ck_indexes);
1229
1230 static const bool eliminated[] = {
1231 false, false, false, false, false, false, false, false, false, true, true, true, true
1232 };
1233 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1234 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1235 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1236 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1237 }
1238 // Check that the sregs have been renamed correctly.
1239 ASSERT_EQ(1, mirs_[6].ssa_rep->num_defs);
1240 EXPECT_EQ(11, mirs_[6].ssa_rep->defs[0]); // 6 -> 11
1241 ASSERT_EQ(2, mirs_[6].ssa_rep->num_uses);
1242 EXPECT_EQ(5, mirs_[6].ssa_rep->uses[0]);
1243 EXPECT_EQ(2, mirs_[6].ssa_rep->uses[1]);
1244 ASSERT_EQ(1, mirs_[7].ssa_rep->num_defs);
1245 EXPECT_EQ(12, mirs_[7].ssa_rep->defs[0]); // 7 -> 12
1246 ASSERT_EQ(2, mirs_[7].ssa_rep->num_uses);
1247 EXPECT_EQ(11, mirs_[7].ssa_rep->uses[0]); // 6 -> 11
1248 EXPECT_EQ(3, mirs_[7].ssa_rep->uses[1]);
1249 ASSERT_EQ(1, mirs_[8].ssa_rep->num_defs);
1250 EXPECT_EQ(8, mirs_[8].ssa_rep->defs[0]);
1251 ASSERT_EQ(1, mirs_[8].ssa_rep->num_uses);
1252 EXPECT_EQ(12, mirs_[8].ssa_rep->uses[0]); // 7 -> 12
1253}
1254
1255TEST_F(GvnDeadCodeEliminationTestSimple, Simple4) {
1256 static const IFieldDef ifields[] = {
1257 { 0u, 1u, 0u, false, kDexMemAccessWord },
1258 };
1259 static const MIRDef mirs[] = {
1260 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1261 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 1u, INT64_C(1)),
1262 DEF_BINOP(3, Instruction::LONG_TO_FLOAT, 3u, 1u, 2u),
1263 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1264 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 5u, 4u),
1265 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 6u, INT64_C(1)),
1266 DEF_BINOP(3, Instruction::LONG_TO_FLOAT, 8u, 6u, 7u),
1267 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1268 };
1269
1270 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 1, 2, 3, 1, 2, 1, 2 };
1271 PrepareSRegToVRegMap(sreg_to_vreg_map);
1272
1273 PrepareIFields(ifields);
1274 PrepareMIRs(mirs);
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001275 static const int32_t wide_sregs[] = { 1, 6 };
1276 MarkAsWideSRegs(wide_sregs);
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001277 PerformGVN_DCE();
1278
1279 ASSERT_EQ(arraysize(mirs), value_names_.size());
1280 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4 };
1281 ExpectValueNamesNE(diff_indexes);
1282 EXPECT_EQ(value_names_[1], value_names_[5]);
1283 EXPECT_EQ(value_names_[2], value_names_[6]);
1284 EXPECT_EQ(value_names_[3], value_names_[7]);
1285
1286 const size_t no_null_ck_indexes[] = { 3, 7 };
1287 ExpectNoNullCheck(no_null_ck_indexes);
1288
1289 static const bool eliminated[] = {
1290 // Simple elimination of CONST_WIDE+LONG_TO_FLOAT allows simple eliminatiion of IGET.
1291 false, false, false, false, false, true, true, true
1292 };
1293 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1294 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1295 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1296 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1297 }
1298 // Check that the sregs have been renamed correctly.
1299 ASSERT_EQ(1, mirs_[2].ssa_rep->num_defs);
1300 EXPECT_EQ(8, mirs_[2].ssa_rep->defs[0]); // 3 -> 8
1301 ASSERT_EQ(2, mirs_[2].ssa_rep->num_uses);
1302 EXPECT_EQ(1, mirs_[2].ssa_rep->uses[0]);
1303 EXPECT_EQ(2, mirs_[2].ssa_rep->uses[1]);
1304 ASSERT_EQ(1, mirs_[3].ssa_rep->num_defs);
1305 EXPECT_EQ(9, mirs_[3].ssa_rep->defs[0]); // 4 -> 9
1306 ASSERT_EQ(1, mirs_[3].ssa_rep->num_uses);
1307 EXPECT_EQ(0, mirs_[3].ssa_rep->uses[0]);
1308 ASSERT_EQ(1, mirs_[4].ssa_rep->num_defs);
1309 EXPECT_EQ(5, mirs_[4].ssa_rep->defs[0]);
1310 ASSERT_EQ(1, mirs_[4].ssa_rep->num_uses);
1311 EXPECT_EQ(9, mirs_[4].ssa_rep->uses[0]); // 4 -> 9
1312}
1313
1314TEST_F(GvnDeadCodeEliminationTestSimple, KillChain1) {
1315 static const IFieldDef ifields[] = {
1316 { 0u, 1u, 0u, false, kDexMemAccessWord },
1317 };
1318 static const MIRDef mirs[] = {
1319 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1320 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1321 DEF_CONST(3, Instruction::CONST, 2u, 2000),
1322 DEF_CONST(3, Instruction::CONST, 3u, 3000),
1323 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1324 DEF_BINOP(3, Instruction::ADD_INT, 5u, 4u, 1u),
1325 DEF_BINOP(3, Instruction::MUL_INT, 6u, 5u, 2u),
1326 DEF_BINOP(3, Instruction::SUB_INT, 7u, 6u, 3u),
1327 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 8u, 7u),
1328 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1329 DEF_BINOP(3, Instruction::ADD_INT, 10u, 9u, 1u),
1330 DEF_BINOP(3, Instruction::MUL_INT, 11u, 10u, 2u),
1331 DEF_BINOP(3, Instruction::SUB_INT, 12u, 11u, 3u),
1332 };
1333
1334 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 4, 5, 4, 5, 6, 4, 5, 4, 5 };
1335 PrepareSRegToVRegMap(sreg_to_vreg_map);
1336
1337 PrepareIFields(ifields);
1338 PrepareMIRs(mirs);
1339 PerformGVN_DCE();
1340
1341 ASSERT_EQ(arraysize(mirs), value_names_.size());
1342 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
1343 ExpectValueNamesNE(diff_indexes);
1344 EXPECT_EQ(value_names_[4], value_names_[9]);
1345 EXPECT_EQ(value_names_[5], value_names_[10]);
1346 EXPECT_EQ(value_names_[6], value_names_[11]);
1347 EXPECT_EQ(value_names_[7], value_names_[12]);
1348
1349 const size_t no_null_ck_indexes[] = { 4, 9 };
1350 ExpectNoNullCheck(no_null_ck_indexes);
1351
1352 static const bool eliminated[] = {
1353 false, false, false, false, false, false, false, false, false, true, true, true, true
1354 };
1355 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1356 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1357 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1358 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1359 }
1360 // Check that the sregs have been renamed correctly.
1361 ASSERT_EQ(1, mirs_[6].ssa_rep->num_defs);
1362 EXPECT_EQ(11, mirs_[6].ssa_rep->defs[0]); // 6 -> 11
1363 ASSERT_EQ(2, mirs_[6].ssa_rep->num_uses);
1364 EXPECT_EQ(5, mirs_[6].ssa_rep->uses[0]);
1365 EXPECT_EQ(2, mirs_[6].ssa_rep->uses[1]);
1366 ASSERT_EQ(1, mirs_[7].ssa_rep->num_defs);
1367 EXPECT_EQ(12, mirs_[7].ssa_rep->defs[0]); // 7 -> 12
1368 ASSERT_EQ(2, mirs_[7].ssa_rep->num_uses);
1369 EXPECT_EQ(11, mirs_[7].ssa_rep->uses[0]); // 6 -> 11
1370 EXPECT_EQ(3, mirs_[7].ssa_rep->uses[1]);
1371 ASSERT_EQ(1, mirs_[8].ssa_rep->num_defs);
1372 EXPECT_EQ(8, mirs_[8].ssa_rep->defs[0]);
1373 ASSERT_EQ(1, mirs_[8].ssa_rep->num_uses);
1374 EXPECT_EQ(12, mirs_[8].ssa_rep->uses[0]); // 7 -> 12
1375}
1376
1377TEST_F(GvnDeadCodeEliminationTestSimple, KillChain2) {
1378 static const IFieldDef ifields[] = {
1379 { 0u, 1u, 0u, false, kDexMemAccessWord },
1380 };
1381 static const MIRDef mirs[] = {
1382 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1383 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1384 DEF_CONST(3, Instruction::CONST, 2u, 2000),
1385 DEF_CONST(3, Instruction::CONST, 3u, 3000),
1386 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1387 DEF_BINOP(3, Instruction::ADD_INT, 5u, 4u, 1u),
1388 DEF_BINOP(3, Instruction::MUL_INT, 6u, 5u, 2u),
1389 DEF_BINOP(3, Instruction::SUB_INT, 7u, 6u, 3u),
1390 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 8u, 7u),
1391 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1392 DEF_BINOP(3, Instruction::ADD_INT, 10u, 9u, 1u),
1393 DEF_BINOP(3, Instruction::MUL_INT, 11u, 10u, 2u),
1394 DEF_BINOP(3, Instruction::SUB_INT, 12u, 11u, 3u),
1395 DEF_CONST(3, Instruction::CONST, 13u, 4000),
1396 };
1397
1398 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 4, 5, 5, 4, 6, 4, 7, 7, 4, 7 };
1399 PrepareSRegToVRegMap(sreg_to_vreg_map);
1400
1401 PrepareIFields(ifields);
1402 PrepareMIRs(mirs);
1403 PerformGVN_DCE();
1404
1405 ASSERT_EQ(arraysize(mirs), value_names_.size());
1406 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 13 };
1407 ExpectValueNamesNE(diff_indexes);
1408 EXPECT_EQ(value_names_[4], value_names_[9]);
1409 EXPECT_EQ(value_names_[5], value_names_[10]);
1410 EXPECT_EQ(value_names_[6], value_names_[11]);
1411 EXPECT_EQ(value_names_[7], value_names_[12]);
1412
1413 const size_t no_null_ck_indexes[] = { 4, 9 };
1414 ExpectNoNullCheck(no_null_ck_indexes);
1415
1416 static const bool eliminated[] = {
1417 false, false, false, false, false, false, false, false, false, true, true, true, true, false
1418 };
1419 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1420 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1421 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1422 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1423 }
1424 // Check that the sregs have been renamed correctly.
1425 ASSERT_EQ(1, mirs_[7].ssa_rep->num_defs);
1426 EXPECT_EQ(12, mirs_[7].ssa_rep->defs[0]); // 7 -> 12
1427 ASSERT_EQ(2, mirs_[7].ssa_rep->num_uses);
1428 EXPECT_EQ(6, mirs_[7].ssa_rep->uses[0]);
1429 EXPECT_EQ(3, mirs_[7].ssa_rep->uses[1]);
1430 ASSERT_EQ(1, mirs_[8].ssa_rep->num_defs);
1431 EXPECT_EQ(8, mirs_[8].ssa_rep->defs[0]);
1432 ASSERT_EQ(1, mirs_[8].ssa_rep->num_uses);
1433 EXPECT_EQ(12, mirs_[8].ssa_rep->uses[0]); // 7 -> 12
1434}
1435
1436TEST_F(GvnDeadCodeEliminationTestSimple, KillChain3) {
1437 static const IFieldDef ifields[] = {
1438 { 0u, 1u, 0u, false, kDexMemAccessWord },
1439 };
1440 static const MIRDef mirs[] = {
1441 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1442 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1443 DEF_CONST(3, Instruction::CONST, 2u, 2000),
1444 DEF_CONST(3, Instruction::CONST, 3u, 3000),
1445 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1446 DEF_BINOP(3, Instruction::ADD_INT, 5u, 4u, 1u),
1447 DEF_BINOP(3, Instruction::MUL_INT, 6u, 5u, 2u),
1448 DEF_BINOP(3, Instruction::SUB_INT, 7u, 6u, 3u),
1449 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 8u, 7u),
1450 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1451 DEF_BINOP(3, Instruction::ADD_INT, 10u, 9u, 1u),
1452 DEF_BINOP(3, Instruction::MUL_INT, 11u, 10u, 2u),
1453 DEF_CONST(3, Instruction::CONST, 12u, 4000),
1454 DEF_BINOP(3, Instruction::SUB_INT, 13u, 11u, 3u),
1455 };
1456
1457 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 4, 5, 5, 4, 6, 4, 7, 4, 7, 4 };
1458 PrepareSRegToVRegMap(sreg_to_vreg_map);
1459
1460 PrepareIFields(ifields);
1461 PrepareMIRs(mirs);
1462 PerformGVN_DCE();
1463
1464 ASSERT_EQ(arraysize(mirs), value_names_.size());
1465 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12 };
1466 ExpectValueNamesNE(diff_indexes);
1467 EXPECT_EQ(value_names_[4], value_names_[9]);
1468 EXPECT_EQ(value_names_[5], value_names_[10]);
1469 EXPECT_EQ(value_names_[6], value_names_[11]);
1470 EXPECT_EQ(value_names_[7], value_names_[13]);
1471
1472 const size_t no_null_ck_indexes[] = { 4, 9 };
1473 ExpectNoNullCheck(no_null_ck_indexes);
1474
1475 static const bool eliminated[] = {
1476 false, false, false, false, false, false, false, false, false, true, true, true, false, true
1477 };
1478 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1479 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1480 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1481 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1482 }
1483 // Check that the sregs have been renamed correctly.
1484 ASSERT_EQ(1, mirs_[7].ssa_rep->num_defs);
1485 EXPECT_EQ(13, mirs_[7].ssa_rep->defs[0]); // 7 -> 13
1486 ASSERT_EQ(2, mirs_[7].ssa_rep->num_uses);
1487 EXPECT_EQ(6, mirs_[7].ssa_rep->uses[0]);
1488 EXPECT_EQ(3, mirs_[7].ssa_rep->uses[1]);
1489 ASSERT_EQ(1, mirs_[8].ssa_rep->num_defs);
1490 EXPECT_EQ(8, mirs_[8].ssa_rep->defs[0]);
1491 ASSERT_EQ(1, mirs_[8].ssa_rep->num_uses);
1492 EXPECT_EQ(13, mirs_[8].ssa_rep->uses[0]); // 7 -> 13
1493}
1494
1495TEST_F(GvnDeadCodeEliminationTestSimple, KeepChain1) {
1496 // KillChain2 without the final CONST.
1497 static const IFieldDef ifields[] = {
1498 { 0u, 1u, 0u, false, kDexMemAccessWord },
1499 };
1500 static const MIRDef mirs[] = {
1501 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1502 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1503 DEF_CONST(3, Instruction::CONST, 2u, 2000),
1504 DEF_CONST(3, Instruction::CONST, 3u, 3000),
1505 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1506 DEF_BINOP(3, Instruction::ADD_INT, 5u, 4u, 1u),
1507 DEF_BINOP(3, Instruction::MUL_INT, 6u, 5u, 2u),
1508 DEF_BINOP(3, Instruction::SUB_INT, 7u, 6u, 3u),
1509 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 8u, 7u),
1510 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1511 DEF_BINOP(3, Instruction::ADD_INT, 10u, 9u, 1u),
1512 DEF_BINOP(3, Instruction::MUL_INT, 11u, 10u, 2u),
1513 DEF_BINOP(3, Instruction::SUB_INT, 12u, 11u, 3u),
1514 };
1515
1516 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 4, 5, 5, 4, 6, 4, 7, 7, 4 };
1517 PrepareSRegToVRegMap(sreg_to_vreg_map);
1518
1519 PrepareIFields(ifields);
1520 PrepareMIRs(mirs);
1521 PerformGVN_DCE();
1522
1523 ASSERT_EQ(arraysize(mirs), value_names_.size());
1524 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
1525 ExpectValueNamesNE(diff_indexes);
1526 EXPECT_EQ(value_names_[4], value_names_[9]);
1527 EXPECT_EQ(value_names_[5], value_names_[10]);
1528 EXPECT_EQ(value_names_[6], value_names_[11]);
1529 EXPECT_EQ(value_names_[7], value_names_[12]);
1530
1531 const size_t no_null_ck_indexes[] = { 4, 9 };
1532 ExpectNoNullCheck(no_null_ck_indexes);
1533
1534 static const bool eliminated[] = {
1535 false, false, false, false, false, false, false, false, false, false, false, false, false
1536 };
1537 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1538 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1539 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1540 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1541 }
1542}
1543
1544TEST_F(GvnDeadCodeEliminationTestSimple, KeepChain2) {
1545 // KillChain1 with MIRs in the middle of the chain.
1546 static const IFieldDef ifields[] = {
1547 { 0u, 1u, 0u, false, kDexMemAccessWord },
1548 };
1549 static const MIRDef mirs[] = {
1550 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1551 DEF_CONST(3, Instruction::CONST, 1u, 1000),
1552 DEF_CONST(3, Instruction::CONST, 2u, 2000),
1553 DEF_CONST(3, Instruction::CONST, 3u, 3000),
1554 DEF_IGET(3, Instruction::IGET, 4u, 0u, 0u),
1555 DEF_BINOP(3, Instruction::ADD_INT, 5u, 4u, 1u),
1556 DEF_BINOP(3, Instruction::MUL_INT, 6u, 5u, 2u),
1557 DEF_BINOP(3, Instruction::SUB_INT, 7u, 6u, 3u),
1558 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 8u, 7u),
1559 DEF_IGET(3, Instruction::IGET, 9u, 0u, 0u),
1560 DEF_BINOP(3, Instruction::ADD_INT, 10u, 9u, 1u),
1561 DEF_CONST(3, Instruction::CONST, 11u, 4000),
1562 DEF_UNOP(3, Instruction::INT_TO_FLOAT, 12u, 11u),
1563 DEF_BINOP(3, Instruction::MUL_INT, 13u, 10u, 2u),
1564 DEF_BINOP(3, Instruction::SUB_INT, 14u, 13u, 3u),
1565 };
1566
1567 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3, 4, 5, 4, 5, 6, 4, 5, 4, 7, 4, 5 };
1568 PrepareSRegToVRegMap(sreg_to_vreg_map);
1569
1570 PrepareIFields(ifields);
1571 PrepareMIRs(mirs);
1572 PerformGVN_DCE();
1573
1574 ASSERT_EQ(arraysize(mirs), value_names_.size());
1575 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
1576 ExpectValueNamesNE(diff_indexes);
1577 EXPECT_EQ(value_names_[4], value_names_[9]);
1578 EXPECT_EQ(value_names_[5], value_names_[10]);
1579 EXPECT_EQ(value_names_[6], value_names_[13]);
1580 EXPECT_EQ(value_names_[7], value_names_[14]);
1581
1582 const size_t no_null_ck_indexes[] = { 4, 9 };
1583 ExpectNoNullCheck(no_null_ck_indexes);
1584
1585 static const bool eliminated[] = {
1586 false, false, false, false, false, false, false, false, false,
1587 false, false, false, false, false, false
1588 };
1589 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1590 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1591 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1592 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1593 }
1594}
1595
1596TEST_F(GvnDeadCodeEliminationTestDiamond, CreatePhi1) {
1597 static const MIRDef mirs[] = {
1598 DEF_CONST(3, Instruction::CONST, 0u, 1000),
1599 DEF_CONST(4, Instruction::CONST, 1u, 1000),
1600 };
1601
1602 static const int32_t sreg_to_vreg_map[] = { 0, 0 };
1603 PrepareSRegToVRegMap(sreg_to_vreg_map);
1604
1605 PrepareMIRs(mirs);
1606 PerformGVN_DCE();
1607
1608 ASSERT_EQ(arraysize(mirs), value_names_.size());
1609 EXPECT_EQ(value_names_[0], value_names_[1]);
1610
1611 static const bool eliminated[] = {
1612 false, true,
1613 };
1614 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1615 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1616 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1617 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1618 }
1619 // Check that we've created a single-input Phi to replace the CONST 3u.
1620 BasicBlock* bb4 = cu_.mir_graph->GetBasicBlock(4);
1621 MIR* phi = bb4->first_mir_insn;
1622 ASSERT_TRUE(phi != nullptr);
1623 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi->dalvikInsn.opcode));
1624 ASSERT_EQ(1, phi->ssa_rep->num_uses);
1625 EXPECT_EQ(0, phi->ssa_rep->uses[0]);
1626 ASSERT_EQ(1, phi->ssa_rep->num_defs);
1627 EXPECT_EQ(1, phi->ssa_rep->defs[0]);
1628 EXPECT_EQ(0u, phi->dalvikInsn.vA);
1629}
1630
1631TEST_F(GvnDeadCodeEliminationTestDiamond, CreatePhi2) {
Vladimir Markof60715c2015-05-07 15:53:41 +01001632 static const MIRDef mirs[] = {
1633 DEF_CONST(3, Instruction::CONST, 0u, 1000),
1634 DEF_MOVE(4, Instruction::MOVE, 1u, 0u),
1635 DEF_CONST(4, Instruction::CONST, 2u, 1000),
1636 };
1637
1638 static const int32_t sreg_to_vreg_map[] = { 0, 1, 0 };
1639 PrepareSRegToVRegMap(sreg_to_vreg_map);
1640
1641 PrepareMIRs(mirs);
1642 PerformGVN_DCE();
1643
1644 ASSERT_EQ(arraysize(mirs), value_names_.size());
1645 EXPECT_EQ(value_names_[0], value_names_[1]);
1646 EXPECT_EQ(value_names_[0], value_names_[2]);
1647
1648 static const bool eliminated[] = {
1649 false, false, true,
1650 };
1651 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1652 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1653 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1654 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1655 }
1656 // Check that we've created a single-input Phi to replace the CONST 3u.
1657 BasicBlock* bb4 = cu_.mir_graph->GetBasicBlock(4);
1658 MIR* phi = bb4->first_mir_insn;
1659 ASSERT_TRUE(phi != nullptr);
1660 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi->dalvikInsn.opcode));
1661 ASSERT_EQ(1, phi->ssa_rep->num_uses);
1662 EXPECT_EQ(0, phi->ssa_rep->uses[0]);
1663 ASSERT_EQ(1, phi->ssa_rep->num_defs);
1664 EXPECT_EQ(2, phi->ssa_rep->defs[0]);
1665 EXPECT_EQ(0u, phi->dalvikInsn.vA);
1666 MIR* move = phi->next;
1667 ASSERT_TRUE(move != nullptr);
1668 ASSERT_EQ(Instruction::MOVE, move->dalvikInsn.opcode);
1669 ASSERT_EQ(1, move->ssa_rep->num_uses);
1670 EXPECT_EQ(2, move->ssa_rep->uses[0]);
1671 ASSERT_EQ(1, move->ssa_rep->num_defs);
1672 EXPECT_EQ(1, move->ssa_rep->defs[0]);
1673 EXPECT_EQ(1u, move->dalvikInsn.vA);
1674 EXPECT_EQ(0u, move->dalvikInsn.vB);
1675}
1676
1677TEST_F(GvnDeadCodeEliminationTestDiamond, CreatePhi3) {
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001678 static const IFieldDef ifields[] = {
1679 { 0u, 1u, 0u, false, kDexMemAccessWord },
1680 };
1681 static const MIRDef mirs[] = {
1682 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1683 DEF_CONST(4, Instruction::CONST, 1u, 1000),
1684 DEF_IPUT(4, Instruction::IPUT, 1u, 0u, 0u),
1685 DEF_CONST(5, Instruction::CONST, 3u, 2000),
1686 DEF_IPUT(5, Instruction::IPUT, 3u, 0u, 0u),
1687 DEF_IGET(6, Instruction::IGET, 5u, 0u, 0u),
1688 };
1689
1690 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2 /* dummy */, 1, 2 /* dummy */, 1 };
1691 PrepareSRegToVRegMap(sreg_to_vreg_map);
1692
1693 PrepareIFields(ifields);
1694 PrepareMIRs(mirs);
1695 PerformGVN_DCE();
1696
1697 ASSERT_EQ(arraysize(mirs), value_names_.size());
1698 static const size_t diff_indexes[] = { 0, 1, 3, 5 };
1699 ExpectValueNamesNE(diff_indexes);
1700
1701 const size_t no_null_ck_indexes[] = { 2, 4, 5 };
1702 ExpectNoNullCheck(no_null_ck_indexes);
1703
1704 static const bool eliminated[] = {
1705 false, false, false, false, false, true,
1706 };
1707 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1708 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1709 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1710 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1711 }
1712 // Check that we've created a two-input Phi to replace the IGET 5u.
1713 BasicBlock* bb6 = cu_.mir_graph->GetBasicBlock(6);
1714 MIR* phi = bb6->first_mir_insn;
1715 ASSERT_TRUE(phi != nullptr);
1716 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi->dalvikInsn.opcode));
1717 ASSERT_EQ(2, phi->ssa_rep->num_uses);
1718 EXPECT_EQ(1, phi->ssa_rep->uses[0]);
1719 EXPECT_EQ(3, phi->ssa_rep->uses[1]);
1720 ASSERT_EQ(1, phi->ssa_rep->num_defs);
1721 EXPECT_EQ(5, phi->ssa_rep->defs[0]);
1722 EXPECT_EQ(1u, phi->dalvikInsn.vA);
1723}
1724
1725TEST_F(GvnDeadCodeEliminationTestDiamond, KillChainInAnotherBlock1) {
1726 static const IFieldDef ifields[] = {
1727 { 0u, 1u, 0u, false, kDexMemAccessObject }, // linked list
1728 };
1729 static const MIRDef mirs[] = {
1730 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1731 DEF_IGET(3, Instruction::IGET_OBJECT, 1u, 0u, 0u),
1732 DEF_IGET(3, Instruction::IGET_OBJECT, 2u, 1u, 0u),
1733 DEF_IGET(3, Instruction::IGET_OBJECT, 3u, 2u, 0u),
1734 DEF_IGET(3, Instruction::IGET_OBJECT, 4u, 3u, 0u),
1735 DEF_IFZ(3, Instruction::IF_NEZ, 4u),
1736 DEF_IGET(4, Instruction::IGET_OBJECT, 6u, 0u, 0u),
1737 DEF_IGET(4, Instruction::IGET_OBJECT, 7u, 6u, 0u),
1738 DEF_IGET(4, Instruction::IGET_OBJECT, 8u, 7u, 0u),
1739 DEF_IGET(4, Instruction::IGET_OBJECT, 9u, 8u, 0u),
1740 };
1741
1742 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 1, 2, 3 /* dummy */, 1, 2, 1, 2 };
1743 PrepareSRegToVRegMap(sreg_to_vreg_map);
1744
1745 PrepareIFields(ifields);
1746 PrepareMIRs(mirs);
1747 PerformGVN_DCE();
1748
1749 ASSERT_EQ(arraysize(mirs), value_names_.size());
1750 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4 };
1751 ExpectValueNamesNE(diff_indexes);
1752 EXPECT_EQ(value_names_[1], value_names_[6]);
1753 EXPECT_EQ(value_names_[2], value_names_[7]);
1754 EXPECT_EQ(value_names_[3], value_names_[8]);
1755 EXPECT_EQ(value_names_[4], value_names_[9]);
1756
1757 const size_t no_null_ck_indexes[] = { 1, 6, 7, 8, 9 };
1758 ExpectNoNullCheck(no_null_ck_indexes);
1759
1760 static const bool eliminated[] = {
1761 false, false, false, false, false, false, true, true, true, true,
1762 };
1763 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1764 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1765 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1766 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1767 }
1768 // Check that we've created two single-input Phis to replace the IGET 8u and IGET 9u;
1769 // the IGET 6u and IGET 7u were killed without a replacement.
1770 BasicBlock* bb4 = cu_.mir_graph->GetBasicBlock(4);
1771 MIR* phi1 = bb4->first_mir_insn;
1772 ASSERT_TRUE(phi1 != nullptr);
1773 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi1->dalvikInsn.opcode));
1774 MIR* phi2 = phi1->next;
1775 ASSERT_TRUE(phi2 != nullptr);
1776 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi2->dalvikInsn.opcode));
1777 ASSERT_TRUE(phi2->next == &mirs_[6]);
1778 if (phi1->dalvikInsn.vA == 2u) {
1779 std::swap(phi1, phi2);
1780 }
1781 ASSERT_EQ(1, phi1->ssa_rep->num_uses);
1782 EXPECT_EQ(3, phi1->ssa_rep->uses[0]);
1783 ASSERT_EQ(1, phi1->ssa_rep->num_defs);
1784 EXPECT_EQ(8, phi1->ssa_rep->defs[0]);
1785 EXPECT_EQ(1u, phi1->dalvikInsn.vA);
1786 ASSERT_EQ(1, phi2->ssa_rep->num_uses);
1787 EXPECT_EQ(4, phi2->ssa_rep->uses[0]);
1788 ASSERT_EQ(1, phi2->ssa_rep->num_defs);
1789 EXPECT_EQ(9, phi2->ssa_rep->defs[0]);
1790 EXPECT_EQ(2u, phi2->dalvikInsn.vA);
1791}
1792
1793TEST_F(GvnDeadCodeEliminationTestDiamond, KillChainInAnotherBlock2) {
1794 static const IFieldDef ifields[] = {
1795 { 0u, 1u, 0u, false, kDexMemAccessObject }, // linked list
1796 };
1797 static const MIRDef mirs[] = {
1798 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1799 DEF_IGET(3, Instruction::IGET_OBJECT, 1u, 0u, 0u),
1800 DEF_IGET(3, Instruction::IGET_OBJECT, 2u, 1u, 0u),
1801 DEF_IGET(3, Instruction::IGET_OBJECT, 3u, 2u, 0u),
1802 DEF_IGET(3, Instruction::IGET_OBJECT, 4u, 3u, 0u),
1803 DEF_IFZ(3, Instruction::IF_NEZ, 4u),
1804 DEF_IGET(4, Instruction::IGET_OBJECT, 6u, 0u, 0u),
1805 DEF_IGET(4, Instruction::IGET_OBJECT, 7u, 6u, 0u),
1806 DEF_IGET(4, Instruction::IGET_OBJECT, 8u, 7u, 0u),
1807 DEF_CONST(4, Instruction::CONST, 9u, 1000),
1808 };
1809
1810 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 1, 2, 3 /* dummy */, 1, 2, 1, 2 };
1811 PrepareSRegToVRegMap(sreg_to_vreg_map);
1812
1813 PrepareIFields(ifields);
1814 PrepareMIRs(mirs);
1815 PerformGVN_DCE();
1816
1817 ASSERT_EQ(arraysize(mirs), value_names_.size());
1818 static const size_t diff_indexes[] = { 0, 1, 2, 3, 4, 9 };
1819 ExpectValueNamesNE(diff_indexes);
1820 EXPECT_EQ(value_names_[1], value_names_[6]);
1821 EXPECT_EQ(value_names_[2], value_names_[7]);
1822 EXPECT_EQ(value_names_[3], value_names_[8]);
1823
1824 const size_t no_null_ck_indexes[] = { 1, 6, 7, 8 };
1825 ExpectNoNullCheck(no_null_ck_indexes);
1826
1827 static const bool eliminated[] = {
1828 false, false, false, false, false, false, true, true, true, false,
1829 };
1830 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1831 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1832 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1833 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1834 }
1835 // Check that we've created a single-input Phi to replace the IGET 8u;
1836 // the IGET 6u and IGET 7u were killed without a replacement.
1837 BasicBlock* bb4 = cu_.mir_graph->GetBasicBlock(4);
1838 MIR* phi = bb4->first_mir_insn;
1839 ASSERT_TRUE(phi != nullptr);
1840 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi->dalvikInsn.opcode));
1841 ASSERT_TRUE(phi->next == &mirs_[6]);
1842 ASSERT_EQ(1, phi->ssa_rep->num_uses);
1843 EXPECT_EQ(3, phi->ssa_rep->uses[0]);
1844 ASSERT_EQ(1, phi->ssa_rep->num_defs);
1845 EXPECT_EQ(8, phi->ssa_rep->defs[0]);
1846 EXPECT_EQ(1u, phi->dalvikInsn.vA);
1847}
1848
1849TEST_F(GvnDeadCodeEliminationTestLoop, IFieldLoopVariable) {
1850 static const IFieldDef ifields[] = {
1851 { 0u, 1u, 0u, false, kDexMemAccessWord },
1852 };
1853 static const MIRDef mirs[] = {
1854 DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 0u),
1855 DEF_CONST(3, Instruction::CONST, 1u, 1),
1856 DEF_CONST(3, Instruction::CONST, 2u, 0),
1857 DEF_IPUT(3, Instruction::IPUT, 2u, 0u, 0u),
1858 DEF_IGET(4, Instruction::IGET, 4u, 0u, 0u),
1859 DEF_BINOP(4, Instruction::ADD_INT, 5u, 4u, 1u),
1860 DEF_IPUT(4, Instruction::IPUT, 5u, 0u, 0u),
1861 };
1862
1863 static const int32_t sreg_to_vreg_map[] = { 0, 1, 2, 3 /* dummy */, 2, 2 };
1864 PrepareSRegToVRegMap(sreg_to_vreg_map);
1865
1866 PrepareIFields(ifields);
1867 PrepareMIRs(mirs);
1868 PerformGVN_DCE();
1869
1870 ASSERT_EQ(arraysize(mirs), value_names_.size());
1871 static const size_t diff_indexes[] = { 0, 1, 2, 4, 5 };
1872 ExpectValueNamesNE(diff_indexes);
1873
1874 const size_t no_null_ck_indexes[] = { 3, 4, 6 };
1875 ExpectNoNullCheck(no_null_ck_indexes);
1876
1877 static const bool eliminated[] = {
1878 false, false, false, false, true, false, false,
1879 };
1880 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1881 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1882 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1883 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1884 }
1885 // Check that we've created a two-input Phi to replace the IGET 3u.
1886 BasicBlock* bb4 = cu_.mir_graph->GetBasicBlock(4);
1887 MIR* phi = bb4->first_mir_insn;
1888 ASSERT_TRUE(phi != nullptr);
1889 ASSERT_EQ(kMirOpPhi, static_cast<int>(phi->dalvikInsn.opcode));
1890 ASSERT_TRUE(phi->next == &mirs_[4]);
1891 ASSERT_EQ(2, phi->ssa_rep->num_uses);
1892 EXPECT_EQ(2, phi->ssa_rep->uses[0]);
1893 EXPECT_EQ(5, phi->ssa_rep->uses[1]);
1894 ASSERT_EQ(1, phi->ssa_rep->num_defs);
1895 EXPECT_EQ(4, phi->ssa_rep->defs[0]);
1896 EXPECT_EQ(2u, phi->dalvikInsn.vA);
1897}
1898
Vladimir Marko83d46ef2015-05-12 18:27:20 +01001899TEST_F(GvnDeadCodeEliminationTestDiamond, LongOverlaps1) {
1900 static const MIRDef mirs[] = {
1901 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 0u, 1000u),
1902 DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 2u, 1000u),
1903 DEF_MOVE_WIDE(4, Instruction::MOVE_WIDE, 4u, 0u),
1904 DEF_MOVE_WIDE(4, Instruction::MOVE_WIDE, 6u, 2u),
1905 DEF_MOVE_WIDE(4, Instruction::MOVE_WIDE, 8u, 4u),
1906 DEF_MOVE_WIDE(4, Instruction::MOVE_WIDE, 10u, 6u),
1907 };
1908
1909 // The last insn should overlap the first and second.
1910 static const int32_t sreg_to_vreg_map[] = { 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3 };
1911 PrepareSRegToVRegMap(sreg_to_vreg_map);
1912
1913 PrepareMIRs(mirs);
1914 static const int32_t wide_sregs[] = { 0, 2, 4, 6, 8, 10 };
1915 MarkAsWideSRegs(wide_sregs);
1916 PerformGVN_DCE();
1917
1918 ASSERT_EQ(arraysize(mirs), value_names_.size());
1919 EXPECT_EQ(value_names_[0], value_names_[1]);
1920 EXPECT_EQ(value_names_[0], value_names_[2]);
1921 EXPECT_EQ(value_names_[0], value_names_[3]);
1922 EXPECT_EQ(value_names_[0], value_names_[4]);
1923
1924 static const bool eliminated[] = {
1925 false, false, false, false, false, false,
1926 };
1927 static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
1928 for (size_t i = 0; i != arraysize(eliminated); ++i) {
1929 bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
1930 EXPECT_EQ(eliminated[i], actually_eliminated) << i;
1931 }
1932}
1933
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001934} // namespace art