8379667: C2: Deep recursion with cmovP_regNode::bottom_type

Reviewed-by: aseoane, dlong
This commit is contained in:
Quan Anh Mai 2026-05-06 11:14:44 +00:00
parent c53a98ce9e
commit f5624e65ed
8 changed files with 204 additions and 282 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,6 @@
class Compile;
class Node;
class MachNode;
class MachTypeNode;
class MachOper;
//---------------------------Matcher-------------------------------------------

View 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;
}
}