mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-22 11:28:11 +00:00
8334650: Add debug information about whether an Assertion Predicate is for the init or last value
Reviewed-by: roland, kvn
This commit is contained in:
parent
25c3845be2
commit
a5f401f3a8
@ -57,6 +57,7 @@ class JProjNode;
|
||||
class JumpProjNode;
|
||||
class SCMemProjNode;
|
||||
class PhaseIdealLoop;
|
||||
enum class AssertionPredicateType;
|
||||
|
||||
// The success projection of a Parse Predicate is always an IfTrueNode and the uncommon projection an IfFalseNode
|
||||
typedef IfTrueNode ParsePredicateSuccessProj;
|
||||
@ -318,11 +319,23 @@ public:
|
||||
//------------------------------IfNode-----------------------------------------
|
||||
// Output selected Control, based on a boolean test
|
||||
class IfNode : public MultiBranchNode {
|
||||
public:
|
||||
float _prob; // Probability of true path being taken.
|
||||
float _fcnt; // Frequency counter
|
||||
|
||||
private:
|
||||
NOT_PRODUCT(AssertionPredicateType _assertion_predicate_type;)
|
||||
|
||||
void init_node(Node* control, Node* bol) {
|
||||
init_class_id(Class_If);
|
||||
init_req(0, control);
|
||||
init_req(1, bol);
|
||||
}
|
||||
|
||||
// Size is bigger to hold the probability field. However, _prob does not
|
||||
// change the semantics so it does not appear in the hash & cmp functions.
|
||||
virtual uint size_of() const { return sizeof(*this); }
|
||||
|
||||
private:
|
||||
// Helper methods for fold_compares
|
||||
bool cmpi_folds(PhaseIterGVN* igvn, bool fold_ne = false);
|
||||
bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn);
|
||||
@ -413,14 +426,8 @@ public:
|
||||
// Magic manifest probabilities such as 0.83, 0.7, ... can be found in
|
||||
// gen_subtype_check() and catch_inline_exceptions().
|
||||
|
||||
float _prob; // Probability of true path being taken.
|
||||
float _fcnt; // Frequency counter
|
||||
IfNode( Node *control, Node *b, float p, float fcnt )
|
||||
: MultiBranchNode(2), _prob(p), _fcnt(fcnt) {
|
||||
init_class_id(Class_If);
|
||||
init_req(0,control);
|
||||
init_req(1,b);
|
||||
}
|
||||
IfNode(Node* control, Node* bol, float p, float fcnt);
|
||||
NOT_PRODUCT(IfNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type);)
|
||||
|
||||
static IfNode* make_with_same_profile(IfNode* if_node_profile, Node* ctrl, BoolNode* bol);
|
||||
|
||||
@ -450,14 +457,20 @@ public:
|
||||
|
||||
class RangeCheckNode : public IfNode {
|
||||
private:
|
||||
int is_range_check(Node* &range, Node* &index, jint &offset);
|
||||
int is_range_check(Node*& range, Node*& index, jint& offset);
|
||||
|
||||
public:
|
||||
RangeCheckNode(Node* control, Node *b, float p, float fcnt)
|
||||
: IfNode(control, b, p, fcnt) {
|
||||
RangeCheckNode(Node* control, Node* bol, float p, float fcnt) : IfNode(control, bol, p, fcnt) {
|
||||
init_class_id(Class_RangeCheck);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
RangeCheckNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type)
|
||||
: IfNode(control, bol, p, fcnt, assertion_predicate_type) {
|
||||
init_class_id(Class_RangeCheck);
|
||||
}
|
||||
#endif // NOT PRODUCT
|
||||
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
};
|
||||
|
||||
@ -47,6 +47,24 @@
|
||||
extern uint explicit_null_checks_elided;
|
||||
#endif
|
||||
|
||||
IfNode::IfNode(Node* control, Node* bol, float p, float fcnt)
|
||||
: MultiBranchNode(2),
|
||||
_prob(p),
|
||||
_fcnt(fcnt)
|
||||
NOT_PRODUCT(COMMA _assertion_predicate_type(AssertionPredicateType::None)) {
|
||||
init_node(control, bol);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
IfNode::IfNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type)
|
||||
: MultiBranchNode(2),
|
||||
_prob(p),
|
||||
_fcnt(fcnt),
|
||||
_assertion_predicate_type(assertion_predicate_type) {
|
||||
init_node(control, bol);
|
||||
}
|
||||
#endif // NOT_PRODUCT
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Value------------------------------------------
|
||||
// Return a tuple for whichever arm of the IF is reachable
|
||||
@ -1822,11 +1840,23 @@ void IfProjNode::pin_array_access_nodes(PhaseIterGVN* igvn) {
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
//------------------------------dump_spec--------------------------------------
|
||||
void IfNode::dump_spec(outputStream *st) const {
|
||||
st->print("P=%f, C=%f",_prob,_fcnt);
|
||||
void IfNode::dump_spec(outputStream* st) const {
|
||||
switch (_assertion_predicate_type) {
|
||||
case AssertionPredicateType::Init_value:
|
||||
st->print("#Init Value Assertion Predicate ");
|
||||
break;
|
||||
case AssertionPredicateType::Last_value:
|
||||
st->print("#Last Value Assertion Predicate ");
|
||||
break;
|
||||
case AssertionPredicateType::None:
|
||||
// No Assertion Predicate
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown Assertion Predicate type");
|
||||
}
|
||||
st->print("P=%f, C=%f", _prob, _fcnt);
|
||||
}
|
||||
#endif
|
||||
#endif // NOT PRODUCT
|
||||
|
||||
//------------------------------idealize_test----------------------------------
|
||||
// Try to canonicalize tests better. Peek at the Cmp/Bool/If sequence and
|
||||
@ -2181,6 +2211,8 @@ void ParsePredicateNode::dump_spec(outputStream* st) const {
|
||||
default:
|
||||
fatal("unknown kind");
|
||||
}
|
||||
if (_useless) {
|
||||
st->print("#useless ");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NOT PRODUCT
|
||||
|
||||
@ -101,7 +101,8 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred,
|
||||
// is an IfTrue projection. This code is also used to clone predicates to cloned loops.
|
||||
IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_success_proj,
|
||||
Node* new_entry, const Deoptimization::DeoptReason reason,
|
||||
const int opcode, const bool rewire_uncommon_proj_phi_inputs) {
|
||||
const int opcode, const bool rewire_uncommon_proj_phi_inputs
|
||||
NOT_PRODUCT (COMMA AssertionPredicateType assertion_predicate_type)) {
|
||||
assert(parse_predicate_success_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!");
|
||||
ParsePredicateNode* parse_predicate = parse_predicate_success_proj->in(0)->as_ParsePredicate();
|
||||
ParsePredicateUncommonProj* uncommon_proj = parse_predicate->uncommon_proj();
|
||||
@ -143,10 +144,12 @@ IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessPro
|
||||
IfNode* new_iff = nullptr;
|
||||
switch (opcode) {
|
||||
case Op_If:
|
||||
new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt);
|
||||
new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt
|
||||
NOT_PRODUCT(COMMA assertion_predicate_type));
|
||||
break;
|
||||
case Op_RangeCheck:
|
||||
new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt);
|
||||
new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt
|
||||
NOT_PRODUCT(COMMA assertion_predicate_type));
|
||||
break;
|
||||
case Op_ParsePredicate:
|
||||
new_iff = new ParsePredicateNode(entry, reason, &_igvn);
|
||||
@ -1320,7 +1323,8 @@ IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL
|
||||
Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over
|
||||
C->add_template_assertion_predicate_opaq(opaque_bol);
|
||||
register_new_node(opaque_bol, upper_bound_proj);
|
||||
IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode());
|
||||
IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(),
|
||||
false NOT_PRODUCT(COMMA AssertionPredicateType::Init_value));
|
||||
_igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);
|
||||
assert(opaque_init->outcnt() > 0, "should be used");
|
||||
|
||||
@ -1345,7 +1349,8 @@ IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL
|
||||
opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1));
|
||||
C->add_template_assertion_predicate_opaq(opaque_bol);
|
||||
register_new_node(opaque_bol, new_proj);
|
||||
new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode());
|
||||
new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(),
|
||||
false NOT_PRODUCT(COMMA AssertionPredicateType::Last_value));
|
||||
_igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);
|
||||
assert(max_value->outcnt() > 0, "should be used");
|
||||
assert(assertion_predicate_has_loop_opaque_node(new_proj->in(0)->as_If()), "unexpected");
|
||||
|
||||
@ -2769,10 +2769,9 @@ bool PhaseIdealLoop::is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, N
|
||||
|
||||
// Same as PhaseIdealLoop::duplicate_predicates() but for range checks
|
||||
// eliminated by iteration splitting.
|
||||
Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* ctrl,
|
||||
const int scale_con, Node* offset, Node* limit,
|
||||
jint stride_con, Node* value,
|
||||
const bool is_template) {
|
||||
Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(
|
||||
IdealLoopTree* loop, Node* ctrl, const int scale_con, Node* offset, Node* limit, jint stride_con, Node* value,
|
||||
const bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) {
|
||||
bool overflow = false;
|
||||
BoolNode* bol = rc_predicate(ctrl, scale_con, offset, value, nullptr, stride_con,
|
||||
limit, (stride_con > 0) != (scale_con > 0), overflow);
|
||||
@ -2993,8 +2992,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
|
||||
|
||||
// Add two Template Assertion Predicates to create new Initialized Assertion Predicates from when either
|
||||
// unrolling or splitting this main-loop further.
|
||||
loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset,
|
||||
int_limit, stride_con, opaque_init, true);
|
||||
loop_entry = add_range_check_elimination_assertion_predicate(
|
||||
loop, loop_entry, scale_con, int_offset, int_limit, stride_con, opaque_init, true
|
||||
NOT_PRODUCT(COMMA AssertionPredicateType::Init_value));
|
||||
assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
|
||||
|
||||
Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride());
|
||||
@ -3006,8 +3006,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
|
||||
// init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi
|
||||
max_value = new CastIINode(max_value, loop->_head->as_CountedLoop()->phi()->bottom_type());
|
||||
register_new_node(max_value, loop_entry);
|
||||
loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset,
|
||||
int_limit, stride_con, max_value, true);
|
||||
loop_entry = add_range_check_elimination_assertion_predicate(
|
||||
loop, loop_entry, scale_con, int_offset, int_limit, stride_con, max_value, true
|
||||
NOT_PRODUCT(COMMA AssertionPredicateType::Last_value));
|
||||
assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected");
|
||||
|
||||
} else {
|
||||
|
||||
@ -1339,9 +1339,10 @@ public:
|
||||
bool* p_short_scale, int depth);
|
||||
|
||||
// Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted
|
||||
IfTrueNode* create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason, int opcode,
|
||||
bool rewire_uncommon_proj_phi_inputs = false);
|
||||
IfTrueNode* create_new_if_for_predicate(
|
||||
ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason, int opcode,
|
||||
bool rewire_uncommon_proj_phi_inputs = false
|
||||
NOT_PRODUCT (COMMA AssertionPredicateType assertion_predicate_type = AssertionPredicateType::None));
|
||||
|
||||
private:
|
||||
// Helper functions for create_new_if_for_predicate()
|
||||
@ -1382,9 +1383,9 @@ public:
|
||||
IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit,
|
||||
jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason);
|
||||
void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj);
|
||||
Node* add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* predicate_proj, int scale_con,
|
||||
Node* offset, Node* limit, int stride_con, Node* value,
|
||||
bool is_template);
|
||||
Node* add_range_check_elimination_assertion_predicate(
|
||||
IdealLoopTree* loop, Node* predicate_proj, int scale_con, Node* offset, Node* limit, int stride_con, Node* value,
|
||||
bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type = AssertionPredicateType::None));
|
||||
|
||||
// Helper function to collect predicate for eliminating the useless ones
|
||||
void eliminate_useless_predicates();
|
||||
|
||||
@ -193,6 +193,15 @@
|
||||
* Main Loop Head
|
||||
*/
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Assertion Predicates are either emitted to check the initial value of a range check in the first iteration or the last
|
||||
// value of a range check in the last iteration of a loop.
|
||||
enum class AssertionPredicateType {
|
||||
None, // Not an Assertion Predicate
|
||||
Init_value,
|
||||
Last_value
|
||||
};
|
||||
#endif // NOT PRODUCT
|
||||
|
||||
// Class to represent Assertion Predicates with a HaltNode instead of an UCT (i.e. either an Initialized Assertion
|
||||
// Predicate or a Template Assertion Predicate created after the initial one at Loop Predication).
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user