Re-factor Quick ABI support
Now every architecture must provide a mapper between
VRs parameters and physical registers. Additionally as
a helper function architecture can provide a bulk copy
helper for GenDalvikArgs utility.
All other things becomes a common code stuff:
GetArgMappingToPhysicalReg, GenDalvikArgsNoRange,
GenDalvikArgsRange, FlushIns.
Mapper now uses shorty representation of input
parameters. This is required due to location are not
enough to detect the type of parameter (fp or core).
For the details
see https://android-review.googlesource.com/#/c/113936/.
Change-Id: Ie762b921e0acaa936518ee6b63c9a9d25f83e434
Signed-off-by: Serguei Katkov <serguei.i.katkov@intel.com>
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index e8d0c32..c3b19a3 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -26,16 +26,6 @@
class ArmMir2Lir FINAL : public Mir2Lir {
protected:
- // TODO: Consolidate hard float target support.
- // InToRegStorageMapper and InToRegStorageMapping can be shared with all backends.
- // Base class used to get RegStorage for next argument.
- class InToRegStorageMapper {
- public:
- virtual RegStorage GetNextReg(bool is_double_or_float, bool is_wide) = 0;
- virtual ~InToRegStorageMapper() {
- }
- };
-
// Inherited class for ARM backend.
class InToRegStorageArmMapper FINAL : public InToRegStorageMapper {
public:
@@ -43,45 +33,25 @@
: cur_core_reg_(0), cur_fp_reg_(0), cur_fp_double_reg_(0) {
}
- virtual ~InToRegStorageArmMapper() {
- }
+ RegStorage GetNextReg(ShortyArg arg) OVERRIDE;
- RegStorage GetNextReg(bool is_double_or_float, bool is_wide) OVERRIDE;
+ virtual void Reset() OVERRIDE {
+ cur_core_reg_ = 0;
+ cur_fp_reg_ = 0;
+ cur_fp_double_reg_ = 0;
+ }
private:
- uint32_t cur_core_reg_;
- uint32_t cur_fp_reg_;
- uint32_t cur_fp_double_reg_;
+ size_t cur_core_reg_;
+ size_t cur_fp_reg_;
+ size_t cur_fp_double_reg_;
};
- // Class to map argument to RegStorage. The mapping object is initialized by a mapper.
- class InToRegStorageMapping FINAL {
- public:
- InToRegStorageMapping()
- : max_mapped_in_(0), is_there_stack_mapped_(false), initialized_(false) {
- }
-
- int GetMaxMappedIn() const {
- return max_mapped_in_;
- }
-
- bool IsThereStackMapped() const {
- return is_there_stack_mapped_;
- }
-
- bool IsInitialized() const {
- return initialized_;
- }
-
- void Initialize(RegLocation* arg_locs, int count, InToRegStorageMapper* mapper);
- RegStorage Get(int in_position) const;
-
- private:
- std::map<int, RegStorage> mapping_;
- int max_mapped_in_;
- bool is_there_stack_mapped_;
- bool initialized_;
- };
+ InToRegStorageArmMapper in_to_reg_storage_arm_mapper_;
+ InToRegStorageMapper* GetResetedInToRegStorageMapper() OVERRIDE {
+ in_to_reg_storage_arm_mapper_.Reset();
+ return &in_to_reg_storage_arm_mapper_;
+ }
public:
ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
@@ -127,7 +97,6 @@
}
}
- RegStorage GetArgMappingToPhysicalReg(int arg_num) OVERRIDE;
RegLocation GetReturnAlt() OVERRIDE;
RegLocation GetReturnWideAlt() OVERRIDE;
RegLocation LocCReturn() OVERRIDE;
@@ -289,19 +258,6 @@
LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
size_t GetInstructionOffset(LIR* lir);
- int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
- NextCallInsn next_call_insn,
- const MethodReference& target_method,
- uint32_t vtable_idx,
- uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
- bool skip_this) OVERRIDE;
- int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
- NextCallInsn next_call_insn,
- const MethodReference& target_method,
- uint32_t vtable_idx,
- uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
- bool skip_this) OVERRIDE;
-
private:
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
void GenMulLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
@@ -360,7 +316,7 @@
RegStorage::FloatSolo32(reg_num * 2 + 1));
}
- InToRegStorageMapping in_to_reg_storage_mapping_;
+ int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE;
};
} // namespace art
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 0e8f645..7190a49 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -896,7 +896,7 @@
Mir2Lir::InstallLiteralPools();
}
-RegStorage ArmMir2Lir::InToRegStorageArmMapper::GetNextReg(bool is_double_or_float, bool is_wide) {
+RegStorage ArmMir2Lir::InToRegStorageArmMapper::GetNextReg(ShortyArg arg) {
const RegStorage coreArgMappingToPhysicalReg[] =
{rs_r1, rs_r2, rs_r3};
const int coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
@@ -906,28 +906,18 @@
constexpr uint32_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
static_assert(fpArgMappingToPhysicalRegSize % 2 == 0, "Number of FP Arg regs is not even");
- if (kArm32QuickCodeUseSoftFloat) {
- is_double_or_float = false; // Regard double as long, float as int.
- is_wide = false; // Map long separately.
- }
-
RegStorage result = RegStorage::InvalidReg();
- if (is_double_or_float) {
- // TODO: Remove "cur_fp_double_reg_ % 2 != 0" when we return double as double.
- if (is_wide || cur_fp_double_reg_ % 2 != 0) {
+ // Regard double as long, float as int for kArm32QuickCodeUseSoftFloat.
+ if (arg.IsFP() && !kArm32QuickCodeUseSoftFloat) {
+ if (arg.IsWide()) {
cur_fp_double_reg_ = std::max(cur_fp_double_reg_, RoundUp(cur_fp_reg_, 2));
if (cur_fp_double_reg_ < fpArgMappingToPhysicalRegSize) {
- // TODO: Replace by following code in the branch when FlushIns() support 64-bit registers.
- // result = RegStorage::MakeRegPair(fpArgMappingToPhysicalReg[cur_fp_double_reg_],
- // fpArgMappingToPhysicalReg[cur_fp_double_reg_ + 1]);
- // result = As64BitFloatReg(result);
- // cur_fp_double_reg_ += 2;
- result = fpArgMappingToPhysicalReg[cur_fp_double_reg_];
- cur_fp_double_reg_++;
+ result = RegStorage::MakeRegPair(fpArgMappingToPhysicalReg[cur_fp_double_reg_],
+ fpArgMappingToPhysicalReg[cur_fp_double_reg_ + 1]);
+ result = As64BitFloatReg(result);
+ cur_fp_double_reg_ += 2;
}
} else {
- // TODO: Remove the check when we return double as double.
- DCHECK_EQ(cur_fp_double_reg_ % 2, 0U);
if (cur_fp_reg_ % 2 == 0) {
cur_fp_reg_ = std::max(cur_fp_double_reg_, cur_fp_reg_);
}
@@ -939,270 +929,23 @@
} else {
if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
result = coreArgMappingToPhysicalReg[cur_core_reg_++];
- // TODO: Enable following code when FlushIns() support 64-bit registers.
- // if (is_wide && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
- // result = RegStorage::MakeRegPair(result, coreArgMappingToPhysicalReg[cur_core_reg_++]);
- // }
+ if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+ result = RegStorage::MakeRegPair(result, coreArgMappingToPhysicalReg[cur_core_reg_++]);
+ }
}
}
return result;
}
-RegStorage ArmMir2Lir::InToRegStorageMapping::Get(int in_position) const {
- DCHECK(IsInitialized());
- auto res = mapping_.find(in_position);
- return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
-}
-
-void ArmMir2Lir::InToRegStorageMapping::Initialize(RegLocation* arg_locs, int count,
- InToRegStorageMapper* mapper) {
- DCHECK(mapper != nullptr);
- max_mapped_in_ = -1;
- is_there_stack_mapped_ = false;
- for (int in_position = 0; in_position < count; in_position++) {
- RegStorage reg = mapper->GetNextReg(arg_locs[in_position].fp,
- arg_locs[in_position].wide);
- if (reg.Valid()) {
- mapping_[in_position] = reg;
- // TODO: Enable the following code when FlushIns() support 64-bit argument registers.
- // if (arg_locs[in_position].wide) {
- // if (reg.Is32Bit()) {
- // // As it is a split long, the hi-part is on stack.
- // is_there_stack_mapped_ = true;
- // }
- // // We covered 2 v-registers, so skip the next one
- // in_position++;
- // }
- max_mapped_in_ = std::max(max_mapped_in_, in_position);
- } else {
- is_there_stack_mapped_ = true;
- }
- }
- initialized_ = true;
-}
-
-// TODO: Should be able to return long, double registers.
-// Need check some common code as it will break some assumption.
-RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
- if (!in_to_reg_storage_mapping_.IsInitialized()) {
- int start_vreg = mir_graph_->GetFirstInVR();
- RegLocation* arg_locs = &mir_graph_->reg_location_[start_vreg];
-
- InToRegStorageArmMapper mapper;
- in_to_reg_storage_mapping_.Initialize(arg_locs, mir_graph_->GetNumOfInVRs(), &mapper);
- }
- return in_to_reg_storage_mapping_.Get(arg_num);
-}
-
-int ArmMir2Lir::GenDalvikArgsNoRange(CallInfo* info,
- int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
- const MethodReference& target_method,
- uint32_t vtable_idx, uintptr_t direct_code,
- uintptr_t direct_method, InvokeType type, bool skip_this) {
+int ArmMir2Lir::GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) {
if (kArm32QuickCodeUseSoftFloat) {
- return Mir2Lir::GenDalvikArgsNoRange(info, call_state, pcrLabel, next_call_insn, target_method,
- vtable_idx, direct_code, direct_method, type, skip_this);
- } else {
- return GenDalvikArgsRange(info, call_state, pcrLabel, next_call_insn, target_method, vtable_idx,
- direct_code, direct_method, type, skip_this);
+ return Mir2Lir::GenDalvikArgsBulkCopy(info, first, count);
}
-}
-
-int ArmMir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
- LIR** pcrLabel, NextCallInsn next_call_insn,
- const MethodReference& target_method,
- uint32_t vtable_idx, uintptr_t direct_code,
- uintptr_t direct_method, InvokeType type, bool skip_this) {
- if (kArm32QuickCodeUseSoftFloat) {
- return Mir2Lir::GenDalvikArgsRange(info, call_state, pcrLabel, next_call_insn, target_method,
- vtable_idx, direct_code, direct_method, type, skip_this);
- }
-
- // TODO: Rework the implementation when argument register can be long or double.
-
- /* If no arguments, just return */
- if (info->num_arg_words == 0) {
- return call_state;
- }
-
- const int start_index = skip_this ? 1 : 0;
-
- InToRegStorageArmMapper mapper;
- InToRegStorageMapping in_to_reg_storage_mapping;
- in_to_reg_storage_mapping.Initialize(info->args, info->num_arg_words, &mapper);
- const int last_mapped_in = in_to_reg_storage_mapping.GetMaxMappedIn();
- int regs_left_to_pass_via_stack = info->num_arg_words - (last_mapped_in + 1);
-
- // First of all, check whether it makes sense to use bulk copying.
- // Bulk copying is done only for the range case.
- // TODO: make a constant instead of 2
- if (info->is_range && regs_left_to_pass_via_stack >= 2) {
- // Scan the rest of the args - if in phys_reg flush to memory
- for (int next_arg = last_mapped_in + 1; next_arg < info->num_arg_words;) {
- RegLocation loc = info->args[next_arg];
- if (loc.wide) {
- // TODO: Only flush hi-part.
- if (loc.high_word) {
- loc = info->args[--next_arg];
- }
- loc = UpdateLocWide(loc);
- if (loc.location == kLocPhysReg) {
- ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
- StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
- }
- next_arg += 2;
- } else {
- loc = UpdateLoc(loc);
- if (loc.location == kLocPhysReg) {
- ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
- if (loc.ref) {
- StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile);
- } else {
- StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32,
- kNotVolatile);
- }
- }
- next_arg++;
- }
- }
-
- // The rest can be copied together
- int start_offset = SRegOffset(info->args[last_mapped_in + 1].s_reg_low);
- int outs_offset = StackVisitor::GetOutVROffset(last_mapped_in + 1,
- cu_->instruction_set);
-
- int current_src_offset = start_offset;
- int current_dest_offset = outs_offset;
-
- // Only davik regs are accessed in this loop; no next_call_insn() calls.
- ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
- while (regs_left_to_pass_via_stack > 0) {
- /*
- * TODO: Improve by adding block copy for large number of arguments. This
- * should be done, if possible, as a target-depending helper. For now, just
- * copy a Dalvik vreg at a time.
- */
- // Moving 32-bits via general purpose register.
- size_t bytes_to_move = sizeof(uint32_t);
-
- // Instead of allocating a new temp, simply reuse one of the registers being used
- // for argument passing.
- RegStorage temp = TargetReg(kArg3, kNotWide);
-
- // Now load the argument VR and store to the outs.
- Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
- Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
-
- current_src_offset += bytes_to_move;
- current_dest_offset += bytes_to_move;
- regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
- }
- DCHECK_EQ(regs_left_to_pass_via_stack, 0);
- }
-
- // Now handle rest not registers if they are
- if (in_to_reg_storage_mapping.IsThereStackMapped()) {
- RegStorage regWide = TargetReg(kArg2, kWide);
- for (int i = start_index; i <= last_mapped_in + regs_left_to_pass_via_stack; i++) {
- RegLocation rl_arg = info->args[i];
- rl_arg = UpdateRawLoc(rl_arg);
- RegStorage reg = in_to_reg_storage_mapping.Get(i);
- // TODO: Only pass split wide hi-part via stack.
- if (!reg.Valid() || rl_arg.wide) {
- int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
-
- {
- ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
- if (rl_arg.wide) {
- if (rl_arg.location == kLocPhysReg) {
- StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
- } else {
- LoadValueDirectWideFixed(rl_arg, regWide);
- StoreBaseDisp(TargetPtrReg(kSp), out_offset, regWide, k64, kNotVolatile);
- }
- } else {
- if (rl_arg.location == kLocPhysReg) {
- if (rl_arg.ref) {
- StoreRefDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, kNotVolatile);
- } else {
- StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
- }
- } else {
- if (rl_arg.ref) {
- RegStorage regSingle = TargetReg(kArg2, kRef);
- LoadValueDirectFixed(rl_arg, regSingle);
- StoreRefDisp(TargetPtrReg(kSp), out_offset, regSingle, kNotVolatile);
- } else {
- RegStorage regSingle = TargetReg(kArg2, kNotWide);
- LoadValueDirectFixed(rl_arg, regSingle);
- StoreBaseDisp(TargetPtrReg(kSp), out_offset, regSingle, k32, kNotVolatile);
- }
- }
- }
- }
-
- call_state = next_call_insn(cu_, info, call_state, target_method,
- vtable_idx, direct_code, direct_method, type);
- }
- if (rl_arg.wide) {
- i++;
- }
- }
- }
-
- // Finish with mapped registers
- for (int i = start_index; i <= last_mapped_in; i++) {
- RegLocation rl_arg = info->args[i];
- rl_arg = UpdateRawLoc(rl_arg);
- RegStorage reg = in_to_reg_storage_mapping.Get(i);
- if (reg.Valid()) {
- if (reg.Is64Bit()) {
- LoadValueDirectWideFixed(rl_arg, reg);
- } else {
- // TODO: Only split long should be the case we need to care about.
- if (rl_arg.wide) {
- ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
- int high_word = rl_arg.high_word ? 1 : 0;
- rl_arg = high_word ? info->args[i - 1] : rl_arg;
- if (rl_arg.location == kLocPhysReg) {
- RegStorage rs_arg = rl_arg.reg;
- if (rs_arg.IsDouble() && rs_arg.Is64BitSolo()) {
- rs_arg = As64BitFloatRegPair(rs_arg);
- }
- RegStorage rs_arg_low = rs_arg.GetLow();
- RegStorage rs_arg_high = rs_arg.GetHigh();
- OpRegCopy(reg, high_word ? rs_arg_high : rs_arg_low);
- } else {
- Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low + high_word), reg);
- }
- } else {
- LoadValueDirectFixed(rl_arg, reg);
- }
- }
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- }
- if (reg.Is64Bit()) {
- i++;
- }
- }
-
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- if (pcrLabel) {
- if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
- *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
- } else {
- *pcrLabel = nullptr;
- // In lieu of generating a check for kArg1 being null, we need to
- // perform a load when doing implicit checks.
- RegStorage tmp = AllocTemp();
- Load32Disp(TargetReg(kArg1, kRef), 0, tmp);
- MarkPossibleNullPointerException(info->opt_flags);
- FreeTemp(tmp);
- }
- }
- return call_state;
+ /*
+ * TODO: Improve by adding block copy for large number of arguments. For now, just
+ * copy a Dalvik vreg at a time.
+ */
+ return count;
}
} // namespace art