8212043: Add floating-point Math.min/max intrinsics
authorpli
Tue, 18 Dec 2018 16:50:35 +0000
changeset 53041 f15af1e2c683
parent 53040 6aeb6a23fb83
child 53042 56fbb14251ca
8212043: Add floating-point Math.min/max intrinsics Summary: Floating-point Math.min() and Math.max() intrinsics are enabled on AArch64 platform Reviewed-by: adinn, aph
src/hotspot/cpu/aarch64/aarch64.ad
src/hotspot/cpu/aarch64/assembler_aarch64.hpp
src/hotspot/share/adlc/formssel.cpp
src/hotspot/share/classfile/vmSymbols.cpp
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/opto/addnode.hpp
src/hotspot/share/opto/c2compiler.cpp
src/hotspot/share/opto/classes.hpp
src/hotspot/share/opto/library_call.cpp
src/hotspot/share/opto/type.cpp
src/hotspot/share/opto/type.hpp
src/hotspot/share/runtime/vmStructs.cpp
src/java.base/share/classes/java/lang/Math.java
src/java.base/share/classes/java/lang/StrictMath.java
--- a/src/hotspot/cpu/aarch64/aarch64.ad	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/cpu/aarch64/aarch64.ad	Tue Dec 18 16:50:35 2018 +0000
@@ -12601,6 +12601,63 @@
 %}
 
 
+// Math.max(FF)F
+instruct maxF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
+  match(Set dst (MaxF src1 src2));
+
+  format %{ "fmaxs   $dst, $src1, $src2" %}
+  ins_encode %{
+    __ fmaxs(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg),
+             as_FloatRegister($src2$$reg));
+  %}
+
+  ins_pipe(fp_dop_reg_reg_s);
+%}
+
+// Math.min(FF)F
+instruct minF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
+  match(Set dst (MinF src1 src2));
+
+  format %{ "fmins   $dst, $src1, $src2" %}
+  ins_encode %{
+    __ fmins(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg),
+             as_FloatRegister($src2$$reg));
+  %}
+
+  ins_pipe(fp_dop_reg_reg_s);
+%}
+
+// Math.max(DD)D
+instruct maxD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
+  match(Set dst (MaxD src1 src2));
+
+  format %{ "fmaxd   $dst, $src1, $src2" %}
+  ins_encode %{
+    __ fmaxd(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg),
+             as_FloatRegister($src2$$reg));
+  %}
+
+  ins_pipe(fp_dop_reg_reg_d);
+%}
+
+// Math.min(DD)D
+instruct minD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{
+  match(Set dst (MinD src1 src2));
+
+  format %{ "fmind   $dst, $src1, $src2" %}
+  ins_encode %{
+    __ fmind(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg),
+             as_FloatRegister($src2$$reg));
+  %}
+
+  ins_pipe(fp_dop_reg_reg_d);
+%}
+
+
 instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{
   match(Set dst (DivF src1  src2));
 
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp	Tue Dec 18 16:50:35 2018 +0000
@@ -1826,12 +1826,16 @@
   INSN(fdivs, 0b000, 0b00, 0b0001);
   INSN(fadds, 0b000, 0b00, 0b0010);
   INSN(fsubs, 0b000, 0b00, 0b0011);
+  INSN(fmaxs, 0b000, 0b00, 0b0100);
+  INSN(fmins, 0b000, 0b00, 0b0101);
   INSN(fnmuls, 0b000, 0b00, 0b1000);
 
   INSN(fmuld, 0b000, 0b01, 0b0000);
   INSN(fdivd, 0b000, 0b01, 0b0001);
   INSN(faddd, 0b000, 0b01, 0b0010);
   INSN(fsubd, 0b000, 0b01, 0b0011);
+  INSN(fmaxd, 0b000, 0b01, 0b0100);
+  INSN(fmind, 0b000, 0b01, 0b0101);
   INSN(fnmuld, 0b000, 0b01, 0b1000);
 
 #undef INSN
--- a/src/hotspot/share/adlc/formssel.cpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/adlc/formssel.cpp	Tue Dec 18 16:50:35 2018 +0000
@@ -3801,7 +3801,7 @@
     "AddVB","AddVS","AddVI","AddVL","AddVF","AddVD",
     "AndI","AndL",
     "AndV",
-    "MaxI","MinI",
+    "MaxI","MinI","MaxF","MinF","MaxD","MinD",
     "MulI","MulL","MulF","MulD",
     "MulVS","MulVI","MulVL","MulVF","MulVD",
     "OrI","OrL",
--- a/src/hotspot/share/classfile/vmSymbols.cpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/classfile/vmSymbols.cpp	Tue Dec 18 16:50:35 2018 +0000
@@ -580,6 +580,10 @@
   case vmIntrinsics::_max:
   case vmIntrinsics::_floatToIntBits:
   case vmIntrinsics::_doubleToLongBits:
+  case vmIntrinsics::_maxF:
+  case vmIntrinsics::_minF:
+  case vmIntrinsics::_maxD:
+  case vmIntrinsics::_minD:
     if (!InlineMathNatives) return true;
     break;
   case vmIntrinsics::_fmaD:
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Tue Dec 18 16:50:35 2018 +0000
@@ -748,6 +748,7 @@
   do_class(java_lang_StrictMath,          "java/lang/StrictMath")                                                       \
   do_signature(double2_double_signature,  "(DD)D")                                                                      \
   do_signature(double3_double_signature,  "(DDD)D")                                                                     \
+  do_signature(float2_float_signature,    "(FF)F")                                                                      \
   do_signature(float3_float_signature,    "(FFF)F")                                                                     \
   do_signature(int2_int_signature,        "(II)I")                                                                      \
   do_signature(long2_long_signature,      "(JJ)J")                                                                      \
@@ -794,6 +795,10 @@
   do_intrinsic(_subtractExactL,           java_lang_Math,         subtractExact_name, long2_long_signature,      F_S)   \
   do_intrinsic(_fmaD,                     java_lang_Math,         fma_name,           double3_double_signature,  F_S)   \
   do_intrinsic(_fmaF,                     java_lang_Math,         fma_name,           float3_float_signature,    F_S)   \
+  do_intrinsic(_maxF,                     java_lang_Math,         max_name,           float2_float_signature,    F_S)   \
+  do_intrinsic(_minF,                     java_lang_Math,         min_name,           float2_float_signature,    F_S)   \
+  do_intrinsic(_maxD,                     java_lang_Math,         max_name,           double2_double_signature,  F_S)   \
+  do_intrinsic(_minD,                     java_lang_Math,         min_name,           double2_double_signature,  F_S)   \
                                                                                                                         \
   do_intrinsic(_floatToRawIntBits,        java_lang_Float,        floatToRawIntBits_name,   float_int_signature, F_S)   \
    do_name(     floatToRawIntBits_name,                          "floatToRawIntBits")                                   \
--- a/src/hotspot/share/opto/addnode.hpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/opto/addnode.hpp	Tue Dec 18 16:50:35 2018 +0000
@@ -249,4 +249,52 @@
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
 };
 
+//------------------------------MaxFNode---------------------------------------
+// Maximum of 2 floats.
+class MaxFNode : public MaxNode {
+public:
+  MaxFNode(Node *in1, Node *in2) : MaxNode(in1, in2) {}
+  virtual int Opcode() const;
+  virtual const Type *add_ring(const Type*, const Type*) const { return Type::FLOAT; }
+  virtual const Type *add_id() const { return TypeF::NEG_INF; }
+  virtual const Type *bottom_type() const { return Type::FLOAT; }
+  virtual uint ideal_reg() const { return Op_RegF; }
+};
+
+//------------------------------MinFNode---------------------------------------
+// Minimum of 2 floats.
+class MinFNode : public MaxNode {
+public:
+  MinFNode(Node *in1, Node *in2) : MaxNode(in1, in2) {}
+  virtual int Opcode() const;
+  virtual const Type *add_ring(const Type*, const Type*) const { return Type::FLOAT; }
+  virtual const Type *add_id() const { return TypeF::POS_INF; }
+  virtual const Type *bottom_type() const { return Type::FLOAT; }
+  virtual uint ideal_reg() const { return Op_RegF; }
+};
+
+//------------------------------MaxDNode---------------------------------------
+// Maximum of 2 doubles.
+class MaxDNode : public MaxNode {
+public:
+  MaxDNode(Node *in1, Node *in2) : MaxNode(in1, in2) {}
+  virtual int Opcode() const;
+  virtual const Type *add_ring(const Type*, const Type*) const { return Type::DOUBLE; }
+  virtual const Type *add_id() const { return TypeD::NEG_INF; }
+  virtual const Type *bottom_type() const { return Type::DOUBLE; }
+  virtual uint ideal_reg() const { return Op_RegD; }
+};
+
+//------------------------------MinDNode---------------------------------------
+// Minimum of 2 doubles.
+class MinDNode : public MaxNode {
+public:
+  MinDNode(Node *in1, Node *in2) : MaxNode(in1, in2) {}
+  virtual int Opcode() const;
+  virtual const Type *add_ring(const Type*, const Type*) const { return Type::DOUBLE; }
+  virtual const Type *add_id() const { return TypeD::POS_INF; }
+  virtual const Type *bottom_type() const { return Type::DOUBLE; }
+  virtual uint ideal_reg() const { return Op_RegD; }
+};
+
 #endif // SHARE_VM_OPTO_ADDNODE_HPP
--- a/src/hotspot/share/opto/c2compiler.cpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/opto/c2compiler.cpp	Tue Dec 18 16:50:35 2018 +0000
@@ -440,6 +440,18 @@
   case vmIntrinsics::_isWhitespace:
     if (!Matcher::match_rule_supported(Op_Whitespace)) return false;
     break;
+  case vmIntrinsics::_maxF:
+    if (!Matcher::match_rule_supported(Op_MaxF)) return false;
+    break;
+  case vmIntrinsics::_minF:
+    if (!Matcher::match_rule_supported(Op_MinF)) return false;
+    break;
+  case vmIntrinsics::_maxD:
+    if (!Matcher::match_rule_supported(Op_MaxD)) return false;
+    break;
+  case vmIntrinsics::_minD:
+    if (!Matcher::match_rule_supported(Op_MinD)) return false;
+    break;
   case vmIntrinsics::_hashCode:
   case vmIntrinsics::_identityHashCode:
   case vmIntrinsics::_getClass:
--- a/src/hotspot/share/opto/classes.hpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/opto/classes.hpp	Tue Dec 18 16:50:35 2018 +0000
@@ -202,6 +202,8 @@
 macro(Mach)
 macro(MachProj)
 macro(MulAddS2I)
+macro(MaxD)
+macro(MaxF)
 macro(MaxI)
 macro(MemBarAcquire)
 macro(LoadFence)
@@ -214,6 +216,8 @@
 macro(MemBarVolatile)
 macro(MemBarStoreStore)
 macro(MergeMem)
+macro(MinD)
+macro(MinF)
 macro(MinI)
 macro(ModD)
 macro(ModF)
--- a/src/hotspot/share/opto/library_call.cpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/opto/library_call.cpp	Tue Dec 18 16:50:35 2018 +0000
@@ -325,6 +325,7 @@
   bool inline_vectorizedMismatch();
   bool inline_fma(vmIntrinsics::ID id);
   bool inline_character_compare(vmIntrinsics::ID id);
+  bool inline_fp_min_max(vmIntrinsics::ID id);
 
   bool inline_profileBoolean();
   bool inline_isCompileConstant();
@@ -874,6 +875,12 @@
   case vmIntrinsics::_isWhitespace:
     return inline_character_compare(intrinsic_id());
 
+  case vmIntrinsics::_maxF:
+  case vmIntrinsics::_minF:
+  case vmIntrinsics::_maxD:
+  case vmIntrinsics::_minD:
+    return inline_fp_min_max(intrinsic_id());
+
   default:
     // If you get here, it may be that someone has added a new intrinsic
     // to the list in vmSymbols.hpp without implementing it here.
@@ -6588,6 +6595,42 @@
   return true;
 }
 
+//------------------------------inline_fp_min_max------------------------------
+bool LibraryCallKit::inline_fp_min_max(vmIntrinsics::ID id) {
+  Node *a = NULL;
+  Node *b = NULL;
+  Node *n = NULL;
+  switch (id) {
+  case vmIntrinsics::_maxF:
+  case vmIntrinsics::_minF:
+    assert(callee()->signature()->size() == 2, "minF/maxF has 2 parameters of size 1 each.");
+    a = argument(0);
+    b = argument(1);
+    break;
+  case vmIntrinsics::_maxD:
+  case vmIntrinsics::_minD:
+    assert(callee()->signature()->size() == 4, "minD/maxD has 2 parameters of size 2 each.");
+    a = round_double_node(argument(0));
+    b = round_double_node(argument(2));
+    break;
+  default:
+    fatal_unexpected_iid(id);
+    break;
+  }
+  if (a->is_Con() || b->is_Con()) {
+    return false;
+  }
+  switch (id) {
+  case vmIntrinsics::_maxF:  n = new MaxFNode(a, b);  break;
+  case vmIntrinsics::_minF:  n = new MinFNode(a, b);  break;
+  case vmIntrinsics::_maxD:  n = new MaxDNode(a, b);  break;
+  case vmIntrinsics::_minD:  n = new MinDNode(a, b);  break;
+  default:  fatal_unexpected_iid(id);  break;
+  }
+  set_result(_gvn.transform(n));
+  return true;
+}
+
 bool LibraryCallKit::inline_profileBoolean() {
   Node* counts = argument(1);
   const TypeAryPtr* ary = NULL;
--- a/src/hotspot/share/opto/type.cpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/opto/type.cpp	Tue Dec 18 16:50:35 2018 +0000
@@ -416,6 +416,18 @@
 
 #define SMALLINT ((juint)3)  // a value too insignificant to consider widening
 
+static double pos_dinf() {
+  union { int64_t i; double d; } v;
+  v.i = CONST64(0x7ff0000000000000);
+  return v.d;
+}
+
+static float pos_finf() {
+  union { int32_t i; float f; } v;
+  v.i = 0x7f800000;
+  return v.f;
+}
+
 //--------------------------Initialize_shared----------------------------------
 void Type::Initialize_shared(Compile* current) {
   // This method does not need to be locked because the first system
@@ -445,9 +457,13 @@
 
   TypeF::ZERO = TypeF::make(0.0); // Float 0 (positive zero)
   TypeF::ONE  = TypeF::make(1.0); // Float 1
+  TypeF::POS_INF = TypeF::make(pos_finf());
+  TypeF::NEG_INF = TypeF::make(-pos_finf());
 
   TypeD::ZERO = TypeD::make(0.0); // Double 0 (positive zero)
   TypeD::ONE  = TypeD::make(1.0); // Double 1
+  TypeD::POS_INF = TypeD::make(pos_dinf());
+  TypeD::NEG_INF = TypeD::make(-pos_dinf());
 
   TypeInt::MINUS_1 = TypeInt::make(-1);  // -1
   TypeInt::ZERO    = TypeInt::make( 0);  //  0
@@ -1087,6 +1103,8 @@
 // Convenience common pre-built types.
 const TypeF *TypeF::ZERO;       // Floating point zero
 const TypeF *TypeF::ONE;        // Floating point one
+const TypeF *TypeF::POS_INF;    // Floating point positive infinity
+const TypeF *TypeF::NEG_INF;    // Floating point negative infinity
 
 //------------------------------make-------------------------------------------
 // Create a float constant
@@ -1195,6 +1213,8 @@
 // Convenience common pre-built types.
 const TypeD *TypeD::ZERO;       // Floating point zero
 const TypeD *TypeD::ONE;        // Floating point one
+const TypeD *TypeD::POS_INF;    // Floating point positive infinity
+const TypeD *TypeD::NEG_INF;    // Floating point negative infinity
 
 //------------------------------make-------------------------------------------
 const TypeD *TypeD::make(double d) {
--- a/src/hotspot/share/opto/type.hpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/opto/type.hpp	Tue Dec 18 16:50:35 2018 +0000
@@ -483,6 +483,8 @@
   // Convenience common pre-built types.
   static const TypeF *ZERO; // positive zero only
   static const TypeF *ONE;
+  static const TypeF *POS_INF;
+  static const TypeF *NEG_INF;
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
 #endif
@@ -510,6 +512,8 @@
   // Convenience common pre-built types.
   static const TypeD *ZERO; // positive zero only
   static const TypeD *ONE;
+  static const TypeD *POS_INF;
+  static const TypeD *NEG_INF;
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
 #endif
--- a/src/hotspot/share/runtime/vmStructs.cpp	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Tue Dec 18 16:50:35 2018 +0000
@@ -1516,6 +1516,10 @@
   declare_c2_type(MaxNode, AddNode)                                       \
   declare_c2_type(MaxINode, MaxNode)                                      \
   declare_c2_type(MinINode, MaxNode)                                      \
+  declare_c2_type(MaxFNode, MaxNode)                                      \
+  declare_c2_type(MinFNode, MaxNode)                                      \
+  declare_c2_type(MaxDNode, MaxNode)                                      \
+  declare_c2_type(MinDNode, MaxNode)                                      \
   declare_c2_type(StartNode, MultiNode)                                   \
   declare_c2_type(StartOSRNode, StartNode)                                \
   declare_c2_type(ParmNode, ProjNode)                                     \
--- a/src/java.base/share/classes/java/lang/Math.java	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/java.base/share/classes/java/lang/Math.java	Tue Dec 18 16:50:35 2018 +0000
@@ -1460,6 +1460,7 @@
      * @param   b   another argument.
      * @return  the larger of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static float max(float a, float b) {
         if (a != a)
             return a;   // a is NaN
@@ -1486,6 +1487,7 @@
      * @param   b   another argument.
      * @return  the larger of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static double max(double a, double b) {
         if (a != a)
             return a;   // a is NaN
@@ -1541,6 +1543,7 @@
      * @param   b   another argument.
      * @return  the smaller of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static float min(float a, float b) {
         if (a != a)
             return a;   // a is NaN
@@ -1567,6 +1570,7 @@
      * @param   b   another argument.
      * @return  the smaller of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static double min(double a, double b) {
         if (a != a)
             return a;   // a is NaN
--- a/src/java.base/share/classes/java/lang/StrictMath.java	Tue Dec 18 16:22:46 2018 -0500
+++ b/src/java.base/share/classes/java/lang/StrictMath.java	Tue Dec 18 16:50:35 2018 +0000
@@ -1154,6 +1154,7 @@
      * @param   b   another argument.
      * @return  the larger of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static float max(float a, float b) {
         return Math.max(a, b);
     }
@@ -1172,6 +1173,7 @@
      * @param   b   another argument.
      * @return  the larger of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static double max(double a, double b) {
         return Math.max(a, b);
     }
@@ -1219,6 +1221,7 @@
      * @param   b   another argument.
      * @return  the smaller of {@code a} and {@code b.}
      */
+    @HotSpotIntrinsicCandidate
     public static float min(float a, float b) {
         return Math.min(a, b);
     }
@@ -1237,6 +1240,7 @@
      * @param   b   another argument.
      * @return  the smaller of {@code a} and {@code b}.
      */
+    @HotSpotIntrinsicCandidate
     public static double min(double a, double b) {
         return Math.min(a, b);
     }