8253734: C2: Optimize Move nodes

Reviewed-by: thartmann, neliasso, kvn
This commit is contained in:
Vladimir Ivanov 2020-10-26 17:24:08 +00:00
parent 6666dcbe72
commit 83a91bfaed
5 changed files with 132 additions and 15 deletions

View File

@ -1268,6 +1268,59 @@ Node* LoadNode::convert_to_signed_load(PhaseGVN& gvn) {
is_unaligned_access(), is_mismatched_access());
}
bool LoadNode::has_reinterpret_variant(const Type* rt) {
BasicType bt = rt->basic_type();
switch (Opcode()) {
case Op_LoadI: return (bt == T_FLOAT);
case Op_LoadL: return (bt == T_DOUBLE);
case Op_LoadF: return (bt == T_INT);
case Op_LoadD: return (bt == T_LONG);
default: return false;
}
}
Node* LoadNode::convert_to_reinterpret_load(PhaseGVN& gvn, const Type* rt) {
BasicType bt = rt->basic_type();
assert(has_reinterpret_variant(rt), "no reinterpret variant: %s %s", Name(), type2name(bt));
bool is_mismatched = is_mismatched_access();
const TypeRawPtr* raw_type = gvn.type(in(MemNode::Memory))->isa_rawptr();
if (raw_type == NULL) {
is_mismatched = true; // conservatively match all non-raw accesses as mismatched
}
return LoadNode::make(gvn, in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address),
raw_adr_type(), rt, bt, _mo, _control_dependency,
is_unaligned_access(), is_mismatched);
}
bool StoreNode::has_reinterpret_variant(const Type* vt) {
BasicType bt = vt->basic_type();
switch (Opcode()) {
case Op_StoreI: return (bt == T_FLOAT);
case Op_StoreL: return (bt == T_DOUBLE);
case Op_StoreF: return (bt == T_INT);
case Op_StoreD: return (bt == T_LONG);
default: return false;
}
}
Node* StoreNode::convert_to_reinterpret_store(PhaseGVN& gvn, Node* val, const Type* vt) {
BasicType bt = vt->basic_type();
assert(has_reinterpret_variant(vt), "no reinterpret variant: %s %s", Name(), type2name(bt));
StoreNode* st = StoreNode::make(gvn, in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), raw_adr_type(), val, bt, _mo);
bool is_mismatched = is_mismatched_access();
const TypeRawPtr* raw_type = gvn.type(in(MemNode::Memory))->isa_rawptr();
if (raw_type == NULL) {
is_mismatched = true; // conservatively match all non-raw accesses as mismatched
}
if (is_mismatched) {
st->set_mismatched_access();
}
return st;
}
// We're loading from an object which has autobox behaviour.
// If this object is result of a valueOf call we'll have a phi
// merging a newly allocated object and a load from the cache.
@ -2548,6 +2601,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* mem = in(MemNode::Memory);
Node* address = in(MemNode::Address);
Node* value = in(MemNode::ValueIn);
// Back-to-back stores to same address? Fold em up. Generally
// unsafe if I have intervening uses... Also disallowed for StoreCM
// since they must follow each StoreP operation. Redundant StoreCMs
@ -2611,6 +2665,19 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) {
}
}
// Fold reinterpret cast into memory operation:
// StoreX mem (MoveY2X v) => StoreY mem v
if (value->is_Move()) {
const Type* vt = value->in(1)->bottom_type();
if (has_reinterpret_variant(vt)) {
if (phase->C->post_loop_opts_phase()) {
return convert_to_reinterpret_store(*phase, value->in(1), vt);
} else {
phase->C->record_for_post_loop_opts_igvn(this); // attempt the transformation once loop opts are over
}
}
}
return NULL; // No further progress
}

View File

@ -282,6 +282,9 @@ public:
Node* convert_to_unsigned_load(PhaseGVN& gvn);
Node* convert_to_signed_load(PhaseGVN& gvn);
bool has_reinterpret_variant(const Type* rt);
Node* convert_to_reinterpret_load(PhaseGVN& gvn, const Type* rt);
void pin() { _control_dependency = Pinned; }
bool has_unknown_control_dependency() const { return _control_dependency == UnknownControl; }
@ -634,6 +637,9 @@ public:
// have all possible loads of the value stored been optimized away?
bool value_never_loaded(PhaseTransform *phase) const;
bool has_reinterpret_variant(const Type* vt);
Node* convert_to_reinterpret_store(PhaseGVN& gvn, Node* val, const Type* vt);
MemBarNode* trailing_membar() const;
};

View File

@ -352,6 +352,36 @@ Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return abs;
}
//------------------------------MoveNode------------------------------------------
Node* MoveNode::Ideal(PhaseGVN* phase, bool can_reshape) {
if (can_reshape) {
// Fold reinterpret cast into memory operation:
// MoveX2Y (LoadX mem) => LoadY mem
LoadNode* ld = in(1)->isa_Load();
if (ld != NULL && (ld->outcnt() == 1)) { // replace only
const Type* rt = bottom_type();
if (ld->has_reinterpret_variant(rt)) {
if (phase->C->post_loop_opts_phase()) {
return ld->convert_to_reinterpret_load(*phase, rt);
} else {
phase->C->record_for_post_loop_opts_igvn(this); // attempt the transformation once loop opts are over
}
}
}
}
return NULL;
}
Node* MoveNode::Identity(PhaseGVN* phase) {
if (in(1)->is_Move()) {
// Back-to-back moves: MoveX2Y (MoveY2X v) => v
assert(bottom_type() == in(1)->in(1)->bottom_type(), "sanity");
return in(1)->in(1);
}
return this;
}
//------------------------------Value------------------------------------------
const Type* MoveL2DNode::Value(PhaseGVN* phase) const {
const Type *t = phase->type( in(1) );

View File

@ -98,41 +98,52 @@ class CMoveNNode : public CMoveNode {
};
//
class MoveI2FNode : public Node {
class MoveNode : public Node {
protected:
MoveNode(Node* value) : Node(NULL, value) {
init_class_id(Class_Move);
}
public:
MoveI2FNode( Node *value ) : Node(0,value) {}
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
virtual Node* Identity(PhaseGVN* phase);
};
class MoveI2FNode : public MoveNode {
public:
MoveI2FNode(Node* value) : MoveNode(value) {}
virtual int Opcode() const;
virtual const Type *bottom_type() const { return Type::FLOAT; }
virtual const Type* bottom_type() const { return Type::FLOAT; }
virtual uint ideal_reg() const { return Op_RegF; }
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node* Identity(PhaseGVN* phase);
};
class MoveL2DNode : public Node {
class MoveL2DNode : public MoveNode {
public:
MoveL2DNode( Node *value ) : Node(0,value) {}
MoveL2DNode(Node* value) : MoveNode(value) {}
virtual int Opcode() const;
virtual const Type *bottom_type() const { return Type::DOUBLE; }
virtual const Type* bottom_type() const { return Type::DOUBLE; }
virtual uint ideal_reg() const { return Op_RegD; }
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node* Identity(PhaseGVN* phase);
};
class MoveF2INode : public Node {
class MoveF2INode : public MoveNode {
public:
MoveF2INode( Node *value ) : Node(0,value) {}
MoveF2INode(Node* value) : MoveNode(value) {}
virtual int Opcode() const;
virtual const Type *bottom_type() const { return TypeInt::INT; }
virtual const Type* bottom_type() const { return TypeInt::INT; }
virtual uint ideal_reg() const { return Op_RegI; }
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node* Identity(PhaseGVN* phase);
};
class MoveD2LNode : public Node {
class MoveD2LNode : public MoveNode {
public:
MoveD2LNode( Node *value ) : Node(0,value) {}
MoveD2LNode(Node* value) : MoveNode(value) {}
virtual int Opcode() const;
virtual const Type *bottom_type() const { return TypeLong::LONG; }
virtual const Type* bottom_type() const { return TypeLong::LONG; }
virtual uint ideal_reg() const { return Op_RegL; }
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node* Identity(PhaseGVN* phase);

View File

@ -112,6 +112,7 @@ class MemBarNode;
class MemBarStoreStoreNode;
class MemNode;
class MergeMemNode;
class MoveNode;
class MulNode;
class MultiNode;
class MultiBranchNode;
@ -721,10 +722,11 @@ public:
DEFINE_CLASS_ID(Vector, Node, 13)
DEFINE_CLASS_ID(VectorMaskCmp, Vector, 0)
DEFINE_CLASS_ID(ClearArray, Node, 14)
DEFINE_CLASS_ID(Halt, Node, 15)
DEFINE_CLASS_ID(Opaque1, Node, 16)
DEFINE_CLASS_ID(Halt, Node, 15)
DEFINE_CLASS_ID(Opaque1, Node, 16)
DEFINE_CLASS_ID(Move, Node, 17)
_max_classes = ClassMask_Opaque1
_max_classes = ClassMask_Move
};
#undef DEFINE_CLASS_ID
@ -870,6 +872,7 @@ public:
DEFINE_CLASS_QUERY(MemBar)
DEFINE_CLASS_QUERY(MemBarStoreStore)
DEFINE_CLASS_QUERY(MergeMem)
DEFINE_CLASS_QUERY(Move)
DEFINE_CLASS_QUERY(Mul)
DEFINE_CLASS_QUERY(Multi)
DEFINE_CLASS_QUERY(MultiBranch)