8231649: PPC64: Intrinsics for Math.ceil, floor, rint on Power
Reviewed-by: mdoerr, vlivanov
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp Tue Oct 22 22:00:21 2019 -0400
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp Tue Oct 22 21:26:45 2019 -0500
@@ -444,6 +444,9 @@
FDIV_OPCODE = (63u << OPCODE_SHIFT | 18u << 1),
FDIVS_OPCODE = (59u << OPCODE_SHIFT | 18u << 1),
FMR_OPCODE = (63u << OPCODE_SHIFT | 72u << 1),
+ FRIN_OPCODE = (63u << OPCODE_SHIFT | 392u << 1),
+ FRIP_OPCODE = (63u << OPCODE_SHIFT | 456u << 1),
+ FRIM_OPCODE = (63u << OPCODE_SHIFT | 488u << 1),
// These are special Power6 opcodes, reused for "lfdepx" and "stfdepx"
// on Power7. Do not use.
// MFFGPR_OPCODE = (31u << OPCODE_SHIFT | 607u << 1),
@@ -545,6 +548,9 @@
XVMSUBADP_OPCODE=(60u << OPCODE_SHIFT | 113u << 3),
XVNMSUBASP_OPCODE=(60u<< OPCODE_SHIFT | 209u << 3),
XVNMSUBADP_OPCODE=(60u<< OPCODE_SHIFT | 241u << 3),
+ XVRDPI_OPCODE = (60u << OPCODE_SHIFT | 201u << 2),
+ XVRDPIM_OPCODE = (60u << OPCODE_SHIFT | 249u << 2),
+ XVRDPIP_OPCODE = (60u << OPCODE_SHIFT | 233u << 2),
// Deliver A Random Number (introduced with POWER9)
DARN_OPCODE = (31u << OPCODE_SHIFT | 755u << 1),
@@ -1981,6 +1987,10 @@
inline void fmr( FloatRegister d, FloatRegister b);
inline void fmr_( FloatRegister d, FloatRegister b);
+ inline void frin( FloatRegister d, FloatRegister b);
+ inline void frip( FloatRegister d, FloatRegister b);
+ inline void frim( FloatRegister d, FloatRegister b);
+
// inline void mffgpr( FloatRegister d, Register b);
// inline void mftgpr( Register d, FloatRegister b);
inline void cmpb( Register a, Register s, Register b);
@@ -2241,6 +2251,9 @@
inline void xvmsubadp(VectorSRegister d, VectorSRegister a, VectorSRegister b);
inline void xvnmsubasp(VectorSRegister d, VectorSRegister a, VectorSRegister b);
inline void xvnmsubadp(VectorSRegister d, VectorSRegister a, VectorSRegister b);
+ inline void xvrdpi( VectorSRegister d, VectorSRegister b);
+ inline void xvrdpim( VectorSRegister d, VectorSRegister b);
+ inline void xvrdpip( VectorSRegister d, VectorSRegister b);
// VSX Extended Mnemonics
inline void xxspltd( VectorSRegister d, VectorSRegister a, int x);
--- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Tue Oct 22 22:00:21 2019 -0400
+++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Tue Oct 22 21:26:45 2019 -0500
@@ -675,6 +675,10 @@
inline void Assembler::fmr( FloatRegister d, FloatRegister b) { emit_int32( FMR_OPCODE | frt(d) | frb(b) | rc(0)); }
inline void Assembler::fmr_(FloatRegister d, FloatRegister b) { emit_int32( FMR_OPCODE | frt(d) | frb(b) | rc(1)); }
+inline void Assembler::frin( FloatRegister d, FloatRegister b) { emit_int32( FRIN_OPCODE | frt(d) | frb(b) | rc(0)); }
+inline void Assembler::frip( FloatRegister d, FloatRegister b) { emit_int32( FRIP_OPCODE | frt(d) | frb(b) | rc(0)); }
+inline void Assembler::frim( FloatRegister d, FloatRegister b) { emit_int32( FRIM_OPCODE | frt(d) | frb(b) | rc(0)); }
+
// These are special Power6 opcodes, reused for "lfdepx" and "stfdepx"
// on Power7. Do not use.
//inline void Assembler::mffgpr( FloatRegister d, Register b) { emit_int32( MFFGPR_OPCODE | frt(d) | rb(b) | rc(0)); }
@@ -796,6 +800,10 @@
inline void Assembler::xvmsubadp( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVMSUBADP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
inline void Assembler::xvnmsubasp(VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVNMSUBASP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
inline void Assembler::xvnmsubadp(VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVNMSUBADP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
+inline void Assembler::xvrdpi( VectorSRegister d, VectorSRegister b) { emit_int32( XVRDPI_OPCODE | vsrt(d) | vsrb(b)); }
+inline void Assembler::xvrdpim( VectorSRegister d, VectorSRegister b) { emit_int32( XVRDPIM_OPCODE | vsrt(d) | vsrb(b)); }
+inline void Assembler::xvrdpip( VectorSRegister d, VectorSRegister b) { emit_int32( XVRDPIP_OPCODE | vsrt(d) | vsrb(b)); }
+
inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mfvrd( Register a, VectorRegister d) { emit_int32( MFVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mtvrwz( VectorRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
--- a/src/hotspot/cpu/ppc/ppc.ad Tue Oct 22 22:00:21 2019 -0400
+++ b/src/hotspot/cpu/ppc/ppc.ad Tue Oct 22 21:26:45 2019 -0500
@@ -972,6 +972,8 @@
// To keep related declarations/definitions/uses close together,
// we switch between source %{ }% and source_hpp %{ }% freely as needed.
+#include "opto/convertnode.hpp"
+
// Returns true if Node n is followed by a MemBar node that
// will do an acquire. If so, this node must not do the acquire
// operation.
@@ -2272,6 +2274,7 @@
case Op_AddVL:
case Op_SubVL:
case Op_MulVI:
+ case Op_RoundDoubleModeV:
return SuperwordUseVSX;
case Op_PopCountVI:
return (SuperwordUseVSX && UsePopCountInstruction);
@@ -14454,6 +14457,53 @@
ins_pipe(pipe_class_default);
%}
+// Round Instructions
+instruct roundD_reg(regD dst, regD src, immI8 rmode) %{
+ match(Set dst (RoundDoubleMode src rmode));
+ format %{ "RoundDoubleMode $src,$rmode" %}
+ size(4);
+ ins_encode %{
+ switch ($rmode$$constant) {
+ case RoundDoubleModeNode::rmode_rint:
+ __ frin($dst$$FloatRegister, $src$$FloatRegister);
+ break;
+ case RoundDoubleModeNode::rmode_floor:
+ __ frim($dst$$FloatRegister, $src$$FloatRegister);
+ break;
+ case RoundDoubleModeNode::rmode_ceil:
+ __ frip($dst$$FloatRegister, $src$$FloatRegister);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+// Vector Round Instructions
+instruct vround2D_reg(vecX dst, vecX src, immI8 rmode) %{
+ match(Set dst (RoundDoubleModeV src rmode));
+ predicate(n->as_Vector()->length() == 2);
+ format %{ "RoundDoubleModeV $src,$rmode" %}
+ size(4);
+ ins_encode %{
+ switch ($rmode$$constant) {
+ case RoundDoubleModeNode::rmode_rint:
+ __ xvrdpi($dst$$VectorSRegister, $src$$VectorSRegister);
+ break;
+ case RoundDoubleModeNode::rmode_floor:
+ __ xvrdpim($dst$$VectorSRegister, $src$$VectorSRegister);
+ break;
+ case RoundDoubleModeNode::rmode_ceil:
+ __ xvrdpip($dst$$VectorSRegister, $src$$VectorSRegister);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Vector Negate Instructions
instruct vneg4F_reg(vecX dst, vecX src) %{
--- a/src/hotspot/share/opto/convertnode.cpp Tue Oct 22 22:00:21 2019 -0400
+++ b/src/hotspot/share/opto/convertnode.cpp Tue Oct 22 21:26:45 2019 -0500
@@ -532,6 +532,11 @@
}
//=============================================================================
+RoundDoubleModeNode* RoundDoubleModeNode::make(PhaseGVN& gvn, Node* arg, RoundDoubleModeNode::RoundingMode rmode) {
+ ConINode* rm = gvn.intcon(rmode);
+ return new RoundDoubleModeNode(arg, (Node *)rm);
+}
+
//------------------------------Identity---------------------------------------
// Remove redundant roundings.
Node* RoundDoubleModeNode::Identity(PhaseGVN* phase) {
--- a/src/hotspot/share/opto/convertnode.hpp Tue Oct 22 22:00:21 2019 -0400
+++ b/src/hotspot/share/opto/convertnode.hpp Tue Oct 22 21:26:45 2019 -0500
@@ -215,7 +215,13 @@
//-----------------------------RoundDoubleModeNode-----------------------------
class RoundDoubleModeNode: public Node {
public:
+ enum RoundingMode {
+ rmode_rint = 0,
+ rmode_floor = 1,
+ rmode_ceil = 2
+ };
RoundDoubleModeNode(Node *in1, Node * rmode): Node(0, in1, rmode) {}
+ static RoundDoubleModeNode* make(PhaseGVN& gvn, Node* arg, RoundDoubleModeNode::RoundingMode rmode);
virtual int Opcode() const;
virtual const Type *bottom_type() const { return Type::DOUBLE; }
virtual uint ideal_reg() const { return Op_RegD; }
--- a/src/hotspot/share/opto/library_call.cpp Tue Oct 22 22:00:21 2019 -0400
+++ b/src/hotspot/share/opto/library_call.cpp Tue Oct 22 21:26:45 2019 -0500
@@ -1822,9 +1822,9 @@
switch (id) {
case vmIntrinsics::_dabs: n = new AbsDNode( arg); break;
case vmIntrinsics::_dsqrt: n = new SqrtDNode(C, control(), arg); break;
- case vmIntrinsics::_ceil: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(2))); break;
- case vmIntrinsics::_floor: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(1))); break;
- case vmIntrinsics::_rint: n = new RoundDoubleModeNode(arg, makecon(TypeInt::make(0))); break;
+ case vmIntrinsics::_ceil: n = RoundDoubleModeNode::make(_gvn, arg, RoundDoubleModeNode::rmode_ceil); break;
+ case vmIntrinsics::_floor: n = RoundDoubleModeNode::make(_gvn, arg, RoundDoubleModeNode::rmode_floor); break;
+ case vmIntrinsics::_rint: n = RoundDoubleModeNode::make(_gvn, arg, RoundDoubleModeNode::rmode_rint); break;
default: fatal_unexpected_iid(id); break;
}
set_result(_gvn.transform(n));