ART: inline Math.Max/Min (float and double)
This implements the inlined version of Math.Max/Min intrinsics.
Change-Id: I2db8fa7603db3cdf01016ec26811a96f91b1e6ed
Signed-off-by: Alexei Zavjalov <alexei.zavjalov@intel.com>
Signed-off-by: Shou, Yixin <yixin.shou@intel.com>
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index fc65deb..62053fd 100755
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -705,4 +705,77 @@
}
}
+bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
+ if (is_double) {
+ RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg);
+ RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg);
+ RegLocation rl_dest = InlineTargetWide(info);
+ RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true);
+
+ // Avoid src2 corruption by OpRegCopyWide.
+ if (rl_result.reg == rl_src2.reg) {
+ std::swap(rl_src2.reg, rl_src1.reg);
+ }
+
+ OpRegCopyWide(rl_result.reg, rl_src1.reg);
+ NewLIR2(kX86UcomisdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
+ // If either arg is NaN, return NaN.
+ LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
+ // Min/Max branches.
+ LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
+ LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
+ // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
+ NewLIR2((is_min) ? kX86OrpdRR : kX86AndpdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
+ LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
+ // Handle NaN.
+ branch_nan->target = NewLIR0(kPseudoTargetLabel);
+ LoadConstantWide(rl_result.reg, INT64_C(0x7ff8000000000000));
+ LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
+ // Handle Min/Max. Copy greater/lesser value from src2.
+ branch_cond1->target = NewLIR0(kPseudoTargetLabel);
+ OpRegCopyWide(rl_result.reg, rl_src2.reg);
+ // Right operand is already in result reg.
+ branch_cond2->target = NewLIR0(kPseudoTargetLabel);
+ // Exit.
+ branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
+ branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
+ StoreValueWide(rl_dest, rl_result);
+ } else {
+ RegLocation rl_src1 = LoadValue(info->args[0], kFPReg);
+ RegLocation rl_src2 = LoadValue(info->args[1], kFPReg);
+ RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
+
+ // Avoid src2 corruption by OpRegCopyWide.
+ if (rl_result.reg == rl_src2.reg) {
+ std::swap(rl_src2.reg, rl_src1.reg);
+ }
+
+ OpRegCopy(rl_result.reg, rl_src1.reg);
+ NewLIR2(kX86UcomissRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
+ // If either arg is NaN, return NaN.
+ LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
+ // Min/Max branches.
+ LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
+ LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
+ // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
+ NewLIR2((is_min) ? kX86OrpsRR : kX86AndpsRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
+ LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
+ // Handle NaN.
+ branch_nan->target = NewLIR0(kPseudoTargetLabel);
+ LoadConstantNoClobber(rl_result.reg, 0x7fc00000);
+ LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
+ // Handle Min/Max. Copy greater/lesser value from src2.
+ branch_cond1->target = NewLIR0(kPseudoTargetLabel);
+ OpRegCopy(rl_result.reg, rl_src2.reg);
+ // Right operand is already in result reg.
+ branch_cond2->target = NewLIR0(kPseudoTargetLabel);
+ // Exit.
+ branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
+ branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
+ StoreValue(rl_dest, rl_result);
+ }
+ return true;
+}
+
} // namespace art