Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 62 additions & 76 deletions src/hotspot/share/opto/divnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1516,123 +1516,109 @@ const Type* UModLNode::Value(PhaseGVN* phase) const {
return unsigned_mod_value<TypeLong, julong, jlong>(phase, this);
}

Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* super = CallLeafPureNode::Ideal(phase, can_reshape);
if (super != nullptr) {
return super;
}

if (!can_reshape) {
return nullptr;
}

PhaseIterGVN* igvn = phase->is_IterGVN();

// Either input is TOP ==> the result is TOP
const Type* t1 = phase->type(dividend());
const Type* t2 = phase->type(divisor());
if (t1 == Type::TOP || t2 == Type::TOP) {
return phase->C->top();
}

const Type* ModFNode::get_result_if_constant(const Type* dividend, const Type* divisor) const {
// If either number is not a constant, we know nothing.
if ((t1->base() != Type::FloatCon) || (t2->base() != Type::FloatCon)) {
if ((dividend->base() != Type::FloatCon) || (divisor->base() != Type::FloatCon)) {
return nullptr; // note: x%x can be either NaN or 0
}

float f1 = t1->getf();
float f2 = t2->getf();
jint x1 = jint_cast(f1); // note: *(int*)&f1, not just (int)f1
jint x2 = jint_cast(f2);
float dividend_f = dividend->getf();
float divisor_f = divisor->getf();
jint dividend_i = jint_cast(dividend_f); // note: *(int*)&f1, not just (int)f1
jint divisor_i = jint_cast(divisor_f);

// If either is a NaN, return an input NaN
if (g_isnan(f1)) {
return replace_with_con(igvn, t1);
if (g_isnan(dividend_f)) {
return dividend;
}
if (g_isnan(f2)) {
return replace_with_con(igvn, t2);
if (g_isnan(divisor_f)) {
return divisor;
}

// If an operand is infinity or the divisor is +/- zero, punt.
if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jint) {
if (!g_isfinite(dividend_f) || !g_isfinite(divisor_f) || divisor_i == 0 || divisor_i == min_jint) {
return nullptr;
}

// We must be modulo'ing 2 float constants.
// Make sure that the sign of the fmod is equal to the sign of the dividend
jint xr = jint_cast(fmod(f1, f2));
if ((x1 ^ xr) < 0) {
jint xr = jint_cast(fmod(dividend_f, divisor_f));
if ((dividend_i ^ xr) < 0) {
xr ^= min_jint;
}

return replace_with_con(igvn, TypeF::make(jfloat_cast(xr)));
return TypeF::make(jfloat_cast(xr));
}

Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* super = CallLeafPureNode::Ideal(phase, can_reshape);
if (super != nullptr) {
return super;
}

if (!can_reshape) {
return nullptr;
}

PhaseIterGVN* igvn = phase->is_IterGVN();

// Either input is TOP ==> the result is TOP
const Type* t1 = phase->type(dividend());
const Type* t2 = phase->type(divisor());
if (t1 == Type::TOP || t2 == Type::TOP) {
return nullptr;
}

const Type* ModDNode::get_result_if_constant(const Type* dividend, const Type* divisor) const {
// If either number is not a constant, we know nothing.
if ((t1->base() != Type::DoubleCon) || (t2->base() != Type::DoubleCon)) {
if ((dividend->base() != Type::DoubleCon) || (divisor->base() != Type::DoubleCon)) {
return nullptr; // note: x%x can be either NaN or 0
}

double f1 = t1->getd();
double f2 = t2->getd();
jlong x1 = jlong_cast(f1); // note: *(long*)&f1, not just (long)f1
jlong x2 = jlong_cast(f2);
double dividend_d = dividend->getd();
double divisor_d = divisor->getd();
jlong dividend_l = jlong_cast(dividend_d); // note: *(long*)&f1, not just (long)f1
jlong divisor_l = jlong_cast(divisor_d);

// If either is a NaN, return an input NaN
if (g_isnan(f1)) {
return replace_with_con(igvn, t1);
if (g_isnan(dividend_d)) {
return dividend;
}
if (g_isnan(f2)) {
return replace_with_con(igvn, t2);
if (g_isnan(divisor_d)) {
return divisor;
}

// If an operand is infinity or the divisor is +/- zero, punt.
if (!g_isfinite(f1) || !g_isfinite(f2) || x2 == 0 || x2 == min_jlong) {
if (!g_isfinite(dividend_d) || !g_isfinite(divisor_d) || divisor_l == 0 || divisor_l == min_jlong) {
return nullptr;
}

// We must be modulo'ing 2 double constants.
// Make sure that the sign of the fmod is equal to the sign of the dividend
jlong xr = jlong_cast(fmod(f1, f2));
if ((x1 ^ xr) < 0) {
jlong xr = jlong_cast(fmod(dividend_d, divisor_d));
if ((dividend_l ^ xr) < 0) {
xr ^= min_jlong;
}

return replace_with_con(igvn, TypeD::make(jdouble_cast(xr)));
return TypeD::make(jdouble_cast(xr));
}

Node* ModFloatingNode::Ideal(PhaseGVN* phase, bool can_reshape) {
if (can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();

// Either input is TOP ==> the result is TOP
const Type* dividend_type = phase->type(dividend());
const Type* divisor_type = phase->type(divisor());
if (dividend_type == Type::TOP || divisor_type == Type::TOP) {
return phase->C->top();
}
const Type* constant_result = get_result_if_constant(dividend_type, divisor_type);
if (constant_result != nullptr) {
return make_tuple_of_input_state_and_constant_result(igvn, constant_result);
}
}

return CallLeafPureNode::Ideal(phase, can_reshape);
}

Node* ModFloatingNode::replace_with_con(PhaseIterGVN* phase, const Type* con) {
Compile* C = phase->C;
/* Give a tuple node for ::Ideal to return, made of the input state (control to return addr)
* and the given constant result. Idealization of projections will make sure to transparently
* propagate the input state and replace the result by the said constant.
*/
TupleNode* ModFloatingNode::make_tuple_of_input_state_and_constant_result(PhaseIterGVN* phase, const Type* con) const {
Node* con_node = phase->makecon(con);
CallProjections projs;
extract_projections(&projs, false, false);
phase->replace_node(projs.fallthrough_proj, in(TypeFunc::Control));
if (projs.resproj != nullptr) {
phase->replace_node(projs.resproj, con_node);
}
phase->replace_node(this, C->top());
C->remove_macro_node(this);
disconnect_inputs(C);
return nullptr;
TupleNode* tuple = TupleNode::make(
tf()->range(),
in(TypeFunc::Control),
in(TypeFunc::I_O),
in(TypeFunc::Memory),
in(TypeFunc::FramePtr),
in(TypeFunc::ReturnAdr),
con_node);

return tuple;
}

//=============================================================================
Expand Down
31 changes: 18 additions & 13 deletions src/hotspot/share/opto/divnode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,39 +157,44 @@ class ModLNode : public Node {

// Base class for float and double modulus
class ModFloatingNode : public CallLeafPureNode {
TupleNode* make_tuple_of_input_state_and_constant_result(PhaseIterGVN* phase, const Type* con) const;

protected:
Node* replace_with_con(PhaseIterGVN* phase, const Type* con);
virtual Node* dividend() const = 0;
virtual Node* divisor() const = 0;
virtual const Type* get_result_if_constant(const Type* dividend, const Type* divisor) const = 0;

public:
ModFloatingNode(Compile* C, const TypeFunc* tf, address addr, const char* name);
Node* Ideal(PhaseGVN* phase, bool can_reshape) override;
};

// Float Modulus
class ModFNode : public ModFloatingNode {
private:
Node* dividend() const { return in(TypeFunc::Parms + 0); }
Node* divisor() const { return in(TypeFunc::Parms + 1); }
Node* dividend() const override { return in(TypeFunc::Parms + 0); }
Node* divisor() const override { return in(TypeFunc::Parms + 1); }
const Type* get_result_if_constant(const Type* dividend, const Type* divisor) const override;

public:
ModFNode(Compile* C, Node* a, Node* b);
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegF; }
virtual uint size_of() const { return sizeof(*this); }
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
int Opcode() const override;
uint ideal_reg() const override { return Op_RegF; }
uint size_of() const override { return sizeof(*this); }
};

// Double Modulus
class ModDNode : public ModFloatingNode {
private:
Node* dividend() const { return in(TypeFunc::Parms + 0); }
Node* divisor() const { return in(TypeFunc::Parms + 2); }
Node* dividend() const override { return in(TypeFunc::Parms + 0); }
Node* divisor() const override { return in(TypeFunc::Parms + 2); }
const Type* get_result_if_constant(const Type* dividend, const Type* divisor) const override;

public:
ModDNode(Compile* C, Node* a, Node* b);
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegD; }
virtual uint size_of() const { return sizeof(*this); }
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
int Opcode() const override;
uint ideal_reg() const override { return Op_RegD; }
uint size_of() const override { return sizeof(*this); }
};

//------------------------------UModINode---------------------------------------
Expand Down