Add x86 inlined abs method for float/double
Add the optimized implementation of inlined abs method for
float/double for X86 side.
Change-Id: I2f367542f321d88a976129f9f7156fd3c2965c8a
Signed-off-by: Yixin Shou <yixin.shou@intel.com>
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 6397208..3f9379c 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -292,10 +292,14 @@
return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
}
-bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
+bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) {
ReaderMutexLock mu(Thread::Current(), lock_);
auto it = inline_methods_.find(method_index);
- return it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0;
+ bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0);
+ if (res && intrinsic != nullptr) {
+ *intrinsic = it->second;
+ }
+ return res;
}
bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index c03f89c..70693c2 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -67,7 +67,7 @@
/**
* Check whether a particular method index corresponds to an intrinsic function.
*/
- bool IsIntrinsic(uint32_t method_index) LOCKS_EXCLUDED(lock_);
+ bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) LOCKS_EXCLUDED(lock_);
/**
* Generate code for an intrinsic function invocation.
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 9155677..ca65432 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -953,8 +953,8 @@
bool GenInlinedReverseBytes(CallInfo* info, OpSize size);
bool GenInlinedAbsInt(CallInfo* info);
virtual bool GenInlinedAbsLong(CallInfo* info);
- bool GenInlinedAbsFloat(CallInfo* info);
- bool GenInlinedAbsDouble(CallInfo* info);
+ virtual bool GenInlinedAbsFloat(CallInfo* info);
+ virtual bool GenInlinedAbsDouble(CallInfo* info);
bool GenInlinedFloatCvt(CallInfo* info);
bool GenInlinedDoubleCvt(CallInfo* info);
virtual bool GenInlinedIndexOf(CallInfo* info, bool zero_based);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index d874aaa..d482e58 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -155,6 +155,8 @@
bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
bool GenInlinedSqrt(CallInfo* info);
+ bool GenInlinedAbsFloat(CallInfo* info) OVERRIDE;
+ bool GenInlinedAbsDouble(CallInfo* info) OVERRIDE;
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNotLong(RegLocation rl_dest, RegLocation rl_src);
@@ -796,6 +798,14 @@
*/
void AnalyzeDoubleUse(RegLocation rl_use);
+ /*
+ * @brief Analyze one invoke-static MIR instruction
+ * @param opcode MIR instruction opcode.
+ * @param bb Basic block containing instruction.
+ * @param mir Instruction to analyze.
+ */
+ void AnalyzeInvokeStatic(int opcode, BasicBlock * bb, MIR *mir);
+
bool Gen64Bit() const { return gen64bit_; }
// Information derived from analysis of MIR
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 458f9c6..20bb7bf 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -587,5 +587,107 @@
return true;
}
+bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
+ // Get the argument
+ RegLocation rl_src = info->args[0];
+
+ // Get the inlined intrinsic target virtual register
+ RegLocation rl_dest = InlineTarget(info);
+
+ // Get the virtual register number
+ DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
+ int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+
+ // if argument is the same as inlined intrinsic target
+ if (v_src_reg == v_dst_reg) {
+ rl_src = UpdateLoc(rl_src);
+
+ // if argument is in the physical register
+ if (rl_src.location == kLocPhysReg) {
+ rl_src = LoadValue(rl_src, kCoreReg);
+ OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff);
+ StoreValue(rl_dest, rl_src);
+ return true;
+ }
+ // the argument is in memory
+ DCHECK((rl_src.location == kLocDalvikFrame) ||
+ (rl_src.location == kLocCompilerTemp));
+
+ // Operate directly into memory.
+ int displacement = SRegOffset(rl_dest.s_reg_low);
+ ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+ LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement, 0x7fffffff);
+ AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
+ AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
+ return true;
+ } else {
+ rl_src = LoadValue(rl_src, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
+ StoreValue(rl_dest, rl_result);
+ return true;
+ }
+}
+
+bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
+ RegLocation rl_src = info->args[0];
+ RegLocation rl_dest = InlineTargetWide(info);
+ DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
+ int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+ rl_src = UpdateLocWide(rl_src);
+
+ // if argument is in the physical XMM register
+ if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) {
+ RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
+ if (rl_result.reg != rl_src.reg) {
+ LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
+ NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
+ } else {
+ RegStorage sign_mask = AllocTempDouble();
+ LoadConstantWide(sign_mask, 0x7fffffffffffffff);
+ NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg());
+ FreeTemp(sign_mask);
+ }
+ StoreValueWide(rl_dest, rl_result);
+ return true;
+ } else if (v_src_reg == v_dst_reg) {
+ // if argument is the same as inlined intrinsic target
+ // if argument is in the physical register
+ if (rl_src.location == kLocPhysReg) {
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff);
+ StoreValueWide(rl_dest, rl_src);
+ return true;
+ }
+ // the argument is in memory
+ DCHECK((rl_src.location == kLocDalvikFrame) ||
+ (rl_src.location == kLocCompilerTemp));
+
+ // Operate directly into memory.
+ int displacement = SRegOffset(rl_dest.s_reg_low);
+ ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+ LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
+ return true;
+ } else {
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ OpRegCopyWide(rl_result.reg, rl_src.reg);
+ OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff);
+ StoreValueWide(rl_dest, rl_result);
+ return true;
+ }
+}
} // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index b93e3e8..46e877f 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -18,6 +18,8 @@
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/dataflow_iterator-inl.h"
#include "x86_lir.h"
+#include "dex/quick/dex_file_method_inliner.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
namespace art {
@@ -953,6 +955,9 @@
case Instruction::PACKED_SWITCH:
store_method_addr_ = true;
break;
+ case Instruction::INVOKE_STATIC:
+ AnalyzeInvokeStatic(opcode, bb, mir);
+ break;
default:
// Other instructions are not interesting yet.
break;
@@ -1020,4 +1025,22 @@
DCHECK(CheckCorePoolSanity());
return loc;
}
+
+void X86Mir2Lir::AnalyzeInvokeStatic(int opcode, BasicBlock * bb, MIR *mir) {
+ uint32_t index = mir->dalvikInsn.vB;
+ if (!(mir->optimization_flags & MIR_INLINED)) {
+ DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
+ InlineMethod method;
+ if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
+ ->IsIntrinsic(index, &method)) {
+ switch (method.opcode) {
+ case kIntrinsicAbsDouble:
+ store_method_addr_ = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
} // namespace art