summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2014-12-09 11:09:39 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-12-09 11:09:40 +0000
commit6bb3919e4413ad50f9b7e009829bba292b609e03 (patch)
tree2b99a452959b6380ca5117a64648e83d63c9d6e2 /compiler
parentd1780b98e5b58208e6836c8520dad2a2dadfe322 (diff)
parent8b858e16563ebf8e522df026a6ab409f1bd9b3de (diff)
downloadart-6bb3919e4413ad50f9b7e009829bba292b609e03.zip
art-6bb3919e4413ad50f9b7e009829bba292b609e03.tar.gz
art-6bb3919e4413ad50f9b7e009829bba292b609e03.tar.bz2
Merge "Quick: Redefine the notion of back-egdes."
Diffstat (limited to 'compiler')
-rw-r--r--compiler/dex/bb_optimizations.h35
-rw-r--r--compiler/dex/frontend.cc1
-rw-r--r--compiler/dex/frontend.h1
-rw-r--r--compiler/dex/mir_dataflow.cc2
-rw-r--r--compiler/dex/mir_graph.cc21
-rw-r--r--compiler/dex/mir_graph.h60
-rw-r--r--compiler/dex/mir_optimization.cc127
-rw-r--r--compiler/dex/mir_optimization_test.cc294
-rw-r--r--compiler/dex/pass_driver_me_opts.cc1
-rw-r--r--compiler/dex/quick/gen_common.cc21
-rw-r--r--compiler/dex/quick/mir_to_lir.cc62
-rw-r--r--compiler/dex/quick/mir_to_lir.h4
-rw-r--r--compiler/dex/ssa_transformation.cc6
13 files changed, 499 insertions, 136 deletions
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h
index 764a4cf..0407e32 100644
--- a/compiler/dex/bb_optimizations.h
+++ b/compiler/dex/bb_optimizations.h
@@ -297,6 +297,41 @@ class BBOptimizations : public PassME {
void Start(PassDataHolder* data) const;
};
+/**
+ * @class SuspendCheckElimination
+ * @brief Any simple BasicBlock optimization can be put here.
+ */
+class SuspendCheckElimination : public PassME {
+ public:
+ SuspendCheckElimination()
+ : PassME("SuspendCheckElimination", kTopologicalSortTraversal, "6_post_sce_cfg") {
+ }
+
+ bool Gate(const PassDataHolder* data) const {
+ DCHECK(data != nullptr);
+ CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+ DCHECK(c_unit != nullptr);
+ return c_unit->mir_graph->EliminateSuspendChecksGate();
+ }
+
+ bool Worker(PassDataHolder* data) const {
+ DCHECK(data != nullptr);
+ PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
+ CompilationUnit* c_unit = pass_me_data_holder->c_unit;
+ DCHECK(c_unit != nullptr);
+ BasicBlock* bb = pass_me_data_holder->bb;
+ DCHECK(bb != nullptr);
+ return c_unit->mir_graph->EliminateSuspendChecks(bb);
+ }
+
+ void End(PassDataHolder* data) const {
+ DCHECK(data != nullptr);
+ CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+ DCHECK(c_unit != nullptr);
+ c_unit->mir_graph->EliminateSuspendChecksEnd();
+ }
+};
+
} // namespace art
#endif // ART_COMPILER_DEX_BB_OPTIMIZATIONS_H_
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 3f6231c..fb5dc9c 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -47,6 +47,7 @@ static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimi
// (1 << kTrackLiveTemps) |
// (1 << kSafeOptimizations) |
// (1 << kBBOpt) |
+ // (1 << kSuspendCheckElimination) |
// (1 << kMatch) |
// (1 << kPromoteCompilerTemps) |
// (1 << kSuppressExceptionEdges) |
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index bed3b97..1145818 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -46,6 +46,7 @@ enum opt_control_vector {
kTrackLiveTemps,
kSafeOptimizations,
kBBOpt,
+ kSuspendCheckElimination,
kMatch,
kPromoteCompilerTemps,
kBranchFusing,
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 5b7ac3c..64895d8 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -1343,7 +1343,7 @@ void MIRGraph::CompilerInitializeSSAConversion() {
* counts explicitly used s_regs. A later phase will add implicit
* counts for things such as Method*, null-checked references, etc.
*/
-void MIRGraph::CountUses(class BasicBlock* bb) {
+void MIRGraph::CountUses(BasicBlock* bb) {
if (bb->block_type != kDalvikByteCode) {
return;
}
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index b17f506..d7ecb2c 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -127,7 +127,7 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena)
ifield_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)),
sfield_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)),
method_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)),
- gen_suspend_test_list_(arena->Adapter()) {
+ suspend_checks_in_loops_(nullptr) {
memset(&temp_, 0, sizeof(temp_));
use_counts_.reserve(256);
raw_use_counts_.reserve(256);
@@ -1947,6 +1947,7 @@ void MIRGraph::ComputeTopologicalSortOrder() {
DCHECK_EQ(bb->hidden, false);
DCHECK_EQ(bb->visited, false);
bb->visited = true;
+ bb->nesting_depth = loop_head_stack.size();
// Now add the basic block.
uint16_t idx = static_cast<uint16_t>(topological_order_.size());
@@ -1988,24 +1989,6 @@ bool BasicBlock::IsExceptionBlock() const {
return false;
}
-bool MIRGraph::HasSuspendTestBetween(BasicBlock* source, BasicBlockId target_id) {
- BasicBlock* target = GetBasicBlock(target_id);
-
- if (source == nullptr || target == nullptr)
- return false;
-
- int idx;
- for (idx = gen_suspend_test_list_.size() - 1; idx >= 0; idx--) {
- BasicBlock* bb = gen_suspend_test_list_[idx];
- if (bb == source)
- return true; // The block has been inserted by a suspend check before.
- if (source->dominators->IsBitSet(bb->id) && bb->dominators->IsBitSet(target_id))
- return true;
- }
-
- return false;
-}
-
ChildBlockIterator::ChildBlockIterator(BasicBlock* bb, MIRGraph* mir_graph)
: basic_block_(bb), mir_graph_(mir_graph), visited_fallthrough_(false),
visited_taken_(false), have_successors_(false) {
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index db1cf4b..9890690 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -34,6 +34,7 @@
namespace art {
+class DexFileMethodInliner;
class GlobalValueNumbering;
enum DataFlowAttributePos {
@@ -131,11 +132,9 @@ enum DataFlowAttributePos {
enum OatMethodAttributes {
kIsLeaf, // Method is leaf.
- kHasLoop, // Method contains simple loop.
};
#define METHOD_IS_LEAF (1 << kIsLeaf)
-#define METHOD_HAS_LOOP (1 << kHasLoop)
// Minimum field size to contain Dalvik v_reg number.
#define VREG_NUM_WIDTH 16
@@ -731,6 +730,10 @@ class MIRGraph {
return max_nested_loops_;
}
+ bool IsLoopHead(BasicBlockId bb_id) {
+ return topological_order_loop_ends_[topological_order_indexes_[bb_id]] != 0u;
+ }
+
bool IsConst(int32_t s_reg) const {
return is_constant_v_->IsBitSet(s_reg);
}
@@ -969,13 +972,23 @@ class MIRGraph {
return reg_location_[method_sreg_];
}
- bool IsBackedge(BasicBlock* branch_bb, BasicBlockId target_bb_id) {
- return ((target_bb_id != NullBasicBlockId) &&
- (GetBasicBlock(target_bb_id)->start_offset <= branch_bb->start_offset));
+ bool IsBackEdge(BasicBlock* branch_bb, BasicBlockId target_bb_id) {
+ DCHECK_NE(target_bb_id, NullBasicBlockId);
+ DCHECK_LT(target_bb_id, topological_order_indexes_.size());
+ DCHECK_LT(branch_bb->id, topological_order_indexes_.size());
+ return topological_order_indexes_[target_bb_id] <= topological_order_indexes_[branch_bb->id];
}
- bool IsBackwardsBranch(BasicBlock* branch_bb) {
- return IsBackedge(branch_bb, branch_bb->taken) || IsBackedge(branch_bb, branch_bb->fall_through);
+ bool IsSuspendCheckEdge(BasicBlock* branch_bb, BasicBlockId target_bb_id) {
+ if (!IsBackEdge(branch_bb, target_bb_id)) {
+ return false;
+ }
+ if (suspend_checks_in_loops_ == nullptr) {
+ // We didn't run suspend check elimination.
+ return true;
+ }
+ uint16_t target_depth = GetBasicBlock(target_bb_id)->nesting_depth;
+ return (suspend_checks_in_loops_[branch_bb->id] & (1u << (target_depth - 1u))) == 0;
}
void CountBranch(DexOffset target_offset) {
@@ -1055,6 +1068,9 @@ class MIRGraph {
bool ApplyGlobalValueNumberingGate();
bool ApplyGlobalValueNumbering(BasicBlock* bb);
void ApplyGlobalValueNumberingEnd();
+ bool EliminateSuspendChecksGate();
+ bool EliminateSuspendChecks(BasicBlock* bb);
+ void EliminateSuspendChecksEnd();
uint16_t GetGvnIFieldId(MIR* mir) const {
DCHECK(IsInstructionIGetOrIPut(mir->dalvikInsn.opcode));
@@ -1166,7 +1182,7 @@ class MIRGraph {
* @brief Count the uses in the BasicBlock
* @param bb the BasicBlock
*/
- void CountUses(class BasicBlock* bb);
+ void CountUses(BasicBlock* bb);
static uint64_t GetDataFlowAttributes(Instruction::Code opcode);
static uint64_t GetDataFlowAttributes(MIR* mir);
@@ -1210,20 +1226,6 @@ class MIRGraph {
void HandleSSADef(int* defs, int dalvik_reg, int reg_index);
bool InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed);
- // Used for removing redudant suspend tests
- void AppendGenSuspendTestList(BasicBlock* bb) {
- if (gen_suspend_test_list_.size() == 0 ||
- gen_suspend_test_list_.back() != bb) {
- gen_suspend_test_list_.push_back(bb);
- }
- }
-
- /* This is used to check if there is already a method call dominating the
- * source basic block of a backedge and being dominated by the target basic
- * block of the backedge.
- */
- bool HasSuspendTestBetween(BasicBlock* source, BasicBlockId target_id);
-
protected:
int FindCommonParent(int block1, int block2);
void ComputeSuccLineIn(ArenaBitVector* dest, const ArenaBitVector* src1,
@@ -1339,6 +1341,10 @@ class MIRGraph {
uint16_t* ifield_ids_; // Part of GVN/LVN but cached here for LVN to avoid recalculation.
uint16_t* sfield_ids_; // Ditto.
} gvn;
+ // Suspend check elimination.
+ struct {
+ DexFileMethodInliner* inliner;
+ } sce;
} temp_;
static const int kInvalidEntry = -1;
ArenaVector<BasicBlock*> block_list_;
@@ -1374,11 +1380,19 @@ class MIRGraph {
ArenaVector<MirIFieldLoweringInfo> ifield_lowering_infos_;
ArenaVector<MirSFieldLoweringInfo> sfield_lowering_infos_;
ArenaVector<MirMethodLoweringInfo> method_lowering_infos_;
+
+ // In the suspend check elimination pass we determine for each basic block and enclosing
+ // loop whether there's guaranteed to be a suspend check on the path from the loop head
+ // to this block. If so, we can eliminate the back-edge suspend check.
+ // The bb->id is index into suspend_checks_in_loops_ and the loop head's depth is bit index
+ // in a suspend_checks_in_loops_[bb->id].
+ uint32_t* suspend_checks_in_loops_;
+
static const uint64_t oat_data_flow_attributes_[kMirOpLast];
- ArenaVector<BasicBlock*> gen_suspend_test_list_; // List of blocks containing suspend tests
friend class MirOptimizationTest;
friend class ClassInitCheckEliminationTest;
+ friend class SuspendCheckEliminationTest;
friend class NullCheckEliminationTest;
friend class GlobalValueNumberingTest;
friend class LocalValueNumberingTest;
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index fd4c3d7..fc96075 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -542,28 +542,6 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
}
}
break;
- case Instruction::RETURN_VOID:
- case Instruction::RETURN:
- case Instruction::RETURN_WIDE:
- case Instruction::RETURN_OBJECT:
- if (bb->GetFirstNonPhiInsn() == mir) {
- // This is a simple return BB. Eliminate suspend checks on predecessor back-edges.
- for (BasicBlockId pred_id : bb->predecessors) {
- BasicBlock* pred_bb = GetBasicBlock(pred_id);
- DCHECK(pred_bb != nullptr);
- if (IsBackedge(pred_bb, bb->id) && pred_bb->last_mir_insn != nullptr &&
- (IsInstructionIfCc(pred_bb->last_mir_insn->dalvikInsn.opcode) ||
- IsInstructionIfCcZ(pred_bb->last_mir_insn->dalvikInsn.opcode) ||
- IsInstructionGoto(pred_bb->last_mir_insn->dalvikInsn.opcode))) {
- pred_bb->last_mir_insn->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK;
- if (cu_->verbose) {
- LOG(INFO) << "Suppressed suspend check on branch to return at 0x" << std::hex
- << pred_bb->last_mir_insn->offset;
- }
- }
- }
- }
- break;
default:
break;
}
@@ -592,12 +570,8 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
if ((tk_ft == NULL) && (ft_tk == NULL) && (tk_tk == ft_ft) &&
(Predecessors(tk) == 1) && (Predecessors(ft) == 1)) {
/*
- * Okay - we have the basic diamond shape. At the very least, we can eliminate the
- * suspend check on the taken-taken branch back to the join point.
+ * Okay - we have the basic diamond shape.
*/
- if (SelectKind(tk->last_mir_insn) == kSelectGoto) {
- tk->last_mir_insn->optimization_flags |= (MIR_IGNORE_SUSPEND_CHECK);
- }
// TODO: Add logic for LONG.
// Are the block bodies something we can handle?
@@ -1636,4 +1610,103 @@ void MIRGraph::BasicBlockOptimization() {
temp_scoped_alloc_.reset();
}
+bool MIRGraph::EliminateSuspendChecksGate() {
+ if ((cu_->disable_opt & (1 << kSuspendCheckElimination)) != 0 || // Disabled.
+ GetMaxNestedLoops() == 0u || // Nothing to do.
+ GetMaxNestedLoops() >= 32u || // Only 32 bits in suspend_checks_in_loops_[.].
+ // Exclude 32 as well to keep bit shifts well-defined.
+ !HasInvokes()) { // No invokes to actually eliminate any suspend checks.
+ return false;
+ }
+ if (cu_->compiler_driver != nullptr && cu_->compiler_driver->GetMethodInlinerMap() != nullptr) {
+ temp_.sce.inliner =
+ cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file);
+ }
+ suspend_checks_in_loops_ = static_cast<uint32_t*>(
+ arena_->Alloc(GetNumBlocks() * sizeof(*suspend_checks_in_loops_), kArenaAllocMisc));
+ return true;
+}
+
+bool MIRGraph::EliminateSuspendChecks(BasicBlock* bb) {
+ if (bb->block_type != kDalvikByteCode) {
+ return false;
+ }
+ DCHECK_EQ(GetTopologicalSortOrderLoopHeadStack()->size(), bb->nesting_depth);
+ if (bb->nesting_depth == 0u) {
+ // Out of loops.
+ DCHECK_EQ(suspend_checks_in_loops_[bb->id], 0u); // The array was zero-initialized.
+ return false;
+ }
+ uint32_t suspend_checks_in_loops = (1u << bb->nesting_depth) - 1u; // Start with all loop heads.
+ bool found_invoke = false;
+ for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+ if (IsInstructionInvoke(mir->dalvikInsn.opcode) &&
+ (temp_.sce.inliner == nullptr ||
+ !temp_.sce.inliner->IsIntrinsic(mir->dalvikInsn.vB, nullptr))) {
+ // Non-intrinsic invoke, rely on a suspend point in the invoked method.
+ found_invoke = true;
+ break;
+ }
+ }
+ if (!found_invoke) {
+ // Intersect suspend checks from predecessors.
+ uint16_t bb_topo_idx = topological_order_indexes_[bb->id];
+ uint32_t pred_mask_union = 0u;
+ for (BasicBlockId pred_id : bb->predecessors) {
+ uint16_t pred_topo_idx = topological_order_indexes_[pred_id];
+ if (pred_topo_idx < bb_topo_idx) {
+ // Determine the loop depth of the predecessors relative to this block.
+ size_t pred_loop_depth = topological_order_loop_head_stack_.size();
+ while (pred_loop_depth != 0u &&
+ pred_topo_idx < topological_order_loop_head_stack_[pred_loop_depth - 1].first) {
+ --pred_loop_depth;
+ }
+ DCHECK_LE(pred_loop_depth, GetBasicBlock(pred_id)->nesting_depth);
+ uint32_t pred_mask = (1u << pred_loop_depth) - 1u;
+ // Intersect pred_mask bits in suspend_checks_in_loops with
+ // suspend_checks_in_loops_[pred_id].
+ uint32_t pred_loops_without_checks = pred_mask & ~suspend_checks_in_loops_[pred_id];
+ suspend_checks_in_loops = suspend_checks_in_loops & ~pred_loops_without_checks;
+ pred_mask_union |= pred_mask;
+ }
+ }
+ DCHECK_EQ(((1u << (IsLoopHead(bb->id) ? bb->nesting_depth - 1u: bb->nesting_depth)) - 1u),
+ pred_mask_union);
+ suspend_checks_in_loops &= pred_mask_union;
+ }
+ suspend_checks_in_loops_[bb->id] = suspend_checks_in_loops;
+ if (suspend_checks_in_loops == 0u) {
+ return false;
+ }
+ // Apply MIR_IGNORE_SUSPEND_CHECK if appropriate.
+ if (bb->taken != NullBasicBlockId) {
+ DCHECK(bb->last_mir_insn != nullptr);
+ DCHECK(IsInstructionIfCc(bb->last_mir_insn->dalvikInsn.opcode) ||
+ IsInstructionIfCcZ(bb->last_mir_insn->dalvikInsn.opcode) ||
+ IsInstructionGoto(bb->last_mir_insn->dalvikInsn.opcode) ||
+ (static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) >= kMirOpFusedCmplFloat &&
+ static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) <= kMirOpFusedCmpLong));
+ if (!IsSuspendCheckEdge(bb, bb->taken) &&
+ (bb->fall_through == NullBasicBlockId || !IsSuspendCheckEdge(bb, bb->fall_through))) {
+ bb->last_mir_insn->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK;
+ }
+ } else if (bb->fall_through != NullBasicBlockId && IsSuspendCheckEdge(bb, bb->fall_through)) {
+ // We've got a fall-through suspend edge. Add an artificial GOTO to force suspend check.
+ MIR* mir = NewMIR();
+ mir->dalvikInsn.opcode = Instruction::GOTO;
+ mir->dalvikInsn.vA = 0; // Branch offset.
+ mir->offset = GetBasicBlock(bb->fall_through)->start_offset;
+ mir->m_unit_index = current_method_;
+ mir->ssa_rep = reinterpret_cast<SSARepresentation*>(
+ arena_->Alloc(sizeof(SSARepresentation), kArenaAllocDFInfo)); // Zero-initialized.
+ bb->AppendMIR(mir);
+ std::swap(bb->fall_through, bb->taken); // The fall-through has become taken.
+ }
+ return true;
+}
+
+void MIRGraph::EliminateSuspendChecksEnd() {
+ temp_.sce.inliner = nullptr;
+}
+
} // namespace art
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index c794cc6..6c2e9c0 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -88,6 +88,8 @@ class MirOptimizationTest : public testing::Test {
{ bb, opcode, 0u, vA, vB, vC }
#define DEF_INVOKE(bb, opcode, vC, method_info) \
{ bb, opcode, method_info, 0u, 0u, vC }
+#define DEF_OTHER0(bb, opcode) \
+ { bb, opcode, 0u, 0u, 0u, 0u }
#define DEF_OTHER1(bb, opcode, vA) \
{ bb, opcode, 0u, vA, 0u, 0u }
#define DEF_OTHER2(bb, opcode, vA, vB) \
@@ -175,6 +177,56 @@ class MirOptimizationTest : public testing::Test {
PrepareBasicBlocks(bbs);
}
+ void PrepareNestedLoopsWhile_While() {
+ static const BBDef bbs[] = {
+ DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+ DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+ DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(8)),
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 8), DEF_PRED2(3, 7)), // Outer while loop head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)), // Inner while loop head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)), // "taken" loops to inner head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(5)), // "taken" loops to outer head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+ };
+ PrepareBasicBlocks(bbs);
+ }
+
+ void PrepareNestedLoopsWhile_WhileWhile() {
+ static const BBDef bbs[] = {
+ DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+ DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+ DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(10)),
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 10), DEF_PRED2(3, 9)), // Outer while loop head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)), // Inner while loop head 1.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)), // Loops to inner head 1.
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 9), DEF_PRED2(5, 8)), // Inner while loop head 2.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED1(7)), // loops to inner head 2.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(7)), // loops to outer head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+ };
+ PrepareBasicBlocks(bbs);
+ }
+
+ void PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge() {
+ // Extra edge from the first inner loop body to second inner loop body (6u->8u).
+ static const BBDef bbs[] = {
+ DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+ DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+ DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(10)),
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 10), DEF_PRED2(3, 9)), // Outer while loop head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)), // Inner while loop head 1.
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 8), DEF_PRED1(5)), // Loops to inner head 1.
+ DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 9), DEF_PRED2(5, 8)), // Inner while loop head 2.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED2(7, 6)), // loops to inner head 2.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(7)), // loops to outer head.
+ DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+ };
+ PrepareBasicBlocks(bbs);
+ }
+
void PrepareCatch() {
static const BBDef bbs[] = {
DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
@@ -397,6 +449,43 @@ class NullCheckEliminationTest : public MirOptimizationTest {
}
};
+class SuspendCheckEliminationTest : public MirOptimizationTest {
+ protected:
+ bool IsBackEdge(BasicBlockId branch_bb, BasicBlockId target_bb) {
+ BasicBlock* branch = cu_.mir_graph->GetBasicBlock(branch_bb);
+ return target_bb != NullBasicBlockId && cu_.mir_graph->IsBackEdge(branch, target_bb);
+ }
+
+ bool IsSuspendCheckEdge(BasicBlockId branch_bb, BasicBlockId target_bb) {
+ BasicBlock* branch = cu_.mir_graph->GetBasicBlock(branch_bb);
+ return cu_.mir_graph->IsSuspendCheckEdge(branch, target_bb);
+ }
+
+ void PerformSuspendCheckElimination() {
+ cu_.mir_graph->SSATransformationStart();
+ cu_.mir_graph->ComputeDFSOrders();
+ cu_.mir_graph->ComputeDominators();
+ cu_.mir_graph->ComputeTopologicalSortOrder();
+ cu_.mir_graph->SSATransformationEnd();
+ bool gate_result = cu_.mir_graph->EliminateSuspendChecksGate();
+ ASSERT_TRUE(gate_result);
+ TopologicalSortIterator iterator(cu_.mir_graph.get());
+ bool change = false;
+ for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
+ change = cu_.mir_graph->EliminateSuspendChecks(bb);
+ }
+ cu_.mir_graph->EliminateSuspendChecksEnd();
+ }
+
+ SuspendCheckEliminationTest()
+ : MirOptimizationTest() {
+ static const MethodDef methods[] = {
+ { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false }, // Dummy.
+ };
+ PrepareMethods(methods);
+ }
+};
+
TEST_F(ClassInitCheckEliminationTest, SingleBlock) {
static const SFieldDef sfields[] = {
{ 0u, 1u, 0u, 0u, kDexMemAccessWord },
@@ -882,7 +971,208 @@ TEST_F(NullCheckEliminationTest, Catch) {
}
}
-// Undefine MIR_DEF for null check elimination.
-#undef MIR_DEF
+TEST_F(SuspendCheckEliminationTest, LoopNoElimination) {
+ static const MIRDef mirs[] = {
+ DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u, 0u), // Force the pass to run.
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge back.
+ };
+
+ PrepareLoop();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(4u, 4u));
+ EXPECT_TRUE(IsSuspendCheckEdge(4u, 4u)); // Suspend point on loop to self.
+}
+
+TEST_F(SuspendCheckEliminationTest, LoopElimination) {
+ static const MIRDef mirs[] = {
+ DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in the loop.
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge back.
+ };
+
+ PrepareLoop();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(4u, 4u));
+ EXPECT_FALSE(IsSuspendCheckEdge(4u, 4u)); // No suspend point on loop to self.
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_NoElimination) {
+ static const MIRDef mirs[] = {
+ DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u, 0u), // Force the pass to run.
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_While();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(7u, 4u));
+ EXPECT_TRUE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInOuterLoopHead) {
+ static const MIRDef mirs[] = {
+ DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in outer loop head.
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_While();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(7u, 4u));
+ EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInOuterLoopBody) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_INVOKE(7u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in outer loop body.
+ DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_While();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(7u, 4u));
+ EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInInnerLoopHead) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in inner loop head.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_While();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(7u, 4u));
+ EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInInnerLoopBody) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop.
+ DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in inner loop body.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER0(7u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_While();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(7u, 4u));
+ EXPECT_TRUE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_InvokeInFirstInnerLoopHead) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in first inner loop head.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
+ DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
+ DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_WhileWhile();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(8u, 7u));
+ EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));
+ ASSERT_TRUE(IsBackEdge(9u, 4u));
+ EXPECT_FALSE(IsSuspendCheckEdge(9u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_InvokeInFirstInnerLoopBody) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
+ DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in first inner loop body.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
+ DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
+ DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_WhileWhile();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(8u, 7u));
+ EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));
+ ASSERT_TRUE(IsBackEdge(9u, 4u));
+ EXPECT_TRUE(IsSuspendCheckEdge(9u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_WithExtraEdge_InvokeInFirstInnerLoopBody) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
+ DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in first inner loop body.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
+ DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
+ DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(8u, 7u));
+ EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u)); // Unaffected by the extra edge.
+ ASSERT_TRUE(IsBackEdge(9u, 4u));
+ EXPECT_TRUE(IsSuspendCheckEdge(9u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_WithExtraEdge_InvokeInSecondInnerLoopHead) {
+ static const MIRDef mirs[] = {
+ DEF_OTHER1(4u, Instruction::IF_NEZ, 1u), // Edge out of outer loop.
+ DEF_OTHER1(5u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 1.
+ DEF_OTHER0(6u, Instruction::GOTO), // Edge back to inner loop head.
+ DEF_INVOKE(7u, Instruction::INVOKE_STATIC, 0u, 0u), // Invoke in second inner loop head.
+ DEF_OTHER1(7u, Instruction::IF_NEZ, 2u), // Edge out of inner loop 2.
+ DEF_OTHER0(8u, Instruction::GOTO), // Edge back to inner loop 2 head.
+ DEF_OTHER0(9u, Instruction::GOTO), // Edge back to outer loop head.
+ };
+
+ PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge();
+ PrepareMIRs(mirs);
+ PerformSuspendCheckElimination();
+ ASSERT_TRUE(IsBackEdge(6u, 5u));
+ EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+ ASSERT_TRUE(IsBackEdge(8u, 7u));
+ EXPECT_FALSE(IsSuspendCheckEdge(8u, 7u)); // Unaffected by the extra edge.
+ ASSERT_TRUE(IsBackEdge(9u, 4u));
+ EXPECT_FALSE(IsSuspendCheckEdge(9u, 4u));
+}
} // namespace art
diff --git a/compiler/dex/pass_driver_me_opts.cc b/compiler/dex/pass_driver_me_opts.cc
index a2bf8b4..c476b2a 100644
--- a/compiler/dex/pass_driver_me_opts.cc
+++ b/compiler/dex/pass_driver_me_opts.cc
@@ -46,6 +46,7 @@ const Pass* const PassDriver<PassDriverMEOpts>::g_passes[] = {
GetPassInstance<TypeInference>(),
GetPassInstance<GlobalValueNumberingPass>(),
GetPassInstance<BBOptimizations>(),
+ GetPassInstance<SuspendCheckElimination>(),
};
// The number of the passes in the initial list of Passes (g_passes).
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 774176e..50014b0 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -2163,18 +2163,15 @@ class SuspendCheckSlowPath : public Mir2Lir::LIRSlowPath {
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTest(int opt_flags) {
+ if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK) != 0) {
+ return;
+ }
if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) {
- if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
- return;
- }
FlushAllRegs();
LIR* branch = OpTestSuspend(NULL);
LIR* cont = NewLIR0(kPseudoTargetLabel);
AddSlowPath(new (arena_) SuspendCheckSlowPath(this, branch, cont));
} else {
- if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
- return;
- }
FlushAllRegs(); // TODO: needed?
LIR* inst = CheckSuspendUsingLoad();
MarkSafepointPC(inst);
@@ -2183,11 +2180,11 @@ void Mir2Lir::GenSuspendTest(int opt_flags) {
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
+ if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK) != 0) {
+ OpUnconditionalBranch(target);
+ return;
+ }
if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) {
- if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
- OpUnconditionalBranch(target);
- return;
- }
OpTestSuspend(target);
FlushAllRegs();
LIR* branch = OpUnconditionalBranch(nullptr);
@@ -2195,10 +2192,6 @@ void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
} else {
// For the implicit suspend check, just perform the trigger
// load and branch to the target.
- if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
- OpUnconditionalBranch(target);
- return;
- }
FlushAllRegs();
LIR* inst = CheckSuspendUsingLoad();
MarkSafepointPC(inst);
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index bd88091..524ee21 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -549,8 +549,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
case Instruction::GOTO:
case Instruction::GOTO_16:
case Instruction::GOTO_32:
- if (mir_graph_->IsBackedge(bb, bb->taken) &&
- (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken))) {
+ if (mir_graph_->IsBackEdge(bb, bb->taken)) {
GenSuspendTestAndBranch(opt_flags, &label_list[bb->taken]);
} else {
OpUnconditionalBranch(&label_list[bb->taken]);
@@ -582,12 +581,10 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
case Instruction::IF_GE:
case Instruction::IF_GT:
case Instruction::IF_LE: {
- LIR* taken = &label_list[bb->taken];
- if (mir_graph_->IsBackwardsBranch(bb) &&
- (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
- !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
GenSuspendTest(opt_flags);
}
+ LIR* taken = &label_list[bb->taken];
GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken);
break;
}
@@ -597,12 +594,10 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
case Instruction::IF_GEZ:
case Instruction::IF_GTZ:
case Instruction::IF_LEZ: {
- LIR* taken = &label_list[bb->taken];
- if (mir_graph_->IsBackwardsBranch(bb) &&
- (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
- !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
GenSuspendTest(opt_flags);
}
+ LIR* taken = &label_list[bb->taken];
GenCompareZeroAndBranch(opcode, rl_src[0], taken);
break;
}
@@ -771,69 +766,37 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
case Instruction::INVOKE_STATIC_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, true));
- if (!kLeafOptimization) {
- // If the invocation is not inlined, we can assume there is already a
- // suspend check at the return site
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_STATIC:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, false));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_DIRECT:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, false));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_DIRECT_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, true));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_VIRTUAL:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, false));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, true));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_SUPER:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, false));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_SUPER_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, true));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_INTERFACE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, false));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::INVOKE_INTERFACE_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, true));
- if (!kLeafOptimization) {
- mir_graph_->AppendGenSuspendTestList(bb);
- }
break;
case Instruction::NEG_INT:
@@ -1034,18 +997,33 @@ void Mir2Lir::HandleExtendedMethodMIR(BasicBlock* bb, MIR* mir) {
break;
}
case kMirOpFusedCmplFloat:
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+ GenSuspendTest(mir->optimization_flags);
+ }
GenFusedFPCmpBranch(bb, mir, false /*gt bias*/, false /*double*/);
break;
case kMirOpFusedCmpgFloat:
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+ GenSuspendTest(mir->optimization_flags);
+ }
GenFusedFPCmpBranch(bb, mir, true /*gt bias*/, false /*double*/);
break;
case kMirOpFusedCmplDouble:
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+ GenSuspendTest(mir->optimization_flags);
+ }
GenFusedFPCmpBranch(bb, mir, false /*gt bias*/, true /*double*/);
break;
case kMirOpFusedCmpgDouble:
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+ GenSuspendTest(mir->optimization_flags);
+ }
GenFusedFPCmpBranch(bb, mir, true /*gt bias*/, true /*double*/);
break;
case kMirOpFusedCmpLong:
+ if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+ GenSuspendTest(mir->optimization_flags);
+ }
GenFusedLongCmpBranch(bb, mir);
break;
case kMirOpSelect:
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index dd09330..a2b85ff 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -843,8 +843,8 @@ class Mir2Lir : public Backend {
virtual void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2, int flags);
void GenConversionCall(QuickEntrypointEnum trampoline, RegLocation rl_dest, RegLocation rl_src);
- virtual void GenSuspendTest(int opt_flags);
- virtual void GenSuspendTestAndBranch(int opt_flags, LIR* target);
+ void GenSuspendTest(int opt_flags);
+ void GenSuspendTestAndBranch(int opt_flags, LIR* target);
// This will be overridden by x86 implementation.
virtual void GenConstWide(RegLocation rl_dest, int64_t value);
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index b803462..7cd431e 100644
--- a/compiler/dex/ssa_transformation.cc
+++ b/compiler/dex/ssa_transformation.cc
@@ -197,12 +197,6 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) {
dom_post_order_traversal_.push_back(curr_bb->id);
}
work_stack.pop_back();
-
- /* hacky loop detection */
- if ((curr_bb->taken != NullBasicBlockId) && curr_bb->dominators->IsBitSet(curr_bb->taken)) {
- curr_bb->nesting_depth++;
- attributes_ |= METHOD_HAS_LOOP;
- }
}
}
}