Skip null check in MarkGCCard() for known non-null values.
Use GVN's knowledge of non-null values to set a new MIR flag
for IPUT/SPUT/APUT to skip the value null check.
Change-Id: I97a8d1447acb530c9bbbf7b362add366d1486ee1
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index b56fd6f..4d377df 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -316,9 +316,8 @@
enum MIROptimizationFlagPositions {
kMIRIgnoreNullCheck = 0,
- kMIRNullCheckOnly,
kMIRIgnoreRangeCheck,
- kMIRRangeCheckOnly,
+ kMIRStoreNonNullValue, // Storing non-null value, always mark GC card.
kMIRClassIsInitialized,
kMIRClassIsInDexCache,
kMirIgnoreDivZeroCheck,
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index e0c4e27..114346d 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -1110,6 +1110,12 @@
// If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
HandleEscapingRef(base);
+ if (gvn_->CanModify() && null_checked_.count(base) != 0u) {
+ if (gvn_->GetCompilationUnit()->verbose) {
+ LOG(INFO) << "Removing GC card mark value null check for 0x" << std::hex << mir->offset;
+ }
+ mir->optimization_flags |= MIR_STORE_NON_NULL_VALUE;
+ }
}
void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index f4f13f2..0fcb584 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -607,7 +607,9 @@
EXPECT_NE(value_names_[13], value_names_[16]); // New value.
EXPECT_NE(value_names_[14], value_names_[17]); // New value.
for (size_t i = 0u; i != mir_count_; ++i) {
- int expected = (i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0;
+ int expected =
+ ((i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0) |
+ ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
}
}
@@ -640,7 +642,8 @@
for (size_t i = 0u; i != mir_count_; ++i) {
int expected =
((i != 0u && i != 3u && i != 6u && i != 9u) ? MIR_IGNORE_NULL_CHECK : 0u) |
- ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u);
+ ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u) |
+ ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
}
}
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index c8ea972..1a18841 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -145,9 +145,8 @@
#define INVALID_OFFSET (0xDEADF00FU)
#define MIR_IGNORE_NULL_CHECK (1 << kMIRIgnoreNullCheck)
-#define MIR_NULL_CHECK_ONLY (1 << kMIRNullCheckOnly)
#define MIR_IGNORE_RANGE_CHECK (1 << kMIRIgnoreRangeCheck)
-#define MIR_RANGE_CHECK_ONLY (1 << kMIRRangeCheckOnly)
+#define MIR_STORE_NON_NULL_VALUE (1 << kMIRStoreNonNullValue)
#define MIR_CLASS_IS_INITIALIZED (1 << kMIRClassIsInitialized)
#define MIR_CLASS_IS_IN_DEX_CACHE (1 << kMIRClassIsInDexCache)
#define MIR_IGNORE_DIV_ZERO_CHECK (1 << kMirIgnoreDivZeroCheck)
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index cab039b..e38dbf5 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -872,7 +872,7 @@
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
- MarkGCCard(rl_new_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_new_value.reg, rl_object.reg);
}
RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
@@ -1471,7 +1471,7 @@
FreeTemp(reg_ptr);
}
if (card_mark) {
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 0e00698..b12fc0a 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -758,7 +758,7 @@
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
- MarkGCCard(rl_new_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_new_value.reg, rl_object.reg);
}
RegStorage r_ptr = AllocTempRef();
@@ -1281,7 +1281,7 @@
FreeTemp(reg_ptr);
}
if (card_mark) {
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 80cb535..1cde01e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -314,13 +314,17 @@
}
}
-void Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void Mir2Lir::MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg) {
DCHECK(val_reg.Valid());
DCHECK_EQ(val_reg.Is64Bit(), cu_->target64);
- LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
- UnconditionallyMarkGCCard(tgt_addr_reg);
- LIR* target = NewLIR0(kPseudoTargetLabel);
- branch_over->target = target;
+ if ((opt_flags & MIR_STORE_NON_NULL_VALUE) != 0) {
+ UnconditionallyMarkGCCard(tgt_addr_reg);
+ } else {
+ LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
+ UnconditionallyMarkGCCard(tgt_addr_reg);
+ LIR* target = NewLIR0(kPseudoTargetLabel);
+ branch_over->target = target;
+ }
}
/* Dump instructions and constant pool contents */
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 4dd24cb..d1b8b03 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -665,7 +665,7 @@
field_info.IsVolatile() ? kVolatile : kNotVolatile);
}
if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
- MarkGCCard(rl_src.reg, r_base);
+ MarkGCCard(mir->optimization_flags, rl_src.reg, r_base);
}
FreeTemp(r_base);
} else {
@@ -940,7 +940,7 @@
}
MarkPossibleNullPointerExceptionAfter(opt_flags, store);
if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
- MarkGCCard(rl_src.reg, rl_obj.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_obj.reg);
}
} else {
QuickEntrypointEnum target;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index a7900ae..31b81bf 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1668,7 +1668,7 @@
GenMemBarrier(kAnyAny);
}
if (is_object) {
- MarkGCCard(rl_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_value.reg, rl_object.reg);
}
return true;
}
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index fb47238..0778c3b 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -641,7 +641,7 @@
FreeTemp(reg_ptr);
}
if (card_mark) {
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 70ef991..0d30927 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -332,7 +332,7 @@
kNotVolatile);
}
if (IsRef(size)) {
- MarkGCCard(reg_src, reg_obj);
+ MarkGCCard(0, reg_src, reg_obj);
}
return true;
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 886b238..49b8452 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1075,8 +1075,9 @@
* @brief Mark a garbage collection card. Skip if the stored value is null.
* @param val_reg the register holding the stored value to check against null.
* @param tgt_addr_reg the address of the object or array where the value was stored.
+ * @param opt_flags the optimization flags which may indicate that the value is non-null.
*/
- void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+ void MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg);
/*
* @brief Load the address of the dex method into the register.
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 3f501b4..74ae8a6 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1170,7 +1170,7 @@
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
FreeTemp(rs_r0); // Temporarily release EAX for MarkGCCard().
- MarkGCCard(rl_new_value.reg, rl_object.reg);
+ MarkGCCard(0, rl_new_value.reg, rl_object.reg);
LockTemp(rs_r0);
}
@@ -2398,7 +2398,7 @@
if (!constant_index) {
FreeTemp(rl_index.reg);
}
- MarkGCCard(rl_src.reg, rl_array.reg);
+ MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
}
}