ARM: Use hardfp calling convention between java to java call.
This patch default to use hardfp calling convention. Softfp can be enabled
by setting kArm32QuickCodeUseSoftFloat to true.
We get about -1 ~ +5% performance improvement with different benchmark
tests. Hopefully, we should be able to get more performance by address the left
TODOs, as some part of the code takes the original assumption which is not
optimal.
DONE:
1. Interpreter to quick code
2. Quick code to interpreter
3. Transition assembly and callee-saves
4. Trampoline(generic jni, resolution, invoke with access check and etc.)
5. Pass fp arg reg following aapcs(gpr and stack do not follow aapcs)
6. Quick helper assembly routines to handle ABI differences
7. Quick code method entry
8. Quick code method invocation
9. JNI compiler
TODO:
10. Rework ArgMap, FlushIn, GenDalvikArgs and affected common code.
11. Rework CallRuntimeHelperXXX().
Change-Id: I9965d8a007f4829f2560b63bcbbde271bdcf6ec2
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 6fd29f2..442c4fc 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -25,6 +25,64 @@
namespace art {
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:
+ InToRegStorageArmMapper()
+ : cur_core_reg_(0), cur_fp_reg_(0), cur_fp_double_reg_(0) {
+ }
+
+ virtual ~InToRegStorageArmMapper() {
+ }
+
+ RegStorage GetNextReg(bool is_double_or_float, bool is_wide) OVERRIDE;
+
+ private:
+ uint32_t cur_core_reg_;
+ uint32_t cur_fp_reg_;
+ uint32_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_;
+ };
+
public:
ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
@@ -47,15 +105,30 @@
void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
// Required for target - register utilities.
- RegStorage TargetReg(SpecialTargetRegister reg);
- RegStorage GetArgMappingToPhysicalReg(int arg_num);
- RegLocation GetReturnAlt();
- RegLocation GetReturnWideAlt();
- RegLocation LocCReturn();
- RegLocation LocCReturnRef();
- RegLocation LocCReturnDouble();
- RegLocation LocCReturnFloat();
- RegLocation LocCReturnWide();
+ RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
+ RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) OVERRIDE {
+ if (wide_kind == kWide) {
+ DCHECK((kArg0 <= reg && reg < kArg3) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
+ RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg),
+ TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
+ if (ret_reg.IsFloat()) {
+ // Regard double as double, be consistent with register allocation.
+ ret_reg = As64BitFloatReg(ret_reg);
+ }
+ return ret_reg;
+ } else {
+ return TargetReg(reg);
+ }
+ }
+
+ RegStorage GetArgMappingToPhysicalReg(int arg_num) OVERRIDE;
+ RegLocation GetReturnAlt() OVERRIDE;
+ RegLocation GetReturnWideAlt() OVERRIDE;
+ RegLocation LocCReturn() OVERRIDE;
+ RegLocation LocCReturnRef() OVERRIDE;
+ RegLocation LocCReturnDouble() OVERRIDE;
+ RegLocation LocCReturnFloat() OVERRIDE;
+ RegLocation LocCReturnWide() OVERRIDE;
ResourceMask GetRegMaskCommon(const RegStorage& reg) const OVERRIDE;
void AdjustSpillMask();
void ClobberCallerSave();
@@ -210,6 +283,19 @@
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,
@@ -226,10 +312,10 @@
RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
bool is_div, int flags) OVERRIDE;
RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) OVERRIDE;
- typedef struct {
+ struct EasyMultiplyOp {
OpKind op;
uint32_t shift;
- } EasyMultiplyOp;
+ };
bool GetEasyMultiplyOp(int lit, EasyMultiplyOp* op);
bool GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops);
void GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops);
@@ -239,6 +325,36 @@
static constexpr ResourceMask EncodeArmRegFpcsList(int reg_list);
ArenaVector<LIR*> call_method_insns_;
+
+ /**
+ * @brief Given float register pair, returns Solo64 float register.
+ * @param reg #RegStorage containing a float register pair (e.g. @c s2 and @c s3).
+ * @return A Solo64 float mapping to the register pair (e.g. @c d1).
+ */
+ static RegStorage As64BitFloatReg(RegStorage reg) {
+ DCHECK(reg.IsFloat());
+
+ RegStorage low = reg.GetLow();
+ RegStorage high = reg.GetHigh();
+ DCHECK((low.GetRegNum() % 2 == 0) && (low.GetRegNum() + 1 == high.GetRegNum()));
+
+ return RegStorage::FloatSolo64(low.GetRegNum() / 2);
+ }
+
+ /**
+ * @brief Given Solo64 float register, returns float register pair.
+ * @param reg #RegStorage containing a Solo64 float register (e.g. @c d1).
+ * @return A float register pair mapping to the Solo64 float pair (e.g. @c s2 and s3).
+ */
+ static RegStorage As64BitFloatRegPair(RegStorage reg) {
+ DCHECK(reg.IsDouble() && reg.Is64BitSolo());
+
+ int reg_num = reg.GetRegNum();
+ return RegStorage::MakeRegPair(RegStorage::FloatSolo32(reg_num * 2),
+ RegStorage::FloatSolo32(reg_num * 2 + 1));
+ }
+
+ InToRegStorageMapping in_to_reg_storage_mapping_;
};
} // namespace art