Home | History | Annotate | Download | only in dex
      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 "dex/dataflow_iterator-inl.h"
     19 
     20 namespace art {
     21 
     22 bool MIRGraph::SetFp(int index, bool is_fp) {
     23   bool change = false;
     24   if (is_fp && !reg_location_[index].fp) {
     25     reg_location_[index].fp = true;
     26     reg_location_[index].defined = true;
     27     change = true;
     28   }
     29   return change;
     30 }
     31 
     32 bool MIRGraph::SetCore(int index, bool is_core) {
     33   bool change = false;
     34   if (is_core && !reg_location_[index].defined) {
     35     reg_location_[index].core = true;
     36     reg_location_[index].defined = true;
     37     change = true;
     38   }
     39   return change;
     40 }
     41 
     42 bool MIRGraph::SetRef(int index, bool is_ref) {
     43   bool change = false;
     44   if (is_ref && !reg_location_[index].defined) {
     45     reg_location_[index].ref = true;
     46     reg_location_[index].defined = true;
     47     change = true;
     48   }
     49   return change;
     50 }
     51 
     52 bool MIRGraph::SetWide(int index, bool is_wide) {
     53   bool change = false;
     54   if (is_wide && !reg_location_[index].wide) {
     55     reg_location_[index].wide = true;
     56     change = true;
     57   }
     58   return change;
     59 }
     60 
     61 bool MIRGraph::SetHigh(int index, bool is_high) {
     62   bool change = false;
     63   if (is_high && !reg_location_[index].high_word) {
     64     reg_location_[index].high_word = true;
     65     change = true;
     66   }
     67   return change;
     68 }
     69 
     70 /*
     71  * Infer types and sizes.  We don't need to track change on sizes,
     72  * as it doesn't propagate.  We're guaranteed at least one pass through
     73  * the cfg.
     74  */
     75 bool MIRGraph::InferTypeAndSize(BasicBlock* bb) {
     76   MIR *mir;
     77   bool changed = false;   // Did anything change?
     78 
     79   if (bb->data_flow_info == NULL) return false;
     80   if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock)
     81     return false;
     82 
     83   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
     84     SSARepresentation *ssa_rep = mir->ssa_rep;
     85     if (ssa_rep) {
     86       int attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
     87 
     88       // Handle defs
     89       if (attrs & DF_DA) {
     90         if (attrs & DF_CORE_A) {
     91           changed |= SetCore(ssa_rep->defs[0], true);
     92         }
     93         if (attrs & DF_REF_A) {
     94           changed |= SetRef(ssa_rep->defs[0], true);
     95         }
     96         if (attrs & DF_A_WIDE) {
     97           reg_location_[ssa_rep->defs[0]].wide = true;
     98           reg_location_[ssa_rep->defs[1]].wide = true;
     99           reg_location_[ssa_rep->defs[1]].high_word = true;
    100           DCHECK_EQ(SRegToVReg(ssa_rep->defs[0])+1,
    101           SRegToVReg(ssa_rep->defs[1]));
    102         }
    103       }
    104 
    105       // Handles uses
    106       int next = 0;
    107       if (attrs & DF_UA) {
    108         if (attrs & DF_CORE_A) {
    109           changed |= SetCore(ssa_rep->uses[next], true);
    110         }
    111         if (attrs & DF_REF_A) {
    112           changed |= SetRef(ssa_rep->uses[next], true);
    113         }
    114         if (attrs & DF_A_WIDE) {
    115           reg_location_[ssa_rep->uses[next]].wide = true;
    116           reg_location_[ssa_rep->uses[next + 1]].wide = true;
    117           reg_location_[ssa_rep->uses[next + 1]].high_word = true;
    118           DCHECK_EQ(SRegToVReg(ssa_rep->uses[next])+1,
    119           SRegToVReg(ssa_rep->uses[next + 1]));
    120           next += 2;
    121         } else {
    122           next++;
    123         }
    124       }
    125       if (attrs & DF_UB) {
    126         if (attrs & DF_CORE_B) {
    127           changed |= SetCore(ssa_rep->uses[next], true);
    128         }
    129         if (attrs & DF_REF_B) {
    130           changed |= SetRef(ssa_rep->uses[next], true);
    131         }
    132         if (attrs & DF_B_WIDE) {
    133           reg_location_[ssa_rep->uses[next]].wide = true;
    134           reg_location_[ssa_rep->uses[next + 1]].wide = true;
    135           reg_location_[ssa_rep->uses[next + 1]].high_word = true;
    136           DCHECK_EQ(SRegToVReg(ssa_rep->uses[next])+1,
    137                                SRegToVReg(ssa_rep->uses[next + 1]));
    138           next += 2;
    139         } else {
    140           next++;
    141         }
    142       }
    143       if (attrs & DF_UC) {
    144         if (attrs & DF_CORE_C) {
    145           changed |= SetCore(ssa_rep->uses[next], true);
    146         }
    147         if (attrs & DF_REF_C) {
    148           changed |= SetRef(ssa_rep->uses[next], true);
    149         }
    150         if (attrs & DF_C_WIDE) {
    151           reg_location_[ssa_rep->uses[next]].wide = true;
    152           reg_location_[ssa_rep->uses[next + 1]].wide = true;
    153           reg_location_[ssa_rep->uses[next + 1]].high_word = true;
    154           DCHECK_EQ(SRegToVReg(ssa_rep->uses[next])+1,
    155           SRegToVReg(ssa_rep->uses[next + 1]));
    156         }
    157       }
    158 
    159       // Special-case return handling
    160       if ((mir->dalvikInsn.opcode == Instruction::RETURN) ||
    161           (mir->dalvikInsn.opcode == Instruction::RETURN_WIDE) ||
    162           (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) {
    163         switch (cu_->shorty[0]) {
    164             case 'I':
    165               changed |= SetCore(ssa_rep->uses[0], true);
    166               break;
    167             case 'J':
    168               changed |= SetCore(ssa_rep->uses[0], true);
    169               changed |= SetCore(ssa_rep->uses[1], true);
    170               reg_location_[ssa_rep->uses[0]].wide = true;
    171               reg_location_[ssa_rep->uses[1]].wide = true;
    172               reg_location_[ssa_rep->uses[1]].high_word = true;
    173               break;
    174             case 'F':
    175               changed |= SetFp(ssa_rep->uses[0], true);
    176               break;
    177             case 'D':
    178               changed |= SetFp(ssa_rep->uses[0], true);
    179               changed |= SetFp(ssa_rep->uses[1], true);
    180               reg_location_[ssa_rep->uses[0]].wide = true;
    181               reg_location_[ssa_rep->uses[1]].wide = true;
    182               reg_location_[ssa_rep->uses[1]].high_word = true;
    183               break;
    184             case 'L':
    185               changed |= SetRef(ssa_rep->uses[0], true);
    186               break;
    187             default: break;
    188         }
    189       }
    190 
    191       // Special-case handling for format 35c/3rc invokes
    192       Instruction::Code opcode = mir->dalvikInsn.opcode;
    193       int flags = (static_cast<int>(opcode) >= kNumPackedOpcodes)
    194           ? 0 : Instruction::FlagsOf(mir->dalvikInsn.opcode);
    195       if ((flags & Instruction::kInvoke) &&
    196           (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) {
    197         DCHECK_EQ(next, 0);
    198         int target_idx = mir->dalvikInsn.vB;
    199         const char* shorty = GetShortyFromTargetIdx(target_idx);
    200         // Handle result type if floating point
    201         if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
    202           MIR* move_result_mir = FindMoveResult(bb, mir);
    203           // Result might not be used at all, so no move-result
    204           if (move_result_mir && (move_result_mir->dalvikInsn.opcode !=
    205               Instruction::MOVE_RESULT_OBJECT)) {
    206             SSARepresentation* tgt_rep = move_result_mir->ssa_rep;
    207             DCHECK(tgt_rep != NULL);
    208             tgt_rep->fp_def[0] = true;
    209             changed |= SetFp(tgt_rep->defs[0], true);
    210             if (shorty[0] == 'D') {
    211               tgt_rep->fp_def[1] = true;
    212               changed |= SetFp(tgt_rep->defs[1], true);
    213             }
    214           }
    215         }
    216         int num_uses = mir->dalvikInsn.vA;
    217         // If this is a non-static invoke, mark implicit "this"
    218         if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) &&
    219             (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) {
    220           reg_location_[ssa_rep->uses[next]].defined = true;
    221           reg_location_[ssa_rep->uses[next]].ref = true;
    222           next++;
    223         }
    224         uint32_t cpos = 1;
    225         if (strlen(shorty) > 1) {
    226           for (int i = next; i < num_uses;) {
    227             DCHECK_LT(cpos, strlen(shorty));
    228             switch (shorty[cpos++]) {
    229               case 'D':
    230                 ssa_rep->fp_use[i] = true;
    231                 ssa_rep->fp_use[i+1] = true;
    232                 reg_location_[ssa_rep->uses[i]].wide = true;
    233                 reg_location_[ssa_rep->uses[i+1]].wide = true;
    234                 reg_location_[ssa_rep->uses[i+1]].high_word = true;
    235                 DCHECK_EQ(SRegToVReg(ssa_rep->uses[i])+1, SRegToVReg(ssa_rep->uses[i+1]));
    236                 i++;
    237                 break;
    238               case 'J':
    239                 reg_location_[ssa_rep->uses[i]].wide = true;
    240                 reg_location_[ssa_rep->uses[i+1]].wide = true;
    241                 reg_location_[ssa_rep->uses[i+1]].high_word = true;
    242                 DCHECK_EQ(SRegToVReg(ssa_rep->uses[i])+1, SRegToVReg(ssa_rep->uses[i+1]));
    243                 changed |= SetCore(ssa_rep->uses[i], true);
    244                 i++;
    245                 break;
    246               case 'F':
    247                 ssa_rep->fp_use[i] = true;
    248                 break;
    249               case 'L':
    250                 changed |= SetRef(ssa_rep->uses[i], true);
    251                 break;
    252               default:
    253                 changed |= SetCore(ssa_rep->uses[i], true);
    254                 break;
    255             }
    256             i++;
    257           }
    258         }
    259       }
    260 
    261       for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) {
    262         if (ssa_rep->fp_use[i])
    263           changed |= SetFp(ssa_rep->uses[i], true);
    264         }
    265       for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) {
    266         if (ssa_rep->fp_def[i])
    267           changed |= SetFp(ssa_rep->defs[i], true);
    268         }
    269       // Special-case handling for moves & Phi
    270       if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) {
    271         /*
    272          * If any of our inputs or outputs is defined, set all.
    273          * Some ugliness related to Phi nodes and wide values.
    274          * The Phi set will include all low words or all high
    275          * words, so we have to treat them specially.
    276          */
    277         bool is_phi = (static_cast<int>(mir->dalvikInsn.opcode) ==
    278                       kMirOpPhi);
    279         RegLocation rl_temp = reg_location_[ssa_rep->defs[0]];
    280         bool defined_fp = rl_temp.defined && rl_temp.fp;
    281         bool defined_core = rl_temp.defined && rl_temp.core;
    282         bool defined_ref = rl_temp.defined && rl_temp.ref;
    283         bool is_wide = rl_temp.wide || ((attrs & DF_A_WIDE) != 0);
    284         bool is_high = is_phi && rl_temp.wide && rl_temp.high_word;
    285         for (int i = 0; i < ssa_rep->num_uses; i++) {
    286           rl_temp = reg_location_[ssa_rep->uses[i]];
    287           defined_fp |= rl_temp.defined && rl_temp.fp;
    288           defined_core |= rl_temp.defined && rl_temp.core;
    289           defined_ref |= rl_temp.defined && rl_temp.ref;
    290           is_wide |= rl_temp.wide;
    291           is_high |= is_phi && rl_temp.wide && rl_temp.high_word;
    292         }
    293         /*
    294          * We don't normally expect to see a Dalvik register definition used both as a
    295          * floating point and core value, though technically it could happen with constants.
    296          * Until we have proper typing, detect this situation and disable register promotion
    297          * (which relies on the distinction between core a fp usages).
    298          */
    299         if ((defined_fp && (defined_core | defined_ref)) &&
    300             ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) {
    301           LOG(WARNING) << PrettyMethod(cu_->method_idx, *cu_->dex_file)
    302                        << " op at block " << bb->id
    303                        << " has both fp and core/ref uses for same def.";
    304           cu_->disable_opt |= (1 << kPromoteRegs);
    305         }
    306         changed |= SetFp(ssa_rep->defs[0], defined_fp);
    307         changed |= SetCore(ssa_rep->defs[0], defined_core);
    308         changed |= SetRef(ssa_rep->defs[0], defined_ref);
    309         changed |= SetWide(ssa_rep->defs[0], is_wide);
    310         changed |= SetHigh(ssa_rep->defs[0], is_high);
    311         if (attrs & DF_A_WIDE) {
    312           changed |= SetWide(ssa_rep->defs[1], true);
    313           changed |= SetHigh(ssa_rep->defs[1], true);
    314         }
    315         for (int i = 0; i < ssa_rep->num_uses; i++) {
    316           changed |= SetFp(ssa_rep->uses[i], defined_fp);
    317           changed |= SetCore(ssa_rep->uses[i], defined_core);
    318           changed |= SetRef(ssa_rep->uses[i], defined_ref);
    319           changed |= SetWide(ssa_rep->uses[i], is_wide);
    320           changed |= SetHigh(ssa_rep->uses[i], is_high);
    321         }
    322         if (attrs & DF_A_WIDE) {
    323           DCHECK_EQ(ssa_rep->num_uses, 2);
    324           changed |= SetWide(ssa_rep->uses[1], true);
    325           changed |= SetHigh(ssa_rep->uses[1], true);
    326         }
    327       }
    328     }
    329   }
    330   return changed;
    331 }
    332 
    333 static const char* storage_name[] = {" Frame ", "PhysReg", " Spill "};
    334 
    335 void MIRGraph::DumpRegLocTable(RegLocation* table, int count) {
    336   // FIXME: Quick-specific.  Move to Quick (and make a generic version for MIRGraph?
    337   Mir2Lir* cg = static_cast<Mir2Lir*>(cu_->cg.get());
    338   if (cg != NULL) {
    339     for (int i = 0; i < count; i++) {
    340       LOG(INFO) << StringPrintf("Loc[%02d] : %s, %c %c %c %c %c %c %c%d %c%d S%d",
    341           table[i].orig_sreg, storage_name[table[i].location],
    342           table[i].wide ? 'W' : 'N', table[i].defined ? 'D' : 'U',
    343           table[i].fp ? 'F' : table[i].ref ? 'R' :'C',
    344           table[i].is_const ? 'c' : 'n',
    345           table[i].high_word ? 'H' : 'L', table[i].home ? 'h' : 't',
    346           cg->IsFpReg(table[i].low_reg) ? 's' : 'r',
    347           table[i].low_reg & cg->FpRegMask(),
    348           cg->IsFpReg(table[i].high_reg) ? 's' : 'r',
    349           table[i].high_reg & cg->FpRegMask(), table[i].s_reg_low);
    350     }
    351   } else {
    352     // Either pre-regalloc or Portable.
    353     for (int i = 0; i < count; i++) {
    354       LOG(INFO) << StringPrintf("Loc[%02d] : %s, %c %c %c %c %c %c S%d",
    355           table[i].orig_sreg, storage_name[table[i].location],
    356           table[i].wide ? 'W' : 'N', table[i].defined ? 'D' : 'U',
    357           table[i].fp ? 'F' : table[i].ref ? 'R' :'C',
    358           table[i].is_const ? 'c' : 'n',
    359           table[i].high_word ? 'H' : 'L', table[i].home ? 'h' : 't',
    360           table[i].s_reg_low);
    361     }
    362   }
    363 }
    364 
    365 static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0,
    366                                      INVALID_REG, INVALID_REG, INVALID_SREG,
    367                                      INVALID_SREG};
    368 
    369 /*
    370  * Simple register allocation.  Some Dalvik virtual registers may
    371  * be promoted to physical registers.  Most of the work for temp
    372  * allocation is done on the fly.  We also do some initialization and
    373  * type inference here.
    374  */
    375 void MIRGraph::BuildRegLocations() {
    376   /* Allocate the location map */
    377   RegLocation* loc = static_cast<RegLocation*>(arena_->Alloc(GetNumSSARegs() * sizeof(*loc),
    378                                                              ArenaAllocator::kAllocRegAlloc));
    379   for (int i = 0; i < GetNumSSARegs(); i++) {
    380     loc[i] = fresh_loc;
    381     loc[i].s_reg_low = i;
    382     loc[i].is_const = is_constant_v_->IsBitSet(i);
    383   }
    384 
    385   /* Patch up the locations for Method* and the compiler temps */
    386   loc[method_sreg_].location = kLocCompilerTemp;
    387   loc[method_sreg_].defined = true;
    388   for (int i = 0; i < cu_->num_compiler_temps; i++) {
    389     CompilerTemp* ct = compiler_temps_.Get(i);
    390     loc[ct->s_reg].location = kLocCompilerTemp;
    391     loc[ct->s_reg].defined = true;
    392   }
    393 
    394   reg_location_ = loc;
    395 
    396   int num_regs = cu_->num_dalvik_registers;
    397 
    398   /* Add types of incoming arguments based on signature */
    399   int num_ins = cu_->num_ins;
    400   if (num_ins > 0) {
    401     int s_reg = num_regs - num_ins;
    402     if ((cu_->access_flags & kAccStatic) == 0) {
    403       // For non-static, skip past "this"
    404       reg_location_[s_reg].defined = true;
    405       reg_location_[s_reg].ref = true;
    406       s_reg++;
    407     }
    408     const char* shorty = cu_->shorty;
    409     int shorty_len = strlen(shorty);
    410     for (int i = 1; i < shorty_len; i++) {
    411       switch (shorty[i]) {
    412         case 'D':
    413           reg_location_[s_reg].wide = true;
    414           reg_location_[s_reg+1].high_word = true;
    415           reg_location_[s_reg+1].fp = true;
    416           DCHECK_EQ(SRegToVReg(s_reg)+1, SRegToVReg(s_reg+1));
    417           reg_location_[s_reg].fp = true;
    418           reg_location_[s_reg].defined = true;
    419           s_reg++;
    420           break;
    421         case 'J':
    422           reg_location_[s_reg].wide = true;
    423           reg_location_[s_reg+1].high_word = true;
    424           DCHECK_EQ(SRegToVReg(s_reg)+1, SRegToVReg(s_reg+1));
    425           reg_location_[s_reg].core = true;
    426           reg_location_[s_reg].defined = true;
    427           s_reg++;
    428           break;
    429         case 'F':
    430           reg_location_[s_reg].fp = true;
    431           reg_location_[s_reg].defined = true;
    432           break;
    433         case 'L':
    434           reg_location_[s_reg].ref = true;
    435           reg_location_[s_reg].defined = true;
    436           break;
    437         default:
    438           reg_location_[s_reg].core = true;
    439           reg_location_[s_reg].defined = true;
    440           break;
    441         }
    442         s_reg++;
    443       }
    444   }
    445 
    446   /* Do type & size inference pass */
    447   PreOrderDfsIterator iter(this, true /* iterative */);
    448   bool change = false;
    449   for (BasicBlock* bb = iter.Next(false); bb != NULL; bb = iter.Next(change)) {
    450     change = InferTypeAndSize(bb);
    451   }
    452 
    453   /*
    454    * Set the s_reg_low field to refer to the pre-SSA name of the
    455    * base Dalvik virtual register.  Once we add a better register
    456    * allocator, remove this remapping.
    457    */
    458   for (int i = 0; i < GetNumSSARegs(); i++) {
    459     if (reg_location_[i].location != kLocCompilerTemp) {
    460       int orig_sreg = reg_location_[i].s_reg_low;
    461       reg_location_[i].orig_sreg = orig_sreg;
    462       reg_location_[i].s_reg_low = SRegToVReg(orig_sreg);
    463     }
    464   }
    465 }
    466 
    467 }  // namespace art
    468