From 4b537a851b686402513a7c4a4e60f5457bb8d7c1 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 30 Jun 2014 22:24:53 -0700 Subject: [PATCH] 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 --- compiler/dex/mir_graph.h | 34 +---- compiler/dex/quick/arm64/arm64_lir.h | 2 + compiler/dex/quick/arm64/call_arm64.cc | 10 +- compiler/dex/quick/arm64/codegen_arm64.h | 21 ++- compiler/dex/quick/arm64/int_arm64.cc | 8 +- compiler/dex/quick/arm64/target_arm64.cc | 4 +- compiler/dex/quick/arm64/utility_arm64.cc | 16 ++- compiler/dex/quick/codegen_util.cc | 4 +- compiler/dex/quick/gen_common.cc | 83 ++++++------ compiler/dex/quick/gen_invoke.cc | 205 ++++++++++++++++-------------- compiler/dex/quick/gen_loadstore.cc | 4 +- compiler/dex/quick/mir_to_lir-inl.h | 13 ++ compiler/dex/quick/mir_to_lir.cc | 51 ++++++++ compiler/dex/quick/mir_to_lir.h | 80 +++++++++++- compiler/dex/quick/ralloc_util.cc | 27 +++- compiler/dex/reg_location.h | 60 +++++++++ 16 files changed, 428 insertions(+), 194 deletions(-) create mode 100644 compiler/dex/reg_location.h diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index f4e28e6c0..398c7f641 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 @@ class ChildBlockIterator { }; /* - * 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 b0865f1c3..ea7f439cf 100644 --- a/compiler/dex/quick/arm64/arm64_lir.h +++ b/compiler/dex/quick/arm64/arm64_lir.h @@ -179,6 +179,8 @@ constexpr RegStorage rs_wLR(RegStorage::kValid | rwLR); // 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 cfdf926fb..3e0b3cf31 100644 --- a/compiler/dex/quick/arm64/call_arm64.cc +++ b/compiler/dex/quick/arm64/call_arm64.cc @@ -132,7 +132,7 @@ void Arm64Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, // 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 @@ void Arm64Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { // 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 @@ void Arm64Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { // 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::GenMoveException(RegLocation rl_dest) { */ 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 a9340a5cc..f71713fc9 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 @@ class Arm64Mir2Lir : public Mir2Lir { 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 56fb2dd01..18a4e8f2a 100644 --- a/compiler/dex/quick/arm64/int_arm64.cc +++ b/compiler/dex/quick/arm64/int_arm64.cc @@ -181,6 +181,8 @@ LIR* Arm64Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) { 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 @@ LIR* Arm64Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) { 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 @@ void Arm64Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) { 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 6105837f7..dcb0050a8 100644 --- a/compiler/dex/quick/arm64/target_arm64.cc +++ b/compiler/dex/quick/arm64/target_arm64.cc @@ -88,7 +88,7 @@ RegLocation Arm64Mir2Lir::LocCReturn() { } RegLocation Arm64Mir2Lir::LocCReturnRef() { - return arm_loc_c_return; + return arm_loc_c_return_ref; } RegLocation Arm64Mir2Lir::LocCReturnWide() { @@ -1097,7 +1097,7 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, // 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 e2484101d..8561091b6 100644 --- a/compiler/dex/quick/arm64/utility_arm64.cc +++ b/compiler/dex/quick/arm64/utility_arm64.cc @@ -891,9 +891,8 @@ LIR* Arm64Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegSto 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 @@ LIR* Arm64Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegSto 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* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegSt 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 @@ LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegSt 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 f31b67016..e571b3a40 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -1184,7 +1184,7 @@ void Mir2Lir::LoadCodeAddress(const MethodReference& target_method, InvokeType t // 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(data_target); } @@ -1200,7 +1200,7 @@ void Mir2Lir::LoadMethodAddress(const MethodReference& target_method, InvokeType // 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(data_target); } diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 04a23cf13..2c5905524 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -127,14 +127,17 @@ void Mir2Lir::GenArrayBoundsCheck(int index, RegStorage length) { 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 @@ void Mir2Lir::GenFilledNewArray(CallInfo* info) { 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 @@ void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, bool is_long_or_double, // 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::GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl 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 @@ void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { 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 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know 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 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know 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 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know } 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 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know } } /* 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 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know /* 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 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ 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 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ // 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 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ } } // 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 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ 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 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ // 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 569c97f3a..aa574dce2 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -223,7 +223,7 @@ template void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset 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(r_tgt, helper_offset, safepoint_pc); @@ -276,7 +276,7 @@ void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(ThreadOffset h OpRegCopy(TargetReg(kArg0), arg0); } LoadCurrMethodDirect(TargetReg(kArg1)); - LoadValueDirectFixed(arg2, TargetReg(kArg2)); + LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -288,80 +288,103 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset 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 (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 { + 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) { - 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)); + LoadValueDirectFixed(arg1, arg1_reg); + } else { + LoadValueDirectWideFixed(arg1, arg1_reg); + } + } else { + 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, arg1.fp ? TargetReg(kFArg0) : TargetReg(kArg1)); + LoadValueDirectFixed(arg1, TargetReg(kArg1)); } } else { - LoadValueDirectFixed(arg1, TargetReg(kArg1)); + 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 { - if (cu_->instruction_set == kMips) { - RegStorage r_tmp; - if (arg1.fp) { - r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3)); + RegStorage r_tmp; + if (arg0.fp) { + if (cu_->target64) { + r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg0).GetReg()); } else { - // skip kArg1 for stack alignment. - r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)); + r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg0), TargetReg(kFArg1)); } - LoadValueDirectWideFixed(arg1, r_tmp); } else { - RegStorage r_tmp; if (cu_->target64) { - r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg()); + r_tmp = RegStorage::Solo64(TargetReg(kArg0).GetReg()); } else { - r_tmp = RegStorage::MakeRegPair(TargetReg(kArg1), TargetReg(kArg2)); + r_tmp = RegStorage::MakeRegPair(TargetReg(kArg0), TargetReg(kArg1)); } - LoadValueDirectWideFixed(arg1, r_tmp); } - } - } else { - RegStorage r_tmp; - if (arg0.fp) { - if (cu_->target64) { - r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg0).GetReg()); - } 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)); - } - } else { - RegStorage r_tmp; - if (arg1.fp) { + LoadValueDirectWideFixed(arg0, r_tmp); + if (arg1.wide == 0) { if (cu_->target64) { - r_tmp = RegStorage::FloatSolo64(TargetReg(kFArg1).GetReg()); + LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg1) : TargetReg(kArg1)); } else { - r_tmp = RegStorage::MakeRegPair(TargetReg(kFArg2), TargetReg(kFArg3)); + LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2)); } } else { - if (cu_->target64) { - r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg()); + 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 { - r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)); + if (cu_->target64) { + r_tmp = RegStorage::Solo64(TargetReg(kArg1).GetReg()); + } else { + r_tmp = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)); + } } + LoadValueDirectWideFixed(arg1, r_tmp); } - LoadValueDirectWideFixed(arg1, r_tmp); } } ClobberCallerSave(); @@ -381,16 +404,16 @@ void Mir2Lir::CopyToArgumentRegs(RegStorage arg0, RegStorage arg1) { 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 @@ template void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset 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(r_tgt, helper_offset, safepoint_pc); } @@ -449,13 +472,13 @@ void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset(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 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset(arg0.wide), 0U); - LoadValueDirectFixed(arg0, TargetReg(kArg0)); - DCHECK_EQ(static_cast(arg1.wide), 0U); - LoadValueDirectFixed(arg1, TargetReg(kArg1)); - DCHECK_EQ(static_cast(arg1.wide), 0U); - LoadValueDirectFixed(arg2, TargetReg(kArg2)); + LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0)); + LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1)); + LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -502,13 +522,13 @@ void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) { */ 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 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, 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 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, 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 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, 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 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, 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 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, 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 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, // 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 bfb77fc22..1cddeb977 100644 --- a/compiler/dex/quick/gen_loadstore.cc +++ b/compiler/dex/quick/gen_loadstore.cc @@ -192,7 +192,7 @@ void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) { 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 @@ void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) { } } 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 9912101eb..9a62255f5 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -253,6 +253,19 @@ inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(RegStorage reg) { 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 5d68187d8..984e8ea5f 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -1267,4 +1267,55 @@ LIR* Mir2Lir::LIRSlowPath::GenerateTargetLabel(int opcode) { 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 cb0bb80fe..c98fbca62 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 CompilationUnit; struct InlineMethod; struct MIR; struct LIR; -struct RegLocation; struct RegisterInfo; class DexFileMethodInliner; class MIRGraph; @@ -239,6 +239,9 @@ COMPILE_ASSERT(!IsLargeFrame(kSmallFrameSize, kX86_64), 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 @@ class Mir2Lir : public Backend { 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 @@ class Mir2Lir : public Backend { */ 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 81dabd448..38370ad88 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -420,24 +420,28 @@ RegStorage Mir2Lir::AllocTempWide() { 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 Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) { 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 @@ RegStorage Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) { ClobberSReg(s_reg + 1); } } + CheckRegStorage(reg, WidenessCheck::kIgnoreWide, + reg_class == kRefReg ? RefCheck::kCheckRef : RefCheck::kIgnoreRef, + FPCheck::kIgnoreFP); return reg; } @@ -996,7 +1005,7 @@ RegLocation Mir2Lir::UpdateLoc(RegLocation loc) { 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 @@ RegLocation Mir2Lir::UpdateLoc(RegLocation loc) { FreeTemp(reg); } } + CheckRegLocation(loc); } return loc; } @@ -1044,6 +1054,7 @@ RegLocation Mir2Lir::UpdateLocWide(RegLocation loc) { FreeTemp(reg); } } + CheckRegLocation(loc); } return loc; } @@ -1073,6 +1084,7 @@ RegLocation Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) { MarkWide(loc.reg); MarkLive(loc); } + CheckRegLocation(loc); return loc; } @@ -1086,10 +1098,16 @@ RegLocation Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) { 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 @@ RegLocation Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) { 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 @@ RegLocation Mir2Lir::GetReturnWide(RegisterClass reg_class) { Clobber(res.reg); LockTemp(res.reg); MarkWide(res.reg); + CheckRegLocation(res); return res; } @@ -1354,6 +1376,7 @@ RegLocation Mir2Lir::GetReturn(RegisterClass reg_class) { } 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 000000000..38f59dac5 --- /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_ -- 2.11.0