mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-09 21:19:38 +00:00
8379667: C2: Deep recursion with cmovP_regNode::bottom_type
Reviewed-by: aseoane, dlong
This commit is contained in:
parent
c53a98ce9e
commit
f5624e65ed
@ -453,14 +453,6 @@ Form::DataType InstructForm::is_ideal_store() const {
|
||||
return _matrule->is_ideal_store();
|
||||
}
|
||||
|
||||
// Return 'true' if this instruction matches an ideal vector node
|
||||
bool InstructForm::is_vector() const {
|
||||
if( _matrule == nullptr ) return false;
|
||||
|
||||
return _matrule->is_vector();
|
||||
}
|
||||
|
||||
|
||||
// Return the input register that must match the output register
|
||||
// If this is not required, return 0
|
||||
uint InstructForm::two_address(FormDict &globals) {
|
||||
@ -767,51 +759,6 @@ int InstructForm::memory_operand(FormDict &globals) const {
|
||||
return NO_MEMORY_OPERAND;
|
||||
}
|
||||
|
||||
// This instruction captures the machine-independent bottom_type
|
||||
// Expected use is for pointer vs oop determination for LoadP
|
||||
bool InstructForm::captures_bottom_type(FormDict &globals) const {
|
||||
if (_matrule && _matrule->_rChild &&
|
||||
(!strcmp(_matrule->_rChild->_opType,"CastPP") || // new result type
|
||||
!strcmp(_matrule->_rChild->_opType,"CastDD") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CastFF") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CastII") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CastLL") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CastVV") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CastX2P") || // new result type
|
||||
!strcmp(_matrule->_rChild->_opType,"DecodeN") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"EncodeP") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"DecodeNKlass") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"EncodePKlass") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"LoadN") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"LoadNKlass") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CreateEx") || // type of exception
|
||||
!strcmp(_matrule->_rChild->_opType,"CheckCastPP") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"GetAndSetP") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"GetAndSetN") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"RotateLeft") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"RotateRight") ||
|
||||
#if INCLUDE_SHENANDOAHGC
|
||||
!strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN") ||
|
||||
#endif
|
||||
!strcmp(_matrule->_rChild->_opType,"StrInflatedCopy") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"VectorCmpMasked")||
|
||||
!strcmp(_matrule->_rChild->_opType,"VectorMaskGen")||
|
||||
!strcmp(_matrule->_rChild->_opType,"VerifyVectorAlignment")||
|
||||
!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") ||
|
||||
!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true;
|
||||
else if ( is_ideal_load() == Form::idealP ) return true;
|
||||
else if ( is_ideal_store() != Form::none ) return true;
|
||||
|
||||
if (needs_base_oop_edge(globals)) return true;
|
||||
|
||||
if (is_vector()) return true;
|
||||
if (is_mach_constant()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Access instr_cost attribute or return null.
|
||||
const char* InstructForm::cost() {
|
||||
for (Attribute* cur = _attribs; cur != nullptr; cur = (Attribute*)cur->_next) {
|
||||
@ -1181,9 +1128,6 @@ const char *InstructForm::mach_base_class(FormDict &globals) const {
|
||||
}
|
||||
else if (is_mach_constant()) {
|
||||
return "MachConstantNode";
|
||||
}
|
||||
else if (captures_bottom_type(globals)) {
|
||||
return "MachTypeNode";
|
||||
} else {
|
||||
return "MachNode";
|
||||
}
|
||||
@ -4337,58 +4281,6 @@ Form::DataType MatchRule::is_ideal_load() const {
|
||||
return ideal_load;
|
||||
}
|
||||
|
||||
bool MatchRule::is_vector() const {
|
||||
static const char *vector_list[] = {
|
||||
"AddVB","AddVS","AddVI","AddVL","AddVHF","AddVF","AddVD",
|
||||
"SubVB","SubVS","SubVI","SubVL","SubVHF","SubVF","SubVD",
|
||||
"MulVB","MulVS","MulVI","MulVL","MulVHF","MulVF","MulVD",
|
||||
"DivVHF","DivVF","DivVD",
|
||||
"AbsVB","AbsVS","AbsVI","AbsVL","AbsVF","AbsVD",
|
||||
"NegVF","NegVD","NegVI","NegVL",
|
||||
"SqrtVD","SqrtVF","SqrtVHF",
|
||||
"AndV" ,"XorV" ,"OrV",
|
||||
"MaxV", "MinV", "MinVHF", "MaxVHF", "UMinV", "UMaxV",
|
||||
"CompressV", "ExpandV", "CompressM", "CompressBitsV", "ExpandBitsV",
|
||||
"AddReductionVI", "AddReductionVL",
|
||||
"AddReductionVHF", "AddReductionVF", "AddReductionVD",
|
||||
"MulReductionVI", "MulReductionVL",
|
||||
"MulReductionVHF", "MulReductionVF", "MulReductionVD",
|
||||
"MaxReductionV", "MinReductionV",
|
||||
"AndReductionV", "OrReductionV", "XorReductionV",
|
||||
"MulAddVS2VI", "MacroLogicV",
|
||||
"LShiftCntV","RShiftCntV",
|
||||
"LShiftVB","LShiftVS","LShiftVI","LShiftVL",
|
||||
"RShiftVB","RShiftVS","RShiftVI","RShiftVL",
|
||||
"URShiftVB","URShiftVS","URShiftVI","URShiftVL",
|
||||
"Replicate","ReverseV","ReverseBytesV",
|
||||
"RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector",
|
||||
"LoadVectorGather", "StoreVectorScatter", "LoadVectorGatherMasked", "StoreVectorScatterMasked",
|
||||
"SelectFromTwoVector", "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",
|
||||
"VectorRearrange", "VectorLoadShuffle", "VectorLoadConst",
|
||||
"VectorCastB2X", "VectorCastS2X", "VectorCastI2X",
|
||||
"VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F",
|
||||
"VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X",
|
||||
"VectorMaskWrapper","VectorMaskCmp","VectorReinterpret","LoadVectorMasked","StoreVectorMasked",
|
||||
"FmaVD", "FmaVF", "FmaVHF", "PopCountVI", "PopCountVL", "PopulateIndex", "VectorLongToMask",
|
||||
"CountLeadingZerosV", "CountTrailingZerosV", "SignumVF", "SignumVD", "SaturatingAddV", "SaturatingSubV",
|
||||
// Next are vector mask ops.
|
||||
"MaskAll", "AndVMask", "OrVMask", "XorVMask", "VectorMaskCast",
|
||||
"RoundVF", "RoundVD",
|
||||
// Next are not supported currently.
|
||||
"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",
|
||||
"ExtractB","ExtractUB","ExtractC","ExtractS","ExtractI","ExtractL","ExtractF","ExtractD"
|
||||
};
|
||||
int cnt = sizeof(vector_list)/sizeof(char*);
|
||||
if (_rChild) {
|
||||
const char *opType = _rChild->_opType;
|
||||
for (int i=0; i<cnt; i++)
|
||||
if (strcmp(opType,vector_list[i]) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MatchRule::skip_antidep_check() const {
|
||||
// Some loads operate on what is effectively immutable memory so we
|
||||
// should skip the anti dep computations. For some of these nodes
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -169,7 +169,6 @@ public:
|
||||
virtual bool is_ideal_safepoint() const; // node matches 'SafePoint'
|
||||
virtual bool is_ideal_nop() const; // node matches 'Nop'
|
||||
virtual bool is_ideal_control() const; // control node
|
||||
virtual bool is_vector() const; // vector instruction
|
||||
|
||||
virtual Form::CallType is_ideal_call() const; // matches ideal 'Call'
|
||||
virtual Form::DataType is_ideal_load() const; // node matches ideal 'LoadXNode'
|
||||
@ -199,11 +198,6 @@ public:
|
||||
MANY_MEMORY_OPERANDS = 999999
|
||||
};
|
||||
|
||||
|
||||
// This instruction captures the machine-independent bottom_type
|
||||
// Expected use is for pointer vs oop determination for LoadP
|
||||
virtual bool captures_bottom_type(FormDict& globals) const;
|
||||
|
||||
virtual const char *cost(); // Access ins_cost attribute
|
||||
virtual uint num_opnds(); // Count of num_opnds for MachNode class
|
||||
// Counts USE_DEF opnds twice. See also num_unique_opnds().
|
||||
@ -1065,7 +1059,6 @@ public:
|
||||
bool is_ideal_goto() const; // node matches ideal 'Goto'
|
||||
bool is_ideal_loopEnd() const; // node matches ideal 'LoopEnd'
|
||||
bool is_ideal_bool() const; // node matches ideal 'Bool'
|
||||
bool is_vector() const; // vector instruction
|
||||
Form::DataType is_ideal_load() const;// node matches ideal 'LoadXNode'
|
||||
// Should antidep checks be disabled for this rule
|
||||
// See definition of MatchRule::skip_antidep_check
|
||||
|
||||
@ -1324,11 +1324,8 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, int peephole_numb
|
||||
fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",
|
||||
inst_num, unmatched_edge);
|
||||
}
|
||||
// If new instruction captures bottom type
|
||||
if( root_form->captures_bottom_type(globals) ) {
|
||||
// Get bottom type from instruction whose result we are replacing
|
||||
fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);
|
||||
}
|
||||
// Get bottom type from instruction whose result we are replacing
|
||||
fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);
|
||||
// Define result register and result operand
|
||||
fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num);
|
||||
fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num);
|
||||
@ -1587,11 +1584,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
|
||||
fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n", cnt);
|
||||
}
|
||||
|
||||
// Fill in the bottom_type where requested
|
||||
if (node->captures_bottom_type(_globalNames) &&
|
||||
new_inst->captures_bottom_type(_globalNames)) {
|
||||
fprintf(fp, " ((MachTypeNode*)n%d)->_bottom_type = bottom_type();\n", cnt);
|
||||
}
|
||||
// Fill in the bottom_type
|
||||
fprintf(fp, " n%d->_bottom_type = bottom_type();\n", cnt);
|
||||
|
||||
const char *resultOper = new_inst->reduce_result();
|
||||
fprintf(fp," n%d->set_opnd_array(0, state->MachOperGenerator(%s));\n",
|
||||
@ -3965,13 +3959,15 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the bottom_type where requested
|
||||
if (inst->captures_bottom_type(_globalNames)) {
|
||||
if (strncmp("MachCall", inst->mach_base_class(_globalNames), strlen("MachCall")) != 0
|
||||
&& strncmp("MachIf", inst->mach_base_class(_globalNames), strlen("MachIf")) != 0) {
|
||||
fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);
|
||||
}
|
||||
// Fill in the bottom_type
|
||||
if (inst->_matrule != nullptr && strcmp(inst->_matrule->_opType, "PrefetchAllocation") == 0) {
|
||||
// Special case, with AllocatePrefetchStyle == 3, this should be Type::MEMORY, but the graph
|
||||
// seems unsound, needs further investigation
|
||||
fprintf(fp_cpp, "%s node->_bottom_type = Type::ABIO;\n", indent);
|
||||
} else {
|
||||
fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);
|
||||
}
|
||||
|
||||
if( inst->is_ideal_if() ) {
|
||||
fprintf(fp_cpp, "%s node->_prob = _leaf->as_If()->_prob;\n", indent);
|
||||
fprintf(fp_cpp, "%s node->_fcnt = _leaf->as_If()->_fcnt;\n", indent);
|
||||
@ -4026,10 +4022,8 @@ void InstructForm::define_cisc_version(ArchDesc& AD, FILE* fp_cpp) {
|
||||
fprintf(fp_cpp, "MachNode *%sNode::cisc_version(int offset) {\n", this->_ident);
|
||||
// Create the MachNode object
|
||||
fprintf(fp_cpp, " %sNode *node = new %sNode();\n", name, name);
|
||||
// Fill in the bottom_type where requested
|
||||
if ( this->captures_bottom_type(AD.globalNames()) ) {
|
||||
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
|
||||
}
|
||||
// Fill in the bottom_type
|
||||
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
|
||||
|
||||
uint cur_num_opnds = num_opnds();
|
||||
if (cur_num_opnds > 1 && cur_num_opnds != num_unique_opnds()) {
|
||||
@ -4075,10 +4069,9 @@ void InstructForm::define_short_branch_methods(ArchDesc& AD, FILE* fp_cpp) {
|
||||
fprintf(fp_cpp, " node->_prob = _prob;\n");
|
||||
fprintf(fp_cpp, " node->_fcnt = _fcnt;\n");
|
||||
}
|
||||
// Fill in the bottom_type where requested
|
||||
if ( this->captures_bottom_type(AD.globalNames()) ) {
|
||||
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
|
||||
}
|
||||
|
||||
// Fill in the bottom_type
|
||||
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
|
||||
|
||||
fprintf(fp_cpp, "\n");
|
||||
// Short branch version must use same node index for access
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1841,112 +1841,6 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||
fprintf(fp," virtual const Pipeline *pipeline() const;\n");
|
||||
}
|
||||
|
||||
// Generate virtual function for MachNodeX::bottom_type when necessary
|
||||
//
|
||||
// Note on accuracy: Pointer-types of machine nodes need to be accurate,
|
||||
// or else alias analysis on the matched graph may produce bad code.
|
||||
// Moreover, the aliasing decisions made on machine-node graph must be
|
||||
// no less accurate than those made on the ideal graph, or else the graph
|
||||
// may fail to schedule. (Reason: Memory ops which are reordered in
|
||||
// the ideal graph might look interdependent in the machine graph,
|
||||
// thereby removing degrees of scheduling freedom that the optimizer
|
||||
// assumed would be available.)
|
||||
//
|
||||
// %%% We should handle many of these cases with an explicit ADL clause:
|
||||
// instruct foo() %{ ... bottom_type(TypeRawPtr::BOTTOM); ... %}
|
||||
if( data_type != Form::none ) {
|
||||
// A constant's bottom_type returns a Type containing its constant value
|
||||
|
||||
// !!!!!
|
||||
// Convert all ints, floats, ... to machine-independent TypeXs
|
||||
// as is done for pointers
|
||||
//
|
||||
// Construct appropriate constant type containing the constant value.
|
||||
fprintf(fp," virtual const class Type *bottom_type() const {\n");
|
||||
switch( data_type ) {
|
||||
case Form::idealI:
|
||||
fprintf(fp," return TypeInt::make(opnd_array(1)->constant());\n");
|
||||
break;
|
||||
case Form::idealP:
|
||||
case Form::idealN:
|
||||
case Form::idealNKlass:
|
||||
fprintf(fp," return opnd_array(1)->type();\n");
|
||||
break;
|
||||
case Form::idealD:
|
||||
fprintf(fp," return TypeD::make(opnd_array(1)->constantD());\n");
|
||||
break;
|
||||
case Form::idealH:
|
||||
fprintf(fp," return TypeH::make(opnd_array(1)->constantH());\n");
|
||||
break;
|
||||
case Form::idealF:
|
||||
fprintf(fp," return TypeF::make(opnd_array(1)->constantF());\n");
|
||||
break;
|
||||
case Form::idealL:
|
||||
fprintf(fp," return TypeLong::make(opnd_array(1)->constantL());\n");
|
||||
break;
|
||||
default:
|
||||
assert( false, "Unimplemented()" );
|
||||
break;
|
||||
}
|
||||
fprintf(fp," };\n");
|
||||
}
|
||||
/* else if ( instr->_matrule && instr->_matrule->_rChild &&
|
||||
( strcmp("ConvF2I",instr->_matrule->_rChild->_opType)==0
|
||||
|| strcmp("ConvD2I",instr->_matrule->_rChild->_opType)==0 ) ) {
|
||||
// !!!!! !!!!!
|
||||
// Provide explicit bottom type for conversions to int
|
||||
// On Intel the result operand is a stackSlot, untyped.
|
||||
fprintf(fp," virtual const class Type *bottom_type() const {");
|
||||
fprintf(fp, " return TypeInt::INT;");
|
||||
fprintf(fp, " };\n");
|
||||
}*/
|
||||
else if( instr->is_ideal_copy() &&
|
||||
!strcmp(instr->_matrule->_lChild->_opType,"stackSlotP") ) {
|
||||
// !!!!!
|
||||
// Special hack for ideal Copy of pointer. Bottom type is oop or not depending on input.
|
||||
fprintf(fp," const Type *bottom_type() const { return in(1)->bottom_type(); } // Copy?\n");
|
||||
}
|
||||
else if( instr->is_ideal_loadPC() ) {
|
||||
// LoadPCNode provides the return address of a call to native code.
|
||||
// Define its bottom type to be TypeRawPtr::BOTTOM instead of TypePtr::BOTTOM
|
||||
// since it is a pointer to an internal VM location and must have a zero offset.
|
||||
// Allocation detects derived pointers, in part, by their non-zero offsets.
|
||||
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // LoadPC?\n");
|
||||
}
|
||||
else if( instr->is_ideal_box() ) {
|
||||
// BoxNode provides the address of a stack slot.
|
||||
// Define its bottom type to be TypeRawPtr::BOTTOM instead of TypePtr::BOTTOM
|
||||
// This prevents raise_above_anti_dependences from complaining. It will
|
||||
// complain if it sees that the pointer base is TypePtr::BOTTOM since
|
||||
// it doesn't understand what that might alias.
|
||||
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // Box?\n");
|
||||
}
|
||||
else if (instr->_matrule && instr->_matrule->_rChild &&
|
||||
(!strcmp(instr->_matrule->_rChild->_opType,"CMoveP") || !strcmp(instr->_matrule->_rChild->_opType,"CMoveN")) ) {
|
||||
int offset = 1;
|
||||
// Special special hack to see if the Cmp? has been incorporated in the conditional move
|
||||
MatchNode *rl = instr->_matrule->_rChild->_lChild;
|
||||
if (rl && !strcmp(rl->_opType, "Binary") && rl->_rChild && strncmp(rl->_rChild->_opType, "Cmp", 3) == 0) {
|
||||
offset = 2;
|
||||
fprintf(fp," const Type *bottom_type() const { if (req() == 3) return in(2)->bottom_type();\n\tconst Type *t = in(oper_input_base()+%d)->bottom_type(); return (req() <= oper_input_base()+%d) ? t : t->meet(in(oper_input_base()+%d)->bottom_type()); } // %s\n",
|
||||
offset, offset+1, offset+1, instr->_matrule->_rChild->_opType);
|
||||
} else {
|
||||
// Special hack for ideal CMove; ideal type depends on inputs
|
||||
fprintf(fp," const Type *bottom_type() const { const Type *t = in(oper_input_base()+%d)->bottom_type(); return (req() <= oper_input_base()+%d) ? t : t->meet(in(oper_input_base()+%d)->bottom_type()); } // %s\n",
|
||||
offset, offset+1, offset+1, instr->_matrule->_rChild->_opType);
|
||||
}
|
||||
}
|
||||
else if (instr->is_tls_instruction()) {
|
||||
// Special hack for tlsLoadP
|
||||
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // tlsLoadP\n");
|
||||
}
|
||||
else if ( instr->is_ideal_if() ) {
|
||||
fprintf(fp," const Type *bottom_type() const { return TypeTuple::IFBOTH; } // matched IfNode\n");
|
||||
}
|
||||
else if ( instr->is_ideal_membar() ) {
|
||||
fprintf(fp," const Type *bottom_type() const { return TypeTuple::MEMBAR; } // matched MemBar\n");
|
||||
}
|
||||
|
||||
// Check where 'ideal_type' must be customized
|
||||
/*
|
||||
if ( instr->_matrule && instr->_matrule->_rChild &&
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -561,7 +561,11 @@ void MachNode::dump_spec(outputStream *st) const {
|
||||
if (barrier_data() != 0) {
|
||||
st->print(" barrier(");
|
||||
BarrierSet::barrier_set()->barrier_set_c2()->dump_barrier_data(this, st);
|
||||
st->print(") ");
|
||||
st->print(")");
|
||||
}
|
||||
if (_bottom_type != nullptr) {
|
||||
st->print(" ");
|
||||
_bottom_type->dump_on(st);
|
||||
}
|
||||
}
|
||||
|
||||
@ -572,19 +576,6 @@ void MachNode::dump_format(PhaseRegAlloc *ra, outputStream *st) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
#ifndef PRODUCT
|
||||
void MachTypeNode::dump_spec(outputStream *st) const {
|
||||
MachNode::dump_spec(st);
|
||||
if (_bottom_type != nullptr) {
|
||||
_bottom_type->dump_on(st);
|
||||
} else {
|
||||
st->print(" null");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
int MachConstantNode::constant_offset() {
|
||||
// Bind the offset lazily.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -220,7 +220,7 @@ public:
|
||||
// ADLC inherit from this class.
|
||||
class MachNode : public Node {
|
||||
public:
|
||||
MachNode() : Node((uint)0), _barrier(0), _num_opnds(0), _opnds(nullptr) {
|
||||
MachNode() : Node((uint)0), _bottom_type(nullptr), _barrier(0), _num_opnds(0), _opnds(nullptr) {
|
||||
init_class_id(Class_Mach);
|
||||
}
|
||||
// Required boilerplate
|
||||
@ -282,6 +282,9 @@ public:
|
||||
// output have choices - but they must use the same choice.
|
||||
virtual uint two_adr( ) const { return 0; }
|
||||
|
||||
// Capture the type of the matched ideal node
|
||||
const Type* _bottom_type;
|
||||
|
||||
// The GC might require some barrier metadata for machine code emission.
|
||||
uint8_t _barrier;
|
||||
|
||||
@ -331,7 +334,17 @@ public:
|
||||
virtual MachNode *Expand( State *, Node_List &proj_list, Node* mem ) { return this; }
|
||||
|
||||
// Bottom_type call; value comes from operand0
|
||||
virtual const class Type *bottom_type() const { return _opnds[0]->type(); }
|
||||
virtual const Type* bottom_type() const {
|
||||
if (_bottom_type != nullptr) {
|
||||
return _bottom_type;
|
||||
}
|
||||
const Type* res = _opnds[0]->type();
|
||||
// The type system around pointers is complex, do not rely on operand type then
|
||||
assert(res != nullptr, "must be not null");
|
||||
assert(is_MachTemp() || res->isa_ptr() == nullptr, "must not be a pointer");
|
||||
return res;
|
||||
}
|
||||
|
||||
virtual uint ideal_reg() const {
|
||||
const Type *t = _opnds[0]->type();
|
||||
if (t == TypeInt::CC) {
|
||||
@ -418,20 +431,6 @@ public:
|
||||
virtual const class Type *bottom_type() const { return _opnds == nullptr ? Type::CONTROL : MachNode::bottom_type(); }
|
||||
};
|
||||
|
||||
//------------------------------MachTypeNode----------------------------
|
||||
// Machine Nodes that need to retain a known Type.
|
||||
class MachTypeNode : public MachNode {
|
||||
virtual uint size_of() const { return sizeof(*this); } // Size is bigger
|
||||
public:
|
||||
MachTypeNode( ) {}
|
||||
const Type *_bottom_type;
|
||||
|
||||
virtual const class Type *bottom_type() const { return _bottom_type; }
|
||||
#ifndef PRODUCT
|
||||
virtual void dump_spec(outputStream *st) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
//------------------------------MachBreakpointNode----------------------------
|
||||
// Machine breakpoint or interrupt Node
|
||||
class MachBreakpointNode : public MachIdealNode {
|
||||
@ -477,12 +476,12 @@ public:
|
||||
|
||||
//------------------------------MachConstantNode-------------------------------
|
||||
// Machine node that holds a constant which is stored in the constant table.
|
||||
class MachConstantNode : public MachTypeNode {
|
||||
class MachConstantNode : public MachNode {
|
||||
protected:
|
||||
ConstantTable::Constant _constant; // This node's constant.
|
||||
|
||||
public:
|
||||
MachConstantNode() : MachTypeNode() {
|
||||
MachConstantNode() : MachNode() {
|
||||
init_class_id(Class_MachConstant);
|
||||
}
|
||||
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
class Compile;
|
||||
class Node;
|
||||
class MachNode;
|
||||
class MachTypeNode;
|
||||
class MachOper;
|
||||
|
||||
//---------------------------Matcher-------------------------------------------
|
||||
|
||||
161
test/hotspot/jtreg/compiler/types/TestCMovePMachType.java
Normal file
161
test/hotspot/jtreg/compiler/types/TestCMovePMachType.java
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package compiler.types;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8379667
|
||||
* @summary C2 crashes due to deep recursion in cmovP_regNode::bottom_type
|
||||
* @run main/othervm -Xbatch -XX:CompileCommand=memlimit,${test.main.class}::test,50M~crash ${test.main.class}
|
||||
*/
|
||||
public class TestCMovePMachType {
|
||||
interface I0 {}
|
||||
interface I1 {}
|
||||
interface I2 {}
|
||||
interface I3 {}
|
||||
interface I4 {}
|
||||
interface I5 {}
|
||||
interface I6 {}
|
||||
interface I7 {}
|
||||
interface I8 {}
|
||||
interface I9 {}
|
||||
interface I10 {}
|
||||
interface I11 {}
|
||||
interface I12 {}
|
||||
interface I13 {}
|
||||
interface I14 {}
|
||||
interface I15 {}
|
||||
interface I16 {}
|
||||
interface I17 {}
|
||||
interface I18 {}
|
||||
interface I19 {}
|
||||
interface IA {}
|
||||
interface IB {}
|
||||
|
||||
static class P implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19 {
|
||||
int v;
|
||||
}
|
||||
|
||||
static class A extends P implements IA {}
|
||||
static class B extends P implements IB {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
A a = new A();
|
||||
B b = new B();
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
test(a, b, false, false);
|
||||
test(a, b, false, true);
|
||||
test(a, b, true, false);
|
||||
test(a, b, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// This method is compiled into a giant chain of CMovePs, which leads to a deep recursion when
|
||||
// invoking Node::bottom_type on the corresponding MachNodes
|
||||
private static int test(A p1, B p2, boolean b1, boolean b2) {
|
||||
P p = b1 ? p1 : p2;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
p = b2 ? p : p2;
|
||||
p = b1 ? p : p1;
|
||||
int r = p.v;
|
||||
p.v = 0;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user