Skip to content

Commit d381d58

Browse files
8332268: C2: Add missing optimizations for UDivI/L and UModI/L and unify the shared logic with the signed nodes
Reviewed-by: chagedorn, thartmann, epeter, qamai
1 parent 45c914c commit d381d58

17 files changed

+1126
-18
lines changed

src/hotspot/share/opto/divnode.cpp

Lines changed: 135 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,47 @@ static Node *transform_long_divide( PhaseGVN *phase, Node *dividend, jlong divis
447447
return q;
448448
}
449449

450+
template <typename TypeClass, typename Unsigned>
451+
Node* unsigned_div_ideal(PhaseGVN* phase, bool can_reshape, Node* div) {
452+
// Check for dead control input
453+
if (div->in(0) != nullptr && div->remove_dead_region(phase, can_reshape)) {
454+
return div;
455+
}
456+
// Don't bother trying to transform a dead node
457+
if (div->in(0) != nullptr && div->in(0)->is_top()) {
458+
return nullptr;
459+
}
460+
461+
const Type* t = phase->type(div->in(2));
462+
if (t == Type::TOP) {
463+
return nullptr;
464+
}
465+
const TypeClass* type_divisor = t->cast<TypeClass>();
466+
467+
// Check for useless control input
468+
// Check for excluding div-zero case
469+
if (div->in(0) != nullptr && (type_divisor->_hi < 0 || type_divisor->_lo > 0)) {
470+
div->set_req(0, nullptr); // Yank control input
471+
return div;
472+
}
473+
474+
if (!type_divisor->is_con()) {
475+
return nullptr;
476+
}
477+
Unsigned divisor = static_cast<Unsigned>(type_divisor->get_con()); // Get divisor
478+
479+
if (divisor == 0 || divisor == 1) {
480+
return nullptr; // Dividing by zero constant does not idealize
481+
}
482+
483+
if (is_power_of_2(divisor)) {
484+
return make_urshift<TypeClass>(div->in(1), phase->intcon(log2i_graceful(divisor)));
485+
}
486+
487+
return nullptr;
488+
}
489+
490+
450491
//=============================================================================
451492
//------------------------------Identity---------------------------------------
452493
// If the divisor is 1, we are an identity on the dividend.
@@ -873,12 +914,9 @@ const Type* UDivINode::Value(PhaseGVN* phase) const {
873914

874915
//------------------------------Idealize---------------------------------------
875916
Node *UDivINode::Ideal(PhaseGVN *phase, bool can_reshape) {
876-
// Check for dead control input
877-
if (in(0) && remove_dead_region(phase, can_reshape)) return this;
878-
return nullptr;
917+
return unsigned_div_ideal<TypeInt, juint>(phase, can_reshape, this);
879918
}
880919

881-
882920
//=============================================================================
883921
//------------------------------Identity---------------------------------------
884922
// If the divisor is 1, we are an identity on the dividend.
@@ -912,12 +950,9 @@ const Type* UDivLNode::Value(PhaseGVN* phase) const {
912950

913951
//------------------------------Idealize---------------------------------------
914952
Node *UDivLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
915-
// Check for dead control input
916-
if (in(0) && remove_dead_region(phase, can_reshape)) return this;
917-
return nullptr;
953+
return unsigned_div_ideal<TypeLong, julong>(phase, can_reshape, this);
918954
}
919955

920-
921956
//=============================================================================
922957
//------------------------------Idealize---------------------------------------
923958
Node *ModINode::Ideal(PhaseGVN *phase, bool can_reshape) {
@@ -1084,12 +1119,98 @@ const Type* ModINode::Value(PhaseGVN* phase) const {
10841119

10851120
//=============================================================================
10861121
//------------------------------Idealize---------------------------------------
1087-
Node *UModINode::Ideal(PhaseGVN *phase, bool can_reshape) {
1122+
1123+
template <typename TypeClass, typename Unsigned>
1124+
static Node* unsigned_mod_ideal(PhaseGVN* phase, bool can_reshape, Node* mod) {
10881125
// Check for dead control input
1089-
if( in(0) && remove_dead_region(phase, can_reshape) ) return this;
1126+
if (mod->in(0) != nullptr && mod->remove_dead_region(phase, can_reshape)) {
1127+
return mod;
1128+
}
1129+
// Don't bother trying to transform a dead node
1130+
if (mod->in(0) != nullptr && mod->in(0)->is_top()) {
1131+
return nullptr;
1132+
}
1133+
1134+
// Get the modulus
1135+
const Type* t = phase->type(mod->in(2));
1136+
if (t == Type::TOP) {
1137+
return nullptr;
1138+
}
1139+
const TypeClass* type_divisor = t->cast<TypeClass>();
1140+
1141+
// Check for useless control input
1142+
// Check for excluding mod-zero case
1143+
if (mod->in(0) != nullptr && (type_divisor->_hi < 0 || type_divisor->_lo > 0)) {
1144+
mod->set_req(0, nullptr); // Yank control input
1145+
return mod;
1146+
}
1147+
1148+
if (!type_divisor->is_con()) {
1149+
return nullptr;
1150+
}
1151+
Unsigned divisor = static_cast<Unsigned>(type_divisor->get_con());
1152+
1153+
if (divisor == 0) {
1154+
return nullptr;
1155+
}
1156+
1157+
if (is_power_of_2(divisor)) {
1158+
return make_and<TypeClass>(mod->in(1), phase->makecon(TypeClass::make(divisor - 1)));
1159+
}
1160+
10901161
return nullptr;
10911162
}
10921163

1164+
template <typename TypeClass, typename Unsigned, typename Signed>
1165+
static const Type* unsigned_mod_value(PhaseGVN* phase, const Node* mod) {
1166+
const Type* t1 = phase->type(mod->in(1));
1167+
const Type* t2 = phase->type(mod->in(2));
1168+
if (t1 == Type::TOP) {
1169+
return Type::TOP;
1170+
}
1171+
if (t2 == Type::TOP) {
1172+
return Type::TOP;
1173+
}
1174+
1175+
// 0 MOD X is 0
1176+
if (t1 == TypeClass::ZERO) {
1177+
return TypeClass::ZERO;
1178+
}
1179+
// X MOD X is 0
1180+
if (mod->in(1) == mod->in(2)) {
1181+
return TypeClass::ZERO;
1182+
}
1183+
1184+
// Either input is BOTTOM ==> the result is the local BOTTOM
1185+
const Type* bot = mod->bottom_type();
1186+
if ((t1 == bot) || (t2 == bot) ||
1187+
(t1 == Type::BOTTOM) || (t2 == Type::BOTTOM)) {
1188+
return bot;
1189+
}
1190+
1191+
const TypeClass* type_divisor = t2->cast<TypeClass>();
1192+
if (type_divisor->is_con() && type_divisor->get_con() == 1) {
1193+
return TypeClass::ZERO;
1194+
}
1195+
1196+
const TypeClass* type_dividend = t1->cast<TypeClass>();
1197+
if (type_dividend->is_con() && type_divisor->is_con()) {
1198+
Unsigned dividend = static_cast<Unsigned>(type_dividend->get_con());
1199+
Unsigned divisor = static_cast<Unsigned>(type_divisor->get_con());
1200+
return TypeClass::make(static_cast<Signed>(dividend % divisor));
1201+
}
1202+
1203+
return bot;
1204+
}
1205+
1206+
Node* UModINode::Ideal(PhaseGVN* phase, bool can_reshape) {
1207+
return unsigned_mod_ideal<TypeInt, juint>(phase, can_reshape, this);
1208+
}
1209+
1210+
const Type* UModINode::Value(PhaseGVN* phase) const {
1211+
return unsigned_mod_value<TypeInt, juint, jint>(phase, this);
1212+
}
1213+
10931214
//=============================================================================
10941215
//------------------------------Idealize---------------------------------------
10951216
Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
@@ -1303,11 +1424,12 @@ const Type* ModFNode::Value(PhaseGVN* phase) const {
13031424
//=============================================================================
13041425
//------------------------------Idealize---------------------------------------
13051426
Node *UModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
1306-
// Check for dead control input
1307-
if( in(0) && remove_dead_region(phase, can_reshape) ) return this;
1308-
return nullptr;
1427+
return unsigned_mod_ideal<TypeLong, julong>(phase, can_reshape, this);
13091428
}
13101429

1430+
const Type* UModLNode::Value(PhaseGVN* phase) const {
1431+
return unsigned_mod_value<TypeLong, julong, jlong>(phase, this);
1432+
}
13111433

13121434
//=============================================================================
13131435
//------------------------------Value------------------------------------------

src/hotspot/share/opto/divnode.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ class UModINode : public Node {
171171
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
172172
virtual const Type *bottom_type() const { return TypeInt::INT; }
173173
virtual uint ideal_reg() const { return Op_RegI; }
174+
virtual const Type* Value(PhaseGVN* phase) const;
174175
};
175176

176177
//------------------------------UModLNode---------------------------------------
@@ -182,6 +183,7 @@ class UModLNode : public Node {
182183
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
183184
virtual const Type *bottom_type() const { return TypeLong::LONG; }
184185
virtual uint ideal_reg() const { return Op_RegL; }
186+
virtual const Type* Value(PhaseGVN* phase) const;
185187
};
186188

187189
//------------------------------DivModNode---------------------------------------

src/hotspot/share/opto/loopopts.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,14 @@ bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) co
278278
switch (n->Opcode()) {
279279
case Op_DivI:
280280
case Op_ModI:
281+
case Op_UDivI:
282+
case Op_UModI:
281283
zero = TypeInt::ZERO;
282284
break;
283285
case Op_DivL:
284286
case Op_ModL:
287+
case Op_UDivL:
288+
case Op_UModL:
285289
zero = TypeLong::ZERO;
286290
break;
287291
default:

src/hotspot/share/opto/mulnode.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,19 @@ class AndLNode : public MulLNode {
226226
virtual uint ideal_reg() const { return Op_RegL; }
227227
};
228228

229+
template <typename TypeClass>
230+
Node* make_and(Node* a, Node* b);
231+
232+
template <>
233+
inline Node* make_and<TypeLong>(Node* a, Node* b) {
234+
return new AndLNode(a, b);
235+
}
236+
237+
template <>
238+
inline Node* make_and<TypeInt>(Node* a, Node* b) {
239+
return new AndINode(a, b);
240+
}
241+
229242
class LShiftNode : public Node {
230243
public:
231244
LShiftNode(Node *in1, Node *in2) : Node(nullptr,in1,in2) {
@@ -358,6 +371,19 @@ class URShiftLNode : public Node {
358371
virtual uint ideal_reg() const { return Op_RegL; }
359372
};
360373

374+
template <typename TypeClass>
375+
Node* make_urshift(Node* a, Node* b);
376+
377+
template <>
378+
inline Node* make_urshift<TypeLong>(Node* a, Node* b) {
379+
return new URShiftLNode(a, b);
380+
}
381+
382+
template <>
383+
inline Node* make_urshift<TypeInt>(Node* a, Node* b) {
384+
return new URShiftINode(a, b);
385+
}
386+
361387
//------------------------------FmaNode--------------------------------------
362388
// fused-multiply-add
363389
class FmaNode : public Node {

src/hotspot/share/opto/node.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,6 @@ class Node {
11261126
// Check if 'this' node dominates or equal to 'sub'.
11271127
DomResult dominates(Node* sub, Node_List &nlist);
11281128

1129-
protected:
11301129
bool remove_dead_region(PhaseGVN *phase, bool can_reshape);
11311130
public:
11321131

src/hotspot/share/opto/phaseX.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,9 @@ void PhaseIterGVN::remove_speculative_types() {
17311731
bool PhaseIterGVN::no_dependent_zero_check(Node* n) const {
17321732
switch (n->Opcode()) {
17331733
case Op_DivI:
1734-
case Op_ModI: {
1734+
case Op_ModI:
1735+
case Op_UDivI:
1736+
case Op_UModI: {
17351737
// Type of divisor includes 0?
17361738
if (type(n->in(2)) == Type::TOP) {
17371739
// 'n' is dead. Treat as if zero check is still there to avoid any further optimizations.
@@ -1741,7 +1743,9 @@ bool PhaseIterGVN::no_dependent_zero_check(Node* n) const {
17411743
return (type_divisor->_hi < 0 || type_divisor->_lo > 0);
17421744
}
17431745
case Op_DivL:
1744-
case Op_ModL: {
1746+
case Op_ModL:
1747+
case Op_UDivL:
1748+
case Op_UModL: {
17451749
// Type of divisor includes 0?
17461750
if (type(n->in(2)) == Type::TOP) {
17471751
// 'n' is dead. Treat as if zero check is still there to avoid any further optimizations.

src/hotspot/share/opto/type.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ class Type {
314314
const TypeAryPtr *isa_aryptr() const; // Returns null if not AryPtr
315315
const TypeAryPtr *is_aryptr() const; // Array oop
316316

317+
template <typename TypeClass>
318+
const TypeClass* cast() const;
319+
317320
const TypeMetadataPtr *isa_metadataptr() const; // Returns null if not oop ptr type
318321
const TypeMetadataPtr *is_metadataptr() const; // Java-style GC'd pointer
319322
const TypeKlassPtr *isa_klassptr() const; // Returns null if not KlassPtr
@@ -2166,6 +2169,15 @@ inline bool Type::is_floatingpoint() const {
21662169
return false;
21672170
}
21682171

2172+
template <>
2173+
inline const TypeInt* Type::cast<TypeInt>() const {
2174+
return is_int();
2175+
}
2176+
2177+
template <>
2178+
inline const TypeLong* Type::cast<TypeLong>() const {
2179+
return is_long();
2180+
}
21692181

21702182
// ===============================================================
21712183
// Things that need to be 64-bits in the 64-bit build but

test/hotspot/jtreg/compiler/c2/irTests/DivINodeIdealizationTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ public int identityThird(int x, int y) {
127127
IRNode.DIV, "1",
128128
IRNode.DIV_BY_ZERO_TRAP, "1"
129129
})
130-
// Hotspot should keep the division because it may cause a division by zero trap
131130
public int retainDenominator(int x, int y) {
132131
return (x * y) / y;
133132
}

test/hotspot/jtreg/compiler/c2/irTests/DivLNodeIdealizationTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ public long identityThird(long x, long y) {
125125
IRNode.DIV_L, "1",
126126
IRNode.DIV_BY_ZERO_TRAP, "1"
127127
})
128-
// Hotspot should keep the division because it may cause a division by zero trap
129128
public long retainDenominator(long x, long y) {
130129
return (x * y) / y;
131130
}

0 commit comments

Comments
 (0)