Quick: Eliminate check-cast guaranteed by instance-of.
Eliminate check-cast if the result of an instance-of with
the very same type on the same value is used to branch to
the check-cast's block or a dominator of it.
Note that there already exists a verifier-based elimination
of check-cast but it excludes check-cast on interfaces. This
new optimization works for interface types and, since it's
GVN-based, it can better recognize when the same reference
is used for instance-of and check-cast.
Change-Id: Ib315199805099d1cb0534bb4a90dc51baa409685
diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc
index ab3c946..30e3ce0 100644
--- a/compiler/dex/global_value_numbering.cc
+++ b/compiler/dex/global_value_numbering.cc
@@ -16,6 +16,7 @@
#include "global_value_numbering.h"
+#include "base/bit_vector-inl.h"
#include "base/stl_util.h"
#include "local_value_numbering.h"
@@ -206,4 +207,41 @@
return true;
}
+bool GlobalValueNumbering::IsBlockEnteredOnTrue(uint16_t cond, BasicBlockId bb_id) {
+ DCHECK_NE(cond, kNoValue);
+ BasicBlock* bb = mir_graph_->GetBasicBlock(bb_id);
+ if (bb->predecessors.size() == 1u) {
+ BasicBlockId pred_id = bb->predecessors[0];
+ BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_id);
+ if (pred_bb->last_mir_insn != nullptr) {
+ Instruction::Code opcode = pred_bb->last_mir_insn->dalvikInsn.opcode;
+ if ((opcode == Instruction::IF_NEZ && pred_bb->taken == bb_id) ||
+ (opcode == Instruction::IF_EQZ && pred_bb->fall_through == bb_id)) {
+ DCHECK(lvns_[pred_id] != nullptr);
+ uint16_t operand = lvns_[pred_id]->GetSregValue(pred_bb->last_mir_insn->ssa_rep->uses[0]);
+ if (operand == cond) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool GlobalValueNumbering::IsTrueInBlock(uint16_t cond, BasicBlockId bb_id) {
+ // We're not doing proper value propagation, so just see if the condition is used
+ // with if-nez/if-eqz to branch/fall-through to this bb or one of its dominators.
+ DCHECK_NE(cond, kNoValue);
+ if (IsBlockEnteredOnTrue(cond, bb_id)) {
+ return true;
+ }
+ BasicBlock* bb = mir_graph_->GetBasicBlock(bb_id);
+ for (uint32_t dom_id : bb->dominators->Indexes()) {
+ if (IsBlockEnteredOnTrue(cond, dom_id)) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace art