Promote pointer to dex cache arrays on arm.
Do the use-count analysis on temps (ArtMethod* and the new
PC-relative temp) in Mir2Lir, rather than MIRGraph. MIRGraph
isn't really supposed to know how the ArtMethod* is used by
the backend.
Change-Id: Iaf56a46ae203eca86281b02b54f39a80fe5cc2dd
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 3f4f1fe..518e3ea 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -491,6 +491,14 @@
FlushIns(ArgLocs, rl_method);
+ // We can promote a PC-relative reference to dex cache arrays to a register
+ // if it's used at least twice. Without investigating where we should lazily
+ // load the reference, we conveniently load it after flushing inputs.
+ if (dex_cache_arrays_base_reg_.Valid()) {
+ OpPcRelDexCacheArrayAddr(cu_->dex_file, dex_cache_arrays_min_offset_,
+ dex_cache_arrays_base_reg_);
+ }
+
FreeTemp(rs_r0);
FreeTemp(rs_r1);
FreeTemp(rs_r2);
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 619c11f..83b27df 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -260,6 +260,9 @@
*/
LIR* GenCallInsn(const MirMethodLoweringInfo& method_info) OVERRIDE;
+ void CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) OVERRIDE;
+ void DoPromotion() OVERRIDE;
+
/*
* @brief Handle ARM specific literals.
*/
@@ -306,6 +309,10 @@
// Instructions needing patching with PC relative code addresses.
ArenaVector<LIR*> dex_cache_access_insns_;
+ // Register with a reference to the dex cache arrays at dex_cache_arrays_min_offset_,
+ // if promoted.
+ RegStorage dex_cache_arrays_base_reg_;
+
/**
* @brief Given float register pair, returns Solo64 float register.
* @param reg #RegStorage containing a float register pair (e.g. @c s2 and @c s3).
@@ -341,6 +348,8 @@
uint32_t unused_idx ATTRIBUTE_UNUSED,
uintptr_t direct_code, uintptr_t direct_method,
InvokeType type);
+
+ void OpPcRelDexCacheArrayAddr(const DexFile* dex_file, int offset, RegStorage r_dest);
};
} // namespace art
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index c788401..47669db 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -1091,7 +1091,7 @@
return dex_cache_arrays_layout_.Valid();
}
-void ArmMir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) {
+void ArmMir2Lir::OpPcRelDexCacheArrayAddr(const DexFile* dex_file, int offset, RegStorage r_dest) {
LIR* movw = NewLIR2(kThumb2MovImm16, r_dest.GetReg(), 0);
LIR* movt = NewLIR2(kThumb2MovImm16H, r_dest.GetReg(), 0);
ArmOpcode add_pc_opcode = (r_dest.GetRegNum() < 8) ? kThumbAddRRLH : kThumbAddRRHH;
@@ -1105,7 +1105,16 @@
movt->operands[4] = movw->operands[4];
dex_cache_access_insns_.push_back(movw);
dex_cache_access_insns_.push_back(movt);
- LoadRefDisp(r_dest, 0, r_dest, kNotVolatile);
+}
+
+void ArmMir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) {
+ if (dex_cache_arrays_base_reg_.Valid()) {
+ LoadRefDisp(dex_cache_arrays_base_reg_, offset - dex_cache_arrays_min_offset_,
+ r_dest, kNotVolatile);
+ } else {
+ OpPcRelDexCacheArrayAddr(dex_file, offset, r_dest);
+ LoadRefDisp(r_dest, 0, r_dest, kNotVolatile);
+ }
}
LIR* ArmMir2Lir::OpVldm(RegStorage r_base, int count) {
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 580dcb7..5f27338 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -576,7 +576,8 @@
ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
: Mir2Lir(cu, mir_graph, arena),
call_method_insns_(arena->Adapter()),
- dex_cache_access_insns_(arena->Adapter()) {
+ dex_cache_access_insns_(arena->Adapter()),
+ dex_cache_arrays_base_reg_(RegStorage::InvalidReg()) {
call_method_insns_.reserve(100);
// Sanity check - make sure encoding map lines up.
for (int i = 0; i < kArmLast; i++) {
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index e4bd2a3..c3371cf 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -19,6 +19,7 @@
#include "arch/arm/instruction_set_features_arm.h"
#include "arm_lir.h"
#include "base/logging.h"
+#include "dex/mir_graph.h"
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/reg_storage_eq.h"
#include "driver/compiler_driver.h"
@@ -1266,4 +1267,38 @@
return offset;
}
+void ArmMir2Lir::CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) {
+ // Start with the default counts.
+ Mir2Lir::CountRefs(core_counts, fp_counts, num_regs);
+
+ if (pc_rel_temp_ != nullptr) {
+ // Now, if the dex cache array base temp is used only once outside any loops (weight = 1),
+ // avoid the promotion, otherwise boost the weight by factor 4 because the full PC-relative
+ // load sequence is 4 instructions long.
+ int p_map_idx = SRegToPMap(pc_rel_temp_->s_reg_low);
+ if (core_counts[p_map_idx].count == 1) {
+ core_counts[p_map_idx].count = 0;
+ } else {
+ core_counts[p_map_idx].count *= 4;
+ }
+ }
+}
+
+void ArmMir2Lir::DoPromotion() {
+ if (CanUseOpPcRelDexCacheArrayLoad()) {
+ pc_rel_temp_ = mir_graph_->GetNewCompilerTemp(kCompilerTempBackend, false);
+ }
+
+ Mir2Lir::DoPromotion();
+
+ if (pc_rel_temp_ != nullptr) {
+ // Now, if the dex cache array base temp is promoted, remember the register but
+ // always remove the temp's stack location to avoid unnecessarily bloating the stack.
+ dex_cache_arrays_base_reg_ = mir_graph_->reg_location_[pc_rel_temp_->s_reg_low].reg;
+ DCHECK(!dex_cache_arrays_base_reg_.Valid() || !dex_cache_arrays_base_reg_.IsFloat());
+ mir_graph_->RemoveLastCompilerTemp(kCompilerTempBackend, false, pc_rel_temp_);
+ pc_rel_temp_ = nullptr;
+ }
+}
+
} // namespace art