8253734: C2: Optimize Move nodes
Reviewed-by: thartmann, neliasso, kvn
This commit is contained in:
parent
6666dcbe72
commit
83a91bfaed
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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) );
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user