diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index 26243a1e4e8..49696bc63e9 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,21 +29,21 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=8.2.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26/sapmachine-jdk-26_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=f5e7279cb0e456b471823fb258d5ae27af2077e27d03d202b3efefc3d85a8796 +LINUX_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26.0.1/sapmachine-jdk-26.0.1_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=4422a642da9764419477a80bea1d614391c40b71060f0de1610467d4c70807a0 ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz -ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26/sapmachine-jdk-26_linux-x64-musl_bin.tar.gz -ALPINE_LINUX_X64_BOOT_JDK_SHA256=fed54c7ecfa6b66900a28dbb358e942b4699a3234beb826b890885c3501b0ff4 +ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26.0.1/sapmachine-jdk-26.0.1_linux-x64-musl_bin.tar.gz +ALPINE_LINUX_X64_BOOT_JDK_SHA256=58dad03eaf3ec5d40bc2f94d8c1bd5f6e47c650d2d6b52fe3572926285f62e04 MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26/sapmachine-jdk-26_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=86be6e6cf1b13f0798dc3fe3667b0264ea697aae67c62de5577dcedd1e08897e +MACOS_AARCH64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26.0.1/sapmachine-jdk-26.0.1_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=3663faab53b08e20c87112166bae3399340ead434d8e3a58cbb2a28ef1e0c584 MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk26/c3cc523845074aa0af4f5e1e1ed4151d/35/GPL/openjdk-26_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=8642b89d889c14ede2c446fd5bbe3621c8a3082e3df02013fd1658e39f52929a +MACOS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin26-binaries/releases/download/jdk-26.0.1%2B8/OpenJDK26U-jdk_x64_mac_hotspot_26.0.1_8.tar.gz +MACOS_X64_BOOT_JDK_SHA256=032df492c8749864ee8b135e3d0ea5a17ef5c847309d5fdf8f1dd55e246b8319 WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26/sapmachine-jdk-26_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=3387870d83372f5309f503c00e97d09d9f40f052051c6121a6708408be4793f8 +WINDOWS_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-26.0.1/sapmachine-jdk-26.0.1_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=1b7ff2fe4bb201047a7e43b83c318b9e0bf53bd8a9ea8e8ac95df2917ff0cbd8 diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 79779782c2a..5802217c1c1 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -453,6 +453,14 @@ 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) { @@ -759,6 +767,51 @@ 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) { @@ -1128,6 +1181,9 @@ 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"; } @@ -4281,6 +4337,58 @@ 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; iadd_req(inst%d->in(%d)); // unmatched ideal edge\n", inst_num, unmatched_edge); } - // Get bottom type from instruction whose result we are replacing - fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num); + // 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); + } // 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); @@ -1584,8 +1587,11 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { fprintf(fp, " ((MachIfNode*)n%d)->_fcnt = _fcnt;\n", cnt); } - // Fill in the bottom_type - fprintf(fp, " n%d->_bottom_type = bottom_type();\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); + } const char *resultOper = new_inst->reduce_result(); 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 } } - // 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); + // 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); + } } - 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); @@ -4022,8 +4026,10 @@ 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 - fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n"); + // Fill in the bottom_type where requested + if ( this->captures_bottom_type(AD.globalNames()) ) { + 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()) { @@ -4069,9 +4075,10 @@ 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 - fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n"); + // Fill in the bottom_type where requested + if ( this->captures_bottom_type(AD.globalNames()) ) { + fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n"); + } fprintf(fp_cpp, "\n"); // Short branch version must use same node index for access diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index f7389b5a1b1..6cb82f4df7f 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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,6 +1841,112 @@ 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 && diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index c35861df735..ec861865ff5 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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,11 +561,7 @@ 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(")"); - } - if (_bottom_type != nullptr) { - st->print(" "); - _bottom_type->dump_on(st); + st->print(") "); } } @@ -576,6 +572,19 @@ 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. diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index daa2aad960a..b60313b7f75 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ class MachOper : public ResourceObj { // ADLC inherit from this class. class MachNode : public Node { public: - MachNode() : Node((uint)0), _bottom_type(nullptr), _barrier(0), _num_opnds(0), _opnds(nullptr) { + MachNode() : Node((uint)0), _barrier(0), _num_opnds(0), _opnds(nullptr) { init_class_id(Class_Mach); } // Required boilerplate @@ -282,9 +282,6 @@ class MachNode : public Node { // 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; @@ -334,17 +331,7 @@ class MachNode : public Node { virtual MachNode *Expand( State *, Node_List &proj_list, Node* mem ) { return this; } // Bottom_type call; value comes from operand0 - 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 const class Type *bottom_type() const { return _opnds[0]->type(); } virtual uint ideal_reg() const { const Type *t = _opnds[0]->type(); if (t == TypeInt::CC) { @@ -431,6 +418,20 @@ class MachIdealNode : public MachNode { 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 { @@ -476,12 +477,12 @@ class MachConstantBaseNode : public MachIdealNode { //------------------------------MachConstantNode------------------------------- // Machine node that holds a constant which is stored in the constant table. -class MachConstantNode : public MachNode { +class MachConstantNode : public MachTypeNode { protected: ConstantTable::Constant _constant; // This node's constant. public: - MachConstantNode() : MachNode() { + MachConstantNode() : MachTypeNode() { init_class_id(Class_MachConstant); } diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index 31f4a782247..a3d0f8e7d6c 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -38,6 +38,7 @@ class Compile; class Node; class MachNode; +class MachTypeNode; class MachOper; //---------------------------Matcher------------------------------------------- diff --git a/test/hotspot/jtreg/compiler/types/TestCMovePMachType.java b/test/hotspot/jtreg/compiler/types/TestCMovePMachType.java deleted file mode 100644 index 48069fd900e..00000000000 --- a/test/hotspot/jtreg/compiler/types/TestCMovePMachType.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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; - } -}