Skip to content

Commit 93a3d4a

Browse files
committed
8384281: [BACKOUT] C2: Deep recursion with cmovP_regNode::bottom_type
Reviewed-by: mbaesken, rrich, dbriemann
1 parent d204824 commit 93a3d4a

8 files changed

Lines changed: 282 additions & 204 deletions

File tree

src/hotspot/share/adlc/formssel.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,14 @@ Form::DataType InstructForm::is_ideal_store() const {
453453
return _matrule->is_ideal_store();
454454
}
455455

456+
// Return 'true' if this instruction matches an ideal vector node
457+
bool InstructForm::is_vector() const {
458+
if( _matrule == nullptr ) return false;
459+
460+
return _matrule->is_vector();
461+
}
462+
463+
456464
// Return the input register that must match the output register
457465
// If this is not required, return 0
458466
uint InstructForm::two_address(FormDict &globals) {
@@ -759,6 +767,51 @@ int InstructForm::memory_operand(FormDict &globals) const {
759767
return NO_MEMORY_OPERAND;
760768
}
761769

770+
// This instruction captures the machine-independent bottom_type
771+
// Expected use is for pointer vs oop determination for LoadP
772+
bool InstructForm::captures_bottom_type(FormDict &globals) const {
773+
if (_matrule && _matrule->_rChild &&
774+
(!strcmp(_matrule->_rChild->_opType,"CastPP") || // new result type
775+
!strcmp(_matrule->_rChild->_opType,"CastDD") ||
776+
!strcmp(_matrule->_rChild->_opType,"CastFF") ||
777+
!strcmp(_matrule->_rChild->_opType,"CastII") ||
778+
!strcmp(_matrule->_rChild->_opType,"CastLL") ||
779+
!strcmp(_matrule->_rChild->_opType,"CastVV") ||
780+
!strcmp(_matrule->_rChild->_opType,"CastX2P") || // new result type
781+
!strcmp(_matrule->_rChild->_opType,"DecodeN") ||
782+
!strcmp(_matrule->_rChild->_opType,"EncodeP") ||
783+
!strcmp(_matrule->_rChild->_opType,"DecodeNKlass") ||
784+
!strcmp(_matrule->_rChild->_opType,"EncodePKlass") ||
785+
!strcmp(_matrule->_rChild->_opType,"LoadN") ||
786+
!strcmp(_matrule->_rChild->_opType,"LoadNKlass") ||
787+
!strcmp(_matrule->_rChild->_opType,"CreateEx") || // type of exception
788+
!strcmp(_matrule->_rChild->_opType,"CheckCastPP") ||
789+
!strcmp(_matrule->_rChild->_opType,"GetAndSetP") ||
790+
!strcmp(_matrule->_rChild->_opType,"GetAndSetN") ||
791+
!strcmp(_matrule->_rChild->_opType,"RotateLeft") ||
792+
!strcmp(_matrule->_rChild->_opType,"RotateRight") ||
793+
#if INCLUDE_SHENANDOAHGC
794+
!strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") ||
795+
!strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN") ||
796+
#endif
797+
!strcmp(_matrule->_rChild->_opType,"StrInflatedCopy") ||
798+
!strcmp(_matrule->_rChild->_opType,"VectorCmpMasked")||
799+
!strcmp(_matrule->_rChild->_opType,"VectorMaskGen")||
800+
!strcmp(_matrule->_rChild->_opType,"VerifyVectorAlignment")||
801+
!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") ||
802+
!strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true;
803+
else if ( is_ideal_load() == Form::idealP ) return true;
804+
else if ( is_ideal_store() != Form::none ) return true;
805+
806+
if (needs_base_oop_edge(globals)) return true;
807+
808+
if (is_vector()) return true;
809+
if (is_mach_constant()) return true;
810+
811+
return false;
812+
}
813+
814+
762815
// Access instr_cost attribute or return null.
763816
const char* InstructForm::cost() {
764817
for (Attribute* cur = _attribs; cur != nullptr; cur = (Attribute*)cur->_next) {
@@ -1128,6 +1181,9 @@ const char *InstructForm::mach_base_class(FormDict &globals) const {
11281181
}
11291182
else if (is_mach_constant()) {
11301183
return "MachConstantNode";
1184+
}
1185+
else if (captures_bottom_type(globals)) {
1186+
return "MachTypeNode";
11311187
} else {
11321188
return "MachNode";
11331189
}
@@ -4281,6 +4337,58 @@ Form::DataType MatchRule::is_ideal_load() const {
42814337
return ideal_load;
42824338
}
42834339

4340+
bool MatchRule::is_vector() const {
4341+
static const char *vector_list[] = {
4342+
"AddVB","AddVS","AddVI","AddVL","AddVHF","AddVF","AddVD",
4343+
"SubVB","SubVS","SubVI","SubVL","SubVHF","SubVF","SubVD",
4344+
"MulVB","MulVS","MulVI","MulVL","MulVHF","MulVF","MulVD",
4345+
"DivVHF","DivVF","DivVD",
4346+
"AbsVB","AbsVS","AbsVI","AbsVL","AbsVF","AbsVD",
4347+
"NegVF","NegVD","NegVI","NegVL",
4348+
"SqrtVD","SqrtVF","SqrtVHF",
4349+
"AndV" ,"XorV" ,"OrV",
4350+
"MaxV", "MinV", "MinVHF", "MaxVHF", "UMinV", "UMaxV",
4351+
"CompressV", "ExpandV", "CompressM", "CompressBitsV", "ExpandBitsV",
4352+
"AddReductionVI", "AddReductionVL",
4353+
"AddReductionVHF", "AddReductionVF", "AddReductionVD",
4354+
"MulReductionVI", "MulReductionVL",
4355+
"MulReductionVHF", "MulReductionVF", "MulReductionVD",
4356+
"MaxReductionV", "MinReductionV",
4357+
"AndReductionV", "OrReductionV", "XorReductionV",
4358+
"MulAddVS2VI", "MacroLogicV",
4359+
"LShiftCntV","RShiftCntV",
4360+
"LShiftVB","LShiftVS","LShiftVI","LShiftVL",
4361+
"RShiftVB","RShiftVS","RShiftVI","RShiftVL",
4362+
"URShiftVB","URShiftVS","URShiftVI","URShiftVL",
4363+
"Replicate","ReverseV","ReverseBytesV",
4364+
"RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector",
4365+
"LoadVectorGather", "StoreVectorScatter", "LoadVectorGatherMasked", "StoreVectorScatterMasked",
4366+
"SelectFromTwoVector", "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",
4367+
"VectorRearrange", "VectorLoadShuffle", "VectorLoadConst",
4368+
"VectorCastB2X", "VectorCastS2X", "VectorCastI2X",
4369+
"VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F",
4370+
"VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X",
4371+
"VectorMaskWrapper","VectorMaskCmp","VectorReinterpret","LoadVectorMasked","StoreVectorMasked",
4372+
"FmaVD", "FmaVF", "FmaVHF", "PopCountVI", "PopCountVL", "PopulateIndex", "VectorLongToMask",
4373+
"CountLeadingZerosV", "CountTrailingZerosV", "SignumVF", "SignumVD", "SaturatingAddV", "SaturatingSubV",
4374+
// Next are vector mask ops.
4375+
"MaskAll", "AndVMask", "OrVMask", "XorVMask", "VectorMaskCast",
4376+
"RoundVF", "RoundVD",
4377+
// Next are not supported currently.
4378+
"PackB","PackS","PackI","PackL","PackF","PackD","Pack2L","Pack2D",
4379+
"ExtractB","ExtractUB","ExtractC","ExtractS","ExtractI","ExtractL","ExtractF","ExtractD"
4380+
};
4381+
int cnt = sizeof(vector_list)/sizeof(char*);
4382+
if (_rChild) {
4383+
const char *opType = _rChild->_opType;
4384+
for (int i=0; i<cnt; i++)
4385+
if (strcmp(opType,vector_list[i]) == 0)
4386+
return true;
4387+
}
4388+
return false;
4389+
}
4390+
4391+
42844392
bool MatchRule::skip_antidep_check() const {
42854393
// Some loads operate on what is effectively immutable memory so we
42864394
// should skip the anti dep computations. For some of these nodes

src/hotspot/share/adlc/formssel.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -169,6 +169,7 @@ class InstructForm : public Form {
169169
virtual bool is_ideal_safepoint() const; // node matches 'SafePoint'
170170
virtual bool is_ideal_nop() const; // node matches 'Nop'
171171
virtual bool is_ideal_control() const; // control node
172+
virtual bool is_vector() const; // vector instruction
172173

173174
virtual Form::CallType is_ideal_call() const; // matches ideal 'Call'
174175
virtual Form::DataType is_ideal_load() const; // node matches ideal 'LoadXNode'
@@ -198,6 +199,11 @@ class InstructForm : public Form {
198199
MANY_MEMORY_OPERANDS = 999999
199200
};
200201

202+
203+
// This instruction captures the machine-independent bottom_type
204+
// Expected use is for pointer vs oop determination for LoadP
205+
virtual bool captures_bottom_type(FormDict& globals) const;
206+
201207
virtual const char *cost(); // Access ins_cost attribute
202208
virtual uint num_opnds(); // Count of num_opnds for MachNode class
203209
// Counts USE_DEF opnds twice. See also num_unique_opnds().
@@ -1059,6 +1065,7 @@ class MatchRule : public MatchNode {
10591065
bool is_ideal_goto() const; // node matches ideal 'Goto'
10601066
bool is_ideal_loopEnd() const; // node matches ideal 'LoopEnd'
10611067
bool is_ideal_bool() const; // node matches ideal 'Bool'
1068+
bool is_vector() const; // vector instruction
10621069
Form::DataType is_ideal_load() const;// node matches ideal 'LoadXNode'
10631070
// Should antidep checks be disabled for this rule
10641071
// See definition of MatchRule::skip_antidep_check

src/hotspot/share/adlc/output_c.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,8 +1324,11 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, int peephole_numb
13241324
fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",
13251325
inst_num, unmatched_edge);
13261326
}
1327-
// Get bottom type from instruction whose result we are replacing
1328-
fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);
1327+
// If new instruction captures bottom type
1328+
if( root_form->captures_bottom_type(globals) ) {
1329+
// Get bottom type from instruction whose result we are replacing
1330+
fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);
1331+
}
13291332
// Define result register and result operand
13301333
fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num);
13311334
fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num);
@@ -1584,8 +1587,11 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
15841587
fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n", cnt);
15851588
}
15861589

1587-
// Fill in the bottom_type
1588-
fprintf(fp, " n%d->_bottom_type = bottom_type();\n", cnt);
1590+
// Fill in the bottom_type where requested
1591+
if (node->captures_bottom_type(_globalNames) &&
1592+
new_inst->captures_bottom_type(_globalNames)) {
1593+
fprintf(fp, " ((MachTypeNode*)n%d)->_bottom_type = bottom_type();\n", cnt);
1594+
}
15891595

15901596
const char *resultOper = new_inst->reduce_result();
15911597
fprintf(fp," n%d->set_opnd_array(0, state->MachOperGenerator(%s));\n",
@@ -3959,15 +3965,13 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden
39593965
}
39603966
}
39613967

3962-
// Fill in the bottom_type
3963-
if (inst->_matrule != nullptr && strcmp(inst->_matrule->_opType, "PrefetchAllocation") == 0) {
3964-
// Special case, with AllocatePrefetchStyle == 3, this should be Type::MEMORY, but the graph
3965-
// seems unsound, needs further investigation
3966-
fprintf(fp_cpp, "%s node->_bottom_type = Type::ABIO;\n", indent);
3967-
} else {
3968-
fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);
3968+
// Fill in the bottom_type where requested
3969+
if (inst->captures_bottom_type(_globalNames)) {
3970+
if (strncmp("MachCall", inst->mach_base_class(_globalNames), strlen("MachCall")) != 0
3971+
&& strncmp("MachIf", inst->mach_base_class(_globalNames), strlen("MachIf")) != 0) {
3972+
fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);
3973+
}
39693974
}
3970-
39713975
if( inst->is_ideal_if() ) {
39723976
fprintf(fp_cpp, "%s node->_prob = _leaf->as_If()->_prob;\n", indent);
39733977
fprintf(fp_cpp, "%s node->_fcnt = _leaf->as_If()->_fcnt;\n", indent);
@@ -4022,8 +4026,10 @@ void InstructForm::define_cisc_version(ArchDesc& AD, FILE* fp_cpp) {
40224026
fprintf(fp_cpp, "MachNode *%sNode::cisc_version(int offset) {\n", this->_ident);
40234027
// Create the MachNode object
40244028
fprintf(fp_cpp, " %sNode *node = new %sNode();\n", name, name);
4025-
// Fill in the bottom_type
4026-
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
4029+
// Fill in the bottom_type where requested
4030+
if ( this->captures_bottom_type(AD.globalNames()) ) {
4031+
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
4032+
}
40274033

40284034
uint cur_num_opnds = num_opnds();
40294035
if (cur_num_opnds > 1 && cur_num_opnds != num_unique_opnds()) {
@@ -4069,9 +4075,10 @@ void InstructForm::define_short_branch_methods(ArchDesc& AD, FILE* fp_cpp) {
40694075
fprintf(fp_cpp, " node->_prob = _prob;\n");
40704076
fprintf(fp_cpp, " node->_fcnt = _fcnt;\n");
40714077
}
4072-
4073-
// Fill in the bottom_type
4074-
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
4078+
// Fill in the bottom_type where requested
4079+
if ( this->captures_bottom_type(AD.globalNames()) ) {
4080+
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
4081+
}
40754082

40764083
fprintf(fp_cpp, "\n");
40774084
// Short branch version must use same node index for access

src/hotspot/share/adlc/output_h.cpp

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1841,6 +1841,112 @@ void ArchDesc::declareClasses(FILE *fp) {
18411841
fprintf(fp," virtual const Pipeline *pipeline() const;\n");
18421842
}
18431843

1844+
// Generate virtual function for MachNodeX::bottom_type when necessary
1845+
//
1846+
// Note on accuracy: Pointer-types of machine nodes need to be accurate,
1847+
// or else alias analysis on the matched graph may produce bad code.
1848+
// Moreover, the aliasing decisions made on machine-node graph must be
1849+
// no less accurate than those made on the ideal graph, or else the graph
1850+
// may fail to schedule. (Reason: Memory ops which are reordered in
1851+
// the ideal graph might look interdependent in the machine graph,
1852+
// thereby removing degrees of scheduling freedom that the optimizer
1853+
// assumed would be available.)
1854+
//
1855+
// %%% We should handle many of these cases with an explicit ADL clause:
1856+
// instruct foo() %{ ... bottom_type(TypeRawPtr::BOTTOM); ... %}
1857+
if( data_type != Form::none ) {
1858+
// A constant's bottom_type returns a Type containing its constant value
1859+
1860+
// !!!!!
1861+
// Convert all ints, floats, ... to machine-independent TypeXs
1862+
// as is done for pointers
1863+
//
1864+
// Construct appropriate constant type containing the constant value.
1865+
fprintf(fp," virtual const class Type *bottom_type() const {\n");
1866+
switch( data_type ) {
1867+
case Form::idealI:
1868+
fprintf(fp," return TypeInt::make(opnd_array(1)->constant());\n");
1869+
break;
1870+
case Form::idealP:
1871+
case Form::idealN:
1872+
case Form::idealNKlass:
1873+
fprintf(fp," return opnd_array(1)->type();\n");
1874+
break;
1875+
case Form::idealD:
1876+
fprintf(fp," return TypeD::make(opnd_array(1)->constantD());\n");
1877+
break;
1878+
case Form::idealH:
1879+
fprintf(fp," return TypeH::make(opnd_array(1)->constantH());\n");
1880+
break;
1881+
case Form::idealF:
1882+
fprintf(fp," return TypeF::make(opnd_array(1)->constantF());\n");
1883+
break;
1884+
case Form::idealL:
1885+
fprintf(fp," return TypeLong::make(opnd_array(1)->constantL());\n");
1886+
break;
1887+
default:
1888+
assert( false, "Unimplemented()" );
1889+
break;
1890+
}
1891+
fprintf(fp," };\n");
1892+
}
1893+
/* else if ( instr->_matrule && instr->_matrule->_rChild &&
1894+
( strcmp("ConvF2I",instr->_matrule->_rChild->_opType)==0
1895+
|| strcmp("ConvD2I",instr->_matrule->_rChild->_opType)==0 ) ) {
1896+
// !!!!! !!!!!
1897+
// Provide explicit bottom type for conversions to int
1898+
// On Intel the result operand is a stackSlot, untyped.
1899+
fprintf(fp," virtual const class Type *bottom_type() const {");
1900+
fprintf(fp, " return TypeInt::INT;");
1901+
fprintf(fp, " };\n");
1902+
}*/
1903+
else if( instr->is_ideal_copy() &&
1904+
!strcmp(instr->_matrule->_lChild->_opType,"stackSlotP") ) {
1905+
// !!!!!
1906+
// Special hack for ideal Copy of pointer. Bottom type is oop or not depending on input.
1907+
fprintf(fp," const Type *bottom_type() const { return in(1)->bottom_type(); } // Copy?\n");
1908+
}
1909+
else if( instr->is_ideal_loadPC() ) {
1910+
// LoadPCNode provides the return address of a call to native code.
1911+
// Define its bottom type to be TypeRawPtr::BOTTOM instead of TypePtr::BOTTOM
1912+
// since it is a pointer to an internal VM location and must have a zero offset.
1913+
// Allocation detects derived pointers, in part, by their non-zero offsets.
1914+
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // LoadPC?\n");
1915+
}
1916+
else if( instr->is_ideal_box() ) {
1917+
// BoxNode provides the address of a stack slot.
1918+
// Define its bottom type to be TypeRawPtr::BOTTOM instead of TypePtr::BOTTOM
1919+
// This prevents raise_above_anti_dependences from complaining. It will
1920+
// complain if it sees that the pointer base is TypePtr::BOTTOM since
1921+
// it doesn't understand what that might alias.
1922+
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // Box?\n");
1923+
}
1924+
else if (instr->_matrule && instr->_matrule->_rChild &&
1925+
(!strcmp(instr->_matrule->_rChild->_opType,"CMoveP") || !strcmp(instr->_matrule->_rChild->_opType,"CMoveN")) ) {
1926+
int offset = 1;
1927+
// Special special hack to see if the Cmp? has been incorporated in the conditional move
1928+
MatchNode *rl = instr->_matrule->_rChild->_lChild;
1929+
if (rl && !strcmp(rl->_opType, "Binary") && rl->_rChild && strncmp(rl->_rChild->_opType, "Cmp", 3) == 0) {
1930+
offset = 2;
1931+
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",
1932+
offset, offset+1, offset+1, instr->_matrule->_rChild->_opType);
1933+
} else {
1934+
// Special hack for ideal CMove; ideal type depends on inputs
1935+
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",
1936+
offset, offset+1, offset+1, instr->_matrule->_rChild->_opType);
1937+
}
1938+
}
1939+
else if (instr->is_tls_instruction()) {
1940+
// Special hack for tlsLoadP
1941+
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // tlsLoadP\n");
1942+
}
1943+
else if ( instr->is_ideal_if() ) {
1944+
fprintf(fp," const Type *bottom_type() const { return TypeTuple::IFBOTH; } // matched IfNode\n");
1945+
}
1946+
else if ( instr->is_ideal_membar() ) {
1947+
fprintf(fp," const Type *bottom_type() const { return TypeTuple::MEMBAR; } // matched MemBar\n");
1948+
}
1949+
18441950
// Check where 'ideal_type' must be customized
18451951
/*
18461952
if ( instr->_matrule && instr->_matrule->_rChild &&

0 commit comments

Comments
 (0)