Merge "ART: Add a last item in the MIROptimizationFlagPositions enumeration"
diff --git a/Android.mk b/Android.mk
index 92339af..01819ee 100644
--- a/Android.mk
+++ b/Android.mk
@@ -63,7 +63,7 @@
rm -f $(2ND_TARGET_OUT_INTERMEDIATES)/JAVA_LIBRARIES/*_intermediates/javalib.odex
rm -f $(2ND_TARGET_OUT_INTERMEDIATES)/APPS/*_intermediates/*.odex
endif
- rm -rf /tmp/test-*/dalvik-cache/*
+ rm -rf /tmp/$(USER)/test-*/dalvik-cache/*
rm -rf /tmp/android-data/dalvik-cache/*
.PHONY: clean-oat-target
diff --git a/build/Android.common.mk b/build/Android.common.mk
index aaa1490..6135571 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -123,6 +123,11 @@
ART_HOST_CLANG := true
endif
+# enable ART_TARGET_CLANG for ARM64
+ifneq (,$(filter $(TARGET_ARCH),arm64))
+ART_TARGET_CLANG := true
+endif
+
# directory used for dalvik-cache on device
ART_DALVIK_CACHE_DIR := /data/dalvik-cache
@@ -195,6 +200,14 @@
-Wstrict-aliasing \
-fstrict-aliasing
+# these are necessary for Clang ARM64 ART builds
+ifeq ($(ART_TARGET_CLANG), true)
+art_cflags += \
+ -Wno-implicit-exception-spec-mismatch \
+ -DNVALGRIND \
+ -Wno-unused-value
+endif
+
ifeq ($(ART_SMALL_MODE),true)
art_cflags += -DART_SMALL_MODE=1
endif
@@ -209,7 +222,13 @@
endif
art_non_debug_cflags := \
- -O3
+ -O3
+
+# FIXME: upstream LLVM has a vectorizer bug that needs to be fixed
+ifeq ($(ART_TARGET_CLANG),true)
+art_non_debug_cflags += \
+ -fno-vectorize
+endif
art_debug_cflags := \
-O1 \
@@ -238,8 +257,9 @@
ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
ART_TARGET_CFLAGS += -Wthread-safety
else
+ # FIXME: add -Wthread-safety when the problem is fixed
ifeq ($(ART_TARGET_CLANG),true)
- ART_TARGET_CFLAGS += -Wthread-safety
+ ART_TARGET_CFLAGS +=
else
# Warn if -Wthread-safety is not suport and not doing a top-level or 'mma' build.
ifneq ($(ONE_SHOT_MAKEFILE),)
@@ -304,7 +324,7 @@
# Has one argument, the suffix
define call-art-multi-target
$(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-
+
ifdef TARGET_2ND_ARCH
$(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
endif
@@ -329,10 +349,10 @@
# Has one argument, the suffix
define call-art-multi-target-var
$(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-
+
ifdef TARGET_2ND_ARCH
$(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-
+
# Link both together, if it makes sense
ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
@@ -351,10 +371,10 @@
# We assume we can link the names together easily...
define call-art-multi-target-rule
$(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-
+
ifdef TARGET_2ND_ARCH
$(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-
+
# Link both together, if it makes sense
ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index ab0e3e5..05ab8ca 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -27,6 +27,15 @@
kAnyReg,
};
+enum BitsUsed {
+ kSize32Bits,
+ kSize64Bits,
+ kSize128Bits,
+ kSize256Bits,
+ kSize512Bits,
+ kSize1024Bits,
+};
+
enum SpecialTargetRegister {
kSelf, // Thread pointer.
kSuspend, // Used to reduce suspend checks for some targets.
@@ -56,17 +65,6 @@
kLocInvalid
};
-/**
- * Support for vector registers. Initially used for x86 floats. This will be used
- * to replace the assumption that a double takes up 2 single FP registers
- */
-enum VectorLengthType {
- kVectorNotUsed = 0, // This value is NOT in a vector register.
- kVectorLength4, // The value occupies 4 bytes in a vector register.
- kVectorLength8, // The value occupies 8 bytes in a vector register.
- kVectorLength16 // The value occupies 16 bytes in a vector register (unused now).
-};
-
enum BBType {
kNullBlock,
kEntryBlock,
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index ed2ecac..1a9379a 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -40,13 +40,13 @@
/* Default optimizer/debug setting for the compiler. */
static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations
- (1 << kLoadStoreElimination) |
+ (1 << kLoadStoreElimination) | // TODO: this pass has been broken for awhile - fix or delete.
// (1 << kLoadHoisting) |
// (1 << kSuppressLoads) |
// (1 << kNullCheckElimination) |
// (1 << kClassInitCheckElimination) |
// (1 << kPromoteRegs) |
- // (1 << kTrackLiveTemps) |
+ (1 << kTrackLiveTemps) | // FIXME: disable until liveness issue fixed.
// (1 << kSafeOptimizations) |
// (1 << kBBOpt) |
// (1 << kMatch) |
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 36f1be7..2f17e08 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -879,8 +879,8 @@
new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapLiveIn);
for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
- uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
- DecodedInstruction *d_insn = &mir->dalvikInsn;
+ uint64_t df_attributes = GetDataFlowAttributes(mir);
+ MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
if (df_attributes & DF_HAS_USES) {
if (df_attributes & DF_UA) {
@@ -949,7 +949,7 @@
/* Look up new SSA names for format_35c instructions */
void MIRGraph::DataFlowSSAFormat35C(MIR* mir) {
- DecodedInstruction *d_insn = &mir->dalvikInsn;
+ MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
int num_uses = d_insn->vA;
int i;
@@ -967,7 +967,7 @@
/* Look up new SSA names for format_3rc instructions */
void MIRGraph::DataFlowSSAFormat3RC(MIR* mir) {
- DecodedInstruction *d_insn = &mir->dalvikInsn;
+ MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
int num_uses = d_insn->vA;
int i;
@@ -994,7 +994,7 @@
static_cast<struct SSARepresentation *>(arena_->Alloc(sizeof(SSARepresentation),
kArenaAllocDFInfo));
- uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+ uint64_t df_attributes = GetDataFlowAttributes(mir);
// If not a pseudo-op, note non-leaf or can throw
if (static_cast<int>(mir->dalvikInsn.opcode) <
@@ -1064,7 +1064,7 @@
kArenaAllocDFInfo));
}
- DecodedInstruction *d_insn = &mir->dalvikInsn;
+ MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
if (df_attributes & DF_HAS_USES) {
num_uses = 0;
@@ -1252,7 +1252,7 @@
use_counts_.Put(s_reg, use_counts_.Get(s_reg) + weight);
}
if (!(cu_->disable_opt & (1 << kPromoteCompilerTemps))) {
- uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+ uint64_t df_attributes = GetDataFlowAttributes(mir);
// Implicit use of Method* ? */
if (df_attributes & DF_UMS) {
/*
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 8ce4f1f..30d0bc3 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -21,6 +21,7 @@
#include "base/stl_util.h"
#include "compiler_internals.h"
#include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "leb128.h"
@@ -106,11 +107,17 @@
/*
* Parse an instruction, return the length of the instruction
*/
-int MIRGraph::ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_instruction) {
- const Instruction* instruction = Instruction::At(code_ptr);
- *decoded_instruction = DecodedInstruction(instruction);
-
- return instruction->SizeInCodeUnits();
+int MIRGraph::ParseInsn(const uint16_t* code_ptr, MIR::DecodedInstruction* decoded_instruction) {
+ const Instruction* inst = Instruction::At(code_ptr);
+ decoded_instruction->opcode = inst->Opcode();
+ decoded_instruction->vA = inst->HasVRegA() ? inst->VRegA() : 0;
+ decoded_instruction->vB = inst->HasVRegB() ? inst->VRegB() : 0;
+ decoded_instruction->vB_wide = inst->HasWideVRegB() ? inst->WideVRegB() : 0;
+ decoded_instruction->vC = inst->HasVRegC() ? inst->VRegC() : 0;
+ if (inst->HasVarArgs()) {
+ inst->GetVarArgs(decoded_instruction->arg);
+ }
+ return inst->SizeInCodeUnits();
}
@@ -621,7 +628,7 @@
int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
int verify_flags = Instruction::VerifyFlagsOf(insn->dalvikInsn.opcode);
- uint64_t df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode];
+ uint64_t df_flags = GetDataFlowAttributes(insn);
merged_df_flags |= df_flags;
if (df_flags & DF_HAS_DEFS) {
@@ -743,6 +750,17 @@
}
}
+uint64_t MIRGraph::GetDataFlowAttributes(Instruction::Code opcode) {
+ DCHECK_LT((size_t) opcode, (sizeof(oat_data_flow_attributes_) / sizeof(oat_data_flow_attributes_[0])));
+ return oat_data_flow_attributes_[opcode];
+}
+
+uint64_t MIRGraph::GetDataFlowAttributes(MIR* mir) {
+ DCHECK(mir != nullptr);
+ Instruction::Code opcode = mir->dalvikInsn.opcode;
+ return GetDataFlowAttributes(opcode);
+}
+
// TODO: use a configurable base prefix, and adjust callers to supply pass name.
/* Dump the CFG into a DOT graph */
void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks, const char *suffix) {
@@ -924,7 +942,7 @@
}
char* MIRGraph::GetDalvikDisassembly(const MIR* mir) {
- DecodedInstruction insn = mir->dalvikInsn;
+ MIR::DecodedInstruction insn = mir->dalvikInsn;
std::string str;
int flags = 0;
int opcode = insn.opcode;
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 2c125f6..c728d84 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -254,7 +254,15 @@
* additional fields on as-needed basis. Question: how to support MIR Pseudo-ops; probably
* need to carry aux data pointer.
*/
- DecodedInstruction dalvikInsn;
+ struct DecodedInstruction {
+ uint32_t vA;
+ uint32_t vB;
+ uint64_t vB_wide; /* for k51l */
+ uint32_t vC;
+ uint32_t arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */
+ Instruction::Code opcode;
+ } dalvikInsn;
+
uint16_t width; // Note: width can include switch table or fill array data.
NarrowDexOffset offset; // Offset of the instruction in code units.
uint16_t optimization_flags;
@@ -360,13 +368,10 @@
unsigned ref:1; // Something GC cares about.
unsigned high_word:1; // High word of pair?
unsigned home:1; // Does this represent the home location?
- VectorLengthType vec_len:3; // TODO: remove. Is this value in a vector register, and how big is it?
RegStorage reg; // Encoded physical registers.
int16_t s_reg_low; // SSA name for low Dalvik word.
int16_t orig_sreg; // TODO: remove after Bitcode gen complete
// and consolidate usage w/ s_reg_low.
-
- bool IsVectorScalar() const { return vec_len == kVectorLength4 || vec_len == kVectorLength8;}
};
/*
@@ -392,8 +397,8 @@
};
-const RegLocation bad_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, kVectorNotUsed,
- RegStorage(RegStorage::kInvalid), INVALID_SREG, INVALID_SREG};
+const RegLocation bad_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, RegStorage(), INVALID_SREG,
+ INVALID_SREG};
class MIRGraph {
public:
@@ -851,6 +856,9 @@
*/
void CountUses(struct BasicBlock* bb);
+ static uint64_t GetDataFlowAttributes(Instruction::Code opcode);
+ static uint64_t GetDataFlowAttributes(MIR* mir);
+
/**
* @brief Combine BasicBlocks
* @param the BasicBlock we are considering
@@ -868,7 +876,6 @@
RegLocation* reg_location_; // Map SSA names to location.
SafeMap<unsigned int, unsigned int> block_id_map_; // Block collapse lookup cache.
- static const uint64_t oat_data_flow_attributes_[kMirOpLast];
static const char* extended_mir_op_names_[kMirOpLast - kMirOpFirst];
static const uint32_t analysis_attributes_[kMirOpLast];
@@ -882,7 +889,7 @@
void CompilerInitializeSSAConversion();
bool DoSSAConversion(BasicBlock* bb);
bool InvokeUsesMethodStar(MIR* mir);
- int ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_instruction);
+ int ParseInsn(const uint16_t* code_ptr, MIR::DecodedInstruction* decoded_instruction);
bool ContentIsInsn(const uint16_t* code_ptr);
BasicBlock* SplitBlock(DexOffset code_offset, BasicBlock* orig_block,
BasicBlock** immed_pred_block_p);
@@ -985,6 +992,7 @@
GrowableArray<MirIFieldLoweringInfo> ifield_lowering_infos_;
GrowableArray<MirSFieldLoweringInfo> sfield_lowering_infos_;
GrowableArray<MirMethodLoweringInfo> method_lowering_infos_;
+ static const uint64_t oat_data_flow_attributes_[kMirOpLast];
friend class ClassInitCheckEliminationTest;
friend class LocalValueNumberingTest;
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 937e258..5c1bdf4 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -43,13 +43,13 @@
for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
// Skip pass if BB has MIR without SSA representation.
- if (mir->ssa_rep == NULL) {
+ if (mir->ssa_rep == nullptr) {
return;
}
- uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+ uint64_t df_attributes = GetDataFlowAttributes(mir);
- DecodedInstruction *d_insn = &mir->dalvikInsn;
+ MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
if (!(df_attributes & DF_HAS_DEFS)) continue;
@@ -239,7 +239,7 @@
// FIXME - will probably need to revisit all uses of this, as type not defined.
static const RegLocation temp_loc = {kLocCompilerTemp,
- 0, 1 /*defined*/, 0, 0, 0, 0, 0, 1 /*home*/, kVectorNotUsed,
+ 0, 1 /*defined*/, 0, 0, 0, 0, 0, 1 /*home*/,
RegStorage(), INVALID_SREG, INVALID_SREG};
CompilerTemp* MIRGraph::GetNewCompilerTemp(CompilerTempType ct_type, bool wide) {
@@ -559,7 +559,7 @@
if (mir->ssa_rep == NULL) {
continue;
}
- uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+ uint64_t df_attributes = GetDataFlowAttributes(mir);
if (df_attributes & DF_HAS_NULL_CHKS) {
checkstats_->null_checks++;
if (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) {
@@ -644,7 +644,7 @@
MIR* mir = bb->last_mir_insn;
// Grab the attributes from the paired opcode
MIR* throw_insn = mir->meta.throw_insn;
- uint64_t df_attributes = oat_data_flow_attributes_[throw_insn->dalvikInsn.opcode];
+ uint64_t df_attributes = GetDataFlowAttributes(throw_insn);
bool can_combine = true;
if (df_attributes & DF_HAS_NULL_CHKS) {
can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0);
@@ -796,7 +796,7 @@
continue;
}
- uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+ uint64_t df_attributes = GetDataFlowAttributes(mir);
// Might need a null check?
if (df_attributes & DF_HAS_NULL_CHKS) {
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index 40ced70..891d9fb 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -172,7 +172,7 @@
mir->offset = 2 * i; // All insns need to be at least 2 code units long.
mir->width = 2u;
mir->optimization_flags = 0u;
- merged_df_flags |= MIRGraph::oat_data_flow_attributes_[def->opcode];
+ merged_df_flags |= MIRGraph::GetDataFlowAttributes(def->opcode);
}
cu_.mir_graph->merged_df_flags_ = merged_df_flags;
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 70438ec..576e242 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -722,7 +722,7 @@
/* Prep Src and Dest locations */
int next_sreg = 0;
int next_loc = 0;
- uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+ uint64_t attrs = MirGraph::GetDataFlowAttributes(opcode);
rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
if (attrs & DF_UA) {
if (attrs & DF_A_WIDE) {
diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h
index c9acd66..e384f6b 100644
--- a/compiler/dex/quick/arm/arm_lir.h
+++ b/compiler/dex/quick/arm/arm_lir.h
@@ -93,29 +93,8 @@
* +========================+
*/
-// Offset to distingish FP regs.
-#define ARM_FP_REG_OFFSET 32
-// Offset to distinguish DP FP regs.
-#define ARM_FP_DOUBLE 64
// First FP callee save.
#define ARM_FP_CALLEE_SAVE_BASE 16
-// Reg types.
-#define ARM_REGTYPE(x) (x & (ARM_FP_REG_OFFSET | ARM_FP_DOUBLE))
-#define ARM_FPREG(x) ((x & ARM_FP_REG_OFFSET) == ARM_FP_REG_OFFSET)
-#define ARM_LOWREG(x) ((x & 0x7) == x)
-#define ARM_DOUBLEREG(x) ((x & ARM_FP_DOUBLE) == ARM_FP_DOUBLE)
-#define ARM_SINGLEREG(x) (ARM_FPREG(x) && !ARM_DOUBLEREG(x))
-
-/*
- * Note: the low register of a floating point pair is sufficient to
- * create the name of a double, but require both names to be passed to
- * allow for asserts to verify that the pair is consecutive if significant
- * rework is done in this area. Also, it is a good reminder in the calling
- * code that reg locations always describe doubles as a pair of singles.
- */
-#define ARM_S2D(x, y) ((x) | ARM_FP_DOUBLE)
-// Mask to strip off fp flags.
-#define ARM_FP_REG_MASK (ARM_FP_REG_OFFSET-1)
enum ArmResourceEncodingPos {
kArmGPReg0 = 0,
@@ -134,135 +113,197 @@
#define ENCODE_ARM_REG_FPCS_LIST(N) (static_cast<uint64_t>(N) << kArmFPReg16)
enum ArmNativeRegisterPool {
- r0 = 0,
- r1 = 1,
- r2 = 2,
- r3 = 3,
- rARM_SUSPEND = 4,
- r5 = 5,
- r6 = 6,
- r7 = 7,
- r8 = 8,
- rARM_SELF = 9,
- r10 = 10,
- r11 = 11,
- r12 = 12,
- r13sp = 13,
- rARM_SP = 13,
- r14lr = 14,
- rARM_LR = 14,
- r15pc = 15,
- rARM_PC = 15,
- fr0 = 0 + ARM_FP_REG_OFFSET,
- fr1 = 1 + ARM_FP_REG_OFFSET,
- fr2 = 2 + ARM_FP_REG_OFFSET,
- fr3 = 3 + ARM_FP_REG_OFFSET,
- fr4 = 4 + ARM_FP_REG_OFFSET,
- fr5 = 5 + ARM_FP_REG_OFFSET,
- fr6 = 6 + ARM_FP_REG_OFFSET,
- fr7 = 7 + ARM_FP_REG_OFFSET,
- fr8 = 8 + ARM_FP_REG_OFFSET,
- fr9 = 9 + ARM_FP_REG_OFFSET,
- fr10 = 10 + ARM_FP_REG_OFFSET,
- fr11 = 11 + ARM_FP_REG_OFFSET,
- fr12 = 12 + ARM_FP_REG_OFFSET,
- fr13 = 13 + ARM_FP_REG_OFFSET,
- fr14 = 14 + ARM_FP_REG_OFFSET,
- fr15 = 15 + ARM_FP_REG_OFFSET,
- fr16 = 16 + ARM_FP_REG_OFFSET,
- fr17 = 17 + ARM_FP_REG_OFFSET,
- fr18 = 18 + ARM_FP_REG_OFFSET,
- fr19 = 19 + ARM_FP_REG_OFFSET,
- fr20 = 20 + ARM_FP_REG_OFFSET,
- fr21 = 21 + ARM_FP_REG_OFFSET,
- fr22 = 22 + ARM_FP_REG_OFFSET,
- fr23 = 23 + ARM_FP_REG_OFFSET,
- fr24 = 24 + ARM_FP_REG_OFFSET,
- fr25 = 25 + ARM_FP_REG_OFFSET,
- fr26 = 26 + ARM_FP_REG_OFFSET,
- fr27 = 27 + ARM_FP_REG_OFFSET,
- fr28 = 28 + ARM_FP_REG_OFFSET,
- fr29 = 29 + ARM_FP_REG_OFFSET,
- fr30 = 30 + ARM_FP_REG_OFFSET,
- fr31 = 31 + ARM_FP_REG_OFFSET,
- dr0 = fr0 + ARM_FP_DOUBLE,
- dr1 = fr2 + ARM_FP_DOUBLE,
- dr2 = fr4 + ARM_FP_DOUBLE,
- dr3 = fr6 + ARM_FP_DOUBLE,
- dr4 = fr8 + ARM_FP_DOUBLE,
- dr5 = fr10 + ARM_FP_DOUBLE,
- dr6 = fr12 + ARM_FP_DOUBLE,
- dr7 = fr14 + ARM_FP_DOUBLE,
- dr8 = fr16 + ARM_FP_DOUBLE,
- dr9 = fr18 + ARM_FP_DOUBLE,
- dr10 = fr20 + ARM_FP_DOUBLE,
- dr11 = fr22 + ARM_FP_DOUBLE,
- dr12 = fr24 + ARM_FP_DOUBLE,
- dr13 = fr26 + ARM_FP_DOUBLE,
- dr14 = fr28 + ARM_FP_DOUBLE,
- dr15 = fr30 + ARM_FP_DOUBLE,
+ r0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0,
+ r1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 1,
+ r2 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 2,
+ r3 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 3,
+ rARM_SUSPEND = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 4,
+ r5 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 5,
+ r6 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 6,
+ r7 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 7,
+ r8 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 8,
+ rARM_SELF = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 9,
+ r10 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 10,
+ r11 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 11,
+ r12 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 12,
+ r13sp = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 13,
+ rARM_SP = r13sp,
+ r14lr = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 14,
+ rARM_LR = r14lr,
+ r15pc = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 15,
+ rARM_PC = r15pc,
+
+ fr0 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 0,
+ fr1 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 1,
+ fr2 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 2,
+ fr3 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 3,
+ fr4 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 4,
+ fr5 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 5,
+ fr6 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 6,
+ fr7 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 7,
+ fr8 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 8,
+ fr9 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 9,
+ fr10 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 10,
+ fr11 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 11,
+ fr12 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 12,
+ fr13 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 13,
+ fr14 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 14,
+ fr15 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 15,
+ fr16 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 16,
+ fr17 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 17,
+ fr18 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 18,
+ fr19 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 19,
+ fr20 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 20,
+ fr21 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 21,
+ fr22 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 22,
+ fr23 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 23,
+ fr24 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 24,
+ fr25 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 25,
+ fr26 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 26,
+ fr27 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 27,
+ fr28 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 28,
+ fr29 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 29,
+ fr30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
+ fr31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
+
+ dr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
+ dr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1,
+ dr2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
+ dr3 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 3,
+ dr4 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
+ dr5 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 5,
+ dr6 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
+ dr7 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 7,
+ dr8 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8,
+ dr9 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 9,
+ dr10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+ dr11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+ dr12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+ dr13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+ dr14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+ dr15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
+#if 0
+ // Enable when def/use and runtime able to handle these.
+ dr16 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+ dr17 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 17,
+ dr18 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+ dr19 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 19,
+ dr20 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+ dr21 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 21,
+ dr22 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+ dr23 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 23,
+ dr24 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+ dr25 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 25,
+ dr26 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+ dr27 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 27,
+ dr28 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+ dr29 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 29,
+ dr30 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
+ dr31 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 31,
+#endif
};
-// TODO: clean this up; reduce use of or eliminate macros
+constexpr RegStorage rs_r0(RegStorage::kValid | r0);
+constexpr RegStorage rs_r1(RegStorage::kValid | r1);
+constexpr RegStorage rs_r2(RegStorage::kValid | r2);
+constexpr RegStorage rs_r3(RegStorage::kValid | r3);
+constexpr RegStorage rs_rARM_SUSPEND(RegStorage::kValid | rARM_SUSPEND);
+constexpr RegStorage rs_r5(RegStorage::kValid | r5);
+constexpr RegStorage rs_r6(RegStorage::kValid | r6);
+constexpr RegStorage rs_r7(RegStorage::kValid | r7);
+constexpr RegStorage rs_r8(RegStorage::kValid | r8);
+constexpr RegStorage rs_rARM_SELF(RegStorage::kValid | rARM_SELF);
+constexpr RegStorage rs_r10(RegStorage::kValid | r10);
+constexpr RegStorage rs_r11(RegStorage::kValid | r11);
+constexpr RegStorage rs_r12(RegStorage::kValid | r12);
+constexpr RegStorage rs_r13sp(RegStorage::kValid | r13sp);
+constexpr RegStorage rs_rARM_SP(RegStorage::kValid | rARM_SP);
+constexpr RegStorage rs_r14lr(RegStorage::kValid | r14lr);
+constexpr RegStorage rs_rARM_LR(RegStorage::kValid | rARM_LR);
+constexpr RegStorage rs_r15pc(RegStorage::kValid | r15pc);
+constexpr RegStorage rs_rARM_PC(RegStorage::kValid | rARM_PC);
+constexpr RegStorage rs_invalid(RegStorage::kInvalid);
-const RegStorage rs_r0(RegStorage::k32BitSolo, r0);
-const RegStorage rs_r1(RegStorage::k32BitSolo, r1);
-const RegStorage rs_r2(RegStorage::k32BitSolo, r2);
-const RegStorage rs_r3(RegStorage::k32BitSolo, r3);
-const RegStorage rs_rARM_SUSPEND(RegStorage::k32BitSolo, rARM_SUSPEND);
-const RegStorage rs_r5(RegStorage::k32BitSolo, r5);
-const RegStorage rs_r6(RegStorage::k32BitSolo, r6);
-const RegStorage rs_r7(RegStorage::k32BitSolo, r7);
-const RegStorage rs_r8(RegStorage::k32BitSolo, r8);
-const RegStorage rs_rARM_SELF(RegStorage::k32BitSolo, rARM_SELF);
-const RegStorage rs_r10(RegStorage::k32BitSolo, r10);
-const RegStorage rs_r11(RegStorage::k32BitSolo, r11);
-const RegStorage rs_r12(RegStorage::k32BitSolo, r12);
-const RegStorage rs_r13sp(RegStorage::k32BitSolo, r13sp);
-const RegStorage rs_rARM_SP(RegStorage::k32BitSolo, rARM_SP);
-const RegStorage rs_r14lr(RegStorage::k32BitSolo, r14lr);
-const RegStorage rs_rARM_LR(RegStorage::k32BitSolo, rARM_LR);
-const RegStorage rs_r15pc(RegStorage::k32BitSolo, r15pc);
-const RegStorage rs_rARM_PC(RegStorage::k32BitSolo, rARM_PC);
-const RegStorage rs_invalid(RegStorage::kInvalid);
+constexpr RegStorage rs_fr0(RegStorage::kValid | fr0);
+constexpr RegStorage rs_fr1(RegStorage::kValid | fr1);
+constexpr RegStorage rs_fr2(RegStorage::kValid | fr2);
+constexpr RegStorage rs_fr3(RegStorage::kValid | fr3);
+constexpr RegStorage rs_fr4(RegStorage::kValid | fr4);
+constexpr RegStorage rs_fr5(RegStorage::kValid | fr5);
+constexpr RegStorage rs_fr6(RegStorage::kValid | fr6);
+constexpr RegStorage rs_fr7(RegStorage::kValid | fr7);
+constexpr RegStorage rs_fr8(RegStorage::kValid | fr8);
+constexpr RegStorage rs_fr9(RegStorage::kValid | fr9);
+constexpr RegStorage rs_fr10(RegStorage::kValid | fr10);
+constexpr RegStorage rs_fr11(RegStorage::kValid | fr11);
+constexpr RegStorage rs_fr12(RegStorage::kValid | fr12);
+constexpr RegStorage rs_fr13(RegStorage::kValid | fr13);
+constexpr RegStorage rs_fr14(RegStorage::kValid | fr14);
+constexpr RegStorage rs_fr15(RegStorage::kValid | fr15);
+constexpr RegStorage rs_fr16(RegStorage::kValid | fr16);
+constexpr RegStorage rs_fr17(RegStorage::kValid | fr17);
+constexpr RegStorage rs_fr18(RegStorage::kValid | fr18);
+constexpr RegStorage rs_fr19(RegStorage::kValid | fr19);
+constexpr RegStorage rs_fr20(RegStorage::kValid | fr20);
+constexpr RegStorage rs_fr21(RegStorage::kValid | fr21);
+constexpr RegStorage rs_fr22(RegStorage::kValid | fr22);
+constexpr RegStorage rs_fr23(RegStorage::kValid | fr23);
+constexpr RegStorage rs_fr24(RegStorage::kValid | fr24);
+constexpr RegStorage rs_fr25(RegStorage::kValid | fr25);
+constexpr RegStorage rs_fr26(RegStorage::kValid | fr26);
+constexpr RegStorage rs_fr27(RegStorage::kValid | fr27);
+constexpr RegStorage rs_fr28(RegStorage::kValid | fr28);
+constexpr RegStorage rs_fr29(RegStorage::kValid | fr29);
+constexpr RegStorage rs_fr30(RegStorage::kValid | fr30);
+constexpr RegStorage rs_fr31(RegStorage::kValid | fr31);
-// Target-independent aliases.
-#define rARM_ARG0 r0
-#define rs_rARM_ARG0 rs_r0
-#define rARM_ARG1 r1
-#define rs_rARM_ARG1 rs_r1
-#define rARM_ARG2 r2
-#define rs_rARM_ARG2 rs_r2
-#define rARM_ARG3 r3
-#define rs_rARM_ARG3 rs_r3
-#define rARM_FARG0 r0
-#define rs_ARM_FARG0 rs_r0
-#define rARM_FARG1 r1
-#define rs_rARM_FARG1 rs_r1
-#define rARM_FARG2 r2
-#define rs_rARM_FARG2 rs_r2
-#define rARM_FARG3 r3
-#define rs_rARM_FARG3 rs_r3
-#define rARM_RET0 r0
-#define rs_rARM_RET0 rs_r0
-#define rARM_RET1 r1
-#define rs_rARM_RET1 rs_r1
-#define rARM_INVOKE_TGT rARM_LR
-#define rs_rARM_INVOKE_TGT rs_rARM_LR
-#define rARM_COUNT RegStorage::kInvalidRegVal
+constexpr RegStorage rs_dr0(RegStorage::kValid | dr0);
+constexpr RegStorage rs_dr1(RegStorage::kValid | dr1);
+constexpr RegStorage rs_dr2(RegStorage::kValid | dr2);
+constexpr RegStorage rs_dr3(RegStorage::kValid | dr3);
+constexpr RegStorage rs_dr4(RegStorage::kValid | dr4);
+constexpr RegStorage rs_dr5(RegStorage::kValid | dr5);
+constexpr RegStorage rs_dr6(RegStorage::kValid | dr6);
+constexpr RegStorage rs_dr7(RegStorage::kValid | dr7);
+constexpr RegStorage rs_dr8(RegStorage::kValid | dr8);
+constexpr RegStorage rs_dr9(RegStorage::kValid | dr9);
+constexpr RegStorage rs_dr10(RegStorage::kValid | dr10);
+constexpr RegStorage rs_dr11(RegStorage::kValid | dr11);
+constexpr RegStorage rs_dr12(RegStorage::kValid | dr12);
+constexpr RegStorage rs_dr13(RegStorage::kValid | dr13);
+constexpr RegStorage rs_dr14(RegStorage::kValid | dr14);
+constexpr RegStorage rs_dr15(RegStorage::kValid | dr15);
+#if 0
+constexpr RegStorage rs_dr16(RegStorage::kValid | dr16);
+constexpr RegStorage rs_dr17(RegStorage::kValid | dr17);
+constexpr RegStorage rs_dr18(RegStorage::kValid | dr18);
+constexpr RegStorage rs_dr19(RegStorage::kValid | dr19);
+constexpr RegStorage rs_dr20(RegStorage::kValid | dr20);
+constexpr RegStorage rs_dr21(RegStorage::kValid | dr21);
+constexpr RegStorage rs_dr22(RegStorage::kValid | dr22);
+constexpr RegStorage rs_dr23(RegStorage::kValid | dr23);
+constexpr RegStorage rs_dr24(RegStorage::kValid | dr24);
+constexpr RegStorage rs_dr25(RegStorage::kValid | dr25);
+constexpr RegStorage rs_dr26(RegStorage::kValid | dr26);
+constexpr RegStorage rs_dr27(RegStorage::kValid | dr27);
+constexpr RegStorage rs_dr28(RegStorage::kValid | dr28);
+constexpr RegStorage rs_dr29(RegStorage::kValid | dr29);
+constexpr RegStorage rs_dr30(RegStorage::kValid | dr30);
+constexpr RegStorage rs_dr31(RegStorage::kValid | dr31);
+#endif
// RegisterLocation templates return values (r0, or r0/r1).
const RegLocation arm_loc_c_return
- {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG};
const RegLocation arm_loc_c_return_wide
- {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k64BitPair, r0, r1), INVALID_SREG, INVALID_SREG};
const RegLocation arm_loc_c_return_float
- {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG};
const RegLocation arm_loc_c_return_double
- {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k64BitPair, r0, r1), INVALID_SREG, INVALID_SREG};
enum ArmShiftEncodings {
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index f77b0a6..cac766d 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -1137,24 +1137,25 @@
bits |= value;
break;
case kFmtDfp: {
- DCHECK(ARM_DOUBLEREG(operand));
- DCHECK_EQ((operand & 0x1), 0U);
- uint32_t reg_name = (operand & ARM_FP_REG_MASK) >> 1;
+ DCHECK(RegStorage::IsDouble(operand)) << ", Operand = 0x" << std::hex << operand;
+ uint32_t reg_num = RegStorage::RegNum(operand);
/* Snag the 1-bit slice and position it */
- value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end;
+ value = ((reg_num & 0x10) >> 4) << encoder->field_loc[i].end;
/* Extract and position the 4-bit slice */
- value |= (reg_name & 0x0f) << encoder->field_loc[i].start;
+ value |= (reg_num & 0x0f) << encoder->field_loc[i].start;
bits |= value;
break;
}
- case kFmtSfp:
- DCHECK(ARM_SINGLEREG(operand));
+ case kFmtSfp: {
+ DCHECK(RegStorage::IsSingle(operand)) << ", Operand = 0x" << std::hex << operand;
+ uint32_t reg_num = RegStorage::RegNum(operand);
/* Snag the 1-bit slice and position it */
- value = (operand & 0x1) << encoder->field_loc[i].end;
+ value = (reg_num & 0x1) << encoder->field_loc[i].end;
/* Extract and position the 4-bit slice */
- value |= ((operand & 0x1e) >> 1) << encoder->field_loc[i].start;
+ value |= ((reg_num & 0x1e) >> 1) << encoder->field_loc[i].start;
bits |= value;
break;
+ }
case kFmtImm12:
case kFmtModImm:
value = ((operand & 0x800) >> 11) << 26;
@@ -1217,8 +1218,8 @@
AssignDataOffsets();
/*
- * Note: generation must be 1 on first pass (to distinguish from initialized state of 0 for non-visited nodes).
- * Start at zero here, and bit will be flipped to 1 on entry to the loop.
+ * Note: generation must be 1 on first pass (to distinguish from initialized state of 0 for
+ * non-visited nodes). Start at zero here, and bit will be flipped to 1 on entry to the loop.
*/
int generation = 0;
while (true) {
@@ -1244,7 +1245,7 @@
case kFixupNone:
break;
case kFixupVLoad:
- if (lir->operands[1] != r15pc) {
+ if (lir->operands[1] != rs_r15pc.GetReg()) {
break;
}
// NOTE: intentional fallthrough.
@@ -1285,7 +1286,8 @@
* happens.
*/
int base_reg = ((lir->opcode == kThumb2LdrdPcRel8) ||
- (lir->opcode == kThumb2LdrPcRel12)) ? lir->operands[0] : rARM_LR;
+ (lir->opcode == kThumb2LdrPcRel12)) ? lir->operands[0] :
+ rs_rARM_LR.GetReg();
// Add new Adr to generate the address.
LIR* new_adr = RawLIR(lir->dalvik_offset, kThumb2Adr,
@@ -1500,7 +1502,8 @@
EmbeddedData *tab_rec = reinterpret_cast<EmbeddedData*>(UnwrapPointer(lir->operands[2]));
LIR* target = lir->target;
int32_t target_disp = (tab_rec != NULL) ? tab_rec->offset + offset_adjustment
- : target->offset + ((target->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
+ : target->offset + ((target->flags.generation == lir->flags.generation) ? 0 :
+ offset_adjustment);
int32_t disp = target_disp - ((lir->offset + 4) & ~3);
if (disp < 4096) {
lir->operands[1] = disp;
@@ -1533,12 +1536,12 @@
prev_lir = new_mov16H; // Now we've got a new prev.
offset_adjustment -= lir->flags.size;
- if (ARM_LOWREG(lir->operands[0])) {
+ if (RegStorage::RegNum(lir->operands[0]) < 8) {
lir->opcode = kThumbAddRRLH;
} else {
lir->opcode = kThumbAddRRHH;
}
- lir->operands[1] = rARM_PC;
+ lir->operands[1] = rs_rARM_PC.GetReg();
lir->flags.size = EncodingMap[lir->opcode].size;
offset_adjustment += lir->flags.size;
// Must stay in fixup list and have offset updated; will be used by LST/HSP pair.
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 9cb56cf..163c0fe 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -54,8 +54,7 @@
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
uint32_t size = table[1];
- tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*),
- kArenaAllocLIR));
+ tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*), kArenaAllocLIR));
switch_tables_.Insert(tab_rec);
// Get the switch value
@@ -78,7 +77,7 @@
// Establish loop branch target
LIR* target = NewLIR0(kPseudoTargetLabel);
// Load next key/disp
- NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetReg()) | (1 << r_disp.GetReg()));
+ NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetRegNum()) | (1 << r_disp.GetRegNum()));
OpRegReg(kOpCmp, r_key, rl_src.reg);
// Go if match. NOTE: No instruction set switch here - must stay Thumb2
LIR* it = OpIT(kCondEq, "");
@@ -168,7 +167,7 @@
LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pHandleFillArrayData).Int32Value(),
rs_rARM_LR);
// Materialize a pointer to the fill data image
- NewLIR3(kThumb2Adr, r1, 0, WrapPointer(tab_rec));
+ NewLIR3(kThumb2Adr, rs_r1.GetReg(), 0, WrapPointer(tab_rec));
ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR);
MarkSafepointPC(call_inst);
@@ -195,10 +194,12 @@
}
}
Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
- NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+ NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
+ mirror::Object::MonitorOffset().Int32Value() >> 2);
MarkPossibleNullPointerException(opt_flags);
LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_r1, 0, NULL);
- NewLIR4(kThumb2Strex, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+ NewLIR4(kThumb2Strex, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(),
+ mirror::Object::MonitorOffset().Int32Value() >> 2);
LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_r1, 0, NULL);
@@ -221,16 +222,19 @@
// Explicit null-check as slow-path is entered using an IT.
GenNullCheck(rs_r0, opt_flags);
Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
- NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+ NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
+ mirror::Object::MonitorOffset().Int32Value() >> 2);
MarkPossibleNullPointerException(opt_flags);
OpRegImm(kOpCmp, rs_r1, 0);
LIR* it = OpIT(kCondEq, "");
- NewLIR4(kThumb2Strex/*eq*/, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+ NewLIR4(kThumb2Strex/*eq*/, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(),
+ mirror::Object::MonitorOffset().Int32Value() >> 2);
OpEndIT(it);
OpRegImm(kOpCmp, rs_r1, 0);
it = OpIT(kCondNe, "T");
// Go expensive route - artLockObjectFromCode(self, obj);
- LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), rs_rARM_LR);
+ LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(),
+ rs_rARM_LR);
ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
OpEndIT(it);
@@ -339,10 +343,10 @@
* expanding the frame or flushing. This leaves the utility
* code with a single temp: r12. This should be enough.
*/
- LockTemp(r0);
- LockTemp(r1);
- LockTemp(r2);
- LockTemp(r3);
+ LockTemp(rs_r0);
+ LockTemp(rs_r1);
+ LockTemp(rs_r2);
+ LockTemp(rs_r3);
/*
* We can safely skip the stack overflow check if we're
@@ -433,10 +437,10 @@
FlushIns(ArgLocs, rl_method);
- FreeTemp(r0);
- FreeTemp(r1);
- FreeTemp(r2);
- FreeTemp(r3);
+ FreeTemp(rs_r0);
+ FreeTemp(rs_r1);
+ FreeTemp(rs_r2);
+ FreeTemp(rs_r3);
}
void ArmMir2Lir::GenExitSequence() {
@@ -445,8 +449,8 @@
* In the exit path, r0/r1 are live - make sure they aren't
* allocated by the register utilities as temps.
*/
- LockTemp(r0);
- LockTemp(r1);
+ LockTemp(rs_r0);
+ LockTemp(rs_r1);
NewLIR0(kPseudoMethodExit);
OpRegImm(kOpAdd, rs_rARM_SP, frame_size_ - (spill_count * 4));
@@ -454,20 +458,20 @@
if (num_fp_spills_) {
NewLIR1(kThumb2VPopCS, num_fp_spills_);
}
- if (core_spill_mask_ & (1 << rARM_LR)) {
+ if (core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) {
/* Unspill rARM_LR to rARM_PC */
- core_spill_mask_ &= ~(1 << rARM_LR);
- core_spill_mask_ |= (1 << rARM_PC);
+ core_spill_mask_ &= ~(1 << rs_rARM_LR.GetRegNum());
+ core_spill_mask_ |= (1 << rs_rARM_PC.GetRegNum());
}
NewLIR1(kThumb2Pop, core_spill_mask_);
- if (!(core_spill_mask_ & (1 << rARM_PC))) {
+ if (!(core_spill_mask_ & (1 << rs_rARM_PC.GetRegNum()))) {
/* We didn't pop to rARM_PC, so must do a bv rARM_LR */
- NewLIR1(kThumbBx, rARM_LR);
+ NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
}
}
void ArmMir2Lir::GenSpecialExitSequence() {
- NewLIR1(kThumbBx, rARM_LR);
+ NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
}
} // namespace art
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 646859c..9d1723a 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -38,7 +38,7 @@
LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
OpSize size);
LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
- RegStorage r_dest, RegStorage r_dest_hi, OpSize size, int s_reg);
+ RegStorage r_dest, OpSize size, int s_reg);
LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
@@ -46,16 +46,12 @@
LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
OpSize size);
LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
- RegStorage r_src, RegStorage r_src_hi, OpSize size, int s_reg);
+ RegStorage r_src, OpSize size, int s_reg);
void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
// Required for target - register utilities.
- bool IsFpReg(int reg);
- bool IsFpReg(RegStorage reg);
- bool SameRegType(int reg1, int reg2);
RegStorage AllocTypedTemp(bool fp_hint, int reg_class);
RegStorage AllocTypedTempWide(bool fp_hint, int reg_class);
- int S2d(int low_reg, int high_reg);
RegStorage TargetReg(SpecialTargetRegister reg);
RegStorage GetArgMappingToPhysicalReg(int arg_num);
RegLocation GetReturnAlt();
@@ -64,17 +60,16 @@
RegLocation LocCReturnDouble();
RegLocation LocCReturnFloat();
RegLocation LocCReturnWide();
- uint32_t FpRegMask();
- uint64_t GetRegMaskCommon(int reg);
+ uint64_t GetRegMaskCommon(RegStorage reg);
void AdjustSpillMask();
void ClobberCallerSave();
- void FlushReg(RegStorage reg);
- void FlushRegWide(RegStorage reg);
void FreeCallTemps();
void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
void LockCallTemps();
- void MarkPreservedSingle(int v_reg, int reg);
+ void MarkPreservedSingle(int v_reg, RegStorage reg);
+ void MarkPreservedDouble(int v_reg, RegStorage reg);
void CompilerInitializeRegAlloc();
+ RegStorage AllocPreservedDouble(int s_reg);
// Required for target - miscellaneous.
void AssembleLIR();
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index d72f596..bb02f74 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -111,13 +111,11 @@
rl_result = EvalLoc(rl_dest, kFPReg, true);
DCHECK(rl_dest.wide);
DCHECK(rl_result.wide);
- NewLIR3(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
- S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+ NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
StoreValueWide(rl_dest, rl_result);
}
-void ArmMir2Lir::GenConversion(Instruction::Code opcode,
- RegLocation rl_dest, RegLocation rl_src) {
+void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) {
int op = kThumbBkpt;
int src_reg;
RegLocation rl_result;
@@ -143,19 +141,16 @@
break;
case Instruction::LONG_TO_DOUBLE: {
rl_src = LoadValueWide(rl_src, kFPReg);
- src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
+ RegStorage src_low = rl_src.reg.DoubleToLowSingle();
+ RegStorage src_high = rl_src.reg.DoubleToHighSingle();
rl_result = EvalLoc(rl_dest, kFPReg, true);
- // TODO: fix AllocTempDouble to return a k64BitSolo double reg and lose the ARM_FP_DOUBLE.
RegStorage tmp1 = AllocTempDouble();
RegStorage tmp2 = AllocTempDouble();
- // FIXME: needs 64-bit register cleanup.
- NewLIR2(kThumb2VcvtF64S32, tmp1.GetLowReg() | ARM_FP_DOUBLE, (src_reg & ~ARM_FP_DOUBLE) + 1);
- NewLIR2(kThumb2VcvtF64U32, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
- (src_reg & ~ARM_FP_DOUBLE));
+ NewLIR2(kThumb2VcvtF64S32, tmp1.GetReg(), src_high.GetReg());
+ NewLIR2(kThumb2VcvtF64U32, rl_result.reg.GetReg(), src_low.GetReg());
LoadConstantWide(tmp2, 0x41f0000000000000LL);
- NewLIR3(kThumb2VmlaF64, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
- tmp1.GetLowReg() | ARM_FP_DOUBLE, tmp2.GetLowReg() | ARM_FP_DOUBLE);
+ NewLIR3(kThumb2VmlaF64, rl_result.reg.GetReg(), tmp1.GetReg(), tmp2.GetReg());
FreeTemp(tmp1);
FreeTemp(tmp2);
StoreValueWide(rl_dest, rl_result);
@@ -166,23 +161,20 @@
return;
case Instruction::LONG_TO_FLOAT: {
rl_src = LoadValueWide(rl_src, kFPReg);
- src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
+ RegStorage src_low = rl_src.reg.DoubleToLowSingle();
+ RegStorage src_high = rl_src.reg.DoubleToHighSingle();
rl_result = EvalLoc(rl_dest, kFPReg, true);
// Allocate temp registers.
RegStorage high_val = AllocTempDouble();
RegStorage low_val = AllocTempDouble();
RegStorage const_val = AllocTempDouble();
// Long to double.
- NewLIR2(kThumb2VcvtF64S32, high_val.GetLowReg() | ARM_FP_DOUBLE,
- (src_reg & ~ARM_FP_DOUBLE) + 1);
- NewLIR2(kThumb2VcvtF64U32, low_val.GetLowReg() | ARM_FP_DOUBLE,
- (src_reg & ~ARM_FP_DOUBLE));
+ NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
+ NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
- NewLIR3(kThumb2VmlaF64, low_val.GetLowReg() | ARM_FP_DOUBLE,
- high_val.GetLowReg() | ARM_FP_DOUBLE,
- const_val.GetLowReg() | ARM_FP_DOUBLE);
+ NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
// Double to float.
- NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetLowReg() | ARM_FP_DOUBLE);
+ NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
// Free temp registers.
FreeTemp(high_val);
FreeTemp(low_val);
@@ -199,14 +191,14 @@
}
if (rl_src.wide) {
rl_src = LoadValueWide(rl_src, kFPReg);
- src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
+ src_reg = rl_src.reg.GetReg();
} else {
rl_src = LoadValue(rl_src, kFPReg);
src_reg = rl_src.reg.GetReg();
}
if (rl_dest.wide) {
rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
+ NewLIR2(op, rl_result.reg.GetReg(), src_reg);
StoreValueWide(rl_dest, rl_result);
} else {
rl_result = EvalLoc(rl_dest, kFPReg, true);
@@ -225,8 +217,7 @@
rl_src2 = mir_graph_->GetSrcWide(mir, 2);
rl_src1 = LoadValueWide(rl_src1, kFPReg);
rl_src2 = LoadValueWide(rl_src2, kFPReg);
- NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg()),
- S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+ NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
} else {
rl_src1 = mir_graph_->GetSrc(mir, 0);
rl_src2 = mir_graph_->GetSrc(mir, 1);
@@ -300,8 +291,7 @@
ClobberSReg(rl_dest.s_reg_low);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
LoadConstant(rl_result.reg, default_result);
- NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg()),
- S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+ NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
} else {
rl_src1 = LoadValue(rl_src1, kFPReg);
rl_src2 = LoadValue(rl_src2, kFPReg);
@@ -311,7 +301,7 @@
LoadConstant(rl_result.reg, default_result);
NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
}
- DCHECK(!ARM_FPREG(rl_result.reg.GetReg()));
+ DCHECK(!rl_result.reg.IsFloat());
NewLIR0(kThumb2Fmstat);
LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
@@ -338,8 +328,7 @@
RegLocation rl_result;
rl_src = LoadValueWide(rl_src, kFPReg);
rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(kThumb2Vnegd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
- S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
+ NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
StoreValueWide(rl_dest, rl_result);
}
@@ -350,19 +339,16 @@
RegLocation rl_dest = InlineTargetWide(info); // double place for result
rl_src = LoadValueWide(rl_src, kFPReg);
RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
- // TODO: shouldn't need S2d once 64bitSolo has proper double tag bit.
- NewLIR2(kThumb2Vsqrtd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
- S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
- NewLIR2(kThumb2Vcmpd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
- S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()));
+ NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
+ NewLIR2(kThumb2Vcmpd, rl_result.reg.GetReg(), rl_result.reg.GetReg());
NewLIR0(kThumb2Fmstat);
branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
ClobberCallerSave();
LockCallTemps(); // Using fixed registers
RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pSqrt));
- NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
+ NewLIR3(kThumb2Fmrrd, rs_r0.GetReg(), rs_r1.GetReg(), rl_src.reg.GetReg());
NewLIR1(kThumbBlxR, r_tgt.GetReg());
- NewLIR3(kThumb2Fmdrr, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), r0, r1);
+ NewLIR3(kThumb2Fmdrr, rl_result.reg.GetReg(), rs_r0.GetReg(), rs_r1.GetReg());
branch->target = NewLIR0(kPseudoTargetLabel);
StoreValueWide(rl_dest, rl_result);
return true;
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index a2d6373..8391c03 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -322,7 +322,7 @@
*/
bool skip = ((target != NULL) && (target->opcode == kPseudoThrowTarget));
skip &= ((cu_->code_item->insns_size_in_code_units_ - current_dalvik_offset_) > 64);
- if (!skip && (ARM_LOWREG(reg.GetReg())) && (check_value == 0) &&
+ if (!skip && reg.Low8() && (check_value == 0) &&
((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
reg.GetReg(), 0);
@@ -344,13 +344,13 @@
if (r_src.IsPair()) {
r_src = r_src.GetLow();
}
- if (ARM_FPREG(r_dest.GetReg()) || ARM_FPREG(r_src.GetReg()))
+ if (r_dest.IsFloat() || r_src.IsFloat())
return OpFpRegCopy(r_dest, r_src);
- if (ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src.GetReg()))
+ if (r_dest.Low8() && r_src.Low8())
opcode = kThumbMovRR;
- else if (!ARM_LOWREG(r_dest.GetReg()) && !ARM_LOWREG(r_src.GetReg()))
+ else if (!r_dest.Low8() && !r_src.Low8())
opcode = kThumbMovRR_H2H;
- else if (ARM_LOWREG(r_dest.GetReg()))
+ else if (r_dest.Low8())
opcode = kThumbMovRR_H2L;
else
opcode = kThumbMovRR_L2H;
@@ -370,21 +370,19 @@
void ArmMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
if (r_dest != r_src) {
- bool dest_fp = ARM_FPREG(r_dest.GetLowReg());
- bool src_fp = ARM_FPREG(r_src.GetLowReg());
+ bool dest_fp = r_dest.IsFloat();
+ bool src_fp = r_src.IsFloat();
+ DCHECK(r_dest.Is64Bit());
+ DCHECK(r_src.Is64Bit());
if (dest_fp) {
if (src_fp) {
- // FIXME: handle 64-bit solo's here.
- OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
- RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
+ OpRegCopy(r_dest, r_src);
} else {
- NewLIR3(kThumb2Fmdrr, S2d(r_dest.GetLowReg(), r_dest.GetHighReg()),
- r_src.GetLowReg(), r_src.GetHighReg());
+ NewLIR3(kThumb2Fmdrr, r_dest.GetReg(), r_src.GetLowReg(), r_src.GetHighReg());
}
} else {
if (src_fp) {
- NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), S2d(r_src.GetLowReg(),
- r_src.GetHighReg()));
+ NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_src.GetReg());
} else {
// Handle overlap
if (r_src.GetHighReg() == r_dest.GetLowReg()) {
@@ -747,16 +745,18 @@
// around the potentially locked temp by using LR for r_ptr, unconditionally.
// TODO: Pass information about the need for more temps to the stack frame generation
// code so that we can rely on being able to allocate enough temps.
- DCHECK(!reg_pool_->core_regs[rARM_LR].is_temp);
- MarkTemp(rARM_LR);
- FreeTemp(rARM_LR);
- LockTemp(rARM_LR);
+ DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp());
+ MarkTemp(rs_rARM_LR);
+ FreeTemp(rs_rARM_LR);
+ LockTemp(rs_rARM_LR);
bool load_early = true;
if (is_long) {
- int expected_reg = is_long ? rl_src_expected.reg.GetLowReg() : rl_src_expected.reg.GetReg();
- int new_val_reg = is_long ? rl_src_new_value.reg.GetLowReg() : rl_src_new_value.reg.GetReg();
- bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !IsFpReg(expected_reg);
- bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !IsFpReg(new_val_reg);
+ RegStorage expected_reg = rl_src_expected.reg.IsPair() ? rl_src_expected.reg.GetLow() :
+ rl_src_expected.reg;
+ RegStorage new_val_reg = rl_src_new_value.reg.IsPair() ? rl_src_new_value.reg.GetLow() :
+ rl_src_new_value.reg;
+ bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !expected_reg.IsFloat();
+ bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !new_val_reg.IsFloat();
bool expected_is_good_reg = expected_is_core_reg && !IsTemp(expected_reg);
bool new_value_is_good_reg = new_value_is_core_reg && !IsTemp(new_val_reg);
@@ -802,9 +802,9 @@
// Free now unneeded rl_object and rl_offset to give more temps.
ClobberSReg(rl_object.s_reg_low);
- FreeTemp(rl_object.reg.GetReg());
+ FreeTemp(rl_object.reg);
ClobberSReg(rl_offset.s_reg_low);
- FreeTemp(rl_offset.reg.GetReg());
+ FreeTemp(rl_offset.reg);
RegLocation rl_expected;
if (!is_long) {
@@ -813,9 +813,9 @@
rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
} else {
// NOTE: partially defined rl_expected & rl_new_value - but we just want the regs.
- int low_reg = AllocTemp().GetReg();
- int high_reg = AllocTemp().GetReg();
- rl_new_value.reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+ RegStorage low_reg = AllocTemp();
+ RegStorage high_reg = AllocTemp();
+ rl_new_value.reg = RegStorage::MakeRegPair(low_reg, high_reg);
rl_expected = rl_new_value;
}
@@ -840,7 +840,7 @@
LoadValueDirectWide(rl_src_new_value, rl_new_value.reg);
}
// Make sure we use ORR that sets the ccode
- if (ARM_LOWREG(r_tmp.GetReg()) && ARM_LOWREG(r_tmp_high.GetReg())) {
+ if (r_tmp.Low8() && r_tmp_high.Low8()) {
NewLIR2(kThumbOrr, r_tmp.GetReg(), r_tmp_high.GetReg());
} else {
NewLIR4(kThumb2OrrRRRs, r_tmp.GetReg(), r_tmp.GetReg(), r_tmp_high.GetReg(), 0);
@@ -881,8 +881,8 @@
StoreValue(rl_dest, rl_result);
// Now, restore lr to its non-temp status.
- Clobber(rARM_LR);
- UnmarkTemp(rARM_LR);
+ Clobber(rs_rARM_LR);
+ UnmarkTemp(rs_rARM_LR);
return true;
}
@@ -891,11 +891,11 @@
}
LIR* ArmMir2Lir::OpVldm(RegStorage r_base, int count) {
- return NewLIR3(kThumb2Vldms, r_base.GetReg(), fr0, count);
+ return NewLIR3(kThumb2Vldms, r_base.GetReg(), rs_fr0.GetReg(), count);
}
LIR* ArmMir2Lir::OpVstm(RegStorage r_base, int count) {
- return NewLIR3(kThumb2Vstms, r_base.GetReg(), fr0, count);
+ return NewLIR3(kThumb2Vstms, r_base.GetReg(), rs_fr0.GetReg(), count);
}
void ArmMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
@@ -918,7 +918,7 @@
// Test suspend flag, return target of taken suspend branch
LIR* ArmMir2Lir::OpTestSuspend(LIR* target) {
- NewLIR2(kThumbSubRI8, rARM_SUSPEND, 1);
+ NewLIR2(kThumbSubRI8, rs_rARM_SUSPEND.GetReg(), 1);
return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
}
@@ -1012,9 +1012,9 @@
RegStorage res_lo;
RegStorage res_hi;
bool dest_promoted = rl_dest.location == kLocPhysReg && rl_dest.reg.Valid() &&
- !IsTemp(rl_dest.reg.GetLowReg()) && !IsTemp(rl_dest.reg.GetHighReg());
- bool src1_promoted = !IsTemp(rl_src1.reg.GetLowReg()) && !IsTemp(rl_src1.reg.GetHighReg());
- bool src2_promoted = !IsTemp(rl_src2.reg.GetLowReg()) && !IsTemp(rl_src2.reg.GetHighReg());
+ !IsTemp(rl_dest.reg.GetLow()) && !IsTemp(rl_dest.reg.GetHigh());
+ bool src1_promoted = !IsTemp(rl_src1.reg.GetLow()) && !IsTemp(rl_src1.reg.GetHigh());
+ bool src2_promoted = !IsTemp(rl_src2.reg.GetLow()) && !IsTemp(rl_src2.reg.GetHigh());
// Check if rl_dest is *not* either operand and we have enough temp registers.
if ((rl_dest.s_reg_low != rl_src1.s_reg_low && rl_dest.s_reg_low != rl_src2.s_reg_low) &&
(dest_promoted || src1_promoted || src2_promoted)) {
@@ -1036,10 +1036,10 @@
}
// Temporarily add LR to the temp pool, and assign it to tmp1
- MarkTemp(rARM_LR);
- FreeTemp(rARM_LR);
+ MarkTemp(rs_rARM_LR);
+ FreeTemp(rs_rARM_LR);
RegStorage tmp1 = rs_rARM_LR;
- LockTemp(rARM_LR);
+ LockTemp(rs_rARM_LR);
if (rl_src1.reg == rl_src2.reg) {
DCHECK(res_hi.Valid());
@@ -1054,7 +1054,7 @@
DCHECK(!res_hi.Valid());
DCHECK_NE(rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
DCHECK_NE(rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
- FreeTemp(rl_src1.reg.GetHighReg());
+ FreeTemp(rl_src1.reg.GetHigh());
res_hi = AllocTemp();
}
DCHECK(res_hi.Valid());
@@ -1073,8 +1073,8 @@
// Now, restore lr to its non-temp status.
FreeTemp(tmp1);
- Clobber(rARM_LR);
- UnmarkTemp(rARM_LR);
+ Clobber(rs_rARM_LR);
+ UnmarkTemp(rs_rARM_LR);
if (reg_status != 0) {
// We had manually allocated registers for rl_result.
@@ -1116,7 +1116,7 @@
*/
void ArmMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_dest, int scale) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
int len_offset = mirror::Array::LengthOffset().Int32Value();
int data_offset;
RegLocation rl_result;
@@ -1158,7 +1158,7 @@
// No special indexed operation, lea + load w/ displacement
reg_ptr = AllocTemp();
OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kArmLsl, scale));
- FreeTemp(rl_index.reg.GetReg());
+ FreeTemp(rl_index.reg);
}
rl_result = EvalLoc(rl_dest, reg_class, true);
@@ -1189,7 +1189,7 @@
// Offset base, then use indexed load
RegStorage reg_ptr = AllocTemp();
OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
- FreeTemp(rl_array.reg.GetReg());
+ FreeTemp(rl_array.reg);
rl_result = EvalLoc(rl_dest, reg_class, true);
if (needs_range_check) {
@@ -1209,7 +1209,7 @@
*/
void ArmMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
int len_offset = mirror::Array::LengthOffset().Int32Value();
bool constant_index = rl_index.is_const;
@@ -1234,8 +1234,8 @@
bool allocated_reg_ptr_temp = false;
if (constant_index) {
reg_ptr = rl_array.reg;
- } else if (IsTemp(rl_array.reg.GetReg()) && !card_mark) {
- Clobber(rl_array.reg.GetReg());
+ } else if (IsTemp(rl_array.reg) && !card_mark) {
+ Clobber(rl_array.reg);
reg_ptr = rl_array.reg;
} else {
allocated_reg_ptr_temp = true;
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 305e89b..f59720b 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -25,16 +25,41 @@
namespace art {
-static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
- r11, r12, rARM_SP, rARM_LR, rARM_PC};
-static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
-static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
- fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
- fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
- fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
-static int core_temps[] = {r0, r1, r2, r3, r12};
-static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
- fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
+// TODO: rework this when c++11 support allows.
+static const RegStorage core_regs_arr[] =
+ {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
+ rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
+static const RegStorage sp_regs_arr[] =
+ {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
+ rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
+ rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
+ rs_fr31};
+static const RegStorage dp_regs_arr[] =
+ {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
+ rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
+static const RegStorage reserved_regs_arr[] =
+ {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
+static const RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
+static const RegStorage sp_temps_arr[] =
+ {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
+ rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
+static const RegStorage dp_temps_arr[] =
+ {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
+
+static const std::vector<RegStorage> core_regs(core_regs_arr,
+ core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
+static const std::vector<RegStorage> sp_regs(sp_regs_arr,
+ sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
+static const std::vector<RegStorage> dp_regs(dp_regs_arr,
+ dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
+static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
+ reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
+static const std::vector<RegStorage> core_temps(core_temps_arr,
+ core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
+static const std::vector<RegStorage> sp_temps(sp_temps_arr,
+ sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
+static const std::vector<RegStorage> dp_temps(dp_temps_arr,
+ dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
RegLocation ArmMir2Lir::LocCReturn() {
return arm_loc_c_return;
@@ -54,74 +79,61 @@
// Return a target-dependent special register.
RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
- int res_reg = RegStorage::kInvalidRegVal;
+ RegStorage res_reg = RegStorage::InvalidReg();
switch (reg) {
- case kSelf: res_reg = rARM_SELF; break;
- case kSuspend: res_reg = rARM_SUSPEND; break;
- case kLr: res_reg = rARM_LR; break;
- case kPc: res_reg = rARM_PC; break;
- case kSp: res_reg = rARM_SP; break;
- case kArg0: res_reg = rARM_ARG0; break;
- case kArg1: res_reg = rARM_ARG1; break;
- case kArg2: res_reg = rARM_ARG2; break;
- case kArg3: res_reg = rARM_ARG3; break;
- case kFArg0: res_reg = rARM_FARG0; break;
- case kFArg1: res_reg = rARM_FARG1; break;
- case kFArg2: res_reg = rARM_FARG2; break;
- case kFArg3: res_reg = rARM_FARG3; break;
- case kRet0: res_reg = rARM_RET0; break;
- case kRet1: res_reg = rARM_RET1; break;
- case kInvokeTgt: res_reg = rARM_INVOKE_TGT; break;
- case kHiddenArg: res_reg = r12; break;
- case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
- case kCount: res_reg = rARM_COUNT; break;
+ case kSelf: res_reg = rs_rARM_SELF; break;
+ case kSuspend: res_reg = rs_rARM_SUSPEND; break;
+ case kLr: res_reg = rs_rARM_LR; break;
+ case kPc: res_reg = rs_rARM_PC; break;
+ case kSp: res_reg = rs_rARM_SP; break;
+ case kArg0: res_reg = rs_r0; break;
+ case kArg1: res_reg = rs_r1; break;
+ case kArg2: res_reg = rs_r2; break;
+ case kArg3: res_reg = rs_r3; break;
+ case kFArg0: res_reg = rs_r0; break;
+ case kFArg1: res_reg = rs_r1; break;
+ case kFArg2: res_reg = rs_r2; break;
+ case kFArg3: res_reg = rs_r3; break;
+ case kRet0: res_reg = rs_r0; break;
+ case kRet1: res_reg = rs_r1; break;
+ case kInvokeTgt: res_reg = rs_rARM_LR; break;
+ case kHiddenArg: res_reg = rs_r12; break;
+ case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
+ case kCount: res_reg = RegStorage::InvalidReg(); break;
}
- return RegStorage::Solo32(res_reg);
+ return res_reg;
}
RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
// For the 32-bit internal ABI, the first 3 arguments are passed in registers.
switch (arg_num) {
case 0:
- return rs_rARM_ARG1;
+ return rs_r1;
case 1:
- return rs_rARM_ARG2;
+ return rs_r2;
case 2:
- return rs_rARM_ARG3;
+ return rs_r3;
default:
return RegStorage::InvalidReg();
}
}
-// Create a double from a pair of singles.
-int ArmMir2Lir::S2d(int low_reg, int high_reg) {
- return ARM_S2D(low_reg, high_reg);
-}
-
-// Return mask to strip off fp reg flags and bias.
-uint32_t ArmMir2Lir::FpRegMask() {
- return ARM_FP_REG_MASK;
-}
-
-// True if both regs single, both core or both double.
-bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
- return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
-}
-
/*
* Decode the register id.
*/
-uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
+uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
uint64_t seed;
int shift;
- int reg_id;
-
-
- reg_id = reg & 0x1f;
+ int reg_id = reg.GetRegNum();
/* Each double register is equal to a pair of single-precision FP registers */
- seed = ARM_DOUBLEREG(reg) ? 3 : 1;
+ if (reg.IsDouble()) {
+ seed = 0x3;
+ reg_id = reg_id << 1;
+ } else {
+ seed = 1;
+ }
/* FP register starts at bit position 16 */
- shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
+ shift = reg.IsFloat() ? kArmFPReg0 : 0;
/* Expand the double register id into single offset */
shift += reg_id;
return (seed << shift);
@@ -196,7 +208,7 @@
}
/* Fixup for kThumbPush/lr and kThumbPop/pc */
if (opcode == kThumbPush || opcode == kThumbPop) {
- uint64_t r8Mask = GetRegMaskCommon(r8);
+ uint64_t r8Mask = GetRegMaskCommon(rs_r8);
if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
lir->u.m.use_mask &= ~r8Mask;
lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
@@ -274,9 +286,9 @@
if (vector & 0x1) {
int reg_id = i;
if (opcode == kThumbPush && i == 8) {
- reg_id = r14lr;
+ reg_id = rs_rARM_LR.GetRegNum();
} else if (opcode == kThumbPop && i == 8) {
- reg_id = r15pc;
+ reg_id = rs_rARM_PC.GetRegNum();
}
if (printed) {
snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
@@ -391,10 +403,10 @@
snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
break;
case 's':
- snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
+ snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
break;
case 'S':
- snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
+ snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
break;
case 'h':
snprintf(tbuf, arraysize(tbuf), "%04x", operand);
@@ -404,6 +416,7 @@
snprintf(tbuf, arraysize(tbuf), "%d", operand);
break;
case 'C':
+ operand = RegStorage::RegNum(operand);
DCHECK_LT(operand, static_cast<int>(
sizeof(core_reg_names)/sizeof(core_reg_names[0])));
snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
@@ -539,48 +552,46 @@
RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
- return AllocTempFloat();
+ return AllocTempSingle();
return AllocTemp();
}
void ArmMir2Lir::CompilerInitializeRegAlloc() {
- int num_regs = sizeof(core_regs)/sizeof(*core_regs);
- int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
- int num_temps = sizeof(core_temps)/sizeof(*core_temps);
- int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
- int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
- reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
- kArenaAllocRegAlloc));
- reg_pool_->num_core_regs = num_regs;
- reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
- (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
- reg_pool_->num_fp_regs = num_fp_regs;
- reg_pool_->FPRegs = static_cast<RegisterInfo*>
- (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
- CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
- CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
+ reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
+ core_temps, sp_temps, dp_temps);
- // Keep special registers from being allocated
- // Don't reserve the r4 if we are doing implicit suspend checks.
+ // Target-specific adjustments.
+
+ // Alias single precision floats to appropriate half of overlapping double.
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ int sp_reg_num = info->GetReg().GetRegNum();
+ int dp_reg_num = sp_reg_num >> 1;
+ RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
+ RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
+ // Double precision register's master storage should refer to itself.
+ DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
+ // Redirect single precision's master storage to master.
+ info->SetMaster(dp_reg_info);
+ // Singles should show a single 32-bit mask bit, at first referring to the low half.
+ DCHECK_EQ(info->StorageMask(), 0x1U);
+ if (sp_reg_num & 1) {
+ // For odd singles, change to user the high word of the backing double.
+ info->SetStorageMask(0x2);
+ }
+ }
+
// TODO: re-enable this when we can safely save r4 over the suspension code path.
bool no_suspend = NO_SUSPEND; // || !Runtime::Current()->ExplicitSuspendChecks();
- for (int i = 0; i < num_reserved; i++) {
- if (no_suspend && (ReservedRegs[i] == rARM_SUSPEND)) {
- // Don't reserve the suspend register.
- continue;
- }
- MarkInUse(ReservedRegs[i]);
- }
- // Mark temp regs - all others not in use can be used for promotion
- for (int i = 0; i < num_temps; i++) {
- MarkTemp(core_temps[i]);
- }
- for (int i = 0; i < num_fp_temps; i++) {
- MarkTemp(fp_temps[i]);
+ if (no_suspend) {
+ GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
}
- // Start allocation at r2 in an attempt to avoid clobbering return values
- reg_pool_->next_core_reg = r2;
+ // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
+ // TODO: adjust when we roll to hard float calling convention.
+ reg_pool_->next_core_reg_ = 2;
+ reg_pool_->next_sp_reg_ = 0;
+ reg_pool_->next_dp_reg_ = 0;
}
void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
@@ -602,7 +613,7 @@
*/
void ArmMir2Lir::AdjustSpillMask() {
- core_spill_mask_ |= (1 << rARM_LR);
+ core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
num_core_spills_++;
}
@@ -612,123 +623,99 @@
* include any holes in the mask. Associate holes with
* Dalvik register INVALID_VREG (0xFFFFU).
*/
-void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
- DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
- reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
+void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
+ DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
+ int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
// Ensure fp_vmap_table is large enough
int table_size = fp_vmap_table_.size();
- for (int i = table_size; i < (reg + 1); i++) {
+ for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
fp_vmap_table_.push_back(INVALID_VREG);
}
// Add the current mapping
- fp_vmap_table_[reg] = v_reg;
+ fp_vmap_table_[adjusted_reg_num] = v_reg;
// Size of fp_vmap_table is high-water mark, use to set mask
num_fp_spills_ = fp_vmap_table_.size();
fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
}
-void ArmMir2Lir::FlushRegWide(RegStorage reg) {
- RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
- RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
- DCHECK(info1 && info2 && info1->pair && info2->pair &&
- (info1->partner == info2->reg) &&
- (info2->partner == info1->reg));
- if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
- if (!(info1->is_temp && info2->is_temp)) {
- /* Should not happen. If it does, there's a problem in eval_loc */
- LOG(FATAL) << "Long half-temp, half-promoted";
- }
-
- info1->dirty = false;
- info2->dirty = false;
- if (mir_graph_->SRegToVReg(info2->s_reg) <
- mir_graph_->SRegToVReg(info1->s_reg))
- info1 = info2;
- int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
- StoreBaseDispWide(rs_rARM_SP, VRegOffset(v_reg),
- RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
- }
-}
-
-void ArmMir2Lir::FlushReg(RegStorage reg) {
- DCHECK(!reg.IsPair());
- RegisterInfo* info = GetRegInfo(reg.GetReg());
- if (info->live && info->dirty) {
- info->dirty = false;
- int v_reg = mir_graph_->SRegToVReg(info->s_reg);
- StoreBaseDisp(rs_rARM_SP, VRegOffset(v_reg), reg, k32);
- }
-}
-
-/* Give access to the target-dependent FP register encoding to common code */
-bool ArmMir2Lir::IsFpReg(int reg) {
- return ARM_FPREG(reg);
-}
-
-bool ArmMir2Lir::IsFpReg(RegStorage reg) {
- return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
+void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
+ // TEMP: perform as 2 singles.
+ int reg_num = reg.GetRegNum() << 1;
+ RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
+ RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
+ MarkPreservedSingle(v_reg, lo);
+ MarkPreservedSingle(v_reg + 1, hi);
}
/* Clobber all regs that might be used by an external C call */
void ArmMir2Lir::ClobberCallerSave() {
- Clobber(r0);
- Clobber(r1);
- Clobber(r2);
- Clobber(r3);
- Clobber(r12);
- Clobber(r14lr);
- Clobber(fr0);
- Clobber(fr1);
- Clobber(fr2);
- Clobber(fr3);
- Clobber(fr4);
- Clobber(fr5);
- Clobber(fr6);
- Clobber(fr7);
- Clobber(fr8);
- Clobber(fr9);
- Clobber(fr10);
- Clobber(fr11);
- Clobber(fr12);
- Clobber(fr13);
- Clobber(fr14);
- Clobber(fr15);
+ // TODO: rework this - it's gotten even more ugly.
+ Clobber(rs_r0);
+ Clobber(rs_r1);
+ Clobber(rs_r2);
+ Clobber(rs_r3);
+ Clobber(rs_r12);
+ Clobber(rs_r14lr);
+ Clobber(rs_fr0);
+ Clobber(rs_fr1);
+ Clobber(rs_fr2);
+ Clobber(rs_fr3);
+ Clobber(rs_fr4);
+ Clobber(rs_fr5);
+ Clobber(rs_fr6);
+ Clobber(rs_fr7);
+ Clobber(rs_fr8);
+ Clobber(rs_fr9);
+ Clobber(rs_fr10);
+ Clobber(rs_fr11);
+ Clobber(rs_fr12);
+ Clobber(rs_fr13);
+ Clobber(rs_fr14);
+ Clobber(rs_fr15);
+ Clobber(rs_dr0);
+ Clobber(rs_dr1);
+ Clobber(rs_dr2);
+ Clobber(rs_dr3);
+ Clobber(rs_dr4);
+ Clobber(rs_dr5);
+ Clobber(rs_dr6);
+ Clobber(rs_dr7);
}
RegLocation ArmMir2Lir::GetReturnWideAlt() {
RegLocation res = LocCReturnWide();
- res.reg.SetReg(r2);
- res.reg.SetHighReg(r3);
- Clobber(r2);
- Clobber(r3);
- MarkInUse(r2);
- MarkInUse(r3);
- MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
+ res.reg.SetLowReg(rs_r2.GetReg());
+ res.reg.SetHighReg(rs_r3.GetReg());
+ Clobber(rs_r2);
+ Clobber(rs_r3);
+ MarkInUse(rs_r2);
+ MarkInUse(rs_r3);
+ MarkWide(res.reg);
return res;
}
RegLocation ArmMir2Lir::GetReturnAlt() {
RegLocation res = LocCReturn();
- res.reg.SetReg(r1);
- Clobber(r1);
- MarkInUse(r1);
+ res.reg.SetReg(rs_r1.GetReg());
+ Clobber(rs_r1);
+ MarkInUse(rs_r1);
return res;
}
/* To be used when explicitly managing register use */
void ArmMir2Lir::LockCallTemps() {
- LockTemp(r0);
- LockTemp(r1);
- LockTemp(r2);
- LockTemp(r3);
+ LockTemp(rs_r0);
+ LockTemp(rs_r1);
+ LockTemp(rs_r2);
+ LockTemp(rs_r3);
}
/* To be used when explicitly managing register use */
void ArmMir2Lir::FreeCallTemps() {
- FreeTemp(r0);
- FreeTemp(r1);
- FreeTemp(r2);
- FreeTemp(r3);
+ FreeTemp(rs_r0);
+ FreeTemp(rs_r1);
+ FreeTemp(rs_r2);
+ FreeTemp(rs_r3);
}
RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
@@ -758,4 +745,59 @@
return ArmMir2Lir::EncodingMap[opcode].fmt;
}
+/*
+ * Somewhat messy code here. We want to allocate a pair of contiguous
+ * physical single-precision floating point registers starting with
+ * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
+ * has already been allocated - try to fit if possible. Fail to
+ * allocate if we can't meet the requirements for the pair of
+ * s_reg<=sX[even] & (s_reg+1)<= sX+1.
+ */
+// TODO: needs rewrite to support non-backed 64-bit float regs.
+RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
+ RegStorage res;
+ int v_reg = mir_graph_->SRegToVReg(s_reg);
+ int p_map_idx = SRegToPMap(s_reg);
+ if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
+ // Upper reg is already allocated. Can we fit?
+ int high_reg = promotion_map_[p_map_idx+1].FpReg;
+ if ((high_reg & 1) == 0) {
+ // High reg is even - fail.
+ return res; // Invalid.
+ }
+ // Is the low reg of the pair free?
+ // FIXME: rework.
+ RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
+ if (p->InUse() || p->IsTemp()) {
+ // Already allocated or not preserved - fail.
+ return res; // Invalid.
+ }
+ // OK - good to go.
+ res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
+ p->MarkInUse();
+ MarkPreservedSingle(v_reg, p->GetReg());
+ } else {
+ /*
+ * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
+ * different underlying physical registers.
+ */
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->dp_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if (!info->IsTemp() && !info->InUse()) {
+ res = info->GetReg();
+ info->MarkInUse();
+ MarkPreservedDouble(v_reg, info->GetReg());
+ break;
+ }
+ }
+ }
+ if (res.Valid()) {
+ promotion_map_[p_map_idx].fp_location = kLocPhysReg;
+ promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg();
+ promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
+ promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg();
+ }
+ return res;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 2e64f74..08acef7 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -69,7 +69,7 @@
}
LIR* ArmMir2Lir::LoadFPConstantValue(int r_dest, int value) {
- DCHECK(ARM_SINGLEREG(r_dest));
+ DCHECK(RegStorage::IsSingle(r_dest));
if (value == 0) {
// TODO: we need better info about the target CPU. a vector exclusive or
// would probably be better here if we could rely on its existance.
@@ -88,7 +88,7 @@
data_target = AddWordData(&literal_list_, value);
}
LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kThumb2Vldrs,
- r_dest, r15pc, 0, 0, 0, data_target);
+ r_dest, rs_r15pc.GetReg(), 0, 0, 0, data_target);
SetMemRefType(load_pc_rel, true, kLiteral);
AppendLIR(load_pc_rel);
return load_pc_rel;
@@ -173,12 +173,12 @@
LIR* res;
int mod_imm;
- if (ARM_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
return LoadFPConstantValue(r_dest.GetReg(), value);
}
/* See if the value can be constructed cheaply */
- if (ARM_LOWREG(r_dest.GetReg()) && (value >= 0) && (value <= 255)) {
+ if (r_dest.Low8() && (value >= 0) && (value <= 255)) {
return NewLIR2(kThumbMovImm, r_dest.GetReg(), value);
}
/* Check Modified immediate special cases */
@@ -204,7 +204,7 @@
}
LIR* ArmMir2Lir::OpUnconditionalBranch(LIR* target) {
- LIR* res = NewLIR1(kThumbBUncond, 0 /* offset to be patched during assembly*/);
+ LIR* res = NewLIR1(kThumbBUncond, 0 /* offset to be patched during assembly */);
res->target = target;
return res;
}
@@ -237,7 +237,7 @@
LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2,
int shift) {
bool thumb_form =
- ((shift == 0) && ARM_LOWREG(r_dest_src1.GetReg()) && ARM_LOWREG(r_src2.GetReg()));
+ ((shift == 0) && r_dest_src1.Low8() && r_src2.Low8());
ArmOpcode opcode = kThumbBkpt;
switch (op) {
case kOpAdc:
@@ -256,9 +256,9 @@
case kOpCmp:
if (thumb_form)
opcode = kThumbCmpRR;
- else if ((shift == 0) && !ARM_LOWREG(r_dest_src1.GetReg()) && !ARM_LOWREG(r_src2.GetReg()))
+ else if ((shift == 0) && !r_dest_src1.Low8() && !r_src2.Low8())
opcode = kThumbCmpHH;
- else if ((shift == 0) && ARM_LOWREG(r_dest_src1.GetReg()))
+ else if ((shift == 0) && r_dest_src1.Low8())
opcode = kThumbCmpLH;
else if (shift == 0)
opcode = kThumbCmpHL;
@@ -270,11 +270,11 @@
break;
case kOpMov:
DCHECK_EQ(shift, 0);
- if (ARM_LOWREG(r_dest_src1.GetReg()) && ARM_LOWREG(r_src2.GetReg()))
+ if (r_dest_src1.Low8() && r_src2.Low8())
opcode = kThumbMovRR;
- else if (!ARM_LOWREG(r_dest_src1.GetReg()) && !ARM_LOWREG(r_src2.GetReg()))
+ else if (!r_dest_src1.Low8() && !r_src2.Low8())
opcode = kThumbMovRR_H2H;
- else if (ARM_LOWREG(r_dest_src1.GetReg()))
+ else if (r_dest_src1.Low8())
opcode = kThumbMovRR_H2L;
else
opcode = kThumbMovRR_L2H;
@@ -389,8 +389,7 @@
LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
RegStorage r_src2, int shift) {
ArmOpcode opcode = kThumbBkpt;
- bool thumb_form = (shift == 0) && ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src1.GetReg()) &&
- ARM_LOWREG(r_src2.GetReg());
+ bool thumb_form = (shift == 0) && r_dest.Low8() && r_src1.Low8() && r_src2.Low8();
switch (op) {
case kOpAdd:
opcode = (thumb_form) ? kThumbAddRRR : kThumb2AddRRR;
@@ -466,7 +465,7 @@
int32_t abs_value = (neg) ? -value : value;
ArmOpcode opcode = kThumbBkpt;
ArmOpcode alt_opcode = kThumbBkpt;
- bool all_low_regs = (ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src1.GetReg()));
+ bool all_low_regs = r_dest.Low8() && r_src1.Low8();
int32_t mod_imm = ModifiedImmediate(value);
switch (op) {
@@ -488,10 +487,9 @@
case kOpRor:
return NewLIR3(kThumb2RorRRI5, r_dest.GetReg(), r_src1.GetReg(), value);
case kOpAdd:
- if (ARM_LOWREG(r_dest.GetReg()) && (r_src1 == rs_r13sp) &&
- (value <= 1020) && ((value & 0x3) == 0)) {
+ if (r_dest.Low8() && (r_src1 == rs_r13sp) && (value <= 1020) && ((value & 0x3) == 0)) {
return NewLIR3(kThumbAddSpRel, r_dest.GetReg(), r_src1.GetReg(), value >> 2);
- } else if (ARM_LOWREG(r_dest.GetReg()) && (r_src1 == rs_r15pc) &&
+ } else if (r_dest.Low8() && (r_src1 == rs_r15pc) &&
(value <= 1020) && ((value & 0x3) == 0)) {
return NewLIR3(kThumbAddPcRel, r_dest.GetReg(), r_src1.GetReg(), value >> 2);
}
@@ -601,7 +599,7 @@
LIR* ArmMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
bool neg = (value < 0);
int32_t abs_value = (neg) ? -value : value;
- bool short_form = (((abs_value & 0xff) == abs_value) && ARM_LOWREG(r_dest_src1.GetReg()));
+ bool short_form = (((abs_value & 0xff) == abs_value) && r_dest_src1.Low8());
ArmOpcode opcode = kThumbBkpt;
switch (op) {
case kOpAdd:
@@ -643,22 +641,24 @@
LIR* res = NULL;
int32_t val_lo = Low32Bits(value);
int32_t val_hi = High32Bits(value);
- int target_reg = S2d(r_dest.GetLowReg(), r_dest.GetHighReg());
- if (ARM_FPREG(r_dest.GetLowReg())) {
+ if (r_dest.IsFloat()) {
+ DCHECK(!r_dest.IsPair());
if ((val_lo == 0) && (val_hi == 0)) {
// TODO: we need better info about the target CPU. a vector exclusive or
// would probably be better here if we could rely on its existance.
// Load an immediate +2.0 (which encodes to 0)
- NewLIR2(kThumb2Vmovd_IMM8, target_reg, 0);
+ NewLIR2(kThumb2Vmovd_IMM8, r_dest.GetReg(), 0);
// +0.0 = +2.0 - +2.0
- res = NewLIR3(kThumb2Vsubd, target_reg, target_reg, target_reg);
+ res = NewLIR3(kThumb2Vsubd, r_dest.GetReg(), r_dest.GetReg(), r_dest.GetReg());
} else {
int encoded_imm = EncodeImmDouble(value);
if (encoded_imm >= 0) {
- res = NewLIR2(kThumb2Vmovd_IMM8, target_reg, encoded_imm);
+ res = NewLIR2(kThumb2Vmovd_IMM8, r_dest.GetReg(), encoded_imm);
}
}
} else {
+ // NOTE: Arm32 assumption here.
+ DCHECK(r_dest.IsPair());
if ((InexpensiveConstantInt(val_lo) && (InexpensiveConstantInt(val_hi)))) {
res = LoadConstantNoClobber(r_dest.GetLow(), val_lo);
LoadConstantNoClobber(r_dest.GetHigh(), val_hi);
@@ -670,13 +670,13 @@
if (data_target == NULL) {
data_target = AddWideData(&literal_list_, val_lo, val_hi);
}
- if (ARM_FPREG(r_dest.GetLowReg())) {
+ if (r_dest.IsFloat()) {
res = RawLIR(current_dalvik_offset_, kThumb2Vldrd,
- target_reg, r15pc, 0, 0, 0, data_target);
+ r_dest.GetReg(), rs_r15pc.GetReg(), 0, 0, 0, data_target);
} else {
DCHECK(r_dest.IsPair());
res = RawLIR(current_dalvik_offset_, kThumb2LdrdPcRel8,
- r_dest.GetLowReg(), r_dest.GetHighReg(), r15pc, 0, 0, data_target);
+ r_dest.GetLowReg(), r_dest.GetHighReg(), rs_r15pc.GetReg(), 0, 0, data_target);
}
SetMemRefType(res, true, kLiteral);
AppendLIR(res);
@@ -690,22 +690,20 @@
LIR* ArmMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
int scale, OpSize size) {
- bool all_low_regs = ARM_LOWREG(r_base.GetReg()) && ARM_LOWREG(r_index.GetReg()) &&
- ARM_LOWREG(r_dest.GetReg());
+ bool all_low_regs = r_base.Low8() && r_index.Low8() && r_dest.Low8();
LIR* load;
ArmOpcode opcode = kThumbBkpt;
bool thumb_form = (all_low_regs && (scale == 0));
RegStorage reg_ptr;
- if (ARM_FPREG(r_dest.GetReg())) {
- if (ARM_SINGLEREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
+ if (r_dest.IsSingle()) {
DCHECK((size == k32) || (size == kSingle) || (size == kReference));
opcode = kThumb2Vldrs;
size = kSingle;
} else {
- DCHECK(ARM_DOUBLEREG(r_dest.GetReg()));
+ DCHECK(r_dest.IsDouble());
DCHECK((size == k64) || (size == kDouble));
- DCHECK_EQ((r_dest.GetReg() & 0x1), 0);
opcode = kThumb2Vldrd;
size = kDouble;
}
@@ -758,20 +756,19 @@
LIR* ArmMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
int scale, OpSize size) {
- bool all_low_regs = ARM_LOWREG(r_base.GetReg()) && ARM_LOWREG(r_index.GetReg()) &&
- ARM_LOWREG(r_src.GetReg());
+ bool all_low_regs = r_base.Low8() && r_index.Low8() && r_src.Low8();
LIR* store = NULL;
ArmOpcode opcode = kThumbBkpt;
bool thumb_form = (all_low_regs && (scale == 0));
RegStorage reg_ptr;
- if (ARM_FPREG(r_src.GetReg())) {
- if (ARM_SINGLEREG(r_src.GetReg())) {
+ if (r_src.IsFloat()) {
+ if (r_src.IsSingle()) {
DCHECK((size == k32) || (size == kSingle) || (size == kReference));
opcode = kThumb2Vstrs;
size = kSingle;
} else {
- DCHECK(ARM_DOUBLEREG(r_src.GetReg()));
+ DCHECK(r_src.IsDouble());
DCHECK((size == k64) || (size == kDouble));
DCHECK_EQ((r_src.GetReg() & 0x1), 0);
opcode = kThumb2Vstrd;
@@ -833,21 +830,16 @@
ArmOpcode opcode = kThumbBkpt;
bool short_form = false;
bool thumb2Form = (displacement < 4092 && displacement >= 0);
- bool all_low = r_dest.Is32Bit() && ARM_LOWREG(r_base.GetReg() && ARM_LOWREG(r_dest.GetReg()));
+ bool all_low = r_dest.Is32Bit() && r_base.Low8() && r_dest.Low8();
int encoded_disp = displacement;
bool already_generated = false;
- int dest_low_reg = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
bool null_pointer_safepoint = false;
switch (size) {
case kDouble:
// Intentional fall-though.
case k64:
- if (ARM_FPREG(dest_low_reg)) {
- // Note: following change to avoid using pairs for doubles, replace conversion w/ DCHECK.
- if (r_dest.IsPair()) {
- DCHECK(ARM_FPREG(r_dest.GetHighReg()));
- r_dest = RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg()));
- }
+ if (r_dest.IsFloat()) {
+ DCHECK(!r_dest.IsPair());
opcode = kThumb2Vldrd;
if (displacement <= 1020) {
short_form = true;
@@ -870,7 +862,7 @@
case k32:
// Intentional fall-though.
case kReference:
- if (ARM_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
opcode = kThumb2Vldrs;
if (displacement <= 1020) {
short_form = true;
@@ -878,13 +870,13 @@
}
break;
}
- if (ARM_LOWREG(r_dest.GetReg()) && (r_base.GetReg() == r15pc) &&
- (displacement <= 1020) && (displacement >= 0)) {
+ if (r_dest.Low8() && (r_base == rs_rARM_PC) && (displacement <= 1020) &&
+ (displacement >= 0)) {
short_form = true;
encoded_disp >>= 2;
opcode = kThumbLdrPcRel;
- } else if (ARM_LOWREG(r_dest.GetReg()) && (r_base.GetReg() == r13sp) &&
- (displacement <= 1020) && (displacement >= 0)) {
+ } else if (r_dest.Low8() && (r_base == rs_rARM_SP) && (displacement <= 1020) &&
+ (displacement >= 0)) {
short_form = true;
encoded_disp >>= 2;
opcode = kThumbLdrSpRel;
@@ -940,7 +932,7 @@
} else {
RegStorage reg_offset = AllocTemp();
LoadConstant(reg_offset, encoded_disp);
- if (ARM_FPREG(dest_low_reg)) {
+ if (r_dest.IsFloat()) {
// No index ops - must use a long sequence. Turn the offset into a direct pointer.
OpRegReg(kOpAdd, reg_offset, r_base);
load = LoadBaseDispBody(reg_offset, 0, r_dest, size, s_reg);
@@ -985,15 +977,14 @@
ArmOpcode opcode = kThumbBkpt;
bool short_form = false;
bool thumb2Form = (displacement < 4092 && displacement >= 0);
- bool all_low = r_src.Is32Bit() && (ARM_LOWREG(r_base.GetReg()) && ARM_LOWREG(r_src.GetReg()));
+ bool all_low = r_src.Is32Bit() && r_base.Low8() && r_src.Low8();
int encoded_disp = displacement;
bool already_generated = false;
- int src_low_reg = r_src.IsPair() ? r_src.GetLowReg() : r_src.GetReg();
bool null_pointer_safepoint = false;
switch (size) {
case k64:
case kDouble:
- if (!ARM_FPREG(src_low_reg)) {
+ if (!r_src.IsFloat()) {
if (displacement <= 1020) {
store = NewLIR4(kThumb2StrdI8, r_src.GetLowReg(), r_src.GetHighReg(), r_base.GetReg(),
displacement >> 2);
@@ -1004,11 +995,7 @@
}
already_generated = true;
} else {
- // Note: following change to avoid using pairs for doubles, replace conversion w/ DCHECK.
- if (r_src.IsPair()) {
- DCHECK(ARM_FPREG(r_src.GetHighReg()));
- r_src = RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg()));
- }
+ DCHECK(!r_src.IsPair());
opcode = kThumb2Vstrd;
if (displacement <= 1020) {
short_form = true;
@@ -1017,10 +1004,12 @@
}
break;
case kSingle:
+ // Intentional fall-through.
case k32:
+ // Intentional fall-through.
case kReference:
- if (ARM_FPREG(r_src.GetReg())) {
- DCHECK(ARM_SINGLEREG(r_src.GetReg()));
+ if (r_src.IsFloat()) {
+ DCHECK(r_src.IsSingle());
opcode = kThumb2Vstrs;
if (displacement <= 1020) {
short_form = true;
@@ -1028,8 +1017,7 @@
}
break;
}
- if (ARM_LOWREG(r_src.GetReg()) && (r_base == rs_r13sp) &&
- (displacement <= 1020) && (displacement >= 0)) {
+ if (r_src.Low8() && (r_base == rs_r13sp) && (displacement <= 1020) && (displacement >= 0)) {
short_form = true;
encoded_disp >>= 2;
opcode = kThumbStrSpRel;
@@ -1074,7 +1062,7 @@
} else {
RegStorage r_scratch = AllocTemp();
LoadConstant(r_scratch, encoded_disp);
- if (ARM_FPREG(src_low_reg)) {
+ if (r_src.IsFloat()) {
// No index ops - must use a long sequence. Turn the offset into a direct pointer.
OpRegReg(kOpAdd, r_scratch, r_base);
store = StoreBaseDispBody(r_scratch, 0, r_src, size);
@@ -1113,14 +1101,14 @@
LIR* ArmMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
int opcode;
- DCHECK_EQ(ARM_DOUBLEREG(r_dest.GetReg()), ARM_DOUBLEREG(r_src.GetReg()));
- if (ARM_DOUBLEREG(r_dest.GetReg())) {
+ DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
+ if (r_dest.IsDouble()) {
opcode = kThumb2Vmovd;
} else {
- if (ARM_SINGLEREG(r_dest.GetReg())) {
- opcode = ARM_SINGLEREG(r_src.GetReg()) ? kThumb2Vmovs : kThumb2Fmsr;
+ if (r_dest.IsSingle()) {
+ opcode = r_src.IsSingle() ? kThumb2Vmovs : kThumb2Fmsr;
} else {
- DCHECK(ARM_SINGLEREG(r_src.GetReg()));
+ DCHECK(r_src.IsSingle());
opcode = kThumb2Fmrs;
}
}
@@ -1142,8 +1130,7 @@
}
LIR* ArmMir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_src, RegStorage r_src_hi,
- OpSize size, int s_reg) {
+ int displacement, RegStorage r_src, OpSize size, int s_reg) {
LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for Arm";
return NULL;
}
@@ -1154,8 +1141,7 @@
}
LIR* ArmMir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_dest, RegStorage r_dest_hi,
- OpSize size, int s_reg) {
+ int displacement, RegStorage r_dest, OpSize size, int s_reg) {
LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for Arm";
return NULL;
}
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 0596d4f..9f84e09 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -254,7 +254,7 @@
PromotionMap v_reg_map = promotion_map_[i];
std::string buf;
if (v_reg_map.fp_location == kLocPhysReg) {
- StringAppendF(&buf, " : s%d", v_reg_map.FpReg & FpRegMask());
+ StringAppendF(&buf, " : s%d", RegStorage::RegNum(v_reg_map.FpReg));
}
std::string buf3;
@@ -942,7 +942,7 @@
switch_tables_(arena, 4, kGrowableArraySwitchTables),
fill_array_data_(arena, 4, kGrowableArrayFillArrayData),
tempreg_info_(arena, 20, kGrowableArrayMisc),
- reginfo_map_(arena, 64, kGrowableArrayMisc),
+ reginfo_map_(arena, RegStorage::kMaxRegs, kGrowableArrayMisc),
pointer_storage_(arena, 128, kGrowableArrayMisc),
data_offset_(0),
total_size_(0),
@@ -1050,10 +1050,11 @@
int Mir2Lir::ComputeFrameSize() {
/* Figure out the frame size */
static const uint32_t kAlignMask = kStackAlignment - 1;
- uint32_t size = ((num_core_spills_ + num_fp_spills_ +
- 1 /* filler word */ + cu_->num_regs + cu_->num_outs)
- * sizeof(uint32_t)) +
- GetNumBytesForCompilerTempSpillRegion();
+ uint32_t size = num_core_spills_ * GetBytesPerGprSpillLocation(cu_->instruction_set)
+ + num_fp_spills_ * GetBytesPerFprSpillLocation(cu_->instruction_set)
+ + sizeof(uint32_t) // Filler.
+ + (cu_->num_regs + cu_->num_outs) * sizeof(uint32_t)
+ + GetNumBytesForCompilerTempSpillRegion();
/* Align and set */
return (size + kAlignMask) & ~(kAlignMask);
}
@@ -1185,8 +1186,19 @@
RegLocation Mir2Lir::NarrowRegLoc(RegLocation loc) {
loc.wide = false;
- if (loc.reg.IsPair()) {
- loc.reg = loc.reg.GetLow();
+ if (loc.location == kLocPhysReg) {
+ if (loc.reg.IsPair()) {
+ loc.reg = loc.reg.GetLow();
+ } else {
+ // FIXME: temp workaround.
+ // Issue here: how do we narrow to a 32-bit value in 64-bit container?
+ // Probably the wrong thing to narrow the RegStorage container here. That
+ // should be a target decision. At the RegLocation level, we're only
+ // modifying the view of the Dalvik value - this is orthogonal to the storage
+ // container size. Consider this a temp workaround.
+ DCHECK(loc.reg.IsDouble());
+ loc.reg = loc.reg.DoubleToLowSingle();
+ }
}
return loc;
}
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 8b9a686..2cd17cc 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -330,9 +330,10 @@
bool is_type_initialized; // Ignored as an array does not have an initializer.
bool use_direct_type_ptr;
uintptr_t direct_type_ptr;
+ bool is_finalizable;
if (kEmbedClassInCode &&
- driver->CanEmbedTypeInCode(*dex_file, type_idx,
- &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr,
+ &direct_type_ptr, &is_finalizable)) {
// The fast path.
if (!use_direct_type_ptr) {
LoadClassType(type_idx, kArg0);
@@ -700,7 +701,7 @@
cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet());
if (field_info.FastGet() && !SLOW_FIELD_PATH) {
RegLocation rl_result;
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
rl_obj = LoadValue(rl_obj, kCoreReg);
if (is_long_or_double) {
@@ -773,7 +774,7 @@
const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut());
if (field_info.FastPut() && !SLOW_FIELD_PATH) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
rl_obj = LoadValue(rl_obj, kCoreReg);
if (is_long_or_double) {
@@ -980,9 +981,11 @@
bool is_type_initialized;
bool use_direct_type_ptr;
uintptr_t direct_type_ptr;
+ bool is_finalizable;
if (kEmbedClassInCode &&
- driver->CanEmbedTypeInCode(*dex_file, type_idx,
- &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr,
+ &direct_type_ptr, &is_finalizable) &&
+ !is_finalizable) {
// The fast path.
if (!use_direct_type_ptr) {
LoadClassType(type_idx, kArg0);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 93a23a6..9c1fbe4 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -22,12 +22,16 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "invoke_type.h"
#include "mirror/array.h"
+#include "mirror/object_array-inl.h"
#include "mirror/string.h"
#include "mir_to_lir-inl.h"
#include "x86/codegen_x86.h"
namespace art {
+// Shortcuts to repeatedly used long types.
+typedef mirror::ObjectArray<mirror::Object> ObjArray;
+
/*
* This source files contains "gen" codegen routines that should
* be applicable to most targets. Only mid-level support utilities
@@ -358,7 +362,7 @@
rl_src.location = kLocPhysReg;
rl_src.reg = TargetReg(kArg0);
rl_src.home = false;
- MarkLive(rl_src.reg, rl_src.s_reg_low);
+ MarkLive(rl_src);
if (rl_method.wide) {
StoreValueWide(rl_method, rl_src);
} else {
@@ -494,8 +498,8 @@
case 2: // Grab target method*
CHECK_EQ(cu->dex_file, target_method.dex_file);
cg->LoadRefDisp(cg->TargetReg(kArg0),
- mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
- (target_method.dex_method_index * 4), cg->TargetReg(kArg0));
+ ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(),
+ cg->TargetReg(kArg0));
break;
case 3: // Grab the code from the method*
if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
@@ -548,8 +552,8 @@
cg->TargetReg(kInvokeTgt));
break;
case 3: // Get target method [use kInvokeTgt, set kArg0]
- cg->LoadRefDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
- mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
+ cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
+ ObjArray::OffsetOfElement(method_idx).Int32Value(),
cg->TargetReg(kArg0));
break;
case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
@@ -605,8 +609,8 @@
break;
case 4: // Get target method [use kInvokeTgt, set kArg0]
// NOTE: native pointer.
- cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), ((method_idx % ClassLinker::kImtSize) * 4) +
- mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
+ cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
+ ObjArray::OffsetOfElement(method_idx % ClassLinker::kImtSize).Int32Value(),
cg->TargetReg(kArg0));
break;
case 5: // Get the compiled code address [use kArg0, set kInvokeTgt]
@@ -753,7 +757,8 @@
// Wide spans, we need the 2nd half of uses[2].
rl_arg = UpdateLocWide(rl_use2);
if (rl_arg.location == kLocPhysReg) {
- reg = rl_arg.reg.GetHigh();
+ // NOTE: not correct for 64-bit core regs, but this needs rewriting for hard-float.
+ reg = rl_arg.reg.IsPair() ? rl_arg.reg.GetHigh() : rl_arg.reg.DoubleToHighSingle();
} else {
// kArg2 & rArg3 can safely be used here
reg = TargetReg(kArg3);
@@ -768,34 +773,28 @@
}
// Loop through the rest
while (next_use < info->num_arg_words) {
- RegStorage low_reg;
- RegStorage high_reg;
+ RegStorage arg_reg;
rl_arg = info->args[next_use];
rl_arg = UpdateRawLoc(rl_arg);
if (rl_arg.location == kLocPhysReg) {
- if (rl_arg.wide) {
- low_reg = rl_arg.reg.GetLow();
- high_reg = rl_arg.reg.GetHigh();
- } else {
- low_reg = rl_arg.reg;
- }
+ arg_reg = rl_arg.reg;
} else {
- low_reg = TargetReg(kArg2);
+ arg_reg = rl_arg.wide ? RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)) :
+ TargetReg(kArg2);
if (rl_arg.wide) {
- high_reg = TargetReg(kArg3);
- LoadValueDirectWideFixed(rl_arg, RegStorage::MakeRegPair(low_reg, high_reg));
+ LoadValueDirectWideFixed(rl_arg, arg_reg);
} else {
- LoadValueDirectFixed(rl_arg, low_reg);
+ LoadValueDirectFixed(rl_arg, arg_reg);
}
call_state = next_call_insn(cu_, info, call_state, target_method,
vtable_idx, direct_code, direct_method, type);
}
int outs_offset = (next_use + 1) * 4;
if (rl_arg.wide) {
- StoreBaseDispWide(TargetReg(kSp), outs_offset, RegStorage::MakeRegPair(low_reg, high_reg));
+ StoreBaseDispWide(TargetReg(kSp), outs_offset, arg_reg);
next_use += 2;
} else {
- Store32Disp(TargetReg(kSp), outs_offset, low_reg);
+ Store32Disp(TargetReg(kSp), outs_offset, arg_reg);
next_use++;
}
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
@@ -926,7 +925,7 @@
// Allocate a free xmm temp. Since we are working through the calling sequence,
// we expect to have an xmm temporary available.
RegStorage temp = AllocTempDouble();
- CHECK_GT(temp.GetLowReg(), 0);
+ DCHECK(temp.Valid());
LIR* ld1 = nullptr;
LIR* ld2 = nullptr;
@@ -989,9 +988,7 @@
}
// Free the temporary used for the data movement.
- // CLEANUP: temp is currently a bogus pair, elmiminate extra free when updated.
- FreeTemp(temp.GetLow());
- FreeTemp(temp.GetHigh());
+ FreeTemp(temp);
} else {
// Moving 32-bits via general purpose register.
bytes_to_move = sizeof(uint32_t);
@@ -1136,8 +1133,8 @@
if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
LoadBaseIndexed(reg_ptr, reg_off, rl_result.reg, 1, kUnsignedHalf);
} else {
- LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.reg,
- RegStorage::InvalidReg(), kUnsignedHalf, INVALID_SREG);
+ LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.reg, kUnsignedHalf,
+ INVALID_SREG);
}
FreeTemp(reg_off);
FreeTemp(reg_ptr);
@@ -1409,7 +1406,7 @@
Load32Disp(TargetReg(kSelf), offset.Int32Value(), rl_result.reg);
} else {
CHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
- reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg.GetReg(), offset);
+ reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg, offset);
}
StoreValue(rl_dest, rl_result);
return true;
@@ -1432,13 +1429,12 @@
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (is_long) {
if (cu_->instruction_set == kX86) {
- LoadBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_result.reg.GetLow(),
- rl_result.reg.GetHigh(), k64, INVALID_SREG);
+ LoadBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_result.reg, k64, INVALID_SREG);
} else {
RegStorage rl_temp_offset = AllocTemp();
OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
LoadBaseDispWide(rl_temp_offset, 0, rl_result.reg, INVALID_SREG);
- FreeTemp(rl_temp_offset.GetReg());
+ FreeTemp(rl_temp_offset);
}
} else {
LoadBaseIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0, k32);
@@ -1480,13 +1476,12 @@
if (is_long) {
rl_value = LoadValueWide(rl_src_value, kCoreReg);
if (cu_->instruction_set == kX86) {
- StoreBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_value.reg.GetLow(),
- rl_value.reg.GetHigh(), k64, INVALID_SREG);
+ StoreBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_value.reg, k64, INVALID_SREG);
} else {
RegStorage rl_temp_offset = AllocTemp();
OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
StoreBaseDispWide(rl_temp_offset, 0, rl_value.reg);
- FreeTemp(rl_temp_offset.GetReg());
+ FreeTemp(rl_temp_offset);
}
} else {
rl_value = LoadValue(rl_src_value, kCoreReg);
@@ -1494,7 +1489,7 @@
}
// Free up the temp early, to ensure x86 doesn't run out of temporaries in MarkGCCard.
- FreeTemp(rl_offset.reg.GetReg());
+ FreeTemp(rl_offset.reg);
if (is_volatile) {
// A load might follow the volatile store so insert a StoreLoad barrier.
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index 9808f7f..e6911cd 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -143,7 +143,7 @@
if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
LoadValueDirect(rl_src, rl_src.reg);
rl_src.location = kLocPhysReg;
- MarkLive(rl_src.reg, rl_src.s_reg_low);
+ MarkLive(rl_src);
}
return rl_src;
}
@@ -184,12 +184,12 @@
}
// Dest is now live and dirty (until/if we flush it to home location)
- MarkLive(rl_dest.reg, rl_dest.s_reg_low);
+ MarkLive(rl_dest);
MarkDirty(rl_dest);
ResetDefLoc(rl_dest);
- if (IsDirty(rl_dest.reg) && oat_live_out(rl_dest.s_reg_low)) {
+ if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) {
def_start = last_lir_insn_;
Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
MarkClean(rl_dest);
@@ -207,13 +207,7 @@
if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
LoadValueDirectWide(rl_src, rl_src.reg);
rl_src.location = kLocPhysReg;
- MarkLive(rl_src.reg.GetLow(), rl_src.s_reg_low);
- if (rl_src.reg.GetLowReg() != rl_src.reg.GetHighReg()) {
- MarkLive(rl_src.reg.GetHigh(), GetSRegHi(rl_src.s_reg_low));
- } else {
- // This must be an x86 vector register value.
- DCHECK(IsFpReg(rl_src.reg) && (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64));
- }
+ MarkLive(rl_src);
}
return rl_src;
}
@@ -254,24 +248,13 @@
}
// Dest is now live and dirty (until/if we flush it to home location)
- MarkLive(rl_dest.reg.GetLow(), rl_dest.s_reg_low);
-
- // Does this wide value live in two registers (or one vector one)?
- // FIXME: wide reg update.
- if (rl_dest.reg.GetLowReg() != rl_dest.reg.GetHighReg()) {
- MarkLive(rl_dest.reg.GetHigh(), GetSRegHi(rl_dest.s_reg_low));
- MarkDirty(rl_dest);
- MarkPair(rl_dest.reg.GetLowReg(), rl_dest.reg.GetHighReg());
- } else {
- // This must be an x86 vector register value,
- DCHECK(IsFpReg(rl_dest.reg) && (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64));
- MarkDirty(rl_dest);
- }
-
+ MarkLive(rl_dest);
+ MarkWide(rl_dest.reg);
+ MarkDirty(rl_dest);
ResetDefLocWide(rl_dest);
- if (IsDirty(rl_dest.reg) && (oat_live_out(rl_dest.s_reg_low) ||
- oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
+ if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) ||
+ LiveOut(GetSRegHi(rl_dest.s_reg_low)))) {
def_start = last_lir_insn_;
DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
@@ -295,13 +278,12 @@
}
// Dest is now live and dirty (until/if we flush it to home location)
- MarkLive(rl_dest.reg, rl_dest.s_reg_low);
+ MarkLive(rl_dest);
MarkDirty(rl_dest);
ResetDefLoc(rl_dest);
- if (IsDirty(rl_dest.reg) &&
- oat_live_out(rl_dest.s_reg_low)) {
+ if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) {
LIR *def_start = last_lir_insn_;
Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
MarkClean(rl_dest);
@@ -314,7 +296,6 @@
}
void Mir2Lir::StoreFinalValueWide(RegLocation rl_dest, RegLocation rl_src) {
- DCHECK_EQ(IsFpReg(rl_src.reg.GetLowReg()), IsFpReg(rl_src.reg.GetHighReg()));
DCHECK(rl_dest.wide);
DCHECK(rl_src.wide);
DCHECK_EQ(rl_src.location, kLocPhysReg);
@@ -325,28 +306,17 @@
// Just re-assign the registers. Dest gets Src's regs.
rl_dest.location = kLocPhysReg;
rl_dest.reg = rl_src.reg;
- Clobber(rl_src.reg.GetLowReg());
- Clobber(rl_src.reg.GetHighReg());
+ Clobber(rl_src.reg);
}
// Dest is now live and dirty (until/if we flush it to home location).
- MarkLive(rl_dest.reg.GetLow(), rl_dest.s_reg_low);
-
- // Does this wide value live in two registers (or one vector one)?
- // FIXME: wide reg.
- if (rl_dest.reg.GetLowReg() != rl_dest.reg.GetHighReg()) {
- MarkLive(rl_dest.reg.GetHigh(), GetSRegHi(rl_dest.s_reg_low));
- MarkDirty(rl_dest);
- MarkPair(rl_dest.reg.GetLowReg(), rl_dest.reg.GetHighReg());
- } else {
- // This must be an x86 vector register value,
- DCHECK(IsFpReg(rl_dest.reg) && (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64));
- MarkDirty(rl_dest);
- }
+ MarkLive(rl_dest);
+ MarkWide(rl_dest.reg);
+ MarkDirty(rl_dest);
ResetDefLocWide(rl_dest);
- if (IsDirty(rl_dest.reg) && (oat_live_out(rl_dest.s_reg_low) ||
- oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
+ if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) ||
+ LiveOut(GetSRegHi(rl_dest.s_reg_low)))) {
LIR *def_start = last_lir_insn_;
DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
@@ -369,7 +339,7 @@
RegLocation Mir2Lir::ForceTemp(RegLocation loc) {
DCHECK(!loc.wide);
DCHECK(loc.location == kLocPhysReg);
- DCHECK(!IsFpReg(loc.reg));
+ DCHECK(!loc.reg.IsFloat());
if (IsTemp(loc.reg)) {
Clobber(loc.reg);
} else {
@@ -383,21 +353,20 @@
return loc;
}
-// FIXME: wide regs.
+// FIXME: will need an update for 64-bit core regs.
RegLocation Mir2Lir::ForceTempWide(RegLocation loc) {
DCHECK(loc.wide);
DCHECK(loc.location == kLocPhysReg);
- DCHECK(!IsFpReg(loc.reg.GetLowReg()));
- DCHECK(!IsFpReg(loc.reg.GetHighReg()));
- if (IsTemp(loc.reg.GetLowReg())) {
- Clobber(loc.reg.GetLowReg());
+ DCHECK(!loc.reg.IsFloat());
+ if (IsTemp(loc.reg.GetLow())) {
+ Clobber(loc.reg.GetLow());
} else {
RegStorage temp_low = AllocTemp();
OpRegCopy(temp_low, loc.reg.GetLow());
loc.reg.SetLowReg(temp_low.GetReg());
}
- if (IsTemp(loc.reg.GetHighReg())) {
- Clobber(loc.reg.GetHighReg());
+ if (IsTemp(loc.reg.GetHigh())) {
+ Clobber(loc.reg.GetHigh());
} else {
RegStorage temp_high = AllocTemp();
OpRegCopy(temp_high, loc.reg.GetHigh());
diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc
index 4bdc9fa..4a918a1 100644
--- a/compiler/dex/quick/local_optimizations.cc
+++ b/compiler/dex/quick/local_optimizations.cc
@@ -163,7 +163,7 @@
DCHECK(!(check_flags & IS_STORE));
/* Same value && same register type */
if (check_lir->flags.alias_info == this_lir->flags.alias_info &&
- SameRegType(check_lir->operands[0], native_reg_id)) {
+ RegStorage::SameRegType(check_lir->operands[0], native_reg_id)) {
/*
* Different destination register - insert
* a move
@@ -179,7 +179,7 @@
/* Must alias */
if (check_lir->flags.alias_info == this_lir->flags.alias_info) {
/* Only optimize compatible registers */
- bool reg_compatible = SameRegType(check_lir->operands[0], native_reg_id);
+ bool reg_compatible = RegStorage::SameRegType(check_lir->operands[0], native_reg_id);
if ((is_this_lir_load && is_check_lir_load) ||
(!is_this_lir_load && is_check_lir_load)) {
/* RAR or RAW */
diff --git a/compiler/dex/quick/mips/README.mips b/compiler/dex/quick/mips/README.mips
index 061c157..ff561fa 100644
--- a/compiler/dex/quick/mips/README.mips
+++ b/compiler/dex/quick/mips/README.mips
@@ -17,7 +17,7 @@
code generation for switch tables, fill array data, 64-bit
data handling and the register usage conventions.
- o The memory model. Verify that oatGenMemoryBarrier() generates the
+ o The memory model. Verify that GenMemoryBarrier() generates the
appropriate flavor of sync.
Register promotion
diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc
index a579254..baae319 100644
--- a/compiler/dex/quick/mips/assemble_mips.cc
+++ b/compiler/dex/quick/mips/assemble_mips.cc
@@ -672,16 +672,17 @@
bits |= (value << encoder->field_loc[i].end);
break;
case kFmtDfp: {
- DCHECK(MIPS_DOUBLEREG(operand));
+ // TODO: do we need to adjust now that we're using 64BitSolo?
+ DCHECK(RegStorage::IsDouble(operand)) << ", Operand = 0x" << std::hex << operand;
DCHECK_EQ((operand & 0x1), 0U);
- value = ((operand & MIPS_FP_REG_MASK) << encoder->field_loc[i].start) &
+ value = (RegStorage::RegNum(operand) << encoder->field_loc[i].start) &
((1 << (encoder->field_loc[i].end + 1)) - 1);
bits |= value;
break;
}
case kFmtSfp:
- DCHECK(MIPS_SINGLEREG(operand));
- value = ((operand & MIPS_FP_REG_MASK) << encoder->field_loc[i].start) &
+ DCHECK(RegStorage::IsSingle(operand)) << ", Operand = 0x" << std::hex << operand;
+ value = (RegStorage::RegNum(operand) << encoder->field_loc[i].start) &
((1 << (encoder->field_loc[i].end + 1)) - 1);
bits |= value;
break;
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index df13882..3af3715 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -295,10 +295,10 @@
* expanding the frame or flushing. This leaves the utility
* code with a single temp: r12. This should be enough.
*/
- LockTemp(rMIPS_ARG0);
- LockTemp(rMIPS_ARG1);
- LockTemp(rMIPS_ARG2);
- LockTemp(rMIPS_ARG3);
+ LockTemp(rs_rMIPS_ARG0);
+ LockTemp(rs_rMIPS_ARG1);
+ LockTemp(rs_rMIPS_ARG2);
+ LockTemp(rs_rMIPS_ARG3);
/*
* We can safely skip the stack overflow check if we're
@@ -351,10 +351,10 @@
FlushIns(ArgLocs, rl_method);
- FreeTemp(rMIPS_ARG0);
- FreeTemp(rMIPS_ARG1);
- FreeTemp(rMIPS_ARG2);
- FreeTemp(rMIPS_ARG3);
+ FreeTemp(rs_rMIPS_ARG0);
+ FreeTemp(rs_rMIPS_ARG1);
+ FreeTemp(rs_rMIPS_ARG2);
+ FreeTemp(rs_rMIPS_ARG3);
}
void MipsMir2Lir::GenExitSequence() {
@@ -362,8 +362,8 @@
* In the exit path, rMIPS_RET0/rMIPS_RET1 are live - make sure they aren't
* allocated by the register utilities as temps.
*/
- LockTemp(rMIPS_RET0);
- LockTemp(rMIPS_RET1);
+ LockTemp(rs_rMIPS_RET0);
+ LockTemp(rs_rMIPS_RET1);
NewLIR0(kPseudoMethodExit);
UnSpillCoreRegs();
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 81d6782..7a8376e 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -39,7 +39,7 @@
LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
OpSize size);
LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
- RegStorage r_dest, RegStorage r_dest_hi, OpSize size, int s_reg);
+ RegStorage r_dest, OpSize size, int s_reg);
LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
@@ -47,16 +47,12 @@
LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
OpSize size);
LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
- RegStorage r_src, RegStorage r_src_hi, OpSize size, int s_reg);
+ RegStorage r_src, OpSize size, int s_reg);
void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
// Required for target - register utilities.
- bool IsFpReg(int reg);
- bool IsFpReg(RegStorage reg);
- bool SameRegType(int reg1, int reg2);
RegStorage AllocTypedTemp(bool fp_hint, int reg_class);
RegStorage AllocTypedTempWide(bool fp_hint, int reg_class);
- int S2d(int low_reg, int high_reg);
RegStorage TargetReg(SpecialTargetRegister reg);
RegStorage GetArgMappingToPhysicalReg(int arg_num);
RegLocation GetReturnAlt();
@@ -65,16 +61,14 @@
RegLocation LocCReturnDouble();
RegLocation LocCReturnFloat();
RegLocation LocCReturnWide();
- uint32_t FpRegMask();
- uint64_t GetRegMaskCommon(int reg);
+ uint64_t GetRegMaskCommon(RegStorage reg);
void AdjustSpillMask();
void ClobberCallerSave();
- void FlushReg(RegStorage reg);
- void FlushRegWide(RegStorage reg);
void FreeCallTemps();
void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
void LockCallTemps();
- void MarkPreservedSingle(int v_reg, int reg);
+ void MarkPreservedSingle(int v_reg, RegStorage reg);
+ void MarkPreservedDouble(int v_reg, RegStorage reg);
void CompilerInitializeRegAlloc();
// Required for target - miscellaneous.
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index a479dc7..9fffb2f 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -111,15 +111,13 @@
rl_result = EvalLoc(rl_dest, kFPReg, true);
DCHECK(rl_dest.wide);
DCHECK(rl_result.wide);
- NewLIR3(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
- S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+ NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
StoreValueWide(rl_dest, rl_result);
}
void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src) {
int op = kMipsNop;
- int src_reg;
RegLocation rl_result;
switch (opcode) {
case Instruction::INT_TO_FLOAT:
@@ -157,18 +155,14 @@
}
if (rl_src.wide) {
rl_src = LoadValueWide(rl_src, kFPReg);
- src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
} else {
rl_src = LoadValue(rl_src, kFPReg);
- src_reg = rl_src.reg.GetReg();
}
+ rl_result = EvalLoc(rl_dest, kFPReg, true);
+ NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
if (rl_dest.wide) {
- rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
StoreValueWide(rl_dest, rl_result);
} else {
- rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(op, rl_result.reg.GetReg(), src_reg);
StoreValue(rl_dest, rl_result);
}
}
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 7c0becd..1410e14 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -44,16 +44,16 @@
RegLocation rl_src2) {
rl_src1 = LoadValueWide(rl_src1, kCoreReg);
rl_src2 = LoadValueWide(rl_src2, kCoreReg);
- int t0 = AllocTemp().GetReg();
- int t1 = AllocTemp().GetReg();
+ RegStorage t0 = AllocTemp();
+ RegStorage t1 = AllocTemp();
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
- NewLIR3(kMipsSlt, t0, rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
- NewLIR3(kMipsSlt, t1, rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
- NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1, t0);
+ NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
+ NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
+ NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
- NewLIR3(kMipsSltu, t0, rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
- NewLIR3(kMipsSltu, t1, rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
- NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1, t0);
+ NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
+ NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
+ NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
FreeTemp(t0);
FreeTemp(t1);
LIR* target = NewLIR0(kPseudoTargetLabel);
@@ -114,13 +114,13 @@
if (cmp_zero) {
branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
} else {
- int t_reg = AllocTemp().GetReg();
+ RegStorage t_reg = AllocTemp();
if (swapped) {
- NewLIR3(slt_op, t_reg, src2.GetReg(), src1.GetReg());
+ NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
} else {
- NewLIR3(slt_op, t_reg, src1.GetReg(), src2.GetReg());
+ NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
}
- branch = NewLIR1(br_op, t_reg);
+ branch = NewLIR1(br_op, t_reg.GetReg());
FreeTemp(t_reg);
}
branch->target = target;
@@ -167,7 +167,7 @@
if (r_src.IsPair()) {
r_src = r_src.GetLow();
}
- if (MIPS_FPREG(r_dest.GetReg()) || MIPS_FPREG(r_src.GetReg()))
+ if (r_dest.IsFloat() || r_src.IsFloat())
return OpFpRegCopy(r_dest, r_src);
LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
r_dest.GetReg(), r_src.GetReg());
@@ -186,17 +186,15 @@
void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
if (r_dest != r_src) {
- bool dest_fp = MIPS_FPREG(r_dest.GetLowReg());
- bool src_fp = MIPS_FPREG(r_src.GetLowReg());
+ bool dest_fp = r_dest.IsFloat();
+ bool src_fp = r_src.IsFloat();
if (dest_fp) {
if (src_fp) {
- // FIXME: handle this here - reserve OpRegCopy for 32-bit copies.
- OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
- RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
- } else {
- /* note the operands are swapped for the mtc1 instr */
- NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
- NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
+ OpRegCopy(r_dest, r_src);
+ } else {
+ /* note the operands are swapped for the mtc1 instr */
+ NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
+ NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
}
} else {
if (src_fp) {
@@ -238,9 +236,9 @@
RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
bool is_div) {
- int t_reg = AllocTemp().GetReg();
- NewLIR3(kMipsAddiu, t_reg, rZERO, lit);
- NewLIR2(kMipsDiv, reg1.GetReg(), t_reg);
+ RegStorage t_reg = AllocTemp();
+ NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
+ NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (is_div) {
NewLIR1(kMipsMflo, rl_result.reg.GetReg());
@@ -470,7 +468,7 @@
*/
void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_dest, int scale) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
int len_offset = mirror::Array::LengthOffset().Int32Value();
int data_offset;
RegLocation rl_result;
@@ -496,7 +494,7 @@
}
/* reg_ptr -> array data */
OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
- FreeTemp(rl_array.reg.GetReg());
+ FreeTemp(rl_array.reg);
if ((size == k64) || (size == kDouble)) {
if (scale) {
RegStorage r_new_index = AllocTemp();
@@ -537,7 +535,7 @@
*/
void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
int len_offset = mirror::Array::LengthOffset().Int32Value();
int data_offset;
@@ -551,8 +549,8 @@
rl_index = LoadValue(rl_index, kCoreReg);
RegStorage reg_ptr;
bool allocated_reg_ptr_temp = false;
- if (IsTemp(rl_array.reg.GetReg()) && !card_mark) {
- Clobber(rl_array.reg.GetReg());
+ if (IsTemp(rl_array.reg) && !card_mark) {
+ Clobber(rl_array.reg);
reg_ptr = rl_array.reg;
} else {
reg_ptr = AllocTemp();
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index c5150ee..5b2cb9d 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -86,26 +86,6 @@
* +========================+
*/
-// Offset to distingish FP regs.
-#define MIPS_FP_REG_OFFSET 32
-// Offset to distinguish DP FP regs.
-#define MIPS_FP_DOUBLE 64
-// Reg types.
-#define MIPS_REGTYPE(x) (x & (MIPS_FP_REG_OFFSET | MIPS_FP_DOUBLE))
-#define MIPS_FPREG(x) ((x & MIPS_FP_REG_OFFSET) == MIPS_FP_REG_OFFSET)
-#define MIPS_DOUBLEREG(x) ((x & MIPS_FP_DOUBLE) == MIPS_FP_DOUBLE)
-#define MIPS_SINGLEREG(x) (MIPS_FPREG(x) && !MIPS_DOUBLEREG(x))
-// FIXME: out of date comment.
-/*
- * Note: the low register of a floating point pair is sufficient to
- * create the name of a double, but require both names to be passed to
- * allow for asserts to verify that the pair is consecutive if significant
- * rework is done in this area. Also, it is a good reminder in the calling
- * code that reg locations always describe doubles as a pair of singles.
- */
-#define MIPS_S2D(x, y) ((x) | MIPS_FP_DOUBLE)
-// Mask to strip off fp flags.
-#define MIPS_FP_REG_MASK (MIPS_FP_REG_OFFSET-1)
#define LOWORD_OFFSET 0
#define HIWORD_OFFSET 4
@@ -159,135 +139,159 @@
#define ENCODE_MIPS_REG_LO (1ULL << kMipsRegLO)
enum MipsNativeRegisterPool {
- rZERO = 0,
- rAT = 1,
- rV0 = 2,
- rV1 = 3,
- rA0 = 4,
- rA1 = 5,
- rA2 = 6,
- rA3 = 7,
- rT0 = 8,
- rT1 = 9,
- rT2 = 10,
- rT3 = 11,
- rT4 = 12,
- rT5 = 13,
- rT6 = 14,
- rT7 = 15,
- rS0 = 16,
- rS1 = 17,
- rS2 = 18,
- rS3 = 19,
- rS4 = 20,
- rS5 = 21,
- rS6 = 22,
- rS7 = 23,
- rT8 = 24,
- rT9 = 25,
- rK0 = 26,
- rK1 = 27,
- rGP = 28,
- rSP = 29,
- rFP = 30,
- rRA = 31,
+ rZERO = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0,
+ rAT = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 1,
+ rV0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 2,
+ rV1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 3,
+ rA0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 4,
+ rA1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 5,
+ rA2 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 6,
+ rA3 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 7,
+ rT0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 8,
+ rT1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 9,
+ rT2 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 10,
+ rT3 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 11,
+ rT4 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 12,
+ rT5 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 13,
+ rT6 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 14,
+ rT7 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 15,
+ rS0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 16,
+ rS1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 17,
+ rS2 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 18,
+ rS3 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 19,
+ rS4 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 20,
+ rS5 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 21,
+ rS6 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 22,
+ rS7 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 23,
+ rT8 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 24,
+ rT9 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 25,
+ rK0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 26,
+ rK1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 27,
+ rGP = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 28,
+ rSP = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 29,
+ rFP = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 30,
+ rRA = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 31,
- rF0 = 0 + MIPS_FP_REG_OFFSET,
- rF1,
- rF2,
- rF3,
- rF4,
- rF5,
- rF6,
- rF7,
- rF8,
- rF9,
- rF10,
- rF11,
- rF12,
- rF13,
- rF14,
- rF15,
+ rF0 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 0,
+ rF1 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 1,
+ rF2 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 2,
+ rF3 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 3,
+ rF4 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 4,
+ rF5 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 5,
+ rF6 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 6,
+ rF7 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 7,
+ rF8 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 8,
+ rF9 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 9,
+ rF10 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 10,
+ rF11 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 11,
+ rF12 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 12,
+ rF13 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 13,
+ rF14 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 14,
+ rF15 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 15,
#if 0
/*
* TODO: The shared resource mask doesn't have enough bit positions to describe all
* MIPS registers. Expand it and enable use of fp registers 16 through 31.
*/
- rF16,
- rF17,
- rF18,
- rF19,
- rF20,
- rF21,
- rF22,
- rF23,
- rF24,
- rF25,
- rF26,
- rF27,
- rF28,
- rF29,
- rF30,
- rF31,
+ rF16 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 16,
+ rF17 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 17,
+ rF18 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 18,
+ rF19 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 19,
+ rF20 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 20,
+ rF21 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 21,
+ rF22 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 22,
+ rF23 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 23,
+ rF24 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 24,
+ rF25 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 25,
+ rF26 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 26,
+ rF27 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 27,
+ rF28 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 28,
+ rF29 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 29,
+ rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
+ rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
#endif
- rDF0 = rF0 + MIPS_FP_DOUBLE,
- rDF1 = rF2 + MIPS_FP_DOUBLE,
- rDF2 = rF4 + MIPS_FP_DOUBLE,
- rDF3 = rF6 + MIPS_FP_DOUBLE,
- rDF4 = rF8 + MIPS_FP_DOUBLE,
- rDF5 = rF10 + MIPS_FP_DOUBLE,
- rDF6 = rF12 + MIPS_FP_DOUBLE,
- rDF7 = rF14 + MIPS_FP_DOUBLE,
+ rD0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
+ rD1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1,
+ rD2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
+ rD3 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 3,
+ rD4 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
+ rD5 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 5,
+ rD6 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
+ rD7 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 7,
#if 0 // TODO: expand resource mask to enable use of all MIPS fp registers.
- rDF8 = rF16 + MIPS_FP_DOUBLE,
- rDF9 = rF18 + MIPS_FP_DOUBLE,
- rDF10 = rF20 + MIPS_FP_DOUBLE,
- rDF11 = rF22 + MIPS_FP_DOUBLE,
- rDF12 = rF24 + MIPS_FP_DOUBLE,
- rDF13 = rF26 + MIPS_FP_DOUBLE,
- rDF14 = rF28 + MIPS_FP_DOUBLE,
- rDF15 = rF30 + MIPS_FP_DOUBLE,
+ rD8 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8,
+ rD9 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 9,
+ rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+ rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+ rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+ rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+ rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+ rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
#endif
};
-const RegStorage rs_rZERO(RegStorage::k32BitSolo, rZERO);
-const RegStorage rs_rAT(RegStorage::k32BitSolo, rAT);
-const RegStorage rs_rV0(RegStorage::k32BitSolo, rV0);
-const RegStorage rs_rV1(RegStorage::k32BitSolo, rV1);
-const RegStorage rs_rA0(RegStorage::k32BitSolo, rA0);
-const RegStorage rs_rA1(RegStorage::k32BitSolo, rA1);
-const RegStorage rs_rA2(RegStorage::k32BitSolo, rA2);
-const RegStorage rs_rA3(RegStorage::k32BitSolo, rA3);
-const RegStorage rs_rT0(RegStorage::k32BitSolo, rT0);
-const RegStorage rs_rT1(RegStorage::k32BitSolo, rT1);
-const RegStorage rs_rT2(RegStorage::k32BitSolo, rT2);
-const RegStorage rs_rT3(RegStorage::k32BitSolo, rT3);
-const RegStorage rs_rT4(RegStorage::k32BitSolo, rT4);
-const RegStorage rs_rT5(RegStorage::k32BitSolo, rT5);
-const RegStorage rs_rT6(RegStorage::k32BitSolo, rT6);
-const RegStorage rs_rT7(RegStorage::k32BitSolo, rT7);
-const RegStorage rs_rS0(RegStorage::k32BitSolo, rS0);
-const RegStorage rs_rS1(RegStorage::k32BitSolo, rS1);
-const RegStorage rs_rS2(RegStorage::k32BitSolo, rS2);
-const RegStorage rs_rS3(RegStorage::k32BitSolo, rS3);
-const RegStorage rs_rS4(RegStorage::k32BitSolo, rS4);
-const RegStorage rs_rS5(RegStorage::k32BitSolo, rS5);
-const RegStorage rs_rS6(RegStorage::k32BitSolo, rS6);
-const RegStorage rs_rS7(RegStorage::k32BitSolo, rS7);
-const RegStorage rs_rT8(RegStorage::k32BitSolo, rT8);
-const RegStorage rs_rT9(RegStorage::k32BitSolo, rT9);
-const RegStorage rs_rK0(RegStorage::k32BitSolo, rK0);
-const RegStorage rs_rK1(RegStorage::k32BitSolo, rK1);
-const RegStorage rs_rGP(RegStorage::k32BitSolo, rGP);
-const RegStorage rs_rSP(RegStorage::k32BitSolo, rSP);
-const RegStorage rs_rFP(RegStorage::k32BitSolo, rFP);
-const RegStorage rs_rRA(RegStorage::k32BitSolo, rRA);
-const RegStorage rs_rF12(RegStorage::k32BitSolo, rF12);
-const RegStorage rs_rF13(RegStorage::k32BitSolo, rF13);
-const RegStorage rs_rF14(RegStorage::k32BitSolo, rF14);
-const RegStorage rs_rF15(RegStorage::k32BitSolo, rF15);
-const RegStorage rs_rF0(RegStorage::k32BitSolo, rF0);
-const RegStorage rs_rF1(RegStorage::k32BitSolo, rF1);
+constexpr RegStorage rs_rZERO(RegStorage::kValid | rZERO);
+constexpr RegStorage rs_rAT(RegStorage::kValid | rAT);
+constexpr RegStorage rs_rV0(RegStorage::kValid | rV0);
+constexpr RegStorage rs_rV1(RegStorage::kValid | rV1);
+constexpr RegStorage rs_rA0(RegStorage::kValid | rA0);
+constexpr RegStorage rs_rA1(RegStorage::kValid | rA1);
+constexpr RegStorage rs_rA2(RegStorage::kValid | rA2);
+constexpr RegStorage rs_rA3(RegStorage::kValid | rA3);
+constexpr RegStorage rs_rT0(RegStorage::kValid | rT0);
+constexpr RegStorage rs_rT1(RegStorage::kValid | rT1);
+constexpr RegStorage rs_rT2(RegStorage::kValid | rT2);
+constexpr RegStorage rs_rT3(RegStorage::kValid | rT3);
+constexpr RegStorage rs_rT4(RegStorage::kValid | rT4);
+constexpr RegStorage rs_rT5(RegStorage::kValid | rT5);
+constexpr RegStorage rs_rT6(RegStorage::kValid | rT6);
+constexpr RegStorage rs_rT7(RegStorage::kValid | rT7);
+constexpr RegStorage rs_rS0(RegStorage::kValid | rS0);
+constexpr RegStorage rs_rS1(RegStorage::kValid | rS1);
+constexpr RegStorage rs_rS2(RegStorage::kValid | rS2);
+constexpr RegStorage rs_rS3(RegStorage::kValid | rS3);
+constexpr RegStorage rs_rS4(RegStorage::kValid | rS4);
+constexpr RegStorage rs_rS5(RegStorage::kValid | rS5);
+constexpr RegStorage rs_rS6(RegStorage::kValid | rS6);
+constexpr RegStorage rs_rS7(RegStorage::kValid | rS7);
+constexpr RegStorage rs_rT8(RegStorage::kValid | rT8);
+constexpr RegStorage rs_rT9(RegStorage::kValid | rT9);
+constexpr RegStorage rs_rK0(RegStorage::kValid | rK0);
+constexpr RegStorage rs_rK1(RegStorage::kValid | rK1);
+constexpr RegStorage rs_rGP(RegStorage::kValid | rGP);
+constexpr RegStorage rs_rSP(RegStorage::kValid | rSP);
+constexpr RegStorage rs_rFP(RegStorage::kValid | rFP);
+constexpr RegStorage rs_rRA(RegStorage::kValid | rRA);
+
+constexpr RegStorage rs_rMIPS_LR(RegStorage::kInvalid); // Not used for MIPS.
+constexpr RegStorage rs_rMIPS_PC(RegStorage::kInvalid); // Not used for MIPS.
+constexpr RegStorage rs_rMIPS_COUNT(RegStorage::kInvalid); // Not used for MIPS.
+
+constexpr RegStorage rs_rF0(RegStorage::kValid | rF0);
+constexpr RegStorage rs_rF1(RegStorage::kValid | rF1);
+constexpr RegStorage rs_rF2(RegStorage::kValid | rF2);
+constexpr RegStorage rs_rF3(RegStorage::kValid | rF3);
+constexpr RegStorage rs_rF4(RegStorage::kValid | rF4);
+constexpr RegStorage rs_rF5(RegStorage::kValid | rF5);
+constexpr RegStorage rs_rF6(RegStorage::kValid | rF6);
+constexpr RegStorage rs_rF7(RegStorage::kValid | rF7);
+constexpr RegStorage rs_rF8(RegStorage::kValid | rF8);
+constexpr RegStorage rs_rF9(RegStorage::kValid | rF9);
+constexpr RegStorage rs_rF10(RegStorage::kValid | rF10);
+constexpr RegStorage rs_rF11(RegStorage::kValid | rF11);
+constexpr RegStorage rs_rF12(RegStorage::kValid | rF12);
+constexpr RegStorage rs_rF13(RegStorage::kValid | rF13);
+constexpr RegStorage rs_rF14(RegStorage::kValid | rF14);
+constexpr RegStorage rs_rF15(RegStorage::kValid | rF15);
+
+constexpr RegStorage rs_rD0(RegStorage::kValid | rD0);
+constexpr RegStorage rs_rD1(RegStorage::kValid | rD1);
+constexpr RegStorage rs_rD2(RegStorage::kValid | rD2);
+constexpr RegStorage rs_rD3(RegStorage::kValid | rD3);
+constexpr RegStorage rs_rD4(RegStorage::kValid | rD4);
+constexpr RegStorage rs_rD5(RegStorage::kValid | rD5);
+constexpr RegStorage rs_rD6(RegStorage::kValid | rD6);
+constexpr RegStorage rs_rD7(RegStorage::kValid | rD7);
// TODO: reduce/eliminate use of these.
#define rMIPS_SUSPEND rS0
@@ -311,9 +315,9 @@
#define rMIPS_FARG2 rFARG2
#define rs_rMIPS_FARG2 rs_rFARG2
#define rMIPS_FARG3 rFARG3
-#define rs_MIPS_FARG3 rs_rFARG3
+#define rs_rMIPS_FARG3 rs_rFARG3
#define rMIPS_RET0 rRESULT0
-#define rs_MIPS_RET0 rs_rRESULT0
+#define rs_rMIPS_RET0 rs_rRESULT0
#define rMIPS_RET1 rRESULT1
#define rs_rMIPS_RET1 rs_rRESULT1
#define rMIPS_INVOKE_TGT rT9
@@ -322,16 +326,17 @@
// RegisterLocation templates return values (r_V0, or r_V0/r_V1).
const RegLocation mips_loc_c_return
- {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k32BitSolo, rV0), INVALID_SREG, INVALID_SREG};
const RegLocation mips_loc_c_return_wide
- {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k64BitPair, rV0, rV1), INVALID_SREG, INVALID_SREG};
const RegLocation mips_loc_c_return_float
- {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1,
RegStorage(RegStorage::k32BitSolo, rF0), INVALID_SREG, INVALID_SREG};
+// FIXME: move MIPS to k64Bitsolo for doubles
const RegLocation mips_loc_c_return_double
- {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1,
RegStorage(RegStorage::k64BitPair, rF0, rF1), INVALID_SREG, INVALID_SREG};
enum MipsShiftEncodings {
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 7f4cd5e..8d91aba 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -26,18 +26,40 @@
namespace art {
-static int core_regs[] = {rZERO, rAT, rV0, rV1, rA0, rA1, rA2, rA3,
- rT0, rT1, rT2, rT3, rT4, rT5, rT6, rT7,
- rS0, rS1, rS2, rS3, rS4, rS5, rS6, rS7, rT8,
- rT9, rK0, rK1, rGP, rSP, rFP, rRA};
-static int ReservedRegs[] = {rZERO, rAT, rS0, rS1, rK0, rK1, rGP, rSP,
- rRA};
-static int core_temps[] = {rV0, rV1, rA0, rA1, rA2, rA3, rT0, rT1, rT2,
- rT3, rT4, rT5, rT6, rT7, rT8};
-static int FpRegs[] = {rF0, rF1, rF2, rF3, rF4, rF5, rF6, rF7,
- rF8, rF9, rF10, rF11, rF12, rF13, rF14, rF15};
-static int fp_temps[] = {rF0, rF1, rF2, rF3, rF4, rF5, rF6, rF7,
- rF8, rF9, rF10, rF11, rF12, rF13, rF14, rF15};
+static const RegStorage core_regs_arr[] =
+ {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2,
+ rs_rT3, rs_rT4, rs_rT5, rs_rT6, rs_rT7, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5,
+ rs_rS6, rs_rS7, rs_rT8, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rFP, rs_rRA};
+static RegStorage sp_regs_arr[] =
+ {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
+ rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
+static RegStorage dp_regs_arr[] =
+ {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static const RegStorage reserved_regs_arr[] =
+ {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
+static RegStorage core_temps_arr[] =
+ {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rT4,
+ rs_rT5, rs_rT6, rs_rT7, rs_rT8};
+static RegStorage sp_temps_arr[] =
+ {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
+ rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
+static RegStorage dp_temps_arr[] =
+ {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+
+static const std::vector<RegStorage> core_regs(core_regs_arr,
+ core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
+static const std::vector<RegStorage> sp_regs(sp_regs_arr,
+ sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
+static const std::vector<RegStorage> dp_regs(dp_regs_arr,
+ dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
+static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
+ reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
+static const std::vector<RegStorage> core_temps(core_temps_arr,
+ core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
+static const std::vector<RegStorage> sp_temps(sp_temps_arr,
+ sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
+static const std::vector<RegStorage> dp_temps(dp_temps_arr,
+ dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
RegLocation MipsMir2Lir::LocCReturn() {
return mips_loc_c_return;
@@ -57,29 +79,29 @@
// Return a target-dependent special register.
RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
- int res_reg = RegStorage::kInvalidRegVal;
+ RegStorage res_reg;
switch (reg) {
- case kSelf: res_reg = rMIPS_SELF; break;
- case kSuspend: res_reg = rMIPS_SUSPEND; break;
- case kLr: res_reg = rMIPS_LR; break;
- case kPc: res_reg = rMIPS_PC; break;
- case kSp: res_reg = rMIPS_SP; break;
- case kArg0: res_reg = rMIPS_ARG0; break;
- case kArg1: res_reg = rMIPS_ARG1; break;
- case kArg2: res_reg = rMIPS_ARG2; break;
- case kArg3: res_reg = rMIPS_ARG3; break;
- case kFArg0: res_reg = rMIPS_FARG0; break;
- case kFArg1: res_reg = rMIPS_FARG1; break;
- case kFArg2: res_reg = rMIPS_FARG2; break;
- case kFArg3: res_reg = rMIPS_FARG3; break;
- case kRet0: res_reg = rMIPS_RET0; break;
- case kRet1: res_reg = rMIPS_RET1; break;
- case kInvokeTgt: res_reg = rMIPS_INVOKE_TGT; break;
- case kHiddenArg: res_reg = rT0; break;
- case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
- case kCount: res_reg = rMIPS_COUNT; break;
+ case kSelf: res_reg = rs_rMIPS_SELF; break;
+ case kSuspend: res_reg = rs_rMIPS_SUSPEND; break;
+ case kLr: res_reg = rs_rMIPS_LR; break;
+ case kPc: res_reg = rs_rMIPS_PC; break;
+ case kSp: res_reg = rs_rMIPS_SP; break;
+ case kArg0: res_reg = rs_rMIPS_ARG0; break;
+ case kArg1: res_reg = rs_rMIPS_ARG1; break;
+ case kArg2: res_reg = rs_rMIPS_ARG2; break;
+ case kArg3: res_reg = rs_rMIPS_ARG3; break;
+ case kFArg0: res_reg = rs_rMIPS_FARG0; break;
+ case kFArg1: res_reg = rs_rMIPS_FARG1; break;
+ case kFArg2: res_reg = rs_rMIPS_FARG2; break;
+ case kFArg3: res_reg = rs_rMIPS_FARG3; break;
+ case kRet0: res_reg = rs_rMIPS_RET0; break;
+ case kRet1: res_reg = rs_rMIPS_RET1; break;
+ case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
+ case kHiddenArg: res_reg = rs_rT0; break;
+ case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
+ case kCount: res_reg = rs_rMIPS_COUNT; break;
}
- return RegStorage::Solo32(res_reg);
+ return res_reg;
}
RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
@@ -96,35 +118,22 @@
}
}
-// Create a double from a pair of singles.
-int MipsMir2Lir::S2d(int low_reg, int high_reg) {
- return MIPS_S2D(low_reg, high_reg);
-}
-
-// Return mask to strip off fp reg flags and bias.
-uint32_t MipsMir2Lir::FpRegMask() {
- return MIPS_FP_REG_MASK;
-}
-
-// True if both regs single, both core or both double.
-bool MipsMir2Lir::SameRegType(int reg1, int reg2) {
- return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
-}
-
/*
* Decode the register id.
*/
-uint64_t MipsMir2Lir::GetRegMaskCommon(int reg) {
+uint64_t MipsMir2Lir::GetRegMaskCommon(RegStorage reg) {
uint64_t seed;
int shift;
- int reg_id;
-
-
- reg_id = reg & 0x1f;
+ int reg_id = reg.GetRegNum();
/* Each double register is equal to a pair of single-precision FP registers */
- seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
- /* FP register starts at bit position 16 */
- shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
+ if (reg.IsDouble()) {
+ seed = 0x3;
+ reg_id = reg_id << 1;
+ } else {
+ seed = 1;
+ }
+ /* FP register starts at bit position 32 */
+ shift = reg.IsFloat() ? kMipsFPReg0 : 0;
/* Expand the double register id into single offset */
shift += reg_id;
return (seed << shift);
@@ -209,11 +218,11 @@
}
break;
case 's':
- snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
+ snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
break;
case 'S':
- DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
- snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
+ DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
+ snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
break;
case 'h':
snprintf(tbuf, arraysize(tbuf), "%04x", operand);
@@ -327,7 +336,7 @@
*/
void MipsMir2Lir::AdjustSpillMask() {
- core_spill_mask_ |= (1 << rRA);
+ core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
num_core_spills_++;
}
@@ -337,92 +346,63 @@
* include any holes in the mask. Associate holes with
* Dalvik register INVALID_VREG (0xFFFFU).
*/
-void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
+void MipsMir2Lir::MarkPreservedSingle(int s_reg, RegStorage reg) {
LOG(FATAL) << "No support yet for promoted FP regs";
}
-void MipsMir2Lir::FlushRegWide(RegStorage reg) {
- RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
- RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
- DCHECK(info1 && info2 && info1->pair && info2->pair &&
- (info1->partner == info2->reg) &&
- (info2->partner == info1->reg));
- if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
- if (!(info1->is_temp && info2->is_temp)) {
- /* Should not happen. If it does, there's a problem in eval_loc */
- LOG(FATAL) << "Long half-temp, half-promoted";
- }
-
- info1->dirty = false;
- info2->dirty = false;
- if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
- info1 = info2;
- int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
- StoreBaseDispWide(rs_rMIPS_SP, VRegOffset(v_reg),
- RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
- }
-}
-
-void MipsMir2Lir::FlushReg(RegStorage reg) {
- DCHECK(!reg.IsPair());
- RegisterInfo* info = GetRegInfo(reg.GetReg());
- if (info->live && info->dirty) {
- info->dirty = false;
- int v_reg = mir_graph_->SRegToVReg(info->s_reg);
- Store32Disp(rs_rMIPS_SP, VRegOffset(v_reg), reg);
- }
-}
-
-/* Give access to the target-dependent FP register encoding to common code */
-bool MipsMir2Lir::IsFpReg(int reg) {
- return MIPS_FPREG(reg);
-}
-
-bool MipsMir2Lir::IsFpReg(RegStorage reg) {
- return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
+void MipsMir2Lir::MarkPreservedDouble(int s_reg, RegStorage reg) {
+ LOG(FATAL) << "No support yet for promoted FP regs";
}
/* Clobber all regs that might be used by an external C call */
void MipsMir2Lir::ClobberCallerSave() {
- Clobber(rZERO);
- Clobber(rAT);
- Clobber(rV0);
- Clobber(rV1);
- Clobber(rA0);
- Clobber(rA1);
- Clobber(rA2);
- Clobber(rA3);
- Clobber(rT0);
- Clobber(rT1);
- Clobber(rT2);
- Clobber(rT3);
- Clobber(rT4);
- Clobber(rT5);
- Clobber(rT6);
- Clobber(rT7);
- Clobber(rT8);
- Clobber(rT9);
- Clobber(rK0);
- Clobber(rK1);
- Clobber(rGP);
- Clobber(rFP);
- Clobber(rRA);
- Clobber(rF0);
- Clobber(rF1);
- Clobber(rF2);
- Clobber(rF3);
- Clobber(rF4);
- Clobber(rF5);
- Clobber(rF6);
- Clobber(rF7);
- Clobber(rF8);
- Clobber(rF9);
- Clobber(rF10);
- Clobber(rF11);
- Clobber(rF12);
- Clobber(rF13);
- Clobber(rF14);
- Clobber(rF15);
+ Clobber(rs_rZERO);
+ Clobber(rs_rAT);
+ Clobber(rs_rV0);
+ Clobber(rs_rV1);
+ Clobber(rs_rA0);
+ Clobber(rs_rA1);
+ Clobber(rs_rA2);
+ Clobber(rs_rA3);
+ Clobber(rs_rT0);
+ Clobber(rs_rT1);
+ Clobber(rs_rT2);
+ Clobber(rs_rT3);
+ Clobber(rs_rT4);
+ Clobber(rs_rT5);
+ Clobber(rs_rT6);
+ Clobber(rs_rT7);
+ Clobber(rs_rT8);
+ Clobber(rs_rT9);
+ Clobber(rs_rK0);
+ Clobber(rs_rK1);
+ Clobber(rs_rGP);
+ Clobber(rs_rFP);
+ Clobber(rs_rRA);
+ Clobber(rs_rF0);
+ Clobber(rs_rF1);
+ Clobber(rs_rF2);
+ Clobber(rs_rF3);
+ Clobber(rs_rF4);
+ Clobber(rs_rF5);
+ Clobber(rs_rF6);
+ Clobber(rs_rF7);
+ Clobber(rs_rF8);
+ Clobber(rs_rF9);
+ Clobber(rs_rF10);
+ Clobber(rs_rF11);
+ Clobber(rs_rF12);
+ Clobber(rs_rF13);
+ Clobber(rs_rF14);
+ Clobber(rs_rF15);
+ Clobber(rs_rD0);
+ Clobber(rs_rD1);
+ Clobber(rs_rD2);
+ Clobber(rs_rD3);
+ Clobber(rs_rD4);
+ Clobber(rs_rD5);
+ Clobber(rs_rD6);
+ Clobber(rs_rD7);
}
RegLocation MipsMir2Lir::GetReturnWideAlt() {
@@ -439,18 +419,18 @@
/* To be used when explicitly managing register use */
void MipsMir2Lir::LockCallTemps() {
- LockTemp(rMIPS_ARG0);
- LockTemp(rMIPS_ARG1);
- LockTemp(rMIPS_ARG2);
- LockTemp(rMIPS_ARG3);
+ LockTemp(rs_rMIPS_ARG0);
+ LockTemp(rs_rMIPS_ARG1);
+ LockTemp(rs_rMIPS_ARG2);
+ LockTemp(rs_rMIPS_ARG3);
}
/* To be used when explicitly managing register use */
void MipsMir2Lir::FreeCallTemps() {
- FreeTemp(rMIPS_ARG0);
- FreeTemp(rMIPS_ARG1);
- FreeTemp(rMIPS_ARG2);
- FreeTemp(rMIPS_ARG3);
+ FreeTemp(rs_rMIPS_ARG0);
+ FreeTemp(rs_rMIPS_ARG1);
+ FreeTemp(rs_rMIPS_ARG2);
+ FreeTemp(rs_rMIPS_ARG3);
}
void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
@@ -461,56 +441,52 @@
// Alloc a pair of core registers, or a double.
RegStorage MipsMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
- int high_reg;
- int low_reg;
-
if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
return AllocTempDouble();
}
- low_reg = AllocTemp().GetReg();
- high_reg = AllocTemp().GetReg();
- return RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+ RegStorage low_reg = AllocTemp();
+ RegStorage high_reg = AllocTemp();
+ return RegStorage::MakeRegPair(low_reg, high_reg);
}
RegStorage MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
- return AllocTempFloat();
-}
+ return AllocTempSingle();
+ }
return AllocTemp();
}
void MipsMir2Lir::CompilerInitializeRegAlloc() {
- int num_regs = sizeof(core_regs)/sizeof(*core_regs);
- int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
- int num_temps = sizeof(core_temps)/sizeof(*core_temps);
- int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
- int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
- reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
- kArenaAllocRegAlloc));
- reg_pool_->num_core_regs = num_regs;
- reg_pool_->core_regs = static_cast<RegisterInfo*>
- (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
- reg_pool_->num_fp_regs = num_fp_regs;
- reg_pool_->FPRegs = static_cast<RegisterInfo*>
- (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
- CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
- CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
- // Keep special registers from being allocated
- for (int i = 0; i < num_reserved; i++) {
- if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
- // To measure cost of suspend check
- continue;
+ reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
+ core_temps, sp_temps, dp_temps);
+
+ // Target-specific adjustments.
+
+ // Alias single precision floats to appropriate half of overlapping double.
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ int sp_reg_num = info->GetReg().GetRegNum();
+ int dp_reg_num = sp_reg_num >> 1;
+ RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
+ RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
+ // Double precision register's master storage should refer to itself.
+ DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
+ // Redirect single precision's master storage to master.
+ info->SetMaster(dp_reg_info);
+ // Singles should show a single 32-bit mask bit, at first referring to the low half.
+ DCHECK_EQ(info->StorageMask(), 0x1U);
+ if (sp_reg_num & 1) {
+ // For odd singles, change to user the high word of the backing double.
+ info->SetStorageMask(0x2);
}
- MarkInUse(ReservedRegs[i]);
}
- // Mark temp regs - all others not in use can be used for promotion
- for (int i = 0; i < num_temps; i++) {
- MarkTemp(core_temps[i]);
- }
- for (int i = 0; i < num_fp_temps; i++) {
- MarkTemp(fp_temps[i]);
- }
+
+ // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
+ // TODO: adjust when we roll to hard float calling convention.
+ reg_pool_->next_core_reg_ = 2;
+ reg_pool_->next_sp_reg_ = 2;
+ reg_pool_->next_dp_reg_ = 1;
}
void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index a865430..50b945a 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -24,12 +24,12 @@
LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
int opcode;
/* must be both DOUBLE or both not DOUBLE */
- DCHECK_EQ(MIPS_DOUBLEREG(r_dest.GetReg()), MIPS_DOUBLEREG(r_src.GetReg()));
- if (MIPS_DOUBLEREG(r_dest.GetReg())) {
+ DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
+ if (r_dest.IsDouble()) {
opcode = kMipsFmovd;
} else {
- if (MIPS_SINGLEREG(r_dest.GetReg())) {
- if (MIPS_SINGLEREG(r_src.GetReg())) {
+ if (r_dest.IsSingle()) {
+ if (r_src.IsSingle()) {
opcode = kMipsFmovs;
} else {
/* note the operands are swapped for the mtc1 instr */
@@ -39,7 +39,7 @@
opcode = kMipsMtc1;
}
} else {
- DCHECK(MIPS_SINGLEREG(r_src.GetReg()));
+ DCHECK(r_src.IsSingle());
opcode = kMipsMfc1;
}
}
@@ -79,9 +79,9 @@
LIR *res;
RegStorage r_dest_save = r_dest;
- int is_fp_reg = MIPS_FPREG(r_dest.GetReg());
+ int is_fp_reg = r_dest.IsFloat();
if (is_fp_reg) {
- DCHECK(MIPS_SINGLEREG(r_dest.GetReg()));
+ DCHECK(r_dest.IsSingle());
r_dest = AllocTemp();
}
@@ -355,8 +355,8 @@
MipsOpCode opcode = kMipsNop;
RegStorage t_reg = AllocTemp();
- if (MIPS_FPREG(r_dest.GetReg())) {
- DCHECK(MIPS_SINGLEREG(r_dest.GetReg()));
+ if (r_dest.IsFloat()) {
+ DCHECK(r_dest.IsSingle());
DCHECK((size == k32) || (size == kSingle) || (size == kReference));
size = kSingle;
} else {
@@ -407,8 +407,8 @@
MipsOpCode opcode = kMipsNop;
RegStorage t_reg = AllocTemp();
- if (MIPS_FPREG(r_src.GetReg())) {
- DCHECK(MIPS_SINGLEREG(r_src.GetReg()));
+ if (r_src.IsFloat()) {
+ DCHECK(r_src.IsSingle());
DCHECK((size == k32) || (size == kSingle) || (size == kReference));
size = kSingle;
} else {
@@ -469,16 +469,16 @@
case kDouble:
pair = true;
opcode = kMipsLw;
- if (MIPS_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
opcode = kMipsFlwc1;
- if (MIPS_DOUBLEREG(r_dest.GetReg())) {
- // TODO: rework to use k64BitSolo
- r_dest.SetReg(r_dest.GetReg() - MIPS_FP_DOUBLE);
+ if (r_dest.IsDouble()) {
+ int reg_num = (r_dest.GetRegNum() << 1) | RegStorage::kFloatingPoint;
+ r_dest = RegStorage(RegStorage::k64BitSolo, reg_num, reg_num + 1);
} else {
- DCHECK(MIPS_FPREG(r_dest_hi.GetReg()));
+ DCHECK(r_dest_hi.IsFloat());
DCHECK_EQ(r_dest.GetReg(), r_dest_hi.GetReg() - 1);
+ r_dest_hi.SetReg(r_dest.GetReg() + 1);
}
- r_dest_hi.SetReg(r_dest.GetReg() + 1);
}
short_form = IS_SIMM16_2WORD(displacement);
DCHECK_EQ((displacement & 0x3), 0);
@@ -487,9 +487,9 @@
case kSingle:
case kReference:
opcode = kMipsLw;
- if (MIPS_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
opcode = kMipsFlwc1;
- DCHECK(MIPS_SINGLEREG(r_dest.GetReg()));
+ DCHECK(r_dest.IsSingle());
}
DCHECK_EQ((displacement & 0x3), 0);
break;
@@ -567,22 +567,22 @@
LIR *store2 = NULL;
MipsOpCode opcode = kMipsNop;
bool short_form = IS_SIMM16(displacement);
- bool pair = false;
+ bool pair = r_src.IsPair();
switch (size) {
case k64:
case kDouble:
- pair = true;
opcode = kMipsSw;
- if (MIPS_FPREG(r_src.GetReg())) {
+ if (r_src.IsFloat()) {
opcode = kMipsFswc1;
- if (MIPS_DOUBLEREG(r_src.GetReg())) {
- r_src.SetReg(r_src.GetReg() - MIPS_FP_DOUBLE);
+ if (r_src.IsDouble()) {
+ int reg_num = (r_src.GetRegNum() << 1) | RegStorage::kFloatingPoint;
+ r_src = RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
} else {
- DCHECK(MIPS_FPREG(r_src_hi.GetReg()));
+ DCHECK(r_src_hi.IsFloat());
DCHECK_EQ(r_src.GetReg(), (r_src_hi.GetReg() - 1));
+ r_src_hi.SetReg(r_src.GetReg() + 1);
}
- r_src_hi.SetReg(r_src.GetReg() + 1);
}
short_form = IS_SIMM16_2WORD(displacement);
DCHECK_EQ((displacement & 0x3), 0);
@@ -591,9 +591,9 @@
case kSingle:
case kReference:
opcode = kMipsSw;
- if (MIPS_FPREG(r_src.GetReg())) {
+ if (r_src.IsFloat()) {
opcode = kMipsFswc1;
- DCHECK(MIPS_SINGLEREG(r_src.GetReg()));
+ DCHECK(r_src.IsSingle());
}
DCHECK_EQ((displacement & 0x3), 0);
break;
@@ -665,8 +665,7 @@
}
LIR* MipsMir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_src, RegStorage r_src_hi,
- OpSize size, int s_reg) {
+ int displacement, RegStorage r_src, OpSize size, int s_reg) {
LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for MIPS";
return NULL;
}
@@ -677,8 +676,7 @@
}
LIR* MipsMir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_dest, RegStorage r_dest_hi,
- OpSize size, int s_reg) {
+ int displacement, RegStorage r_dest, OpSize size, int s_reg) {
LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for MIPS";
return NULL;
}
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index b2362fc..f5d71c4 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -25,20 +25,21 @@
/* Mark a temp register as dead. Does not affect allocation state. */
inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
- if (p->is_temp) {
- DCHECK(!(p->live && p->dirty)) << "Live & dirty temp in clobber";
- p->live = false;
- p->s_reg = INVALID_SREG;
- p->def_start = NULL;
- p->def_end = NULL;
- if (p->pair) {
- p->pair = false;
- p = GetRegInfo(p->partner);
- p->pair = false;
- p->live = false;
- p->s_reg = INVALID_SREG;
- p->def_start = NULL;
- p->def_end = NULL;
+ if (p->IsTemp()) {
+ DCHECK(!(p->IsLive() && p->IsDirty())) << "Live & dirty temp in clobber";
+ p->SetIsLive(false);
+ p->SetSReg(INVALID_SREG);
+ p->ResetDefBody();
+ if (p->IsWide()) {
+ p->SetIsWide(false);
+ if (p->GetReg() != p->Partner()) {
+ // Register pair - deal with the other half.
+ p = GetRegInfo(p->Partner());
+ p->SetIsWide(false);
+ p->SetIsLive(false);
+ p->SetSReg(INVALID_SREG);
+ p->ResetDefBody();
+ }
}
}
}
@@ -143,7 +144,9 @@
* Mark the corresponding bit(s).
*/
inline void Mir2Lir::SetupRegMask(uint64_t* mask, int reg) {
- *mask |= GetRegMaskCommon(reg);
+ DCHECK_EQ((reg & ~RegStorage::kRegValMask), 0);
+ DCHECK(reginfo_map_.Get(reg) != nullptr) << "No info for 0x" << reg;
+ *mask |= reginfo_map_.Get(reg)->DefUseMask();
}
/*
@@ -228,9 +231,11 @@
SetupTargetResourceMasks(lir, flags);
}
-inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(int reg) {
- DCHECK(reginfo_map_.Get(reg) != NULL);
- return reginfo_map_.Get(reg);
+inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(RegStorage reg) {
+ RegisterInfo* res = reg.IsPair() ? reginfo_map_.Get(reg.GetLowReg()) :
+ reginfo_map_.Get(reg.GetReg());
+ DCHECK(res != nullptr);
+ return res;
}
} // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 6c5279e..c9e1950 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -286,7 +286,7 @@
// Prep Src and Dest locations.
int next_sreg = 0;
int next_loc = 0;
- uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+ uint64_t attrs = MIRGraph::GetDataFlowAttributes(opcode);
rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
if (attrs & DF_UA) {
if (attrs & DF_A_WIDE) {
@@ -991,8 +991,7 @@
if (cu_->disable_opt & (1 << kTrackLiveTemps)) {
ClobberAllRegs();
// Reset temp allocation to minimize differences when A/B testing.
- reg_pool_->next_core_reg = 0;
- reg_pool_->next_fp_reg = 0;
+ reg_pool_->ResetNextTemp();
}
if (cu_->disable_opt & (1 << kSuppressLoads)) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 9283a29..cb4396f 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -241,32 +241,151 @@
};
/*
- * Data structure tracking the mapping between a Dalvik register (pair) and a
- * native register (pair). The idea is to reuse the previously loaded value
- * if possible, otherwise to keep the value in a native register as long as
- * possible.
+ * Data structure tracking the mapping detween a Dalvik value (32 or 64 bits)
+ * and native register storage. The primary purpose is to reuse previuosly
+ * loaded values, if possible, and otherwise to keep the value in register
+ * storage as long as possible.
+ *
+ * NOTE 1: wide_value refers to the width of the Dalvik value contained in
+ * this register (or pair). For example, a 64-bit register containing a 32-bit
+ * Dalvik value would have wide_value==false even though the storage container itself
+ * is wide. Similarly, a 32-bit register containing half of a 64-bit Dalvik value
+ * would have wide_value==true (and additionally would have its partner field set to the
+ * other half whose wide_value field would also be true.
+ *
+ * NOTE 2: In the case of a register pair, you can determine which of the partners
+ * is the low half by looking at the s_reg names. The high s_reg will equal low_sreg + 1.
+ *
+ * NOTE 3: In the case of a 64-bit register holding a Dalvik wide value, wide_value
+ * will be true and partner==self. s_reg refers to the low-order word of the Dalvik
+ * value, and the s_reg of the high word is implied (s_reg + 1).
+ *
+ * NOTE 4: The reg and is_temp fields should always be correct. If is_temp is false no
+ * other fields have meaning. [perhaps not true, wide should work for promoted regs?]
+ * If is_temp==true and live==false, no other fields have
+ * meaning. If is_temp==true and live==true, wide_value, partner, dirty, s_reg, def_start
+ * and def_end describe the relationship between the temp register/register pair and
+ * the Dalvik value[s] described by s_reg/s_reg+1.
+ *
+ * The fields used_storage, master_storage and storage_mask are used to track allocation
+ * in light of potential aliasing. For example, consider Arm's d2, which overlaps s4 & s5.
+ * d2's storage mask would be 0x00000003, the two low-order bits denoting 64 bits of
+ * storage use. For s4, it would be 0x0000001; for s5 0x00000002. These values should not
+ * change once initialized. The "used_storage" field tracks current allocation status.
+ * Although each record contains this field, only the field from the largest member of
+ * an aliased group is used. In our case, it would be d2's. The master_storage pointer
+ * of d2, s4 and s5 would all point to d2's used_storage field. Each bit in a used_storage
+ * represents 32 bits of storage. d2's used_storage would be initialized to 0xfffffffc.
+ * Then, if we wanted to determine whether s4 could be allocated, we would "and"
+ * s4's storage_mask with s4's *master_storage. If the result is zero, s4 is free and
+ * to allocate: *master_storage |= storage_mask. To free, *master_storage &= ~storage_mask.
+ *
+ * For an X86 vector register example, storage_mask would be:
+ * 0x00000001 for 32-bit view of xmm1
+ * 0x00000003 for 64-bit view of xmm1
+ * 0x0000000f for 128-bit view of xmm1
+ * 0x000000ff for 256-bit view of ymm1 // future expansion, if needed
+ * 0x0000ffff for 512-bit view of ymm1 // future expansion, if needed
+ * 0xffffffff for 1024-bit view of ymm1 // future expansion, if needed
+ *
+ * NOTE: the x86 usage is still somewhat in flux. There are competing notions of how
+ * to treat xmm registers:
+ * 1. Treat them all as 128-bits wide, but denote how much data used via bytes field.
+ * o This more closely matches reality, but means you'd need to be able to get
+ * to the associated RegisterInfo struct to figure out how it's being used.
+ * o This is how 64-bit core registers will be used - always 64 bits, but the
+ * "bytes" field will be 4 for 32-bit usage and 8 for 64-bit usage.
+ * 2. View the xmm registers based on contents.
+ * o A single in a xmm2 register would be k32BitVector, while a double in xmm2 would
+ * be a k64BitVector.
+ * o Note that the two uses above would be considered distinct registers (but with
+ * the aliasing mechanism, we could detect interference).
+ * o This is how aliased double and single float registers will be handled on
+ * Arm and MIPS.
+ * Working plan is, for all targets, to follow mechanism 1 for 64-bit core registers, and
+ * mechanism 2 for aliased float registers and x86 vector registers.
*/
- struct RegisterInfo {
- int reg; // Reg number
- bool in_use; // Has it been allocated?
- bool is_temp; // Can allocate as temp?
- bool pair; // Part of a register pair?
- int partner; // If pair, other reg of pair.
- bool live; // Is there an associated SSA name?
- bool dirty; // If live, is it dirty?
- int s_reg; // Name of live value.
- LIR *def_start; // Starting inst in last def sequence.
- LIR *def_end; // Ending inst in last def sequence.
+ class RegisterInfo {
+ public:
+ RegisterInfo(RegStorage r, uint64_t mask = ENCODE_ALL);
+ ~RegisterInfo() {}
+ static void* operator new(size_t size, ArenaAllocator* arena) {
+ return arena->Alloc(size, kArenaAllocRegAlloc);
+ }
+
+ bool InUse() { return (storage_mask_ & master_->used_storage_) != 0; }
+ void MarkInUse() { master_->used_storage_ |= storage_mask_; }
+ void MarkFree() { master_->used_storage_ &= ~storage_mask_; }
+ RegStorage GetReg() { return reg_; }
+ void SetReg(RegStorage reg) { reg_ = reg; }
+ bool IsTemp() { return is_temp_; }
+ void SetIsTemp(bool val) { is_temp_ = val; }
+ bool IsWide() { return wide_value_; }
+ void SetIsWide(bool val) { wide_value_ = val; }
+ bool IsLive() { return live_; }
+ void SetIsLive(bool val) { live_ = val; }
+ bool IsDirty() { return dirty_; }
+ void SetIsDirty(bool val) { dirty_ = val; }
+ RegStorage Partner() { return partner_; }
+ void SetPartner(RegStorage partner) { partner_ = partner; }
+ int SReg() { return s_reg_; }
+ void SetSReg(int s_reg) { s_reg_ = s_reg; }
+ uint64_t DefUseMask() { return def_use_mask_; }
+ void SetDefUseMask(uint64_t def_use_mask) { def_use_mask_ = def_use_mask; }
+ RegisterInfo* Master() { return master_; }
+ void SetMaster(RegisterInfo* master) { master_ = master; }
+ uint32_t StorageMask() { return storage_mask_; }
+ void SetStorageMask(uint32_t storage_mask) { storage_mask_ = storage_mask; }
+ LIR* DefStart() { return def_start_; }
+ void SetDefStart(LIR* def_start) { def_start_ = def_start; }
+ LIR* DefEnd() { return def_end_; }
+ void SetDefEnd(LIR* def_end) { def_end_ = def_end; }
+ void ResetDefBody() { def_start_ = def_end_ = nullptr; }
+
+
+ private:
+ RegStorage reg_;
+ bool is_temp_; // Can allocate as temp?
+ bool wide_value_; // Holds a Dalvik wide value (either itself, or part of a pair).
+ bool live_; // Is there an associated SSA name?
+ bool dirty_; // If live, is it dirty?
+ RegStorage partner_; // If wide_value, other reg of pair or self if 64-bit register.
+ int s_reg_; // Name of live value.
+ uint64_t def_use_mask_; // Resources for this element.
+ uint32_t used_storage_; // 1 bit per 4 bytes of storage. Unused by aliases.
+ RegisterInfo* master_; // Pointer to controlling storage mask.
+ uint32_t storage_mask_; // Track allocation of sub-units.
+ LIR *def_start_; // Starting inst in last def sequence.
+ LIR *def_end_; // Ending inst in last def sequence.
};
- struct RegisterPool {
- int num_core_regs;
- RegisterInfo *core_regs;
- int next_core_reg;
- int num_fp_regs;
- RegisterInfo *FPRegs;
- int next_fp_reg;
- };
+ class RegisterPool {
+ public:
+ RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena, const std::vector<RegStorage>& core_regs,
+ const std::vector<RegStorage>& sp_regs, const std::vector<RegStorage>& dp_regs,
+ const std::vector<RegStorage>& reserved_regs,
+ const std::vector<RegStorage>& core_temps,
+ const std::vector<RegStorage>& sp_temps,
+ const std::vector<RegStorage>& dp_temps);
+ ~RegisterPool() {}
+ static void* operator new(size_t size, ArenaAllocator* arena) {
+ return arena->Alloc(size, kArenaAllocRegAlloc);
+ }
+ void ResetNextTemp() {
+ next_core_reg_ = 0;
+ next_sp_reg_ = 0;
+ next_dp_reg_ = 0;
+ }
+ GrowableArray<RegisterInfo*> core_regs_;
+ int next_core_reg_;
+ GrowableArray<RegisterInfo*> sp_regs_; // Single precision float.
+ int next_sp_reg_;
+ GrowableArray<RegisterInfo*> dp_regs_; // Double precision float.
+ int next_dp_reg_;
+
+ private:
+ Mir2Lir* const m2l_;
+ };
struct PromotionMap {
RegLocationType core_location:3;
@@ -339,7 +458,14 @@
return *reinterpret_cast<const int32_t*>(switch_data);
}
- RegisterClass oat_reg_class_by_size(OpSize size) {
+ /*
+ * TODO: this is a trace JIT vestige, and its use should be reconsidered. At the time
+ * it was introduced, it was intended to be a quick best guess of type without having to
+ * take the time to do type analysis. Currently, though, we have a much better idea of
+ * the types of Dalvik virtual registers. Instead of using this for a best guess, why not
+ * just use our knowledge of type to select the most appropriate register class?
+ */
+ RegisterClass RegClassBySize(OpSize size) {
return (size == kUnsignedHalf || size == kSignedHalf || size == kUnsignedByte ||
size == kSignedByte) ? kCoreReg : kAnyReg;
}
@@ -459,75 +585,63 @@
// Shared by all targets - implemented in ralloc_util.cc
int GetSRegHi(int lowSreg);
- bool oat_live_out(int s_reg);
- int oatSSASrc(MIR* mir, int num);
+ bool LiveOut(int s_reg);
void SimpleRegAlloc();
void ResetRegPool();
- void CompilerInitPool(RegisterInfo* regs, int* reg_nums, int num);
- void DumpRegPool(RegisterInfo* p, int num_regs);
+ void CompilerInitPool(RegisterInfo* info, RegStorage* regs, int num);
+ void DumpRegPool(GrowableArray<RegisterInfo*>* regs);
void DumpCoreRegPool();
void DumpFpRegPool();
+ void DumpRegPools();
/* Mark a temp register as dead. Does not affect allocation state. */
- void Clobber(int reg) {
- ClobberBody(GetRegInfo(reg));
- }
void Clobber(RegStorage reg);
- void ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg);
+ void ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg);
void ClobberSReg(int s_reg);
int SRegToPMap(int s_reg);
void RecordCorePromotion(RegStorage reg, int s_reg);
RegStorage AllocPreservedCoreReg(int s_reg);
- void RecordFpPromotion(RegStorage reg, int s_reg);
+ void RecordSinglePromotion(RegStorage reg, int s_reg);
+ void RecordDoublePromotion(RegStorage reg, int s_reg);
RegStorage AllocPreservedSingle(int s_reg);
- RegStorage AllocPreservedDouble(int s_reg);
- RegStorage AllocTempBody(RegisterInfo* p, int num_regs, int* next_temp, bool required);
- virtual RegStorage AllocTempDouble();
+ virtual RegStorage AllocPreservedDouble(int s_reg);
+ RegStorage AllocTempBody(GrowableArray<RegisterInfo*> ®s, int* next_temp, bool required);
RegStorage AllocFreeTemp();
RegStorage AllocTemp();
- RegStorage AllocTempFloat();
- RegisterInfo* AllocLiveBody(RegisterInfo* p, int num_regs, int s_reg);
- RegisterInfo* AllocLive(int s_reg, int reg_class);
- void FreeTemp(int reg);
+ RegStorage AllocTempSingle();
+ RegStorage AllocTempDouble();
+ void FlushReg(RegStorage reg);
+ void FlushRegWide(RegStorage reg);
+ RegStorage AllocLiveReg(int s_reg, int reg_class, bool wide);
+ RegStorage FindLiveReg(GrowableArray<RegisterInfo*> ®s, int s_reg);
void FreeTemp(RegStorage reg);
- RegisterInfo* IsLive(int reg);
bool IsLive(RegStorage reg);
- RegisterInfo* IsTemp(int reg);
bool IsTemp(RegStorage reg);
- RegisterInfo* IsPromoted(int reg);
bool IsPromoted(RegStorage reg);
- bool IsDirty(int reg);
bool IsDirty(RegStorage reg);
- void LockTemp(int reg);
void LockTemp(RegStorage reg);
- void ResetDef(int reg);
void ResetDef(RegStorage reg);
- void NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2);
+ void NullifyRange(RegStorage reg, int s_reg);
void MarkDef(RegLocation rl, LIR *start, LIR *finish);
void MarkDefWide(RegLocation rl, LIR *start, LIR *finish);
RegLocation WideToNarrow(RegLocation rl);
void ResetDefLoc(RegLocation rl);
- virtual void ResetDefLocWide(RegLocation rl);
+ void ResetDefLocWide(RegLocation rl);
void ResetDefTracking();
void ClobberAllRegs();
void FlushSpecificReg(RegisterInfo* info);
- void FlushAllRegsBody(RegisterInfo* info, int num_regs);
void FlushAllRegs();
bool RegClassMatches(int reg_class, RegStorage reg);
- void MarkLive(RegStorage reg, int s_reg);
- void MarkTemp(int reg);
+ void MarkLive(RegLocation loc);
+ void MarkLiveReg(RegStorage reg, int s_reg);
void MarkTemp(RegStorage reg);
- void UnmarkTemp(int reg);
void UnmarkTemp(RegStorage reg);
- void MarkPair(int low_reg, int high_reg);
+ void MarkWide(RegStorage reg);
void MarkClean(RegLocation loc);
void MarkDirty(RegLocation loc);
- void MarkInUse(int reg);
void MarkInUse(RegStorage reg);
- void CopyRegInfo(int new_reg, int old_reg);
- void CopyRegInfo(RegStorage new_reg, RegStorage old_reg);
bool CheckCorePoolSanity();
RegLocation UpdateLoc(RegLocation loc);
- virtual RegLocation UpdateLocWide(RegLocation loc);
+ RegLocation UpdateLocWide(RegLocation loc);
RegLocation UpdateRawLoc(RegLocation loc);
/**
@@ -538,7 +652,7 @@
* @param update Whether the liveness information should be updated.
* @return Returns the properly typed temporary in physical register pairs.
*/
- virtual RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
+ RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
/**
* @brief Used to load register location into a typed temporary.
@@ -547,7 +661,7 @@
* @param update Whether the liveness information should be updated.
* @return Returns the properly typed temporary in physical register.
*/
- virtual RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
+ RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
void CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs);
void DumpCounts(const RefCounts* arr, int size, const char* msg);
@@ -556,7 +670,7 @@
int SRegOffset(int s_reg);
RegLocation GetReturnWide(bool is_double);
RegLocation GetReturn(bool is_float);
- RegisterInfo* GetRegInfo(int reg);
+ RegisterInfo* GetRegInfo(RegStorage reg);
// Shared by all targets - implemented in gen_common.cc.
void AddIntrinsicSlowPath(CallInfo* info, LIR* branch, LIR* resume = nullptr);
@@ -868,8 +982,8 @@
virtual LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
int scale, OpSize size) = 0;
virtual LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_dest, RegStorage r_dest_hi,
- OpSize size, int s_reg) = 0;
+ int displacement, RegStorage r_dest, OpSize size,
+ int s_reg) = 0;
virtual LIR* LoadConstantNoClobber(RegStorage r_dest, int value) = 0;
virtual LIR* LoadConstantWide(RegStorage r_dest, int64_t value) = 0;
virtual LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
@@ -878,18 +992,13 @@
virtual LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
int scale, OpSize size) = 0;
virtual LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_src, RegStorage r_src_hi,
- OpSize size, int s_reg) = 0;
+ int displacement, RegStorage r_src, OpSize size,
+ int s_reg) = 0;
virtual void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) = 0;
// Required for target - register utilities.
- virtual bool IsFpReg(int reg) = 0;
- virtual bool IsFpReg(RegStorage reg) = 0;
- virtual bool SameRegType(int reg1, int reg2) = 0;
virtual RegStorage AllocTypedTemp(bool fp_hint, int reg_class) = 0;
virtual RegStorage AllocTypedTempWide(bool fp_hint, int reg_class) = 0;
- // TODO: elminate S2d.
- virtual int S2d(int low_reg, int high_reg) = 0;
virtual RegStorage TargetReg(SpecialTargetRegister reg) = 0;
virtual RegStorage GetArgMappingToPhysicalReg(int arg_num) = 0;
virtual RegLocation GetReturnAlt() = 0;
@@ -898,17 +1007,14 @@
virtual RegLocation LocCReturnDouble() = 0;
virtual RegLocation LocCReturnFloat() = 0;
virtual RegLocation LocCReturnWide() = 0;
- // TODO: use to reduce/eliminate xx_FPREG() macro use.
- virtual uint32_t FpRegMask() = 0;
- virtual uint64_t GetRegMaskCommon(int reg) = 0;
+ virtual uint64_t GetRegMaskCommon(RegStorage reg) = 0;
virtual void AdjustSpillMask() = 0;
virtual void ClobberCallerSave() = 0;
- virtual void FlushReg(RegStorage reg) = 0;
- virtual void FlushRegWide(RegStorage reg) = 0;
virtual void FreeCallTemps() = 0;
virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) = 0;
virtual void LockCallTemps() = 0;
- virtual void MarkPreservedSingle(int v_reg, int reg) = 0;
+ virtual void MarkPreservedSingle(int v_reg, RegStorage reg) = 0;
+ virtual void MarkPreservedDouble(int v_reg, RegStorage reg) = 0;
virtual void CompilerInitializeRegAlloc() = 0;
// Required for target - miscellaneous.
@@ -1199,11 +1305,6 @@
private:
void ClobberBody(RegisterInfo* p);
- void ResetDefBody(RegisterInfo* p) {
- p->def_start = NULL;
- p->def_end = NULL;
- }
-
void SetCurrentDexPc(DexOffset dexpc) {
current_dalvik_offset_ = dexpc;
}
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 6455572..a39611e 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -30,7 +30,7 @@
void Mir2Lir::ResetRegPool() {
GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
- info->in_use = false;
+ info->MarkFree();
}
// Reset temp tracking sanity check.
if (kIsDebugBuild) {
@@ -38,66 +38,124 @@
}
}
- /*
- * Set up temp & preserved register pools specialized by target.
- * Note: num_regs may be zero.
- */
-void Mir2Lir::CompilerInitPool(RegisterInfo* regs, int* reg_nums, int num) {
- for (int i = 0; i < num; i++) {
- uint32_t reg_number = reg_nums[i];
- regs[i].reg = reg_number;
- regs[i].in_use = false;
- regs[i].is_temp = false;
- regs[i].pair = false;
- regs[i].live = false;
- regs[i].dirty = false;
- regs[i].s_reg = INVALID_SREG;
- size_t map_size = reginfo_map_.Size();
- if (reg_number >= map_size) {
- for (uint32_t i = 0; i < ((reg_number - map_size) + 1); i++) {
- reginfo_map_.Insert(NULL);
- }
- }
- reginfo_map_.Put(reg_number, ®s[i]);
+Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask)
+ : reg_(r), is_temp_(false), wide_value_(false), live_(false),
+ dirty_(false), partner_(r), s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
+ switch (r.StorageSize()) {
+ case 0: storage_mask_ = 0xffffffff; break;
+ case 4: storage_mask_ = 0x00000001; break;
+ case 8: storage_mask_ = 0x00000003; break;
+ case 16: storage_mask_ = 0x0000000f; break;
+ case 32: storage_mask_ = 0x000000ff; break;
+ case 64: storage_mask_ = 0x0000ffff; break;
+ case 128: storage_mask_ = 0xffffffff; break;
}
+ used_storage_ = r.Valid() ? ~storage_mask_ : storage_mask_;
}
-void Mir2Lir::DumpRegPool(RegisterInfo* p, int num_regs) {
+Mir2Lir::RegisterPool::RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena,
+ const std::vector<RegStorage>& core_regs,
+ const std::vector<RegStorage>& sp_regs,
+ const std::vector<RegStorage>& dp_regs,
+ const std::vector<RegStorage>& reserved_regs,
+ const std::vector<RegStorage>& core_temps,
+ const std::vector<RegStorage>& sp_temps,
+ const std::vector<RegStorage>& dp_temps) :
+ core_regs_(arena, core_regs.size()), next_core_reg_(0), sp_regs_(arena, sp_regs.size()),
+ next_sp_reg_(0), dp_regs_(arena, dp_regs.size()), next_dp_reg_(0), m2l_(m2l) {
+ // Initialize the fast lookup map.
+ m2l_->reginfo_map_.Reset();
+ m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
+ for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
+ m2l_->reginfo_map_.Insert(nullptr);
+ }
+
+ // Construct the register pool.
+ for (RegStorage reg : core_regs) {
+ RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
+ m2l_->reginfo_map_.Put(reg.GetReg(), info);
+ core_regs_.Insert(info);
+ }
+ for (RegStorage reg : sp_regs) {
+ RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
+ m2l_->reginfo_map_.Put(reg.GetReg(), info);
+ sp_regs_.Insert(info);
+ }
+ for (RegStorage reg : dp_regs) {
+ RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
+ m2l_->reginfo_map_.Put(reg.GetReg(), info);
+ dp_regs_.Insert(info);
+ }
+
+ // Keep special registers from being allocated.
+ for (RegStorage reg : reserved_regs) {
+ m2l_->MarkInUse(reg);
+ }
+
+ // Mark temp regs - all others not in use can be used for promotion
+ for (RegStorage reg : core_temps) {
+ m2l_->MarkTemp(reg);
+ }
+ for (RegStorage reg : sp_temps) {
+ m2l_->MarkTemp(reg);
+ }
+ for (RegStorage reg : dp_temps) {
+ m2l_->MarkTemp(reg);
+ }
+
+ // Add an entry for InvalidReg with zero'd mask.
+ RegisterInfo* invalid_reg = new (arena) RegisterInfo(RegStorage::InvalidReg(), 0);
+ m2l_->reginfo_map_.Put(RegStorage::InvalidReg().GetReg(), invalid_reg);
+}
+
+void Mir2Lir::DumpRegPool(GrowableArray<RegisterInfo*>* regs) {
LOG(INFO) << "================================================";
- for (int i = 0; i < num_regs; i++) {
+ GrowableArray<RegisterInfo*>::Iterator it(regs);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
LOG(INFO) << StringPrintf(
- "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d",
- p[i].reg, p[i].is_temp, p[i].in_use, p[i].pair, p[i].partner,
- p[i].live, p[i].dirty, p[i].s_reg);
+ "R[%d:%d:%c]: T:%d, U:%d, W:%d, p:%d, LV:%d, D:%d, SR:%d, DEF:%d",
+ info->GetReg().GetReg(), info->GetReg().GetRegNum(), info->GetReg().IsFloat() ? 'f' : 'c',
+ info->IsTemp(), info->InUse(), info->IsWide(), info->Partner().GetReg(), info->IsLive(),
+ info->IsDirty(), info->SReg(), info->DefStart() != nullptr);
}
LOG(INFO) << "================================================";
}
void Mir2Lir::DumpCoreRegPool() {
- DumpRegPool(reg_pool_->core_regs, reg_pool_->num_core_regs);
+ DumpRegPool(®_pool_->core_regs_);
}
void Mir2Lir::DumpFpRegPool() {
- DumpRegPool(reg_pool_->FPRegs, reg_pool_->num_fp_regs);
+ DumpRegPool(®_pool_->sp_regs_);
+ DumpRegPool(®_pool_->dp_regs_);
+}
+
+void Mir2Lir::DumpRegPools() {
+ LOG(INFO) << "Core registers";
+ DumpCoreRegPool();
+ LOG(INFO) << "FP registers";
+ DumpFpRegPool();
}
void Mir2Lir::Clobber(RegStorage reg) {
if (reg.IsPair()) {
- ClobberBody(GetRegInfo(reg.GetLowReg()));
- ClobberBody(GetRegInfo(reg.GetHighReg()));
+ ClobberBody(GetRegInfo(reg.GetLow()));
+ ClobberBody(GetRegInfo(reg.GetHigh()));
} else {
- ClobberBody(GetRegInfo(reg.GetReg()));
+ ClobberBody(GetRegInfo(reg));
}
}
-void Mir2Lir::ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg) {
- for (int i = 0; i< num_regs; i++) {
- if (p[i].s_reg == s_reg) {
- if (p[i].is_temp) {
- p[i].live = false;
+void Mir2Lir::ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg) {
+ GrowableArray<RegisterInfo*>::Iterator it(regs);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if ((info->SReg() == s_reg) ||
+ (info->IsWide() && (GetRegInfo(info->Partner())->SReg() == s_reg))) {
+ // NOTE: a single s_reg may appear multiple times, so we can't short-circuit.
+ if (info->IsTemp()) {
+ info->SetIsLive(false);
}
- p[i].def_start = NULL;
- p[i].def_end = NULL;
+ info->ResetDefBody();
}
}
}
@@ -114,14 +172,17 @@
* addressed.
*/
void Mir2Lir::ClobberSReg(int s_reg) {
- /* Reset live temp tracking sanity checker */
- if (kIsDebugBuild) {
- if (s_reg == live_sreg_) {
- live_sreg_ = INVALID_SREG;
+ if (s_reg != INVALID_SREG) {
+ /* Reset live temp tracking sanity checker */
+ if (kIsDebugBuild) {
+ if (s_reg == live_sreg_) {
+ live_sreg_ = INVALID_SREG;
+ }
}
+ ClobberSRegBody(®_pool_->core_regs_, s_reg);
+ ClobberSRegBody(®_pool_->sp_regs_, s_reg);
+ ClobberSRegBody(®_pool_->dp_regs_, s_reg);
}
- ClobberSRegBody(reg_pool_->core_regs, reg_pool_->num_core_regs, s_reg);
- ClobberSRegBody(reg_pool_->FPRegs, reg_pool_->num_fp_regs, s_reg);
}
/*
@@ -153,11 +214,12 @@
}
}
+// TODO: refactor following Alloc/Record routines - much commonality.
void Mir2Lir::RecordCorePromotion(RegStorage reg, int s_reg) {
int p_map_idx = SRegToPMap(s_reg);
int v_reg = mir_graph_->SRegToVReg(s_reg);
- int reg_num = reg.GetReg();
- GetRegInfo(reg_num)->in_use = true;
+ int reg_num = reg.GetRegNum();
+ GetRegInfo(reg)->MarkInUse();
core_spill_mask_ |= (1 << reg_num);
// Include reg for later sort
core_vmap_table_.push_back(reg_num << VREG_NUM_WIDTH | (v_reg & ((1 << VREG_NUM_WIDTH) - 1)));
@@ -166,13 +228,13 @@
promotion_map_[p_map_idx].core_reg = reg_num;
}
-/* Reserve a callee-save register. Return -1 if none available */
+/* Reserve a callee-save register. Return InvalidReg if none available */
RegStorage Mir2Lir::AllocPreservedCoreReg(int s_reg) {
RegStorage res;
- RegisterInfo* core_regs = reg_pool_->core_regs;
- for (int i = 0; i < reg_pool_->num_core_regs; i++) {
- if (!core_regs[i].is_temp && !core_regs[i].in_use) {
- res = RegStorage::Solo32(core_regs[i].reg);
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->core_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if (!info->IsTemp() && !info->InUse()) {
+ res = info->GetReg();
RecordCorePromotion(res, s_reg);
break;
}
@@ -180,100 +242,66 @@
return res;
}
-void Mir2Lir::RecordFpPromotion(RegStorage reg, int s_reg) {
+void Mir2Lir::RecordSinglePromotion(RegStorage reg, int s_reg) {
int p_map_idx = SRegToPMap(s_reg);
int v_reg = mir_graph_->SRegToVReg(s_reg);
- int reg_num = reg.GetReg();
- GetRegInfo(reg_num)->in_use = true;
- MarkPreservedSingle(v_reg, reg_num);
+ GetRegInfo(reg)->MarkInUse();
+ MarkPreservedSingle(v_reg, reg);
promotion_map_[p_map_idx].fp_location = kLocPhysReg;
- promotion_map_[p_map_idx].FpReg = reg_num;
+ promotion_map_[p_map_idx].FpReg = reg.GetReg();
}
-// Reserve a callee-save fp single register.
+// Reserve a callee-save sp single register.
RegStorage Mir2Lir::AllocPreservedSingle(int s_reg) {
RegStorage res;
- RegisterInfo* FPRegs = reg_pool_->FPRegs;
- for (int i = 0; i < reg_pool_->num_fp_regs; i++) {
- if (!FPRegs[i].is_temp && !FPRegs[i].in_use) {
- res = RegStorage::Solo32(FPRegs[i].reg);
- RecordFpPromotion(res, s_reg);
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if (!info->IsTemp() && !info->InUse()) {
+ res = info->GetReg();
+ RecordSinglePromotion(res, s_reg);
break;
}
}
return res;
}
-/*
- * Somewhat messy code here. We want to allocate a pair of contiguous
- * physical single-precision floating point registers starting with
- * an even numbered reg. It is possible that the paired s_reg (s_reg+1)
- * has already been allocated - try to fit if possible. Fail to
- * allocate if we can't meet the requirements for the pair of
- * s_reg<=sX[even] & (s_reg+1)<= sX+1.
- */
-// TODO: needs rewrite to support non-backed 64-bit float regs.
+void Mir2Lir::RecordDoublePromotion(RegStorage reg, int s_reg) {
+ int p_map_idx = SRegToPMap(s_reg);
+ int v_reg = mir_graph_->SRegToVReg(s_reg);
+ GetRegInfo(reg)->MarkInUse();
+ MarkPreservedDouble(v_reg, reg);
+ promotion_map_[p_map_idx].fp_location = kLocPhysReg;
+ promotion_map_[p_map_idx].FpReg = reg.GetReg();
+}
+
+// Reserve a callee-save dp solo register.
RegStorage Mir2Lir::AllocPreservedDouble(int s_reg) {
RegStorage res;
- int v_reg = mir_graph_->SRegToVReg(s_reg);
- int p_map_idx = SRegToPMap(s_reg);
- if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
- // Upper reg is already allocated. Can we fit?
- int high_reg = promotion_map_[p_map_idx+1].FpReg;
- if ((high_reg & 1) == 0) {
- // High reg is even - fail.
- return res; // Invalid.
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->dp_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if (!info->IsTemp() && !info->InUse()) {
+ res = info->GetReg();
+ RecordDoublePromotion(res, s_reg);
+ break;
}
- // Is the low reg of the pair free?
- RegisterInfo* p = GetRegInfo(high_reg-1);
- if (p->in_use || p->is_temp) {
- // Already allocated or not preserved - fail.
- return res; // Invalid.
- }
- // OK - good to go.
- res = RegStorage(RegStorage::k64BitPair, p->reg, p->reg + 1);
- p->in_use = true;
- DCHECK_EQ((res.GetReg() & 1), 0);
- MarkPreservedSingle(v_reg, res.GetReg());
- } else {
- RegisterInfo* FPRegs = reg_pool_->FPRegs;
- for (int i = 0; i < reg_pool_->num_fp_regs; i++) {
- if (!FPRegs[i].is_temp && !FPRegs[i].in_use &&
- ((FPRegs[i].reg & 0x1) == 0x0) &&
- !FPRegs[i+1].is_temp && !FPRegs[i+1].in_use &&
- ((FPRegs[i+1].reg & 0x1) == 0x1) &&
- (FPRegs[i].reg + 1) == FPRegs[i+1].reg) {
- res = RegStorage(RegStorage::k64BitPair, FPRegs[i].reg, FPRegs[i].reg+1);
- FPRegs[i].in_use = true;
- MarkPreservedSingle(v_reg, res.GetLowReg());
- FPRegs[i+1].in_use = true;
- DCHECK_EQ(res.GetLowReg() + 1, FPRegs[i+1].reg);
- MarkPreservedSingle(v_reg+1, res.GetLowReg() + 1);
- break;
- }
- }
- }
- if (res.Valid()) {
- promotion_map_[p_map_idx].fp_location = kLocPhysReg;
- promotion_map_[p_map_idx].FpReg = res.GetLowReg();
- promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
- promotion_map_[p_map_idx+1].FpReg = res.GetLowReg() + 1;
}
return res;
}
-RegStorage Mir2Lir::AllocTempBody(RegisterInfo* p, int num_regs, int* next_temp,
- bool required) {
+
+RegStorage Mir2Lir::AllocTempBody(GrowableArray<RegisterInfo*> ®s, int* next_temp, bool required) {
+ int num_regs = regs.Size();
int next = *next_temp;
for (int i = 0; i< num_regs; i++) {
if (next >= num_regs)
next = 0;
- if (p[next].is_temp && !p[next].in_use && !p[next].live) {
- Clobber(p[next].reg);
- p[next].in_use = true;
- p[next].pair = false;
+ RegisterInfo* info = regs.Get(next);
+ if (info->IsTemp() && !info->InUse() && !info->IsLive()) {
+ Clobber(info->GetReg());
+ info->MarkInUse();
+ info->SetIsWide(false);
*next_temp = next + 1;
- return RegStorage::Solo32(p[next].reg);
+ return info->GetReg();
}
next++;
}
@@ -281,201 +309,166 @@
for (int i = 0; i< num_regs; i++) {
if (next >= num_regs)
next = 0;
- if (p[next].is_temp && !p[next].in_use) {
- Clobber(p[next].reg);
- p[next].in_use = true;
- p[next].pair = false;
+ RegisterInfo* info = regs.Get(next);
+ if (info->IsTemp() && !info->InUse()) {
+ Clobber(info->GetReg());
+ info->MarkInUse();
+ info->SetIsWide(false);
*next_temp = next + 1;
- return RegStorage::Solo32(p[next].reg);
+ return info->GetReg();
}
next++;
}
if (required) {
CodegenDump();
- DumpRegPool(reg_pool_->core_regs,
- reg_pool_->num_core_regs);
+ DumpRegPools();
LOG(FATAL) << "No free temp registers";
}
return RegStorage::InvalidReg(); // No register available
}
-// REDO: too many assumptions.
-// Virtualize - this is target dependent.
-RegStorage Mir2Lir::AllocTempDouble() {
- RegisterInfo* p = reg_pool_->FPRegs;
- int num_regs = reg_pool_->num_fp_regs;
- /* Start looking at an even reg */
- int next = reg_pool_->next_fp_reg & ~0x1;
-
- // First try to avoid allocating live registers
- for (int i = 0; i < num_regs; i+=2) {
- if (next >= num_regs)
- next = 0;
- if ((p[next].is_temp && !p[next].in_use && !p[next].live) &&
- (p[next+1].is_temp && !p[next+1].in_use && !p[next+1].live)) {
- Clobber(p[next].reg);
- Clobber(p[next+1].reg);
- p[next].in_use = true;
- p[next+1].in_use = true;
- DCHECK_EQ((p[next].reg+1), p[next+1].reg);
- DCHECK_EQ((p[next].reg & 0x1), 0);
- reg_pool_->next_fp_reg = next + 2;
- if (reg_pool_->next_fp_reg >= num_regs) {
- reg_pool_->next_fp_reg = 0;
- }
- // FIXME: should return k64BitSolo.
- return RegStorage(RegStorage::k64BitPair, p[next].reg, p[next+1].reg);
- }
- next += 2;
- }
- next = reg_pool_->next_fp_reg & ~0x1;
-
- // No choice - find a pair and kill it.
- for (int i = 0; i < num_regs; i+=2) {
- if (next >= num_regs)
- next = 0;
- if (p[next].is_temp && !p[next].in_use && p[next+1].is_temp &&
- !p[next+1].in_use) {
- Clobber(p[next].reg);
- Clobber(p[next+1].reg);
- p[next].in_use = true;
- p[next+1].in_use = true;
- DCHECK_EQ((p[next].reg+1), p[next+1].reg);
- DCHECK_EQ((p[next].reg & 0x1), 0);
- reg_pool_->next_fp_reg = next + 2;
- if (reg_pool_->next_fp_reg >= num_regs) {
- reg_pool_->next_fp_reg = 0;
- }
- return RegStorage(RegStorage::k64BitPair, p[next].reg, p[next+1].reg);
- }
- next += 2;
- }
- LOG(FATAL) << "No free temp registers (pair)";
- return RegStorage::InvalidReg();
-}
-
/* Return a temp if one is available, -1 otherwise */
RegStorage Mir2Lir::AllocFreeTemp() {
- return AllocTempBody(reg_pool_->core_regs,
- reg_pool_->num_core_regs,
- ®_pool_->next_core_reg, false);
+ return AllocTempBody(reg_pool_->core_regs_, ®_pool_->next_core_reg_, false);
}
RegStorage Mir2Lir::AllocTemp() {
- return AllocTempBody(reg_pool_->core_regs,
- reg_pool_->num_core_regs,
- ®_pool_->next_core_reg, true);
+ return AllocTempBody(reg_pool_->core_regs_, ®_pool_->next_core_reg_, true);
}
-RegStorage Mir2Lir::AllocTempFloat() {
- return AllocTempBody(reg_pool_->FPRegs,
- reg_pool_->num_fp_regs,
- ®_pool_->next_fp_reg, true);
+RegStorage Mir2Lir::AllocTempSingle() {
+ RegStorage res = AllocTempBody(reg_pool_->sp_regs_, ®_pool_->next_sp_reg_, true);
+ DCHECK(res.IsSingle()) << "Reg: 0x" << std::hex << res.GetRawBits();
+ return res;
}
-Mir2Lir::RegisterInfo* Mir2Lir::AllocLiveBody(RegisterInfo* p, int num_regs, int s_reg) {
- if (s_reg == -1)
- return NULL;
- for (int i = 0; i < num_regs; i++) {
- if ((p[i].s_reg == s_reg) && p[i].live) {
- if (p[i].is_temp)
- p[i].in_use = true;
- return &p[i];
+RegStorage Mir2Lir::AllocTempDouble() {
+ RegStorage res = AllocTempBody(reg_pool_->dp_regs_, ®_pool_->next_dp_reg_, true);
+ DCHECK(res.IsDouble()) << "Reg: 0x" << std::hex << res.GetRawBits();
+ return res;
+}
+
+RegStorage Mir2Lir::FindLiveReg(GrowableArray<RegisterInfo*> ®s, int s_reg) {
+ RegStorage res;
+ GrowableArray<RegisterInfo*>::Iterator it(®s);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if ((info->SReg() == s_reg) && info->IsLive()) {
+ res = info->GetReg();
+ break;
}
}
- return NULL;
-}
-
-Mir2Lir::RegisterInfo* Mir2Lir::AllocLive(int s_reg, int reg_class) {
- RegisterInfo* res = NULL;
- switch (reg_class) {
- case kAnyReg:
- res = AllocLiveBody(reg_pool_->FPRegs,
- reg_pool_->num_fp_regs, s_reg);
- if (res)
- break;
- /* Intentional fallthrough */
- case kCoreReg:
- res = AllocLiveBody(reg_pool_->core_regs,
- reg_pool_->num_core_regs, s_reg);
- break;
- case kFPReg:
- res = AllocLiveBody(reg_pool_->FPRegs,
- reg_pool_->num_fp_regs, s_reg);
- break;
- default:
- LOG(FATAL) << "Invalid register type";
- }
return res;
}
-void Mir2Lir::FreeTemp(int reg) {
- RegisterInfo* p = GetRegInfo(reg);
- if (p->is_temp) {
- p->in_use = false;
+RegStorage Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) {
+ RegStorage reg;
+ // TODO: might be worth a sanity check here to verify at most 1 live reg per s_reg.
+ if ((reg_class == kAnyReg) || (reg_class == kFPReg)) {
+ reg = FindLiveReg(wide ? reg_pool_->dp_regs_ : reg_pool_->sp_regs_, s_reg);
}
- p->pair = false;
+ if (!reg.Valid() && (reg_class != kFPReg)) {
+ reg = FindLiveReg(reg_pool_->core_regs_, s_reg);
+ }
+ if (reg.Valid()) {
+ if (wide && reg.Is32Bit() && !reg.IsFloat()) {
+ // Only allow reg pairs for Core.
+ RegStorage high_reg = FindLiveReg(reg_pool_->core_regs_, s_reg + 1);
+ if (high_reg.Valid()) {
+ RegisterInfo* info_lo = GetRegInfo(reg);
+ RegisterInfo* info_hi = GetRegInfo(high_reg);
+ if (info_lo->IsTemp()) {
+ info_lo->MarkInUse();
+ }
+ if (info_hi->IsTemp()) {
+ info_hi->MarkInUse();
+ }
+ reg = RegStorage::MakeRegPair(reg, high_reg);
+ MarkWide(reg);
+ } else {
+ // Only half available - clobber.
+ Clobber(reg);
+ reg = RegStorage::InvalidReg();
+ }
+ }
+ if (reg.Valid() && !reg.IsPair()) {
+ RegisterInfo* info = GetRegInfo(reg);
+ if (info->IsTemp()) {
+ info->MarkInUse();
+ }
+ }
+ if (reg.Valid() && (wide != GetRegInfo(reg)->IsWide())) {
+ // Width mismatch - don't try to reuse.
+ Clobber(reg);
+ reg = RegStorage::InvalidReg();
+ }
+ }
+ return reg;
}
void Mir2Lir::FreeTemp(RegStorage reg) {
if (reg.IsPair()) {
- FreeTemp(reg.GetLowReg());
- FreeTemp(reg.GetHighReg());
+ FreeTemp(reg.GetLow());
+ FreeTemp(reg.GetHigh());
} else {
- FreeTemp(reg.GetReg());
+ RegisterInfo* p = GetRegInfo(reg);
+ if (p->IsTemp()) {
+ p->MarkFree();
+ p->SetIsWide(false);
+ p->SetPartner(reg);
+ }
}
}
-Mir2Lir::RegisterInfo* Mir2Lir::IsLive(int reg) {
- RegisterInfo* p = GetRegInfo(reg);
- return p->live ? p : NULL;
-}
-
bool Mir2Lir::IsLive(RegStorage reg) {
+ bool res;
if (reg.IsPair()) {
- return IsLive(reg.GetLowReg()) || IsLive(reg.GetHighReg());
+ RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+ res = p_lo->IsLive() || p_hi->IsLive();
} else {
- return IsLive(reg.GetReg());
+ RegisterInfo* p = GetRegInfo(reg);
+ res = p->IsLive();
}
-}
-
-Mir2Lir::RegisterInfo* Mir2Lir::IsTemp(int reg) {
- RegisterInfo* p = GetRegInfo(reg);
- return (p->is_temp) ? p : NULL;
+ return res;
}
bool Mir2Lir::IsTemp(RegStorage reg) {
+ bool res;
if (reg.IsPair()) {
- return IsTemp(reg.GetLowReg()) || IsTemp(reg.GetHighReg());
+ RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+ res = p_lo->IsTemp() || p_hi->IsTemp();
} else {
- return IsTemp(reg.GetReg());
+ RegisterInfo* p = GetRegInfo(reg);
+ res = p->IsTemp();
}
-}
-
-Mir2Lir::RegisterInfo* Mir2Lir::IsPromoted(int reg) {
- RegisterInfo* p = GetRegInfo(reg);
- return (p->is_temp) ? NULL : p;
+ return res;
}
bool Mir2Lir::IsPromoted(RegStorage reg) {
+ bool res;
if (reg.IsPair()) {
- return IsPromoted(reg.GetLowReg()) || IsPromoted(reg.GetHighReg());
+ RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+ res = !p_lo->IsTemp() || !p_hi->IsTemp();
} else {
- return IsPromoted(reg.GetReg());
+ RegisterInfo* p = GetRegInfo(reg);
+ res = !p->IsTemp();
}
-}
-
-bool Mir2Lir::IsDirty(int reg) {
- RegisterInfo* p = GetRegInfo(reg);
- return p->dirty;
+ return res;
}
bool Mir2Lir::IsDirty(RegStorage reg) {
+ bool res;
if (reg.IsPair()) {
- return IsDirty(reg.GetLowReg()) || IsDirty(reg.GetHighReg());
+ RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+ res = p_lo->IsDirty() || p_hi->IsDirty();
} else {
- return IsDirty(reg.GetReg());
+ RegisterInfo* p = GetRegInfo(reg);
+ res = p->IsDirty();
}
+ return res;
}
/*
@@ -483,35 +476,44 @@
* register. No check is made to see if the register was previously
* allocated. Use with caution.
*/
-void Mir2Lir::LockTemp(int reg) {
- RegisterInfo* p = GetRegInfo(reg);
- DCHECK(p->is_temp);
- p->in_use = true;
- p->live = false;
-}
-
void Mir2Lir::LockTemp(RegStorage reg) {
- DCHECK(!reg.IsPair());
- LockTemp(reg.GetReg());
-}
-
-void Mir2Lir::ResetDef(int reg) {
- ResetDefBody(GetRegInfo(reg));
+ DCHECK(IsTemp(reg));
+ if (reg.IsPair()) {
+ RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+ p_lo->MarkInUse();
+ p_lo->SetIsLive(false);
+ p_hi->MarkInUse();
+ p_hi->SetIsLive(false);
+ } else {
+ RegisterInfo* p = GetRegInfo(reg);
+ p->MarkInUse();
+ p->SetIsLive(false);
+ }
}
void Mir2Lir::ResetDef(RegStorage reg) {
- DCHECK(!reg.IsPair()); // Is this done? If so, do on both low and high.
- ResetDef(reg.GetReg());
+ if (reg.IsPair()) {
+ GetRegInfo(reg.GetLow())->ResetDefBody();
+ GetRegInfo(reg.GetHigh())->ResetDefBody();
+ } else {
+ GetRegInfo(reg)->ResetDefBody();
+ }
}
-void Mir2Lir::NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2) {
- if (start && finish) {
- LIR *p;
- DCHECK_EQ(s_reg1, s_reg2);
- for (p = start; ; p = p->next) {
+void Mir2Lir::NullifyRange(RegStorage reg, int s_reg) {
+ RegisterInfo* info = nullptr;
+ RegStorage rs = reg.IsPair() ? reg.GetLow() : reg;
+ if (IsTemp(rs)) {
+ info = GetRegInfo(reg);
+ }
+ if ((info != nullptr) && (info->DefStart() != nullptr) && (info->DefEnd() != nullptr)) {
+ DCHECK_EQ(info->SReg(), s_reg); // Make sure we're on the same page.
+ for (LIR* p = info->DefStart();; p = p->next) {
NopLIR(p);
- if (p == finish)
+ if (p == info->DefEnd()) {
break;
+ }
}
}
}
@@ -525,9 +527,9 @@
DCHECK(!rl.wide);
DCHECK(start && start->next);
DCHECK(finish);
- RegisterInfo* p = GetRegInfo(rl.reg.GetReg());
- p->def_start = start->next;
- p->def_end = finish;
+ RegisterInfo* p = GetRegInfo(rl.reg);
+ p->SetDefStart(start->next);
+ p->SetDefEnd(finish);
}
/*
@@ -539,28 +541,33 @@
DCHECK(rl.wide);
DCHECK(start && start->next);
DCHECK(finish);
- RegisterInfo* p = GetRegInfo(rl.reg.GetLowReg());
- ResetDef(rl.reg.GetHighReg()); // Only track low of pair
- p->def_start = start->next;
- p->def_end = finish;
+ RegisterInfo* p;
+ if (rl.reg.IsPair()) {
+ p = GetRegInfo(rl.reg.GetLow());
+ ResetDef(rl.reg.GetHigh()); // Only track low of pair
+ } else {
+ p = GetRegInfo(rl.reg);
+ }
+ p->SetDefStart(start->next);
+ p->SetDefEnd(finish);
}
RegLocation Mir2Lir::WideToNarrow(RegLocation rl) {
DCHECK(rl.wide);
if (rl.location == kLocPhysReg) {
- RegisterInfo* info_lo = GetRegInfo(rl.reg.GetLowReg());
- RegisterInfo* info_hi = GetRegInfo(rl.reg.GetHighReg());
- if (info_lo->is_temp) {
- info_lo->pair = false;
- info_lo->def_start = NULL;
- info_lo->def_end = NULL;
+ if (rl.reg.IsPair()) {
+ RegisterInfo* info_lo = GetRegInfo(rl.reg.GetLow());
+ RegisterInfo* info_hi = GetRegInfo(rl.reg.GetHigh());
+ if (info_lo->IsTemp()) {
+ info_lo->SetIsWide(false);
+ info_lo->ResetDefBody();
+ }
+ if (info_hi->IsTemp()) {
+ info_hi->SetIsWide(false);
+ info_hi->ResetDefBody();
+ }
+ rl.reg = rl.reg.GetLow();
}
- if (info_hi->is_temp) {
- info_hi->pair = false;
- info_hi->def_start = NULL;
- info_hi->def_end = NULL;
- }
- rl.reg = RegStorage::Solo32(rl.reg.GetLowReg());
}
rl.wide = false;
return rl;
@@ -568,220 +575,244 @@
void Mir2Lir::ResetDefLoc(RegLocation rl) {
DCHECK(!rl.wide);
- RegisterInfo* p = IsTemp(rl.reg.GetReg());
- if (p && !(cu_->disable_opt & (1 << kSuppressLoads))) {
- DCHECK(!p->pair);
- NullifyRange(p->def_start, p->def_end, p->s_reg, rl.s_reg_low);
+ if (IsTemp(rl.reg) && !(cu_->disable_opt & (1 << kSuppressLoads))) {
+ NullifyRange(rl.reg, rl.s_reg_low);
}
- ResetDef(rl.reg.GetReg());
+ ResetDef(rl.reg);
}
void Mir2Lir::ResetDefLocWide(RegLocation rl) {
DCHECK(rl.wide);
- RegisterInfo* p_low = IsTemp(rl.reg.GetLowReg());
- RegisterInfo* p_high = IsTemp(rl.reg.GetHighReg());
- if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) {
- DCHECK(p_low->pair);
- NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low);
+ // If pair, only track low reg of pair.
+ RegStorage rs = rl.reg.IsPair() ? rl.reg.GetLow() : rl.reg;
+ if (IsTemp(rs) && !(cu_->disable_opt & (1 << kSuppressLoads))) {
+ NullifyRange(rs, rl.s_reg_low);
}
- if (p_high && !(cu_->disable_opt & (1 << kSuppressLoads))) {
- DCHECK(p_high->pair);
- }
- ResetDef(rl.reg.GetLowReg());
- ResetDef(rl.reg.GetHighReg());
+ ResetDef(rs);
}
void Mir2Lir::ResetDefTracking() {
- for (int i = 0; i< reg_pool_->num_core_regs; i++) {
- ResetDefBody(®_pool_->core_regs[i]);
+ GrowableArray<RegisterInfo*>::Iterator core_it(®_pool_->core_regs_);
+ for (RegisterInfo* info = core_it.Next(); info != nullptr; info = core_it.Next()) {
+ info->ResetDefBody();
}
- for (int i = 0; i< reg_pool_->num_fp_regs; i++) {
- ResetDefBody(®_pool_->FPRegs[i]);
+ GrowableArray<RegisterInfo*>::Iterator sp_it(®_pool_->core_regs_);
+ for (RegisterInfo* info = sp_it.Next(); info != nullptr; info = sp_it.Next()) {
+ info->ResetDefBody();
+ }
+ GrowableArray<RegisterInfo*>::Iterator dp_it(®_pool_->core_regs_);
+ for (RegisterInfo* info = dp_it.Next(); info != nullptr; info = dp_it.Next()) {
+ info->ResetDefBody();
}
}
void Mir2Lir::ClobberAllRegs() {
GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
- info->live = false;
- info->s_reg = INVALID_SREG;
- info->def_start = NULL;
- info->def_end = NULL;
- info->pair = false;
+ info->SetIsLive(false);
+ info->SetSReg(INVALID_SREG);
+ info->ResetDefBody();
+ info->SetIsWide(false);
+ }
+}
+
+void Mir2Lir::FlushRegWide(RegStorage reg) {
+ if (reg.IsPair()) {
+ RegisterInfo* info1 = GetRegInfo(reg.GetLow());
+ RegisterInfo* info2 = GetRegInfo(reg.GetHigh());
+ DCHECK(info1 && info2 && info1->IsWide() && info2->IsWide() &&
+ (info1->Partner() == info2->GetReg()) && (info2->Partner() == info1->GetReg()));
+ if ((info1->IsLive() && info1->IsDirty()) || (info2->IsLive() && info2->IsDirty())) {
+ if (!(info1->IsTemp() && info2->IsTemp())) {
+ /* Should not happen. If it does, there's a problem in eval_loc */
+ LOG(FATAL) << "Long half-temp, half-promoted";
+ }
+
+ info1->SetIsDirty(false);
+ info2->SetIsDirty(false);
+ if (mir_graph_->SRegToVReg(info2->SReg()) < mir_graph_->SRegToVReg(info1->SReg())) {
+ info1 = info2;
+ }
+ int v_reg = mir_graph_->SRegToVReg(info1->SReg());
+ StoreBaseDispWide(TargetReg(kSp), VRegOffset(v_reg), reg);
+ }
+ } else {
+ RegisterInfo* info = GetRegInfo(reg);
+ if (info->IsLive() && info->IsDirty()) {
+ info->SetIsDirty(false);
+ int v_reg = mir_graph_->SRegToVReg(info->SReg());
+ StoreBaseDispWide(TargetReg(kSp), VRegOffset(v_reg), reg);
+ }
+ }
+}
+
+void Mir2Lir::FlushReg(RegStorage reg) {
+ DCHECK(!reg.IsPair());
+ RegisterInfo* info = GetRegInfo(reg);
+ if (info->IsLive() && info->IsDirty()) {
+ info->SetIsDirty(false);
+ int v_reg = mir_graph_->SRegToVReg(info->SReg());
+ StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, kWord);
}
}
void Mir2Lir::FlushSpecificReg(RegisterInfo* info) {
- if (info->pair) {
- FlushRegWide(RegStorage(RegStorage::k64BitPair, info->reg, info->partner));
+ if (info->IsWide()) {
+ FlushRegWide(info->GetReg());
} else {
- FlushReg(RegStorage::Solo32(info->reg));
- }
-}
-
-// Make sure nothing is live and dirty
-void Mir2Lir::FlushAllRegsBody(RegisterInfo* info, int num_regs) {
- for (int i = 0; i < num_regs; i++) {
- if (info[i].live && info[i].dirty) {
- FlushSpecificReg(&info[i]);
- }
+ FlushReg(info->GetReg());
}
}
void Mir2Lir::FlushAllRegs() {
- FlushAllRegsBody(reg_pool_->core_regs,
- reg_pool_->num_core_regs);
- FlushAllRegsBody(reg_pool_->FPRegs,
- reg_pool_->num_fp_regs);
- ClobberAllRegs();
+ GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ if (info->IsLive() && info->IsDirty()) {
+ FlushSpecificReg(info);
+ }
+ DCHECK(info->IsTemp());
+ info->SetIsLive(false);
+ info->SetSReg(INVALID_SREG);
+ info->ResetDefBody();
+ info->SetIsWide(false);
+ }
}
-// TUNING: rewrite all of this reg stuff. Probably use an attribute table
bool Mir2Lir::RegClassMatches(int reg_class, RegStorage reg) {
- int reg_num = reg.IsPair() ? reg.GetLowReg() : reg.GetReg();
if (reg_class == kAnyReg) {
return true;
} else if (reg_class == kCoreReg) {
- return !IsFpReg(reg_num);
+ return !reg.IsFloat();
} else {
- return IsFpReg(reg_num);
+ return reg.IsFloat();
}
}
-void Mir2Lir::MarkLive(RegStorage reg, int s_reg) {
- DCHECK(!reg.IsPair()); // Could be done - but would that be meaningful?
- RegisterInfo* info = GetRegInfo(reg.GetReg());
- if ((info->s_reg == s_reg) && info->live) {
- return; /* already live */
- } else if (s_reg != INVALID_SREG) {
+void Mir2Lir::MarkLiveReg(RegStorage reg, int s_reg) {
+ RegisterInfo* info = GetRegInfo(reg);
+ if ((info->SReg() == s_reg) && info->IsLive()) {
+ return; // Already live.
+ }
+ if (s_reg != INVALID_SREG) {
ClobberSReg(s_reg);
- if (info->is_temp) {
- info->live = true;
+ if (info->IsTemp()) {
+ info->SetIsLive(true);
}
} else {
- /* Can't be live if no associated s_reg */
- DCHECK(info->is_temp);
- info->live = false;
+ // Can't be live if no associated s_reg.
+ DCHECK(info->IsTemp());
+ info->SetIsLive(false);
}
- info->s_reg = s_reg;
+ info->SetSReg(s_reg);
}
-void Mir2Lir::MarkTemp(int reg) {
- RegisterInfo* info = GetRegInfo(reg);
- tempreg_info_.Insert(info);
- info->is_temp = true;
+void Mir2Lir::MarkLive(RegLocation loc) {
+ RegStorage reg = loc.reg;
+ int s_reg = loc.s_reg_low;
+ if (reg.IsPair()) {
+ MarkLiveReg(reg.GetLow(), s_reg);
+ MarkLiveReg(reg.GetHigh(), s_reg+1);
+ } else {
+ if (loc.wide) {
+ ClobberSReg(s_reg + 1);
+ }
+ MarkLiveReg(reg, s_reg);
+ }
}
void Mir2Lir::MarkTemp(RegStorage reg) {
DCHECK(!reg.IsPair());
- MarkTemp(reg.GetReg());
-}
-
-void Mir2Lir::UnmarkTemp(int reg) {
RegisterInfo* info = GetRegInfo(reg);
- tempreg_info_.Delete(info);
- info->is_temp = false;
+ tempreg_info_.Insert(info);
+ info->SetIsTemp(true);
}
void Mir2Lir::UnmarkTemp(RegStorage reg) {
DCHECK(!reg.IsPair());
- UnmarkTemp(reg.GetReg());
+ RegisterInfo* info = GetRegInfo(reg);
+ tempreg_info_.Delete(info);
+ info->SetIsTemp(false);
}
-void Mir2Lir::MarkPair(int low_reg, int high_reg) {
- DCHECK_NE(low_reg, high_reg);
- RegisterInfo* info_lo = GetRegInfo(low_reg);
- RegisterInfo* info_hi = GetRegInfo(high_reg);
- info_lo->pair = info_hi->pair = true;
- info_lo->partner = high_reg;
- info_hi->partner = low_reg;
-}
-
-void Mir2Lir::MarkClean(RegLocation loc) {
- if (loc.wide) {
- RegisterInfo* info = GetRegInfo(loc.reg.GetLowReg());
- info->dirty = false;
- info = GetRegInfo(loc.reg.GetHighReg());
- info->dirty = false;
+void Mir2Lir::MarkWide(RegStorage reg) {
+ if (reg.IsPair()) {
+ RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
+ info_lo->SetIsWide(true);
+ info_hi->SetIsWide(true);
+ info_lo->SetPartner(reg.GetHigh());
+ info_hi->SetPartner(reg.GetLow());
} else {
- RegisterInfo* info = GetRegInfo(loc.reg.GetReg());
- info->dirty = false;
+ RegisterInfo* info = GetRegInfo(reg);
+ info->SetIsWide(true);
+ info->SetPartner(reg);
}
}
+void Mir2Lir::MarkClean(RegLocation loc) {
+ if (loc.reg.IsPair()) {
+ RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
+ info->SetIsDirty(false);
+ info = GetRegInfo(loc.reg.GetHigh());
+ info->SetIsDirty(false);
+ } else {
+ RegisterInfo* info = GetRegInfo(loc.reg);
+ info->SetIsDirty(false);
+ }
+}
+
+// FIXME: need to verify rules/assumptions about how wide values are treated in 64BitSolos.
void Mir2Lir::MarkDirty(RegLocation loc) {
if (loc.home) {
// If already home, can't be dirty
return;
}
- if (loc.wide) {
- RegisterInfo* info = GetRegInfo(loc.reg.GetLowReg());
- info->dirty = true;
- info = GetRegInfo(loc.reg.GetHighReg());
- info->dirty = true;
+ if (loc.reg.IsPair()) {
+ RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
+ info->SetIsDirty(true);
+ info = GetRegInfo(loc.reg.GetHigh());
+ info->SetIsDirty(true);
} else {
- RegisterInfo* info = GetRegInfo(loc.reg.GetReg());
- info->dirty = true;
+ RegisterInfo* info = GetRegInfo(loc.reg);
+ info->SetIsDirty(true);
}
}
-void Mir2Lir::MarkInUse(int reg) {
- RegisterInfo* info = GetRegInfo(reg);
- info->in_use = true;
-}
-
void Mir2Lir::MarkInUse(RegStorage reg) {
if (reg.IsPair()) {
- MarkInUse(reg.GetLowReg());
- MarkInUse(reg.GetHighReg());
+ GetRegInfo(reg.GetLow())->MarkInUse();
+ GetRegInfo(reg.GetHigh())->MarkInUse();
} else {
- MarkInUse(reg.GetReg());
+ GetRegInfo(reg)->MarkInUse();
}
}
-void Mir2Lir::CopyRegInfo(int new_reg, int old_reg) {
- RegisterInfo* new_info = GetRegInfo(new_reg);
- RegisterInfo* old_info = GetRegInfo(old_reg);
- // Target temp, live, dirty status must not change
- bool is_temp = new_info->is_temp;
- bool live = new_info->live;
- bool dirty = new_info->dirty;
- *new_info = *old_info;
- // Restore target's temp, live, dirty status
- new_info->is_temp = is_temp;
- new_info->live = live;
- new_info->dirty = dirty;
- new_info->reg = new_reg;
-}
-
-void Mir2Lir::CopyRegInfo(RegStorage new_reg, RegStorage old_reg) {
- DCHECK(!new_reg.IsPair());
- DCHECK(!old_reg.IsPair());
- CopyRegInfo(new_reg.GetReg(), old_reg.GetReg());
-}
-
bool Mir2Lir::CheckCorePoolSanity() {
- for (static int i = 0; i < reg_pool_->num_core_regs; i++) {
- if (reg_pool_->core_regs[i].pair) {
- static int my_reg = reg_pool_->core_regs[i].reg;
- static int my_sreg = reg_pool_->core_regs[i].s_reg;
- static int partner_reg = reg_pool_->core_regs[i].partner;
- static RegisterInfo* partner = GetRegInfo(partner_reg);
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->core_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ RegStorage my_reg = info->GetReg();
+ if (info->IsWide() && my_reg.IsPair()) {
+ int my_sreg = info->SReg();
+ RegStorage partner_reg = info->Partner();
+ RegisterInfo* partner = GetRegInfo(partner_reg);
DCHECK(partner != NULL);
- DCHECK(partner->pair);
- DCHECK_EQ(my_reg, partner->partner);
- static int partner_sreg = partner->s_reg;
+ DCHECK(partner->IsWide());
+ DCHECK_EQ(my_reg.GetReg(), partner->Partner().GetReg());
+ int partner_sreg = partner->SReg();
if (my_sreg == INVALID_SREG) {
DCHECK_EQ(partner_sreg, INVALID_SREG);
} else {
int diff = my_sreg - partner_sreg;
- DCHECK((diff == -1) || (diff == 1));
+ DCHECK((diff == 0) || (diff == -1) || (diff == 1));
}
+ } else {
+ // TODO: add whatever sanity checks might be useful for 64BitSolo regs here.
+ // TODO: sanity checks for floating point pools?
}
- if (!reg_pool_->core_regs[i].live) {
- DCHECK(reg_pool_->core_regs[i].def_start == NULL);
- DCHECK(reg_pool_->core_regs[i].def_end == NULL);
+ if (!info->IsLive()) {
+ DCHECK(info->DefStart() == NULL);
+ DCHECK(info->DefEnd() == NULL);
}
}
return true;
@@ -796,80 +827,64 @@
* is a bit complex when dealing with FP regs. Examine code to see
* if it's worthwhile trying to be more clever here.
*/
-
RegLocation Mir2Lir::UpdateLoc(RegLocation loc) {
DCHECK(!loc.wide);
DCHECK(CheckCorePoolSanity());
if (loc.location != kLocPhysReg) {
DCHECK((loc.location == kLocDalvikFrame) ||
(loc.location == kLocCompilerTemp));
- RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg);
- if (info_lo) {
- if (info_lo->pair) {
- Clobber(info_lo->reg);
- Clobber(info_lo->partner);
- FreeTemp(info_lo->reg);
- } else {
- loc.reg = RegStorage::Solo32(info_lo->reg);
+ RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, false);
+ if (reg.Valid()) {
+ bool match = true;
+ RegisterInfo* info = GetRegInfo(reg);
+ match &= !reg.IsPair();
+ match &= !info->IsWide();
+ if (match) {
loc.location = kLocPhysReg;
+ loc.reg = reg;
+ } else {
+ Clobber(reg);
+ FreeTemp(reg);
}
}
}
return loc;
}
-/* see comments for update_loc */
RegLocation Mir2Lir::UpdateLocWide(RegLocation loc) {
DCHECK(loc.wide);
DCHECK(CheckCorePoolSanity());
if (loc.location != kLocPhysReg) {
DCHECK((loc.location == kLocDalvikFrame) ||
(loc.location == kLocCompilerTemp));
- // Are the dalvik regs already live in physical registers?
- RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg);
- RegisterInfo* info_hi = AllocLive(GetSRegHi(loc.s_reg_low), kAnyReg);
- bool match = true;
- match = match && (info_lo != NULL);
- match = match && (info_hi != NULL);
- // Are they both core or both FP?
- match = match && (IsFpReg(info_lo->reg) == IsFpReg(info_hi->reg));
- // If a pair of floating point singles, are they properly aligned?
- if (match && IsFpReg(info_lo->reg)) {
- match &= ((info_lo->reg & 0x1) == 0);
- match &= ((info_hi->reg - info_lo->reg) == 1);
- }
- // If previously used as a pair, it is the same pair?
- if (match && (info_lo->pair || info_hi->pair)) {
- match = (info_lo->pair == info_hi->pair);
- match &= ((info_lo->reg == info_hi->partner) &&
- (info_hi->reg == info_lo->partner));
- }
- if (match) {
- // Can reuse - update the register usage info
- loc.location = kLocPhysReg;
- loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_hi->reg);
- MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
- DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
- return loc;
- }
- // Can't easily reuse - clobber and free any overlaps
- if (info_lo) {
- Clobber(info_lo->reg);
- FreeTemp(info_lo->reg);
- if (info_lo->pair)
- Clobber(info_lo->partner);
- }
- if (info_hi) {
- Clobber(info_hi->reg);
- FreeTemp(info_hi->reg);
- if (info_hi->pair)
- Clobber(info_hi->partner);
+ RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, true);
+ if (reg.Valid()) {
+ bool match = true;
+ if (reg.IsPair()) {
+ // If we've got a register pair, make sure that it was last used as the same pair.
+ RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
+ RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
+ match &= info_lo->IsWide();
+ match &= info_hi->IsWide();
+ match &= (info_lo->Partner() == info_hi->GetReg());
+ match &= (info_hi->Partner() == info_lo->GetReg());
+ } else {
+ RegisterInfo* info = GetRegInfo(reg);
+ match &= info->IsWide();
+ match &= (info->GetReg() == info->Partner());
+ }
+ if (match) {
+ loc.location = kLocPhysReg;
+ loc.reg = reg;
+ } else {
+ Clobber(reg);
+ FreeTemp(reg);
+ }
}
}
return loc;
}
-
/* For use in cases we don't know (or care) width */
RegLocation Mir2Lir::UpdateRawLoc(RegLocation loc) {
if (loc.wide)
@@ -885,18 +900,15 @@
/* If already in registers, we can assume proper form. Right reg class? */
if (loc.location == kLocPhysReg) {
- DCHECK_EQ(IsFpReg(loc.reg.GetLowReg()), IsFpReg(loc.reg.GetHighReg()));
- DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
if (!RegClassMatches(reg_class, loc.reg)) {
/* Wrong register class. Reallocate and copy */
RegStorage new_regs = AllocTypedTempWide(loc.fp, reg_class);
OpRegCopyWide(new_regs, loc.reg);
- CopyRegInfo(new_regs.GetLowReg(), loc.reg.GetLowReg());
- CopyRegInfo(new_regs.GetHighReg(), loc.reg.GetHighReg());
+ // Associate the old sreg with the new register and clobber the old register.
+ GetRegInfo(new_regs)->SetSReg(GetRegInfo(loc.reg)->SReg());
Clobber(loc.reg);
loc.reg = new_regs;
- MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
- DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
+ MarkWide(loc.reg);
}
return loc;
}
@@ -905,23 +917,19 @@
DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
loc.reg = AllocTypedTempWide(loc.fp, reg_class);
+ MarkWide(loc.reg);
- MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
if (update) {
loc.location = kLocPhysReg;
- MarkLive(loc.reg.GetLow(), loc.s_reg_low);
- // Does this wide value live in two registers or one vector register?
- if (loc.reg.GetLowReg() != loc.reg.GetHighReg()) {
- MarkLive(loc.reg.GetHigh(), GetSRegHi(loc.s_reg_low));
- }
+ MarkLive(loc);
}
- DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
return loc;
}
RegLocation Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) {
- if (loc.wide)
+ if (loc.wide) {
return EvalLocWide(loc, reg_class, update);
+ }
loc = UpdateLoc(loc);
@@ -930,7 +938,8 @@
/* Wrong register class. Realloc, copy and transfer ownership */
RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
OpRegCopy(new_reg, loc.reg);
- CopyRegInfo(new_reg, loc.reg);
+ // Associate the old sreg with the new register and clobber the old register.
+ GetRegInfo(new_reg)->SetSReg(GetRegInfo(loc.reg)->SReg());
Clobber(loc.reg);
loc.reg = new_reg;
}
@@ -943,7 +952,7 @@
if (update) {
loc.location = kLocPhysReg;
- MarkLive(loc.reg, loc.s_reg_low);
+ MarkLive(loc);
}
return loc;
}
@@ -1115,9 +1124,14 @@
int low_reg = promotion_map_[p_map_idx].FpReg;
int high_reg = promotion_map_[p_map_idx+1].FpReg;
// Doubles require pair of singles starting at even reg
+ // TODO: move target-specific restrictions out of here.
if (((low_reg & 0x1) == 0) && ((low_reg + 1) == high_reg)) {
curr->location = kLocPhysReg;
- curr->reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+ if (cu_->instruction_set == kThumb2) {
+ curr->reg = RegStorage::FloatSolo64(RegStorage::RegNum(low_reg) >> 1);
+ } else {
+ curr->reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+ }
curr->home = true;
}
}
@@ -1155,13 +1169,18 @@
RegLocation gpr_res = LocCReturnWide();
RegLocation fpr_res = LocCReturnDouble();
RegLocation res = is_double ? fpr_res : gpr_res;
- Clobber(res.reg.GetLowReg());
- Clobber(res.reg.GetHighReg());
- LockTemp(res.reg.GetLowReg());
- LockTemp(res.reg.GetHighReg());
- // Does this wide value live in two registers or one vector register?
- if (res.reg.GetLowReg() != res.reg.GetHighReg()) {
- MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
+ if (res.reg.IsPair()) {
+ Clobber(res.reg);
+ LockTemp(res.reg);
+ // Does this wide value live in two registers or one vector register?
+ if (res.reg.GetLowReg() != res.reg.GetHighReg()) {
+ // FIXME: I think we want to mark these as wide as well.
+ MarkWide(res.reg);
+ }
+ } else {
+ Clobber(res.reg);
+ LockTemp(res.reg);
+ MarkWide(res.reg);
}
return res;
}
@@ -1170,11 +1189,11 @@
RegLocation gpr_res = LocCReturn();
RegLocation fpr_res = LocCReturnFloat();
RegLocation res = is_float ? fpr_res : gpr_res;
- Clobber(res.reg.GetReg());
+ Clobber(res.reg);
if (cu_->instruction_set == kMips) {
- MarkInUse(res.reg.GetReg());
+ MarkInUse(res.reg);
} else {
- LockTemp(res.reg.GetReg());
+ LockTemp(res.reg);
}
return res;
}
@@ -1204,14 +1223,9 @@
return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
}
-bool Mir2Lir::oat_live_out(int s_reg) {
+bool Mir2Lir::LiveOut(int s_reg) {
// For now.
return true;
}
-int Mir2Lir::oatSSASrc(MIR* mir, int num) {
- DCHECK_GT(mir->ssa_rep->num_uses, num);
- return mir->ssa_rep->uses[num];
-}
-
} // namespace art
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index e7a1a69..58e2f42 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -175,7 +175,7 @@
{ kX86Mov32AI, kArrayImm, IS_STORE | IS_QUIN_OP | REG_USE01, { 0, 0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32AI", "[!0r+!1r<<!2d+!3d],!4d" },
{ kX86Mov32TI, kThreadImm, IS_STORE | IS_BINARY_OP, { THREAD_PREFIX, 0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32TI", "fs:[!0d],!1d" },
- { kX86Lea32RM, kRegMem, IS_TERTIARY_OP | IS_LOAD | REG_DEF0_USE12, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RM", "!0r,[!1r+!2d]" },
+ { kX86Lea32RM, kRegMem, IS_TERTIARY_OP | IS_LOAD | REG_DEF0_USE1, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RM", "!0r,[!1r+!2d]" },
{ kX86Lea32RA, kRegArray, IS_QUIN_OP | REG_DEF0_USE12, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RA", "!0r,[!1r+!2r<<!3d+!4d]" },
@@ -388,11 +388,11 @@
}
}
++size; // modrm
- if (has_sib || base == rX86_SP) {
+ if (has_sib || RegStorage::RegNum(base) == rs_rX86_SP.GetRegNum()) {
// SP requires a SIB byte.
++size;
}
- if (displacement != 0 || base == rBP) {
+ if (displacement != 0 || RegStorage::RegNum(base) == rs_rBP.GetRegNum()) {
// BP requires an explicit displacement, even when it's 0.
if (entry->opcode != kX86Lea32RA) {
DCHECK_NE(entry->flags & (IS_LOAD | IS_STORE), 0ULL) << entry->name;
@@ -446,7 +446,7 @@
} else {
// AX opcodes don't require the modrm byte.
int reg = lir->operands[0];
- return size - (reg == rAX ? 1 : 0);
+ return size - (RegStorage::RegNum(reg) == rs_rAX.GetRegNum() ? 1 : 0);
}
}
case kMemImm: // lir operands - 0: base, 1: disp, 2: immediate
@@ -533,7 +533,7 @@
DCHECK_EQ(lir->opcode, static_cast<int>(kX86StartOfMethod));
return 5 /* call opcode + 4 byte displacement */ + 1 /* pop reg */ +
ComputeSize(&X86Mir2Lir::EncodingMap[kX86Sub32RI], 0, 0, false) -
- (lir->operands[0] == rAX ? 1 : 0); // shorter ax encoding
+ (RegStorage::RegNum(lir->operands[0]) == rs_rAX.GetRegNum() ? 1 : 0); // shorter ax encoding
default:
break;
}
@@ -574,7 +574,7 @@
static uint8_t ModrmForDisp(int base, int disp) {
// BP requires an explicit disp, so do not omit it in the 0 case
- if (disp == 0 && base != rBP) {
+ if (disp == 0 && RegStorage::RegNum(base) != rs_rBP.GetRegNum()) {
return 0;
} else if (IS_SIMM8(disp)) {
return 1;
@@ -585,7 +585,7 @@
void X86Mir2Lir::EmitDisp(uint8_t base, int disp) {
// BP requires an explicit disp, so do not omit it in the 0 case
- if (disp == 0 && base != rBP) {
+ if (disp == 0 && RegStorage::RegNum(base) != rs_rBP.GetRegNum()) {
return;
} else if (IS_SIMM8(disp)) {
code_buffer_.push_back(disp & 0xFF);
@@ -598,26 +598,28 @@
}
void X86Mir2Lir::EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp) {
- DCHECK_LT(reg_or_opcode, 8);
- DCHECK_LT(base, 8);
- uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base;
+ DCHECK_LT(RegStorage::RegNum(reg_or_opcode), 8);
+ DCHECK_LT(RegStorage::RegNum(base), 8);
+ uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (RegStorage::RegNum(reg_or_opcode) << 3) |
+ RegStorage::RegNum(base);
code_buffer_.push_back(modrm);
- if (base == rX86_SP) {
+ if (RegStorage::RegNum(base) == rs_rX86_SP.GetRegNum()) {
// Special SIB for SP base
- code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
+ code_buffer_.push_back(0 << 6 | rs_rX86_SP.GetRegNum() << 3 | rs_rX86_SP.GetRegNum());
}
EmitDisp(base, disp);
}
void X86Mir2Lir::EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index,
int scale, int disp) {
- DCHECK_LT(reg_or_opcode, 8);
- uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | rX86_SP;
+ DCHECK_LT(RegStorage::RegNum(reg_or_opcode), 8);
+ uint8_t modrm = (ModrmForDisp(base, disp) << 6) | RegStorage::RegNum(reg_or_opcode) << 3 |
+ rs_rX86_SP.GetRegNum();
code_buffer_.push_back(modrm);
DCHECK_LT(scale, 4);
- DCHECK_LT(index, 8);
- DCHECK_LT(base, 8);
- uint8_t sib = (scale << 6) | (index << 3) | base;
+ DCHECK_LT(RegStorage::RegNum(index), 8);
+ DCHECK_LT(RegStorage::RegNum(base), 8);
+ uint8_t sib = (scale << 6) | (RegStorage::RegNum(index) << 3) | RegStorage::RegNum(base);
code_buffer_.push_back(sib);
EmitDisp(base, disp);
}
@@ -651,24 +653,22 @@
// There's no 3-byte instruction with +rd
DCHECK(entry->skeleton.opcode != 0x0F ||
(entry->skeleton.extra_opcode1 != 0x38 && entry->skeleton.extra_opcode1 != 0x3A));
- DCHECK(!X86_FPREG(reg));
- DCHECK_LT(reg, 8);
- code_buffer_.back() += reg;
+ DCHECK(!RegStorage::IsFloat(reg));
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ code_buffer_.back() += RegStorage::RegNum(reg);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
}
void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) {
EmitPrefixAndOpcode(entry);
- if (X86_FPREG(reg)) {
- reg = reg & X86_FP_REG_MASK;
- }
- if (reg >= 4) {
- DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+ if (RegStorage::RegNum(reg) >= 4) {
+ DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " "
+ << static_cast<int>(RegStorage::RegNum(reg))
<< " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
}
- DCHECK_LT(reg, 8);
- uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
code_buffer_.push_back(modrm);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -696,13 +696,10 @@
void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry,
uint8_t base, int disp, uint8_t reg) {
EmitPrefixAndOpcode(entry);
- if (X86_FPREG(reg)) {
- reg = reg & X86_FP_REG_MASK;
- }
- if (reg >= 4) {
+ if (RegStorage::RegNum(reg) >= 4) {
DCHECK(strchr(entry->name, '8') == NULL ||
entry->opcode == kX86Movzx8RM || entry->opcode == kX86Movsx8RM)
- << entry->name << " " << static_cast<int>(reg)
+ << entry->name << " " << static_cast<int>(RegStorage::RegNum(reg))
<< " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
}
EmitModrmDisp(reg, base, disp);
@@ -720,17 +717,14 @@
void X86Mir2Lir::EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
int scale, int disp) {
EmitPrefixAndOpcode(entry);
- if (X86_FPREG(reg)) {
- reg = reg & X86_FP_REG_MASK;
- }
EmitModrmSibDisp(reg, base, index, scale, disp);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
}
-void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale, int disp,
- uint8_t reg) {
+void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale,
+ int disp, uint8_t reg) {
// Opcode will flip operands.
EmitRegArray(entry, reg, base, index, scale, disp);
}
@@ -738,15 +732,13 @@
void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp) {
DCHECK_NE(entry->skeleton.prefix1, 0);
EmitPrefixAndOpcode(entry);
- if (X86_FPREG(reg)) {
- reg = reg & X86_FP_REG_MASK;
- }
- if (reg >= 4) {
- DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+ if (RegStorage::RegNum(reg) >= 4) {
+ DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " "
+ << static_cast<int>(RegStorage::RegNum(reg))
<< " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
}
- DCHECK_LT(reg, 8);
- uint8_t modrm = (0 << 6) | (reg << 3) | rBP;
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ uint8_t modrm = (0 << 6) | (RegStorage::RegNum(reg) << 3) | rs_rBP.GetRegNum();
code_buffer_.push_back(modrm);
code_buffer_.push_back(disp & 0xFF);
code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -759,15 +751,9 @@
void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2) {
EmitPrefixAndOpcode(entry);
- if (X86_FPREG(reg1)) {
- reg1 = reg1 & X86_FP_REG_MASK;
- }
- if (X86_FPREG(reg2)) {
- reg2 = reg2 & X86_FP_REG_MASK;
- }
- DCHECK_LT(reg1, 8);
- DCHECK_LT(reg2, 8);
- uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
+ DCHECK_LT(RegStorage::RegNum(reg1), 8);
+ DCHECK_LT(RegStorage::RegNum(reg2), 8);
+ uint8_t modrm = (3 << 6) | (RegStorage::RegNum(reg1) << 3) | RegStorage::RegNum(reg2);
code_buffer_.push_back(modrm);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -777,15 +763,9 @@
void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
uint8_t reg1, uint8_t reg2, int32_t imm) {
EmitPrefixAndOpcode(entry);
- if (X86_FPREG(reg1)) {
- reg1 = reg1 & X86_FP_REG_MASK;
- }
- if (X86_FPREG(reg2)) {
- reg2 = reg2 & X86_FP_REG_MASK;
- }
- DCHECK_LT(reg1, 8);
- DCHECK_LT(reg2, 8);
- uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
+ DCHECK_LT(RegStorage::RegNum(reg1), 8);
+ DCHECK_LT(RegStorage::RegNum(reg2), 8);
+ uint8_t modrm = (3 << 6) | (RegStorage::RegNum(reg1) << 3) | RegStorage::RegNum(reg2);
code_buffer_.push_back(modrm);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -800,8 +780,8 @@
void X86Mir2Lir::EmitRegMemImm(const X86EncodingMap* entry,
uint8_t reg, uint8_t base, int disp, int32_t imm) {
EmitPrefixAndOpcode(entry);
- DCHECK(!X86_FPREG(reg));
- DCHECK_LT(reg, 8);
+ DCHECK(!RegStorage::IsFloat(reg));
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
EmitModrmDisp(reg, base, disp);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -817,14 +797,11 @@
} else {
DCHECK_EQ(0, entry->skeleton.prefix2);
}
- if (reg == rAX && entry->skeleton.ax_opcode != 0) {
+ if (RegStorage::RegNum(reg) == rs_rAX.GetRegNum() && entry->skeleton.ax_opcode != 0) {
code_buffer_.push_back(entry->skeleton.ax_opcode);
} else {
EmitOpcode(entry);
- if (X86_FPREG(reg)) {
- reg = reg & X86_FP_REG_MASK;
- }
- uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+ uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
code_buffer_.push_back(modrm);
}
EmitImm(entry, imm);
@@ -839,7 +816,7 @@
void X86Mir2Lir::EmitThreadImm(const X86EncodingMap* entry, int disp, int imm) {
EmitPrefixAndOpcode(entry);
- uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
+ uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rs_rBP.GetRegNum();
code_buffer_.push_back(modrm);
code_buffer_.push_back(disp & 0xFF);
code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -850,8 +827,8 @@
}
void X86Mir2Lir::EmitMovRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
- DCHECK_LT(reg, 8);
- code_buffer_.push_back(0xB8 + reg);
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ code_buffer_.push_back(0xB8 + RegStorage::RegNum(reg));
code_buffer_.push_back(imm & 0xFF);
code_buffer_.push_back((imm >> 8) & 0xFF);
code_buffer_.push_back((imm >> 16) & 0xFF);
@@ -869,12 +846,13 @@
DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- if (reg >= 4) {
- DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+ if (RegStorage::RegNum(reg) >= 4) {
+ DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " "
+ << static_cast<int>(RegStorage::RegNum(reg))
<< " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
}
- DCHECK_LT(reg, 8);
- uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
code_buffer_.push_back(modrm);
if (imm != 1) {
DCHECK_EQ(entry->skeleton.immediate_bytes, 1);
@@ -884,14 +862,14 @@
}
void X86Mir2Lir::EmitShiftRegCl(const X86EncodingMap* entry, uint8_t reg, uint8_t cl) {
- DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
+ DCHECK_EQ(cl, static_cast<uint8_t>(rs_rCX.GetReg()));
EmitPrefix(entry);
code_buffer_.push_back(entry->skeleton.opcode);
DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- DCHECK_LT(reg, 8);
- uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
code_buffer_.push_back(modrm);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -899,13 +877,13 @@
void X86Mir2Lir::EmitShiftMemCl(const X86EncodingMap* entry, uint8_t base,
int displacement, uint8_t cl) {
- DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
+ DCHECK_EQ(cl, static_cast<uint8_t>(rs_rCX.GetReg()));
EmitPrefix(entry);
code_buffer_.push_back(entry->skeleton.opcode);
DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- DCHECK_LT(base, 8);
+ DCHECK_LT(RegStorage::RegNum(base), 8);
EmitModrmDisp(entry->skeleton.modrm_opcode, base, displacement);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -926,13 +904,14 @@
DCHECK_EQ(0x90, entry->skeleton.extra_opcode1);
code_buffer_.push_back(0x90 | condition);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- DCHECK_LT(reg, 8);
- uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
code_buffer_.push_back(modrm);
DCHECK_EQ(entry->skeleton.immediate_bytes, 0);
}
-void X86Mir2Lir::EmitRegRegCond(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2, uint8_t condition) {
+void X86Mir2Lir::EmitRegRegCond(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2,
+ uint8_t condition) {
// Generate prefix and opcode without the condition
EmitPrefixAndOpcode(entry);
@@ -945,14 +924,14 @@
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
// Check that registers requested for encoding are sane.
- DCHECK_LT(reg1, 8);
- DCHECK_LT(reg2, 8);
+ DCHECK_LT(RegStorage::RegNum(reg1), 8);
+ DCHECK_LT(RegStorage::RegNum(reg2), 8);
// For register to register encoding, the mod is 3.
const uint8_t mod = (3 << 6);
// Encode the ModR/M byte now.
- const uint8_t modrm = mod | (reg1 << 3) | reg2;
+ const uint8_t modrm = mod | (RegStorage::RegNum(reg1) << 3) | RegStorage::RegNum(reg2);
code_buffer_.push_back(modrm);
}
@@ -975,8 +954,8 @@
DCHECK(entry->opcode == kX86JmpR);
code_buffer_.push_back(entry->skeleton.opcode);
uint8_t reg = static_cast<uint8_t>(rel);
- DCHECK_LT(reg, 8);
- uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
code_buffer_.push_back(modrm);
}
}
@@ -1018,7 +997,7 @@
void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) {
DCHECK_NE(entry->skeleton.prefix1, 0);
EmitPrefixAndOpcode(entry);
- uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
+ uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rs_rBP.GetRegNum();
code_buffer_.push_back(modrm);
code_buffer_.push_back(disp & 0xFF);
code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -1042,26 +1021,23 @@
disp = tab_rec->offset;
}
EmitPrefix(entry);
- if (X86_FPREG(reg)) {
- reg = reg & X86_FP_REG_MASK;
- }
- DCHECK_LT(reg, 8);
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
if (entry->opcode == kX86PcRelLoadRA) {
code_buffer_.push_back(entry->skeleton.opcode);
DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- uint8_t modrm = (2 << 6) | (reg << 3) | rX86_SP;
+ uint8_t modrm = (2 << 6) | (RegStorage::RegNum(reg) << 3) | rs_rX86_SP.GetRegNum();
code_buffer_.push_back(modrm);
DCHECK_LT(scale, 4);
- DCHECK_LT(index, 8);
- DCHECK_LT(base_or_table, 8);
+ DCHECK_LT(RegStorage::RegNum(index), 8);
+ DCHECK_LT(RegStorage::RegNum(base_or_table), 8);
uint8_t base = static_cast<uint8_t>(base_or_table);
- uint8_t sib = (scale << 6) | (index << 3) | base;
+ uint8_t sib = (scale << 6) | (RegStorage::RegNum(index) << 3) | RegStorage::RegNum(base);
code_buffer_.push_back(sib);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
} else {
- code_buffer_.push_back(entry->skeleton.opcode + reg);
+ code_buffer_.push_back(entry->skeleton.opcode + RegStorage::RegNum(reg));
}
code_buffer_.push_back(disp & 0xFF);
code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -1079,10 +1055,11 @@
code_buffer_.push_back(0);
code_buffer_.push_back(0);
- DCHECK_LT(reg, 8);
- code_buffer_.push_back(0x58 + reg); // pop reg
+ DCHECK_LT(RegStorage::RegNum(reg), 8);
+ code_buffer_.push_back(0x58 + RegStorage::RegNum(reg)); // pop reg
- EmitRegImm(&X86Mir2Lir::EncodingMap[kX86Sub32RI], reg, offset + 5 /* size of call +0 */);
+ EmitRegImm(&X86Mir2Lir::EncodingMap[kX86Sub32RI], RegStorage::RegNum(reg),
+ offset + 5 /* size of call +0 */);
}
void X86Mir2Lir::EmitUnimplemented(const X86EncodingMap* entry, LIR* lir) {
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 06cc861..f701a1f 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -152,10 +152,10 @@
LoadValueDirect(rl_method, rs_rX86_ARG2);
store_method_addr_used_ = true;
} else {
- NewLIR1(kX86StartOfMethod, rX86_ARG2);
+ NewLIR1(kX86StartOfMethod, rs_rX86_ARG2.GetReg());
}
- NewLIR2(kX86PcRelAdr, rX86_ARG1, WrapPointer(tab_rec));
- NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2);
+ NewLIR2(kX86PcRelAdr, rs_rX86_ARG1.GetReg(), WrapPointer(tab_rec));
+ NewLIR2(kX86Add32RR, rs_rX86_ARG1.GetReg(), rs_rX86_ARG2.GetReg());
CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pHandleFillArrayData), rs_rX86_ARG0,
rs_rX86_ARG1, true);
}
@@ -191,9 +191,9 @@
* expanding the frame or flushing. This leaves the utility
* code with no spare temps.
*/
- LockTemp(rX86_ARG0);
- LockTemp(rX86_ARG1);
- LockTemp(rX86_ARG2);
+ LockTemp(rs_rX86_ARG0);
+ LockTemp(rs_rX86_ARG1);
+ LockTemp(rs_rX86_ARG2);
/* Build frame, return address already on stack */
// TODO: 64 bit.
@@ -240,7 +240,7 @@
// in case a signal comes in that's not using an alternate signal stack and the large frame may
// have moved us outside of the reserved area at the end of the stack.
// cmp rX86_SP, fs:[stack_end_]; jcc throw_slowpath
- OpRegThreadMem(kOpCmp, rX86_SP, Thread::StackEndOffset<4>());
+ OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
LIR* branch = OpCondBranch(kCondUlt, nullptr);
AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, frame_size_ - 4));
}
@@ -249,15 +249,15 @@
if (base_of_code_ != nullptr) {
// We have been asked to save the address of the method start for later use.
- setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rX86_ARG0);
+ setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rs_rX86_ARG0.GetReg());
int displacement = SRegOffset(base_of_code_->s_reg_low);
// Native pointer - must be natural word size.
setup_method_address_[1] = StoreWordDisp(rs_rX86_SP, displacement, rs_rX86_ARG0);
}
- FreeTemp(rX86_ARG0);
- FreeTemp(rX86_ARG1);
- FreeTemp(rX86_ARG2);
+ FreeTemp(rs_rX86_ARG0);
+ FreeTemp(rs_rX86_ARG1);
+ FreeTemp(rs_rX86_ARG2);
}
void X86Mir2Lir::GenExitSequence() {
@@ -265,8 +265,8 @@
* In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't
* allocated by the register utilities as temps.
*/
- LockTemp(rX86_RET0);
- LockTemp(rX86_RET1);
+ LockTemp(rs_rX86_RET0);
+ LockTemp(rs_rX86_RET1);
NewLIR0(kPseudoMethodExit);
UnSpillCoreRegs();
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 760290c..c3ea55f 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -37,27 +37,21 @@
LIR* LoadBaseDispWide(RegStorage r_base, int displacement, RegStorage r_dest, int s_reg);
LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
OpSize size);
- // TODO: collapse r_dest, r_dest_hi
LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
- RegStorage r_dest, RegStorage r_dest_hi, OpSize size, int s_reg);
+ RegStorage r_dest, OpSize size, int s_reg);
LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
LIR* StoreBaseDispWide(RegStorage r_base, int displacement, RegStorage r_src);
LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
OpSize size);
- // TODO: collapse r_src, r_src_hi
LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
- RegStorage r_src, RegStorage r_src_hi, OpSize size, int s_reg);
+ RegStorage r_src, OpSize size, int s_reg);
void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
// Required for target - register utilities.
- bool IsFpReg(int reg);
- bool IsFpReg(RegStorage reg);
- bool SameRegType(int reg1, int reg2);
RegStorage AllocTypedTemp(bool fp_hint, int reg_class);
RegStorage AllocTypedTempWide(bool fp_hint, int reg_class);
- int S2d(int low_reg, int high_reg);
RegStorage TargetReg(SpecialTargetRegister reg);
RegStorage GetArgMappingToPhysicalReg(int arg_num);
RegLocation GetReturnAlt();
@@ -66,16 +60,14 @@
RegLocation LocCReturnDouble();
RegLocation LocCReturnFloat();
RegLocation LocCReturnWide();
- uint32_t FpRegMask();
- uint64_t GetRegMaskCommon(int reg);
+ uint64_t GetRegMaskCommon(RegStorage reg);
void AdjustSpillMask();
void ClobberCallerSave();
- void FlushReg(RegStorage reg);
- void FlushRegWide(RegStorage reg);
void FreeCallTemps();
void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
void LockCallTemps();
- void MarkPreservedSingle(int v_reg, int reg);
+ void MarkPreservedSingle(int v_reg, RegStorage reg);
+ void MarkPreservedDouble(int v_reg, RegStorage reg);
void CompilerInitializeRegAlloc();
// Required for target - miscellaneous.
@@ -252,7 +244,7 @@
void OpRegCopyWide(RegStorage dest, RegStorage src);
void OpTlsCmp(ThreadOffset<4> offset, int val);
- void OpRegThreadMem(OpKind op, int r_dest, ThreadOffset<4> thread_offset);
+ void OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset);
void SpillCoreRegs();
void UnSpillCoreRegs();
static const X86EncodingMap EncodingMap[kX86Last];
@@ -261,12 +253,6 @@
bool InexpensiveConstantLong(int64_t value);
bool InexpensiveConstantDouble(int64_t value);
- RegLocation UpdateLocWide(RegLocation loc);
- RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
- RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
- RegStorage AllocTempDouble();
- void ResetDefLocWide(RegLocation rl);
-
/*
* @brief x86 specific codegen for int operations.
* @param opcode Operation to perform.
@@ -379,7 +365,6 @@
void EmitUnimplemented(const X86EncodingMap* entry, LIR* lir);
void GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
int64_t val, ConditionCode ccode);
- void OpVectorRegCopyWide(uint8_t fp_reg, uint8_t low_reg, uint8_t high_reg);
void GenConstWide(RegLocation rl_dest, int64_t value);
static bool ProvidesFullMemoryBarrier(X86OpCode opcode);
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index f7b0c9d..1ed0b63 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -67,7 +67,7 @@
RegStorage r_src1 = rl_src1.reg;
RegStorage r_src2 = rl_src2.reg;
if (r_dest == r_src2) {
- r_src2 = AllocTempFloat();
+ r_src2 = AllocTempSingle();
OpRegCopy(r_src2, r_dest);
}
OpRegCopy(r_dest, r_src1);
@@ -77,6 +77,12 @@
void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
+ DCHECK(rl_dest.wide);
+ DCHECK(rl_dest.fp);
+ DCHECK(rl_src1.wide);
+ DCHECK(rl_src1.fp);
+ DCHECK(rl_src2.wide);
+ DCHECK(rl_src2.fp);
X86OpCode op = kX86Nop;
RegLocation rl_result;
@@ -112,22 +118,14 @@
LOG(FATAL) << "Unexpected opcode: " << opcode;
}
rl_src1 = LoadValueWide(rl_src1, kFPReg);
- DCHECK(rl_src1.wide);
rl_src2 = LoadValueWide(rl_src2, kFPReg);
- DCHECK(rl_src2.wide);
rl_result = EvalLoc(rl_dest, kFPReg, true);
- DCHECK(rl_dest.wide);
- DCHECK(rl_result.wide);
- // TODO: update with direct 64-bit reg.
- int r_dest = S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg());
- int r_src1 = S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
- int r_src2 = S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg());
- if (r_dest == r_src2) {
- r_src2 = AllocTempDouble().GetLowReg() | X86_FP_DOUBLE;
- OpRegCopy(RegStorage::Solo64(r_src2), RegStorage::Solo64(r_dest));
+ if (rl_result.reg == rl_src2.reg) {
+ rl_src2.reg = AllocTempDouble();
+ OpRegCopy(rl_src2.reg, rl_result.reg);
}
- OpRegCopy(RegStorage::Solo64(r_dest), RegStorage::Solo64(r_src1));
- NewLIR2(op, r_dest, r_src2);
+ OpRegCopy(rl_result.reg, rl_src1.reg);
+ NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
StoreValueWide(rl_dest, rl_result);
}
@@ -141,16 +139,13 @@
// If the source is in physical register, then put it in its location on stack.
if (rl_src.location == kLocPhysReg) {
- RegisterInfo* lo_info = GetRegInfo(rl_src.reg.GetLowReg());
+ RegisterInfo* reg_info = GetRegInfo(rl_src.reg);
- if (lo_info != nullptr && lo_info->is_temp) {
+ if (reg_info != nullptr && reg_info->IsTemp()) {
// Calling FlushSpecificReg because it will only write back VR if it is dirty.
- FlushSpecificReg(lo_info);
- // ResetDef for low/high to prevent NullifyRange from removing stores.
- ResetDef(rl_src.reg.GetLowReg());
- if (rl_src.reg.GetLowReg() != rl_src.reg.GetHighReg() && GetRegInfo(rl_src.reg.GetHighReg()) != nullptr) {
- ResetDef(rl_src.reg.GetHighReg());
- }
+ FlushSpecificReg(reg_info);
+ // ResetDef to prevent NullifyRange from removing stores.
+ ResetDef(rl_src.reg);
} else {
// It must have been register promoted if it is not a temp but is still in physical
// register. Since we need it to be in memory to convert, we place it there now.
@@ -159,9 +154,10 @@
}
// Push the source virtual register onto the x87 stack.
- LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(), src_v_reg_offset + LOWORD_OFFSET);
+ LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(),
+ src_v_reg_offset + LOWORD_OFFSET);
AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
- true /* is_load */, true /* is64bit */);
+ true /* is_load */, true /* is64bit */);
// Now pop off x87 stack and store it in the destination VR's stack location.
int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
@@ -204,7 +200,6 @@
RegLocation rl_src) {
RegisterClass rcSrc = kFPReg;
X86OpCode op = kX86Nop;
- int src_reg;
RegLocation rl_result;
switch (opcode) {
case Instruction::INT_TO_FLOAT:
@@ -225,18 +220,17 @@
break;
case Instruction::FLOAT_TO_INT: {
rl_src = LoadValue(rl_src, kFPReg);
- src_reg = rl_src.reg.GetReg();
// In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
ClobberSReg(rl_dest.s_reg_low);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
- int temp_reg = AllocTempFloat().GetReg();
+ RegStorage temp_reg = AllocTempSingle();
LoadConstant(rl_result.reg, 0x7fffffff);
- NewLIR2(kX86Cvtsi2ssRR, temp_reg, rl_result.reg.GetReg());
- NewLIR2(kX86ComissRR, src_reg, temp_reg);
+ NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
+ NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
- NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), src_reg);
+ NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
branch_na_n->target = NewLIR0(kPseudoTargetLabel);
NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
@@ -247,18 +241,17 @@
}
case Instruction::DOUBLE_TO_INT: {
rl_src = LoadValueWide(rl_src, kFPReg);
- src_reg = rl_src.reg.GetLowReg();
// In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
ClobberSReg(rl_dest.s_reg_low);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
- int temp_reg = AllocTempDouble().GetLowReg() | X86_FP_DOUBLE;
+ RegStorage temp_reg = AllocTempDouble();
LoadConstant(rl_result.reg, 0x7fffffff);
- NewLIR2(kX86Cvtsi2sdRR, temp_reg, rl_result.reg.GetReg());
- NewLIR2(kX86ComisdRR, src_reg, temp_reg);
+ NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
+ NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
- NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), src_reg);
+ NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
branch_na_n->target = NewLIR0(kPseudoTargetLabel);
NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
@@ -282,20 +275,18 @@
default:
LOG(INFO) << "Unexpected opcode: " << opcode;
}
+ // At this point, target will be either float or double.
+ DCHECK(rl_dest.fp);
if (rl_src.wide) {
rl_src = LoadValueWide(rl_src, rcSrc);
- src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
} else {
rl_src = LoadValue(rl_src, rcSrc);
- src_reg = rl_src.reg.GetReg();
}
+ rl_result = EvalLoc(rl_dest, kFPReg, true);
+ NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
if (rl_dest.wide) {
- rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
StoreValueWide(rl_dest, rl_result);
} else {
- rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(op, rl_result.reg.GetReg(), src_reg);
StoreValue(rl_dest, rl_result);
}
}
@@ -304,34 +295,28 @@
RegLocation rl_src1, RegLocation rl_src2) {
bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
- int src_reg1;
- int src_reg2;
if (single) {
rl_src1 = LoadValue(rl_src1, kFPReg);
- src_reg1 = rl_src1.reg.GetReg();
rl_src2 = LoadValue(rl_src2, kFPReg);
- src_reg2 = rl_src2.reg.GetReg();
} else {
rl_src1 = LoadValueWide(rl_src1, kFPReg);
- src_reg1 = S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
rl_src2 = LoadValueWide(rl_src2, kFPReg);
- src_reg2 = S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg());
}
// In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
ClobberSReg(rl_dest.s_reg_low);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
if (single) {
- NewLIR2(kX86UcomissRR, src_reg1, src_reg2);
+ NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
} else {
- NewLIR2(kX86UcomisdRR, src_reg1, src_reg2);
+ NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
}
LIR* branch = NULL;
if (unordered_gt) {
branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
}
// If the result reg can't be byte accessed, use a jump and move instead of a set.
- if (rl_result.reg.GetReg() >= 4) {
+ if (rl_result.reg.GetReg() >= rs_rX86_SP.GetReg()) {
LIR* branch2 = NULL;
if (unordered_gt) {
branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
@@ -363,8 +348,7 @@
rl_src2 = mir_graph_->GetSrcWide(mir, 2);
rl_src1 = LoadValueWide(rl_src1, kFPReg);
rl_src2 = LoadValueWide(rl_src2, kFPReg);
- NewLIR2(kX86UcomisdRR, S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
- S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+ NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
} else {
rl_src1 = mir_graph_->GetSrc(mir, 0);
rl_src2 = mir_graph_->GetSrc(mir, 1);
@@ -442,8 +426,7 @@
RegLocation rl_dest = InlineTargetWide(info); // double place for result
rl_src = LoadValueWide(rl_src, kFPReg);
RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
- NewLIR2(kX86SqrtsdRR, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
- S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
+ NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
StoreValueWide(rl_dest, rl_result);
return true;
}
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 96c4cbe..4446f43 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -33,18 +33,18 @@
RegLocation rl_src2) {
FlushAllRegs();
LockCallTemps(); // Prepare for explicit register usage
- RegStorage r_tmp1(RegStorage::k64BitPair, r0, r1);
- RegStorage r_tmp2(RegStorage::k64BitPair, r2, r3);
+ RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_r0, rs_r1);
+ RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_r2, rs_r3);
LoadValueDirectWideFixed(rl_src1, r_tmp1);
LoadValueDirectWideFixed(rl_src2, r_tmp2);
// Compute (r1:r0) = (r1:r0) - (r3:r2)
OpRegReg(kOpSub, rs_r0, rs_r2); // r0 = r0 - r2
OpRegReg(kOpSbc, rs_r1, rs_r3); // r1 = r1 - r3 - CF
- NewLIR2(kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
- NewLIR2(kX86Movzx8RR, r2, r2);
+ NewLIR2(kX86Set8R, rs_r2.GetReg(), kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
+ NewLIR2(kX86Movzx8RR, rs_r2.GetReg(), rs_r2.GetReg());
OpReg(kOpNeg, rs_r2); // r2 = -r2
OpRegReg(kOpOr, rs_r0, rs_r1); // r0 = high | low - sets ZF
- NewLIR2(kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
+ NewLIR2(kX86Set8R, rs_r0.GetReg(), kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
NewLIR2(kX86Movzx8RR, r0, r0);
OpRegReg(kOpOr, rs_r0, rs_r2); // r0 = r0 | r2
RegLocation rl_result = LocCReturn();
@@ -106,7 +106,7 @@
if (r_src.IsPair()) {
r_src = r_src.GetLow();
}
- if (X86_FPREG(r_dest.GetReg()) || X86_FPREG(r_src.GetReg()))
+ if (r_dest.IsFloat() || r_src.IsFloat())
return OpFpRegCopy(r_dest, r_src);
LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR,
r_dest.GetReg(), r_src.GetReg());
@@ -125,31 +125,28 @@
void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
if (r_dest != r_src) {
- // FIXME: handle k64BitSolo when we start using them.
- DCHECK(r_dest.IsPair());
- DCHECK(r_src.IsPair());
- bool dest_fp = X86_FPREG(r_dest.GetLowReg());
- bool src_fp = X86_FPREG(r_src.GetLowReg());
+ bool dest_fp = r_dest.IsFloat();
+ bool src_fp = r_src.IsFloat();
if (dest_fp) {
if (src_fp) {
- // TODO: we ought to handle this case here - reserve OpRegCopy for 32-bit copies.
- OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
- RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
+ OpRegCopy(r_dest, r_src);
} else {
// TODO: Prevent this from happening in the code. The result is often
// unused or could have been loaded more easily from memory.
- NewLIR2(kX86MovdxrRR, r_dest.GetLowReg(), r_src.GetLowReg());
+ NewLIR2(kX86MovdxrRR, r_dest.GetReg(), r_src.GetLowReg());
RegStorage r_tmp = AllocTempDouble();
- NewLIR2(kX86MovdxrRR, r_tmp.GetLowReg(), r_src.GetHighReg());
- NewLIR2(kX86PunpckldqRR, r_dest.GetLowReg(), r_tmp.GetLowReg());
+ NewLIR2(kX86MovdxrRR, r_tmp.GetReg(), r_src.GetHighReg());
+ NewLIR2(kX86PunpckldqRR, r_dest.GetReg(), r_tmp.GetReg());
FreeTemp(r_tmp);
}
} else {
if (src_fp) {
- NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetLowReg());
- NewLIR2(kX86PsrlqRI, r_src.GetLowReg(), 32);
- NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetLowReg());
+ NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetReg());
+ NewLIR2(kX86PsrlqRI, r_src.GetReg(), 32);
+ NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetReg());
} else {
+ DCHECK(r_dest.IsPair());
+ DCHECK(r_src.IsPair());
// Handle overlap
if (r_src.GetHighReg() == r_dest.GetLowReg() && r_src.GetLowReg() == r_dest.GetHighReg()) {
// Deal with cycles.
@@ -289,8 +286,8 @@
FlushAllRegs();
LockCallTemps(); // Prepare for explicit register usage
- RegStorage r_tmp1(RegStorage::k64BitPair, r0, r1);
- RegStorage r_tmp2(RegStorage::k64BitPair, r2, r3);
+ RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_r0, rs_r1);
+ RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_r2, rs_r3);
LoadValueDirectWideFixed(rl_src1, r_tmp1);
LoadValueDirectWideFixed(rl_src2, r_tmp2);
// Swap operands and condition code to prevent use of zero flag.
@@ -452,8 +449,7 @@
LockCallTemps(); // Prepare for explicit register usage.
// Assume that the result will be in EDX.
- RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, rs_r2,
- INVALID_SREG, INVALID_SREG};
+ RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r2, INVALID_SREG, INVALID_SREG};
// handle div/rem by 1 special case.
if (imm == 1) {
@@ -516,7 +512,7 @@
// We will need the value later.
if (rl_src.location == kLocPhysReg) {
// We can use it directly.
- DCHECK(rl_src.reg.GetReg() != r0 && rl_src.reg.GetReg() != r2);
+ DCHECK(rl_src.reg.GetReg() != rs_r0.GetReg() && rl_src.reg.GetReg() != rs_r2.GetReg());
numerator_reg = rl_src.reg;
} else {
numerator_reg = rs_r1;
@@ -532,21 +528,21 @@
LoadConstantNoClobber(rs_r2, magic);
// EDX:EAX = magic & dividend.
- NewLIR1(kX86Imul32DaR, r2);
+ NewLIR1(kX86Imul32DaR, rs_r2.GetReg());
if (imm > 0 && magic < 0) {
// Add numerator to EDX.
DCHECK(numerator_reg.Valid());
- NewLIR2(kX86Add32RR, r2, numerator_reg.GetReg());
+ NewLIR2(kX86Add32RR, rs_r2.GetReg(), numerator_reg.GetReg());
} else if (imm < 0 && magic > 0) {
DCHECK(numerator_reg.Valid());
- NewLIR2(kX86Sub32RR, r2, numerator_reg.GetReg());
+ NewLIR2(kX86Sub32RR, rs_r2.GetReg(), numerator_reg.GetReg());
}
// Do we need the shift?
if (shift != 0) {
// Shift EDX by 'shift' bits.
- NewLIR2(kX86Sar32RI, r2, shift);
+ NewLIR2(kX86Sar32RI, rs_r2.GetReg(), shift);
}
// Add 1 to EDX if EDX < 0.
@@ -555,10 +551,10 @@
OpRegCopy(rs_r0, rs_r2);
// Move sign bit to bit 0, zeroing the rest.
- NewLIR2(kX86Shr32RI, r2, 31);
+ NewLIR2(kX86Shr32RI, rs_r2.GetReg(), 31);
// EDX = EDX + EAX.
- NewLIR2(kX86Add32RR, r2, r0);
+ NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r0.GetReg());
// Quotient is in EDX.
if (!is_div) {
@@ -571,7 +567,7 @@
OpRegRegImm(kOpMul, rs_r2, rs_r2, imm);
// EDX -= EAX.
- NewLIR2(kX86Sub32RR, r0, r2);
+ NewLIR2(kX86Sub32RR, rs_r0.GetReg(), rs_r2.GetReg());
// For this case, return the result in EAX.
rl_result.reg.SetReg(r0);
@@ -625,12 +621,11 @@
// Expected case.
minus_one_branch->target = NewLIR0(kPseudoTargetLabel);
minint_branch->target = minus_one_branch->target;
- NewLIR1(kX86Idivmod32DaR, r1);
+ NewLIR1(kX86Idivmod32DaR, rs_r1.GetReg());
done->target = NewLIR0(kPseudoTargetLabel);
// Result is in EAX for div and EDX for rem.
- RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, rs_r0,
- INVALID_SREG, INVALID_SREG};
+ RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r0, INVALID_SREG, INVALID_SREG};
if (!is_div) {
rl_result.reg.SetReg(r2);
}
@@ -741,16 +736,16 @@
// TODO: CFI support.
FlushAllRegs();
LockCallTemps();
- RegStorage r_tmp1(RegStorage::k64BitPair, rAX, rDX);
- RegStorage r_tmp2(RegStorage::k64BitPair, rBX, rCX);
+ RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_rAX, rs_rDX);
+ RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_rBX, rs_rCX);
LoadValueDirectWideFixed(rl_src_expected, r_tmp1);
LoadValueDirectWideFixed(rl_src_new_value, r_tmp2);
- NewLIR1(kX86Push32R, rDI);
- MarkTemp(rDI);
- LockTemp(rDI);
- NewLIR1(kX86Push32R, rSI);
- MarkTemp(rSI);
- LockTemp(rSI);
+ NewLIR1(kX86Push32R, rs_rDI.GetReg());
+ MarkTemp(rs_rDI);
+ LockTemp(rs_rDI);
+ NewLIR1(kX86Push32R, rs_rSI.GetReg());
+ MarkTemp(rs_rSI);
+ LockTemp(rs_rSI);
const int push_offset = 4 /* push edi */ + 4 /* push esi */;
int srcObjSp = IsInReg(this, rl_src_obj, rs_rSI) ? 0
: (IsInReg(this, rl_src_obj, rs_rDI) ? 4
@@ -761,22 +756,23 @@
: (IsInReg(this, rl_src_offset, rs_rDI) ? 4
: (SRegOffset(rl_src_offset.s_reg_low) + push_offset));
LoadWordDisp(TargetReg(kSp), srcOffsetSp, rs_rSI);
- NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
+ NewLIR4(kX86LockCmpxchg8bA, rs_rDI.GetReg(), rs_rSI.GetReg(), 0, 0);
// After a store we need to insert barrier in case of potential load. Since the
// locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
GenMemBarrier(kStoreLoad);
- FreeTemp(rSI);
- UnmarkTemp(rSI);
- NewLIR1(kX86Pop32R, rSI);
- FreeTemp(rDI);
- UnmarkTemp(rDI);
- NewLIR1(kX86Pop32R, rDI);
+ FreeTemp(rs_rSI);
+ UnmarkTemp(rs_rSI);
+ NewLIR1(kX86Pop32R, rs_rSI.GetReg());
+ FreeTemp(rs_rDI);
+ UnmarkTemp(rs_rDI);
+ NewLIR1(kX86Pop32R, rs_rDI.GetReg());
FreeCallTemps();
} else {
// EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
FlushReg(rs_r0);
+ Clobber(rs_r0);
LockTemp(rs_r0);
RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
@@ -784,9 +780,9 @@
if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
// Mark card for object assuming new value is stored.
- FreeTemp(r0); // Temporarily release EAX for MarkGCCard().
+ FreeTemp(rs_r0); // Temporarily release EAX for MarkGCCard().
MarkGCCard(rl_new_value.reg, rl_object.reg);
- LockTemp(r0);
+ LockTemp(rs_r0);
}
RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
@@ -797,7 +793,7 @@
// locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
GenMemBarrier(kStoreLoad);
- FreeTemp(r0);
+ FreeTemp(rs_r0);
}
// Convert ZF to boolean
@@ -1003,8 +999,8 @@
LoadBaseDisp(rs_rX86_SP, displacement, dest, k32, sreg);
break;
default:
- m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(), rX86_SP,
- displacement, val);
+ m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(),
+ rs_rX86_SP.GetReg(), displacement, val);
AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */);
break;
}
@@ -1062,7 +1058,7 @@
}
// ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
- NewLIR2(kX86Add32RR, r1, r0);
+ NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r0.GetReg());
// EAX <- 2L
LoadConstantNoClobber(rs_r0, val_lo);
@@ -1071,18 +1067,17 @@
if (src1_in_reg) {
NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
} else {
- LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
+ LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP.GetReg(), displacement + LOWORD_OFFSET);
AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
true /* is_load */, true /* is_64bit */);
}
// EDX <- EDX + ECX (add high words)
- NewLIR2(kX86Add32RR, r2, r1);
+ NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r1.GetReg());
// Result is EDX:EAX
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
- RegStorage::MakeRegPair(rs_r0, rs_r2),
- INVALID_SREG, INVALID_SREG};
+ RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
+ RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
StoreValueWide(rl_dest, rl_result);
return;
}
@@ -1103,7 +1098,7 @@
// ECX <- 1H
if (src1_in_reg) {
- NewLIR2(kX86Mov32RR, r1, rl_src1.reg.GetHighReg());
+ NewLIR2(kX86Mov32RR, rs_r1.GetReg(), rl_src1.reg.GetHighReg());
} else {
LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1,
k32, GetSRegHi(rl_src1.s_reg_low));
@@ -1113,20 +1108,21 @@
// Take advantage of the fact that the values are the same.
// ECX <- ECX * 2L (1H * 2L)
if (src2_in_reg) {
- NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetLowReg());
+ NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
} else {
int displacement = SRegOffset(rl_src2.s_reg_low);
- LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+ LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP.GetReg(),
+ displacement + LOWORD_OFFSET);
AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
true /* is_load */, true /* is_64bit */);
}
// ECX <- 2*ECX (2H * 1L) + (1H * 2L)
- NewLIR2(kX86Add32RR, r1, r1);
+ NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r1.GetReg());
} else {
// EAX <- 2H
if (src2_in_reg) {
- NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetHighReg());
+ NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetHighReg());
} else {
LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0,
k32, GetSRegHi(rl_src2.s_reg_low));
@@ -1134,31 +1130,33 @@
// EAX <- EAX * 1L (2H * 1L)
if (src1_in_reg) {
- NewLIR2(kX86Imul32RR, r0, rl_src1.reg.GetLowReg());
+ NewLIR2(kX86Imul32RR, rs_r0.GetReg(), rl_src1.reg.GetLowReg());
} else {
int displacement = SRegOffset(rl_src1.s_reg_low);
- LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
+ LIR *m = NewLIR3(kX86Imul32RM, rs_r0.GetReg(), rs_rX86_SP.GetReg(),
+ displacement + LOWORD_OFFSET);
AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
true /* is_load */, true /* is_64bit */);
}
// ECX <- ECX * 2L (1H * 2L)
if (src2_in_reg) {
- NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetLowReg());
+ NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
} else {
int displacement = SRegOffset(rl_src2.s_reg_low);
- LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+ LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP.GetReg(),
+ displacement + LOWORD_OFFSET);
AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
true /* is_load */, true /* is_64bit */);
}
// ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
- NewLIR2(kX86Add32RR, r1, r0);
+ NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r0.GetReg());
}
// EAX <- 2L
if (src2_in_reg) {
- NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetLowReg());
+ NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetLowReg());
} else {
LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0,
k32, rl_src2.s_reg_low);
@@ -1169,16 +1167,16 @@
NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
} else {
int displacement = SRegOffset(rl_src1.s_reg_low);
- LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
+ LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP.GetReg(), displacement + LOWORD_OFFSET);
AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
true /* is_load */, true /* is_64bit */);
}
// EDX <- EDX + ECX (add high words)
- NewLIR2(kX86Add32RR, r2, r1);
+ NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r1.GetReg());
// Result is EDX:EAX
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
StoreValueWide(rl_dest, rl_result);
}
@@ -1295,12 +1293,12 @@
// Get one of the source operands into temporary register.
rl_src1 = LoadValueWide(rl_src1, kCoreReg);
- if (IsTemp(rl_src1.reg.GetLowReg()) && IsTemp(rl_src1.reg.GetHighReg())) {
+ if (IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
GenLongRegOrMemOp(rl_src1, rl_src2, op);
} else if (is_commutative) {
rl_src2 = LoadValueWide(rl_src2, kCoreReg);
// We need at least one of them to be a temporary.
- if (!(IsTemp(rl_src2.reg.GetLowReg()) && IsTemp(rl_src2.reg.GetHighReg()))) {
+ if (!(IsTemp(rl_src2.reg.GetLow()) && IsTemp(rl_src2.reg.GetHigh()))) {
rl_src1 = ForceTempWide(rl_src1);
GenLongRegOrMemOp(rl_src1, rl_src2, op);
} else {
@@ -1358,7 +1356,7 @@
StoreValueWide(rl_dest, rl_result);
}
-void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset<4> thread_offset) {
+void X86Mir2Lir::OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset) {
X86OpCode opcode = kX86Bkpt;
switch (op) {
case kOpCmp: opcode = kX86Cmp32RT; break;
@@ -1367,7 +1365,7 @@
LOG(FATAL) << "Bad opcode: " << op;
break;
}
- NewLIR2(opcode, r_dest, thread_offset.Int32Value());
+ NewLIR2(opcode, r_dest.GetReg(), thread_offset.Int32Value());
}
/*
@@ -1375,7 +1373,7 @@
*/
void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_dest, int scale) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
int len_offset = mirror::Array::LengthOffset().Int32Value();
RegLocation rl_result;
rl_array = LoadValue(rl_array, kCoreReg);
@@ -1410,13 +1408,11 @@
}
}
rl_result = EvalLoc(rl_dest, reg_class, true);
+ LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg, size,
+ INVALID_SREG);
if ((size == k64) || (size == kDouble)) {
- LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg.GetLow(),
- rl_result.reg.GetHigh(), size, INVALID_SREG);
StoreValueWide(rl_dest, rl_result);
} else {
- LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg,
- RegStorage::InvalidReg(), size, INVALID_SREG);
StoreValue(rl_dest, rl_result);
}
}
@@ -1427,7 +1423,7 @@
*/
void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
- RegisterClass reg_class = oat_reg_class_by_size(size);
+ RegisterClass reg_class = RegClassBySize(size);
int len_offset = mirror::Array::LengthOffset().Int32Value();
int data_offset;
@@ -1466,24 +1462,19 @@
rl_src = LoadValue(rl_src, reg_class);
}
// If the src reg can't be byte accessed, move it to a temp first.
- if ((size == kSignedByte || size == kUnsignedByte) && rl_src.reg.GetReg() >= 4) {
+ if ((size == kSignedByte || size == kUnsignedByte) &&
+ rl_src.reg.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
RegStorage temp = AllocTemp();
OpRegCopy(temp, rl_src.reg);
- StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, temp,
- RegStorage::InvalidReg(), size, INVALID_SREG);
+ StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, temp, size, INVALID_SREG);
} else {
- if (rl_src.wide) {
- StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg.GetLow(),
- rl_src.reg.GetHigh(), size, INVALID_SREG);
- } else {
- StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg,
- RegStorage::InvalidReg(), size, INVALID_SREG);
- }
+ StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg, size,
+ INVALID_SREG);
}
if (card_mark) {
// Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
if (!constant_index) {
- FreeTemp(rl_index.reg.GetReg());
+ FreeTemp(rl_index.reg);
}
MarkGCCard(rl_src.reg, rl_array.reg);
}
@@ -1501,7 +1492,7 @@
LoadConstant(rl_result.reg.GetLow(), 0);
} else if (shift_amount > 31) {
OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
- FreeTemp(rl_src.reg.GetHighReg());
+ FreeTemp(rl_src.reg.GetHigh());
NewLIR2(kX86Sal32RI, rl_result.reg.GetHighReg(), shift_amount - 32);
LoadConstant(rl_result.reg.GetLow(), 0);
} else {
@@ -1679,7 +1670,7 @@
int32_t value) {
bool in_mem = loc.location != kLocPhysReg;
bool byte_imm = IS_SIMM8(value);
- DCHECK(in_mem || !IsFpReg(loc.reg));
+ DCHECK(in_mem || !loc.reg.IsFloat());
switch (op) {
case Instruction::ADD_LONG:
case Instruction::ADD_LONG_2ADDR:
@@ -1763,7 +1754,7 @@
RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
DCHECK_EQ(rl_result.location, kLocPhysReg);
- DCHECK(!IsFpReg(rl_result.reg));
+ DCHECK(!rl_result.reg.IsFloat());
if (!IsNoOp(op, val_lo)) {
X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
@@ -1788,8 +1779,7 @@
// Can we do this directly into the destination registers?
if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
rl_dest.reg.GetLowReg() == rl_src1.reg.GetLowReg() &&
- rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() &&
- !IsFpReg(rl_dest.reg)) {
+ rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() && !rl_dest.reg.IsFloat()) {
if (!IsNoOp(op, val_lo)) {
X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
NewLIR2(x86op, rl_dest.reg.GetLowReg(), val_lo);
@@ -1829,9 +1819,9 @@
RegStorage result_reg = rl_result.reg;
// SETcc only works with EAX..EDX.
- if (result_reg == object.reg || result_reg.GetReg() >= 4) {
+ if (result_reg == object.reg || result_reg.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
result_reg = AllocTypedTemp(false, kCoreReg);
- DCHECK_LT(result_reg.GetReg(), 4);
+ DCHECK_LT(result_reg.GetRegNum(), rs_rX86_SP.GetRegNum());
}
// Assume that there is no match.
@@ -1930,7 +1920,7 @@
RegLocation rl_result = GetReturn(false);
// SETcc only works with EAX..EDX.
- DCHECK_LT(rl_result.reg.GetReg(), 4);
+ DCHECK_LT(rl_result.reg.GetRegNum(), 4);
// Is the class NULL?
LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
@@ -2091,7 +2081,7 @@
OpMemReg(op, rl_result, t_reg.GetReg());
FreeTemp(t_reg);
return;
- } else if (!IsFpReg(rl_result.reg.GetReg())) {
+ } else if (!rl_result.reg.IsFloat()) {
// Can do this directly into the result register
OpRegReg(op, rl_result.reg, t_reg);
FreeTemp(t_reg);
@@ -2118,7 +2108,7 @@
OpRegMem(op, rl_result.reg, rl_rhs);
StoreFinalValue(rl_dest, rl_result);
return;
- } else if (!IsFpReg(rl_rhs.reg)) {
+ } else if (!rl_rhs.reg.IsFloat()) {
OpRegReg(op, rl_result.reg, rl_rhs.reg);
StoreFinalValue(rl_dest, rl_result);
return;
@@ -2129,7 +2119,7 @@
// Okay, we can do this into memory.
OpMemReg(op, rl_result, rl_rhs.reg.GetReg());
return;
- } else if (!IsFpReg(rl_result.reg)) {
+ } else if (!rl_result.reg.IsFloat()) {
// Can do this directly into the result register.
OpRegReg(op, rl_result.reg, rl_rhs.reg);
StoreFinalValue(rl_dest, rl_result);
@@ -2195,10 +2185,10 @@
bool X86Mir2Lir::IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs) {
// If we have non-core registers, then we can't do good things.
- if (rl_lhs.location == kLocPhysReg && IsFpReg(rl_lhs.reg.GetReg())) {
+ if (rl_lhs.location == kLocPhysReg && rl_lhs.reg.IsFloat()) {
return false;
}
- if (rl_rhs.location == kLocPhysReg && IsFpReg(rl_rhs.reg.GetReg())) {
+ if (rl_rhs.location == kLocPhysReg && rl_rhs.reg.IsFloat()) {
return false;
}
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 3e3fa72..05bef52 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -26,27 +26,53 @@
namespace art {
-// FIXME: restore "static" when usage uncovered
-/*static*/ int core_regs[] = {
- rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI
+static const RegStorage core_regs_arr[] = {
+ rs_rAX, rs_rCX, rs_rDX, rs_rBX, rs_rX86_SP, rs_rBP, rs_rSI, rs_rDI
#ifdef TARGET_REX_SUPPORT
- r8, r9, r10, r11, r12, r13, r14, 15
+ rs_r8, rs_r9, rs_r10, rs_r11, rs_r12, rs_r13, rs_r14, rs_r15
#endif
};
-/*static*/ int ReservedRegs[] = {rX86_SP};
-/*static*/ int core_temps[] = {rAX, rCX, rDX, rBX};
-/*static*/ int FpRegs[] = {
- fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
+static const RegStorage sp_regs_arr[] = {
+ rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
#ifdef TARGET_REX_SUPPORT
- fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
+ rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15
#endif
};
-/*static*/ int fp_temps[] = {
- fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
+static const RegStorage dp_regs_arr[] = {
+ rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7,
#ifdef TARGET_REX_SUPPORT
- fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
+ rs_dr8, rs_dr9, rs_dr10, rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15
#endif
};
+static const RegStorage reserved_regs_arr[] = {rs_rX86_SP};
+static const RegStorage core_temps_arr[] = {rs_rAX, rs_rCX, rs_rDX, rs_rBX};
+static const RegStorage sp_temps_arr[] = {
+ rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
+#ifdef TARGET_REX_SUPPORT
+ rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15
+#endif
+};
+static const RegStorage dp_temps_arr[] = {
+ rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7,
+#ifdef TARGET_REX_SUPPORT
+ rs_dr8, rs_dr9, rs_dr10, rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15
+#endif
+};
+
+static const std::vector<RegStorage> core_regs(core_regs_arr,
+ core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
+static const std::vector<RegStorage> sp_regs(sp_regs_arr,
+ sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
+static const std::vector<RegStorage> dp_regs(dp_regs_arr,
+ dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
+static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
+ reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
+static const std::vector<RegStorage> core_temps(core_temps_arr,
+ core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
+static const std::vector<RegStorage> sp_temps(sp_temps_arr,
+ sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
+static const std::vector<RegStorage> dp_temps(dp_temps_arr,
+ dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
RegLocation X86Mir2Lir::LocCReturn() {
return x86_loc_c_return;
@@ -66,29 +92,29 @@
// Return a target-dependent special register.
RegStorage X86Mir2Lir::TargetReg(SpecialTargetRegister reg) {
- int res_reg = RegStorage::kInvalidRegVal;
+ RegStorage res_reg = RegStorage::InvalidReg();
switch (reg) {
- case kSelf: res_reg = rX86_SELF; break;
- case kSuspend: res_reg = rX86_SUSPEND; break;
- case kLr: res_reg = rX86_LR; break;
- case kPc: res_reg = rX86_PC; break;
- case kSp: res_reg = rX86_SP; break;
- case kArg0: res_reg = rX86_ARG0; break;
- case kArg1: res_reg = rX86_ARG1; break;
- case kArg2: res_reg = rX86_ARG2; break;
- case kArg3: res_reg = rX86_ARG3; break;
- case kFArg0: res_reg = rX86_FARG0; break;
- case kFArg1: res_reg = rX86_FARG1; break;
- case kFArg2: res_reg = rX86_FARG2; break;
- case kFArg3: res_reg = rX86_FARG3; break;
- case kRet0: res_reg = rX86_RET0; break;
- case kRet1: res_reg = rX86_RET1; break;
- case kInvokeTgt: res_reg = rX86_INVOKE_TGT; break;
- case kHiddenArg: res_reg = rAX; break;
- case kHiddenFpArg: res_reg = fr0; break;
- case kCount: res_reg = rX86_COUNT; break;
+ case kSelf: res_reg = RegStorage::InvalidReg(); break;
+ case kSuspend: res_reg = RegStorage::InvalidReg(); break;
+ case kLr: res_reg = RegStorage::InvalidReg(); break;
+ case kPc: res_reg = RegStorage::InvalidReg(); break;
+ case kSp: res_reg = rs_rX86_SP; break;
+ case kArg0: res_reg = rs_rX86_ARG0; break;
+ case kArg1: res_reg = rs_rX86_ARG1; break;
+ case kArg2: res_reg = rs_rX86_ARG2; break;
+ case kArg3: res_reg = rs_rX86_ARG3; break;
+ case kFArg0: res_reg = rs_rX86_FARG0; break;
+ case kFArg1: res_reg = rs_rX86_FARG1; break;
+ case kFArg2: res_reg = rs_rX86_FARG2; break;
+ case kFArg3: res_reg = rs_rX86_FARG3; break;
+ case kRet0: res_reg = rs_rX86_RET0; break;
+ case kRet1: res_reg = rs_rX86_RET1; break;
+ case kInvokeTgt: res_reg = rs_rX86_INVOKE_TGT; break;
+ case kHiddenArg: res_reg = rs_rAX; break;
+ case kHiddenFpArg: res_reg = rs_fr0; break;
+ case kCount: res_reg = rs_rX86_COUNT; break;
}
- return RegStorage::Solo32(res_reg);
+ return res_reg;
}
RegStorage X86Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
@@ -106,34 +132,19 @@
}
}
-// Create a double from a pair of singles.
-int X86Mir2Lir::S2d(int low_reg, int high_reg) {
- return X86_S2D(low_reg, high_reg);
-}
-
-// Return mask to strip off fp reg flags and bias.
-uint32_t X86Mir2Lir::FpRegMask() {
- return X86_FP_REG_MASK;
-}
-
-// True if both regs single, both core or both double.
-bool X86Mir2Lir::SameRegType(int reg1, int reg2) {
- return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2));
-}
-
/*
* Decode the register id.
*/
-uint64_t X86Mir2Lir::GetRegMaskCommon(int reg) {
+uint64_t X86Mir2Lir::GetRegMaskCommon(RegStorage reg) {
uint64_t seed;
int shift;
int reg_id;
- reg_id = reg & 0xf;
+ reg_id = reg.GetRegNum();
/* Double registers in x86 are just a single FP register */
seed = 1;
/* FP register starts at bit position 16 */
- shift = X86_FPREG(reg) ? kX86FPReg0 : 0;
+ shift = reg.IsFloat() ? kX86FPReg0 : 0;
/* Expand the double register id into single offset */
shift += reg_id;
return (seed << shift);
@@ -162,34 +173,34 @@
}
if (flags & REG_DEFA) {
- SetupRegMask(&lir->u.m.def_mask, rAX);
+ SetupRegMask(&lir->u.m.def_mask, rs_rAX.GetReg());
}
if (flags & REG_DEFD) {
- SetupRegMask(&lir->u.m.def_mask, rDX);
+ SetupRegMask(&lir->u.m.def_mask, rs_rDX.GetReg());
}
if (flags & REG_USEA) {
- SetupRegMask(&lir->u.m.use_mask, rAX);
+ SetupRegMask(&lir->u.m.use_mask, rs_rAX.GetReg());
}
if (flags & REG_USEC) {
- SetupRegMask(&lir->u.m.use_mask, rCX);
+ SetupRegMask(&lir->u.m.use_mask, rs_rCX.GetReg());
}
if (flags & REG_USED) {
- SetupRegMask(&lir->u.m.use_mask, rDX);
+ SetupRegMask(&lir->u.m.use_mask, rs_rDX.GetReg());
}
if (flags & REG_USEB) {
- SetupRegMask(&lir->u.m.use_mask, rBX);
+ SetupRegMask(&lir->u.m.use_mask, rs_rBX.GetReg());
}
// Fixup hard to describe instruction: Uses rAX, rCX, rDI; sets rDI.
if (lir->opcode == kX86RepneScasw) {
- SetupRegMask(&lir->u.m.use_mask, rAX);
- SetupRegMask(&lir->u.m.use_mask, rCX);
- SetupRegMask(&lir->u.m.use_mask, rDI);
- SetupRegMask(&lir->u.m.def_mask, rDI);
+ SetupRegMask(&lir->u.m.use_mask, rs_rAX.GetReg());
+ SetupRegMask(&lir->u.m.use_mask, rs_rCX.GetReg());
+ SetupRegMask(&lir->u.m.use_mask, rs_rDI.GetReg());
+ SetupRegMask(&lir->u.m.def_mask, rs_rDI.GetReg());
}
if (flags & USE_FP_STACK) {
@@ -261,12 +272,13 @@
break;
}
case 'r':
- if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) {
- int fp_reg = operand & X86_FP_REG_MASK;
+ if (RegStorage::IsFloat(operand)) {
+ int fp_reg = RegStorage::RegNum(operand);
buf += StringPrintf("xmm%d", fp_reg);
} else {
- DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName));
- buf += x86RegName[operand];
+ int reg_num = RegStorage::RegNum(operand);
+ DCHECK_LT(static_cast<size_t>(reg_num), sizeof(x86RegName));
+ buf += x86RegName[reg_num];
}
break;
case 't':
@@ -329,7 +341,7 @@
void X86Mir2Lir::AdjustSpillMask() {
// Adjustment for LR spilling, x86 has no LR so nothing to do here
- core_spill_mask_ |= (1 << rRET);
+ core_spill_mask_ |= (1 << rs_rRET.GetRegNum());
num_core_spills_++;
}
@@ -339,97 +351,56 @@
* include any holes in the mask. Associate holes with
* Dalvik register INVALID_VREG (0xFFFFU).
*/
-void X86Mir2Lir::MarkPreservedSingle(int v_reg, int reg) {
- UNIMPLEMENTED(WARNING) << "MarkPreservedSingle";
-#if 0
- LOG(FATAL) << "No support yet for promoted FP regs";
-#endif
+void X86Mir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
+ UNIMPLEMENTED(FATAL) << "MarkPreservedSingle";
}
-void X86Mir2Lir::FlushRegWide(RegStorage reg) {
- RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
- RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
- DCHECK(info1 && info2 && info1->pair && info2->pair &&
- (info1->partner == info2->reg) &&
- (info2->partner == info1->reg));
- if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
- if (!(info1->is_temp && info2->is_temp)) {
- /* Should not happen. If it does, there's a problem in eval_loc */
- LOG(FATAL) << "Long half-temp, half-promoted";
- }
-
- info1->dirty = false;
- info2->dirty = false;
- if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
- info1 = info2;
- int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
- StoreBaseDispWide(rs_rX86_SP, VRegOffset(v_reg),
- RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
- }
-}
-
-void X86Mir2Lir::FlushReg(RegStorage reg) {
- // FIXME: need to handle 32 bits in 64-bit register as well as wide values held in single reg.
- DCHECK(!reg.IsPair());
- RegisterInfo* info = GetRegInfo(reg.GetReg());
- if (info->live && info->dirty) {
- info->dirty = false;
- int v_reg = mir_graph_->SRegToVReg(info->s_reg);
- StoreBaseDisp(rs_rX86_SP, VRegOffset(v_reg), reg, k32);
- }
-}
-
-/* Give access to the target-dependent FP register encoding to common code */
-bool X86Mir2Lir::IsFpReg(int reg) {
- return X86_FPREG(reg);
-}
-
-bool X86Mir2Lir::IsFpReg(RegStorage reg) {
- return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
+void X86Mir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
+ UNIMPLEMENTED(FATAL) << "MarkPreservedDouble";
}
/* Clobber all regs that might be used by an external C call */
void X86Mir2Lir::ClobberCallerSave() {
- Clobber(rAX);
- Clobber(rCX);
- Clobber(rDX);
- Clobber(rBX);
+ Clobber(rs_rAX);
+ Clobber(rs_rCX);
+ Clobber(rs_rDX);
+ Clobber(rs_rBX);
}
RegLocation X86Mir2Lir::GetReturnWideAlt() {
RegLocation res = LocCReturnWide();
- CHECK(res.reg.GetLowReg() == rAX);
- CHECK(res.reg.GetHighReg() == rDX);
- Clobber(rAX);
- Clobber(rDX);
- MarkInUse(rAX);
- MarkInUse(rDX);
- MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
+ DCHECK(res.reg.GetLowReg() == rs_rAX.GetReg());
+ DCHECK(res.reg.GetHighReg() == rs_rDX.GetReg());
+ Clobber(rs_rAX);
+ Clobber(rs_rDX);
+ MarkInUse(rs_rAX);
+ MarkInUse(rs_rDX);
+ MarkWide(res.reg);
return res;
}
RegLocation X86Mir2Lir::GetReturnAlt() {
RegLocation res = LocCReturn();
- res.reg.SetReg(rDX);
- Clobber(rDX);
- MarkInUse(rDX);
+ res.reg.SetReg(rs_rDX.GetReg());
+ Clobber(rs_rDX);
+ MarkInUse(rs_rDX);
return res;
}
/* To be used when explicitly managing register use */
void X86Mir2Lir::LockCallTemps() {
- LockTemp(rX86_ARG0);
- LockTemp(rX86_ARG1);
- LockTemp(rX86_ARG2);
- LockTemp(rX86_ARG3);
+ LockTemp(rs_rX86_ARG0);
+ LockTemp(rs_rX86_ARG1);
+ LockTemp(rs_rX86_ARG2);
+ LockTemp(rs_rX86_ARG3);
}
/* To be used when explicitly managing register use */
void X86Mir2Lir::FreeCallTemps() {
- FreeTemp(rX86_ARG0);
- FreeTemp(rX86_ARG1);
- FreeTemp(rX86_ARG2);
- FreeTemp(rX86_ARG3);
+ FreeTemp(rs_rX86_ARG0);
+ FreeTemp(rs_rX86_ARG1);
+ FreeTemp(rs_rX86_ARG2);
+ FreeTemp(rs_rX86_ARG3);
}
bool X86Mir2Lir::ProvidesFullMemoryBarrier(X86OpCode opcode) {
@@ -495,40 +466,35 @@
RegStorage X86Mir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
- return AllocTempFloat();
+ return AllocTempSingle();
}
return AllocTemp();
}
void X86Mir2Lir::CompilerInitializeRegAlloc() {
- int num_regs = sizeof(core_regs)/sizeof(*core_regs);
- int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
- int num_temps = sizeof(core_temps)/sizeof(*core_temps);
- int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
- int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
- reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
- kArenaAllocRegAlloc));
- reg_pool_->num_core_regs = num_regs;
- reg_pool_->core_regs =
- static_cast<RegisterInfo*>(arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs),
- kArenaAllocRegAlloc));
- reg_pool_->num_fp_regs = num_fp_regs;
- reg_pool_->FPRegs =
- static_cast<RegisterInfo *>(arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs),
- kArenaAllocRegAlloc));
- CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
- CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
- // Keep special registers from being allocated
- for (int i = 0; i < num_reserved; i++) {
- MarkInUse(ReservedRegs[i]);
+ reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
+ core_temps, sp_temps, dp_temps);
+
+ // Target-specific adjustments.
+
+ // Alias single precision xmm to double xmms.
+ // TODO: as needed, add larger vector sizes - alias all to the largest.
+ GrowableArray<RegisterInfo*>::Iterator it(®_pool_->sp_regs_);
+ for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+ int sp_reg_num = info->GetReg().GetRegNum();
+ RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | sp_reg_num);
+ RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
+ // 64-bit xmm vector register's master storage should refer to itself.
+ DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
+ // Redirect 32-bit vector's master storage to 64-bit vector.
+ info->SetMaster(dp_reg_info);
}
- // Mark temp regs - all others not in use can be used for promotion
- for (int i = 0; i < num_temps; i++) {
- MarkTemp(core_temps[i]);
- }
- for (int i = 0; i < num_fp_temps; i++) {
- MarkTemp(fp_temps[i]);
- }
+
+ // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
+ // TODO: adjust for x86/hard float calling convention.
+ reg_pool_->next_core_reg_ = 2;
+ reg_pool_->next_sp_reg_ = 2;
+ reg_pool_->next_dp_reg_ = 1;
}
void X86Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
@@ -541,8 +507,7 @@
if ((free_low != keep_low) && (free_low != keep_high) &&
(free_high != keep_low) && (free_high != keep_high)) {
// No overlap, free both
- FreeTemp(free_low);
- FreeTemp(free_high);
+ FreeTemp(rl_free.reg);
}
}
@@ -551,7 +516,7 @@
return;
}
// Spill mask not including fake return address register
- uint32_t mask = core_spill_mask_ & ~(1 << rRET);
+ uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
int offset = frame_size_ - (4 * num_core_spills_);
for (int reg = 0; mask; mask >>= 1, reg++) {
if (mask & 0x1) {
@@ -566,7 +531,7 @@
return;
}
// Spill mask not including fake return address register
- uint32_t mask = core_spill_mask_ & ~(1 << rRET);
+ uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
int offset = frame_size_ - (4 * num_core_spills_);
for (int reg = 0; mask; mask >>= 1, reg++) {
if (mask & 0x1) {
@@ -629,215 +594,6 @@
return X86Mir2Lir::EncodingMap[opcode].fmt;
}
-/*
- * Return an updated location record with current in-register status.
- * If the value lives in live temps, reflect that fact. No code
- * is generated. If the live value is part of an older pair,
- * clobber both low and high.
- */
-// TODO: Reunify with common code after 'pair mess' has been fixed
-RegLocation X86Mir2Lir::UpdateLocWide(RegLocation loc) {
- DCHECK(loc.wide);
- DCHECK(CheckCorePoolSanity());
- if (loc.location != kLocPhysReg) {
- DCHECK((loc.location == kLocDalvikFrame) ||
- (loc.location == kLocCompilerTemp));
- // Are the dalvik regs already live in physical registers?
- RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg);
-
- // Handle FP registers specially on x86.
- if (info_lo && IsFpReg(info_lo->reg)) {
- bool match = true;
-
- // We can't match a FP register with a pair of Core registers.
- match = match && (info_lo->pair == 0);
-
- if (match) {
- // We can reuse;update the register usage info.
- loc.location = kLocPhysReg;
- loc.vec_len = kVectorLength8;
- // TODO: use k64BitVector
- loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_lo->reg);
- DCHECK(IsFpReg(loc.reg.GetLowReg()));
- return loc;
- }
- // We can't easily reuse; clobber and free any overlaps.
- if (info_lo) {
- Clobber(info_lo->reg);
- FreeTemp(info_lo->reg);
- if (info_lo->pair)
- Clobber(info_lo->partner);
- }
- } else {
- RegisterInfo* info_hi = AllocLive(GetSRegHi(loc.s_reg_low), kAnyReg);
- bool match = true;
- match = match && (info_lo != NULL);
- match = match && (info_hi != NULL);
- // Are they both core or both FP?
- match = match && (IsFpReg(info_lo->reg) == IsFpReg(info_hi->reg));
- // If a pair of floating point singles, are they properly aligned?
- if (match && IsFpReg(info_lo->reg)) {
- match &= ((info_lo->reg & 0x1) == 0);
- match &= ((info_hi->reg - info_lo->reg) == 1);
- }
- // If previously used as a pair, it is the same pair?
- if (match && (info_lo->pair || info_hi->pair)) {
- match = (info_lo->pair == info_hi->pair);
- match &= ((info_lo->reg == info_hi->partner) &&
- (info_hi->reg == info_lo->partner));
- }
- if (match) {
- // Can reuse - update the register usage info
- loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_hi->reg);
- loc.location = kLocPhysReg;
- MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
- DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
- return loc;
- }
- // Can't easily reuse - clobber and free any overlaps
- if (info_lo) {
- Clobber(info_lo->reg);
- FreeTemp(info_lo->reg);
- if (info_lo->pair)
- Clobber(info_lo->partner);
- }
- if (info_hi) {
- Clobber(info_hi->reg);
- FreeTemp(info_hi->reg);
- if (info_hi->pair)
- Clobber(info_hi->partner);
- }
- }
- }
- return loc;
-}
-
-// TODO: Reunify with common code after 'pair mess' has been fixed
-RegLocation X86Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) {
- DCHECK(loc.wide);
-
- loc = UpdateLocWide(loc);
-
- /* If it is already in a register, we can assume proper form. Is it the right reg class? */
- if (loc.location == kLocPhysReg) {
- DCHECK_EQ(IsFpReg(loc.reg.GetLowReg()), loc.IsVectorScalar());
- if (!RegClassMatches(reg_class, loc.reg)) {
- /* It is the wrong register class. Reallocate and copy. */
- if (!IsFpReg(loc.reg.GetLowReg())) {
- // We want this in a FP reg, and it is in core registers.
- DCHECK(reg_class != kCoreReg);
- // Allocate this into any FP reg, and mark it with the right size.
- int32_t low_reg = AllocTypedTemp(true, reg_class).GetReg();
- OpVectorRegCopyWide(low_reg, loc.reg.GetLowReg(), loc.reg.GetHighReg());
- CopyRegInfo(low_reg, loc.reg.GetLowReg());
- Clobber(loc.reg);
- loc.reg.SetReg(low_reg);
- loc.reg.SetHighReg(low_reg); // Play nice with existing code.
- loc.vec_len = kVectorLength8;
- } else {
- // The value is in a FP register, and we want it in a pair of core registers.
- DCHECK_EQ(reg_class, kCoreReg);
- DCHECK_EQ(loc.reg.GetLowReg(), loc.reg.GetHighReg());
- RegStorage new_regs = AllocTypedTempWide(false, kCoreReg); // Force to core registers.
- OpRegCopyWide(new_regs, loc.reg);
- CopyRegInfo(new_regs.GetLowReg(), loc.reg.GetLowReg());
- CopyRegInfo(new_regs.GetHighReg(), loc.reg.GetHighReg());
- Clobber(loc.reg);
- loc.reg = new_regs;
- MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
- DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
- }
- }
- return loc;
- }
-
- DCHECK_NE(loc.s_reg_low, INVALID_SREG);
- DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
-
- loc.reg = AllocTypedTempWide(loc.fp, reg_class);
-
- // FIXME: take advantage of RegStorage notation.
- if (loc.reg.GetLowReg() == loc.reg.GetHighReg()) {
- DCHECK(IsFpReg(loc.reg.GetLowReg()));
- loc.vec_len = kVectorLength8;
- } else {
- MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
- }
- if (update) {
- loc.location = kLocPhysReg;
- MarkLive(loc.reg.GetLow(), loc.s_reg_low);
- if (loc.reg.GetLowReg() != loc.reg.GetHighReg()) {
- MarkLive(loc.reg.GetHigh(), GetSRegHi(loc.s_reg_low));
- }
- }
- return loc;
-}
-
-// TODO: Reunify with common code after 'pair mess' has been fixed
-RegLocation X86Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) {
- if (loc.wide)
- return EvalLocWide(loc, reg_class, update);
-
- loc = UpdateLoc(loc);
-
- if (loc.location == kLocPhysReg) {
- if (!RegClassMatches(reg_class, loc.reg)) {
- /* Wrong register class. Realloc, copy and transfer ownership. */
- RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
- OpRegCopy(new_reg, loc.reg);
- CopyRegInfo(new_reg, loc.reg);
- Clobber(loc.reg);
- loc.reg = new_reg;
- if (IsFpReg(loc.reg.GetReg()) && reg_class != kCoreReg)
- loc.vec_len = kVectorLength4;
- }
- return loc;
- }
-
- DCHECK_NE(loc.s_reg_low, INVALID_SREG);
-
- loc.reg = AllocTypedTemp(loc.fp, reg_class);
- if (IsFpReg(loc.reg.GetReg()) && reg_class != kCoreReg)
- loc.vec_len = kVectorLength4;
-
- if (update) {
- loc.location = kLocPhysReg;
- MarkLive(loc.reg, loc.s_reg_low);
- }
- return loc;
-}
-
-RegStorage X86Mir2Lir::AllocTempDouble() {
- // We really don't need a pair of registers.
- // FIXME - update to double
- int reg = AllocTempFloat().GetReg();
- return RegStorage(RegStorage::k64BitPair, reg, reg);
-}
-
-// TODO: Reunify with common code after 'pair mess' has been fixed
-void X86Mir2Lir::ResetDefLocWide(RegLocation rl) {
- DCHECK(rl.wide);
- RegisterInfo* p_low = IsTemp(rl.reg.GetLowReg());
- if (IsFpReg(rl.reg.GetLowReg())) {
- // We are using only the low register.
- if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) {
- NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low);
- }
- ResetDef(rl.reg.GetLowReg());
- } else {
- RegisterInfo* p_high = IsTemp(rl.reg.GetHighReg());
- if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) {
- DCHECK(p_low->pair);
- NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low);
- }
- if (p_high && !(cu_->disable_opt & (1 << kSuppressLoads))) {
- DCHECK(p_high->pair);
- }
- ResetDef(rl.reg.GetLowReg());
- ResetDef(rl.reg.GetHighReg());
- }
-}
-
void X86Mir2Lir::GenConstWide(RegLocation rl_dest, int64_t value) {
// Can we do this directly to memory?
rl_dest = UpdateLocWide(rl_dest);
@@ -872,7 +628,6 @@
<< (loc.ref ? " r" : " ")
<< (loc.high_word ? " h" : " ")
<< (loc.home ? " H" : " ")
- << " vec_len: " << loc.vec_len
<< ", low: " << static_cast<int>(loc.reg.GetLowReg())
<< ", high: " << static_cast<int>(loc.reg.GetHighReg())
<< ", s_reg: " << loc.s_reg_low
@@ -1059,7 +814,7 @@
// We need to preserve EDI, but have no spare registers, so push it on the stack.
// We have to remember that all stack addresses after this are offset by sizeof(EDI).
- NewLIR1(kX86Push32R, rDI);
+ NewLIR1(kX86Push32R, rs_rDI.GetReg());
// Compute the number of words to search in to rCX.
Load32Disp(rs_rDX, count_offset, rs_rCX);
@@ -1096,7 +851,7 @@
OpRegReg(kOpSub, rs_rCX, rl_start.reg);
if (rl_start.reg == rs_rDI) {
// The special case. We will use EDI further, so lets put start index to stack.
- NewLIR1(kX86Push32R, rDI);
+ NewLIR1(kX86Push32R, rs_rDI.GetReg());
is_index_on_stack = true;
}
} else {
@@ -1110,7 +865,7 @@
length_compare = OpCmpBranch(kCondLe, rs_rCX, rs_rBX, nullptr);
OpRegReg(kOpSub, rs_rCX, rs_rBX);
// Put the start index to stack.
- NewLIR1(kX86Push32R, rBX);
+ NewLIR1(kX86Push32R, rs_rBX.GetReg());
is_index_on_stack = true;
}
}
@@ -1130,12 +885,12 @@
if (start_value == 0) {
OpRegCopy(rs_rDI, rs_rBX);
} else {
- NewLIR3(kX86Lea32RM, rDI, rBX, 2 * start_value);
+ NewLIR3(kX86Lea32RM, rs_rDI.GetReg(), rs_rBX.GetReg(), 2 * start_value);
}
} else {
if (is_index_on_stack == true) {
// Load the start index from stack.
- NewLIR1(kX86Pop32R, rDX);
+ NewLIR1(kX86Pop32R, rs_rDX.GetReg());
OpLea(rs_rDI, rs_rBX, rs_rDX, 1, 0);
} else {
OpLea(rs_rDI, rs_rBX, rl_start.reg, 1, 0);
@@ -1153,7 +908,7 @@
// index = ((curr_ptr - orig_ptr) / 2) - 1.
OpRegReg(kOpSub, rs_rDI, rs_rBX);
OpRegImm(kOpAsr, rs_rDI, 1);
- NewLIR3(kX86Lea32RM, rl_return.reg.GetReg(), rDI, -1);
+ NewLIR3(kX86Lea32RM, rl_return.reg.GetReg(), rs_rDI.GetReg(), -1);
LIR *all_done = NewLIR1(kX86Jmp8, 0);
// Failed to match; return -1.
@@ -1165,7 +920,7 @@
// And join up at the end.
all_done->target = NewLIR0(kPseudoTargetLabel);
// Restore EDI from the stack.
- NewLIR1(kX86Pop32R, rDI);
+ NewLIR1(kX86Pop32R, rs_rDI.GetReg());
// Out of line code returns here.
if (slowpath_branch != nullptr) {
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 4d45055..da6ded5 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -26,18 +26,19 @@
LIR* X86Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
int opcode;
/* must be both DOUBLE or both not DOUBLE */
- DCHECK_EQ(X86_DOUBLEREG(r_dest.GetReg()), X86_DOUBLEREG(r_src.GetReg()));
- if (X86_DOUBLEREG(r_dest.GetReg())) {
+ DCHECK(r_dest.IsFloat() || r_src.IsFloat());
+ DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
+ if (r_dest.IsDouble()) {
opcode = kX86MovsdRR;
} else {
- if (X86_SINGLEREG(r_dest.GetReg())) {
- if (X86_SINGLEREG(r_src.GetReg())) {
+ if (r_dest.IsSingle()) {
+ if (r_src.IsSingle()) {
opcode = kX86MovssRR;
} else { // Fpr <- Gpr
opcode = kX86MovdxrRR;
}
} else { // Gpr <- Fpr
- DCHECK(X86_SINGLEREG(r_src.GetReg()));
+ DCHECK(r_src.IsSingle()) << "Raw: 0x" << std::hex << r_src.GetRawBits();
opcode = kX86MovdrxRR;
}
}
@@ -76,11 +77,10 @@
*/
LIR* X86Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
RegStorage r_dest_save = r_dest;
- if (X86_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
if (value == 0) {
return NewLIR2(kX86XorpsRR, r_dest.GetReg(), r_dest.GetReg());
}
- DCHECK(X86_SINGLEREG(r_dest.GetReg()));
r_dest = AllocTemp();
}
@@ -92,7 +92,7 @@
res = NewLIR2(kX86Mov32RI, r_dest.GetReg(), value);
}
- if (X86_FPREG(r_dest_save.GetReg())) {
+ if (r_dest_save.IsFloat()) {
NewLIR2(kX86MovdxrRR, r_dest_save.GetReg(), r_dest.GetReg());
FreeTemp(r_dest);
}
@@ -129,7 +129,7 @@
LIR* X86Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
X86OpCode opcode = kX86Bkpt;
bool byte_imm = IS_SIMM8(value);
- DCHECK(!X86_FPREG(r_dest_src1.GetReg()));
+ DCHECK(!r_dest_src1.IsFloat());
switch (op) {
case kOpLsl: opcode = kX86Sal32RI; break;
case kOpLsr: opcode = kX86Shr32RI; break;
@@ -191,8 +191,10 @@
case kOpOr: opcode = kX86Or32RR; break;
case kOpXor: opcode = kX86Xor32RR; break;
case kOp2Byte:
+ // TODO: there are several instances of this check. A utility function perhaps?
+ // TODO: Similar to Arm's reg < 8 check. Perhaps add attribute checks to RegStorage?
// Use shifts instead of a byte operand if the source can't be byte accessed.
- if (r_src2.GetReg() >= 4) {
+ if (r_src2.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
NewLIR2(kX86Mov32RR, r_dest_src1.GetReg(), r_src2.GetReg());
NewLIR2(kX86Sal32RI, r_dest_src1.GetReg(), 24);
return NewLIR2(kX86Sar32RI, r_dest_src1.GetReg(), 24);
@@ -207,49 +209,49 @@
LOG(FATAL) << "Bad case in OpRegReg " << op;
break;
}
- CHECK(!src2_must_be_cx || r_src2.GetReg() == rCX);
+ CHECK(!src2_must_be_cx || r_src2.GetReg() == rs_rCX.GetReg());
return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
}
LIR* X86Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) {
- DCHECK(!(X86_FPREG(r_base.GetReg())));
+ DCHECK(!r_base.IsFloat());
X86OpCode opcode = kX86Nop;
int dest = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
switch (move_type) {
case kMov8GP:
- CHECK(!X86_FPREG(dest));
+ CHECK(!r_dest.IsFloat());
opcode = kX86Mov8RM;
break;
case kMov16GP:
- CHECK(!X86_FPREG(dest));
+ CHECK(!r_dest.IsFloat());
opcode = kX86Mov16RM;
break;
case kMov32GP:
- CHECK(!X86_FPREG(dest));
+ CHECK(!r_dest.IsFloat());
opcode = kX86Mov32RM;
break;
case kMov32FP:
- CHECK(X86_FPREG(dest));
+ CHECK(r_dest.IsFloat());
opcode = kX86MovssRM;
break;
case kMov64FP:
- CHECK(X86_FPREG(dest));
+ CHECK(r_dest.IsFloat());
opcode = kX86MovsdRM;
break;
case kMovU128FP:
- CHECK(X86_FPREG(dest));
+ CHECK(r_dest.IsFloat());
opcode = kX86MovupsRM;
break;
case kMovA128FP:
- CHECK(X86_FPREG(dest));
+ CHECK(r_dest.IsFloat());
opcode = kX86MovapsRM;
break;
case kMovLo128FP:
- CHECK(X86_FPREG(dest));
+ CHECK(r_dest.IsFloat());
opcode = kX86MovlpsRM;
break;
case kMovHi128FP:
- CHECK(X86_FPREG(dest));
+ CHECK(r_dest.IsFloat());
opcode = kX86MovhpsRM;
break;
case kMov64GP:
@@ -264,45 +266,45 @@
}
LIR* X86Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
- DCHECK(!(X86_FPREG(r_base.GetReg())));
+ DCHECK(!r_base.IsFloat());
int src = r_src.IsPair() ? r_src.GetLowReg() : r_src.GetReg();
X86OpCode opcode = kX86Nop;
switch (move_type) {
case kMov8GP:
- CHECK(!X86_FPREG(src));
+ CHECK(!r_src.IsFloat());
opcode = kX86Mov8MR;
break;
case kMov16GP:
- CHECK(!X86_FPREG(src));
+ CHECK(!r_src.IsFloat());
opcode = kX86Mov16MR;
break;
case kMov32GP:
- CHECK(!X86_FPREG(src));
+ CHECK(!r_src.IsFloat());
opcode = kX86Mov32MR;
break;
case kMov32FP:
- CHECK(X86_FPREG(src));
+ CHECK(r_src.IsFloat());
opcode = kX86MovssMR;
break;
case kMov64FP:
- CHECK(X86_FPREG(src));
+ CHECK(r_src.IsFloat());
opcode = kX86MovsdMR;
break;
case kMovU128FP:
- CHECK(X86_FPREG(src));
+ CHECK(r_src.IsFloat());
opcode = kX86MovupsMR;
break;
case kMovA128FP:
- CHECK(X86_FPREG(src));
+ CHECK(r_src.IsFloat());
opcode = kX86MovapsMR;
break;
case kMovLo128FP:
- CHECK(X86_FPREG(src));
+ CHECK(r_src.IsFloat());
opcode = kX86MovlpsMR;
break;
case kMovHi128FP:
- CHECK(X86_FPREG(src));
+ CHECK(r_src.IsFloat());
opcode = kX86MovhpsMR;
break;
case kMov64GP:
@@ -367,7 +369,7 @@
LOG(FATAL) << "Bad case in OpMemReg " << op;
break;
}
- LIR *l = NewLIR3(opcode, rX86_SP, displacement, r_value);
+ LIR *l = NewLIR3(opcode, rs_rX86_SP.GetReg(), displacement, r_value);
AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */);
AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, false /* is_64bit */);
return l;
@@ -390,7 +392,7 @@
LOG(FATAL) << "Bad case in OpRegMem " << op;
break;
}
- LIR *l = NewLIR3(opcode, r_dest.GetReg(), rX86_SP, displacement);
+ LIR *l = NewLIR3(opcode, r_dest.GetReg(), rs_rX86_SP.GetReg(), displacement);
AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */);
return l;
}
@@ -449,7 +451,7 @@
X86OpCode opcode = IS_SIMM8(value) ? kX86Imul32RRI8 : kX86Imul32RRI;
return NewLIR3(opcode, r_dest.GetReg(), r_src.GetReg(), value);
} else if (op == kOpAnd) {
- if (value == 0xFF && r_src.GetReg() < 4) {
+ if (value == 0xFF && r_src.Low4()) {
return NewLIR2(kX86Movzx8RR, r_dest.GetReg(), r_src.GetReg());
} else if (value == 0xFFFF) {
return NewLIR2(kX86Movzx16RR, r_dest.GetReg(), r_src.GetReg());
@@ -497,7 +499,7 @@
int32_t val_hi = High32Bits(value);
int32_t low_reg_val = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
LIR *res;
- bool is_fp = X86_FPREG(low_reg_val);
+ bool is_fp = RegStorage::IsFloat(low_reg_val);
// TODO: clean this up once we fully recognize 64-bit storage containers.
if (is_fp) {
if (value == 0) {
@@ -530,10 +532,9 @@
res = LoadConstantNoClobber(RegStorage::Solo32(low_reg_val), val_lo);
}
if (val_hi != 0) {
- // FIXME: clean up when AllocTempDouble no longer returns a pair.
RegStorage r_dest_hi = AllocTempDouble();
- LoadConstantNoClobber(RegStorage::Solo32(r_dest_hi.GetLowReg()), val_hi);
- NewLIR2(kX86PunpckldqRR, low_reg_val, r_dest_hi.GetLowReg());
+ LoadConstantNoClobber(r_dest_hi, val_hi);
+ NewLIR2(kX86PunpckldqRR, low_reg_val, r_dest_hi.GetReg());
FreeTemp(r_dest_hi);
}
}
@@ -544,25 +545,20 @@
return res;
}
-// FIXME: don't split r_dest into two storage units.
LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_dest, RegStorage r_dest_hi,
- OpSize size, int s_reg) {
+ int displacement, RegStorage r_dest, OpSize size, int s_reg) {
LIR *load = NULL;
LIR *load2 = NULL;
bool is_array = r_index.Valid();
- bool pair = false;
- bool is64bit = false;
+ bool pair = r_dest.IsPair();
+ bool is64bit = ((size == k64) || (size == kDouble));
X86OpCode opcode = kX86Nop;
switch (size) {
case k64:
case kDouble:
- // TODO: use regstorage attributes here.
- is64bit = true;
- if (X86_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
opcode = is_array ? kX86MovsdRA : kX86MovsdRM;
} else {
- pair = true;
opcode = is_array ? kX86Mov32RA : kX86Mov32RM;
}
// TODO: double store is to unaligned address
@@ -572,9 +568,9 @@
case kSingle:
case kReference: // TODO: update for reference decompression on 64-bit targets.
opcode = is_array ? kX86Mov32RA : kX86Mov32RM;
- if (X86_FPREG(r_dest.GetReg())) {
+ if (r_dest.IsFloat()) {
opcode = is_array ? kX86MovssRA : kX86MovssRM;
- DCHECK(X86_SINGLEREG(r_dest.GetReg()));
+ DCHECK(r_dest.IsFloat());
}
DCHECK_EQ((displacement & 0x3), 0);
break;
@@ -600,13 +596,14 @@
if (!pair) {
load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
} else {
- if (r_base == r_dest) {
- load2 = NewLIR3(opcode, r_dest_hi.GetReg(), r_base.GetReg(),
+ DCHECK(!r_dest.IsFloat()); // Make sure we're not still using a pair here.
+ if (r_base == r_dest.GetLow()) {
+ load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
displacement + HIWORD_OFFSET);
- load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
+ load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
} else {
- load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
- load2 = NewLIR3(opcode, r_dest_hi.GetReg(), r_base.GetReg(),
+ load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
+ load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
displacement + HIWORD_OFFSET);
}
}
@@ -623,36 +620,37 @@
load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
} else {
- if (r_base == r_dest) {
- if (r_dest_hi == r_index) {
+ DCHECK(!r_dest.IsFloat()); // Make sure we're not still using a pair here.
+ if (r_base == r_dest.GetLow()) {
+ if (r_dest.GetHigh() == r_index) {
// We can't use either register for the first load.
RegStorage temp = AllocTemp();
load2 = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + HIWORD_OFFSET);
- load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
- OpRegCopy(r_dest_hi, temp);
+ OpRegCopy(r_dest.GetHigh(), temp);
FreeTemp(temp);
} else {
- load2 = NewLIR5(opcode, r_dest_hi.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + HIWORD_OFFSET);
- load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
}
} else {
- if (r_dest == r_index) {
+ if (r_dest.GetLow() == r_index) {
// We can't use either register for the first load.
RegStorage temp = AllocTemp();
load = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
- load2 = NewLIR5(opcode, r_dest_hi.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + HIWORD_OFFSET);
- OpRegCopy(r_dest, temp);
+ OpRegCopy(r_dest.GetLow(), temp);
FreeTemp(temp);
} else {
- load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
- load2 = NewLIR5(opcode, r_dest_hi.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + HIWORD_OFFSET);
}
}
@@ -665,44 +663,38 @@
/* Load value from base + scaled index. */
LIR* X86Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
int scale, OpSize size) {
- return LoadBaseIndexedDisp(r_base, r_index, scale, 0,
- r_dest, RegStorage::InvalidReg(), size, INVALID_SREG);
+ return LoadBaseIndexedDisp(r_base, r_index, scale, 0, r_dest, size, INVALID_SREG);
}
-LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement,
- RegStorage r_dest, OpSize size, int s_reg) {
+LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
+ OpSize size, int s_reg) {
// TODO: base this on target.
if (size == kWord) {
size = k32;
}
- return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement,
- r_dest, RegStorage::InvalidReg(), size, s_reg);
+ return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest,
+ size, s_reg);
}
LIR* X86Mir2Lir::LoadBaseDispWide(RegStorage r_base, int displacement, RegStorage r_dest,
int s_reg) {
- return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement,
- r_dest.GetLow(), r_dest.GetHigh(), k64, s_reg);
+ return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest, k64, s_reg);
}
LIR* X86Mir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
- int displacement, RegStorage r_src, RegStorage r_src_hi,
- OpSize size, int s_reg) {
+ int displacement, RegStorage r_src, OpSize size, int s_reg) {
LIR *store = NULL;
LIR *store2 = NULL;
bool is_array = r_index.Valid();
- // FIXME: use regstorage attributes in place of these.
- bool pair = false;
- bool is64bit = false;
+ bool pair = r_src.IsPair();
+ bool is64bit = (size == k64) || (size == kDouble);
X86OpCode opcode = kX86Nop;
switch (size) {
case k64:
case kDouble:
- is64bit = true;
- if (X86_FPREG(r_src.GetReg())) {
+ if (r_src.IsFloat()) {
opcode = is_array ? kX86MovsdAR : kX86MovsdMR;
} else {
- pair = true;
opcode = is_array ? kX86Mov32AR : kX86Mov32MR;
}
// TODO: double store is to unaligned address
@@ -712,9 +704,9 @@
case kSingle:
case kReference:
opcode = is_array ? kX86Mov32AR : kX86Mov32MR;
- if (X86_FPREG(r_src.GetReg())) {
+ if (r_src.IsFloat()) {
opcode = is_array ? kX86MovssAR : kX86MovssMR;
- DCHECK(X86_SINGLEREG(r_src.GetReg()));
+ DCHECK(r_src.IsSingle());
}
DCHECK_EQ((displacement & 0x3), 0);
break;
@@ -735,8 +727,9 @@
if (!pair) {
store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetReg());
} else {
- store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetReg());
- store2 = NewLIR3(opcode, r_base.GetReg(), displacement + HIWORD_OFFSET, r_src_hi.GetReg());
+ DCHECK(!r_src.IsFloat()); // Make sure we're not still using a pair here.
+ store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetLowReg());
+ store2 = NewLIR3(opcode, r_base.GetReg(), displacement + HIWORD_OFFSET, r_src.GetHighReg());
}
if (r_base == rs_rX86_SP) {
AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
@@ -751,21 +744,20 @@
store = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET, r_src.GetReg());
} else {
+ DCHECK(!r_src.IsFloat()); // Make sure we're not still using a pair here.
store = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale,
- displacement + LOWORD_OFFSET, r_src.GetReg());
+ displacement + LOWORD_OFFSET, r_src.GetLowReg());
store2 = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale,
- displacement + HIWORD_OFFSET, r_src_hi.GetReg());
+ displacement + HIWORD_OFFSET, r_src.GetHighReg());
}
}
-
return store;
}
/* store value base base + scaled index. */
LIR* X86Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
int scale, OpSize size) {
- return StoreBaseIndexedDisp(r_base, r_index, scale, 0,
- r_src, RegStorage::InvalidReg(), size, INVALID_SREG);
+ return StoreBaseIndexedDisp(r_base, r_index, scale, 0, r_src, size, INVALID_SREG);
}
LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement,
@@ -774,25 +766,13 @@
if (size == kWord) {
size = k32;
}
- return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src,
- RegStorage::InvalidReg(), size, INVALID_SREG);
+ return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src, size,
+ INVALID_SREG);
}
LIR* X86Mir2Lir::StoreBaseDispWide(RegStorage r_base, int displacement, RegStorage r_src) {
return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement,
- r_src.GetLow(), r_src.GetHigh(), k64, INVALID_SREG);
-}
-
-/*
- * Copy a long value in Core registers to an XMM register
- *
- */
-void X86Mir2Lir::OpVectorRegCopyWide(uint8_t fp_reg, uint8_t low_reg, uint8_t high_reg) {
- NewLIR2(kX86MovdxrRR, fp_reg, low_reg);
- int tmp_reg = AllocTempDouble().GetLowReg();
- NewLIR2(kX86MovdxrRR, tmp_reg, high_reg);
- NewLIR2(kX86PunpckldqRR, fp_reg, tmp_reg);
- FreeTemp(tmp_reg);
+ r_src, k64, INVALID_SREG);
}
LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
@@ -889,7 +869,7 @@
void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) {
// Look at all the uses, and see if they are double constants.
- uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+ uint64_t attrs = MIRGraph::GetDataFlowAttributes(static_cast<Instruction::Code>(opcode));
int next_sreg = 0;
if (attrs & DF_UA) {
if (attrs & DF_A_WIDE) {
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 1759cbe..9bf49c3 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -102,27 +102,6 @@
* +========================+
*/
-// Offset to distingish FP regs.
-#define X86_FP_REG_OFFSET 32
-// Offset to distinguish DP FP regs.
-#define X86_FP_DOUBLE (X86_FP_REG_OFFSET + 16)
-// Reg types.
-#define X86_REGTYPE(x) (x & (X86_FP_REG_OFFSET | X86_FP_DOUBLE))
-#define X86_FPREG(x) ((x & X86_FP_REG_OFFSET) == X86_FP_REG_OFFSET)
-#define X86_DOUBLEREG(x) ((x & X86_FP_DOUBLE) == X86_FP_DOUBLE)
-#define X86_SINGLEREG(x) (X86_FPREG(x) && !X86_DOUBLEREG(x))
-
-/*
- * Note: the low register of a floating point pair is sufficient to
- * create the name of a double, but require both names to be passed to
- * allow for asserts to verify that the pair is consecutive if significant
- * rework is done in this area. Also, it is a good reminder in the calling
- * code that reg locations always describe doubles as a pair of singles.
- */
-#define X86_S2D(x, y) ((x) | X86_FP_DOUBLE)
-/* Mask to strip off fp flags */
-#define X86_FP_REG_MASK 0xF
-
enum X86ResourceEncodingPos {
kX86GPReg0 = 0,
kX86RegSP = 4,
@@ -135,72 +114,119 @@
#define ENCODE_X86_REG_SP (1ULL << kX86RegSP)
#define ENCODE_X86_FP_STACK (1ULL << kX86FPStack)
+// FIXME: for 64-bit, perhaps add an X86_64NativeRegisterPool enum?
enum X86NativeRegisterPool {
- r0 = 0,
- rAX = r0,
- r1 = 1,
- rCX = r1,
- r2 = 2,
- rDX = r2,
- r3 = 3,
- rBX = r3,
- r4sp = 4,
- rX86_SP = r4sp,
+ r0 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0,
+ rAX = r0,
+ r1 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 1,
+ rCX = r1,
+ r2 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 2,
+ rDX = r2,
+ r3 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 3,
+ rBX = r3,
+ r4sp = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 4,
+ rX86_SP = r4sp,
r4sib_no_index = r4sp,
- r5 = 5,
- rBP = r5,
- r5sib_no_base = r5,
- r6 = 6,
- rSI = r6,
- r7 = 7,
- rDI = r7,
+ r5 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 5,
+ rBP = r5,
+ r5sib_no_base = r5,
+ r6 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 6,
+ rSI = r6,
+ r7 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 7,
+ rDI = r7,
#ifndef TARGET_REX_SUPPORT
- rRET = 8, // fake return address register for core spill mask.
+ // fake return address register for core spill mask.
+ rRET = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 8,
#else
- r8 = 8,
- r9 = 9,
- r10 = 10,
- r11 = 11,
- r12 = 12,
- r13 = 13,
- r14 = 14,
- r15 = 15,
- rRET = 16, // fake return address register for core spill mask.
+ r8 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 8,
+ r9 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 9,
+ r10 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 10,
+ r11 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 11,
+ r12 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 12,
+ r13 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 13,
+ r14 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 14,
+ r15 = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 15,
+ // fake return address register for core spill mask.
+ rRET = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 16,
#endif
- fr0 = 0 + X86_FP_REG_OFFSET,
- fr1 = 1 + X86_FP_REG_OFFSET,
- fr2 = 2 + X86_FP_REG_OFFSET,
- fr3 = 3 + X86_FP_REG_OFFSET,
- fr4 = 4 + X86_FP_REG_OFFSET,
- fr5 = 5 + X86_FP_REG_OFFSET,
- fr6 = 6 + X86_FP_REG_OFFSET,
- fr7 = 7 + X86_FP_REG_OFFSET,
- fr8 = 8 + X86_FP_REG_OFFSET,
- fr9 = 9 + X86_FP_REG_OFFSET,
- fr10 = 10 + X86_FP_REG_OFFSET,
- fr11 = 11 + X86_FP_REG_OFFSET,
- fr12 = 12 + X86_FP_REG_OFFSET,
- fr13 = 13 + X86_FP_REG_OFFSET,
- fr14 = 14 + X86_FP_REG_OFFSET,
- fr15 = 15 + X86_FP_REG_OFFSET,
+
+ // xmm registers, single precision view
+ fr0 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 0,
+ fr1 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 1,
+ fr2 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 2,
+ fr3 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 3,
+ fr4 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 4,
+ fr5 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 5,
+ fr6 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 6,
+ fr7 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 7,
+
+ // xmm registers, double precision alises
+ dr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
+ dr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1,
+ dr2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
+ dr3 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 3,
+ dr4 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
+ dr5 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 5,
+ dr6 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
+ dr7 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 7,
+
+ // xmm registers, quad precision alises
+ qr0 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 0,
+ qr1 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 1,
+ qr2 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 2,
+ qr3 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 3,
+ qr4 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 4,
+ qr5 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 5,
+ qr6 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 6,
+ qr7 = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 7,
+
+ // TODO: as needed, add 256, 512 and 1024-bit xmm views.
};
-const RegStorage rs_r0(RegStorage::k32BitSolo, r0);
-const RegStorage rs_rAX = rs_r0;
-const RegStorage rs_r1(RegStorage::k32BitSolo, r1);
-const RegStorage rs_rCX = rs_r1;
-const RegStorage rs_r2(RegStorage::k32BitSolo, r2);
-const RegStorage rs_rDX = rs_r2;
-const RegStorage rs_r3(RegStorage::k32BitSolo, r3);
-const RegStorage rs_rBX = rs_r3;
-const RegStorage rs_r4sp(RegStorage::k32BitSolo, r4sp);
-const RegStorage rs_rX86_SP = rs_r4sp;
-const RegStorage rs_r5(RegStorage::k32BitSolo, r5);
-const RegStorage rs_rBP = rs_r5;
-const RegStorage rs_r6(RegStorage::k32BitSolo, r6);
-const RegStorage rs_rSI = rs_r6;
-const RegStorage rs_r7(RegStorage::k32BitSolo, r7);
-const RegStorage rs_rDI = rs_r7;
+constexpr RegStorage rs_r0(RegStorage::kValid | r0);
+constexpr RegStorage rs_rAX = rs_r0;
+constexpr RegStorage rs_r1(RegStorage::kValid | r1);
+constexpr RegStorage rs_rCX = rs_r1;
+constexpr RegStorage rs_r2(RegStorage::kValid | r2);
+constexpr RegStorage rs_rDX = rs_r2;
+constexpr RegStorage rs_r3(RegStorage::kValid | r3);
+constexpr RegStorage rs_rBX = rs_r3;
+constexpr RegStorage rs_r4sp(RegStorage::kValid | r4sp);
+constexpr RegStorage rs_rX86_SP = rs_r4sp;
+constexpr RegStorage rs_r5(RegStorage::kValid | r5);
+constexpr RegStorage rs_rBP = rs_r5;
+constexpr RegStorage rs_r6(RegStorage::kValid | r6);
+constexpr RegStorage rs_rSI = rs_r6;
+constexpr RegStorage rs_r7(RegStorage::kValid | r7);
+constexpr RegStorage rs_rDI = rs_r7;
+constexpr RegStorage rs_rRET(RegStorage::kValid | rRET);
+
+constexpr RegStorage rs_fr0(RegStorage::kValid | fr0);
+constexpr RegStorage rs_fr1(RegStorage::kValid | fr1);
+constexpr RegStorage rs_fr2(RegStorage::kValid | fr2);
+constexpr RegStorage rs_fr3(RegStorage::kValid | fr3);
+constexpr RegStorage rs_fr4(RegStorage::kValid | fr4);
+constexpr RegStorage rs_fr5(RegStorage::kValid | fr5);
+constexpr RegStorage rs_fr6(RegStorage::kValid | fr6);
+constexpr RegStorage rs_fr7(RegStorage::kValid | fr7);
+
+constexpr RegStorage rs_dr0(RegStorage::kValid | dr0);
+constexpr RegStorage rs_dr1(RegStorage::kValid | dr1);
+constexpr RegStorage rs_dr2(RegStorage::kValid | dr2);
+constexpr RegStorage rs_dr3(RegStorage::kValid | dr3);
+constexpr RegStorage rs_dr4(RegStorage::kValid | dr4);
+constexpr RegStorage rs_dr5(RegStorage::kValid | dr5);
+constexpr RegStorage rs_dr6(RegStorage::kValid | dr6);
+constexpr RegStorage rs_dr7(RegStorage::kValid | dr7);
+
+constexpr RegStorage rs_qr0(RegStorage::kValid | qr0);
+constexpr RegStorage rs_qr1(RegStorage::kValid | qr1);
+constexpr RegStorage rs_qr2(RegStorage::kValid | qr2);
+constexpr RegStorage rs_qr3(RegStorage::kValid | qr3);
+constexpr RegStorage rs_qr4(RegStorage::kValid | qr4);
+constexpr RegStorage rs_qr5(RegStorage::kValid | qr5);
+constexpr RegStorage rs_qr6(RegStorage::kValid | qr6);
+constexpr RegStorage rs_qr7(RegStorage::kValid | qr7);
// TODO: elminate these #defines?
#define rX86_ARG0 rAX
@@ -234,19 +260,17 @@
// RegisterLocation templates return values (r_V0, or r_V0/r_V1).
const RegLocation x86_loc_c_return
- {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k32BitSolo, rAX), INVALID_SREG, INVALID_SREG};
const RegLocation x86_loc_c_return_wide
- {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
RegStorage(RegStorage::k64BitPair, rAX, rDX), INVALID_SREG, INVALID_SREG};
-// TODO: update to use k32BitVector (must encode in 7 bits, including fp flag).
const RegLocation x86_loc_c_return_float
- {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, kVectorLength4,
+ {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1,
RegStorage(RegStorage::k32BitSolo, fr0), INVALID_SREG, INVALID_SREG};
-// TODO: update to use k64BitVector (must encode in 7 bits, including fp flag).
const RegLocation x86_loc_c_return_double
- {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1, kVectorLength8,
- RegStorage(RegStorage::k64BitPair, fr0, fr0), INVALID_SREG, INVALID_SREG};
+ {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1,
+ RegStorage(RegStorage::k64BitSolo, dr0), INVALID_SREG, INVALID_SREG};
/*
* The following enum defines the list of supported X86 instructions by the
diff --git a/compiler/dex/reg_storage.h b/compiler/dex/reg_storage.h
index 11bec99..df5aa7b 100644
--- a/compiler/dex/reg_storage.h
+++ b/compiler/dex/reg_storage.h
@@ -21,77 +21,105 @@
namespace art {
/*
- * Representation of the physical register, register pair or vector holding a Dalvik value.
- * The basic configuration of the storage (i.e. solo reg, pair, vector) is common across all
- * targets, but the encoding of the actual storage element is target independent.
+ * 16-bit representation of the physical register container holding a Dalvik value.
+ * The encoding allows up to 32 physical elements per storage class, and supports eight
+ * register container shapes.
*
- * The two most-significant bits describe the basic shape of the storage, while meaning of the
- * lower 14 bits depends on the shape:
+ * [V] [D] [HHHHH] [SSS] [F] [LLLLL]
*
- * [PW]
- * P: 0 -> pair, 1 -> solo (or vector)
- * W: 1 -> 64 bits, 0 -> 32 bits
+ * [LLLLL]
+ * Physical register number for the low or solo register.
+ * 0..31
*
- * [00] [xxxxxxxxxxxxxx] Invalid (typically all zeros)
- * [01] [HHHHHHH] [LLLLLLL] 64-bit storage, composed of 2 32-bit registers
- * [10] [0] [xxxxxx] [RRRRRRR] 32-bit solo register
- * [11] [0] [xxxxxx] [RRRRRRR] 64-bit solo register
- * [10] [1] [xxxxxx] [VVVVVVV] 32-bit vector storage
- * [11] [1] [xxxxxx] [VVVVVVV] 64-bit vector storage
+ * [F]
+ * Describes type of the [LLLLL] register.
+ * 0: Core
+ * 1: Floating point
*
- * x - don't care
- * L - low register number of a pair
- * H - high register number of a pair
- * R - register number of a solo reg
- * V - vector description
+ * [SSS]
+ * Shape of the register container.
+ * 000: Invalid
+ * 001: 32-bit solo register
+ * 010: 64-bit solo register
+ * 011: 64-bit pair consisting of two 32-bit solo registers
+ * 100: 128-bit solo register
+ * 101: 256-bit solo register
+ * 110: 512-bit solo register
+ * 111: 1024-bit solo register
*
- * Note that in all non-invalid cases, the low 7 bits must be sufficient to describe
- * whether the storage element is floating point (see IsFloatReg()).
+ * [HHHHH]
+ * Physical register number of the high register (valid only for register pair).
+ * 0..31
*
+ * [D]
+ * Describes type of the [HHHHH] register (valid only for register pair).
+ * 0: Core
+ * 1: Floating point
+ *
+ * [V]
+ * 0 -> Invalid
+ * 1 -> Valid
+ *
+ * Note that in all non-invalid cases, we can determine if the storage is floating point
+ * by testing bit 6. Though a mismatch appears to be permitted by the format, the [F][D] values
+ * from each half of a pair must match (this allows the high and low regs of a pair to be more
+ * easily individually manipulated).
+ *
+ * On some target architectures, the same underlying physical register container can be given
+ * different views. For example, Arm's 32-bit single-precision floating point registers
+ * s2 and s3 map to the low and high halves of double-precision d1. Similarly, X86's xmm3
+ * vector register can be viewed as 32-bit, 64-bit, 128-bit, etc. In these cases the use of
+ * one view will affect the other views. The RegStorage class does not concern itself
+ * with potential aliasing. That will be done using the associated RegisterInfo struct.
+ * Distinct RegStorage elements should be created for each view of a physical register
+ * container. The management of the aliased physical elements will be handled via RegisterInfo
+ * records.
*/
class RegStorage {
public:
enum RegStorageKind {
- kInvalid = 0x0000,
- k64BitPair = 0x4000,
- k32BitSolo = 0x8000,
- k64BitSolo = 0xc000,
- k32BitVector = 0xa000,
- k64BitVector = 0xe000,
- kPairMask = 0x8000,
- kPair = 0x0000,
- kSizeMask = 0x4000,
- k64Bit = 0x4000,
- k32Bit = 0x0000,
- kVectorMask = 0xa000,
- kVector = 0xa000,
- kSolo = 0x8000,
- kShapeMask = 0xc000,
- kKindMask = 0xe000
+ kValidMask = 0x8000,
+ kValid = 0x8000,
+ kInvalid = 0x0000,
+ kShapeMask = 0x01c0,
+ k32BitSolo = 0x0040,
+ k64BitSolo = 0x0080,
+ k64BitPair = 0x00c0,
+ k128BitSolo = 0x0100,
+ k256BitSolo = 0x0140,
+ k512BitSolo = 0x0180,
+ k1024BitSolo = 0x01c0,
+ k64BitMask = 0x0180,
+ k64Bits = 0x0080,
+ kShapeTypeMask = 0x01e0,
+ kFloatingPoint = 0x0020,
+ kCoreRegister = 0x0000,
};
- static const uint16_t kRegValMask = 0x007f;
- static const uint16_t kInvalidRegVal = 0x007f;
- static const uint16_t kHighRegShift = 7;
- static const uint16_t kHighRegMask = kRegValMask << kHighRegShift;
+ static const uint16_t kRegValMask = 0x01ff; // Num, type and shape.
+ static const uint16_t kRegTypeMask = 0x003f; // Num and type.
+ static const uint16_t kRegNumMask = 0x001f; // Num only.
+ static const uint16_t kMaxRegs = kRegValMask + 1;
+ // TODO: deprecate use of kInvalidRegVal and speed up GetReg().
+ static const uint16_t kInvalidRegVal = 0x01ff;
+ static const uint16_t kHighRegShift = 9;
+ static const uint16_t kShapeMaskShift = 6;
+ static const uint16_t kHighRegMask = (kRegTypeMask << kHighRegShift);
+ // Reg is [F][LLLLL], will override any existing shape and use rs_kind.
RegStorage(RegStorageKind rs_kind, int reg) {
- DCHECK_NE(rs_kind & kShapeMask, kInvalid);
- DCHECK_NE(rs_kind & kShapeMask, k64BitPair);
- DCHECK_EQ(rs_kind & ~kKindMask, 0);
- DCHECK_EQ(reg & ~kRegValMask, 0);
- reg_ = rs_kind | reg;
+ DCHECK_NE(rs_kind, k64BitPair);
+ DCHECK_EQ(rs_kind & ~kShapeMask, 0);
+ reg_ = kValid | rs_kind | (reg & kRegTypeMask);
}
RegStorage(RegStorageKind rs_kind, int low_reg, int high_reg) {
DCHECK_EQ(rs_kind, k64BitPair);
- DCHECK_EQ(low_reg & ~kRegValMask, 0);
- DCHECK_EQ(high_reg & ~kRegValMask, 0);
- reg_ = rs_kind | (high_reg << kHighRegShift) | low_reg;
+ DCHECK_EQ(low_reg & kFloatingPoint, high_reg & kFloatingPoint);
+ reg_ = kValid | rs_kind | ((high_reg & kRegTypeMask) << kHighRegShift) | (low_reg & kRegTypeMask);
}
- explicit RegStorage(uint16_t val) : reg_(val) {}
+ constexpr explicit RegStorage(uint16_t val) : reg_(val) {}
RegStorage() : reg_(kInvalid) {}
- ~RegStorage() {}
bool operator==(const RegStorage rhs) const {
return (reg_ == rhs.GetRawBits());
@@ -102,73 +130,127 @@
}
bool Valid() const {
- return ((reg_ & kShapeMask) != kInvalid);
+ return ((reg_ & kValidMask) == kValid);
}
bool Is32Bit() const {
- return ((reg_ & kSizeMask) == k32Bit);
+ return ((reg_ & kShapeMask) == k32BitSolo);
}
bool Is64Bit() const {
- return ((reg_ & kSizeMask) == k64Bit);
+ return ((reg_ & k64BitMask) == k64Bits);
}
bool IsPair() const {
- return ((reg_ & kPairMask) == kPair);
+ return ((reg_ & kShapeMask) == k64BitPair);
}
- bool IsSolo() const {
- return ((reg_ & kVectorMask) == kSolo);
+ bool IsFloat() const {
+ DCHECK(Valid());
+ return ((reg_ & kFloatingPoint) == kFloatingPoint);
}
- bool IsVector() const {
- return ((reg_ & kVectorMask) == kVector);
+ bool IsDouble() const {
+ DCHECK(Valid());
+ return (reg_ & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
+ }
+
+ bool IsSingle() const {
+ DCHECK(Valid());
+ return (reg_ & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
+ }
+
+ static bool IsFloat(uint16_t reg) {
+ return ((reg & kFloatingPoint) == kFloatingPoint);
+ }
+
+ static bool IsDouble(uint16_t reg) {
+ return (reg & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
+ }
+
+ static bool IsSingle(uint16_t reg) {
+ return (reg & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
}
// Used to retrieve either the low register of a pair, or the only register.
int GetReg() const {
- DCHECK(!IsPair());
+ DCHECK(!IsPair()) << "reg_ = 0x" << std::hex << reg_;
return Valid() ? (reg_ & kRegValMask) : kInvalidRegVal;
}
+ // Sets shape, type and num of solo.
void SetReg(int reg) {
DCHECK(Valid());
+ DCHECK(!IsPair());
reg_ = (reg_ & ~kRegValMask) | reg;
}
+ // Set the reg number and type only, target remain 64-bit pair.
void SetLowReg(int reg) {
DCHECK(IsPair());
- reg_ = (reg_ & ~kRegValMask) | reg;
+ reg_ = (reg_ & ~kRegTypeMask) | (reg & kRegTypeMask);
}
- // Retrieve the least significant register of a pair.
+ // Retrieve the least significant register of a pair and return as 32-bit solo.
int GetLowReg() const {
DCHECK(IsPair());
- return (reg_ & kRegValMask);
+ return ((reg_ & kRegTypeMask) | k32BitSolo);
}
// Create a stand-alone RegStorage from the low reg of a pair.
RegStorage GetLow() const {
DCHECK(IsPair());
- return RegStorage(k32BitSolo, reg_ & kRegValMask);
+ return RegStorage(k32BitSolo, reg_ & kRegTypeMask);
}
// Retrieve the most significant register of a pair.
int GetHighReg() const {
DCHECK(IsPair());
- return (reg_ & kHighRegMask) >> kHighRegShift;
+ return k32BitSolo | ((reg_ & kHighRegMask) >> kHighRegShift);
}
// Create a stand-alone RegStorage from the high reg of a pair.
RegStorage GetHigh() const {
DCHECK(IsPair());
- return RegStorage(k32BitSolo, (reg_ & kHighRegMask) >> kHighRegShift);
+ return RegStorage(kValid | GetHighReg());
}
void SetHighReg(int reg) {
DCHECK(IsPair());
- reg_ = (reg_ & ~kHighRegMask) | (reg << kHighRegShift);
- DCHECK_EQ(GetHighReg(), reg);
+ reg_ = (reg_ & ~kHighRegMask) | ((reg & kRegTypeMask) << kHighRegShift);
+ }
+
+ // Return the register number of low or solo.
+ int GetRegNum() const {
+ return reg_ & kRegNumMask;
+ }
+
+ // Aliased double to low single.
+ RegStorage DoubleToLowSingle() const {
+ DCHECK(IsDouble());
+ return FloatSolo32(GetRegNum() << 1);
+ }
+
+ // Aliased double to high single.
+ RegStorage DoubleToHighSingle() const {
+ DCHECK(IsDouble());
+ return FloatSolo32((GetRegNum() << 1) + 1);
+ }
+
+ // Single to aliased double.
+ RegStorage SingleToDouble() const {
+ DCHECK(IsSingle());
+ return FloatSolo64(GetRegNum() >> 1);
+ }
+
+ // Is register number in 0..7?
+ bool Low8() const {
+ return GetRegNum() < 8;
+ }
+
+ // Is register number in 0..3?
+ bool Low4() const {
+ return GetRegNum() < 4;
}
// Combine 2 32-bit solo regs into a pair.
@@ -180,24 +262,61 @@
return RegStorage(k64BitPair, low.GetReg(), high.GetReg());
}
+ static bool SameRegType(RegStorage reg1, RegStorage reg2) {
+ return (reg1.IsDouble() == reg2.IsDouble()) && (reg1.IsSingle() == reg2.IsSingle());
+ }
+
+ static bool SameRegType(int reg1, int reg2) {
+ return (IsDouble(reg1) == IsDouble(reg2)) && (IsSingle(reg1) == IsSingle(reg2));
+ }
+
// Create a 32-bit solo.
static RegStorage Solo32(int reg_num) {
- return RegStorage(k32BitSolo, reg_num);
+ return RegStorage(k32BitSolo, reg_num & kRegTypeMask);
+ }
+
+ // Create a floating point 32-bit solo.
+ static RegStorage FloatSolo32(int reg_num) {
+ return RegStorage(k32BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
}
// Create a 64-bit solo.
static RegStorage Solo64(int reg_num) {
- return RegStorage(k64BitSolo, reg_num);
+ return RegStorage(k64BitSolo, reg_num & kRegTypeMask);
+ }
+
+ // Create a floating point 64-bit solo.
+ static RegStorage FloatSolo64(int reg_num) {
+ return RegStorage(k64BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
}
static RegStorage InvalidReg() {
return RegStorage(kInvalid);
}
+ static uint16_t RegNum(int raw_reg_bits) {
+ return raw_reg_bits & kRegNumMask;
+ }
+
int GetRawBits() const {
return reg_;
}
+ size_t StorageSize() {
+ switch (reg_ & kShapeMask) {
+ case kInvalid: return 0;
+ case k32BitSolo: return 4;
+ case k64BitSolo: return 8;
+ case k64BitPair: return 8; // Is this useful? Might want to disallow taking size of pair.
+ case k128BitSolo: return 16;
+ case k256BitSolo: return 32;
+ case k512BitSolo: return 64;
+ case k1024BitSolo: return 128;
+ default: LOG(FATAL) << "Unexpected shap";
+ }
+ return 0;
+ }
+
private:
uint16_t reg_;
};
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index 4be0f59..95b3d86 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -124,7 +124,7 @@
bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) {
SSARepresentation *ssa_rep = mir->ssa_rep;
if (ssa_rep) {
- uint64_t attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+ uint64_t attrs = GetDataFlowAttributes(mir);
const int* uses = ssa_rep->uses;
const int* defs = ssa_rep->defs;
@@ -403,7 +403,7 @@
}
// FIXME - will likely need to revisit all uses of this.
-static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, kVectorNotUsed,
+static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0,
RegStorage(), INVALID_SREG, INVALID_SREG};
void MIRGraph::InitRegLocations() {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0ad30be..e5decc5 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -905,13 +905,14 @@
bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
bool* is_type_initialized, bool* use_direct_type_ptr,
- uintptr_t* direct_type_ptr) {
+ uintptr_t* direct_type_ptr, bool* out_is_finalizable) {
ScopedObjectAccess soa(Thread::Current());
mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == nullptr) {
return false;
}
+ *out_is_finalizable = resolved_class->IsFinalizable();
const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
if (compiling_boot) {
// boot -> boot class pointers.
@@ -1699,44 +1700,34 @@
!StringPiece(descriptor).ends_with("$NoPreloadHolder;");
if (can_init_static_fields) {
VLOG(compiler) << "Initializing: " << descriptor;
- if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
- // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
- ObjectLock<mirror::Class> lock(soa.Self(), &klass);
- mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
- CHECK_EQ(fields->GetLength(), 1);
- fields->Get(0)->SetObj<false>(klass.get(),
- manager->GetClassLinker()->FindPrimitiveClass('V'));
- klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
- } else {
- // TODO multithreading support. We should ensure the current compilation thread has
- // exclusive access to the runtime and the transaction. To achieve this, we could use
- // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
- // checks in Thread::AssertThreadSuspensionIsAllowable.
- Runtime* const runtime = Runtime::Current();
- Transaction transaction;
+ // TODO multithreading support. We should ensure the current compilation thread has
+ // exclusive access to the runtime and the transaction. To achieve this, we could use
+ // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
+ // checks in Thread::AssertThreadSuspensionIsAllowable.
+ Runtime* const runtime = Runtime::Current();
+ Transaction transaction;
- // Run the class initializer in transaction mode.
- runtime->EnterTransactionMode(&transaction);
- const mirror::Class::Status old_status = klass->GetStatus();
- bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
- // TODO we detach transaction from runtime to indicate we quit the transactional
- // mode which prevents the GC from visiting objects modified during the transaction.
- // Ensure GC is not run so don't access freed objects when aborting transaction.
- const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end");
- runtime->ExitTransactionMode();
+ // Run the class initializer in transaction mode.
+ runtime->EnterTransactionMode(&transaction);
+ const mirror::Class::Status old_status = klass->GetStatus();
+ bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
+ // TODO we detach transaction from runtime to indicate we quit the transactional
+ // mode which prevents the GC from visiting objects modified during the transaction.
+ // Ensure GC is not run so don't access freed objects when aborting transaction.
+ const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end");
+ runtime->ExitTransactionMode();
- if (!success) {
- CHECK(soa.Self()->IsExceptionPending());
- ThrowLocation throw_location;
- mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
- VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
- << exception->Dump();
- soa.Self()->ClearException();
- transaction.Abort();
- CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
- }
- soa.Self()->EndAssertNoThreadSuspension(old_casue);
+ if (!success) {
+ CHECK(soa.Self()->IsExceptionPending());
+ ThrowLocation throw_location;
+ mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
+ VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
+ << exception->Dump();
+ soa.Self()->ClearException();
+ transaction.Abort();
+ CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
}
+ soa.Self()->EndAssertNoThreadSuspension(old_casue);
}
}
soa.Self()->AssertNoPendingException();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index d7d40d5..6ac9cf7 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -210,7 +210,7 @@
bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
bool* is_type_initialized, bool* use_direct_type_ptr,
- uintptr_t* direct_type_ptr);
+ uintptr_t* direct_type_ptr, bool* out_is_finalizable);
// Get the DexCache for the
mirror::DexCache* GetDexCache(const DexCompilationUnit* mUnit)
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index e6d983f..62817e7 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -587,7 +587,7 @@
void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
- Object* ref = obj->GetFieldObject<Object, kVerifyNone, false>(offset);
+ Object* ref = obj->GetFieldObject<Object, kVerifyNone>(offset);
// Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
// image.
copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 1efdd38..b0aa63b 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -409,7 +409,7 @@
uint32_t method_idx = instruction.VRegB_35c();
uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
uint32_t args[5];
- instruction.GetArgs(args);
+ instruction.GetVarArgs(args);
if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
return false;
}
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index ff316e5..8b85d71 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -132,6 +132,12 @@
}
}
+ // Make all registers available for the return value.
+ for (size_t i = 0, e = GetNumberOfRegisters(); i < e; ++i) {
+ blocked_registers_[i] = false;
+ }
+ SetupBlockedRegisters(blocked_registers_);
+
Location result_location = locations->Out();
if (result_location.IsUnallocated()) {
switch (result_location.GetPolicy()) {
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index ce1c4de..1b050cf 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -19,7 +19,7 @@
#include "assembler.h"
-#include "gtest/gtest.h"
+#include "common_runtime_test.h" // For ScratchFile
#include <cstdio>
#include <cstdlib>
@@ -30,6 +30,10 @@
namespace art {
+// Use a glocal static variable to keep the same name for all test data. Else we'll just spam the
+// temp directory.
+static std::string tmpnam_;
+
template<typename Ass, typename Reg, typename Imm>
class AssemblerTest : public testing::Test {
public:
@@ -203,6 +207,10 @@
void SetUp() OVERRIDE {
assembler_.reset(new Ass());
+ // Fake a runtime test for ScratchFile
+ std::string android_data;
+ CommonRuntimeTest::SetEnvironmentVariables(android_data);
+
SetUpHelpers();
}
@@ -667,7 +675,8 @@
// Use a consistent tmpnam, so store it.
std::string GetTmpnam() {
if (tmpnam_.length() == 0) {
- tmpnam_ = std::string(tmpnam(nullptr));
+ ScratchFile tmp;
+ tmpnam_ = tmp.GetFilename() + "asm";
}
return tmpnam_;
}
@@ -677,7 +686,6 @@
std::string resolved_assembler_cmd_;
std::string resolved_objdump_cmd_;
std::string resolved_disassemble_cmd_;
- std::string tmpnam_;
static constexpr size_t OBJDUMP_SECTION_LINE_MIN_TOKENS = 6;
};
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 85a2c9e..7b66613 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1435,4 +1435,118 @@
UNIMPLEMENTED art_quick_shr_long
UNIMPLEMENTED art_quick_ushr_long
UNIMPLEMENTED art_quick_indexof
-UNIMPLEMENTED art_quick_string_compareto
+
+ /*
+ * String's compareTo.
+ *
+ * TODO: Not very optimized.
+ *
+ * On entry:
+ * x0: this object pointer
+ * x1: comp object pointer
+ *
+ */
+ .extern __memcmp16
+ENTRY art_quick_string_compareto
+ mov x2, x0 // x0 is return, use x2 for first input.
+ sub x0, x2, x1 // Same string object?
+ cbnz x0,1f
+ ret
+1: // Different string objects.
+
+ ldr w6, [x2, #STRING_OFFSET_OFFSET]
+ ldr w5, [x1, #STRING_OFFSET_OFFSET]
+ ldr w4, [x2, #STRING_COUNT_OFFSET]
+ ldr w3, [x1, #STRING_COUNT_OFFSET]
+ ldr w2, [x2, #STRING_VALUE_OFFSET]
+ ldr w1, [x1, #STRING_VALUE_OFFSET]
+
+ /*
+ * Now: CharArray* Offset Count
+ * first arg x2 w6 w4
+ * second arg x1 w5 w3
+ */
+
+ // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4.
+ subs x0, x4, x3
+ // Min(count1, count2) into w3.
+ csel x3, x3, x4, ge
+
+ // Build pointer into string data.
+
+ // Add offset in array (substr etc.) (sign extend and << 1).
+ add x2, x2, w6, sxtw #1
+ add x1, x1, w5, sxtw #1
+
+ // Add offset in CharArray to array.
+ add x2, x2, #STRING_DATA_OFFSET
+ add x1, x1, #STRING_DATA_OFFSET
+
+ // Check for long string, do memcmp16 for them.
+ cmp w3, #28 // Constant from arm32.
+ bgt .Ldo_memcmp16
+
+ /*
+ * Now:
+ * x2: *first string data
+ * x1: *second string data
+ * w3: iteration count
+ * x0: return value if comparison equal
+ * x4, x5, x6, x7: free
+ */
+
+ // Do a simple unrolled loop.
+.Lloop:
+ // At least two more elements?
+ subs w3, w3, #2
+ b.lt .Lremainder_or_done
+
+ ldrh w4, [x2], #2
+ ldrh w5, [x1], #2
+
+ ldrh w6, [x2], #2
+ ldrh w7, [x1], #2
+
+ subs w4, w4, w5
+ b.ne .Lw4_result
+
+ subs w6, w6, w7
+ b.ne .Lw6_result
+
+ b .Lloop
+
+.Lremainder_or_done:
+ adds w3, w3, #1
+ b.eq .Lremainder
+ ret
+
+.Lremainder:
+ ldrh w4, [x2], #2
+ ldrh w5, [x1], #2
+ subs w4, w4, w5
+ b.ne .Lw4_result
+ ret
+
+// Result is in w4
+.Lw4_result:
+ sxtw x0, w4
+ ret
+
+// Result is in w6
+.Lw6_result:
+ sxtw x0, w6
+ ret
+
+.Ldo_memcmp16:
+ str x0, [sp,#-16]! // Save x0
+
+ mov x0, x2
+ uxtw x2, w3
+ bl __memcmp16
+
+ ldr x1, [sp], #16 // Restore old x0 = length diff
+
+ cmp x0, #0 // Check the memcmp difference
+ csel x0, x0, x1, ne // x0 := x0 != 0 ? x0 : x1
+ ret
+END art_quick_string_compareto
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 8fbca94..94a7598 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -15,6 +15,7 @@
*/
#include "common_runtime_test.h"
+#include "mirror/string-inl.h"
#include <cstdio>
@@ -182,13 +183,14 @@
#endif
}
-
#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
extern "C" void art_quick_lock_object(void);
#endif
TEST_F(StubTest, LockObject) {
#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+ static constexpr size_t kThinLockLoops = 100;
+
Thread* self = Thread::Current();
// Create an object
ScopedObjectAccess soa(self);
@@ -206,6 +208,72 @@
LockWord lock_after = obj->GetLockWord(false);
LockWord::LockState new_state = lock_after.GetState();
EXPECT_EQ(LockWord::LockState::kThinLocked, new_state);
+ EXPECT_EQ(lock_after.ThinLockCount(), 0U); // Thin lock starts count at zero
+
+ for (size_t i = 1; i < kThinLockLoops; ++i) {
+ Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+ reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+
+ // Check we're at lock count i
+
+ LockWord l_inc = obj->GetLockWord(false);
+ LockWord::LockState l_inc_state = l_inc.GetState();
+ EXPECT_EQ(LockWord::LockState::kThinLocked, l_inc_state);
+ EXPECT_EQ(l_inc.ThinLockCount(), i);
+ }
+
+ // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
+
+#else
+ LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
+ // Force-print to std::cout so it's also outside the logcat.
+ std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+class RandGen {
+ public:
+ explicit RandGen(uint32_t seed) : val_(seed) {}
+
+ uint32_t next() {
+ val_ = val_ * 48271 % 2147483647 + 13;
+ return val_;
+ }
+
+ uint32_t val_;
+};
+
+
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+extern "C" void art_quick_lock_object(void);
+extern "C" void art_quick_unlock_object(void);
+#endif
+
+TEST_F(StubTest, UnlockObject) {
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+ static constexpr size_t kThinLockLoops = 100;
+
+ Thread* self = Thread::Current();
+ // Create an object
+ ScopedObjectAccess soa(self);
+ // garbage is created during ClassLinker::Init
+
+ SirtRef<mirror::String> obj(soa.Self(),
+ mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+ LockWord lock = obj->GetLockWord(false);
+ LockWord::LockState old_state = lock.GetState();
+ EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
+
+ Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+ reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+
+ // This should be an illegal monitor state.
+ EXPECT_TRUE(self->IsExceptionPending());
+ self->ClearException();
+
+ LockWord lock_after = obj->GetLockWord(false);
+ LockWord::LockState new_state = lock_after.GetState();
+ EXPECT_EQ(LockWord::LockState::kUnlocked, new_state);
Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
@@ -214,12 +282,94 @@
LockWord::LockState new_state2 = lock_after2.GetState();
EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
+ Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+ reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+
+ LockWord lock_after3 = obj->GetLockWord(false);
+ LockWord::LockState new_state3 = lock_after3.GetState();
+ EXPECT_EQ(LockWord::LockState::kUnlocked, new_state3);
+
+ // Stress test:
+ // Keep a number of objects and their locks in flight. Randomly lock or unlock one of them in
+ // each step.
+
+ RandGen r(0x1234);
+
+ constexpr size_t kNumberOfLocks = 10; // Number of objects = lock
+ constexpr size_t kIterations = 10000; // Number of iterations
+
+ size_t counts[kNumberOfLocks];
+ SirtRef<mirror::String>* objects[kNumberOfLocks];
+
+ // Initialize = allocate.
+ for (size_t i = 0; i < kNumberOfLocks; ++i) {
+ counts[i] = 0;
+ objects[i] = new SirtRef<mirror::String>(soa.Self(),
+ mirror::String::AllocFromModifiedUtf8(soa.Self(), ""));
+ }
+
+ for (size_t i = 0; i < kIterations; ++i) {
+ // Select which lock to update.
+ size_t index = r.next() % kNumberOfLocks;
+
+ bool lock; // Whether to lock or unlock in this step.
+ if (counts[index] == 0) {
+ lock = true;
+ } else if (counts[index] == kThinLockLoops) {
+ lock = false;
+ } else {
+ // Randomly.
+ lock = r.next() % 2 == 0;
+ }
+
+ if (lock) {
+ Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
+ reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+ counts[index]++;
+ } else {
+ Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
+ reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+ counts[index]--;
+ }
+
+ EXPECT_FALSE(self->IsExceptionPending());
+
+ // Check the new state.
+ LockWord lock_iter = objects[index]->get()->GetLockWord(false);
+ LockWord::LockState iter_state = lock_iter.GetState();
+ if (counts[index] > 0) {
+ EXPECT_EQ(LockWord::LockState::kThinLocked, iter_state);
+ EXPECT_EQ(counts[index] - 1, lock_iter.ThinLockCount());
+ } else {
+ EXPECT_EQ(LockWord::LockState::kUnlocked, iter_state);
+ }
+ }
+
+ // Unlock the remaining count times and then check it's unlocked. Then deallocate.
+ // Go reverse order to correctly handle SirtRefs.
+ for (size_t i = 0; i < kNumberOfLocks; ++i) {
+ size_t index = kNumberOfLocks - 1 - i;
+ size_t count = counts[index];
+ while (count > 0) {
+ Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
+ reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+
+ count--;
+ }
+
+ LockWord lock_after4 = objects[index]->get()->GetLockWord(false);
+ LockWord::LockState new_state4 = lock_after4.GetState();
+ EXPECT_EQ(LockWord::LockState::kUnlocked, new_state4);
+
+ delete objects[index];
+ }
+
// TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
#else
- LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
+ LOG(INFO) << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA;
// Force-print to std::cout so it's also outside the logcat.
- std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
+ std::cout << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
#endif
}
@@ -634,14 +784,14 @@
}
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
extern "C" void art_quick_string_compareto(void);
#endif
TEST_F(StubTest, StringCompareTo) {
TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
// TODO: Check the "Unresolved" allocation stubs
Thread* self = Thread::Current();
@@ -650,30 +800,48 @@
// Create some strings
// Use array so we can index into it and use a matrix for expected results
- constexpr size_t string_count = 7;
- const char* c[string_count] = { "", "", "a", "aa", "ab", "aac", "aac" };
+ // Setup: The first half is standard. The second half uses a non-zero offset.
+ // TODO: Shared backing arrays.
+ constexpr size_t base_string_count = 7;
+ const char* c[base_string_count] = { "", "", "a", "aa", "ab", "aac", "aac" , };
+
+ constexpr size_t string_count = 2 * base_string_count;
SirtRef<mirror::String>* s[string_count];
- for (size_t i = 0; i < string_count; ++i) {
+ for (size_t i = 0; i < base_string_count; ++i) {
s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
c[i]));
}
+ RandGen r(0x1234);
+
+ for (size_t i = base_string_count; i < string_count; ++i) {
+ s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
+ c[i - base_string_count]));
+ int32_t length = s[i]->get()->GetLength();
+ if (length > 1) {
+ // Set a random offset and length.
+ int32_t new_offset = 1 + (r.next() % (length - 1));
+ int32_t rest = length - new_offset - 1;
+ int32_t new_length = 1 + (rest > 0 ? r.next() % rest : 0);
+
+ s[i]->get()->SetField32<false>(mirror::String::CountOffset(), new_length);
+ s[i]->get()->SetField32<false>(mirror::String::OffsetOffset(), new_offset);
+ }
+ }
+
// TODO: wide characters
// Matrix of expectations. First component is first parameter. Note we only check against the
- // sign, not the value.
- int32_t expected[string_count][string_count] = {
- { 0, 0, -1, -1, -1, -1, -1 }, // ""
- { 0, 0, -1, -1, -1, -1, -1 }, // ""
- { 1, 1, 0, -1, -1, -1, -1 }, // "a"
- { 1, 1, 1, 0, -1, -1, -1 }, // "aa"
- { 1, 1, 1, 1, 0, 1, 1 }, // "ab"
- { 1, 1, 1, 1, -1, 0, 0 }, // "aac"
- { 1, 1, 1, 1, -1, 0, 0 } // "aac"
- // "" "" a aa ab aac aac
- };
+ // sign, not the value. As we are testing random offsets, we need to compute this and need to
+ // rely on String::CompareTo being correct.
+ int32_t expected[string_count][string_count];
+ for (size_t x = 0; x < string_count; ++x) {
+ for (size_t y = 0; y < string_count; ++y) {
+ expected[x][y] = s[x]->get()->CompareTo(s[y]->get());
+ }
+ }
// Play with it...
@@ -693,12 +861,17 @@
} conv;
conv.r = result;
int32_t e = expected[x][y];
- EXPECT_TRUE(e == 0 ? conv.i == 0 : true) << "x=" << c[x] << " y=" << c[y];
- EXPECT_TRUE(e < 0 ? conv.i < 0 : true) << "x=" << c[x] << " y=" << c[y];
- EXPECT_TRUE(e > 0 ? conv.i > 0 : true) << "x=" << c[x] << " y=" << c[y];
+ EXPECT_TRUE(e == 0 ? conv.i == 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
+ conv.r;
+ EXPECT_TRUE(e < 0 ? conv.i < 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
+ conv.r;
+ EXPECT_TRUE(e > 0 ? conv.i > 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
+ conv.r;
}
}
+ // TODO: Deallocate things.
+
// Tests done.
#else
LOG(INFO) << "Skipping string_compareto as I don't know how to do that on " << kRuntimeISA;
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 9ccf6c9..7b56718 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -870,18 +870,138 @@
UNIMPLEMENTED art_quick_lshl
UNIMPLEMENTED art_quick_lshr
UNIMPLEMENTED art_quick_lushr
-UNIMPLEMENTED art_quick_set32_instance
-UNIMPLEMENTED art_quick_set64_instance
-UNIMPLEMENTED art_quick_set_obj_instance
-UNIMPLEMENTED art_quick_get32_instance
-UNIMPLEMENTED art_quick_get64_instance
-UNIMPLEMENTED art_quick_get_obj_instance
-UNIMPLEMENTED art_quick_set32_static
-UNIMPLEMENTED art_quick_set64_static
-UNIMPLEMENTED art_quick_set_obj_static
-UNIMPLEMENTED art_quick_get32_static
-UNIMPLEMENTED art_quick_get64_static
-UNIMPLEMENTED art_quick_get_obj_static
+
+DEFINE_FUNCTION art_quick_set32_instance
+ movq 8(%rsp), %rcx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx, Object* and new_val are in rdi/rsi/rdx
+ movq %gs:THREAD_SELF_OFFSET, %r8 // pass Thread::Current()
+ movq %rsp, %r9 // pass SP
+ call PLT_SYMBOL(artSet32InstanceFromCode) // (field_idx, Object*, new_val, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO // return or deliver exception
+END_FUNCTION art_quick_set32_instance
+
+DEFINE_FUNCTION art_quick_set64_instance
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx, Object* and new_val are in rdi/rsi/rdx
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artSet64InstanceFromCode) // (field_idx, Object*, new_val, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO // return or deliver exception
+END_FUNCTION art_quick_set64_instance
+
+DEFINE_FUNCTION art_quick_set_obj_instance
+ movq 8(%rsp), %rcx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx, Object* and new_val are in rdi/rsi/rdx
+ movq %gs:THREAD_SELF_OFFSET, %r8 // pass Thread::Current()
+ movq %rsp, %r9 // pass SP
+ call PLT_SYMBOL(artSetObjInstanceFromCode) // (field_idx, Object*, new_val, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO // return or deliver exception
+END_FUNCTION art_quick_set_obj_instance
+
+DEFINE_FUNCTION art_quick_get32_instance
+ movq 8(%rsp), %rdx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx and Object* are in rdi/rsi
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artGet32InstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
+END_FUNCTION art_quick_get32_instance
+
+DEFINE_FUNCTION art_quick_get64_instance
+ movq 8(%rsp), %rdx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx and Object* are in rdi/rsi
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artGet64InstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
+END_FUNCTION art_quick_get64_instance
+
+DEFINE_FUNCTION art_quick_get_obj_instance
+ movq 8(%rsp), %rdx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx and Object* are in rdi/rsi
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artGetObjInstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
+END_FUNCTION art_quick_get_obj_instance
+
+DEFINE_FUNCTION art_quick_set32_static
+ movq 8(%rsp), %rdx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx and new_val are in rdi/rsi
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artSet32StaticFromCode) // (field_idx, new_val, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO // return or deliver exception
+END_FUNCTION art_quick_set32_static
+
+DEFINE_FUNCTION art_quick_set64_static
+ movq %rsi, %rdx // pass new_val
+ movq 8(%rsp), %rsi // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx is in rdi
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artSet64StaticFromCode) // (field_idx, referrer, new_val, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO // return or deliver exception
+END_FUNCTION art_quick_set64_static
+
+DEFINE_FUNCTION art_quick_set_obj_static
+ movq 8(%rsp), %rdx // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx and new_val are in rdi/rsi
+ movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread::Current()
+ movq %rsp, %r8 // pass SP
+ call PLT_SYMBOL(artSetObjStaticFromCode) // (field_idx, new_val, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_set_obj_static
+
+DEFINE_FUNCTION art_quick_get32_static
+ movq 8(%rsp), %rsi // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx is in rdi
+ movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
+ movq %rsp, %rcx // pass SP
+ call PLT_SYMBOL(artGet32StaticFromCode) // (field_idx, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_get32_static
+
+DEFINE_FUNCTION art_quick_get64_static
+ movq 8(%rsp), %rsi // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx is in rdi
+ movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
+ movq %rsp, %rcx // pass SP
+ call PLT_SYMBOL(artGet64StaticFromCode) // (field_idx, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_get64_static
+
+DEFINE_FUNCTION art_quick_get_obj_static
+ movq 8(%rsp), %rsi // pass referrer
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ // field_idx is in rdi
+ movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
+ movq %rsp, %rcx // pass SP
+ call PLT_SYMBOL(artGetObjStaticFromCode) // (field_idx, referrer, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_get_obj_static
DEFINE_FUNCTION art_quick_proxy_invoke_handler
// Save callee and GPR args, mixed together to agree with core spills bitmap of ref. and args
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 6c53563..df88794 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -66,6 +66,9 @@
SirtRef<mirror::DexCache> dex_cache(Thread::Current(), declaring_class->GetDexCache());
const DexFile& dex_file = *dex_cache->GetDexFile();
resolved_string = ResolveString(dex_file, string_idx, dex_cache);
+ if (resolved_string != nullptr) {
+ DCHECK_EQ(dex_cache->GetResolvedString(string_idx), resolved_string);
+ }
}
return resolved_string;
}
@@ -80,6 +83,9 @@
SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
const DexFile& dex_file = *dex_cache->GetDexFile();
resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ if (resolved_type != nullptr) {
+ DCHECK_EQ(dex_cache->GetResolvedType(type_idx), resolved_type);
+ }
}
return resolved_type;
}
@@ -94,6 +100,9 @@
SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
const DexFile& dex_file = *dex_cache->GetDexFile();
resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ if (resolved_type != nullptr) {
+ DCHECK_EQ(dex_cache->GetResolvedType(type_idx), resolved_type);
+ }
}
return resolved_type;
}
@@ -110,6 +119,9 @@
SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
const DexFile& dex_file = *dex_cache->GetDexFile();
resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, referrer, type);
+ if (resolved_method != nullptr) {
+ DCHECK_EQ(dex_cache->GetResolvedMethod(method_idx), resolved_method);
+ }
}
return resolved_method;
}
@@ -126,6 +138,9 @@
SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
const DexFile& dex_file = *dex_cache->GetDexFile();
resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
+ if (resolved_field != nullptr) {
+ DCHECK_EQ(dex_cache->GetResolvedField(field_idx), resolved_field);
+ }
}
return resolved_field;
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 703229c..dbea0d8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -803,13 +803,29 @@
bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
const char* dex_location,
uint32_t dex_location_checksum,
+ const InstructionSet instruction_set,
std::string* error_msg) {
Runtime* runtime = Runtime::Current();
- const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
- uint32_t image_oat_checksum = image_header.GetOatChecksum();
- uintptr_t image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
- bool image_check = ((oat_file->GetOatHeader().GetImageFileLocationOatChecksum() == image_oat_checksum)
- && (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() == image_oat_data_begin));
+ const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+
+ // If the requested instruction set is the same as the current runtime,
+ // we can use the checksums directly. If it isn't, we'll have to read the
+ // image header from the image for the right instruction set.
+ uint32_t image_oat_checksum = 0;
+ uintptr_t image_oat_data_begin = 0;
+ if (instruction_set == kRuntimeISA) {
+ const ImageHeader& image_header = image_space->GetImageHeader();
+ image_oat_checksum = image_header.GetOatChecksum();
+ image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
+ } else {
+ UniquePtr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeaderOrDie(
+ image_space->GetImageLocation().c_str(), instruction_set));
+ image_oat_checksum = image_header->GetOatChecksum();
+ image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
+ }
+ const OatHeader& oat_header = oat_file->GetOatHeader();
+ bool image_check = ((oat_header.GetImageFileLocationOatChecksum() == image_oat_checksum)
+ && (oat_header.GetImageFileLocationOatDataBegin() == image_oat_data_begin));
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum);
if (oat_dex_file == NULL) {
@@ -873,7 +889,7 @@
dex_file = oat_dex_file->OpenDexFile(error_msg);
} else {
bool verified = VerifyOatFileChecksums(oat_file.get(), dex_location, dex_location_checksum,
- error_msg);
+ kRuntimeISA, error_msg);
if (!verified) {
return nullptr;
}
@@ -3215,12 +3231,8 @@
mirror::ArtMethod* clinit = klass->FindClassInitializer();
if (clinit != NULL) {
CHECK(can_init_statics);
- if (LIKELY(Runtime::Current()->IsStarted())) {
- JValue result;
- clinit->Invoke(self, NULL, 0, &result, "V");
- } else {
- art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL);
- }
+ JValue result;
+ clinit->Invoke(self, NULL, 0, &result, "V");
}
uint64_t t1 = NanoTime();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a23add0..2c6873e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -288,6 +288,7 @@
static bool VerifyOatFileChecksums(const OatFile* oat_file,
const char* dex_location,
uint32_t dex_location_checksum,
+ const InstructionSet instruction_set,
std::string* error_msg);
// TODO: replace this with multiple methods that allocate the correct managed type.
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 723e32c..79d3690 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -57,6 +57,9 @@
class ScratchFile {
public:
ScratchFile() {
+ // ANDROID_DATA needs to be set
+ CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
+ "Are you subclassing RuntimeTest?";
filename_ = getenv("ANDROID_DATA");
filename_ += "/TmpFile-XXXXXX";
int fd = mkstemp(&filename_[0]);
diff --git a/runtime/dex_instruction-inl.h b/runtime/dex_instruction-inl.h
index 207b0b6..ad9491f 100644
--- a/runtime/dex_instruction-inl.h
+++ b/runtime/dex_instruction-inl.h
@@ -24,6 +24,68 @@
//------------------------------------------------------------------------------
// VRegA
//------------------------------------------------------------------------------
+inline bool Instruction::HasVRegA() const {
+ switch (FormatOf(Opcode())) {
+ case k10t: return true;
+ case k10x: return true;
+ case k11n: return true;
+ case k11x: return true;
+ case k12x: return true;
+ case k20t: return true;
+ case k21c: return true;
+ case k21h: return true;
+ case k21s: return true;
+ case k21t: return true;
+ case k22b: return true;
+ case k22c: return true;
+ case k22s: return true;
+ case k22t: return true;
+ case k22x: return true;
+ case k23x: return true;
+ case k30t: return true;
+ case k31c: return true;
+ case k31i: return true;
+ case k31t: return true;
+ case k32x: return true;
+ case k35c: return true;
+ case k3rc: return true;
+ case k51l: return true;
+ default: return false;
+ }
+}
+
+inline int32_t Instruction::VRegA() const {
+ switch (FormatOf(Opcode())) {
+ case k10t: return VRegA_10t();
+ case k10x: return VRegA_10x();
+ case k11n: return VRegA_11n();
+ case k11x: return VRegA_11x();
+ case k12x: return VRegA_12x();
+ case k20t: return VRegA_20t();
+ case k21c: return VRegA_21c();
+ case k21h: return VRegA_21h();
+ case k21s: return VRegA_21s();
+ case k21t: return VRegA_21t();
+ case k22b: return VRegA_22b();
+ case k22c: return VRegA_22c();
+ case k22s: return VRegA_22s();
+ case k22t: return VRegA_22t();
+ case k22x: return VRegA_22x();
+ case k23x: return VRegA_23x();
+ case k30t: return VRegA_30t();
+ case k31c: return VRegA_31c();
+ case k31i: return VRegA_31i();
+ case k31t: return VRegA_31t();
+ case k32x: return VRegA_32x();
+ case k35c: return VRegA_35c();
+ case k3rc: return VRegA_3rc();
+ case k51l: return VRegA_51l();
+ default:
+ LOG(FATAL) << "Tried to access vA of instruction " << Name() << " which has no A operand.";
+ exit(EXIT_FAILURE);
+ }
+}
+
inline int8_t Instruction::VRegA_10t(uint16_t inst_data) const {
DCHECK_EQ(FormatOf(Opcode()), k10t);
return static_cast<int8_t>(InstAA(inst_data));
@@ -147,6 +209,66 @@
//------------------------------------------------------------------------------
// VRegB
//------------------------------------------------------------------------------
+inline bool Instruction::HasVRegB() const {
+ switch (FormatOf(Opcode())) {
+ case k11n: return true;
+ case k12x: return true;
+ case k21c: return true;
+ case k21h: return true;
+ case k21s: return true;
+ case k21t: return true;
+ case k22b: return true;
+ case k22c: return true;
+ case k22s: return true;
+ case k22t: return true;
+ case k22x: return true;
+ case k23x: return true;
+ case k31c: return true;
+ case k31i: return true;
+ case k31t: return true;
+ case k32x: return true;
+ case k35c: return true;
+ case k3rc: return true;
+ case k51l: return true;
+ default: return false;
+ }
+}
+
+inline bool Instruction::HasWideVRegB() const {
+ return FormatOf(Opcode()) == k51l;
+}
+
+inline int32_t Instruction::VRegB() const {
+ switch (FormatOf(Opcode())) {
+ case k11n: return VRegB_11n();
+ case k12x: return VRegB_12x();
+ case k21c: return VRegB_21c();
+ case k21h: return VRegB_21h();
+ case k21s: return VRegB_21s();
+ case k21t: return VRegB_21t();
+ case k22b: return VRegB_22b();
+ case k22c: return VRegB_22c();
+ case k22s: return VRegB_22s();
+ case k22t: return VRegB_22t();
+ case k22x: return VRegB_22x();
+ case k23x: return VRegB_23x();
+ case k31c: return VRegB_31c();
+ case k31i: return VRegB_31i();
+ case k31t: return VRegB_31t();
+ case k32x: return VRegB_32x();
+ case k35c: return VRegB_35c();
+ case k3rc: return VRegB_3rc();
+ case k51l: return VRegB_51l();
+ default:
+ LOG(FATAL) << "Tried to access vB of instruction " << Name() << " which has no B operand.";
+ exit(EXIT_FAILURE);
+ }
+}
+
+inline uint64_t Instruction::WideVRegB() const {
+ return VRegB_51l();
+}
+
inline int4_t Instruction::VRegB_11n(uint16_t inst_data) const {
DCHECK_EQ(FormatOf(Opcode()), k11n);
return static_cast<int4_t>((InstB(inst_data) << 28) >> 28);
@@ -246,6 +368,34 @@
//------------------------------------------------------------------------------
// VRegC
//------------------------------------------------------------------------------
+inline bool Instruction::HasVRegC() const {
+ switch (FormatOf(Opcode())) {
+ case k22b: return true;
+ case k22c: return true;
+ case k22s: return true;
+ case k22t: return true;
+ case k23x: return true;
+ case k35c: return true;
+ case k3rc: return true;
+ default: return false;
+ }
+}
+
+inline int32_t Instruction::VRegC() const {
+ switch (FormatOf(Opcode())) {
+ case k22b: return VRegC_22b();
+ case k22c: return VRegC_22c();
+ case k22s: return VRegC_22s();
+ case k22t: return VRegC_22t();
+ case k23x: return VRegC_23x();
+ case k35c: return VRegC_35c();
+ case k3rc: return VRegC_3rc();
+ default:
+ LOG(FATAL) << "Tried to access vC of instruction " << Name() << " which has no C operand.";
+ exit(EXIT_FAILURE);
+ }
+}
+
inline int8_t Instruction::VRegC_22b() const {
DCHECK_EQ(FormatOf(Opcode()), k22b);
return static_cast<int8_t>(Fetch16(1) >> 8);
@@ -281,7 +431,11 @@
return Fetch16(2);
}
-inline void Instruction::GetArgs(uint32_t arg[5], uint16_t inst_data) const {
+inline bool Instruction::HasVarArgs() const {
+ return FormatOf(Opcode()) == k35c;
+}
+
+inline void Instruction::GetVarArgs(uint32_t arg[5], uint16_t inst_data) const {
DCHECK_EQ(FormatOf(Opcode()), k35c);
/*
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 7546245..0494f22 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -70,121 +70,6 @@
#undef INSTRUCTION_SIZE
};
-/*
- * Handy macros for helping decode instructions.
- */
-#define FETCH(_offset) (insns[(_offset)])
-#define FETCH_uint32(_offset) (fetch_uint32_impl((_offset), insns))
-#define INST_A(_insn) (((uint16_t)(_insn) >> 8) & 0x0f)
-#define INST_B(_insn) ((uint16_t)(_insn) >> 12)
-#define INST_AA(_insn) ((_insn) >> 8)
-
-/* Helper for FETCH_uint32, above. */
-static inline uint32_t fetch_uint32_impl(uint32_t offset, const uint16_t* insns) {
- return insns[offset] | ((uint32_t) insns[offset+1] << 16);
-}
-
-
-bool Instruction::HasVRegC() const {
- switch (FormatOf(Opcode())) {
- case k23x: return true;
- case k35c: return true;
- case k3rc: return true;
- default: return false;
- }
-}
-
-bool Instruction::HasVRegB() const {
- switch (FormatOf(Opcode())) {
- case k12x: return true;
- case k22b: return true;
- case k22c: return true;
- case k22s: return true;
- case k22t: return true;
- case k22x: return true;
- case k23x: return true;
- case k32x: return true;
- default: return false;
- }
-}
-
-bool Instruction::HasVRegA() const {
- switch (FormatOf(Opcode())) {
- case k11n: return true;
- case k11x: return true;
- case k12x: return true;
- case k21c: return true;
- case k21h: return true;
- case k21s: return true;
- case k21t: return true;
- case k22b: return true;
- case k22c: return true;
- case k22s: return true;
- case k22t: return true;
- case k22x: return true;
- case k23x: return true;
- case k31c: return true;
- case k31i: return true;
- case k31t: return true;
- case k32x: return true;
- case k51l: return true;
- default: return false;
- }
-}
-
-int32_t Instruction::VRegC() const {
- switch (FormatOf(Opcode())) {
- case k23x: return VRegC_23x();
- case k35c: return VRegC_35c();
- case k3rc: return VRegC_3rc();
- default: LOG(FATAL) << "Tried to access vC of instruction " << Name() <<
- " which has no C operand.";
- }
- return -1;
-}
-
-int32_t Instruction::VRegB() const {
- switch (FormatOf(Opcode())) {
- case k12x: return VRegB_12x();
- case k22b: return VRegB_22b();
- case k22c: return VRegB_22c();
- case k22s: return VRegB_22s();
- case k22t: return VRegB_22t();
- case k22x: return VRegB_22x();
- case k23x: return VRegB_23x();
- case k32x: return VRegB_32x();
- default: LOG(FATAL) << "Tried to access vB of instruction " << Name() <<
- " which has no B operand.";
- }
- return -1;
-}
-
-int32_t Instruction::VRegA() const {
- switch (FormatOf(Opcode())) {
- case k11n: return VRegA_11n();
- case k11x: return VRegA_11x();
- case k12x: return VRegA_12x();
- case k21c: return VRegA_21c();
- case k21h: return VRegA_21h();
- case k21s: return VRegA_21s();
- case k21t: return VRegA_21t();
- case k22b: return VRegA_22b();
- case k22c: return VRegA_22c();
- case k22s: return VRegA_22s();
- case k22t: return VRegA_22t();
- case k22x: return VRegA_22x();
- case k23x: return VRegA_23x();
- case k31c: return VRegA_31c();
- case k31i: return VRegA_31i();
- case k31t: return VRegA_31t();
- case k32x: return VRegA_32x();
- case k51l: return VRegA_51l();
- default: LOG(FATAL) << "Tried to access vA of instruction " << Name() <<
- " which has no A operand.";
- }
- return -1;
-}
-
int32_t Instruction::GetTargetOffset() const {
switch (FormatOf(Opcode())) {
// Cases for conditional branches follow.
@@ -207,145 +92,6 @@
return FlagsOf(opcode) & Instruction::kContinue;
}
-void Instruction::Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const {
- const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- uint16_t insn = *insns;
- Code opcode = static_cast<Code>(insn & 0xFF);
-
- switch (FormatOf(opcode)) {
- case k10x: // op
- /* nothing to do; copy the AA bits out for the verifier */
- vA = INST_AA(insn);
- break;
- case k12x: // op vA, vB
- vA = INST_A(insn);
- vB = INST_B(insn);
- break;
- case k11n: // op vA, #+B
- vA = INST_A(insn);
- vB = (int32_t) (INST_B(insn) << 28) >> 28; // sign extend 4-bit value
- break;
- case k11x: // op vAA
- vA = INST_AA(insn);
- break;
- case k10t: // op +AA
- vA = (int8_t) INST_AA(insn); // sign-extend 8-bit value
- break;
- case k20t: // op +AAAA
- vA = (int16_t) FETCH(1); // sign-extend 16-bit value
- break;
- case k21c: // op vAA, thing@BBBB
- case k22x: // op vAA, vBBBB
- vA = INST_AA(insn);
- vB = FETCH(1);
- break;
- case k21s: // op vAA, #+BBBB
- case k21t: // op vAA, +BBBB
- vA = INST_AA(insn);
- vB = (int16_t) FETCH(1); // sign-extend 16-bit value
- break;
- case k21h: // op vAA, #+BBBB0000[00000000]
- vA = INST_AA(insn);
- /*
- * The value should be treated as right-zero-extended, but we don't
- * actually do that here. Among other things, we don't know if it's
- * the top bits of a 32- or 64-bit value.
- */
- vB = FETCH(1);
- break;
- case k23x: // op vAA, vBB, vCC
- vA = INST_AA(insn);
- vB = FETCH(1) & 0xff;
- vC = FETCH(1) >> 8;
- break;
- case k22b: // op vAA, vBB, #+CC
- vA = INST_AA(insn);
- vB = FETCH(1) & 0xff;
- vC = (int8_t) (FETCH(1) >> 8); // sign-extend 8-bit value
- break;
- case k22s: // op vA, vB, #+CCCC
- case k22t: // op vA, vB, +CCCC
- vA = INST_A(insn);
- vB = INST_B(insn);
- vC = (int16_t) FETCH(1); // sign-extend 16-bit value
- break;
- case k22c: // op vA, vB, thing@CCCC
- vA = INST_A(insn);
- vB = INST_B(insn);
- vC = FETCH(1);
- break;
- case k30t: // op +AAAAAAAA
- vA = FETCH_uint32(1); // signed 32-bit value
- break;
- case k31t: // op vAA, +BBBBBBBB
- case k31c: // op vAA, string@BBBBBBBB
- vA = INST_AA(insn);
- vB = FETCH_uint32(1); // 32-bit value
- break;
- case k32x: // op vAAAA, vBBBB
- vA = FETCH(1);
- vB = FETCH(2);
- break;
- case k31i: // op vAA, #+BBBBBBBB
- vA = INST_AA(insn);
- vB = FETCH_uint32(1); // signed 32-bit value
- break;
- case k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
- {
- /*
- * Note that the fields mentioned in the spec don't appear in
- * their "usual" positions here compared to most formats. This
- * was done so that the field names for the argument count and
- * reference index match between this format and the corresponding
- * range formats (3rc and friends).
- *
- * Bottom line: The argument count is always in vA, and the
- * method constant (or equivalent) is always in vB.
- */
- uint16_t regList;
- int count;
-
- vA = INST_B(insn); // This is labeled A in the spec.
- vB = FETCH(1);
- regList = FETCH(2);
-
- count = vA;
-
- /*
- * Copy the argument registers into the arg[] array, and
- * also copy the first argument (if any) into vC. (The
- * DecodedInstruction structure doesn't have separate
- * fields for {vD, vE, vF, vG}, so there's no need to make
- * copies of those.) Note that cases 5..2 fall through.
- */
- switch (count) {
- case 5: arg[4] = INST_A(insn);
- case 4: arg[3] = (regList >> 12) & 0x0f;
- case 3: arg[2] = (regList >> 8) & 0x0f;
- case 2: arg[1] = (regList >> 4) & 0x0f;
- case 1: vC = arg[0] = regList & 0x0f; break;
- case 0: break; // Valid, but no need to do anything.
- default:
- LOG(ERROR) << "Invalid arg count in 35c (" << count << ")";
- return;
- }
- }
- break;
- case k3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
- vA = INST_AA(insn);
- vB = FETCH(1);
- vC = FETCH(2);
- break;
- case k51l: // op vAA, #+BBBBBBBBBBBBBBBB
- vA = INST_AA(insn);
- vB_wide = FETCH_uint32(1) | ((uint64_t) FETCH_uint32(3) << 32);
- break;
- default:
- LOG(ERROR) << "Can't decode unexpected format " << FormatOf(opcode) << " (op=" << opcode << ")";
- return;
- }
-}
-
size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
// Handle special NOP encoded variable length sequences.
@@ -549,7 +295,7 @@
break;
case k35c: {
uint32_t arg[5];
- GetArgs(arg);
+ GetVarArgs(arg);
switch (Opcode()) {
case FILLED_NEW_ARRAY:
{
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 4352c4a..560e5ff 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -151,8 +151,7 @@
kVerifyError = 0x80000,
};
- // Decodes this instruction, populating its arguments.
- void Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const;
+ static constexpr uint32_t kMaxVarArgRegs = 5;
// Returns the size (in 2 byte code units) of this instruction.
size_t SizeInCodeUnits() const {
@@ -313,6 +312,9 @@
bool HasVRegB() const;
int32_t VRegB() const;
+ bool HasWideVRegB() const;
+ uint64_t WideVRegB() const;
+
int4_t VRegB_11n() const {
return VRegB_11n(Fetch16(0));
}
@@ -365,9 +367,10 @@
uint16_t VRegC_3rc() const;
// Fills the given array with the 'arg' array of the instruction.
- void GetArgs(uint32_t args[5], uint16_t inst_data) const;
- void GetArgs(uint32_t args[5]) const {
- return GetArgs(args, Fetch16(0));
+ bool HasVarArgs() const;
+ void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
+ void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const {
+ return GetVarArgs(args, Fetch16(0));
}
// Returns the opcode field of the instruction. The given "inst_data" parameter must be the first
@@ -549,23 +552,6 @@
std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
-/*
- * Holds the contents of a decoded instruction.
- */
-struct DecodedInstruction {
- uint32_t vA;
- uint32_t vB;
- uint64_t vB_wide; /* for k51l */
- uint32_t vC;
- uint32_t arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */
- Instruction::Code opcode;
-
- explicit DecodedInstruction(const Instruction* inst) {
- inst->Decode(vA, vB, vB_wide, vC, arg);
- opcode = inst->Opcode();
- }
-};
-
} // namespace art
#endif // ART_RUNTIME_DEX_INSTRUCTION_H_
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 05912bf..e52a8fb 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -132,8 +132,7 @@
if (klass == nullptr) {
return nullptr;
}
- gc::Heap* heap = Runtime::Current()->GetHeap();
- return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
+ return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
DCHECK(klass != nullptr);
return klass->Alloc<kInstrumented>(self, allocator_type);
@@ -155,9 +154,11 @@
return nullptr;
}
gc::Heap* heap = Runtime::Current()->GetHeap();
- return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
+ // Pass in false since the object can not be finalizable.
+ return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator());
}
- return klass->Alloc<kInstrumented>(self, allocator_type);
+ // Pass in false since the object can not be finalizable.
+ return klass->Alloc<kInstrumented, false>(self, allocator_type);
}
// Given the context of a calling Method and an initialized class, create an instance.
@@ -169,7 +170,8 @@
gc::AllocatorType allocator_type)
NO_THREAD_SAFETY_ANALYSIS {
DCHECK(klass != nullptr);
- return klass->Alloc<kInstrumented>(self, allocator_type);
+ // Pass in false since the object can not be finalizable.
+ return klass->Alloc<kInstrumented, false>(self, allocator_type);
}
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 680ffbe..5d2603f 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -767,11 +767,18 @@
if (virtual_or_interface) {
// Refine called method based on receiver.
CHECK(receiver != nullptr) << invoke_type;
+
+ mirror::ArtMethod* orig_called = called;
if (invoke_type == kVirtual) {
called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
} else {
called = receiver->GetClass()->FindVirtualMethodForInterface(called);
}
+
+ CHECK(called != nullptr) << PrettyMethod(orig_called) << " "
+ << PrettyTypeOf(receiver) << " "
+ << invoke_type << " " << orig_called->GetVtableIndex();
+
// We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
// of the sharpened method.
if (called->GetDexCacheResolvedMethods() == caller->GetDexCacheResolvedMethods()) {
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index f113030..a693659 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -584,7 +584,7 @@
return AllocRun(self, idx);
}
-void* RosAlloc::AllocFromCurrentRunUnlocked(Thread* self, size_t idx) {
+inline void* RosAlloc::AllocFromCurrentRunUnlocked(Thread* self, size_t idx) {
Run* current_run = current_runs_[idx];
DCHECK(current_run != nullptr);
void* slot_addr = current_run->AllocSlot();
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index f9a6abe..16add0b 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -128,6 +128,18 @@
return (static_cast<uint64_t>(freed_bytes_) * 1000) / (NsToMs(GetDurationNs()) + 1);
}
+void GarbageCollector::RecordFree(uint64_t freed_objects, int64_t freed_bytes) {
+ freed_objects_ += freed_objects;
+ freed_bytes_ += freed_bytes;
+ GetHeap()->RecordFree(freed_objects, freed_bytes);
+}
+
+void GarbageCollector::RecordFreeLargeObjects(uint64_t freed_objects, int64_t freed_bytes) {
+ freed_large_objects_ += freed_objects;
+ freed_large_object_bytes_ += freed_bytes;
+ GetHeap()->RecordFree(freed_objects, freed_bytes);
+}
+
void GarbageCollector::ResetMeasurements() {
cumulative_timings_.Reset();
pause_histogram_.Reset();
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index ca4a1d5..d05f45b 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -88,19 +88,19 @@
// this is the allocation space, for full GC then we swap the zygote bitmaps too.
void SwapBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
- size_t GetFreedBytes() const {
+ int64_t GetFreedBytes() const {
return freed_bytes_;
}
- size_t GetFreedLargeObjectBytes() const {
+ int64_t GetFreedLargeObjectBytes() const {
return freed_large_object_bytes_;
}
- size_t GetFreedObjects() const {
+ uint64_t GetFreedObjects() const {
return freed_objects_;
}
- size_t GetFreedLargeObjects() const {
+ uint64_t GetFreedLargeObjects() const {
return freed_large_objects_;
}
@@ -108,7 +108,7 @@
return pause_histogram_.Sum();
}
- uint64_t GetTotalFreedBytes() const {
+ int64_t GetTotalFreedBytes() const {
return total_freed_bytes_;
}
@@ -141,6 +141,11 @@
// Revoke all the thread-local buffers.
virtual void RevokeAllThreadLocalBuffers() = 0;
+ // Record that you have freed some objects or large objects, calls Heap::RecordFree.
+ // TODO: These are not thread safe, add a lock if we get have parallel sweeping.
+ void RecordFree(uint64_t freed_objects, int64_t freed_bytes);
+ void RecordFreeLargeObjects(uint64_t freed_objects, int64_t freed_bytes);
+
static constexpr size_t kPauseBucketSize = 500;
static constexpr size_t kPauseBucketCount = 32;
@@ -158,13 +163,14 @@
Histogram<uint64_t> pause_histogram_;
uint64_t total_time_ns_;
uint64_t total_freed_objects_;
- uint64_t total_freed_bytes_;
+ int64_t total_freed_bytes_;
- // Single GC statitstics.
- AtomicInteger freed_bytes_;
- AtomicInteger freed_large_object_bytes_;
- AtomicInteger freed_objects_;
- AtomicInteger freed_large_objects_;
+ // Single GC statitstics, freed bytes are signed since the GC can free negative bytes if it
+ // promotes objects to a space which has a larger allocation size.
+ int64_t freed_bytes_;
+ int64_t freed_large_object_bytes_;
+ uint64_t freed_objects_;
+ uint64_t freed_large_objects_;
CumulativeLogger cumulative_timings_;
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index e225d5a..b8051c9 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -1116,13 +1116,10 @@
timings_.EndSplit();
timings_.StartSplit("RecordFree");
- VLOG(heap) << "Freed " << freed_objects << "/" << count
- << " objects with size " << PrettySize(freed_bytes);
- heap_->RecordFree(freed_objects + freed_large_objects, freed_bytes + freed_large_object_bytes);
- freed_objects_.FetchAndAdd(freed_objects);
- freed_large_objects_.FetchAndAdd(freed_large_objects);
- freed_bytes_.FetchAndAdd(freed_bytes);
- freed_large_object_bytes_.FetchAndAdd(freed_large_object_bytes);
+ VLOG(heap) << "Freed " << freed_objects << "/" << count << " objects with size "
+ << PrettySize(freed_bytes);
+ RecordFree(freed_objects, freed_bytes);
+ RecordFreeLargeObjects(freed_large_objects, freed_large_object_bytes);
timings_.EndSplit();
timings_.StartSplit("ResetStack");
@@ -1150,9 +1147,7 @@
size_t freed_objects = 0;
size_t freed_bytes = 0;
alloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
- heap_->RecordFree(freed_objects, freed_bytes);
- freed_objects_.FetchAndAdd(freed_objects);
- freed_bytes_.FetchAndAdd(freed_bytes);
+ RecordFree(freed_objects, freed_bytes);
}
}
SweepLargeObjects(swap_bitmaps);
@@ -1163,9 +1158,7 @@
size_t freed_objects = 0;
size_t freed_bytes = 0;
heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
- freed_large_objects_.FetchAndAdd(freed_objects);
- freed_large_object_bytes_.FetchAndAdd(freed_bytes);
- heap_->RecordFree(freed_objects, freed_bytes);
+ RecordFreeLargeObjects(freed_objects, freed_bytes);
}
// Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index b53ee10..f5d6299 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -262,27 +262,18 @@
// before they are properly counted.
RevokeAllThreadLocalBuffers();
// Record freed memory.
- uint64_t from_bytes = from_space_->GetBytesAllocated();
- uint64_t to_bytes = bytes_moved_;
- uint64_t from_objects = from_space_->GetObjectsAllocated();
- uint64_t to_objects = objects_moved_;
+ const int64_t from_bytes = from_space_->GetBytesAllocated();
+ const int64_t to_bytes = bytes_moved_;
+ const uint64_t from_objects = from_space_->GetObjectsAllocated();
+ const uint64_t to_objects = objects_moved_;
CHECK_LE(to_objects, from_objects);
- int64_t freed_bytes = from_bytes - to_bytes;
- int64_t freed_objects = from_objects - to_objects;
- freed_bytes_.FetchAndAdd(freed_bytes);
- freed_objects_.FetchAndAdd(freed_objects);
// Note: Freed bytes can be negative if we copy form a compacted space to a free-list backed
// space.
- heap_->RecordFree(freed_objects, freed_bytes);
-
+ RecordFree(from_objects - to_objects, from_bytes - to_bytes);
// Clear and protect the from space.
from_space_->Clear();
- VLOG(heap) << "Protecting space " << *from_space_;
- if (kProtectFromSpace) {
- from_space_->GetMemMap()->Protect(PROT_NONE);
- } else {
- from_space_->GetMemMap()->Protect(PROT_READ);
- }
+ VLOG(heap) << "Protecting from_space_: " << *from_space_;
+ from_space_->GetMemMap()->Protect(kProtectFromSpace ? PROT_NONE : PROT_READ);
if (swap_semi_spaces_) {
heap_->SwapSemiSpaces();
}
@@ -687,9 +678,7 @@
size_t freed_objects = 0;
size_t freed_bytes = 0;
alloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
- heap_->RecordFree(freed_objects, freed_bytes);
- freed_objects_.FetchAndAdd(freed_objects);
- freed_bytes_.FetchAndAdd(freed_bytes);
+ RecordFree(freed_objects, freed_bytes);
}
}
if (!is_large_object_space_immune_) {
@@ -703,9 +692,7 @@
size_t freed_objects = 0;
size_t freed_bytes = 0;
heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
- freed_large_objects_.FetchAndAdd(freed_objects);
- freed_large_object_bytes_.FetchAndAdd(freed_bytes);
- heap_->RecordFree(freed_objects, freed_bytes);
+ RecordFreeLargeObjects(freed_objects, freed_bytes);
}
// Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index b25f7ff..9e73f14 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -29,7 +29,9 @@
case kGcCauseBackground: return "Background";
case kGcCauseExplicit: return "Explicit";
case kGcCauseForNativeAlloc: return "NativeAlloc";
- case kGcCauseCollectorTransition: return" CollectorTransition";
+ case kGcCauseCollectorTransition: return "CollectorTransition";
+ case kGcCauseDisableMovingGc: return "DisableMovingGc";
+ case kGcCauseTrim: return "HeapTrim";
default:
LOG(FATAL) << "Unreachable";
}
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 7499b9e..10e6667 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -35,6 +35,10 @@
kGcCauseForNativeAlloc,
// GC triggered for a collector transition.
kGcCauseCollectorTransition,
+ // Not a real GC cause, used when we disable moving GC (currently for GetPrimitiveArrayCritical).
+ kGcCauseDisableMovingGc,
+ // Not a real GC cause, used when we trim the heap.
+ kGcCauseTrim,
};
const char* PrettyCause(GcCause cause);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5d517bb..4484494 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -498,7 +498,7 @@
MutexLock mu(self, *gc_complete_lock_);
++disable_moving_gc_count_;
if (IsMovingGc(collector_type_running_)) {
- WaitForGcToCompleteLocked(self);
+ WaitForGcToCompleteLocked(kGcCauseDisableMovingGc, self);
}
}
@@ -962,7 +962,7 @@
// trimming.
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
- WaitForGcToCompleteLocked(self);
+ WaitForGcToCompleteLocked(kGcCauseTrim, self);
collector_type_running_ = kCollectorTypeHeapTrim;
}
uint64_t start_ns = NanoTime();
@@ -1143,13 +1143,13 @@
GetLiveBitmap()->Walk(Heap::VerificationCallback, this);
}
-void Heap::RecordFree(ssize_t freed_objects, ssize_t freed_bytes) {
+void Heap::RecordFree(uint64_t freed_objects, int64_t freed_bytes) {
// Use signed comparison since freed bytes can be negative when background compaction foreground
// transitions occurs. This is caused by the moving objects from a bump pointer space to a
// free list backed space typically increasing memory footprint due to padding and binning.
- DCHECK_LE(freed_bytes, static_cast<ssize_t>(num_bytes_allocated_.Load()));
- DCHECK_GE(freed_objects, 0);
- num_bytes_allocated_.FetchAndSub(freed_bytes);
+ DCHECK_LE(freed_bytes, static_cast<int64_t>(num_bytes_allocated_.Load()));
+ // Note: This relies on 2s complement for handling negative freed_bytes.
+ num_bytes_allocated_.FetchAndSub(static_cast<ssize_t>(freed_bytes));
if (Runtime::Current()->HasStatsEnabled()) {
RuntimeStats* thread_stats = Thread::Current()->GetStats();
thread_stats->freed_objects += freed_objects;
@@ -1171,7 +1171,7 @@
SirtRef<mirror::Class> sirt_klass(self, *klass);
// The allocation failed. If the GC is running, block until it completes, and then retry the
// allocation.
- collector::GcType last_gc = WaitForGcToComplete(self);
+ collector::GcType last_gc = WaitForGcToComplete(kGcCauseForAlloc, self);
if (last_gc != collector::kGcTypeNone) {
// If we were the default allocator but the allocator changed while we were suspended,
// abort the allocation.
@@ -1418,7 +1418,7 @@
ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
- WaitForGcToCompleteLocked(self);
+ WaitForGcToCompleteLocked(kGcCauseCollectorTransition, self);
// If someone else beat us to it and changed the collector before we could, exit.
// This is safe to do before the suspend all since we set the collector_type_running_ before
// we exit the loop. If another thread attempts to do the heap transition before we exit,
@@ -1819,7 +1819,7 @@
ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
- WaitForGcToCompleteLocked(self);
+ WaitForGcToCompleteLocked(gc_cause, self);
compacting_gc = IsMovingGc(collector_type_);
// GC can be disabled if someone has a used GetPrimitiveArrayCritical.
if (compacting_gc && disable_moving_gc_count_ != 0) {
@@ -2448,13 +2448,13 @@
}
}
-collector::GcType Heap::WaitForGcToComplete(Thread* self) {
+collector::GcType Heap::WaitForGcToComplete(GcCause cause, Thread* self) {
ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
- return WaitForGcToCompleteLocked(self);
+ return WaitForGcToCompleteLocked(cause, self);
}
-collector::GcType Heap::WaitForGcToCompleteLocked(Thread* self) {
+collector::GcType Heap::WaitForGcToCompleteLocked(GcCause cause, Thread* self) {
collector::GcType last_gc_type = collector::kGcTypeNone;
uint64_t wait_start = NanoTime();
while (collector_type_running_ != kCollectorTypeNone) {
@@ -2467,7 +2467,8 @@
uint64_t wait_time = NanoTime() - wait_start;
total_wait_time_ += wait_time;
if (wait_time > long_pause_log_threshold_) {
- LOG(INFO) << "WaitForGcToComplete blocked for " << PrettyDuration(wait_time);
+ LOG(INFO) << "WaitForGcToComplete blocked for " << PrettyDuration(wait_time)
+ << " for cause " << cause;
}
return last_gc_type;
}
@@ -2611,12 +2612,14 @@
non_moving_space_->ClearGrowthLimit();
}
-void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
+void Heap::AddFinalizerReference(Thread* self, mirror::Object** object) {
ScopedObjectAccess soa(self);
- ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(object));
+ ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(*object));
jvalue args[1];
args[0].l = arg.get();
InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
+ // Restore object in case it gets moved.
+ *object = soa.Decode<mirror::Object*>(arg.get());
}
void Heap::EnqueueClearedReferences() {
@@ -2659,7 +2662,7 @@
return;
}
// Wait for any GCs currently running to finish.
- if (WaitForGcToComplete(self) == collector::kGcTypeNone) {
+ if (WaitForGcToComplete(kGcCauseBackground, self) == collector::kGcTypeNone) {
// If the we can't run the GC type we wanted to run, find the next appropriate one and try that
// instead. E.g. can't do partial, so do full instead.
if (CollectGarbageInternal(next_gc_type_, kGcCauseBackground, false) ==
@@ -2792,7 +2795,7 @@
// The second watermark is higher than the gc watermark. If you hit this it means you are
// allocating native objects faster than the GC can keep up with.
if (static_cast<size_t>(native_bytes_allocated_) > native_footprint_limit_) {
- if (WaitForGcToComplete(self) != collector::kGcTypeNone) {
+ if (WaitForGcToComplete(kGcCauseForNativeAlloc, self) != collector::kGcTypeNone) {
// Just finished a GC, attempt to run finalizers.
RunFinalization(env);
CHECK(!env->ExceptionCheck());
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index d3b5cdc..7a9ef1e 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -300,7 +300,8 @@
// Blocks the caller until the garbage collector becomes idle and returns the type of GC we
// waited for.
- collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+ collector::GcType WaitForGcToComplete(GcCause cause, Thread* self)
+ LOCKS_EXCLUDED(gc_complete_lock_);
// Update the heap's process state to a new value, may cause compaction to occur.
void UpdateProcessState(ProcessState process_state);
@@ -357,7 +358,7 @@
// Freed bytes can be negative in cases where we copy objects from a compacted space to a
// free-list backed space.
- void RecordFree(ssize_t freed_objects, ssize_t freed_bytes);
+ void RecordFree(uint64_t freed_objects, int64_t freed_bytes);
// Must be called if a field of an Object in the heap changes, and before any GC safe-point.
// The call is not needed if NULL is stored in the field.
@@ -380,7 +381,7 @@
return card_table_.get();
}
- void AddFinalizerReference(Thread* self, mirror::Object* object);
+ void AddFinalizerReference(Thread* self, mirror::Object** object);
// Returns the number of bytes currently allocated.
size_t GetBytesAllocated() const {
@@ -641,7 +642,7 @@
// Blocks the caller until the garbage collector becomes idle and returns the type of GC we
// waited for.
- collector::GcType WaitForGcToCompleteLocked(Thread* self)
+ collector::GcType WaitForGcToCompleteLocked(GcCause cause, Thread* self)
EXCLUSIVE_LOCKS_REQUIRED(gc_complete_lock_);
void RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time)
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 3de1ba4..858582e 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -33,15 +33,16 @@
Atomic<uint32_t> ImageSpace::bitmap_index_(0);
-ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map,
- accounting::ContinuousSpaceBitmap* live_bitmap)
- : MemMapSpace(name, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
- kGcRetentionPolicyNeverCollect) {
+ImageSpace::ImageSpace(const std::string& image_filename, const char* image_location,
+ MemMap* mem_map, accounting::ContinuousSpaceBitmap* live_bitmap)
+ : MemMapSpace(image_filename, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
+ kGcRetentionPolicyNeverCollect),
+ image_location_(image_location) {
DCHECK(live_bitmap != nullptr);
live_bitmap_.reset(live_bitmap);
}
-static bool GenerateImage(const std::string& image_file_name, std::string* error_msg) {
+static bool GenerateImage(const std::string& image_filename, std::string* error_msg) {
const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
std::vector<std::string> boot_class_path;
Split(boot_class_path_string, ':', boot_class_path);
@@ -57,7 +58,7 @@
arg_vector.push_back(dex2oat);
std::string image_option_string("--image=");
- image_option_string += image_file_name;
+ image_option_string += image_filename;
arg_vector.push_back(image_option_string);
arg_vector.push_back("--runtime-arg");
@@ -72,7 +73,7 @@
}
std::string oat_file_option_string("--oat-file=");
- oat_file_option_string += image_file_name;
+ oat_file_option_string += image_filename;
oat_file_option_string.erase(oat_file_option_string.size() - 3);
oat_file_option_string += "oat";
arg_vector.push_back(oat_file_option_string);
@@ -98,37 +99,72 @@
return Exec(arg_vector, error_msg);
}
-ImageSpace* ImageSpace::Create(const char* original_image_file_name,
- const InstructionSet image_isa) {
- if (OS::FileExists(original_image_file_name)) {
- // If the /system file exists, it should be up-to-date, don't try to generate
- std::string error_msg;
- ImageSpace* space = ImageSpace::Init(original_image_file_name, false, &error_msg);
- if (space == nullptr) {
- LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg;
- }
- return space;
+bool ImageSpace::FindImageFilename(const char* image_location,
+ const InstructionSet image_isa,
+ std::string* image_filename,
+ bool *is_system) {
+ if (OS::FileExists(image_location)) {
+ *image_filename = image_location;
+ *is_system = true;
+ return true;
}
- // If the /system file didn't exist, we need to use one from the dalvik-cache.
- // If the cache file exists, try to open, but if it fails, regenerate.
- // If it does not exist, generate.
+
const std::string dalvik_cache = GetDalvikCacheOrDie(GetInstructionSetString(image_isa));
- std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name,
- dalvik_cache.c_str()));
+
+ // Always set output location even if it does not exist,
+ // so that the caller knows where to create the image.
+ *image_filename = GetDalvikCacheFilenameOrDie(image_location, dalvik_cache.c_str());
+ *is_system = false;
+ return OS::FileExists(image_filename->c_str());
+}
+
+ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
+ const InstructionSet image_isa) {
+ std::string image_filename;
+ bool is_system = false;
+ if (FindImageFilename(image_location, image_isa, &image_filename, &is_system)) {
+ UniquePtr<File> image_file(OS::OpenFileForReading(image_filename.c_str()));
+ UniquePtr<ImageHeader> image_header(new ImageHeader);
+ const bool success = image_file->ReadFully(image_header.get(), sizeof(ImageHeader));
+ if (!success || !image_header->IsValid()) {
+ LOG(FATAL) << "Invalid Image header for: " << image_filename;
+ return nullptr;
+ }
+
+ return image_header.release();
+ }
+
+ LOG(FATAL) << "Unable to find image file for: " << image_location;
+ return nullptr;
+}
+
+ImageSpace* ImageSpace::Create(const char* image_location,
+ const InstructionSet image_isa) {
+ std::string image_filename;
std::string error_msg;
- if (OS::FileExists(image_file_name.c_str())) {
- space::ImageSpace* image_space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
- if (image_space != nullptr) {
- return image_space;
+ bool is_system = false;
+ if (FindImageFilename(image_location, image_isa, &image_filename, &is_system)) {
+ ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location,
+ !is_system, &error_msg);
+ if (space != nullptr) {
+ return space;
+ }
+
+ // If the /system file exists, it should be up-to-date, don't try to generate it.
+ // If it's not the /system file, log a warning and fall through to GenerateImage.
+ if (is_system) {
+ LOG(FATAL) << "Failed to load image '" << image_filename << "': " << error_msg;
+ return nullptr;
} else {
LOG(WARNING) << error_msg;
}
}
- CHECK(GenerateImage(image_file_name, &error_msg))
- << "Failed to generate image '" << image_file_name << "': " << error_msg;
- ImageSpace* space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
+
+ CHECK(GenerateImage(image_filename, &error_msg))
+ << "Failed to generate image '" << image_filename << "': " << error_msg;
+ ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location, true, &error_msg);
if (space == nullptr) {
- LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg;
+ LOG(FATAL) << "Failed to load image '" << image_filename << "': " << error_msg;
}
return space;
}
@@ -147,25 +183,26 @@
}
}
-ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file,
- std::string* error_msg) {
- CHECK(image_file_name != nullptr);
+ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_location,
+ bool validate_oat_file, std::string* error_msg) {
+ CHECK(image_filename != nullptr);
+ CHECK(image_location != nullptr);
uint64_t start_time = 0;
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
start_time = NanoTime();
- LOG(INFO) << "ImageSpace::Init entering image_file_name=" << image_file_name;
+ LOG(INFO) << "ImageSpace::Init entering image_filename=" << image_filename;
}
- UniquePtr<File> file(OS::OpenFileForReading(image_file_name));
+ UniquePtr<File> file(OS::OpenFileForReading(image_filename));
if (file.get() == NULL) {
- *error_msg = StringPrintf("Failed to open '%s'", image_file_name);
+ *error_msg = StringPrintf("Failed to open '%s'", image_filename);
return nullptr;
}
ImageHeader image_header;
bool success = file->ReadFully(&image_header, sizeof(image_header));
if (!success || !image_header.IsValid()) {
- *error_msg = StringPrintf("Invalid image header in '%s'", image_file_name);
+ *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
return nullptr;
}
@@ -177,7 +214,7 @@
file->Fd(),
0,
false,
- image_file_name,
+ image_filename,
error_msg));
if (map.get() == NULL) {
DCHECK(!error_msg->empty());
@@ -190,14 +227,14 @@
PROT_READ, MAP_PRIVATE,
file->Fd(), image_header.GetBitmapOffset(),
false,
- image_file_name,
+ image_filename,
error_msg));
if (image_map.get() == nullptr) {
*error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
return nullptr;
}
uint32_t bitmap_index = bitmap_index_.FetchAndAdd(1);
- std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name,
+ std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename,
bitmap_index));
UniquePtr<accounting::ContinuousSpaceBitmap> bitmap(
accounting::ContinuousSpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
@@ -223,12 +260,13 @@
callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
- UniquePtr<ImageSpace> space(new ImageSpace(image_file_name, map.release(), bitmap.release()));
+ UniquePtr<ImageSpace> space(new ImageSpace(image_filename, image_location,
+ map.release(), bitmap.release()));
if (kIsDebugBuild) {
space->VerifyImageAllocations();
}
- space->oat_file_.reset(space->OpenOatFile(image_file_name, error_msg));
+ space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
if (space->oat_file_.get() == nullptr) {
DCHECK(!error_msg->empty());
return nullptr;
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 1652ec9..622371f 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -46,6 +46,11 @@
static ImageSpace* Create(const char* image, const InstructionSet image_isa)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Reads the image header from the specified image location for the
+ // instruction set image_isa.
+ static ImageHeader* ReadImageHeaderOrDie(const char* image_location,
+ const InstructionSet image_isa);
+
// Releases the OatFile from the ImageSpace so it can be transfer to
// the caller, presumably the ClassLinker.
OatFile* ReleaseOatFile()
@@ -58,10 +63,18 @@
return *reinterpret_cast<ImageHeader*>(Begin());
}
+ // Actual filename where image was loaded from.
+ // For example: /data/dalvik-cache/arm/system@framework@boot.art
const std::string GetImageFilename() const {
return GetName();
}
+ // Symbolic location for image.
+ // For example: /system/framework/boot.art
+ const std::string GetImageLocation() const {
+ return image_location_;
+ }
+
accounting::ContinuousSpaceBitmap* GetLiveBitmap() const OVERRIDE {
return live_bitmap_.get();
}
@@ -90,9 +103,21 @@
// image's OatFile is up-to-date relative to its DexFile
// inputs. Otherwise (for /data), validate the inputs and generate
// the OatFile in /data/dalvik-cache if necessary.
- static ImageSpace* Init(const char* image, bool validate_oat_file, std::string* error_msg)
+ static ImageSpace* Init(const char* image_filename, const char* image_location,
+ bool validate_oat_file, std::string* error_msg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Returns the filename of the image corresponding to
+ // requested image_location, or the filename where a new image
+ // should be written if one doesn't exist. Looks for a generated
+ // image in the specified location and then in the dalvik-cache.
+ //
+ // Returns true if an image was found, false otherwise.
+ static bool FindImageFilename(const char* image_location,
+ const InstructionSet image_isa,
+ std::string* location,
+ bool* is_system);
+
OatFile* OpenOatFile(const char* image, std::string* error_msg) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -105,14 +130,16 @@
UniquePtr<accounting::ContinuousSpaceBitmap> live_bitmap_;
- ImageSpace(const std::string& name, MemMap* mem_map,
- accounting::ContinuousSpaceBitmap* live_bitmap);
+ ImageSpace(const std::string& name, const char* image_location,
+ MemMap* mem_map, accounting::ContinuousSpaceBitmap* live_bitmap);
// The OatFile associated with the image during early startup to
// reserve space contiguous to the image. It is later released to
// the ClassLinker during it's initialization.
UniquePtr<OatFile> oat_file_;
+ const std::string image_location_;
+
DISALLOW_COPY_AND_ASSIGN(ImageSpace);
};
diff --git a/runtime/globals.h b/runtime/globals.h
index e3c54b8..eb52a46 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -20,6 +20,7 @@
#include <stddef.h>
#include <stdint.h>
#include "read_barrier_c.h"
+#include "read_barrier_option.h"
namespace art {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 1e1a8c1..7232e54 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -27,10 +27,6 @@
static void UnstartedRuntimeJni(Thread* self, ArtMethod* method,
Object* receiver, uint32_t* args, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(Runtime::Current()->IsActiveTransaction()) << "Calling native method "
- << PrettyMethod(method)
- << " in unstarted runtime should only happen"
- << " in a transaction";
std::string name(PrettyMethod(method));
if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") {
result->SetL(NULL);
@@ -71,7 +67,11 @@
result->SetL(Array::CreateMultiArray(self, sirt_class, sirt_dimensions));
} else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") {
ScopedObjectAccessUnchecked soa(self);
- result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<true>(soa)));
+ if (Runtime::Current()->IsActiveTransaction()) {
+ result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<true>(soa)));
+ } else {
+ result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<false>(soa)));
+ }
} else if (name == "int java.lang.System.identityHashCode(java.lang.Object)") {
mirror::Object* obj = reinterpret_cast<Object*>(args[0]);
result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0);
@@ -82,13 +82,22 @@
jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
jint expectedValue = args[3];
jint newValue = args[4];
- bool success = obj->CasField32<true>(MemberOffset(offset), expectedValue, newValue);
+ bool success;
+ if (Runtime::Current()->IsActiveTransaction()) {
+ success = obj->CasField32<true>(MemberOffset(offset), expectedValue, newValue);
+ } else {
+ success = obj->CasField32<false>(MemberOffset(offset), expectedValue, newValue);
+ }
result->SetZ(success ? JNI_TRUE : JNI_FALSE);
} else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
Object* obj = reinterpret_cast<Object*>(args[0]);
jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
Object* newValue = reinterpret_cast<Object*>(args[3]);
- obj->SetFieldObject<true>(MemberOffset(offset), newValue);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ obj->SetFieldObject<true>(MemberOffset(offset), newValue);
+ } else {
+ obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+ }
} else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") {
mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
Primitive::Type primitive_type = component->GetPrimitiveType();
@@ -97,9 +106,13 @@
mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
Primitive::Type primitive_type = component->GetPrimitiveType();
result->SetI(Primitive::ComponentSize(primitive_type));
- } else {
+ } else if (Runtime::Current()->IsActiveTransaction()) {
AbortTransaction(self, "Attempt to invoke native method in non-started runtime: %s",
name.c_str());
+
+ } else {
+ LOG(FATAL) << "Calling native method " << PrettyMethod(method) << " in an unstarted "
+ "non-transactional runtime";
}
}
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5660508..ee6a869 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -85,7 +85,7 @@
if (is_range) {
vregC = inst->VRegC_3rc();
} else {
- inst->GetArgs(arg, inst_data);
+ inst->GetVarArgs(arg, inst_data);
}
// Handle receiver apart since it's not part of the shorty.
@@ -224,7 +224,7 @@
if (is_range) {
vregC = inst->VRegC_3rc();
} else {
- inst->GetArgs(arg);
+ inst->GetVarArgs(arg);
}
const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
for (int32_t i = 0; i < length; ++i) {
@@ -302,6 +302,8 @@
CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
<< PrettyDescriptor(descriptor);
result->SetL(found);
+ } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
+ result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
} else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
SirtRef<ClassLoader> class_loader(self, down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset)));
std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
@@ -355,6 +357,12 @@
args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue();
EnterInterpreterFromInvoke(self, c, field.get(), args, NULL);
result->SetL(field.get());
+ } else if (name == "int java.lang.Object.hashCode()") {
+ Object* obj = shadow_frame->GetVRegReference(arg_offset);
+ result->SetI(obj->IdentityHashCode());
+ } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") {
+ ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod();
+ result->SetL(MethodHelper(method).GetNameAsString());
} else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") {
// Special case array copying without initializing System.
@@ -381,7 +389,18 @@
dst->Set(dstPos + i, src->Get(srcPos + i));
}
} else {
- UNIMPLEMENTED(FATAL) << "System.arraycopy of unexpected type: " << PrettyDescriptor(ctype);
+ self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
+ "Unimplemented System.arraycopy for type '%s'",
+ PrettyDescriptor(ctype).c_str());
+ }
+ } else if (name == "java.lang.Object java.lang.ThreadLocal.get()") {
+ std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod()));
+ if (caller == "java.lang.String java.lang.IntegralToString.convertInt(java.lang.AbstractStringBuilder, int)") {
+ // Allocate non-threadlocal buffer.
+ result->SetL(mirror::CharArray::Alloc(self, 11));
+ } else {
+ self->ThrowNewException(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
+ "Unimplemented ThreadLocal.get");
}
} else {
// Not special, continue with regular interpreter execution.
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 071b658..14fc25c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -322,11 +322,7 @@
ASSERT_TRUE(mid2 != NULL);
// Make sure we can actually use it.
jstring s = env_->NewStringUTF("poop");
- // TODO: this should return 4, but the runtime skips the method
- // invoke because the runtime isn't started. In the future it would
- // be nice to use interpretter for things like this. This still does
- // validate that we have a sane jmethodID value.
- ASSERT_EQ(0, env_->CallIntMethod(s, mid2));
+ ASSERT_EQ(4, env_->CallIntMethod(s, mid2));
}
void BogusMethod() {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index bc8d348..65799cd 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -27,11 +27,11 @@
namespace art {
namespace mirror {
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline size_t Array::SizeOf() {
// This is safe from overflow because the array was already allocated, so we know it's sane.
size_t component_size =
- GetClass<kVerifyFlags, kDoReadBarrier>()->template GetComponentSize<kDoReadBarrier>();
+ GetClass<kVerifyFlags, kReadBarrierOption>()->template GetComponentSize<kReadBarrierOption>();
// Don't need to check this since we already check this in GetClass.
int32_t component_count =
GetLength<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>();
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 92f0e67..eead4eb 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -42,7 +42,8 @@
const SirtRef<IntArray>& dimensions)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 7453d4d..4275f25 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -287,9 +287,11 @@
Runtime* runtime = Runtime::Current();
// Call the invoke stub, passing everything as arguments.
if (UNLIKELY(!runtime->IsStarted())) {
- LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started";
- if (result != NULL) {
- result->SetJ(0);
+ if (IsStatic()) {
+ art::interpreter::EnterInterpreterFromInvoke(self, this, nullptr, args, result);
+ } else {
+ Object* receiver = reinterpret_cast<StackReference<Object>*>(&args[0])->AsMirrorPtr();
+ art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
}
} else {
const bool kLogInvocationStartAndReturn = false;
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f61a01d..71f0210 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -411,7 +411,7 @@
static void SetClass(Class* java_lang_reflect_ArtMethod);
- template <bool kDoReadBarrier = true>
+ template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
static Class* GetJavaLangReflectArtMethod() {
// This does not need a RB because it is a root.
return java_lang_reflect_ArtMethod_;
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 8a1f383..a556a1c 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -470,12 +470,21 @@
DCHECK_GE(this->object_size_, sizeof(Object));
}
-template <bool kIsInstrumented>
+template<bool kIsInstrumented, bool kCheckAddFinalizer>
inline Object* Class::Alloc(Thread* self, gc::AllocatorType allocator_type) {
CheckObjectAlloc();
gc::Heap* heap = Runtime::Current()->GetHeap();
- return heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this, this->object_size_,
- allocator_type, VoidFunctor());
+ const bool add_finalizer = kCheckAddFinalizer && IsFinalizable();
+ if (!kCheckAddFinalizer) {
+ DCHECK(!IsFinalizable());
+ }
+ mirror::Object* obj =
+ heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this, this->object_size_,
+ allocator_type, VoidFunctor());
+ if (add_finalizer && LIKELY(obj != nullptr)) {
+ heap->AddFinalizerReference(self, &obj);
+ }
+ return obj;
}
inline Object* Class::AllocObject(Thread* self) {
@@ -492,17 +501,17 @@
VisitStaticFieldsReferences<kVisitClass>(this, visitor);
}
-template<bool kDoReadBarrier>
+template<ReadBarrierOption kReadBarrierOption>
bool Class::IsArtFieldClass() {
- Class* java_lang_Class = GetClass<kVerifyNone, kDoReadBarrier>();
+ Class* java_lang_Class = GetClass<kVerifyNone, kReadBarrierOption>();
Class* java_lang_reflect_ArtField =
- java_lang_Class->GetInstanceField(0)->GetClass<kVerifyNone, kDoReadBarrier>();
+ java_lang_Class->GetInstanceField(0)->GetClass<kVerifyNone, kReadBarrierOption>();
return this == java_lang_reflect_ArtField;
}
-template<bool kDoReadBarrier>
+template<ReadBarrierOption kReadBarrierOption>
bool Class::IsArtMethodClass() {
- return this == ArtMethod::GetJavaLangReflectArtMethod<kDoReadBarrier>();
+ return this == ArtMethod::GetJavaLangReflectArtMethod<kReadBarrierOption>();
}
} // namespace mirror
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 23211c2..00ecead 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -360,9 +360,10 @@
return depth;
}
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return GetComponentType<kVerifyFlags, kDoReadBarrier>() != NULL;
+ return GetComponentType<kVerifyFlags, kReadBarrierOption>() != NULL;
}
bool IsClassClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -371,19 +372,20 @@
bool IsThrowableClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<bool kDoReadBarrier = true>
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsArtFieldClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<bool kDoReadBarrier = true>
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsArtMethodClass();
static MemberOffset ComponentTypeOffset() {
return OFFSET_OF_OBJECT_MEMBER(Class, component_type_);
}
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
Class* GetComponentType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(ComponentTypeOffset());
+ return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(ComponentTypeOffset());
}
void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -393,10 +395,10 @@
SetFieldObject<false, false>(ComponentTypeOffset(), new_component_type);
}
- template<bool kDoReadBarrier = true>
+ template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
size_t GetComponentSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return Primitive::ComponentSize(
- GetComponentType<kDefaultVerifyFlags, kDoReadBarrier>()->GetPrimitiveType());
+ GetComponentType<kDefaultVerifyFlags, kReadBarrierOption>()->GetPrimitiveType());
}
bool IsObjectClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -412,7 +414,7 @@
}
// Creates a raw object instance but does not invoke the default constructor.
- template <bool kIsInstrumented>
+ template<bool kIsInstrumented, bool kCheckAddFinalizer = true>
ALWAYS_INLINE Object* Alloc(Thread* self, gc::AllocatorType allocator_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -427,7 +429,8 @@
return IsClassClass() || IsArrayClass();
}
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
uint32_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, class_size_));
}
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index c70a08d..064fe30 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -34,9 +34,9 @@
namespace art {
namespace mirror {
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline Class* Object::GetClass() {
- return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(
+ return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(
OFFSET_OF_OBJECT_MEMBER(Object, klass_));
}
@@ -105,7 +105,8 @@
inline Object* Object::GetReadBarrierPointer() {
#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
DCHECK(kUseBakerOrBrooksReadBarrier);
- return GetFieldObject<Object, kVerifyNone, false>(OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), false);
+ return GetFieldObject<Object, kVerifyNone, kWithoutReadBarrier>(
+ OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_));
#else
LOG(FATAL) << "Unreachable";
return nullptr;
@@ -118,7 +119,7 @@
// We don't mark the card as this occurs as part of object allocation. Not all objects have
// backing cards, such as large objects.
SetFieldObjectWithoutWriteBarrier<false, false, kVerifyNone>(
- OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr, false);
+ OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr);
#else
LOG(FATAL) << "Unreachable";
#endif
@@ -181,17 +182,17 @@
return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline bool Object::IsClass() {
- Class* java_lang_Class =
- GetClass<kVerifyFlags, kDoReadBarrier>()->template GetClass<kVerifyFlags, kDoReadBarrier>();
- return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis), kDoReadBarrier>() ==
- java_lang_Class;
+ Class* java_lang_Class = GetClass<kVerifyFlags, kReadBarrierOption>()->
+ template GetClass<kVerifyFlags, kReadBarrierOption>();
+ return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis),
+ kReadBarrierOption>() == java_lang_Class;
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline Class* Object::AsClass() {
- DCHECK((IsClass<kVerifyFlags, kDoReadBarrier>()));
+ DCHECK((IsClass<kVerifyFlags, kReadBarrierOption>()));
return down_cast<Class*>(this);
}
@@ -208,15 +209,16 @@
return down_cast<ObjectArray<T>*>(this);
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline bool Object::IsArrayInstance() {
- return GetClass<kVerifyFlags, kDoReadBarrier>()->
- template IsArrayClass<kVerifyFlags, kDoReadBarrier>();
+ return GetClass<kVerifyFlags, kReadBarrierOption>()->
+ template IsArrayClass<kVerifyFlags, kReadBarrierOption>();
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline bool Object::IsArtField() {
- return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtFieldClass<kDoReadBarrier>();
+ return GetClass<kVerifyFlags, kReadBarrierOption>()->
+ template IsArtFieldClass<kReadBarrierOption>();
}
template<VerifyObjectFlags kVerifyFlags>
@@ -225,9 +227,10 @@
return down_cast<ArtField*>(this);
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline bool Object::IsArtMethod() {
- return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtMethodClass<kDoReadBarrier>();
+ return GetClass<kVerifyFlags, kReadBarrierOption>()->
+ template IsArtMethodClass<kReadBarrierOption>();
}
template<VerifyObjectFlags kVerifyFlags>
@@ -247,9 +250,9 @@
return down_cast<Reference*>(this);
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline Array* Object::AsArray() {
- DCHECK((IsArrayInstance<kVerifyFlags, kDoReadBarrier>()));
+ DCHECK((IsArrayInstance<kVerifyFlags, kReadBarrierOption>()));
return down_cast<Array*>(this);
}
@@ -375,21 +378,23 @@
return GetClass<kVerifyFlags>()->IsPhantomReferenceClass();
}
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline size_t Object::SizeOf() {
size_t result;
constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
- if (IsArrayInstance<kVerifyFlags, kDoReadBarrier>()) {
- result = AsArray<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
- } else if (IsClass<kNewFlags, kDoReadBarrier>()) {
- result = AsClass<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
+ if (IsArrayInstance<kVerifyFlags, kReadBarrierOption>()) {
+ result = AsArray<kNewFlags, kReadBarrierOption>()->
+ template SizeOf<kNewFlags, kReadBarrierOption>();
+ } else if (IsClass<kNewFlags, kReadBarrierOption>()) {
+ result = AsClass<kNewFlags, kReadBarrierOption>()->
+ template SizeOf<kNewFlags, kReadBarrierOption>();
} else {
- result = GetClass<kNewFlags, kDoReadBarrier>()->GetObjectSize();
+ result = GetClass<kNewFlags, kReadBarrierOption>()->GetObjectSize();
}
DCHECK_GE(result, sizeof(Object))
- << " class=" << PrettyTypeOf(GetClass<kNewFlags, kDoReadBarrier>());
- DCHECK(!(IsArtField<kNewFlags, kDoReadBarrier>()) || result == sizeof(ArtField));
- DCHECK(!(IsArtMethod<kNewFlags, kDoReadBarrier>()) || result == sizeof(ArtMethod));
+ << " class=" << PrettyTypeOf(GetClass<kNewFlags, kReadBarrierOption>());
+ DCHECK(!(IsArtField<kNewFlags, kReadBarrierOption>()) || result == sizeof(ArtField));
+ DCHECK(!(IsArtMethod<kNewFlags, kReadBarrierOption>()) || result == sizeof(ArtMethod));
return result;
}
@@ -532,14 +537,15 @@
return QuasiAtomic::Cas64(old_value, new_value, addr);
}
-template<class T, VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier, bool kIsVolatile>
+template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption,
+ bool kIsVolatile>
inline T* Object::GetFieldObject(MemberOffset field_offset) {
if (kVerifyFlags & kVerifyThis) {
VerifyObject(this);
}
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
HeapReference<T>* objref_addr = reinterpret_cast<HeapReference<T>*>(raw_addr);
- T* result = ReadBarrier::Barrier<T, kDoReadBarrier>(this, field_offset, objref_addr);
+ T* result = ReadBarrier::Barrier<T, kReadBarrierOption>(this, field_offset, objref_addr);
if (kIsVolatile) {
QuasiAtomic::MembarLoadLoad(); // Ensure loads don't re-order.
}
@@ -549,9 +555,9 @@
return result;
}
-template<class T, VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline T* Object::GetFieldObjectVolatile(MemberOffset field_offset) {
- return GetFieldObject<T, kVerifyFlags, kDoReadBarrier, true>(field_offset);
+ return GetFieldObject<T, kVerifyFlags, kReadBarrierOption, true>(field_offset);
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags,
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 2cd71a0..2f775bc 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -92,9 +92,7 @@
heap->WriteBarrierEveryFieldOf(dest);
}
if (c->IsFinalizable()) {
- SirtRef<Object> sirt_dest(self, dest);
- heap->AddFinalizerReference(self, dest);
- return sirt_dest.get();
+ heap->AddFinalizerReference(self, &dest);
}
return dest;
}
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index cf28b18..442909d 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -67,7 +67,8 @@
return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
}
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
Class* GetClass() ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -86,7 +87,8 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool InstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Object* Clone(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -113,9 +115,11 @@
void Wait(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void Wait(Thread* self, int64_t timeout, int32_t nanos) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
Class* AsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -123,9 +127,11 @@
template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ObjectArray<T>* AsObjectArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsArrayInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
Array* AsArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -158,12 +164,14 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ArtMethod* AsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ArtField* AsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -185,12 +193,12 @@
// Accessor for Java type fields.
template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- bool kDoReadBarrier = true, bool kIsVolatile = false>
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier, bool kIsVolatile = false>
T* GetFieldObject(MemberOffset field_offset) ALWAYS_INLINE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- bool kDoReadBarrier = true>
+ ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
T* GetFieldObjectVolatile(MemberOffset field_offset) ALWAYS_INLINE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 1acbbb0..c324d96 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -57,6 +57,10 @@
static void ResetClass();
static void VisitRoots(RootCallback* callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static Class* GetStackTraceElement() {
+ DCHECK(java_lang_StackTraceElement_ != NULL);
+ return java_lang_StackTraceElement_;
+ }
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
@@ -70,11 +74,6 @@
SirtRef<String>& file_name, int32_t line_number)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static Class* GetStackTraceElement() {
- DCHECK(java_lang_StackTraceElement_ != NULL);
- return java_lang_StackTraceElement_;
- }
-
static Class* java_lang_StackTraceElement_;
friend struct art::StackTraceElementOffsets; // for verifying offset information
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index d393a13..6874fe5 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -24,6 +24,7 @@
#include "object_array.h"
#include "object_array-inl.h"
#include "object_utils.h"
+#include "stack_trace_element.h"
#include "utils.h"
#include "well_known_classes.h"
@@ -53,6 +54,15 @@
}
}
+void Throwable::SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(state != nullptr);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state);
+ } else {
+ SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state);
+ }
+}
+
bool Throwable::IsCheckedException() {
if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) {
return false;
@@ -70,24 +80,49 @@
result += "\n";
Object* stack_state = GetStackState();
// check stack state isn't missing or corrupt
- if (stack_state != NULL && stack_state->IsObjectArray()) {
+ if (stack_state != nullptr && stack_state->IsObjectArray()) {
// Decode the internal stack trace into the depth and method trace
ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state);
int32_t depth = method_trace->GetLength() - 1;
IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
MethodHelper mh;
- for (int32_t i = 0; i < depth; ++i) {
- ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
- mh.ChangeMethod(method);
- uint32_t dex_pc = pc_trace->Get(i);
- int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
- const char* source_file = mh.GetDeclaringClassSourceFile();
- result += StringPrintf(" at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
- source_file, line_number);
+ if (depth == 0) {
+ result += "(Throwable with empty stack trace)";
+ } else {
+ for (int32_t i = 0; i < depth; ++i) {
+ ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
+ mh.ChangeMethod(method);
+ uint32_t dex_pc = pc_trace->Get(i);
+ int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
+ const char* source_file = mh.GetDeclaringClassSourceFile();
+ result += StringPrintf(" at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
+ source_file, line_number);
+ }
+ }
+ } else {
+ Object* stack_trace = GetStackTrace();
+ if (stack_trace != nullptr && stack_trace->IsObjectArray()) {
+ CHECK_EQ(stack_trace->GetClass()->GetComponentType(),
+ StackTraceElement::GetStackTraceElement());
+ ObjectArray<StackTraceElement>* ste_array =
+ down_cast<ObjectArray<StackTraceElement>*>(stack_trace);
+ if (ste_array->GetLength() == 0) {
+ result += "(Throwable with empty stack trace)";
+ } else {
+ for (int32_t i = 0; i < ste_array->GetLength(); ++i) {
+ StackTraceElement* ste = ste_array->Get(i);
+ result += StringPrintf(" at %s (%s:%d)\n",
+ ste->GetMethodName()->ToModifiedUtf8().c_str(),
+ ste->GetFileName()->ToModifiedUtf8().c_str(),
+ ste->GetLineNumber());
+ }
+ }
+ } else {
+ result += "(Throwable with no stack trace)";
}
}
Throwable* cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_));
- if (cause != NULL && cause != this) { // Constructor makes cause == this by default.
+ if (cause != nullptr && cause != this) { // Constructor makes cause == this by default.
result += "Caused by: ";
result += cause->Dump();
}
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 950b5e7..c4127e0 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -42,6 +42,7 @@
// overridden. Also it asserts rather than throwing exceptions. Currently this is only used
// in cases like the verifier where the checks cannot fail and initCause isn't overridden.
void SetCause(Throwable* cause) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsCheckedException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static Class* GetJavaLangThrowable() {
@@ -58,6 +59,9 @@
Object* GetStackState() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_));
}
+ Object* GetStackTrace() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_trace_));
+ }
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
HeapReference<Throwable> cause_;
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index d9c1309..ed1ee7a 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -377,6 +377,8 @@
}
}
+ const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set);
+
// Check if we have an odex file next to the dex file.
std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename));
std::string error_msg;
@@ -403,6 +405,7 @@
return JNI_FALSE;
}
if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
+ target_instruction_set,
&error_msg)) {
if (kVerboseLogging) {
LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename
@@ -433,33 +436,6 @@
return JNI_TRUE;
}
- for (const auto& space : runtime->GetHeap()->GetContinuousSpaces()) {
- if (space->IsImageSpace()) {
- // TODO: Ensure this works with multiple image spaces.
- const ImageHeader& image_header = space->AsImageSpace()->GetImageHeader();
- if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() !=
- image_header.GetOatChecksum()) {
- if (kReasonLogging) {
- ScopedObjectAccess soa(env);
- LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
- << " has out-of-date oat checksum compared to "
- << oat_file->GetLocation();
- }
- return JNI_TRUE;
- }
- if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
- != reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin())) {
- if (kReasonLogging) {
- ScopedObjectAccess soa(env);
- LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
- << " has out-of-date oat begin compared to "
- << oat_file->GetLocation();
- }
- return JNI_TRUE;
- }
- }
- }
-
uint32_t location_checksum;
if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
if (kReasonLogging) {
@@ -470,7 +446,7 @@
}
if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
- &error_msg)) {
+ target_instruction_set, &error_msg)) {
if (kReasonLogging) {
LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
<< " has out-of-date checksum compared to " << filename
diff --git a/runtime/oat.cc b/runtime/oat.cc
index c1a48e9..4b4b3d0 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '2', '2', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '2', '3', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index 8bd8dba..d8fc277 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -174,26 +174,24 @@
return false;
}
- uint32_t return_reg = return_instruction->VRegA_11x();
+ int32_t return_reg = return_instruction->VRegA_11x();
DCHECK_LT(return_reg, code_item->registers_size_);
- uint32_t vA, vB, dummy;
- uint64_t dummy_wide;
- instruction->Decode(vA, vB, dummy_wide, dummy, nullptr);
+ int32_t const_value = instruction->VRegB();
if (instruction->Opcode() == Instruction::CONST_HIGH16) {
- vB <<= 16;
+ const_value <<= 16;
}
- DCHECK_LT(vA, code_item->registers_size_);
- if (vA != return_reg) {
+ DCHECK_LT(instruction->VRegA(), code_item->registers_size_);
+ if (instruction->VRegA() != return_reg) {
return false; // Not returning the value set by const?
}
- if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
+ if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) {
return false; // Returning non-null reference constant?
}
if (result != nullptr) {
result->opcode = kInlineOpNonWideConst;
result->flags = kInlineSpecial;
- result->d.data = static_cast<uint64_t>(vB);
+ result->d.data = static_cast<uint64_t>(const_value);
}
return true;
}
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index ea2f830..88e2f8f 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -23,17 +23,18 @@
namespace art {
-template <typename MirrorType, bool kDoReadBarrier>
+template <typename MirrorType, ReadBarrierOption kReadBarrierOption>
inline MirrorType* ReadBarrier::Barrier(
mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr) {
// Unused for now.
UNUSED(obj);
UNUSED(offset);
UNUSED(ref_addr);
- if (kDoReadBarrier && kUseBakerReadBarrier) {
+ const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
+ if (with_read_barrier && kUseBakerReadBarrier) {
// To be implemented.
return ref_addr->AsMirrorPtr();
- } else if (kDoReadBarrier && kUseBrooksReadBarrier) {
+ } else if (with_read_barrier && kUseBrooksReadBarrier) {
// To be implemented.
return ref_addr->AsMirrorPtr();
} else {
diff --git a/runtime/read_barrier.h b/runtime/read_barrier.h
index 6f59004..73c3d43 100644
--- a/runtime/read_barrier.h
+++ b/runtime/read_barrier.h
@@ -33,7 +33,7 @@
class ReadBarrier {
public:
- template <typename MirrorType, bool kDoReadBarrier = true>
+ template <typename MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
ALWAYS_INLINE static MirrorType* Barrier(
mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/read_barrier_option.h b/runtime/read_barrier_option.h
new file mode 100644
index 0000000..7de8b8a
--- /dev/null
+++ b/runtime/read_barrier_option.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_READ_BARRIER_OPTION_H_
+#define ART_RUNTIME_READ_BARRIER_OPTION_H_
+namespace art {
+
+// Options for performing a read barrier or not.
+enum ReadBarrierOption {
+ kWithReadBarrier, // Perform a read barrier.
+ kWithoutReadBarrier, // Don't perform a read barrier.
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_READ_BARRIER_OPTION_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fbc0460..027feee 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -160,7 +160,7 @@
Trace::Shutdown();
// Make sure to let the GC complete if it is running.
- heap_->WaitForGcToComplete(self);
+ heap_->WaitForGcToComplete(gc::kGcCauseBackground, self);
heap_->DeleteThreadPool();
// Make sure our internal threads are dead before we start tearing down things they're using.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e67a64f..23a6779 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1639,6 +1639,13 @@
if (cause.get() != nullptr) {
exception->SetCause(down_cast<mirror::Throwable*>(DecodeJObject(cause.get())));
}
+ ScopedLocalRef<jobject> trace(GetJniEnv(),
+ Runtime::Current()->IsActiveTransaction()
+ ? CreateInternalStackTrace<true>(soa)
+ : CreateInternalStackTrace<false>(soa));
+ if (trace.get() != nullptr) {
+ exception->SetStackState(down_cast<mirror::Throwable*>(DecodeJObject(trace.get())));
+ }
ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
throw_location.GetDexPc());
SetException(gc_safe_throw_location, exception.get());
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 91170f0..03ceed3 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -649,54 +649,53 @@
}
bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
- DecodedInstruction dec_insn(inst);
bool result = true;
switch (inst->GetVerifyTypeArgumentA()) {
case Instruction::kVerifyRegA:
- result = result && CheckRegisterIndex(dec_insn.vA);
+ result = result && CheckRegisterIndex(inst->VRegA());
break;
case Instruction::kVerifyRegAWide:
- result = result && CheckWideRegisterIndex(dec_insn.vA);
+ result = result && CheckWideRegisterIndex(inst->VRegA());
break;
}
switch (inst->GetVerifyTypeArgumentB()) {
case Instruction::kVerifyRegB:
- result = result && CheckRegisterIndex(dec_insn.vB);
+ result = result && CheckRegisterIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBField:
- result = result && CheckFieldIndex(dec_insn.vB);
+ result = result && CheckFieldIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBMethod:
- result = result && CheckMethodIndex(dec_insn.vB);
+ result = result && CheckMethodIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBNewInstance:
- result = result && CheckNewInstance(dec_insn.vB);
+ result = result && CheckNewInstance(inst->VRegB());
break;
case Instruction::kVerifyRegBString:
- result = result && CheckStringIndex(dec_insn.vB);
+ result = result && CheckStringIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBType:
- result = result && CheckTypeIndex(dec_insn.vB);
+ result = result && CheckTypeIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBWide:
- result = result && CheckWideRegisterIndex(dec_insn.vB);
+ result = result && CheckWideRegisterIndex(inst->VRegB());
break;
}
switch (inst->GetVerifyTypeArgumentC()) {
case Instruction::kVerifyRegC:
- result = result && CheckRegisterIndex(dec_insn.vC);
+ result = result && CheckRegisterIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCField:
- result = result && CheckFieldIndex(dec_insn.vC);
+ result = result && CheckFieldIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCNewArray:
- result = result && CheckNewArray(dec_insn.vC);
+ result = result && CheckNewArray(inst->VRegC());
break;
case Instruction::kVerifyRegCType:
- result = result && CheckTypeIndex(dec_insn.vC);
+ result = result && CheckTypeIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCWide:
- result = result && CheckWideRegisterIndex(dec_insn.vC);
+ result = result && CheckWideRegisterIndex(inst->VRegC());
break;
}
switch (inst->GetVerifyExtraFlags()) {
@@ -709,11 +708,14 @@
case Instruction::kVerifySwitchTargets:
result = result && CheckSwitchTargets(code_offset);
break;
- case Instruction::kVerifyVarArg:
- result = result && CheckVarArgRegs(dec_insn.vA, dec_insn.arg);
+ case Instruction::kVerifyVarArg: {
+ uint32_t args[Instruction::kMaxVarArgRegs];
+ inst->GetVarArgs(args);
+ result = result && CheckVarArgRegs(inst->VRegA(), args);
break;
+ }
case Instruction::kVerifyVarArgRange:
- result = result && CheckVarArgRangeRegs(dec_insn.vA, dec_insn.vC);
+ result = result && CheckVarArgRangeRegs(inst->VRegA(), inst->VRegC());
break;
case Instruction::kVerifyError:
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected opcode " << inst->Name();
@@ -1009,7 +1011,7 @@
}
bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
- if (vA > 5) {
+ if (vA > Instruction::kMaxVarArgRegs) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << vA << ") in non-range invoke)";
return false;
}
@@ -3075,7 +3077,7 @@
size_t params_size = params == NULL ? 0 : params->Size();
uint32_t arg[5];
if (!is_range) {
- inst->GetArgs(arg);
+ inst->GetVarArgs(arg);
}
for (size_t param_index = 0; param_index < params_size; param_index++) {
if (actual_args >= expected_args) {
@@ -3189,7 +3191,7 @@
size_t params_size = params == NULL ? 0 : params->Size();
uint32_t arg[5];
if (!is_range) {
- inst->GetArgs(arg);
+ inst->GetVarArgs(arg);
}
size_t actual_args = 1;
for (size_t param_index = 0; param_index < params_size; param_index++) {
@@ -3255,7 +3257,7 @@
uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
uint32_t arg[5];
if (!is_range) {
- inst->GetArgs(arg);
+ inst->GetVarArgs(arg);
}
for (size_t ui = 0; ui < arg_count; ui++) {
uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui];
diff --git a/test/run-all-tests b/test/run-all-tests
index a6675df..3a991e9 100755
--- a/test/run-all-tests
+++ b/test/run-all-tests
@@ -35,6 +35,7 @@
run_args=""
usage="no"
+sequental="no"
while true; do
if [ "x$1" = "x--host" ]; then
@@ -70,6 +71,12 @@
elif [ "x$1" = "x--help" ]; then
usage="yes"
shift
+ elif [ "x$1" = "x--seq" ]; then
+ sequental="yes"
+ shift
+ elif [ "x$1" = "x-O" ]; then
+ run_args="${run_args} -O"
+ shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
usage="yes"
@@ -89,34 +96,55 @@
"further documentation:"
echo " --debug --dev --host --interpreter --jvm --no-optimize"
echo " --no-verify -O --update --valgrind --zygote"
+ echo " Specific Runtime Options:"
+ echo " --seq Run tests one-by-one, avoiding failures caused by busy CPU"
) 1>&2
exit 1
fi
-# start all the tests
-i=0
-for test_name in *; do
- if [ -d "$test_name" -a -r "$test_name" -a -r "$test_name/info.txt" ]; then
- ./run-test ${run_args} "$test_name" &
- test_pids[i]=$!
- test_names[test_pids[i]]="$test_name"
- let i+=1
- fi
-done
+if [ "$sequental" == "yes" ]; then
+ i=0
+ for test_name in *; do
+ if [ -d "$test_name" -a -r "$test_name" -a -r "$test_name/info.txt" ]; then
+ ./run-test ${run_args} "$test_name"
+ RES=$?
+ test_pids[i]=i
+ test_names[test_pids[i]]="$test_name"
+ if [ "$RES" != "0" ]; then
+ let failure_count+=1
+ failed_test_names="$failed_test_names ${test_names[i]}"
+ else
+ let succeeded_count+=1
+ fi
+ let i+=1
+ fi
+ done
+else
+ # start all the tests
+ i=0
+ for test_name in *; do
+ if [ -d "$test_name" -a -r "$test_name" -a -r "$test_name/info.txt" ]; then
+ ./run-test ${run_args} "$test_name" &
+ test_pids[i]=$!
+ test_names[test_pids[i]]="$test_name"
+ let i+=1
+ fi
+ done
-# wait for all the tests, collecting the failures
-failure_count=0
-succeeded_count=0
-failed_test_names=""
-for pid in ${test_pids[@]}; do
- wait $pid
- if [ "$?" != "0" ]; then
- let failure_count+=1
- failed_test_names="$failed_test_names ${test_names[$pid]}[pid=$pid]"
- else
- let succeeded_count+=1
- fi
-done
+ # wait for all the tests, collecting the failures
+ failure_count=0
+ succeeded_count=0
+ failed_test_names=""
+ for pid in ${test_pids[@]}; do
+ wait $pid
+ if [ "$?" != "0" ]; then
+ let failure_count+=1
+ failed_test_names="$failed_test_names ${test_names[$pid]}[pid=$pid]"
+ else
+ let succeeded_count+=1
+ fi
+ done
+fi
echo "succeeded tests: $succeeded_count"
echo "failed tests: $failure_count"
diff --git a/test/run-test b/test/run-test
index 6e59641..1c5904f 100755
--- a/test/run-test
+++ b/test/run-test
@@ -33,7 +33,7 @@
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
test_dir="test-$$"
-tmp_dir="/tmp/${test_dir}"
+tmp_dir="/tmp/$USER/${test_dir}"
export JAVA="java"
export JAVAC="javac -g"
@@ -165,6 +165,7 @@
break
fi
done
+mkdir -p $tmp_dir
if [ ! "$runtime" = "jvm" ]; then
run_args="${run_args} --lib $lib"
@@ -356,7 +357,7 @@
cd "$oldwd"
rm -rf "$tmp_dir"
if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then
- adb shell rm -r $DEX_LOCATION
+ adb shell rm -rf $DEX_LOCATION
fi
exit 0
fi