Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2014 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 "global_value_numbering.h"
     18 
     19 #include "local_value_numbering.h"
     20 
     21 namespace art {
     22 
     23 GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator)
     24     : cu_(cu),
     25       mir_graph_(cu->mir_graph.get()),
     26       allocator_(allocator),
     27       bbs_processed_(0u),
     28       max_bbs_to_process_(kMaxBbsToProcessMultiplyFactor * mir_graph_->GetNumReachableBlocks()),
     29       last_value_(0u),
     30       modifications_allowed_(false),
     31       global_value_map_(std::less<uint64_t>(), allocator->Adapter()),
     32       field_index_map_(FieldReferenceComparator(), allocator->Adapter()),
     33       field_index_reverse_map_(allocator->Adapter()),
     34       array_location_map_(ArrayLocationComparator(), allocator->Adapter()),
     35       array_location_reverse_map_(allocator->Adapter()),
     36       ref_set_map_(std::less<ValueNameSet>(), allocator->Adapter()),
     37       lvns_(mir_graph_->GetNumBlocks(), nullptr, allocator->Adapter()),
     38       work_lvn_(nullptr),
     39       merge_lvns_(allocator->Adapter()) {
     40 }
     41 
     42 GlobalValueNumbering::~GlobalValueNumbering() {
     43   STLDeleteElements(&lvns_);
     44 }
     45 
     46 LocalValueNumbering* GlobalValueNumbering::PrepareBasicBlock(BasicBlock* bb,
     47                                                              ScopedArenaAllocator* allocator) {
     48   if (UNLIKELY(!Good())) {
     49     return nullptr;
     50   }
     51   if (UNLIKELY(bb->data_flow_info == nullptr)) {
     52     return nullptr;
     53   }
     54   if (UNLIKELY(bb->block_type == kExitBlock)) {
     55     DCHECK(bb->first_mir_insn == nullptr);
     56     return nullptr;
     57   }
     58   if (UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
     59     last_value_ = kNoValue;  // Make bad.
     60     return nullptr;
     61   }
     62   if (allocator == nullptr) {
     63     allocator = allocator_;
     64   }
     65   DCHECK(work_lvn_.get() == nullptr);
     66   work_lvn_.reset(new (allocator) LocalValueNumbering(this, bb->id, allocator));
     67   if (bb->block_type == kEntryBlock) {
     68     if ((cu_->access_flags & kAccStatic) == 0) {
     69       // If non-static method, mark "this" as non-null
     70       int this_reg = cu_->num_dalvik_registers - cu_->num_ins;
     71       uint16_t value_name = work_lvn_->GetSRegValueName(this_reg);
     72       work_lvn_->SetValueNameNullChecked(value_name);
     73     }
     74   } else {
     75     // To avoid repeated allocation on the ArenaStack, reuse a single vector kept as a member.
     76     DCHECK(merge_lvns_.empty());
     77     // If we're running the full GVN, the RepeatingTopologicalSortIterator keeps the loop
     78     // head stack in the MIRGraph up to date and for a loop head we need to check whether
     79     // we're making the initial computation and need to merge only preceding blocks in the
     80     // topological order, or we're recalculating a loop head and need to merge all incoming
     81     // LVNs. When we're not at a loop head (including having an empty loop head stack) all
     82     // predecessors should be preceding blocks and we shall merge all of them anyway.
     83     //
     84     // If we're running the modification phase of the full GVN, the loop head stack will be
     85     // empty and we need to merge all incoming LVNs. If we're running just a simple LVN,
     86     // the loop head stack will also be empty and there will be nothing to merge anyway.
     87     bool use_all_predecessors = true;
     88     uint16_t loop_head_idx = 0u;  // Used only if !use_all_predecessors.
     89     if (mir_graph_->GetTopologicalSortOrderLoopHeadStack()->Size() != 0) {
     90       // Full GVN inside a loop, see if we're at the loop head for the first time.
     91       auto top = mir_graph_->GetTopologicalSortOrderLoopHeadStack()->Peek();
     92       loop_head_idx = top.first;
     93       bool recalculating = top.second;
     94       use_all_predecessors = recalculating ||
     95           loop_head_idx != mir_graph_->GetTopologicalSortOrderIndexes()->Get(bb->id);
     96     }
     97     GrowableArray<BasicBlockId>::Iterator iter(bb->predecessors);
     98     for (BasicBlock* pred_bb = mir_graph_->GetBasicBlock(iter.Next());
     99          pred_bb != nullptr; pred_bb = mir_graph_->GetBasicBlock(iter.Next())) {
    100       if (lvns_[pred_bb->id] != nullptr &&
    101           (use_all_predecessors ||
    102               mir_graph_->GetTopologicalSortOrderIndexes()->Get(pred_bb->id) < loop_head_idx)) {
    103         merge_lvns_.push_back(lvns_[pred_bb->id]);
    104       }
    105     }
    106     // Determine merge type.
    107     LocalValueNumbering::MergeType merge_type = LocalValueNumbering::kNormalMerge;
    108     if (bb->catch_entry) {
    109       merge_type = LocalValueNumbering::kCatchMerge;
    110     } else if (bb->last_mir_insn != nullptr &&
    111         (bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_VOID ||
    112          bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN ||
    113          bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_OBJECT ||
    114          bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_WIDE) &&
    115         (bb->first_mir_insn == bb->last_mir_insn ||
    116          (static_cast<int>(bb->first_mir_insn->dalvikInsn.opcode) == kMirOpPhi &&
    117           (bb->first_mir_insn->next == bb->last_mir_insn ||
    118            (static_cast<int>(bb->first_mir_insn->next->dalvikInsn.opcode) == kMirOpPhi &&
    119             bb->first_mir_insn->next->next == bb->last_mir_insn))))) {
    120       merge_type = LocalValueNumbering::kReturnMerge;
    121     }
    122     // At least one predecessor must have been processed before this bb.
    123     CHECK(!merge_lvns_.empty());
    124     if (merge_lvns_.size() == 1u) {
    125       work_lvn_->MergeOne(*merge_lvns_[0], merge_type);
    126       BasicBlock* pred_bb = mir_graph_->GetBasicBlock(merge_lvns_[0]->Id());
    127       if (HasNullCheckLastInsn(pred_bb, bb->id)) {
    128         int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
    129         uint16_t value_name = merge_lvns_[0]->GetSRegValueName(s_reg);
    130         work_lvn_->SetValueNameNullChecked(value_name);
    131       }
    132     } else {
    133       work_lvn_->Merge(merge_type);
    134     }
    135   }
    136   return work_lvn_.get();
    137 }
    138 
    139 bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) {
    140   DCHECK(work_lvn_ != nullptr);
    141   DCHECK_EQ(bb->id, work_lvn_->Id());
    142   ++bbs_processed_;
    143   merge_lvns_.clear();
    144 
    145   bool change = (lvns_[bb->id] == nullptr) || !lvns_[bb->id]->Equals(*work_lvn_);
    146   if (change) {
    147     std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]);
    148     lvns_[bb->id] = work_lvn_.release();
    149   } else {
    150     work_lvn_.reset();
    151   }
    152   return change;
    153 }
    154 
    155 uint16_t GlobalValueNumbering::GetFieldId(const MirFieldInfo& field_info, uint16_t type) {
    156   FieldReference key = { field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex(), type };
    157   auto lb = field_index_map_.lower_bound(key);
    158   if (lb != field_index_map_.end() && !field_index_map_.key_comp()(key, lb->first)) {
    159     return lb->second;
    160   }
    161   DCHECK_LT(field_index_map_.size(), kNoValue);
    162   uint16_t id = field_index_map_.size();
    163   auto it = field_index_map_.PutBefore(lb, key, id);
    164   field_index_reverse_map_.push_back(&*it);
    165   return id;
    166 }
    167 
    168 uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) {
    169   auto cmp = array_location_map_.key_comp();
    170   ArrayLocation key = { base, index };
    171   auto lb = array_location_map_.lower_bound(key);
    172   if (lb != array_location_map_.end() && !cmp(key, lb->first)) {
    173     return lb->second;
    174   }
    175   uint16_t location = static_cast<uint16_t>(array_location_reverse_map_.size());
    176   DCHECK_EQ(location, array_location_reverse_map_.size());  // No overflow.
    177   auto it = array_location_map_.PutBefore(lb, key, location);
    178   array_location_reverse_map_.push_back(&*it);
    179   return location;
    180 }
    181 
    182 bool GlobalValueNumbering::HasNullCheckLastInsn(const BasicBlock* pred_bb,
    183                                                 BasicBlockId succ_id) {
    184   if (pred_bb->block_type != kDalvikByteCode || pred_bb->last_mir_insn == nullptr) {
    185     return false;
    186   }
    187   Instruction::Code last_opcode = pred_bb->last_mir_insn->dalvikInsn.opcode;
    188   return ((last_opcode == Instruction::IF_EQZ && pred_bb->fall_through == succ_id) ||
    189       (last_opcode == Instruction::IF_NEZ && pred_bb->taken == succ_id));
    190 }
    191 
    192 bool GlobalValueNumbering::NullCheckedInAllPredecessors(
    193     const ScopedArenaVector<uint16_t>& merge_names) const {
    194   // Implicit parameters:
    195   //   - *work_lvn: the LVN for which we're checking predecessors.
    196   //   - merge_lvns_: the predecessor LVNs.
    197   DCHECK_EQ(merge_lvns_.size(), merge_names.size());
    198   for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
    199     const LocalValueNumbering* pred_lvn = merge_lvns_[i];
    200     uint16_t value_name = merge_names[i];
    201     if (!pred_lvn->IsValueNullChecked(value_name)) {
    202       // Check if the predecessor has an IF_EQZ/IF_NEZ as the last insn.
    203       const BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_lvn->Id());
    204       if (!HasNullCheckLastInsn(pred_bb, work_lvn_->Id())) {
    205         return false;
    206       }
    207       // IF_EQZ/IF_NEZ checks some sreg, see if that sreg contains the value_name.
    208       int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
    209       if (!pred_lvn->IsSregValue(s_reg, value_name)) {
    210         return false;
    211       }
    212     }
    213   }
    214   return true;
    215 }
    216 
    217 }  // namespace art
    218