ART: Quick compiler: More size checks, add TargetReg variants
Add variants for TargetReg for requesting specific register usage,
e.g., wide and ref. More register size checks.
With code adapted from https://android-review.googlesource.com/#/c/98605/.
Change-Id: I852d3be509d4dcd242c7283da702a2a76357278d
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index f4e28e6..398c7f6 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -27,6 +27,7 @@
#include "mir_method_info.h"
#include "utils/arena_bit_vector.h"
#include "utils/growable_array.h"
+#include "reg_location.h"
#include "reg_storage.h"
namespace art {
@@ -492,39 +493,6 @@
};
/*
- * Whereas a SSA name describes a definition of a Dalvik vreg, the RegLocation describes
- * the type of an SSA name (and, can also be used by code generators to record where the
- * value is located (i.e. - physical register, frame, spill, etc.). For each SSA name (SReg)
- * there is a RegLocation.
- * A note on SSA names:
- * o SSA names for Dalvik vRegs v0..vN will be assigned 0..N. These represent the "vN_0"
- * names. Negative SSA names represent special values not present in the Dalvik byte code.
- * For example, SSA name -1 represents an invalid SSA name, and SSA name -2 represents the
- * the Method pointer. SSA names < -2 are reserved for future use.
- * o The vN_0 names for non-argument Dalvik should in practice never be used (as they would
- * represent the read of an undefined local variable). The first definition of the
- * underlying Dalvik vReg will result in a vN_1 name.
- *
- * FIXME: The orig_sreg field was added as a workaround for llvm bitcode generation. With
- * the latest restructuring, we should be able to remove it and rely on s_reg_low throughout.
- */
-struct RegLocation {
- RegLocationType location:3;
- unsigned wide:1;
- unsigned defined:1; // Do we know the type?
- unsigned is_const:1; // Constant, value in mir_graph->constant_values[].
- unsigned fp:1; // Floating point?
- unsigned core:1; // Non-floating point?
- unsigned ref:1; // Something GC cares about.
- unsigned high_word:1; // High word of pair?
- unsigned home:1; // Does this represent the home location?
- 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.
-};
-
-/*
* Collection of information describing an invoke, and the destination of
* the subsequent MOVE_RESULT (if applicable). Collected as a unit to enable
* more efficient invoke code generation.
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index b0865f1..ea7f439 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -179,6 +179,8 @@
// RegisterLocation templates return values (following the hard-float calling convention).
const RegLocation arm_loc_c_return =
{kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_w0, INVALID_SREG, INVALID_SREG};
+const RegLocation arm_loc_c_return_ref =
+ {kLocPhysReg, 0, 0, 0, 0, 0, 1, 0, 1, rs_x0, INVALID_SREG, INVALID_SREG};
const RegLocation arm_loc_c_return_wide =
{kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, rs_x0, INVALID_SREG, INVALID_SREG};
const RegLocation arm_loc_c_return_float =
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index cfdf926..3e0b3cf 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -132,7 +132,7 @@
// Load the displacement from the switch table
RegStorage disp_reg = AllocTemp();
- LoadBaseIndexed(table_base, As64BitReg(key_reg), As64BitReg(disp_reg), 2, k32);
+ LoadBaseIndexed(table_base, As64BitReg(key_reg), disp_reg, 2, k32);
// Get base branch address.
RegStorage branch_reg = AllocTempWide();
@@ -195,7 +195,7 @@
// TUNING: How much performance we get when we inline this?
// Since we've already flush all register.
FlushAllRegs();
- LoadValueDirectFixed(rl_src, rs_w0);
+ LoadValueDirectFixed(rl_src, rs_x0); // = TargetRefReg(kArg0)
LockCallTemps(); // Prepare for explicit register usage
LIR* null_check_branch = nullptr;
if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) {
@@ -243,7 +243,7 @@
// TUNING: How much performance we get when we inline this?
// Since we've already flush all register.
FlushAllRegs();
- LoadValueDirectFixed(rl_src, rs_w0); // Get obj
+ LoadValueDirectFixed(rl_src, rs_x0); // Get obj
LockCallTemps(); // Prepare for explicit register usage
LIR* null_check_branch = nullptr;
if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) {
@@ -291,12 +291,12 @@
*/
void Arm64Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
RegStorage reg_card_base = AllocTempWide();
- RegStorage reg_card_no = AllocTemp();
+ RegStorage reg_card_no = AllocTempWide(); // Needs to be wide as addr is ref=64b
LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
LoadWordDisp(rs_xSELF, Thread::CardTableOffset<8>().Int32Value(), reg_card_base);
OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
// TODO(Arm64): generate "strb wB, [xB, wC, uxtw]" rather than "strb wB, [xB, xC]"?
- StoreBaseIndexed(reg_card_base, As64BitReg(reg_card_no), As32BitReg(reg_card_base),
+ StoreBaseIndexed(reg_card_base, reg_card_no, As32BitReg(reg_card_base),
0, kUnsignedByte);
LIR* target = NewLIR0(kPseudoTargetLabel);
branch_over->target = target;
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index a9340a5..f71713f 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -24,13 +24,8 @@
namespace art {
-class Arm64Mir2Lir : public Mir2Lir {
+class Arm64Mir2Lir FINAL : public Mir2Lir {
protected:
- // If we detect a size error, FATAL out.
- static constexpr bool kFailOnSizeError = false && kIsDebugBuild;
- // If we detect a size error, report to LOG.
- static constexpr bool kReportSizeError = false && kIsDebugBuild;
-
// TODO: consolidate 64-bit target support.
class InToRegStorageMapper {
public:
@@ -102,7 +97,19 @@
int offset, int check_value, LIR* target) OVERRIDE;
// Required for target - register utilities.
- RegStorage TargetReg(SpecialTargetRegister reg);
+ RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
+ RegStorage TargetReg(SpecialTargetRegister symbolic_reg, bool is_wide) OVERRIDE {
+ RegStorage reg = TargetReg(symbolic_reg);
+ if (is_wide) {
+ return (reg.Is64Bit()) ? reg : As64BitReg(reg);
+ } else {
+ return (reg.Is32Bit()) ? reg : As32BitReg(reg);
+ }
+ }
+ RegStorage TargetRefReg(SpecialTargetRegister symbolic_reg) OVERRIDE {
+ RegStorage reg = TargetReg(symbolic_reg);
+ return (reg.Is64Bit() ? reg : As64BitReg(reg));
+ }
RegStorage GetArgMappingToPhysicalReg(int arg_num);
RegLocation GetReturnAlt();
RegLocation GetReturnWideAlt();
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 56fb2dd..18a4e8f 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -181,6 +181,8 @@
if (LIKELY(dest_is_fp == src_is_fp)) {
if (LIKELY(!dest_is_fp)) {
+ DCHECK_EQ(r_dest.Is64Bit(), r_src.Is64Bit());
+
// Core/core copy.
// Copies involving the sp register require a different instruction.
opcode = UNLIKELY(A64_REG_IS_SP(r_dest.GetReg())) ? kA64Add4RRdT : kA64Mov2rr;
@@ -210,14 +212,14 @@
if (r_dest.IsDouble()) {
opcode = kA64Fmov2Sx;
} else {
- DCHECK(r_src.IsSingle());
+ r_src = Check32BitReg(r_src);
opcode = kA64Fmov2sw;
}
} else {
if (r_src.IsDouble()) {
opcode = kA64Fmov2xS;
} else {
- DCHECK(r_dest.Is32Bit());
+ r_dest = Check32BitReg(r_dest);
opcode = kA64Fmov2ws;
}
}
@@ -655,7 +657,7 @@
rl_src = LoadValue(rl_src, kCoreReg);
rl_result = EvalLocWide(rl_dest, kCoreReg, true);
- NewLIR4(WIDE(kA64Sbfm4rrdd), rl_result.reg.GetReg(), rl_src.reg.GetReg(), 0, 31);
+ NewLIR4(WIDE(kA64Sbfm4rrdd), rl_result.reg.GetReg(), As64BitReg(rl_src.reg).GetReg(), 0, 31);
StoreValueWide(rl_dest, rl_result);
}
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index 6105837..dcb0050 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -88,7 +88,7 @@
}
RegLocation Arm64Mir2Lir::LocCReturnRef() {
- return arm_loc_c_return;
+ return arm_loc_c_return_ref;
}
RegLocation Arm64Mir2Lir::LocCReturnWide() {
@@ -1097,7 +1097,7 @@
// Instead of allocating a new temp, simply reuse one of the registers being used
// for argument passing.
- RegStorage temp = TargetReg(kArg3);
+ RegStorage temp = TargetReg(kArg3, false);
// Now load the argument VR and store to the outs.
Load32Disp(TargetReg(kSp), current_src_offset, temp);
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index e248410..8561091 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -891,9 +891,8 @@
LIR* load;
int expected_scale = 0;
ArmOpcode opcode = kA64Brk1d;
- DCHECK(r_base.Is64Bit());
- // TODO: need a cleaner handling of index registers here and throughout.
- r_index = Check32BitReg(r_index);
+ r_base = Check64BitReg(r_base);
+ r_index = Check64BitReg(r_index);
if (r_dest.IsFloat()) {
if (r_dest.IsDouble()) {
@@ -928,17 +927,21 @@
expected_scale = 2;
break;
case kUnsignedHalf:
+ r_dest = Check32BitReg(r_dest);
opcode = kA64Ldrh4wXxd;
expected_scale = 1;
break;
case kSignedHalf:
+ r_dest = Check32BitReg(r_dest);
opcode = kA64Ldrsh4rXxd;
expected_scale = 1;
break;
case kUnsignedByte:
+ r_dest = Check32BitReg(r_dest);
opcode = kA64Ldrb3wXx;
break;
case kSignedByte:
+ r_dest = Check32BitReg(r_dest);
opcode = kA64Ldrsb3rXx;
break;
default:
@@ -968,9 +971,8 @@
LIR* store;
int expected_scale = 0;
ArmOpcode opcode = kA64Brk1d;
- DCHECK(r_base.Is64Bit());
- // TODO: need a cleaner handling of index registers here and throughout.
- r_index = Check32BitReg(r_index);
+ r_base = Check64BitReg(r_base);
+ r_index = Check64BitReg(r_index);
if (r_src.IsFloat()) {
if (r_src.IsDouble()) {
@@ -1006,11 +1008,13 @@
break;
case kUnsignedHalf:
case kSignedHalf:
+ r_src = Check32BitReg(r_src);
opcode = kA64Strh4wXxd;
expected_scale = 1;
break;
case kUnsignedByte:
case kSignedByte:
+ r_src = Check32BitReg(r_src);
opcode = kA64Strb3wXx;
break;
default:
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index f31b670..e571b3a 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1184,7 +1184,7 @@
// resolve these invokes to the same method, so we don't care which one we record here.
data_target->operands[2] = type;
}
- LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+ LIR* load_pc_rel = OpPcRelLoad(TargetRefReg(symbolic_reg), data_target);
AppendLIR(load_pc_rel);
DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
}
@@ -1200,7 +1200,7 @@
// resolve these invokes to the same method, so we don't care which one we record here.
data_target->operands[2] = type;
}
- LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+ LIR* load_pc_rel = OpPcRelLoad(TargetRefReg(symbolic_reg), data_target);
AppendLIR(load_pc_rel);
DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
}
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 04a23cf..2c59055 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -127,14 +127,17 @@
m2l_->ResetDefTracking();
GenerateTargetLabel(kPseudoThrowTarget);
- m2l_->OpRegCopy(m2l_->TargetReg(kArg1), length_);
- m2l_->LoadConstant(m2l_->TargetReg(kArg0), index_);
+ RegStorage arg1_32 = m2l_->TargetReg(kArg1, false);
+ RegStorage arg0_32 = m2l_->TargetReg(kArg0, false);
+
+ m2l_->OpRegCopy(arg1_32, length_);
+ m2l_->LoadConstant(arg0_32, index_);
if (m2l_->cu_->target64) {
m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(8, pThrowArrayBounds),
- m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
+ arg0_32, arg1_32, true);
} else {
m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
- m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
+ arg0_32, arg1_32, true);
}
}
@@ -473,7 +476,7 @@
switch (cu_->instruction_set) {
case kThumb2:
case kArm64:
- r_val = TargetReg(kLr);
+ r_val = TargetReg(kLr, false);
break;
case kX86:
case kX86_64:
@@ -597,10 +600,10 @@
// May do runtime call so everything to home locations.
FlushAllRegs();
// Using fixed register to sync with possible call to runtime support.
- RegStorage r_method = TargetReg(kArg1);
+ RegStorage r_method = TargetRefReg(kArg1);
LockTemp(r_method);
LoadCurrMethodDirect(r_method);
- r_base = TargetReg(kArg0);
+ r_base = TargetRefReg(kArg0);
LockTemp(r_base);
LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
kNotVolatile);
@@ -901,12 +904,12 @@
void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) {
RegLocation rl_method = LoadCurrMethod();
- DCHECK(!cu_->target64 || rl_method.reg.Is64Bit());
+ CheckRegLocation(rl_method);
RegStorage res_reg = AllocTempRef();
RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
- *cu_->dex_file,
- type_idx)) {
+ *cu_->dex_file,
+ type_idx)) {
// Call out to helper which resolves type and verifies access.
// Resolved type returned in kRet0.
if (cu_->target64) {
@@ -991,15 +994,15 @@
DCHECK(!IsTemp(rl_method.reg));
r_method = rl_method.reg;
} else {
- r_method = TargetReg(kArg2);
+ r_method = TargetRefReg(kArg2);
LoadCurrMethodDirect(r_method);
}
LoadRefDisp(r_method, mirror::ArtMethod::DexCacheStringsOffset().Int32Value(),
- TargetReg(kArg0), kNotVolatile);
+ TargetRefReg(kArg0), kNotVolatile);
// Might call out to helper, which will return resolved string in kRet0
- LoadRefDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0), kNotVolatile);
- LIR* fromfast = OpCmpImmBranch(kCondEq, TargetReg(kRet0), 0, NULL);
+ LoadRefDisp(TargetRefReg(kArg0), offset_of_string, TargetRefReg(kRet0), kNotVolatile);
+ LIR* fromfast = OpCmpImmBranch(kCondEq, TargetRefReg(kRet0), 0, NULL);
LIR* cont = NewLIR0(kPseudoTargetLabel);
{
@@ -1189,8 +1192,9 @@
FlushAllRegs();
// May generate a call - use explicit registers
LockCallTemps();
- LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
- RegStorage class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
+ RegStorage method_reg = TargetRefReg(kArg1);
+ LoadCurrMethodDirect(method_reg); // kArg1 <= current Method*
+ RegStorage class_reg = TargetRefReg(kArg2); // kArg2 will hold the Class*
if (needs_access_check) {
// Check we have access to type_idx and if not throw IllegalAccessError,
// returns Class* in kArg0
@@ -1205,12 +1209,12 @@
LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
} else if (use_declaring_class) {
LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
- LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
+ LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
class_reg, kNotVolatile);
} else {
// Load dex cache entry into class_reg (kArg2)
LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
- LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
+ LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
class_reg, kNotVolatile);
int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
@@ -1224,7 +1228,7 @@
} else {
CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx, true);
}
- OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
+ OpRegCopy(TargetRefReg(kArg2), TargetRefReg(kRet0)); // Align usage with fast path
LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* reload Ref */
// Rejoin code paths
LIR* hop_target = NewLIR0(kPseudoTargetLabel);
@@ -1232,7 +1236,7 @@
}
}
/* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
- RegLocation rl_result = GetReturn(kRefReg);
+ RegLocation rl_result = GetReturn(kCoreReg);
if (cu_->instruction_set == kMips) {
// On MIPS rArg0 != rl_result, place false in result if branch is taken.
LoadConstant(rl_result.reg, 0);
@@ -1241,7 +1245,7 @@
/* load object->klass_ */
DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
- LoadRefDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1),
+ LoadRefDisp(TargetRefReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetRefReg(kArg1),
kNotVolatile);
/* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
LIR* branchover = NULL;
@@ -1339,26 +1343,27 @@
FlushAllRegs();
// May generate a call - use explicit registers
LockCallTemps();
- LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
- RegStorage class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
+ RegStorage method_reg = TargetRefReg(kArg1);
+ LoadCurrMethodDirect(method_reg); // kArg1 <= current Method*
+ RegStorage class_reg = TargetRefReg(kArg2); // kArg2 will hold the Class*
if (needs_access_check) {
// Check we have access to type_idx and if not throw IllegalAccessError,
// returns Class* in kRet0
// InitializeTypeAndVerifyAccess(idx, method)
if (cu_->target64) {
- CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(8, pInitializeTypeAndVerifyAccess),
- type_idx, TargetReg(kArg1), true);
+ CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(8, pInitializeTypeAndVerifyAccess),
+ type_idx, true);
} else {
- CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
- type_idx, TargetReg(kArg1), true);
+ CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
+ type_idx, true);
}
- OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
+ OpRegCopy(class_reg, TargetRefReg(kRet0)); // Align usage with fast path
} else if (use_declaring_class) {
- LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
+ LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
class_reg, kNotVolatile);
} else {
// Load dex cache entry into class_reg (kArg2)
- LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
+ LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
class_reg, kNotVolatile);
int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
@@ -1383,12 +1388,12 @@
// InitializeTypeFromCode(idx, method)
if (m2l_->cu_->target64) {
m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(8, pInitializeType), type_idx_,
- m2l_->TargetReg(kArg1), true);
+ m2l_->TargetRefReg(kArg1), true);
} else {
m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx_,
- m2l_->TargetReg(kArg1), true);
+ m2l_->TargetRefReg(kArg1), true);
}
- m2l_->OpRegCopy(class_reg_, m2l_->TargetReg(kRet0)); // Align usage with fast path
+ m2l_->OpRegCopy(class_reg_, m2l_->TargetRefReg(kRet0)); // Align usage with fast path
m2l_->OpUnconditionalBranch(cont_);
}
@@ -1401,7 +1406,7 @@
}
}
// At this point, class_reg (kArg2) has class
- LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
+ LoadValueDirectFixed(rl_src, TargetRefReg(kArg0)); // kArg0 <= ref
// Slow path for the case where the classes are not equal. In this case we need
// to call a helper function to do the check.
@@ -1435,7 +1440,7 @@
if (type_known_abstract) {
// Easier case, run slow path if target is non-null (slow path will load from target)
- LIR* branch = OpCmpImmBranch(kCondNe, TargetReg(kArg0), 0, NULL);
+ LIR* branch = OpCmpImmBranch(kCondNe, TargetReg(kArg0), 0, nullptr);
LIR* cont = NewLIR0(kPseudoTargetLabel);
AddSlowPath(new (arena_) SlowPath(this, branch, cont, true));
} else {
@@ -1444,13 +1449,13 @@
// slow path if the classes are not equal.
/* Null is OK - continue */
- LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
+ LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, nullptr);
/* load object->klass_ */
DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
- LoadRefDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1),
- kNotVolatile);
+ LoadRefDisp(TargetRefReg(kArg0), mirror::Object::ClassOffset().Int32Value(),
+ TargetRefReg(kArg1), kNotVolatile);
- LIR* branch2 = OpCmpBranch(kCondNe, TargetReg(kArg1), class_reg, NULL);
+ LIR* branch2 = OpCmpBranch(kCondNe, TargetRefReg(kArg1), class_reg, nullptr);
LIR* cont = NewLIR0(kPseudoTargetLabel);
// Add the slow path that will not perform load since this is already done.
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 569c97f..aa574dc 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -223,7 +223,7 @@
void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset<pointer_size> helper_offset, int arg0,
RegStorage arg1, bool safepoint_pc) {
RegStorage r_tgt = CallHelperSetup(helper_offset);
- OpRegCopy(TargetReg(kArg1), arg1);
+ OpRegCopy(TargetReg(kArg1, arg1.Is64Bit()), arg1);
LoadConstant(TargetReg(kArg0), arg0);
ClobberCallerSave();
CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
@@ -276,7 +276,7 @@
OpRegCopy(TargetReg(kArg0), arg0);
}
LoadCurrMethodDirect(TargetReg(kArg1));
- LoadValueDirectFixed(arg2, TargetReg(kArg2));
+ LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
ClobberCallerSave();
CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
}
@@ -288,80 +288,103 @@
RegLocation arg0, RegLocation arg1,
bool safepoint_pc) {
RegStorage r_tgt = CallHelperSetup(helper_offset);
- if (arg0.wide == 0) {
- LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
- if (arg1.wide == 0) {
- if (cu_->instruction_set == kMips) {
- LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
- } else if (cu_->instruction_set == kArm64) {
- LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
- } else if (cu_->instruction_set == kX86_64) {
- if (arg0.fp) {
- LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg0));
- } else {
- LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg0) : TargetReg(kArg1));
- }
- } else {
- LoadValueDirectFixed(arg1, TargetReg(kArg1));
- }
+ if (cu_->instruction_set == kArm64) {
+ RegStorage arg0_reg = TargetReg((arg0.fp) ? kFArg0 : kArg0, arg0);
+
+ RegStorage arg1_reg;
+ if (arg1.fp == arg0.fp) {
+ arg1_reg = TargetReg((arg1.fp) ? kFArg1 : kArg1, arg1);
} else {
- if (cu_->instruction_set == kMips) {
- RegStorage r_tmp;
- if (arg1.fp) {
- r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3));
- } else {
- // skip kArg1 for stack alignment.
- r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
- }
- LoadValueDirectWideFixed(arg1, r_tmp);
- } else {
- RegStorage r_tmp;
- if (cu_->target64) {
- r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg());
- } else {
- r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2));
- }
- LoadValueDirectWideFixed(arg1, r_tmp);
- }
+ arg1_reg = TargetReg((arg1.fp) ? kFArg0 : kArg0, arg1);
+ }
+
+ if (arg0.wide == 0) {
+ LoadValueDirectFixed(arg0, arg0_reg);
+ } else {
+ LoadValueDirectWideFixed(arg0, arg0_reg);
+ }
+
+ if (arg1.wide == 0) {
+ LoadValueDirectFixed(arg1, arg1_reg);
+ } else {
+ LoadValueDirectWideFixed(arg1, arg1_reg);
}
} else {
- RegStorage r_tmp;
- if (arg0.fp) {
- if (cu_->target64) {
- r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg0).GetReg());
+ if (arg0.wide == 0) {
+ LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
+ if (arg1.wide == 0) {
+ if (cu_->instruction_set == kMips) {
+ LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
+ } else if (cu_->instruction_set == kArm64) {
+ LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
+ } else if (cu_->instruction_set == kX86_64) {
+ if (arg0.fp) {
+ LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg0));
+ } else {
+ LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg0) : TargetReg(kArg1));
+ }
+ } else {
+ LoadValueDirectFixed(arg1, TargetReg(kArg1));
+ }
} else {
- r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg0), TargetReg(kFArg1));
- }
- } else {
- if (cu_->target64) {
- r_tmp = RegStorage::Solo64(TargetReg(kArg0).GetReg());
- } else {
- r_tmp = RegStorage::MakeRegPair(TargetReg(kArg0), TargetReg(kArg1));
- }
- }
- LoadValueDirectWideFixed(arg0, r_tmp);
- if (arg1.wide == 0) {
- if (cu_->target64) {
- LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
- } else {
- LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
+ if (cu_->instruction_set == kMips) {
+ RegStorage r_tmp;
+ if (arg1.fp) {
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3));
+ } else {
+ // skip kArg1 for stack alignment.
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
+ }
+ LoadValueDirectWideFixed(arg1, r_tmp);
+ } else {
+ RegStorage r_tmp;
+ if (cu_->target64) {
+ r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg());
+ } else {
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2));
+ }
+ LoadValueDirectWideFixed(arg1, r_tmp);
+ }
}
} else {
RegStorage r_tmp;
- if (arg1.fp) {
+ if (arg0.fp) {
if (cu_->target64) {
- r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg1).GetReg());
+ r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg0).GetReg());
} else {
- r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3));
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg0), TargetReg(kFArg1));
}
} else {
if (cu_->target64) {
- r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg());
+ r_tmp = RegStorage::Solo64(TargetReg(kArg0).GetReg());
} else {
- r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kArg0), TargetReg(kArg1));
}
}
- LoadValueDirectWideFixed(arg1, r_tmp);
+ LoadValueDirectWideFixed(arg0, r_tmp);
+ if (arg1.wide == 0) {
+ if (cu_->target64) {
+ LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
+ } else {
+ LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
+ }
+ } else {
+ RegStorage r_tmp;
+ if (arg1.fp) {
+ if (cu_->target64) {
+ r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg1).GetReg());
+ } else {
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3));
+ }
+ } else {
+ if (cu_->target64) {
+ r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg());
+ } else {
+ r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
+ }
+ }
+ LoadValueDirectWideFixed(arg1, r_tmp);
+ }
}
}
ClobberCallerSave();
@@ -381,16 +404,16 @@
if (IsSameReg(arg1, TargetReg(kArg0))) {
if (IsSameReg(arg0, TargetReg(kArg1))) {
// Swap kArg0 and kArg1 with kArg2 as temp.
- OpRegCopy(TargetArgReg(kArg2, arg1.Is64Bit()), arg1);
- OpRegCopy(TargetArgReg(kArg0, arg0.Is64Bit()), arg0);
- OpRegCopy(TargetArgReg(kArg1, arg1.Is64Bit()), TargetReg(kArg2));
+ OpRegCopy(TargetReg(kArg2, arg1.Is64Bit()), arg1);
+ OpRegCopy(TargetReg(kArg0, arg0.Is64Bit()), arg0);
+ OpRegCopy(TargetReg(kArg1, arg1.Is64Bit()), TargetReg(kArg2, arg1.Is64Bit()));
} else {
- OpRegCopy(TargetArgReg(kArg1, arg1.Is64Bit()), arg1);
- OpRegCopy(TargetArgReg(kArg0, arg0.Is64Bit()), arg0);
+ OpRegCopy(TargetReg(kArg1, arg1.Is64Bit()), arg1);
+ OpRegCopy(TargetReg(kArg0, arg0.Is64Bit()), arg0);
}
} else {
- OpRegCopy(TargetArgReg(kArg0, arg0.Is64Bit()), arg0);
- OpRegCopy(TargetArgReg(kArg1, arg1.Is64Bit()), arg1);
+ OpRegCopy(TargetReg(kArg0, arg0.Is64Bit()), arg0);
+ OpRegCopy(TargetReg(kArg1, arg1.Is64Bit()), arg1);
}
}
@@ -421,9 +444,9 @@
void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset<pointer_size> helper_offset,
int arg0, RegLocation arg2, bool safepoint_pc) {
RegStorage r_tgt = CallHelperSetup(helper_offset);
- LoadValueDirectFixed(arg2, TargetReg(kArg2));
+ LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
LoadCurrMethodDirect(TargetReg(kArg1));
- LoadConstant(TargetReg(kArg0), arg0);
+ LoadConstant(TargetReg(kArg0, arg0), arg0);
ClobberCallerSave();
CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
}
@@ -449,13 +472,13 @@
RegStorage r_tgt = CallHelperSetup(helper_offset);
DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U); // The static_cast works around an
// instantiation bug in GCC.
- LoadValueDirectFixed(arg1, TargetReg(kArg1));
+ LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
if (arg2.wide == 0) {
- LoadValueDirectFixed(arg2, TargetReg(kArg2));
+ LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
} else {
RegStorage r_tmp;
if (cu_->target64) {
- r_tmp = RegStorage::Solo64(TargetReg(kArg2).GetReg());
+ r_tmp = TargetReg(kArg2, true);
} else {
r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
}
@@ -474,12 +497,9 @@
RegLocation arg2,
bool safepoint_pc) {
RegStorage r_tgt = CallHelperSetup(helper_offset);
- DCHECK_EQ(static_cast<unsigned int>(arg0.wide), 0U);
- LoadValueDirectFixed(arg0, TargetReg(kArg0));
- DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U);
- LoadValueDirectFixed(arg1, TargetReg(kArg1));
- DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U);
- LoadValueDirectFixed(arg2, TargetReg(kArg2));
+ LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0));
+ LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
+ LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
ClobberCallerSave();
CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
}
@@ -502,13 +522,13 @@
*/
RegLocation rl_src = rl_method;
rl_src.location = kLocPhysReg;
- rl_src.reg = TargetReg(kArg0);
+ rl_src.reg = TargetRefReg(kArg0);
rl_src.home = false;
MarkLive(rl_src);
StoreValue(rl_method, rl_src);
// If Method* has been promoted, explicitly flush
if (rl_method.location == kLocPhysReg) {
- StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0), kNotVolatile);
+ StoreRefDisp(TargetReg(kSp), 0, rl_src.reg, kNotVolatile);
}
if (cu_->num_ins == 0) {
@@ -615,15 +635,16 @@
return -1;
}
} else {
+ RegStorage arg0_ref = cg->TargetRefReg(kArg0);
switch (state) {
case 0: // Get the current Method* [sets kArg0]
// TUNING: we can save a reg copy if Method* has been promoted.
- cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
+ cg->LoadCurrMethodDirect(arg0_ref);
break;
case 1: // Get method->dex_cache_resolved_methods_
- cg->LoadRefDisp(cg->TargetReg(kArg0),
+ cg->LoadRefDisp(arg0_ref,
mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
- cg->TargetReg(kArg0),
+ arg0_ref,
kNotVolatile);
// Set up direct code if known.
if (direct_code != 0) {
@@ -637,15 +658,15 @@
break;
case 2: // Grab target method*
CHECK_EQ(cu->dex_file, target_method.dex_file);
- cg->LoadRefDisp(cg->TargetReg(kArg0),
+ cg->LoadRefDisp(arg0_ref,
ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(),
- cg->TargetReg(kArg0),
+ arg0_ref,
kNotVolatile);
break;
case 3: // Grab the code from the method*
if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
if (direct_code == 0) {
- cg->LoadWordDisp(cg->TargetReg(kArg0),
+ cg->LoadWordDisp(arg0_ref,
mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
cg->TargetReg(kInvokeTgt));
}
@@ -678,13 +699,13 @@
switch (state) {
case 0: { // Get "this" [set kArg1]
RegLocation rl_arg = info->args[0];
- cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
+ cg->LoadValueDirectFixed(rl_arg, cg->TargetRefReg(kArg1));
break;
}
case 1: // Is "this" null? [use kArg1]
- cg->GenNullCheck(cg->TargetReg(kArg1), info->opt_flags);
+ cg->GenNullCheck(cg->TargetRefReg(kArg1), info->opt_flags);
// get this->klass_ [use kArg1, set kInvokeTgt]
- cg->LoadRefDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
+ cg->LoadRefDisp(cg->TargetRefReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
cg->TargetReg(kInvokeTgt),
kNotVolatile);
cg->MarkPossibleNullPointerException(info->opt_flags);
@@ -697,12 +718,12 @@
case 3: // Get target method [use kInvokeTgt, set kArg0]
cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
ObjArray::OffsetOfElement(method_idx).Int32Value(),
- cg->TargetReg(kArg0),
+ cg->TargetRefReg(kArg0),
kNotVolatile);
break;
case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
- cg->LoadWordDisp(cg->TargetReg(kArg0),
+ cg->LoadWordDisp(cg->TargetRefReg(kArg0),
mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
cg->TargetReg(kInvokeTgt));
break;
@@ -736,13 +757,13 @@
break;
case 1: { // Get "this" [set kArg1]
RegLocation rl_arg = info->args[0];
- cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
+ cg->LoadValueDirectFixed(rl_arg, cg->TargetRefReg(kArg1));
break;
}
case 2: // Is "this" null? [use kArg1]
- cg->GenNullCheck(cg->TargetReg(kArg1), info->opt_flags);
+ cg->GenNullCheck(cg->TargetRefReg(kArg1), info->opt_flags);
// Get this->klass_ [use kArg1, set kInvokeTgt]
- cg->LoadRefDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
+ cg->LoadRefDisp(cg->TargetRefReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
cg->TargetReg(kInvokeTgt),
kNotVolatile);
cg->MarkPossibleNullPointerException(info->opt_flags);
@@ -757,12 +778,12 @@
// NOTE: native pointer.
cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
ObjArray::OffsetOfElement(method_idx % ClassLinker::kImtSize).Int32Value(),
- cg->TargetReg(kArg0),
+ cg->TargetRefReg(kArg0),
kNotVolatile);
break;
case 5: // Get the compiled code address [use kArg0, set kInvokeTgt]
if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
- cg->LoadWordDisp(cg->TargetReg(kArg0),
+ cg->LoadWordDisp(cg->TargetRefReg(kArg0),
mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
cg->TargetReg(kInvokeTgt));
break;
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index bfb77fc..1cddeb9 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -192,7 +192,7 @@
IsPromoted(rl_src.reg) ||
(rl_dest.location == kLocPhysReg)) {
// Src is live/promoted or Dest has assigned reg.
- rl_dest = EvalLoc(rl_dest, kAnyReg, false);
+ rl_dest = EvalLoc(rl_dest, rl_dest.ref || rl_src.ref ? kRefReg : kAnyReg, false);
OpRegCopy(rl_dest.reg, rl_src.reg);
} else {
// Just re-assign the registers. Dest gets Src's regs
@@ -201,7 +201,7 @@
}
} else {
// Load Src either into promoted Dest or temps allocated for Dest
- rl_dest = EvalLoc(rl_dest, kAnyReg, false);
+ rl_dest = EvalLoc(rl_dest, rl_dest.ref ? kRefReg : kAnyReg, false);
LoadValueDirect(rl_src, rl_dest.reg);
}
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index 9912101..9a62255 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -253,6 +253,19 @@
return res;
}
+inline void Mir2Lir::CheckRegLocation(RegLocation rl) const {
+ if (kFailOnSizeError || kReportSizeError) {
+ CheckRegLocationImpl(rl, kFailOnSizeError, kReportSizeError);
+ }
+}
+
+inline void Mir2Lir::CheckRegStorage(RegStorage rs, WidenessCheck wide, RefCheck ref, FPCheck fp)
+ const {
+ if (kFailOnSizeError || kReportSizeError) {
+ CheckRegStorageImpl(rs, wide, ref, fp, kFailOnSizeError, kReportSizeError);
+ }
+}
+
} // namespace art
#endif // ART_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 5d68187..984e8ea 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -1267,4 +1267,55 @@
return target;
}
+
+void Mir2Lir::CheckRegStorageImpl(RegStorage rs, WidenessCheck wide, RefCheck ref, FPCheck fp,
+ bool fail, bool report)
+ const {
+ if (rs.Valid()) {
+ if (ref == RefCheck::kCheckRef) {
+ if (cu_->target64 && !rs.Is64Bit()) {
+ if (fail) {
+ CHECK(false) << "Reg storage not 64b for ref.";
+ } else if (report) {
+ LOG(WARNING) << "Reg storage not 64b for ref.";
+ }
+ }
+ }
+ if (wide == WidenessCheck::kCheckWide) {
+ if (!rs.Is64Bit()) {
+ if (fail) {
+ CHECK(false) << "Reg storage not 64b for wide.";
+ } else if (report) {
+ LOG(WARNING) << "Reg storage not 64b for wide.";
+ }
+ }
+ }
+ // A tighter check would be nice, but for now soft-float will not check float at all.
+ if (fp == FPCheck::kCheckFP && cu_->instruction_set != kArm) {
+ if (!rs.IsFloat()) {
+ if (fail) {
+ CHECK(false) << "Reg storage not float for fp.";
+ } else if (report) {
+ LOG(WARNING) << "Reg storage not float for fp.";
+ }
+ }
+ } else if (fp == FPCheck::kCheckNotFP) {
+ if (rs.IsFloat()) {
+ if (fail) {
+ CHECK(false) << "Reg storage float for not-fp.";
+ } else if (report) {
+ LOG(WARNING) << "Reg storage float for not-fp.";
+ }
+ }
+ }
+ }
+}
+
+void Mir2Lir::CheckRegLocationImpl(RegLocation rl, bool fail, bool report) const {
+ // Regrettably can't use the fp part of rl, as that is not really indicative of where a value
+ // will be stored.
+ CheckRegStorageImpl(rl.reg, rl.wide ? WidenessCheck::kCheckWide : WidenessCheck::kCheckNotWide,
+ rl.ref ? RefCheck::kCheckRef : RefCheck::kCheckNotRef, FPCheck::kIgnoreFP, fail, report);
+}
+
} // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index cb0bb80..c98fbca 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -21,6 +21,7 @@
#include "compiled_method.h"
#include "dex/compiler_enums.h"
#include "dex/compiler_ir.h"
+#include "dex/reg_location.h"
#include "dex/reg_storage.h"
#include "dex/backend.h"
#include "dex/quick/resource_mask.h"
@@ -124,7 +125,6 @@
struct InlineMethod;
struct MIR;
struct LIR;
-struct RegLocation;
struct RegisterInfo;
class DexFileMethodInliner;
class MIRGraph;
@@ -239,6 +239,9 @@
class Mir2Lir : public Backend {
public:
+ static constexpr bool kFailOnSizeError = true && kIsDebugBuild;
+ static constexpr bool kReportSizeError = true && kIsDebugBuild;
+
/*
* Auxiliary information describing the location of data embedded in the Dalvik
* byte code stream.
@@ -1173,7 +1176,43 @@
virtual void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) = 0;
// Required for target - register utilities.
+
+ /**
+ * @brief Portable way of getting special registers from the backend.
+ * @param reg Enumeration describing the purpose of the register.
+ * @return Return the #RegStorage corresponding to the given purpose @p reg.
+ * @note This function is currently allowed to return any suitable view of the registers
+ * (e.g. this could be 64-bit solo or 32-bit solo for 64-bit backends).
+ */
virtual RegStorage TargetReg(SpecialTargetRegister reg) = 0;
+
+ /**
+ * @brief Portable way of getting special registers from the backend.
+ * @param reg Enumeration describing the purpose of the register.
+ * @param is_wide Whether the view should be 64-bit (rather than 32-bit).
+ * @return Return the #RegStorage corresponding to the given purpose @p reg.
+ */
+ virtual RegStorage TargetReg(SpecialTargetRegister reg, bool is_wide) {
+ return TargetReg(reg);
+ }
+
+ /**
+ * @brief Portable way of getting a special register for storing a reference.
+ * @see TargetReg()
+ */
+ virtual RegStorage TargetRefReg(SpecialTargetRegister reg) {
+ return TargetReg(reg);
+ }
+
+ // Get a reg storage corresponding to the wide & ref flags of the reg location.
+ virtual RegStorage TargetReg(SpecialTargetRegister reg, RegLocation loc) {
+ if (loc.ref) {
+ return TargetRefReg(reg);
+ } else {
+ return TargetReg(reg, loc.wide);
+ }
+ }
+
virtual RegStorage GetArgMappingToPhysicalReg(int arg_num) = 0;
virtual RegLocation GetReturnAlt() = 0;
virtual RegLocation GetReturnWideAlt() = 0;
@@ -1569,6 +1608,45 @@
*/
virtual void GenConst(RegLocation rl_dest, int value);
+ enum class WidenessCheck { // private
+ kIgnoreWide,
+ kCheckWide,
+ kCheckNotWide
+ };
+
+ enum class RefCheck { // private
+ kIgnoreRef,
+ kCheckRef,
+ kCheckNotRef
+ };
+
+ enum class FPCheck { // private
+ kIgnoreFP,
+ kCheckFP,
+ kCheckNotFP
+ };
+
+ /**
+ * Check whether a reg storage seems well-formed, that is, if a reg storage is valid,
+ * that it has the expected form for the flags.
+ * A flag value of 0 means ignore. A flag value of -1 means false. A flag value of 1 means true.
+ */
+ void CheckRegStorageImpl(RegStorage rs, WidenessCheck wide, RefCheck ref, FPCheck fp, bool fail,
+ bool report)
+ const;
+
+ /**
+ * Check whether a reg location seems well-formed, that is, if a reg storage is encoded,
+ * that it has the expected size.
+ */
+ void CheckRegLocationImpl(RegLocation rl, bool fail, bool report) const;
+
+ // See CheckRegStorageImpl. Will print or fail depending on kFailOnSizeError and
+ // kReportSizeError.
+ void CheckRegStorage(RegStorage rs, WidenessCheck wide, RefCheck ref, FPCheck fp) const;
+ // See CheckRegLocationImpl.
+ void CheckRegLocation(RegLocation rl) const;
+
public:
// TODO: add accessors for these.
LIR* literal_list_; // Constants.
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 81dabd4..38370ad 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -420,24 +420,28 @@
RegStorage high_reg = AllocTemp();
res = RegStorage::MakeRegPair(low_reg, high_reg);
}
+ CheckRegStorage(res, WidenessCheck::kCheckWide, RefCheck::kIgnoreRef, FPCheck::kCheckNotFP);
return res;
}
RegStorage Mir2Lir::AllocTempRef() {
RegStorage res = AllocTempBody(*reg_pool_->ref_regs_, reg_pool_->next_ref_reg_, true);
DCHECK(!res.IsPair());
+ CheckRegStorage(res, WidenessCheck::kCheckNotWide, RefCheck::kCheckRef, FPCheck::kCheckNotFP);
return res;
}
RegStorage Mir2Lir::AllocTempSingle() {
RegStorage res = AllocTempBody(reg_pool_->sp_regs_, ®_pool_->next_sp_reg_, true);
DCHECK(res.IsSingle()) << "Reg: 0x" << std::hex << res.GetRawBits();
+ CheckRegStorage(res, WidenessCheck::kCheckNotWide, RefCheck::kCheckNotRef, FPCheck::kIgnoreFP);
return res;
}
RegStorage Mir2Lir::AllocTempDouble() {
RegStorage res = AllocTempBody(reg_pool_->dp_regs_, ®_pool_->next_dp_reg_, true);
DCHECK(res.IsDouble()) << "Reg: 0x" << std::hex << res.GetRawBits();
+ CheckRegStorage(res, WidenessCheck::kCheckWide, RefCheck::kCheckNotRef, FPCheck::kIgnoreFP);
return res;
}
@@ -474,13 +478,15 @@
RegStorage reg;
if (reg_class == kRefReg) {
reg = FindLiveReg(*reg_pool_->ref_regs_, s_reg);
+ CheckRegStorage(reg, WidenessCheck::kCheckNotWide, RefCheck::kCheckRef, FPCheck::kCheckNotFP);
}
if (!reg.Valid() && ((reg_class == kAnyReg) || (reg_class == kFPReg))) {
reg = FindLiveReg(wide ? reg_pool_->dp_regs_ : reg_pool_->sp_regs_, s_reg);
}
if (!reg.Valid() && (reg_class != kFPReg)) {
if (cu_->target64) {
- reg = FindLiveReg(wide ? reg_pool_->core64_regs_ : reg_pool_->core_regs_, s_reg);
+ reg = FindLiveReg(wide || reg_class == kRefReg ? reg_pool_->core64_regs_ :
+ reg_pool_->core_regs_, s_reg);
} else {
reg = FindLiveReg(reg_pool_->core_regs_, s_reg);
}
@@ -525,6 +531,9 @@
ClobberSReg(s_reg + 1);
}
}
+ CheckRegStorage(reg, WidenessCheck::kIgnoreWide,
+ reg_class == kRefReg ? RefCheck::kCheckRef : RefCheck::kIgnoreRef,
+ FPCheck::kIgnoreFP);
return reg;
}
@@ -996,7 +1005,7 @@
if (loc.location != kLocPhysReg) {
DCHECK((loc.location == kLocDalvikFrame) ||
(loc.location == kLocCompilerTemp));
- RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, false);
+ RegStorage reg = AllocLiveReg(loc.s_reg_low, loc.ref ? kRefReg : kAnyReg, false);
if (reg.Valid()) {
bool match = true;
RegisterInfo* info = GetRegInfo(reg);
@@ -1010,6 +1019,7 @@
FreeTemp(reg);
}
}
+ CheckRegLocation(loc);
}
return loc;
}
@@ -1044,6 +1054,7 @@
FreeTemp(reg);
}
}
+ CheckRegLocation(loc);
}
return loc;
}
@@ -1073,6 +1084,7 @@
MarkWide(loc.reg);
MarkLive(loc);
}
+ CheckRegLocation(loc);
return loc;
}
@@ -1086,10 +1098,16 @@
loc.location = kLocPhysReg;
MarkLive(loc);
}
+ CheckRegLocation(loc);
return loc;
}
RegLocation Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) {
+ // Narrow reg_class if the loc is a ref.
+ if (loc.ref && reg_class == kAnyReg) {
+ reg_class = kRefReg;
+ }
+
if (loc.wide) {
return EvalLocWide(loc, reg_class, update);
}
@@ -1106,17 +1124,20 @@
loc.reg = new_reg;
MarkLive(loc);
}
+ CheckRegLocation(loc);
return loc;
}
DCHECK_NE(loc.s_reg_low, INVALID_SREG);
loc.reg = AllocTypedTemp(loc.fp, reg_class);
+ CheckRegLocation(loc);
if (update) {
loc.location = kLocPhysReg;
MarkLive(loc);
}
+ CheckRegLocation(loc);
return loc;
}
@@ -1338,6 +1359,7 @@
Clobber(res.reg);
LockTemp(res.reg);
MarkWide(res.reg);
+ CheckRegLocation(res);
return res;
}
@@ -1354,6 +1376,7 @@
} else {
LockTemp(res.reg);
}
+ CheckRegLocation(res);
return res;
}
diff --git a/compiler/dex/reg_location.h b/compiler/dex/reg_location.h
new file mode 100644
index 0000000..38f59da
--- /dev/null
+++ b/compiler/dex/reg_location.h
@@ -0,0 +1,60 @@
+/*
+ * 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_COMPILER_DEX_REG_LOCATION_H_
+#define ART_COMPILER_DEX_REG_LOCATION_H_
+
+#include "reg_storage.h"
+
+namespace art {
+
+
+/*
+ * Whereas a SSA name describes a definition of a Dalvik vreg, the RegLocation describes
+ * the type of an SSA name (and, can also be used by code generators to record where the
+ * value is located (i.e. - physical register, frame, spill, etc.). For each SSA name (SReg)
+ * there is a RegLocation.
+ * A note on SSA names:
+ * o SSA names for Dalvik vRegs v0..vN will be assigned 0..N. These represent the "vN_0"
+ * names. Negative SSA names represent special values not present in the Dalvik byte code.
+ * For example, SSA name -1 represents an invalid SSA name, and SSA name -2 represents the
+ * the Method pointer. SSA names < -2 are reserved for future use.
+ * o The vN_0 names for non-argument Dalvik should in practice never be used (as they would
+ * represent the read of an undefined local variable). The first definition of the
+ * underlying Dalvik vReg will result in a vN_1 name.
+ *
+ * FIXME: The orig_sreg field was added as a workaround for llvm bitcode generation. With
+ * the latest restructuring, we should be able to remove it and rely on s_reg_low throughout.
+ */
+struct RegLocation {
+ RegLocationType location:3;
+ unsigned wide:1;
+ unsigned defined:1; // Do we know the type?
+ unsigned is_const:1; // Constant, value in mir_graph->constant_values[].
+ unsigned fp:1; // Floating point?
+ unsigned core:1; // Non-floating point?
+ unsigned ref:1; // Something GC cares about.
+ unsigned high_word:1; // High word of pair?
+ unsigned home:1; // Does this represent the home location?
+ 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.
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_REG_LOCATION_H_