Skip to content

Commit

Permalink
8253734: C2: Optimize Move nodes
Browse files Browse the repository at this point in the history
Reviewed-by: thartmann, neliasso, kvn
  • Loading branch information
Vladimir Ivanov committed Oct 26, 2020
1 parent 6666dcb commit 83a91bf
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 15 deletions.
67 changes: 67 additions & 0 deletions src/hotspot/share/opto/memnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/opto/memnode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ class LoadNode : public MemNode {
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; }

Expand Down Expand Up @@ -634,6 +637,9 @@ class StoreNode : public MemNode {
// 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;
};

Expand Down
30 changes: 30 additions & 0 deletions src/hotspot/share/opto/movenode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) );
Expand Down
35 changes: 23 additions & 12 deletions src/hotspot/share/opto/movenode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
virtual Node* Identity(PhaseGVN* phase);
};

class MoveI2FNode : public MoveNode {
public:
MoveI2FNode( Node *value ) : Node(0,value) {}
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);
Expand Down
9 changes: 6 additions & 3 deletions src/hotspot/share/opto/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class MemBarNode;
class MemBarStoreStoreNode;
class MemNode;
class MergeMemNode;
class MoveNode;
class MulNode;
class MultiNode;
class MultiBranchNode;
Expand Down Expand Up @@ -721,10 +722,11 @@ class Node {
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

Expand Down Expand Up @@ -870,6 +872,7 @@ class Node {
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)
Expand Down

1 comment on commit 83a91bf

@bridgekeeper
Copy link

@bridgekeeper bridgekeeper bot commented on 83a91bf Oct 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.