• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 "compiler_internals.h"
18 #include "local_value_numbering.h"
19 #include "dataflow_iterator-inl.h"
20 
21 namespace art {
22 
Predecessors(BasicBlock * bb)23 static unsigned int Predecessors(BasicBlock* bb) {
24   return bb->predecessors->Size();
25 }
26 
27 /* Setup a constant value for opcodes thare have the DF_SETS_CONST attribute */
SetConstant(int32_t ssa_reg,int value)28 void MIRGraph::SetConstant(int32_t ssa_reg, int value) {
29   is_constant_v_->SetBit(ssa_reg);
30   constant_values_[ssa_reg] = value;
31 }
32 
SetConstantWide(int ssa_reg,int64_t value)33 void MIRGraph::SetConstantWide(int ssa_reg, int64_t value) {
34   is_constant_v_->SetBit(ssa_reg);
35   constant_values_[ssa_reg] = Low32Bits(value);
36   constant_values_[ssa_reg + 1] = High32Bits(value);
37 }
38 
DoConstantPropogation(BasicBlock * bb)39 void MIRGraph::DoConstantPropogation(BasicBlock* bb) {
40   MIR* mir;
41 
42   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
43     int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
44 
45     DecodedInstruction *d_insn = &mir->dalvikInsn;
46 
47     if (!(df_attributes & DF_HAS_DEFS)) continue;
48 
49     /* Handle instructions that set up constants directly */
50     if (df_attributes & DF_SETS_CONST) {
51       if (df_attributes & DF_DA) {
52         int32_t vB = static_cast<int32_t>(d_insn->vB);
53         switch (d_insn->opcode) {
54           case Instruction::CONST_4:
55           case Instruction::CONST_16:
56           case Instruction::CONST:
57             SetConstant(mir->ssa_rep->defs[0], vB);
58             break;
59           case Instruction::CONST_HIGH16:
60             SetConstant(mir->ssa_rep->defs[0], vB << 16);
61             break;
62           case Instruction::CONST_WIDE_16:
63           case Instruction::CONST_WIDE_32:
64             SetConstantWide(mir->ssa_rep->defs[0], static_cast<int64_t>(vB));
65             break;
66           case Instruction::CONST_WIDE:
67             SetConstantWide(mir->ssa_rep->defs[0], d_insn->vB_wide);
68             break;
69           case Instruction::CONST_WIDE_HIGH16:
70             SetConstantWide(mir->ssa_rep->defs[0], static_cast<int64_t>(vB) << 48);
71             break;
72           default:
73             break;
74         }
75       }
76       /* Handle instructions that set up constants directly */
77     } else if (df_attributes & DF_IS_MOVE) {
78       int i;
79 
80       for (i = 0; i < mir->ssa_rep->num_uses; i++) {
81         if (!is_constant_v_->IsBitSet(mir->ssa_rep->uses[i])) break;
82       }
83       /* Move a register holding a constant to another register */
84       if (i == mir->ssa_rep->num_uses) {
85         SetConstant(mir->ssa_rep->defs[0], constant_values_[mir->ssa_rep->uses[0]]);
86         if (df_attributes & DF_A_WIDE) {
87           SetConstant(mir->ssa_rep->defs[1], constant_values_[mir->ssa_rep->uses[1]]);
88         }
89       }
90     }
91   }
92   /* TODO: implement code to handle arithmetic operations */
93 }
94 
PropagateConstants()95 void MIRGraph::PropagateConstants() {
96   is_constant_v_ = new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false);
97   constant_values_ = static_cast<int*>(arena_->Alloc(sizeof(int) * GetNumSSARegs(),
98                                                      ArenaAllocator::kAllocDFInfo));
99   AllNodesIterator iter(this, false /* not iterative */);
100   for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
101     DoConstantPropogation(bb);
102   }
103 }
104 
105 /* Advance to next strictly dominated MIR node in an extended basic block */
AdvanceMIR(BasicBlock ** p_bb,MIR * mir)106 static MIR* AdvanceMIR(BasicBlock** p_bb, MIR* mir) {
107   BasicBlock* bb = *p_bb;
108   if (mir != NULL) {
109     mir = mir->next;
110     if (mir == NULL) {
111       bb = bb->fall_through;
112       if ((bb == NULL) || Predecessors(bb) != 1) {
113         mir = NULL;
114       } else {
115       *p_bb = bb;
116       mir = bb->first_mir_insn;
117       }
118     }
119   }
120   return mir;
121 }
122 
123 /*
124  * To be used at an invoke mir.  If the logically next mir node represents
125  * a move-result, return it.  Else, return NULL.  If a move-result exists,
126  * it is required to immediately follow the invoke with no intervening
127  * opcodes or incoming arcs.  However, if the result of the invoke is not
128  * used, a move-result may not be present.
129  */
FindMoveResult(BasicBlock * bb,MIR * mir)130 MIR* MIRGraph::FindMoveResult(BasicBlock* bb, MIR* mir) {
131   BasicBlock* tbb = bb;
132   mir = AdvanceMIR(&tbb, mir);
133   while (mir != NULL) {
134     int opcode = mir->dalvikInsn.opcode;
135     if ((mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) ||
136         (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) ||
137         (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE)) {
138       break;
139     }
140     // Keep going if pseudo op, otherwise terminate
141     if (opcode < kNumPackedOpcodes) {
142       mir = NULL;
143     } else {
144       mir = AdvanceMIR(&tbb, mir);
145     }
146   }
147   return mir;
148 }
149 
NextDominatedBlock(BasicBlock * bb)150 static BasicBlock* NextDominatedBlock(BasicBlock* bb) {
151   if (bb->block_type == kDead) {
152     return NULL;
153   }
154   DCHECK((bb->block_type == kEntryBlock) || (bb->block_type == kDalvikByteCode)
155       || (bb->block_type == kExitBlock));
156   if (((bb->taken != NULL) && (bb->fall_through == NULL)) &&
157       ((bb->taken->block_type == kDalvikByteCode) || (bb->taken->block_type == kExitBlock))) {
158     // Follow simple unconditional branches.
159     bb = bb->taken;
160   } else {
161     // Follow simple fallthrough
162     bb = (bb->taken != NULL) ? NULL : bb->fall_through;
163   }
164   if (bb == NULL || (Predecessors(bb) != 1)) {
165     return NULL;
166   }
167   DCHECK((bb->block_type == kDalvikByteCode) || (bb->block_type == kExitBlock));
168   return bb;
169 }
170 
FindPhi(BasicBlock * bb,int ssa_name)171 static MIR* FindPhi(BasicBlock* bb, int ssa_name) {
172   for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
173     if (static_cast<int>(mir->dalvikInsn.opcode) == kMirOpPhi) {
174       for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
175         if (mir->ssa_rep->uses[i] == ssa_name) {
176           return mir;
177         }
178       }
179     }
180   }
181   return NULL;
182 }
183 
SelectKind(MIR * mir)184 static SelectInstructionKind SelectKind(MIR* mir) {
185   switch (mir->dalvikInsn.opcode) {
186     case Instruction::MOVE:
187     case Instruction::MOVE_OBJECT:
188     case Instruction::MOVE_16:
189     case Instruction::MOVE_OBJECT_16:
190     case Instruction::MOVE_FROM16:
191     case Instruction::MOVE_OBJECT_FROM16:
192       return kSelectMove;
193     case Instruction::CONST:
194     case Instruction::CONST_4:
195     case Instruction::CONST_16:
196       return kSelectConst;
197     case Instruction::GOTO:
198     case Instruction::GOTO_16:
199     case Instruction::GOTO_32:
200       return kSelectGoto;
201     default:
202       return kSelectNone;
203   }
204 }
205 
GetSSAUseCount(int s_reg)206 int MIRGraph::GetSSAUseCount(int s_reg) {
207   return raw_use_counts_.Get(s_reg);
208 }
209 
210 
211 /* Do some MIR-level extended basic block optimizations */
BasicBlockOpt(BasicBlock * bb)212 bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
213   if (bb->block_type == kDead) {
214     return true;
215   }
216   int num_temps = 0;
217   LocalValueNumbering local_valnum(cu_);
218   while (bb != NULL) {
219     for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
220       // TUNING: use the returned value number for CSE.
221       local_valnum.GetValueNumber(mir);
222       // Look for interesting opcodes, skip otherwise
223       Instruction::Code opcode = mir->dalvikInsn.opcode;
224       switch (opcode) {
225         case Instruction::CMPL_FLOAT:
226         case Instruction::CMPL_DOUBLE:
227         case Instruction::CMPG_FLOAT:
228         case Instruction::CMPG_DOUBLE:
229         case Instruction::CMP_LONG:
230           if ((cu_->disable_opt & (1 << kBranchFusing)) != 0) {
231             // Bitcode doesn't allow this optimization.
232             break;
233           }
234           if (mir->next != NULL) {
235             MIR* mir_next = mir->next;
236             Instruction::Code br_opcode = mir_next->dalvikInsn.opcode;
237             ConditionCode ccode = kCondNv;
238             switch (br_opcode) {
239               case Instruction::IF_EQZ:
240                 ccode = kCondEq;
241                 break;
242               case Instruction::IF_NEZ:
243                 ccode = kCondNe;
244                 break;
245               case Instruction::IF_LTZ:
246                 ccode = kCondLt;
247                 break;
248               case Instruction::IF_GEZ:
249                 ccode = kCondGe;
250                 break;
251               case Instruction::IF_GTZ:
252                 ccode = kCondGt;
253                 break;
254               case Instruction::IF_LEZ:
255                 ccode = kCondLe;
256                 break;
257               default:
258                 break;
259             }
260             // Make sure result of cmp is used by next insn and nowhere else
261             if ((ccode != kCondNv) &&
262                 (mir->ssa_rep->defs[0] == mir_next->ssa_rep->uses[0]) &&
263                 (GetSSAUseCount(mir->ssa_rep->defs[0]) == 1)) {
264               mir_next->dalvikInsn.arg[0] = ccode;
265               switch (opcode) {
266                 case Instruction::CMPL_FLOAT:
267                   mir_next->dalvikInsn.opcode =
268                       static_cast<Instruction::Code>(kMirOpFusedCmplFloat);
269                   break;
270                 case Instruction::CMPL_DOUBLE:
271                   mir_next->dalvikInsn.opcode =
272                       static_cast<Instruction::Code>(kMirOpFusedCmplDouble);
273                   break;
274                 case Instruction::CMPG_FLOAT:
275                   mir_next->dalvikInsn.opcode =
276                       static_cast<Instruction::Code>(kMirOpFusedCmpgFloat);
277                   break;
278                 case Instruction::CMPG_DOUBLE:
279                   mir_next->dalvikInsn.opcode =
280                       static_cast<Instruction::Code>(kMirOpFusedCmpgDouble);
281                   break;
282                 case Instruction::CMP_LONG:
283                   mir_next->dalvikInsn.opcode =
284                       static_cast<Instruction::Code>(kMirOpFusedCmpLong);
285                   break;
286                 default: LOG(ERROR) << "Unexpected opcode: " << opcode;
287               }
288               mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
289               mir_next->ssa_rep->num_uses = mir->ssa_rep->num_uses;
290               mir_next->ssa_rep->uses = mir->ssa_rep->uses;
291               mir_next->ssa_rep->fp_use = mir->ssa_rep->fp_use;
292               mir_next->ssa_rep->num_defs = 0;
293               mir->ssa_rep->num_uses = 0;
294               mir->ssa_rep->num_defs = 0;
295             }
296           }
297           break;
298         case Instruction::GOTO:
299         case Instruction::GOTO_16:
300         case Instruction::GOTO_32:
301         case Instruction::IF_EQ:
302         case Instruction::IF_NE:
303         case Instruction::IF_LT:
304         case Instruction::IF_GE:
305         case Instruction::IF_GT:
306         case Instruction::IF_LE:
307         case Instruction::IF_EQZ:
308         case Instruction::IF_NEZ:
309         case Instruction::IF_LTZ:
310         case Instruction::IF_GEZ:
311         case Instruction::IF_GTZ:
312         case Instruction::IF_LEZ:
313           // If we've got a backwards branch to return, no need to suspend check.
314           if ((IsBackedge(bb, bb->taken) && bb->taken->dominates_return) ||
315               (IsBackedge(bb, bb->fall_through) && bb->fall_through->dominates_return)) {
316             mir->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK;
317             if (cu_->verbose) {
318               LOG(INFO) << "Suppressed suspend check on branch to return at 0x" << std::hex << mir->offset;
319             }
320           }
321           break;
322         default:
323           break;
324       }
325       // Is this the select pattern?
326       // TODO: flesh out support for Mips and X86.  NOTE: llvm's select op doesn't quite work here.
327       // TUNING: expand to support IF_xx compare & branches
328       if (!(cu_->compiler_backend == kPortable) && (cu_->instruction_set == kThumb2) &&
329           ((mir->dalvikInsn.opcode == Instruction::IF_EQZ) ||
330           (mir->dalvikInsn.opcode == Instruction::IF_NEZ))) {
331         BasicBlock* ft = bb->fall_through;
332         DCHECK(ft != NULL);
333         BasicBlock* ft_ft = ft->fall_through;
334         BasicBlock* ft_tk = ft->taken;
335 
336         BasicBlock* tk = bb->taken;
337         DCHECK(tk != NULL);
338         BasicBlock* tk_ft = tk->fall_through;
339         BasicBlock* tk_tk = tk->taken;
340 
341         /*
342          * In the select pattern, the taken edge goes to a block that unconditionally
343          * transfers to the rejoin block and the fall_though edge goes to a block that
344          * unconditionally falls through to the rejoin block.
345          */
346         if ((tk_ft == NULL) && (ft_tk == NULL) && (tk_tk == ft_ft) &&
347             (Predecessors(tk) == 1) && (Predecessors(ft) == 1)) {
348           /*
349            * Okay - we have the basic diamond shape.  At the very least, we can eliminate the
350            * suspend check on the taken-taken branch back to the join point.
351            */
352           if (SelectKind(tk->last_mir_insn) == kSelectGoto) {
353               tk->last_mir_insn->optimization_flags |= (MIR_IGNORE_SUSPEND_CHECK);
354           }
355           // Are the block bodies something we can handle?
356           if ((ft->first_mir_insn == ft->last_mir_insn) &&
357               (tk->first_mir_insn != tk->last_mir_insn) &&
358               (tk->first_mir_insn->next == tk->last_mir_insn) &&
359               ((SelectKind(ft->first_mir_insn) == kSelectMove) ||
360               (SelectKind(ft->first_mir_insn) == kSelectConst)) &&
361               (SelectKind(ft->first_mir_insn) == SelectKind(tk->first_mir_insn)) &&
362               (SelectKind(tk->last_mir_insn) == kSelectGoto)) {
363             // Almost there.  Are the instructions targeting the same vreg?
364             MIR* if_true = tk->first_mir_insn;
365             MIR* if_false = ft->first_mir_insn;
366             // It's possible that the target of the select isn't used - skip those (rare) cases.
367             MIR* phi = FindPhi(tk_tk, if_true->ssa_rep->defs[0]);
368             if ((phi != NULL) && (if_true->dalvikInsn.vA == if_false->dalvikInsn.vA)) {
369               /*
370                * We'll convert the IF_EQZ/IF_NEZ to a SELECT.  We need to find the
371                * Phi node in the merge block and delete it (while using the SSA name
372                * of the merge as the target of the SELECT.  Delete both taken and
373                * fallthrough blocks, and set fallthrough to merge block.
374                * NOTE: not updating other dataflow info (no longer used at this point).
375                * If this changes, need to update i_dom, etc. here (and in CombineBlocks).
376                */
377               if (opcode == Instruction::IF_NEZ) {
378                 // Normalize.
379                 MIR* tmp_mir = if_true;
380                 if_true = if_false;
381                 if_false = tmp_mir;
382               }
383               mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpSelect);
384               bool const_form = (SelectKind(if_true) == kSelectConst);
385               if ((SelectKind(if_true) == kSelectMove)) {
386                 if (IsConst(if_true->ssa_rep->uses[0]) &&
387                     IsConst(if_false->ssa_rep->uses[0])) {
388                     const_form = true;
389                     if_true->dalvikInsn.vB = ConstantValue(if_true->ssa_rep->uses[0]);
390                     if_false->dalvikInsn.vB = ConstantValue(if_false->ssa_rep->uses[0]);
391                 }
392               }
393               if (const_form) {
394                 // "true" set val in vB
395                 mir->dalvikInsn.vB = if_true->dalvikInsn.vB;
396                 // "false" set val in vC
397                 mir->dalvikInsn.vC = if_false->dalvikInsn.vB;
398               } else {
399                 DCHECK_EQ(SelectKind(if_true), kSelectMove);
400                 DCHECK_EQ(SelectKind(if_false), kSelectMove);
401                 int* src_ssa =
402                     static_cast<int*>(arena_->Alloc(sizeof(int) * 3, ArenaAllocator::kAllocDFInfo));
403                 src_ssa[0] = mir->ssa_rep->uses[0];
404                 src_ssa[1] = if_true->ssa_rep->uses[0];
405                 src_ssa[2] = if_false->ssa_rep->uses[0];
406                 mir->ssa_rep->uses = src_ssa;
407                 mir->ssa_rep->num_uses = 3;
408               }
409               mir->ssa_rep->num_defs = 1;
410               mir->ssa_rep->defs =
411                   static_cast<int*>(arena_->Alloc(sizeof(int) * 1, ArenaAllocator::kAllocDFInfo));
412               mir->ssa_rep->fp_def =
413                   static_cast<bool*>(arena_->Alloc(sizeof(bool) * 1, ArenaAllocator::kAllocDFInfo));
414               mir->ssa_rep->fp_def[0] = if_true->ssa_rep->fp_def[0];
415               // Match type of uses to def.
416               mir->ssa_rep->fp_use =
417                   static_cast<bool*>(arena_->Alloc(sizeof(bool) * mir->ssa_rep->num_uses,
418                                                    ArenaAllocator::kAllocDFInfo));
419               for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
420                 mir->ssa_rep->fp_use[i] = mir->ssa_rep->fp_def[0];
421               }
422               /*
423                * There is usually a Phi node in the join block for our two cases.  If the
424                * Phi node only contains our two cases as input, we will use the result
425                * SSA name of the Phi node as our select result and delete the Phi.  If
426                * the Phi node has more than two operands, we will arbitrarily use the SSA
427                * name of the "true" path, delete the SSA name of the "false" path from the
428                * Phi node (and fix up the incoming arc list).
429                */
430               if (phi->ssa_rep->num_uses == 2) {
431                 mir->ssa_rep->defs[0] = phi->ssa_rep->defs[0];
432                 phi->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
433               } else {
434                 int dead_def = if_false->ssa_rep->defs[0];
435                 int live_def = if_true->ssa_rep->defs[0];
436                 mir->ssa_rep->defs[0] = live_def;
437                 int* incoming = reinterpret_cast<int*>(phi->dalvikInsn.vB);
438                 for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
439                   if (phi->ssa_rep->uses[i] == live_def) {
440                     incoming[i] = bb->id;
441                   }
442                 }
443                 for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
444                   if (phi->ssa_rep->uses[i] == dead_def) {
445                     int last_slot = phi->ssa_rep->num_uses - 1;
446                     phi->ssa_rep->uses[i] = phi->ssa_rep->uses[last_slot];
447                     incoming[i] = incoming[last_slot];
448                   }
449                 }
450               }
451               phi->ssa_rep->num_uses--;
452               bb->taken = NULL;
453               tk->block_type = kDead;
454               for (MIR* tmir = ft->first_mir_insn; tmir != NULL; tmir = tmir->next) {
455                 tmir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
456               }
457             }
458           }
459         }
460       }
461     }
462     bb = NextDominatedBlock(bb);
463   }
464 
465   if (num_temps > cu_->num_compiler_temps) {
466     cu_->num_compiler_temps = num_temps;
467   }
468   return true;
469 }
470 
NullCheckEliminationInit(struct BasicBlock * bb)471 void MIRGraph::NullCheckEliminationInit(struct BasicBlock* bb) {
472   if (bb->data_flow_info != NULL) {
473     bb->data_flow_info->ending_null_check_v =
474         new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false, kBitMapNullCheck);
475   }
476 }
477 
478 /* Collect stats on number of checks removed */
CountChecks(struct BasicBlock * bb)479 void MIRGraph::CountChecks(struct BasicBlock* bb) {
480   if (bb->data_flow_info != NULL) {
481     for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
482       if (mir->ssa_rep == NULL) {
483         continue;
484       }
485       int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
486       if (df_attributes & DF_HAS_NULL_CHKS) {
487         checkstats_->null_checks++;
488         if (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) {
489           checkstats_->null_checks_eliminated++;
490         }
491       }
492       if (df_attributes & DF_HAS_RANGE_CHKS) {
493         checkstats_->range_checks++;
494         if (mir->optimization_flags & MIR_IGNORE_RANGE_CHECK) {
495           checkstats_->range_checks_eliminated++;
496         }
497       }
498     }
499   }
500 }
501 
502 /* Try to make common case the fallthrough path */
LayoutBlocks(struct BasicBlock * bb)503 static bool LayoutBlocks(struct BasicBlock* bb) {
504   // TODO: For now, just looking for direct throws.  Consider generalizing for profile feedback
505   if (!bb->explicit_throw) {
506     return false;
507   }
508   BasicBlock* walker = bb;
509   while (true) {
510     // Check termination conditions
511     if ((walker->block_type == kEntryBlock) || (Predecessors(walker) != 1)) {
512       break;
513     }
514     BasicBlock* prev = walker->predecessors->Get(0);
515     if (prev->conditional_branch) {
516       if (prev->fall_through == walker) {
517         // Already done - return
518         break;
519       }
520       DCHECK_EQ(walker, prev->taken);
521       // Got one.  Flip it and exit
522       Instruction::Code opcode = prev->last_mir_insn->dalvikInsn.opcode;
523       switch (opcode) {
524         case Instruction::IF_EQ: opcode = Instruction::IF_NE; break;
525         case Instruction::IF_NE: opcode = Instruction::IF_EQ; break;
526         case Instruction::IF_LT: opcode = Instruction::IF_GE; break;
527         case Instruction::IF_GE: opcode = Instruction::IF_LT; break;
528         case Instruction::IF_GT: opcode = Instruction::IF_LE; break;
529         case Instruction::IF_LE: opcode = Instruction::IF_GT; break;
530         case Instruction::IF_EQZ: opcode = Instruction::IF_NEZ; break;
531         case Instruction::IF_NEZ: opcode = Instruction::IF_EQZ; break;
532         case Instruction::IF_LTZ: opcode = Instruction::IF_GEZ; break;
533         case Instruction::IF_GEZ: opcode = Instruction::IF_LTZ; break;
534         case Instruction::IF_GTZ: opcode = Instruction::IF_LEZ; break;
535         case Instruction::IF_LEZ: opcode = Instruction::IF_GTZ; break;
536         default: LOG(FATAL) << "Unexpected opcode " << opcode;
537       }
538       prev->last_mir_insn->dalvikInsn.opcode = opcode;
539       BasicBlock* t_bb = prev->taken;
540       prev->taken = prev->fall_through;
541       prev->fall_through = t_bb;
542       break;
543     }
544     walker = prev;
545   }
546   return false;
547 }
548 
549 /* Combine any basic blocks terminated by instructions that we now know can't throw */
CombineBlocks(struct BasicBlock * bb)550 bool MIRGraph::CombineBlocks(struct BasicBlock* bb) {
551   // Loop here to allow combining a sequence of blocks
552   while (true) {
553     // Check termination conditions
554     if ((bb->first_mir_insn == NULL)
555         || (bb->data_flow_info == NULL)
556         || (bb->block_type == kExceptionHandling)
557         || (bb->block_type == kExitBlock)
558         || (bb->block_type == kDead)
559         || ((bb->taken == NULL) || (bb->taken->block_type != kExceptionHandling))
560         || (bb->successor_block_list.block_list_type != kNotUsed)
561         || (static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) != kMirOpCheck)) {
562       break;
563     }
564 
565     // Test the kMirOpCheck instruction
566     MIR* mir = bb->last_mir_insn;
567     // Grab the attributes from the paired opcode
568     MIR* throw_insn = mir->meta.throw_insn;
569     int df_attributes = oat_data_flow_attributes_[throw_insn->dalvikInsn.opcode];
570     bool can_combine = true;
571     if (df_attributes & DF_HAS_NULL_CHKS) {
572       can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0);
573     }
574     if (df_attributes & DF_HAS_RANGE_CHKS) {
575       can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_RANGE_CHECK) != 0);
576     }
577     if (!can_combine) {
578       break;
579     }
580     // OK - got one.  Combine
581     BasicBlock* bb_next = bb->fall_through;
582     DCHECK(!bb_next->catch_entry);
583     DCHECK_EQ(Predecessors(bb_next), 1U);
584     MIR* t_mir = bb->last_mir_insn->prev;
585     // Overwrite the kOpCheck insn with the paired opcode
586     DCHECK_EQ(bb_next->first_mir_insn, throw_insn);
587     *bb->last_mir_insn = *throw_insn;
588     bb->last_mir_insn->prev = t_mir;
589     // Use the successor info from the next block
590     bb->successor_block_list = bb_next->successor_block_list;
591     // Use the ending block linkage from the next block
592     bb->fall_through = bb_next->fall_through;
593     bb->taken->block_type = kDead;  // Kill the unused exception block
594     bb->taken = bb_next->taken;
595     // Include the rest of the instructions
596     bb->last_mir_insn = bb_next->last_mir_insn;
597     /*
598      * If lower-half of pair of blocks to combine contained a return, move the flag
599      * to the newly combined block.
600      */
601     bb->terminated_by_return = bb_next->terminated_by_return;
602 
603     /*
604      * NOTE: we aren't updating all dataflow info here.  Should either make sure this pass
605      * happens after uses of i_dominated, dom_frontier or update the dataflow info here.
606      */
607 
608     // Kill bb_next and remap now-dead id to parent
609     bb_next->block_type = kDead;
610     block_id_map_.Overwrite(bb_next->id, bb->id);
611 
612     // Now, loop back and see if we can keep going
613   }
614   return false;
615 }
616 
617 /* Eliminate unnecessary null checks for a basic block. */
EliminateNullChecks(struct BasicBlock * bb)618 bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) {
619   if (bb->data_flow_info == NULL) return false;
620 
621   /*
622    * Set initial state.  Be conservative with catch
623    * blocks and start with no assumptions about null check
624    * status (except for "this").
625    */
626   if ((bb->block_type == kEntryBlock) | bb->catch_entry) {
627     temp_ssa_register_v_->ClearAllBits();
628     if ((cu_->access_flags & kAccStatic) == 0) {
629       // If non-static method, mark "this" as non-null
630       int this_reg = cu_->num_dalvik_registers - cu_->num_ins;
631       temp_ssa_register_v_->SetBit(this_reg);
632     }
633   } else if (bb->predecessors->Size() == 1) {
634     BasicBlock* pred_bb = bb->predecessors->Get(0);
635     temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v);
636     if (pred_bb->block_type == kDalvikByteCode) {
637       // Check to see if predecessor had an explicit null-check.
638       MIR* last_insn = pred_bb->last_mir_insn;
639       Instruction::Code last_opcode = last_insn->dalvikInsn.opcode;
640       if (last_opcode == Instruction::IF_EQZ) {
641         if (pred_bb->fall_through == bb) {
642           // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that
643           // it can't be null.
644           temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
645         }
646       } else if (last_opcode == Instruction::IF_NEZ) {
647         if (pred_bb->taken == bb) {
648           // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be
649           // null.
650           temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
651         }
652       }
653     }
654   } else {
655     // Starting state is intersection of all incoming arcs
656     GrowableArray<BasicBlock*>::Iterator iter(bb->predecessors);
657     BasicBlock* pred_bb = iter.Next();
658     DCHECK(pred_bb != NULL);
659     temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v);
660     while (true) {
661       pred_bb = iter.Next();
662       if (!pred_bb) break;
663       if ((pred_bb->data_flow_info == NULL) ||
664           (pred_bb->data_flow_info->ending_null_check_v == NULL)) {
665         continue;
666       }
667       temp_ssa_register_v_->Intersect(pred_bb->data_flow_info->ending_null_check_v);
668     }
669   }
670 
671   // Walk through the instruction in the block, updating as necessary
672   for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
673     if (mir->ssa_rep == NULL) {
674         continue;
675     }
676     int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
677 
678     // Mark target of NEW* as non-null
679     if (df_attributes & DF_NON_NULL_DST) {
680       temp_ssa_register_v_->SetBit(mir->ssa_rep->defs[0]);
681     }
682 
683     // Mark non-null returns from invoke-style NEW*
684     if (df_attributes & DF_NON_NULL_RET) {
685       MIR* next_mir = mir->next;
686       // Next should be an MOVE_RESULT_OBJECT
687       if (next_mir &&
688           next_mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
689         // Mark as null checked
690         temp_ssa_register_v_->SetBit(next_mir->ssa_rep->defs[0]);
691       } else {
692         if (next_mir) {
693           LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode;
694         } else if (bb->fall_through) {
695           // Look in next basic block
696           struct BasicBlock* next_bb = bb->fall_through;
697           for (MIR* tmir = next_bb->first_mir_insn; tmir != NULL;
698             tmir =tmir->next) {
699             if (static_cast<int>(tmir->dalvikInsn.opcode) >= static_cast<int>(kMirOpFirst)) {
700               continue;
701             }
702             // First non-pseudo should be MOVE_RESULT_OBJECT
703             if (tmir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
704               // Mark as null checked
705               temp_ssa_register_v_->SetBit(tmir->ssa_rep->defs[0]);
706             } else {
707               LOG(WARNING) << "Unexpected op after new: " << tmir->dalvikInsn.opcode;
708             }
709             break;
710           }
711         }
712       }
713     }
714 
715     /*
716      * Propagate nullcheck state on register copies (including
717      * Phi pseudo copies.  For the latter, nullcheck state is
718      * the "and" of all the Phi's operands.
719      */
720     if (df_attributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) {
721       int tgt_sreg = mir->ssa_rep->defs[0];
722       int operands = (df_attributes & DF_NULL_TRANSFER_0) ? 1 :
723           mir->ssa_rep->num_uses;
724       bool null_checked = true;
725       for (int i = 0; i < operands; i++) {
726         null_checked &= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]);
727       }
728       if (null_checked) {
729         temp_ssa_register_v_->SetBit(tgt_sreg);
730       }
731     }
732 
733     // Already nullchecked?
734     if ((df_attributes & DF_HAS_NULL_CHKS) && !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) {
735       int src_idx;
736       if (df_attributes & DF_NULL_CHK_1) {
737         src_idx = 1;
738       } else if (df_attributes & DF_NULL_CHK_2) {
739         src_idx = 2;
740       } else {
741         src_idx = 0;
742       }
743       int src_sreg = mir->ssa_rep->uses[src_idx];
744         if (temp_ssa_register_v_->IsBitSet(src_sreg)) {
745           // Eliminate the null check
746           mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
747         } else {
748           // Mark s_reg as null-checked
749           temp_ssa_register_v_->SetBit(src_sreg);
750         }
751      }
752   }
753 
754   // Did anything change?
755   bool changed = !temp_ssa_register_v_->Equal(bb->data_flow_info->ending_null_check_v);
756   if (changed) {
757     bb->data_flow_info->ending_null_check_v->Copy(temp_ssa_register_v_);
758   }
759   return changed;
760 }
761 
NullCheckElimination()762 void MIRGraph::NullCheckElimination() {
763   if (!(cu_->disable_opt & (1 << kNullCheckElimination))) {
764     DCHECK(temp_ssa_register_v_ != NULL);
765     AllNodesIterator iter(this, false /* not iterative */);
766     for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
767       NullCheckEliminationInit(bb);
768     }
769     PreOrderDfsIterator iter2(this, true /* iterative */);
770     bool change = false;
771     for (BasicBlock* bb = iter2.Next(change); bb != NULL; bb = iter2.Next(change)) {
772       change = EliminateNullChecks(bb);
773     }
774   }
775   if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
776     DumpCFG("/sdcard/4_post_nce_cfg/", false);
777   }
778 }
779 
BasicBlockCombine()780 void MIRGraph::BasicBlockCombine() {
781   PreOrderDfsIterator iter(this, false /* not iterative */);
782   for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
783     CombineBlocks(bb);
784   }
785   if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
786     DumpCFG("/sdcard/5_post_bbcombine_cfg/", false);
787   }
788 }
789 
CodeLayout()790 void MIRGraph::CodeLayout() {
791   if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) {
792     VerifyDataflow();
793   }
794   AllNodesIterator iter(this, false /* not iterative */);
795   for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
796     LayoutBlocks(bb);
797   }
798   if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
799     DumpCFG("/sdcard/2_post_layout_cfg/", true);
800   }
801 }
802 
DumpCheckStats()803 void MIRGraph::DumpCheckStats() {
804   Checkstats* stats =
805       static_cast<Checkstats*>(arena_->Alloc(sizeof(Checkstats), ArenaAllocator::kAllocDFInfo));
806   checkstats_ = stats;
807   AllNodesIterator iter(this, false /* not iterative */);
808   for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
809     CountChecks(bb);
810   }
811   if (stats->null_checks > 0) {
812     float eliminated = static_cast<float>(stats->null_checks_eliminated);
813     float checks = static_cast<float>(stats->null_checks);
814     LOG(INFO) << "Null Checks: " << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
815               << stats->null_checks_eliminated << " of " << stats->null_checks << " -> "
816               << (eliminated/checks) * 100.0 << "%";
817     }
818   if (stats->range_checks > 0) {
819     float eliminated = static_cast<float>(stats->range_checks_eliminated);
820     float checks = static_cast<float>(stats->range_checks);
821     LOG(INFO) << "Range Checks: " << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
822               << stats->range_checks_eliminated << " of " << stats->range_checks << " -> "
823               << (eliminated/checks) * 100.0 << "%";
824   }
825 }
826 
BuildExtendedBBList(struct BasicBlock * bb)827 bool MIRGraph::BuildExtendedBBList(struct BasicBlock* bb) {
828   if (bb->visited) return false;
829   if (!((bb->block_type == kEntryBlock) || (bb->block_type == kDalvikByteCode)
830       || (bb->block_type == kExitBlock))) {
831     // Ignore special blocks
832     bb->visited = true;
833     return false;
834   }
835   // Must be head of extended basic block.
836   BasicBlock* start_bb = bb;
837   extended_basic_blocks_.push_back(bb);
838   bool terminated_by_return = false;
839   // Visit blocks strictly dominated by this head.
840   while (bb != NULL) {
841     bb->visited = true;
842     terminated_by_return |= bb->terminated_by_return;
843     bb = NextDominatedBlock(bb);
844   }
845   if (terminated_by_return) {
846     // This extended basic block contains a return, so mark all members.
847     bb = start_bb;
848     while (bb != NULL) {
849       bb->dominates_return = true;
850       bb = NextDominatedBlock(bb);
851     }
852   }
853   return false;  // Not iterative - return value will be ignored
854 }
855 
856 
BasicBlockOptimization()857 void MIRGraph::BasicBlockOptimization() {
858   if (!(cu_->disable_opt & (1 << kBBOpt))) {
859     DCHECK_EQ(cu_->num_compiler_temps, 0);
860     ClearAllVisitedFlags();
861     PreOrderDfsIterator iter2(this, false /* not iterative */);
862     for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) {
863       BuildExtendedBBList(bb);
864     }
865     // Perform extended basic block optimizations.
866     for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) {
867       BasicBlockOpt(extended_basic_blocks_[i]);
868     }
869   }
870   if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
871     DumpCFG("/sdcard/6_post_bbo_cfg/", false);
872   }
873 }
874 
875 }  // namespace art
876