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