Merge "Add x86 inlined abs method for float/double"
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