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:
Christian Hagedorn 2024-06-26 07:09:50 +00:00
parent 25c3845be2
commit a5f401f3a8
6 changed files with 97 additions and 36 deletions

View File

@ -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);
};

View File

@ -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

View File

@ -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");

View File

@ -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 {

View File

@ -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();

View File

@ -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).