blob: a4319c3dc535148813122f94ec5c9d4b7fbb9115 [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 <sstream>
18
19#include "gvn_dead_code_elimination.h"
20
21#include "base/bit_vector-inl.h"
22#include "base/macros.h"
23#include "compiler_enums.h"
24#include "dataflow_iterator-inl.h"
25#include "dex_instruction.h"
26#include "dex/mir_graph.h"
27#include "local_value_numbering.h"
28#include "utils/arena_bit_vector.h"
29
30namespace art {
31
32constexpr uint16_t GvnDeadCodeElimination::kNoValue;
33constexpr uint16_t GvnDeadCodeElimination::kNPos;
34
35inline uint16_t GvnDeadCodeElimination::MIRData::PrevChange(int v_reg) const {
36 DCHECK(has_def);
37 DCHECK(v_reg == vreg_def || v_reg == vreg_def + 1);
38 return (v_reg == vreg_def) ? prev_value.change : prev_value_high.change;
39}
40
41inline void GvnDeadCodeElimination::MIRData::SetPrevChange(int v_reg, uint16_t change) {
42 DCHECK(has_def);
43 DCHECK(v_reg == vreg_def || v_reg == vreg_def + 1);
44 if (v_reg == vreg_def) {
45 prev_value.change = change;
46 } else {
47 prev_value_high.change = change;
48 }
49}
50
51inline void GvnDeadCodeElimination::MIRData::RemovePrevChange(int v_reg, MIRData* prev_data) {
52 DCHECK_NE(PrevChange(v_reg), kNPos);
53 DCHECK(v_reg == prev_data->vreg_def || v_reg == prev_data->vreg_def + 1);
54 if (vreg_def == v_reg) {
55 if (prev_data->vreg_def == v_reg) {
56 prev_value = prev_data->prev_value;
57 low_def_over_high_word = prev_data->low_def_over_high_word;
58 } else {
59 prev_value = prev_data->prev_value_high;
60 low_def_over_high_word =
61 prev_data->prev_value_high.value != kNPos && !prev_data->high_def_over_low_word;
62 }
63 } else {
64 if (prev_data->vreg_def == v_reg) {
65 prev_value_high = prev_data->prev_value;
66 high_def_over_low_word =
67 prev_data->prev_value.value != kNPos && !prev_data->low_def_over_high_word;
68 } else {
69 prev_value_high = prev_data->prev_value_high;
70 high_def_over_low_word = prev_data->high_def_over_low_word;
71 }
72 }
73}
74
75GvnDeadCodeElimination::VRegChains::VRegChains(uint32_t num_vregs, ScopedArenaAllocator* alloc)
76 : num_vregs_(num_vregs),
77 vreg_data_(alloc->AllocArray<VRegValue>(num_vregs, kArenaAllocMisc)),
78 mir_data_(alloc->Adapter()) {
79 mir_data_.reserve(100);
80}
81
82inline void GvnDeadCodeElimination::VRegChains::Reset() {
83 DCHECK(mir_data_.empty());
84 std::fill_n(vreg_data_, num_vregs_, VRegValue());
85}
86
87void GvnDeadCodeElimination::VRegChains::AddMIRWithDef(MIR* mir, int v_reg, bool wide,
88 uint16_t new_value) {
89 uint16_t pos = mir_data_.size();
90 mir_data_.emplace_back(mir);
91 MIRData* data = &mir_data_.back();
92 data->has_def = true;
93 data->wide_def = wide;
94 data->vreg_def = v_reg;
95
96 if (vreg_data_[v_reg].change != kNPos &&
97 mir_data_[vreg_data_[v_reg].change].vreg_def + 1 == v_reg) {
98 data->low_def_over_high_word = true;
99 }
100 data->prev_value = vreg_data_[v_reg];
101 DCHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
102 vreg_data_[v_reg].value = new_value;
103 vreg_data_[v_reg].change = pos;
104
105 if (wide) {
106 if (vreg_data_[v_reg + 1].change != kNPos &&
107 mir_data_[vreg_data_[v_reg + 1].change].vreg_def == v_reg + 1) {
108 data->high_def_over_low_word = true;
109 }
110 data->prev_value_high = vreg_data_[v_reg + 1];
111 DCHECK_LT(static_cast<size_t>(v_reg + 1), num_vregs_);
112 vreg_data_[v_reg + 1].value = new_value;
113 vreg_data_[v_reg + 1].change = pos;
114 }
115}
116
117inline void GvnDeadCodeElimination::VRegChains::AddMIRWithoutDef(MIR* mir) {
118 mir_data_.emplace_back(mir);
119}
120
121void GvnDeadCodeElimination::VRegChains::RemoveLastMIRData() {
122 MIRData* data = LastMIRData();
123 if (data->has_def) {
124 DCHECK_EQ(vreg_data_[data->vreg_def].change, NumMIRs() - 1u);
125 vreg_data_[data->vreg_def] = data->prev_value;
126 if (data->wide_def) {
127 DCHECK_EQ(vreg_data_[data->vreg_def + 1].change, NumMIRs() - 1u);
128 vreg_data_[data->vreg_def + 1] = data->prev_value_high;
129 }
130 }
131 mir_data_.pop_back();
132}
133
134void GvnDeadCodeElimination::VRegChains::RemoveTrailingNops() {
135 // There's at least one NOP to drop. There may be more.
136 MIRData* last_data = LastMIRData();
137 DCHECK(!last_data->must_keep && !last_data->has_def);
138 do {
139 DCHECK_EQ(static_cast<int>(last_data->mir->dalvikInsn.opcode), static_cast<int>(kMirOpNop));
140 mir_data_.pop_back();
141 if (mir_data_.empty()) {
142 break;
143 }
144 last_data = LastMIRData();
145 } while (!last_data->must_keep && !last_data->has_def);
146}
147
148inline size_t GvnDeadCodeElimination::VRegChains::NumMIRs() const {
149 return mir_data_.size();
150}
151
152inline GvnDeadCodeElimination::MIRData* GvnDeadCodeElimination::VRegChains::GetMIRData(size_t pos) {
153 DCHECK_LT(pos, mir_data_.size());
154 return &mir_data_[pos];
155}
156
157inline GvnDeadCodeElimination::MIRData* GvnDeadCodeElimination::VRegChains::LastMIRData() {
158 DCHECK(!mir_data_.empty());
159 return &mir_data_.back();
160}
161
162uint32_t GvnDeadCodeElimination::VRegChains::NumVRegs() const {
163 return num_vregs_;
164}
165
166void GvnDeadCodeElimination::VRegChains::InsertInitialValueHigh(int v_reg, uint16_t value) {
167 DCHECK_NE(value, kNoValue);
168 DCHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
169 uint16_t change = vreg_data_[v_reg].change;
170 if (change == kNPos) {
171 vreg_data_[v_reg].value = value;
172 } else {
173 while (true) {
174 MIRData* data = &mir_data_[change];
175 DCHECK(data->vreg_def == v_reg || data->vreg_def + 1 == v_reg);
176 if (data->vreg_def == v_reg) { // Low word, use prev_value.
177 if (data->prev_value.change == kNPos) {
178 DCHECK_EQ(data->prev_value.value, kNoValue);
179 data->prev_value.value = value;
180 data->low_def_over_high_word = true;
181 break;
182 }
183 change = data->prev_value.change;
184 } else { // High word, use prev_value_high.
185 if (data->prev_value_high.change == kNPos) {
186 DCHECK_EQ(data->prev_value_high.value, kNoValue);
187 data->prev_value_high.value = value;
188 break;
189 }
190 change = data->prev_value_high.change;
191 }
192 }
193 }
194}
195
196void GvnDeadCodeElimination::VRegChains::UpdateInitialVRegValue(int v_reg, bool wide,
197 const LocalValueNumbering* lvn) {
198 DCHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
199 if (!wide) {
200 if (vreg_data_[v_reg].value == kNoValue) {
201 uint16_t old_value = lvn->GetStartingVregValueNumber(v_reg);
202 if (old_value == kNoValue) {
203 // Maybe there was a wide value in v_reg before. Do not check for wide value in v_reg-1,
204 // that will be done only if we see a definition of v_reg-1, otherwise it's unnecessary.
205 old_value = lvn->GetStartingVregValueNumberWide(v_reg);
206 if (old_value != kNoValue) {
207 InsertInitialValueHigh(v_reg + 1, old_value);
208 }
209 }
210 vreg_data_[v_reg].value = old_value;
211 }
212 } else {
213 DCHECK_LT(static_cast<size_t>(v_reg + 1), num_vregs_);
214 bool check_high = true;
215 if (vreg_data_[v_reg].value == kNoValue) {
216 uint16_t old_value = lvn->GetStartingVregValueNumberWide(v_reg);
217 if (old_value != kNoValue) {
218 InsertInitialValueHigh(v_reg + 1, old_value);
219 check_high = false; // High word has been processed.
220 } else {
221 // Maybe there was a narrow value before. Do not check for wide value in v_reg-1,
222 // that will be done only if we see a definition of v_reg-1, otherwise it's unnecessary.
223 old_value = lvn->GetStartingVregValueNumber(v_reg);
224 }
225 vreg_data_[v_reg].value = old_value;
226 }
227 if (check_high && vreg_data_[v_reg + 1].value == kNoValue) {
228 uint16_t old_value = lvn->GetStartingVregValueNumber(v_reg + 1);
229 if (old_value == kNoValue && static_cast<size_t>(v_reg + 2) < num_vregs_) {
230 // Maybe there was a wide value before.
231 old_value = lvn->GetStartingVregValueNumberWide(v_reg + 1);
232 if (old_value != kNoValue) {
233 InsertInitialValueHigh(v_reg + 2, old_value);
234 }
235 }
236 vreg_data_[v_reg + 1].value = old_value;
237 }
238 }
239}
240
241inline uint16_t GvnDeadCodeElimination::VRegChains::LastChange(int v_reg) {
242 DCHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
243 return vreg_data_[v_reg].change;
244}
245
246inline uint16_t GvnDeadCodeElimination::VRegChains::CurrentValue(int v_reg) {
247 DCHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
248 return vreg_data_[v_reg].value;
249}
250
251uint16_t GvnDeadCodeElimination::VRegChains::FindKillHead(int v_reg, uint16_t cutoff) {
252 uint16_t current_value = this->CurrentValue(v_reg);
253 DCHECK_NE(current_value, kNoValue);
254 uint16_t change = LastChange(v_reg);
255 DCHECK_LT(change, mir_data_.size());
256 DCHECK_GE(change, cutoff);
257 bool match_high_word = (mir_data_[change].vreg_def != v_reg);
258 do {
259 MIRData* data = &mir_data_[change];
260 DCHECK(data->vreg_def == v_reg || data->vreg_def + 1 == v_reg);
261 if (data->vreg_def == v_reg) { // Low word, use prev_value.
262 if (data->prev_value.value == current_value &&
263 match_high_word == data->low_def_over_high_word) {
264 break;
265 }
266 change = data->prev_value.change;
267 } else { // High word, use prev_value_high.
268 if (data->prev_value_high.value == current_value &&
269 match_high_word != data->high_def_over_low_word) {
270 break;
271 }
272 change = data->prev_value_high.change;
273 }
274 if (change < cutoff) {
275 change = kNPos;
276 }
277 } while (change != kNPos);
278 return change;
279}
280
281uint16_t GvnDeadCodeElimination::VRegChains::FindFirstChangeAfter(int v_reg,
282 uint16_t change) const {
283 DCHECK_LT(static_cast<size_t>(v_reg), num_vregs_);
284 DCHECK_LT(change, mir_data_.size());
285 uint16_t result = kNPos;
286 uint16_t search_change = vreg_data_[v_reg].change;
287 while (search_change != kNPos && search_change > change) {
288 result = search_change;
289 search_change = mir_data_[search_change].PrevChange(v_reg);
290 }
291 return result;
292}
293
294void GvnDeadCodeElimination::VRegChains::ReplaceChange(uint16_t old_change, uint16_t new_change) {
295 const MIRData* old_data = GetMIRData(old_change);
296 DCHECK(old_data->has_def);
297 int count = old_data->wide_def ? 2 : 1;
298 for (int v_reg = old_data->vreg_def, end = old_data->vreg_def + count; v_reg != end; ++v_reg) {
299 uint16_t next_change = FindFirstChangeAfter(v_reg, old_change);
300 if (next_change == kNPos) {
301 DCHECK_EQ(vreg_data_[v_reg].change, old_change);
302 vreg_data_[v_reg].change = new_change;
303 } else {
304 DCHECK_EQ(mir_data_[next_change].PrevChange(v_reg), old_change);
305 mir_data_[next_change].SetPrevChange(v_reg, new_change);
306 }
307 }
308}
309
310void GvnDeadCodeElimination::VRegChains::RemoveChange(uint16_t change) {
311 MIRData* data = &mir_data_[change];
312 DCHECK(data->has_def);
313 int count = data->wide_def ? 2 : 1;
314 for (int v_reg = data->vreg_def, end = data->vreg_def + count; v_reg != end; ++v_reg) {
315 uint16_t next_change = FindFirstChangeAfter(v_reg, change);
316 if (next_change == kNPos) {
317 DCHECK_EQ(vreg_data_[v_reg].change, change);
318 vreg_data_[v_reg] = (data->vreg_def == v_reg) ? data->prev_value : data->prev_value_high;
319 } else {
320 DCHECK_EQ(mir_data_[next_change].PrevChange(v_reg), change);
321 mir_data_[next_change].RemovePrevChange(v_reg, data);
322 }
323 }
324}
325
326inline bool GvnDeadCodeElimination::VRegChains::IsTopChange(uint16_t change) const {
327 DCHECK_LT(change, mir_data_.size());
328 const MIRData* data = &mir_data_[change];
329 DCHECK(data->has_def);
330 DCHECK_LT(data->wide_def ? data->vreg_def + 1u : data->vreg_def, num_vregs_);
331 return vreg_data_[data->vreg_def].change == change &&
332 (!data->wide_def || vreg_data_[data->vreg_def + 1u].change == change);
333}
334
335bool GvnDeadCodeElimination::VRegChains::IsSRegUsed(uint16_t first_change, uint16_t last_change,
336 int s_reg) const {
337 DCHECK_LE(first_change, last_change);
338 DCHECK_LE(last_change, mir_data_.size());
339 for (size_t c = first_change; c != last_change; ++c) {
340 SSARepresentation* ssa_rep = mir_data_[c].mir->ssa_rep;
341 for (int i = 0; i != ssa_rep->num_uses; ++i) {
342 if (ssa_rep->uses[i] == s_reg) {
343 return true;
344 }
345 }
346 }
347 return false;
348}
349
Vladimir Markoad677272015-04-20 10:48:13 +0100350bool GvnDeadCodeElimination::VRegChains::IsVRegUsed(uint16_t first_change, uint16_t last_change,
351 int v_reg, MIRGraph* mir_graph) const {
352 DCHECK_LE(first_change, last_change);
353 DCHECK_LE(last_change, mir_data_.size());
354 for (size_t c = first_change; c != last_change; ++c) {
355 SSARepresentation* ssa_rep = mir_data_[c].mir->ssa_rep;
356 for (int i = 0; i != ssa_rep->num_uses; ++i) {
357 if (mir_graph->SRegToVReg(ssa_rep->uses[i]) == v_reg) {
358 return true;
359 }
360 }
361 }
362 return false;
363}
364
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000365void GvnDeadCodeElimination::VRegChains::RenameSRegUses(uint16_t first_change, uint16_t last_change,
366 int old_s_reg, int new_s_reg, bool wide) {
367 for (size_t c = first_change; c != last_change; ++c) {
368 SSARepresentation* ssa_rep = mir_data_[c].mir->ssa_rep;
369 for (int i = 0; i != ssa_rep->num_uses; ++i) {
370 if (ssa_rep->uses[i] == old_s_reg) {
371 ssa_rep->uses[i] = new_s_reg;
372 if (wide) {
373 ++i;
374 DCHECK_LT(i, ssa_rep->num_uses);
375 ssa_rep->uses[i] = new_s_reg + 1;
376 }
377 }
378 }
379 }
380}
381
382void GvnDeadCodeElimination::VRegChains::RenameVRegUses(uint16_t first_change, uint16_t last_change,
383 int old_s_reg, int old_v_reg,
384 int new_s_reg, int new_v_reg) {
385 for (size_t c = first_change; c != last_change; ++c) {
386 MIR* mir = mir_data_[c].mir;
387 if (IsInstructionBinOp2Addr(mir->dalvikInsn.opcode) &&
388 mir->ssa_rep->uses[0] == old_s_reg && old_v_reg != new_v_reg) {
389 // Rewrite binop_2ADDR with plain binop before doing the register rename.
390 ChangeBinOp2AddrToPlainBinOp(mir);
391 }
392 uint64_t df_attr = MIRGraph::GetDataFlowAttributes(mir);
393 size_t use = 0u;
394#define REPLACE_VREG(REG) \
395 if ((df_attr & DF_U##REG) != 0) { \
396 if (mir->ssa_rep->uses[use] == old_s_reg) { \
397 DCHECK_EQ(mir->dalvikInsn.v##REG, static_cast<uint32_t>(old_v_reg)); \
398 mir->dalvikInsn.v##REG = new_v_reg; \
399 mir->ssa_rep->uses[use] = new_s_reg; \
400 if ((df_attr & DF_##REG##_WIDE) != 0) { \
401 DCHECK_EQ(mir->ssa_rep->uses[use + 1], old_s_reg + 1); \
402 mir->ssa_rep->uses[use + 1] = new_s_reg + 1; \
403 } \
404 } \
405 use += ((df_attr & DF_##REG##_WIDE) != 0) ? 2 : 1; \
406 }
407 REPLACE_VREG(A)
408 REPLACE_VREG(B)
409 REPLACE_VREG(C)
410#undef REPLACE_VREG
411 // We may encounter an out-of-order Phi which we need to ignore, otherwise we should
412 // only be asked to rename registers specified by DF_UA, DF_UB and DF_UC.
413 DCHECK_EQ(use,
414 static_cast<int>(mir->dalvikInsn.opcode) == kMirOpPhi
415 ? 0u
416 : static_cast<size_t>(mir->ssa_rep->num_uses));
417 }
418}
419
420GvnDeadCodeElimination::GvnDeadCodeElimination(const GlobalValueNumbering* gvn,
421 ScopedArenaAllocator* alloc)
422 : gvn_(gvn),
423 mir_graph_(gvn_->GetMirGraph()),
424 vreg_chains_(mir_graph_->GetNumOfCodeAndTempVRs(), alloc),
425 bb_(nullptr),
426 lvn_(nullptr),
427 no_uses_all_since_(0u),
428 unused_vregs_(new (alloc) ArenaBitVector(alloc, vreg_chains_.NumVRegs(), false)),
429 vregs_to_kill_(new (alloc) ArenaBitVector(alloc, vreg_chains_.NumVRegs(), false)),
430 kill_heads_(alloc->AllocArray<uint16_t>(vreg_chains_.NumVRegs(), kArenaAllocMisc)),
431 changes_to_kill_(alloc->Adapter()),
432 dependent_vregs_(new (alloc) ArenaBitVector(alloc, vreg_chains_.NumVRegs(), false)) {
433 changes_to_kill_.reserve(16u);
434}
435
436void GvnDeadCodeElimination::Apply(BasicBlock* bb) {
437 bb_ = bb;
438 lvn_ = gvn_->GetLvn(bb->id);
439
440 RecordPass();
441 BackwardPass();
442
443 DCHECK_EQ(no_uses_all_since_, 0u);
444 lvn_ = nullptr;
445 bb_ = nullptr;
446}
447
448void GvnDeadCodeElimination::RecordPass() {
449 // Record MIRs with vreg definition data, eliminate single instructions.
450 vreg_chains_.Reset();
451 DCHECK_EQ(no_uses_all_since_, 0u);
452 for (MIR* mir = bb_->first_mir_insn; mir != nullptr; mir = mir->next) {
453 if (RecordMIR(mir)) {
454 RecordPassTryToKillOverwrittenMoveOrMoveSrc();
455 RecordPassTryToKillLastMIR();
456 }
457 }
458}
459
460void GvnDeadCodeElimination::BackwardPass() {
461 // Now process MIRs in reverse order, trying to eliminate them.
462 unused_vregs_->ClearAllBits(); // Implicitly depend on all vregs at the end of BB.
463 while (vreg_chains_.NumMIRs() != 0u) {
464 if (BackwardPassTryToKillLastMIR()) {
465 continue;
466 }
467 BackwardPassProcessLastMIR();
468 }
469}
470
471void GvnDeadCodeElimination::KillMIR(MIRData* data) {
472 DCHECK(!data->must_keep);
473 DCHECK(!data->uses_all_vregs);
474 DCHECK(data->has_def);
475 DCHECK(data->mir->ssa_rep->num_defs == 1 || data->mir->ssa_rep->num_defs == 2);
476
477 KillMIR(data->mir);
478 data->has_def = false;
479 data->is_move = false;
480 data->is_move_src = false;
481}
482
483void GvnDeadCodeElimination::KillMIR(MIR* mir) {
484 mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
485 mir->ssa_rep->num_uses = 0;
486 mir->ssa_rep->num_defs = 0;
487}
488
489void GvnDeadCodeElimination::ChangeBinOp2AddrToPlainBinOp(MIR* mir) {
490 mir->dalvikInsn.vC = mir->dalvikInsn.vB;
491 mir->dalvikInsn.vB = mir->dalvikInsn.vA;
492 mir->dalvikInsn.opcode = static_cast<Instruction::Code>(
493 mir->dalvikInsn.opcode - Instruction::ADD_INT_2ADDR + Instruction::ADD_INT);
494}
495
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000496MIR* GvnDeadCodeElimination::CreatePhi(int s_reg) {
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000497 int v_reg = mir_graph_->SRegToVReg(s_reg);
498 MIR* phi = mir_graph_->NewMIR();
499 phi->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpPhi);
500 phi->dalvikInsn.vA = v_reg;
501 phi->offset = bb_->start_offset;
502 phi->m_unit_index = 0; // Arbitrarily assign all Phi nodes to outermost method.
503
504 phi->ssa_rep = static_cast<struct SSARepresentation *>(mir_graph_->GetArena()->Alloc(
505 sizeof(SSARepresentation), kArenaAllocDFInfo));
506
507 mir_graph_->AllocateSSADefData(phi, 1);
508 phi->ssa_rep->defs[0] = s_reg;
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000509
510 size_t num_uses = bb_->predecessors.size();
511 mir_graph_->AllocateSSAUseData(phi, num_uses);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000512 size_t idx = 0u;
513 for (BasicBlockId pred_id : bb_->predecessors) {
514 BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_id);
515 DCHECK(pred_bb != nullptr);
516 phi->ssa_rep->uses[idx] = pred_bb->data_flow_info->vreg_to_ssa_map_exit[v_reg];
517 DCHECK_NE(phi->ssa_rep->uses[idx], INVALID_SREG);
518 idx++;
519 }
520
521 phi->meta.phi_incoming = static_cast<BasicBlockId*>(mir_graph_->GetArena()->Alloc(
522 sizeof(BasicBlockId) * num_uses, kArenaAllocDFInfo));
523 std::copy(bb_->predecessors.begin(), bb_->predecessors.end(), phi->meta.phi_incoming);
524 bb_->PrependMIR(phi);
525 return phi;
526}
527
528MIR* GvnDeadCodeElimination::RenameSRegDefOrCreatePhi(uint16_t def_change, uint16_t last_change,
529 MIR* mir_to_kill) {
530 DCHECK(mir_to_kill->ssa_rep->num_defs == 1 || mir_to_kill->ssa_rep->num_defs == 2);
531 bool wide = (mir_to_kill->ssa_rep->num_defs != 1);
532 int new_s_reg = mir_to_kill->ssa_rep->defs[0];
533
534 // Just before we kill mir_to_kill, we need to replace the previous SSA reg assigned to the
535 // same dalvik reg to keep consistency with subsequent instructions. However, if there's no
Vladimir Markof60715c2015-05-07 15:53:41 +0100536 // defining MIR for that dalvik reg, the preserved values must come from its predecessors
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000537 // and we need to create a new Phi (a degenerate Phi if there's only a single predecessor).
538 if (def_change == kNPos) {
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000539 if (wide) {
540 DCHECK_EQ(new_s_reg + 1, mir_to_kill->ssa_rep->defs[1]);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000541 DCHECK_EQ(mir_graph_->SRegToVReg(new_s_reg) + 1, mir_graph_->SRegToVReg(new_s_reg + 1));
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000542 CreatePhi(new_s_reg + 1); // High word Phi.
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000543 }
Vladimir Markof60715c2015-05-07 15:53:41 +0100544 MIR* phi = CreatePhi(new_s_reg);
545 // If this is a degenerate Phi with all inputs being the same SSA reg, we need to its uses.
546 DCHECK_NE(phi->ssa_rep->num_uses, 0u);
547 int old_s_reg = phi->ssa_rep->uses[0];
548 bool all_same = true;
549 for (size_t i = 1u, num = phi->ssa_rep->num_uses; i != num; ++i) {
550 if (phi->ssa_rep->uses[i] != old_s_reg) {
551 all_same = false;
552 break;
553 }
554 }
555 if (all_same) {
556 vreg_chains_.RenameSRegUses(0u, last_change, old_s_reg, new_s_reg, wide);
557 }
558 return phi;
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000559 } else {
560 DCHECK_LT(def_change, last_change);
561 DCHECK_LE(last_change, vreg_chains_.NumMIRs());
562 MIRData* def_data = vreg_chains_.GetMIRData(def_change);
563 DCHECK(def_data->has_def);
564 int old_s_reg = def_data->mir->ssa_rep->defs[0];
565 DCHECK_NE(old_s_reg, new_s_reg);
566 DCHECK_EQ(mir_graph_->SRegToVReg(old_s_reg), mir_graph_->SRegToVReg(new_s_reg));
567 def_data->mir->ssa_rep->defs[0] = new_s_reg;
568 if (wide) {
569 if (static_cast<int>(def_data->mir->dalvikInsn.opcode) == kMirOpPhi) {
570 // Currently the high word Phi is always located after the low word Phi.
571 MIR* phi_high = def_data->mir->next;
572 DCHECK(phi_high != nullptr && static_cast<int>(phi_high->dalvikInsn.opcode) == kMirOpPhi);
573 DCHECK_EQ(phi_high->ssa_rep->defs[0], old_s_reg + 1);
574 phi_high->ssa_rep->defs[0] = new_s_reg + 1;
575 } else {
576 DCHECK_EQ(def_data->mir->ssa_rep->defs[1], old_s_reg + 1);
577 def_data->mir->ssa_rep->defs[1] = new_s_reg + 1;
578 }
579 }
580 vreg_chains_.RenameSRegUses(def_change + 1u, last_change, old_s_reg, new_s_reg, wide);
581 return nullptr;
582 }
583}
584
585
586void GvnDeadCodeElimination::BackwardPassProcessLastMIR() {
587 MIRData* data = vreg_chains_.LastMIRData();
588 if (data->uses_all_vregs) {
589 DCHECK(data->must_keep);
590 unused_vregs_->ClearAllBits();
591 DCHECK_EQ(no_uses_all_since_, vreg_chains_.NumMIRs());
592 --no_uses_all_since_;
593 while (no_uses_all_since_ != 0u &&
594 !vreg_chains_.GetMIRData(no_uses_all_since_ - 1u)->uses_all_vregs) {
595 --no_uses_all_since_;
596 }
597 } else {
598 if (data->has_def) {
599 unused_vregs_->SetBit(data->vreg_def);
600 if (data->wide_def) {
601 unused_vregs_->SetBit(data->vreg_def + 1);
602 }
603 }
604 for (int i = 0, num_uses = data->mir->ssa_rep->num_uses; i != num_uses; ++i) {
605 int v_reg = mir_graph_->SRegToVReg(data->mir->ssa_rep->uses[i]);
606 unused_vregs_->ClearBit(v_reg);
607 }
608 }
609 vreg_chains_.RemoveLastMIRData();
610}
611
612void GvnDeadCodeElimination::RecordPassKillMoveByRenamingSrcDef(uint16_t src_change,
613 uint16_t move_change) {
614 DCHECK_LT(src_change, move_change);
615 MIRData* src_data = vreg_chains_.GetMIRData(src_change);
616 MIRData* move_data = vreg_chains_.GetMIRData(move_change);
617 DCHECK(src_data->is_move_src);
618 DCHECK_EQ(src_data->wide_def, move_data->wide_def);
619 DCHECK(move_data->prev_value.change == kNPos || move_data->prev_value.change <= src_change);
620 DCHECK(!move_data->wide_def || move_data->prev_value_high.change == kNPos ||
621 move_data->prev_value_high.change <= src_change);
622
623 int old_s_reg = src_data->mir->ssa_rep->defs[0];
624 // NOTE: old_s_reg may differ from move_data->mir->ssa_rep->uses[0]; value names must match.
625 int new_s_reg = move_data->mir->ssa_rep->defs[0];
626 DCHECK_NE(old_s_reg, new_s_reg);
627
628 if (IsInstructionBinOp2Addr(src_data->mir->dalvikInsn.opcode) &&
629 src_data->vreg_def != move_data->vreg_def) {
630 // Rewrite binop_2ADDR with plain binop before doing the register rename.
631 ChangeBinOp2AddrToPlainBinOp(src_data->mir);
632 }
633 // Remove src_change from the vreg chain(s).
634 vreg_chains_.RemoveChange(src_change);
635 // Replace the move_change with the src_change, copying all necessary data.
636 src_data->is_move_src = move_data->is_move_src;
637 src_data->low_def_over_high_word = move_data->low_def_over_high_word;
638 src_data->high_def_over_low_word = move_data->high_def_over_low_word;
639 src_data->vreg_def = move_data->vreg_def;
640 src_data->prev_value = move_data->prev_value;
641 src_data->prev_value_high = move_data->prev_value_high;
642 src_data->mir->dalvikInsn.vA = move_data->vreg_def;
643 src_data->mir->ssa_rep->defs[0] = new_s_reg;
644 if (move_data->wide_def) {
645 DCHECK_EQ(src_data->mir->ssa_rep->defs[1], old_s_reg + 1);
646 src_data->mir->ssa_rep->defs[1] = new_s_reg + 1;
647 }
648 vreg_chains_.ReplaceChange(move_change, src_change);
649
650 // Rename uses and kill the move.
651 vreg_chains_.RenameVRegUses(src_change + 1u, vreg_chains_.NumMIRs(),
652 old_s_reg, mir_graph_->SRegToVReg(old_s_reg),
653 new_s_reg, mir_graph_->SRegToVReg(new_s_reg));
654 KillMIR(move_data);
655}
656
657void GvnDeadCodeElimination::RecordPassTryToKillOverwrittenMoveOrMoveSrc(uint16_t check_change) {
658 MIRData* data = vreg_chains_.GetMIRData(check_change);
659 DCHECK(data->is_move || data->is_move_src);
660 int32_t dest_s_reg = data->mir->ssa_rep->defs[0];
661
662 if (data->is_move) {
663 // Check if source vreg has changed since the MOVE.
664 int32_t src_s_reg = data->mir->ssa_rep->uses[0];
665 uint32_t src_v_reg = mir_graph_->SRegToVReg(src_s_reg);
666 uint16_t src_change = vreg_chains_.FindFirstChangeAfter(src_v_reg, check_change);
667 bool wide = data->wide_def;
668 if (wide) {
669 uint16_t src_change_high = vreg_chains_.FindFirstChangeAfter(src_v_reg + 1, check_change);
670 if (src_change_high != kNPos && (src_change == kNPos || src_change_high < src_change)) {
671 src_change = src_change_high;
672 }
673 }
674 if (src_change == kNPos ||
675 !vreg_chains_.IsSRegUsed(src_change + 1u, vreg_chains_.NumMIRs(), dest_s_reg)) {
676 // We can simply change all uses of dest to src.
677 size_t rename_end = (src_change != kNPos) ? src_change + 1u : vreg_chains_.NumMIRs();
678 vreg_chains_.RenameVRegUses(check_change + 1u, rename_end,
679 dest_s_reg, mir_graph_->SRegToVReg(dest_s_reg),
680 src_s_reg, mir_graph_->SRegToVReg(src_s_reg));
681
682 // Now, remove the MOVE from the vreg chain(s) and kill it.
683 vreg_chains_.RemoveChange(check_change);
684 KillMIR(data);
685 return;
686 }
687 }
688
689 if (data->is_move_src) {
690 // Try to find a MOVE to a vreg that wasn't changed since check_change.
691 uint16_t value_name =
692 data->wide_def ? lvn_->GetSregValueWide(dest_s_reg) : lvn_->GetSregValue(dest_s_reg);
693 for (size_t c = check_change + 1u, size = vreg_chains_.NumMIRs(); c != size; ++c) {
694 MIRData* d = vreg_chains_.GetMIRData(c);
695 if (d->is_move && d->wide_def == data->wide_def &&
696 (d->prev_value.change == kNPos || d->prev_value.change <= check_change) &&
697 (!d->wide_def ||
698 d->prev_value_high.change == kNPos || d->prev_value_high.change <= check_change)) {
699 // Compare value names to find move to move.
700 int32_t src_s_reg = d->mir->ssa_rep->uses[0];
701 uint16_t src_name =
702 (d->wide_def ? lvn_->GetSregValueWide(src_s_reg) : lvn_->GetSregValue(src_s_reg));
703 if (value_name == src_name) {
Vladimir Markoad677272015-04-20 10:48:13 +0100704 // Check if the move's destination vreg is unused between check_change and the move.
705 uint32_t new_dest_v_reg = mir_graph_->SRegToVReg(d->mir->ssa_rep->defs[0]);
706 if (!vreg_chains_.IsVRegUsed(check_change + 1u, c, new_dest_v_reg, mir_graph_) &&
707 (!d->wide_def ||
708 !vreg_chains_.IsVRegUsed(check_change + 1u, c, new_dest_v_reg + 1, mir_graph_))) {
709 RecordPassKillMoveByRenamingSrcDef(check_change, c);
710 return;
711 }
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000712 }
713 }
714 }
715 }
716}
717
718void GvnDeadCodeElimination::RecordPassTryToKillOverwrittenMoveOrMoveSrc() {
719 // Check if we're overwriting a the result of a move or the definition of a source of a move.
720 // For MOVE_WIDE, we may be overwriting partially; if that's the case, check that the other
721 // word wasn't previously overwritten - we would have tried to rename back then.
722 MIRData* data = vreg_chains_.LastMIRData();
723 if (!data->has_def) {
724 return;
725 }
726 // NOTE: Instructions such as new-array implicitly use all vregs (if they throw) but they can
727 // define a move source which can be renamed. Therefore we allow the checked change to be the
728 // change before no_uses_all_since_. This has no effect on moves as they never use all vregs.
729 if (data->prev_value.change != kNPos && data->prev_value.change + 1u >= no_uses_all_since_) {
730 MIRData* check_data = vreg_chains_.GetMIRData(data->prev_value.change);
731 bool try_to_kill = false;
732 if (!check_data->is_move && !check_data->is_move_src) {
733 DCHECK(!try_to_kill);
734 } else if (!check_data->wide_def) {
735 // Narrow move; always fully overwritten by the last MIR.
736 try_to_kill = true;
737 } else if (data->low_def_over_high_word) {
738 // Overwriting only the high word; is the low word still valid?
739 DCHECK_EQ(check_data->vreg_def + 1u, data->vreg_def);
740 if (vreg_chains_.LastChange(check_data->vreg_def) == data->prev_value.change) {
741 try_to_kill = true;
742 }
743 } else if (!data->wide_def) {
744 // Overwriting only the low word, is the high word still valid?
745 if (vreg_chains_.LastChange(data->vreg_def + 1) == data->prev_value.change) {
746 try_to_kill = true;
747 }
748 } else {
749 // Overwriting both words; was the high word still from the same move?
750 if (data->prev_value_high.change == data->prev_value.change) {
751 try_to_kill = true;
752 }
753 }
754 if (try_to_kill) {
755 RecordPassTryToKillOverwrittenMoveOrMoveSrc(data->prev_value.change);
756 }
757 }
758 if (data->wide_def && data->high_def_over_low_word &&
759 data->prev_value_high.change != kNPos &&
760 data->prev_value_high.change + 1u >= no_uses_all_since_) {
761 MIRData* check_data = vreg_chains_.GetMIRData(data->prev_value_high.change);
762 bool try_to_kill = false;
763 if (!check_data->is_move && !check_data->is_move_src) {
764 DCHECK(!try_to_kill);
765 } else if (!check_data->wide_def) {
766 // Narrow move; always fully overwritten by the last MIR.
767 try_to_kill = true;
768 } else if (vreg_chains_.LastChange(check_data->vreg_def + 1) ==
769 data->prev_value_high.change) {
770 // High word is still valid.
771 try_to_kill = true;
772 }
773 if (try_to_kill) {
774 RecordPassTryToKillOverwrittenMoveOrMoveSrc(data->prev_value_high.change);
775 }
776 }
777}
778
779void GvnDeadCodeElimination::RecordPassTryToKillLastMIR() {
780 MIRData* last_data = vreg_chains_.LastMIRData();
781 if (last_data->must_keep) {
782 return;
783 }
784 if (UNLIKELY(!last_data->has_def)) {
785 // Must be an eliminated MOVE. Drop its data and data of all eliminated MIRs before it.
786 vreg_chains_.RemoveTrailingNops();
787 return;
788 }
789
790 // Try to kill a sequence of consecutive definitions of the same vreg. Allow mixing
791 // wide and non-wide defs; consider high word dead if low word has been overwritten.
792 uint16_t current_value = vreg_chains_.CurrentValue(last_data->vreg_def);
793 uint16_t change = vreg_chains_.NumMIRs() - 1u;
794 MIRData* data = last_data;
795 while (data->prev_value.value != current_value) {
796 --change;
797 if (data->prev_value.change == kNPos || data->prev_value.change != change) {
798 return;
799 }
800 data = vreg_chains_.GetMIRData(data->prev_value.change);
801 if (data->must_keep || !data->has_def || data->vreg_def != last_data->vreg_def) {
802 return;
803 }
804 }
805
806 bool wide = last_data->wide_def;
807 if (wide) {
808 // Check that the low word is valid.
809 if (data->low_def_over_high_word) {
810 return;
811 }
812 // Check that the high word is valid.
813 MIRData* high_data = data;
814 if (!high_data->wide_def) {
815 uint16_t high_change = vreg_chains_.FindFirstChangeAfter(data->vreg_def + 1, change);
816 DCHECK_NE(high_change, kNPos);
817 high_data = vreg_chains_.GetMIRData(high_change);
818 DCHECK_EQ(high_data->vreg_def, data->vreg_def);
819 }
820 if (high_data->prev_value_high.value != current_value || high_data->high_def_over_low_word) {
821 return;
822 }
823 }
824
825 MIR* phi = RenameSRegDefOrCreatePhi(data->prev_value.change, change, last_data->mir);
826 for (size_t i = 0, count = vreg_chains_.NumMIRs() - change; i != count; ++i) {
827 KillMIR(vreg_chains_.LastMIRData()->mir);
828 vreg_chains_.RemoveLastMIRData();
829 }
830 if (phi != nullptr) {
831 // Though the Phi has been added to the beginning, we can put the MIRData at the end.
832 vreg_chains_.AddMIRWithDef(phi, phi->dalvikInsn.vA, wide, current_value);
833 // Reset the previous value to avoid eventually eliminating the Phi itself (unless unused).
834 last_data = vreg_chains_.LastMIRData();
835 last_data->prev_value.value = kNoValue;
836 last_data->prev_value_high.value = kNoValue;
837 }
838}
839
840uint16_t GvnDeadCodeElimination::FindChangesToKill(uint16_t first_change, uint16_t last_change) {
841 // Process dependencies for changes in range [first_change, last_change) and record all
842 // changes that we need to kill. Return kNPos if there's a dependent change that must be
843 // kept unconditionally; otherwise the end of the range processed before encountering
844 // a change that defines a dalvik reg that we need to keep (last_change on full success).
845 changes_to_kill_.clear();
846 dependent_vregs_->ClearAllBits();
847 for (size_t change = first_change; change != last_change; ++change) {
848 MIRData* data = vreg_chains_.GetMIRData(change);
849 DCHECK(!data->uses_all_vregs);
850 bool must_not_depend = data->must_keep;
851 bool depends = false;
852 // Check if the MIR defines a vreg we're trying to eliminate.
853 if (data->has_def && vregs_to_kill_->IsBitSet(data->vreg_def)) {
854 if (change < kill_heads_[data->vreg_def]) {
855 must_not_depend = true;
856 } else {
857 depends = true;
858 }
859 }
860 if (data->has_def && data->wide_def && vregs_to_kill_->IsBitSet(data->vreg_def + 1)) {
861 if (change < kill_heads_[data->vreg_def + 1]) {
862 must_not_depend = true;
863 } else {
864 depends = true;
865 }
866 }
867 if (!depends) {
868 // Check for dependency through SSA reg uses.
869 SSARepresentation* ssa_rep = data->mir->ssa_rep;
870 for (int i = 0; i != ssa_rep->num_uses; ++i) {
871 if (dependent_vregs_->IsBitSet(mir_graph_->SRegToVReg(ssa_rep->uses[i]))) {
872 depends = true;
873 break;
874 }
875 }
876 }
877 // Now check if we can eliminate the insn if we need to.
878 if (depends && must_not_depend) {
879 return kNPos;
880 }
881 if (depends && data->has_def &&
882 vreg_chains_.IsTopChange(change) && !vregs_to_kill_->IsBitSet(data->vreg_def) &&
883 !unused_vregs_->IsBitSet(data->vreg_def) &&
884 (!data->wide_def || !unused_vregs_->IsBitSet(data->vreg_def + 1))) {
885 // This is a top change but neither unnecessary nor one of the top kill changes.
886 return change;
887 }
888 // Finally, update the data.
889 if (depends) {
890 changes_to_kill_.push_back(change);
891 if (data->has_def) {
892 dependent_vregs_->SetBit(data->vreg_def);
893 if (data->wide_def) {
894 dependent_vregs_->SetBit(data->vreg_def + 1);
895 }
896 }
897 } else {
898 if (data->has_def) {
899 dependent_vregs_->ClearBit(data->vreg_def);
900 if (data->wide_def) {
901 dependent_vregs_->ClearBit(data->vreg_def + 1);
902 }
903 }
904 }
905 }
906 return last_change;
907}
908
909void GvnDeadCodeElimination::BackwardPassTryToKillRevertVRegs() {
910}
911
912bool GvnDeadCodeElimination::BackwardPassTryToKillLastMIR() {
913 MIRData* last_data = vreg_chains_.LastMIRData();
914 if (last_data->must_keep) {
915 return false;
916 }
917 DCHECK(!last_data->uses_all_vregs);
918 if (!last_data->has_def) {
919 // Previously eliminated.
920 DCHECK_EQ(static_cast<int>(last_data->mir->dalvikInsn.opcode), static_cast<int>(kMirOpNop));
921 vreg_chains_.RemoveTrailingNops();
922 return true;
923 }
924 if (unused_vregs_->IsBitSet(last_data->vreg_def) ||
925 (last_data->wide_def && unused_vregs_->IsBitSet(last_data->vreg_def + 1))) {
926 if (last_data->wide_def) {
927 // For wide defs, one of the vregs may still be considered needed, fix that.
928 unused_vregs_->SetBit(last_data->vreg_def);
929 unused_vregs_->SetBit(last_data->vreg_def + 1);
930 }
931 KillMIR(last_data->mir);
932 vreg_chains_.RemoveLastMIRData();
933 return true;
934 }
935
936 vregs_to_kill_->ClearAllBits();
937 size_t num_mirs = vreg_chains_.NumMIRs();
938 DCHECK_NE(num_mirs, 0u);
939 uint16_t kill_change = num_mirs - 1u;
940 uint16_t start = num_mirs;
941 size_t num_killed_top_changes = 0u;
942 while (num_killed_top_changes != kMaxNumTopChangesToKill &&
943 kill_change != kNPos && kill_change != num_mirs) {
944 ++num_killed_top_changes;
945
946 DCHECK(vreg_chains_.IsTopChange(kill_change));
947 MIRData* data = vreg_chains_.GetMIRData(kill_change);
948 int count = data->wide_def ? 2 : 1;
949 for (int v_reg = data->vreg_def, end = data->vreg_def + count; v_reg != end; ++v_reg) {
950 uint16_t kill_head = vreg_chains_.FindKillHead(v_reg, no_uses_all_since_);
951 if (kill_head == kNPos) {
952 return false;
953 }
954 kill_heads_[v_reg] = kill_head;
955 vregs_to_kill_->SetBit(v_reg);
956 start = std::min(start, kill_head);
957 }
958 DCHECK_LT(start, vreg_chains_.NumMIRs());
959
960 kill_change = FindChangesToKill(start, num_mirs);
961 }
962
963 if (kill_change != num_mirs) {
964 return false;
965 }
966
967 // Kill all MIRs marked as dependent.
968 for (uint32_t v_reg : vregs_to_kill_->Indexes()) {
969 // Rename s_regs or create Phi only once for each MIR (only for low word).
970 MIRData* data = vreg_chains_.GetMIRData(vreg_chains_.LastChange(v_reg));
971 DCHECK(data->has_def);
972 if (data->vreg_def == v_reg) {
973 MIRData* kill_head_data = vreg_chains_.GetMIRData(kill_heads_[v_reg]);
974 RenameSRegDefOrCreatePhi(kill_head_data->PrevChange(v_reg), num_mirs, data->mir);
975 } else {
976 DCHECK_EQ(data->vreg_def + 1u, v_reg);
977 DCHECK_EQ(vreg_chains_.GetMIRData(kill_heads_[v_reg - 1u])->PrevChange(v_reg - 1u),
978 vreg_chains_.GetMIRData(kill_heads_[v_reg])->PrevChange(v_reg));
979 }
980 }
981 unused_vregs_->Union(vregs_to_kill_);
982 for (auto it = changes_to_kill_.rbegin(), end = changes_to_kill_.rend(); it != end; ++it) {
983 MIRData* data = vreg_chains_.GetMIRData(*it);
984 DCHECK(!data->must_keep);
985 DCHECK(data->has_def);
986 vreg_chains_.RemoveChange(*it);
987 KillMIR(data);
988 }
989
990 vreg_chains_.RemoveTrailingNops();
991 return true;
992}
993
994bool GvnDeadCodeElimination::RecordMIR(MIR* mir) {
995 bool must_keep = false;
996 bool uses_all_vregs = false;
997 bool is_move = false;
998 uint16_t opcode = mir->dalvikInsn.opcode;
999 switch (opcode) {
1000 case kMirOpPhi: {
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001001 // Determine if this Phi is merging wide regs.
1002 RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
1003 if (raw_dest.high_word) {
1004 // This is the high part of a wide reg. Ignore the Phi.
1005 return false;
1006 }
1007 bool wide = raw_dest.wide;
1008 // Record the value.
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001009 DCHECK_EQ(mir->ssa_rep->num_defs, 1);
1010 int s_reg = mir->ssa_rep->defs[0];
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001011 uint16_t new_value = wide ? lvn_->GetSregValueWide(s_reg) : lvn_->GetSregValue(s_reg);
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001012
1013 int v_reg = mir_graph_->SRegToVReg(s_reg);
1014 DCHECK_EQ(vreg_chains_.CurrentValue(v_reg), kNoValue); // No previous def for v_reg.
1015 if (wide) {
1016 DCHECK_EQ(vreg_chains_.CurrentValue(v_reg + 1), kNoValue);
1017 }
1018 vreg_chains_.AddMIRWithDef(mir, v_reg, wide, new_value);
1019 return true; // Avoid the common processing.
1020 }
1021
1022 case kMirOpNop:
1023 case Instruction::NOP:
1024 // Don't record NOPs.
1025 return false;
1026
1027 case kMirOpCheck:
1028 must_keep = true;
1029 uses_all_vregs = true;
1030 break;
1031
1032 case Instruction::RETURN_VOID:
1033 case Instruction::RETURN:
1034 case Instruction::RETURN_OBJECT:
1035 case Instruction::RETURN_WIDE:
1036 case Instruction::GOTO:
1037 case Instruction::GOTO_16:
1038 case Instruction::GOTO_32:
1039 case Instruction::PACKED_SWITCH:
1040 case Instruction::SPARSE_SWITCH:
1041 case Instruction::IF_EQ:
1042 case Instruction::IF_NE:
1043 case Instruction::IF_LT:
1044 case Instruction::IF_GE:
1045 case Instruction::IF_GT:
1046 case Instruction::IF_LE:
1047 case Instruction::IF_EQZ:
1048 case Instruction::IF_NEZ:
1049 case Instruction::IF_LTZ:
1050 case Instruction::IF_GEZ:
1051 case Instruction::IF_GTZ:
1052 case Instruction::IF_LEZ:
1053 case kMirOpFusedCmplFloat:
1054 case kMirOpFusedCmpgFloat:
1055 case kMirOpFusedCmplDouble:
1056 case kMirOpFusedCmpgDouble:
1057 case kMirOpFusedCmpLong:
1058 must_keep = true;
1059 uses_all_vregs = true; // Keep the implicit dependencies on all vregs.
1060 break;
1061
1062 case Instruction::CONST_CLASS:
1063 case Instruction::CONST_STRING:
1064 case Instruction::CONST_STRING_JUMBO:
1065 // NOTE: While we're currently treating CONST_CLASS, CONST_STRING and CONST_STRING_JUMBO
1066 // as throwing but we could conceivably try and eliminate those exceptions if we're
1067 // retrieving the class/string repeatedly.
1068 must_keep = true;
1069 uses_all_vregs = true;
1070 break;
1071
1072 case Instruction::MONITOR_ENTER:
1073 case Instruction::MONITOR_EXIT:
1074 // We can actually try and optimize across the acquire operation of MONITOR_ENTER,
1075 // the value names provided by GVN reflect the possible changes to memory visibility.
1076 // NOTE: In ART, MONITOR_ENTER and MONITOR_EXIT can throw only NPE.
1077 must_keep = true;
1078 uses_all_vregs = (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0;
1079 break;
1080
1081 case Instruction::INVOKE_DIRECT:
1082 case Instruction::INVOKE_DIRECT_RANGE:
1083 case Instruction::INVOKE_VIRTUAL:
1084 case Instruction::INVOKE_VIRTUAL_RANGE:
1085 case Instruction::INVOKE_SUPER:
1086 case Instruction::INVOKE_SUPER_RANGE:
1087 case Instruction::INVOKE_INTERFACE:
1088 case Instruction::INVOKE_INTERFACE_RANGE:
1089 case Instruction::INVOKE_STATIC:
1090 case Instruction::INVOKE_STATIC_RANGE:
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001091 case Instruction::THROW:
1092 case Instruction::FILLED_NEW_ARRAY:
1093 case Instruction::FILLED_NEW_ARRAY_RANGE:
1094 case Instruction::FILL_ARRAY_DATA:
1095 must_keep = true;
1096 uses_all_vregs = true;
1097 break;
1098
1099 case Instruction::NEW_INSTANCE:
1100 case Instruction::NEW_ARRAY:
1101 must_keep = true;
1102 uses_all_vregs = true;
1103 break;
1104
Vladimir Marko22fe45d2015-03-18 11:33:58 +00001105 case Instruction::CHECK_CAST:
1106 DCHECK_EQ(mir->ssa_rep->num_uses, 1);
1107 must_keep = true; // Keep for type information even if MIR_IGNORE_CHECK_CAST.
1108 uses_all_vregs = (mir->optimization_flags & MIR_IGNORE_CHECK_CAST) == 0;
1109 break;
1110
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001111 case kMirOpNullCheck:
1112 DCHECK_EQ(mir->ssa_rep->num_uses, 1);
1113 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) {
1114 mir->ssa_rep->num_uses = 0;
1115 mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
1116 return false;
1117 }
1118 must_keep = true;
1119 uses_all_vregs = true;
1120 break;
1121
1122 case Instruction::MOVE_RESULT:
1123 case Instruction::MOVE_RESULT_OBJECT:
1124 case Instruction::MOVE_RESULT_WIDE:
1125 break;
1126
1127 case Instruction::INSTANCE_OF:
1128 break;
1129
1130 case Instruction::MOVE_EXCEPTION:
1131 must_keep = true;
1132 break;
1133
1134 case kMirOpCopy:
1135 case Instruction::MOVE:
1136 case Instruction::MOVE_FROM16:
1137 case Instruction::MOVE_16:
1138 case Instruction::MOVE_WIDE:
1139 case Instruction::MOVE_WIDE_FROM16:
1140 case Instruction::MOVE_WIDE_16:
1141 case Instruction::MOVE_OBJECT:
1142 case Instruction::MOVE_OBJECT_FROM16:
1143 case Instruction::MOVE_OBJECT_16: {
1144 is_move = true;
1145 // If the MIR defining src vreg is known, allow renaming all uses of src vreg to dest vreg
1146 // while updating the defining MIR to directly define dest vreg. However, changing Phi's
1147 // def this way doesn't work without changing MIRs in other BBs.
1148 int src_v_reg = mir_graph_->SRegToVReg(mir->ssa_rep->uses[0]);
1149 int src_change = vreg_chains_.LastChange(src_v_reg);
1150 if (src_change != kNPos) {
1151 MIRData* src_data = vreg_chains_.GetMIRData(src_change);
1152 if (static_cast<int>(src_data->mir->dalvikInsn.opcode) != kMirOpPhi) {
1153 src_data->is_move_src = true;
1154 }
1155 }
1156 break;
1157 }
1158
1159 case Instruction::CONST_4:
1160 case Instruction::CONST_16:
1161 case Instruction::CONST:
1162 case Instruction::CONST_HIGH16:
1163 case Instruction::CONST_WIDE_16:
1164 case Instruction::CONST_WIDE_32:
1165 case Instruction::CONST_WIDE:
1166 case Instruction::CONST_WIDE_HIGH16:
1167 case Instruction::ARRAY_LENGTH:
1168 case Instruction::CMPL_FLOAT:
1169 case Instruction::CMPG_FLOAT:
1170 case Instruction::CMPL_DOUBLE:
1171 case Instruction::CMPG_DOUBLE:
1172 case Instruction::CMP_LONG:
1173 case Instruction::NEG_INT:
1174 case Instruction::NOT_INT:
1175 case Instruction::NEG_LONG:
1176 case Instruction::NOT_LONG:
1177 case Instruction::NEG_FLOAT:
1178 case Instruction::NEG_DOUBLE:
1179 case Instruction::INT_TO_LONG:
1180 case Instruction::INT_TO_FLOAT:
1181 case Instruction::INT_TO_DOUBLE:
1182 case Instruction::LONG_TO_INT:
1183 case Instruction::LONG_TO_FLOAT:
1184 case Instruction::LONG_TO_DOUBLE:
1185 case Instruction::FLOAT_TO_INT:
1186 case Instruction::FLOAT_TO_LONG:
1187 case Instruction::FLOAT_TO_DOUBLE:
1188 case Instruction::DOUBLE_TO_INT:
1189 case Instruction::DOUBLE_TO_LONG:
1190 case Instruction::DOUBLE_TO_FLOAT:
1191 case Instruction::INT_TO_BYTE:
1192 case Instruction::INT_TO_CHAR:
1193 case Instruction::INT_TO_SHORT:
1194 case Instruction::ADD_INT:
1195 case Instruction::SUB_INT:
1196 case Instruction::MUL_INT:
1197 case Instruction::AND_INT:
1198 case Instruction::OR_INT:
1199 case Instruction::XOR_INT:
1200 case Instruction::SHL_INT:
1201 case Instruction::SHR_INT:
1202 case Instruction::USHR_INT:
1203 case Instruction::ADD_LONG:
1204 case Instruction::SUB_LONG:
1205 case Instruction::MUL_LONG:
1206 case Instruction::AND_LONG:
1207 case Instruction::OR_LONG:
1208 case Instruction::XOR_LONG:
1209 case Instruction::SHL_LONG:
1210 case Instruction::SHR_LONG:
1211 case Instruction::USHR_LONG:
1212 case Instruction::ADD_FLOAT:
1213 case Instruction::SUB_FLOAT:
1214 case Instruction::MUL_FLOAT:
1215 case Instruction::DIV_FLOAT:
1216 case Instruction::REM_FLOAT:
1217 case Instruction::ADD_DOUBLE:
1218 case Instruction::SUB_DOUBLE:
1219 case Instruction::MUL_DOUBLE:
1220 case Instruction::DIV_DOUBLE:
1221 case Instruction::REM_DOUBLE:
1222 case Instruction::ADD_INT_2ADDR:
1223 case Instruction::SUB_INT_2ADDR:
1224 case Instruction::MUL_INT_2ADDR:
1225 case Instruction::AND_INT_2ADDR:
1226 case Instruction::OR_INT_2ADDR:
1227 case Instruction::XOR_INT_2ADDR:
1228 case Instruction::SHL_INT_2ADDR:
1229 case Instruction::SHR_INT_2ADDR:
1230 case Instruction::USHR_INT_2ADDR:
1231 case Instruction::ADD_LONG_2ADDR:
1232 case Instruction::SUB_LONG_2ADDR:
1233 case Instruction::MUL_LONG_2ADDR:
1234 case Instruction::AND_LONG_2ADDR:
1235 case Instruction::OR_LONG_2ADDR:
1236 case Instruction::XOR_LONG_2ADDR:
1237 case Instruction::SHL_LONG_2ADDR:
1238 case Instruction::SHR_LONG_2ADDR:
1239 case Instruction::USHR_LONG_2ADDR:
1240 case Instruction::ADD_FLOAT_2ADDR:
1241 case Instruction::SUB_FLOAT_2ADDR:
1242 case Instruction::MUL_FLOAT_2ADDR:
1243 case Instruction::DIV_FLOAT_2ADDR:
1244 case Instruction::REM_FLOAT_2ADDR:
1245 case Instruction::ADD_DOUBLE_2ADDR:
1246 case Instruction::SUB_DOUBLE_2ADDR:
1247 case Instruction::MUL_DOUBLE_2ADDR:
1248 case Instruction::DIV_DOUBLE_2ADDR:
1249 case Instruction::REM_DOUBLE_2ADDR:
1250 case Instruction::ADD_INT_LIT16:
1251 case Instruction::RSUB_INT:
1252 case Instruction::MUL_INT_LIT16:
1253 case Instruction::AND_INT_LIT16:
1254 case Instruction::OR_INT_LIT16:
1255 case Instruction::XOR_INT_LIT16:
1256 case Instruction::ADD_INT_LIT8:
1257 case Instruction::RSUB_INT_LIT8:
1258 case Instruction::MUL_INT_LIT8:
1259 case Instruction::AND_INT_LIT8:
1260 case Instruction::OR_INT_LIT8:
1261 case Instruction::XOR_INT_LIT8:
1262 case Instruction::SHL_INT_LIT8:
1263 case Instruction::SHR_INT_LIT8:
1264 case Instruction::USHR_INT_LIT8:
1265 break;
1266
1267 case Instruction::DIV_INT:
1268 case Instruction::REM_INT:
1269 case Instruction::DIV_LONG:
1270 case Instruction::REM_LONG:
1271 case Instruction::DIV_INT_2ADDR:
1272 case Instruction::REM_INT_2ADDR:
1273 case Instruction::DIV_LONG_2ADDR:
1274 case Instruction::REM_LONG_2ADDR:
1275 if ((mir->optimization_flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
1276 must_keep = true;
1277 uses_all_vregs = true;
1278 }
1279 break;
1280
1281 case Instruction::DIV_INT_LIT16:
1282 case Instruction::REM_INT_LIT16:
1283 case Instruction::DIV_INT_LIT8:
1284 case Instruction::REM_INT_LIT8:
1285 if (mir->dalvikInsn.vC == 0) { // Explicit division by 0?
1286 must_keep = true;
1287 uses_all_vregs = true;
1288 }
1289 break;
1290
1291 case Instruction::AGET_OBJECT:
1292 case Instruction::AGET:
1293 case Instruction::AGET_WIDE:
1294 case Instruction::AGET_BOOLEAN:
1295 case Instruction::AGET_BYTE:
1296 case Instruction::AGET_CHAR:
1297 case Instruction::AGET_SHORT:
1298 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 ||
1299 (mir->optimization_flags & MIR_IGNORE_RANGE_CHECK) == 0) {
1300 must_keep = true;
1301 uses_all_vregs = true;
1302 }
1303 break;
1304
1305 case Instruction::APUT_OBJECT:
1306 case Instruction::APUT:
1307 case Instruction::APUT_WIDE:
1308 case Instruction::APUT_BYTE:
1309 case Instruction::APUT_BOOLEAN:
1310 case Instruction::APUT_SHORT:
1311 case Instruction::APUT_CHAR:
1312 must_keep = true;
1313 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 ||
1314 (mir->optimization_flags & MIR_IGNORE_RANGE_CHECK) == 0) {
1315 uses_all_vregs = true;
1316 }
1317 break;
1318
1319 case Instruction::IGET_OBJECT:
1320 case Instruction::IGET:
1321 case Instruction::IGET_WIDE:
1322 case Instruction::IGET_BOOLEAN:
1323 case Instruction::IGET_BYTE:
1324 case Instruction::IGET_CHAR:
1325 case Instruction::IGET_SHORT: {
1326 const MirIFieldLoweringInfo& info = mir_graph_->GetIFieldLoweringInfo(mir);
1327 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 ||
1328 !info.IsResolved() || !info.FastGet()) {
1329 must_keep = true;
1330 uses_all_vregs = true;
1331 } else if (info.IsVolatile()) {
1332 must_keep = true;
1333 }
1334 break;
1335 }
1336
1337 case Instruction::IPUT_OBJECT:
1338 case Instruction::IPUT:
1339 case Instruction::IPUT_WIDE:
1340 case Instruction::IPUT_BOOLEAN:
1341 case Instruction::IPUT_BYTE:
1342 case Instruction::IPUT_CHAR:
1343 case Instruction::IPUT_SHORT: {
1344 must_keep = true;
1345 const MirIFieldLoweringInfo& info = mir_graph_->GetIFieldLoweringInfo(mir);
1346 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 ||
1347 !info.IsResolved() || !info.FastPut()) {
1348 uses_all_vregs = true;
1349 }
1350 break;
1351 }
1352
1353 case Instruction::SGET_OBJECT:
1354 case Instruction::SGET:
1355 case Instruction::SGET_WIDE:
1356 case Instruction::SGET_BOOLEAN:
1357 case Instruction::SGET_BYTE:
1358 case Instruction::SGET_CHAR:
1359 case Instruction::SGET_SHORT: {
1360 const MirSFieldLoweringInfo& info = mir_graph_->GetSFieldLoweringInfo(mir);
1361 if ((mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0 ||
1362 !info.IsResolved() || !info.FastGet()) {
1363 must_keep = true;
1364 uses_all_vregs = true;
1365 } else if (info.IsVolatile()) {
1366 must_keep = true;
1367 }
1368 break;
1369 }
1370
1371 case Instruction::SPUT_OBJECT:
1372 case Instruction::SPUT:
1373 case Instruction::SPUT_WIDE:
1374 case Instruction::SPUT_BOOLEAN:
1375 case Instruction::SPUT_BYTE:
1376 case Instruction::SPUT_CHAR:
1377 case Instruction::SPUT_SHORT: {
1378 must_keep = true;
1379 const MirSFieldLoweringInfo& info = mir_graph_->GetSFieldLoweringInfo(mir);
1380 if ((mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0 ||
1381 !info.IsResolved() || !info.FastPut()) {
1382 uses_all_vregs = true;
1383 }
1384 break;
1385 }
1386
1387 default:
1388 LOG(FATAL) << "Unexpected opcode: " << opcode;
1389 UNREACHABLE();
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001390 }
1391
1392 if (mir->ssa_rep->num_defs != 0) {
1393 DCHECK(mir->ssa_rep->num_defs == 1 || mir->ssa_rep->num_defs == 2);
1394 bool wide = (mir->ssa_rep->num_defs == 2);
1395 int s_reg = mir->ssa_rep->defs[0];
1396 int v_reg = mir_graph_->SRegToVReg(s_reg);
1397 uint16_t new_value = wide ? lvn_->GetSregValueWide(s_reg) : lvn_->GetSregValue(s_reg);
1398 DCHECK_NE(new_value, kNoValue);
1399
1400 vreg_chains_.UpdateInitialVRegValue(v_reg, wide, lvn_);
1401 vreg_chains_.AddMIRWithDef(mir, v_reg, wide, new_value);
1402 if (is_move) {
1403 // Allow renaming all uses of dest vreg to src vreg.
1404 vreg_chains_.LastMIRData()->is_move = true;
1405 }
1406 } else {
1407 vreg_chains_.AddMIRWithoutDef(mir);
1408 DCHECK(!is_move) << opcode;
1409 }
1410
1411 if (must_keep) {
1412 MIRData* last_data = vreg_chains_.LastMIRData();
1413 last_data->must_keep = true;
1414 if (uses_all_vregs) {
1415 last_data->uses_all_vregs = true;
1416 no_uses_all_since_ = vreg_chains_.NumMIRs();
1417 }
1418 } else {
1419 DCHECK_NE(mir->ssa_rep->num_defs, 0) << opcode;
1420 DCHECK(!uses_all_vregs) << opcode;
1421 }
1422 return true;
1423}
1424
1425} // namespace art