diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index d7d4c5b60ed7f..a16e5f23ed954 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -32,6 +32,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "opto/phasetype.hpp" +#include "opto/traceAutoVectorizationTag.hpp" #include "runtime/globals_extension.hpp" CompilerDirectives::CompilerDirectives() : _next(nullptr), _match(nullptr), _ref_count(0) { @@ -300,7 +301,8 @@ void DirectiveSet::init_control_intrinsic() { DirectiveSet::DirectiveSet(CompilerDirectives* d) : _inlinematchers(nullptr), _directive(d), - _ideal_phase_name_set(PHASE_NUM_TYPES, mtCompiler) + _ideal_phase_name_set(PHASE_NUM_TYPES, mtCompiler), + _trace_auto_vectorization_tags(TRACE_AUTO_VECTORIZATION_TAG_NUM, mtCompiler) { #define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; compilerdirectives_common_flags(init_defaults_definition) @@ -433,6 +435,16 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle // Parse PrintIdealPhaseName and create a lookup set #ifndef PRODUCT #ifdef COMPILER2 + if (!_modified[TraceAutoVectorizationIndex]) { + // Parse ccstr and create mask + ccstrlist option; + if (CompilerOracle::has_option_value(method, CompileCommand::TraceAutoVectorization, option)) { + TraceAutoVectorizationTagValidator validator(option, false); + if (validator.is_valid()) { + set.cloned()->set_trace_auto_vectorization_tags(validator.tags()); + } + } + } if (!_modified[PrintIdealPhaseIndex]) { // Parse ccstr and create set ccstrlist option; diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index 4c9b51724f9a3..747c878181751 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -87,10 +87,10 @@ NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel)) \ - cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \ cflags(IncrementalInlineForceCleanup, bool, IncrementalInlineForceCleanup, IncrementalInlineForceCleanup) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #define compilerdirectives_c2_string_flags(cflags) \ +NOT_PRODUCT(cflags(TraceAutoVectorization, ccstrlist, "", TraceAutoVectorization)) \ NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) #else #define compilerdirectives_c2_other_flags(cflags) @@ -131,6 +131,7 @@ class DirectiveSet : public CHeapObj { CompilerDirectives* _directive; TriBoolArray<(size_t)vmIntrinsics::number_of_intrinsics(), int> _intrinsic_control_words; CHeapBitMap _ideal_phase_name_set; + CHeapBitMap _trace_auto_vectorization_tags; public: DirectiveSet(CompilerDirectives* directive); @@ -205,6 +206,12 @@ void set_##name(void* value) { \ bool should_print_phase(const CompilerPhaseType cpt) const { return _ideal_phase_name_set.at(cpt); }; + void set_trace_auto_vectorization_tags(const CHeapBitMap& tags) { + _trace_auto_vectorization_tags.set_from(tags); + }; + const CHeapBitMap& trace_auto_vectorization_tags() { + return _trace_auto_vectorization_tags; + }; void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } } diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 66eea29fcc136..089fc5a4d995e 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -35,6 +35,7 @@ #include "oops/method.inline.hpp" #include "oops/symbol.hpp" #include "opto/phasetype.hpp" +#include "opto/traceAutoVectorizationTag.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" @@ -775,8 +776,14 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, jio_snprintf(errorbuf, buf_size, "Unrecognized intrinsic detected in %s: %s", option2name(option), validator.what()); } } -#ifndef PRODUCT - else if (option == CompileCommand::PrintIdealPhase) { +#if !defined(PRODUCT) && defined(COMPILER2) + else if (option == CompileCommand::TraceAutoVectorization) { + TraceAutoVectorizationTagValidator validator(value, true); + + if (!validator.is_valid()) { + jio_snprintf(errorbuf, buf_size, "Unrecognized tag name in %s: %s", option2name(option), validator.what()); + } + } else if (option == CompileCommand::PrintIdealPhase) { PhaseNameValidator validator(value); if (!validator.is_valid()) { diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index be1a270f3c957..192e292d35a2b 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -86,8 +86,8 @@ NOT_PRODUCT(option(TraceEscapeAnalysis, "TraceEscapeAnalysis", Bool)) \ NOT_PRODUCT(option(PrintIdeal, "PrintIdeal", Bool)) \ NOT_PRODUCT(option(PrintIdealPhase, "PrintIdealPhase", Ccstrlist)) \ NOT_PRODUCT(option(IGVPrintLevel, "IGVPrintLevel", Intx)) \ +NOT_PRODUCT(option(TraceAutoVectorization, "TraceAutoVectorization", Ccstrlist)) \ option(Vectorize, "Vectorize", Bool) \ - option(VectorizeDebug, "VectorizeDebug", Uintx) \ option(CloneMapDebug, "CloneMapDebug", Bool) \ option(IncrementalInlineForceCleanup, "IncrementalInlineForceCleanup", Bool) \ option(MaxNodeLimit, "MaxNodeLimit", Intx) \ diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index 60955615133e2..5501490028349 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -28,6 +28,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "opto/phasetype.hpp" +#include "opto/traceAutoVectorizationTag.hpp" #include "runtime/os.hpp" #include @@ -335,6 +336,17 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti if (!valid) { error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what()); } + } +#if !defined(PRODUCT) && defined(COMPILER2) + else if (strncmp(option_key->name, "TraceAutoVectorization", 22) == 0) { + TraceAutoVectorizationTagValidator validator(s, false); + + valid = validator.is_valid(); + if (valid) { + set->set_trace_auto_vectorization_tags(validator.tags()); + } else { + error(VALUE_ERROR, "Unrecognized tag name detected in TraceAutoVectorization: %s", validator.what()); + } } else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) { PhaseNameValidator validator(s); @@ -345,6 +357,7 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti error(VALUE_ERROR, "Unrecognized phase name detected in PrintIdealPhase: %s", validator.what()); } } +#endif if (!valid) { FREE_C_HEAP_ARRAY(char, s); diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 43a6491fee598..fc9a834e6f815 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -26,6 +26,7 @@ #define SHARE_OPTO_PHASETYPE_HPP #include "utilities/bitMap.inline.hpp" +#include "utilities/stringUtils.hpp" #define COMPILER_PHASES(flags) \ flags(BEFORE_STRINGOPTS, "Before StringOpts") \ @@ -139,47 +140,6 @@ static CompilerPhaseType find_phase(const char* str) { return PHASE_NONE; } -class PhaseNameIter { - private: - char* _token; - char* _saved_ptr; - char* _list; - - public: - PhaseNameIter(ccstrlist option) { - _list = (char*) canonicalize(option); - _saved_ptr = _list; - _token = strtok_r(_saved_ptr, ",", &_saved_ptr); - } - - ~PhaseNameIter() { - FREE_C_HEAP_ARRAY(char, _list); - } - - const char* operator*() const { return _token; } - - PhaseNameIter& operator++() { - _token = strtok_r(nullptr, ",", &_saved_ptr); - return *this; - } - - ccstrlist canonicalize(ccstrlist option_value) { - char* canonicalized_list = NEW_C_HEAP_ARRAY(char, strlen(option_value) + 1, mtCompiler); - int i = 0; - char current; - while ((current = option_value[i]) != '\0') { - if (current == '\n' || current == ' ') { - canonicalized_list[i] = ','; - } else { - canonicalized_list[i] = current; - } - i++; - } - canonicalized_list[i] = '\0'; - return canonicalized_list; - } -}; - class PhaseNameValidator { private: CHeapBitMap _phase_name_set; @@ -192,7 +152,7 @@ class PhaseNameValidator { _valid(true), _bad(nullptr) { - for (PhaseNameIter iter(option); *iter != nullptr && _valid; ++iter) { + for (StringUtils::CommaSeparatedStringIterator iter(option); *iter != nullptr && _valid; ++iter) { CompilerPhaseType cpt = find_phase(*iter); if (PHASE_NONE == cpt) { diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 3d6d67dcf89bc..21ee970ae042b 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -69,13 +69,6 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : _num_work_vecs(0), // amount of vector work we have _num_reductions(0) // amount of reduction work we have { -#ifndef PRODUCT - _vector_loop_debug = 0; - if (_phase->C->method() != nullptr) { - _vector_loop_debug = phase->C->directive()->VectorizeDebugOption; - } - -#endif } //------------------------------transform_loop--------------------------- @@ -115,7 +108,7 @@ bool SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { Node *cl_exit = cl->loopexit(); if (cl->is_main_loop() && (cl_exit->in(0) != lpt->_head)) { #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_precondition()) { tty->print_cr("SuperWord::transform_loop: loop too complicated, cl_exit->in(0) != lpt->_head"); tty->print("cl_exit %d", cl_exit->_idx); cl_exit->dump(); tty->print("cl_exit->in(0) %d", cl_exit->in(0)->_idx); cl_exit->in(0)->dump(); @@ -297,9 +290,11 @@ void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) { // stop looking, we already have the max vector to map to. if (cur_max_vector < local_loop_unroll_factor) { is_slp = false; +#ifndef PRODUCT if (TraceSuperWordLoopUnrollAnalysis) { tty->print_cr("slp analysis fails: unroll limit greater than max vector\n"); } +#endif break; } @@ -346,6 +341,11 @@ void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) { } cl->mark_was_slp(); if (cl->is_main_loop()) { +#ifndef PRODUCT + if (TraceSuperWordLoopUnrollAnalysis) { + tty->print_cr("slp analysis: set max unroll to %d", local_loop_unroll_factor); + } +#endif cl->set_slp_max_unroll(local_loop_unroll_factor); } } @@ -519,19 +519,6 @@ void SuperWord::mark_reductions() { // extraction of scalar values from vectors. // bool SuperWord::SLP_extract() { - -#ifndef PRODUCT - if (_do_vector_loop && TraceSuperWord) { - tty->print("SuperWord::SLP_extract\n"); - tty->print("input loop\n"); - _lpt->dump_head(); - _lpt->dump(); - for (uint i = 0; i < _lpt->_body.size(); i++) { - _lpt->_body.at(i)->dump(); - } - } -#endif - CountedLoopNode* cl = lpt()->_head->as_CountedLoop(); assert(cl->is_main_loop(), "SLP should only work on main loops"); @@ -554,7 +541,7 @@ bool SuperWord::SLP_extract() { if (_packset.length() == 0) { #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_any()) { tty->print_cr("\nNo pair packs generated, abort SuperWord."); tty->cr(); } @@ -597,9 +584,11 @@ void SuperWord::find_adjacent_refs() { } } } - if (TraceSuperWord) { +#ifndef PRODUCT + if (is_trace_superword_adjacent_memops()) { tty->print_cr("\nfind_adjacent_refs found %d memops", memops.size()); } +#endif int max_idx; @@ -667,8 +656,8 @@ void SuperWord::find_adjacent_refs() { "packset empty or we find the alignment reference"); #ifndef PRODUCT - if (TraceSuperWord) { - tty->print_cr("\nAfter find_adjacent_refs"); + if (is_trace_superword_packset()) { + tty->print_cr("\nAfter Superword::find_adjacent_refs"); print_packset(); } #endif @@ -750,8 +739,8 @@ MemNode* SuperWord::find_align_to_ref(Node_List &memops, int &idx) { } } -#ifdef ASSERT - if (TraceSuperWord && Verbose) { +#ifndef PRODUCT + if (is_trace_superword_verbose()) { tty->print_cr("\nVector memops after find_align_to_ref"); for (uint i = 0; i < memops.size(); i++) { MemNode* s = memops.at(i)->as_Mem(); @@ -762,9 +751,9 @@ MemNode* SuperWord::find_align_to_ref(Node_List &memops, int &idx) { idx = max_idx; if (max_ct > 0) { -#ifdef ASSERT - if (TraceSuperWord) { - tty->print("\nVector align to node: "); +#ifndef PRODUCT + if (is_trace_superword_adjacent_memops()) { + tty->print("SuperWord::find_align_to_ref: "); memops.at(max_idx)->as_Mem()->dump(); } #endif @@ -825,7 +814,7 @@ int SuperWord::get_iv_adjustment(MemNode* mem_ref) { } #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_alignment()) { tty->print("SuperWord::get_iv_adjustment: n = %d, noffset = %d iv_adjust = %d elt_size = %d scale = %d iv_stride = %d vect_size %d: ", mem_ref->_idx, offset, iv_adjustment, elt_size, scale, iv_stride(), vw); mem_ref->dump(); @@ -858,14 +847,6 @@ void SuperWord::dependence_graph() { // Get slice in predecessor order (last is first) mem_slice_preds(n_tail, n, _nlist); -#ifndef PRODUCT - if(TraceSuperWord && Verbose) { - tty->print_cr("SuperWord::dependence_graph: built a new mem slice"); - for (int j = _nlist.length() - 1; j >= 0 ; j--) { - _nlist.at(j)->dump(); - } - } -#endif // Make the slice dependent on the root DepMem* slice = _dg.dep(n); _dg.make_edge(_dg.root(), slice); @@ -902,13 +883,15 @@ void SuperWord::dependence_graph() { } } - if (TraceSuperWord) { +#ifndef PRODUCT + if (is_trace_superword_dependence_graph()) { tty->print_cr("\nDependence graph for slice: %d", n->_idx); for (int q = 0; q < _nlist.length(); q++) { _dg.print(_nlist.at(q)); } tty->cr(); } +#endif _nlist.clear(); } @@ -921,16 +904,12 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p Node* n = start; Node* prev = nullptr; while (true) { - NOT_PRODUCT( if(is_trace_mem_slice()) tty->print_cr("SuperWord::mem_slice_preds: n %d", n->_idx);) assert(in_bb(n), "must be in block"); for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* out = n->fast_out(i); if (out->is_Load()) { if (in_bb(out)) { preds.push(out); - if (TraceSuperWord && Verbose) { - tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", out->_idx); - } } } else { // FIXME @@ -949,13 +928,20 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p }//for if (n == stop) break; preds.push(n); - if (TraceSuperWord && Verbose) { - tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", n->_idx); - } prev = n; assert(n->is_Mem(), "unexpected node %s", n->Name()); n = n->in(MemNode::Memory); } + +#ifndef PRODUCT + if (is_trace_superword_memory_slices()) { + tty->print_cr("\nSuperWord::mem_slice_preds:"); + stop->dump(); + for (int j = preds.length() - 1; j >= 0 ; j--) { + preds.at(j)->dump(); + } + } +#endif } //------------------------------stmts_can_pack--------------------------- @@ -1206,10 +1192,12 @@ void SuperWord::extend_packlist() { } } - if (TraceSuperWord) { - tty->print_cr("\nAfter extend_packlist"); +#ifndef PRODUCT + if (is_trace_superword_packset()) { + tty->print_cr("\nAfter Superword::extend_packlist"); print_packset(); } +#endif } //------------------------------adjust_alignment_for_type_conversion--------------------------------- @@ -1239,7 +1227,12 @@ bool SuperWord::follow_use_defs(Node_List* p) { if (s1->is_Load()) return false; - NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("SuperWord::follow_use_defs: s1 %d, align %d", s1->_idx, alignment(s1));) +#ifndef PRODUCT + if (is_trace_superword_alignment()) { + tty->print_cr("SuperWord::follow_use_defs: s1 %d, align %d", + s1->_idx, alignment(s1)); + } +#endif bool changed = false; int start = s1->is_Store() ? MemNode::ValueIn : 1; int end = s1->is_Store() ? MemNode::ValueIn+1 : s1->req(); @@ -1258,7 +1251,12 @@ bool SuperWord::follow_use_defs(Node_List* p) { pair->push(t1); pair->push(t2); _packset.append(pair); - NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("SuperWord::follow_use_defs: set_alignment(%d, %d, %d)", t1->_idx, t2->_idx, align);) +#ifndef PRODUCT + if (is_trace_superword_alignment()) { + tty->print_cr("SuperWord::follow_use_defs: set_alignment(%d, %d, %d)", + t1->_idx, t2->_idx, align); + } +#endif set_alignment(t1, t2, align); changed = true; } @@ -1280,7 +1278,12 @@ bool SuperWord::follow_def_uses(Node_List* p) { if (s1->is_Store()) return false; int align = alignment(s1); - NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("SuperWord::follow_def_uses: s1 %d, align %d", s1->_idx, align);) +#ifndef PRODUCT + if (is_trace_superword_alignment()) { + tty->print_cr("SuperWord::follow_def_uses: s1 %d, align %d", + s1->_idx, align); + } +#endif int savings = -1; int num_s1_uses = 0; Node* u1 = nullptr; @@ -1322,7 +1325,12 @@ bool SuperWord::follow_def_uses(Node_List* p) { pair->push(u1); pair->push(u2); _packset.append(pair); - NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("SuperWord::follow_def_uses: set_alignment(%d, %d, %d)", u1->_idx, u2->_idx, align);) +#ifndef PRODUCT + if (is_trace_superword_alignment()) { + tty->print_cr("SuperWord::follow_def_uses: set_alignment(%d, %d, %d)", + u1->_idx, u2->_idx, align); + } +#endif set_alignment(u1, u2, align); changed = true; } @@ -1513,7 +1521,7 @@ void SuperWord::combine_packs() { if (!is_power_of_2(psize)) { // We currently only support power-of-2 sizes for vectors. #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_rejections()) { tty->cr(); tty->print_cr("WARNING: Removed pack[%d] with size that is not a power of 2:", i); print_pack(p1); @@ -1564,7 +1572,7 @@ void SuperWord::combine_packs() { if (!is_marked_reduction(p->at(0)) && !mutually_independent(p)) { #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_rejections()) { tty->cr(); tty->print_cr("WARNING: Found dependency at distance greater than 1."); tty->print_cr("In pack[%d]", i); @@ -1580,8 +1588,8 @@ void SuperWord::combine_packs() { compress_packset(); #ifndef PRODUCT - if (TraceSuperWord) { - tty->print_cr("\nAfter combine_packs"); + if (is_trace_superword_packset()) { + tty->print_cr("\nAfter Superword::combine_packs"); print_packset(); } #endif @@ -1621,8 +1629,8 @@ void SuperWord::filter_packs_for_alignment() { } #ifndef PRODUCT - if (TraceSuperWord || is_trace_align_vector()) { - tty->print_cr("\nfilter_packs_for_alignment:"); + if (is_trace_superword_info() || is_trace_align_vector()) { + tty->print_cr("\nSuperWord::filter_packs_for_alignment:"); } #endif @@ -1652,6 +1660,12 @@ void SuperWord::filter_packs_for_alignment() { if (intersect->is_empty()) { // Solution failed or is not compatible, remove pack i. +#ifndef PRODUCT + if (is_trace_superword_rejections() || is_trace_align_vector()) { + tty->print_cr("Rejected by AlignVector:"); + p->at(0)->dump(); + } +#endif _packset.at_put(i, nullptr); mem_ops_rejected++; } else { @@ -1663,7 +1677,7 @@ void SuperWord::filter_packs_for_alignment() { } #ifndef PRODUCT - if (TraceSuperWord || is_trace_align_vector()) { + if (is_trace_superword_info() || is_trace_align_vector()) { tty->print("\n final solution: "); current->print(); tty->print_cr(" rejected mem_ops packs: %d of %d", mem_ops_rejected, mem_ops_count); @@ -1680,6 +1694,13 @@ void SuperWord::filter_packs_for_alignment() { // Remove all nullptr from packset compress_packset(); + +#ifndef PRODUCT + if (is_trace_superword_packset() || is_trace_align_vector()) { + tty->print_cr("\nAfter Superword::filter_packs_for_alignment"); + print_packset(); + } +#endif } // Compress packset, such that it has no nullptr entries @@ -1725,7 +1746,7 @@ void SuperWord::filter_packs() { bool impl = implemented(pk); if (!impl) { #ifndef PRODUCT - if ((TraceSuperWord && Verbose) || _vector_loop_debug) { + if (is_trace_superword_rejections()) { tty->print_cr("Unimplemented"); pk->at(0)->dump(); } @@ -1749,7 +1770,7 @@ void SuperWord::filter_packs() { bool prof = profitable(pk); if (!prof) { #ifndef PRODUCT - if ((TraceSuperWord && Verbose) || _vector_loop_debug) { + if (is_trace_superword_rejections()) { tty->print_cr("Unprofitable"); pk->at(0)->dump(); } @@ -1761,8 +1782,8 @@ void SuperWord::filter_packs() { } while (changed); #ifndef PRODUCT - if (TraceSuperWord) { - tty->print_cr("\nAfter filter_packs"); + if (is_trace_superword_packset()) { + tty->print_cr("\nAfter Superword::filter_packs"); print_packset(); tty->cr(); } @@ -2236,17 +2257,19 @@ void SuperWord::schedule() { // introduced a cycle. The SuperWord paper mentions the need for this // in "3.7 Scheduling". if (!graph.schedule_success()) { - if (TraceSuperWord) { +#ifndef PRODUCT + if (is_trace_superword_rejections()) { tty->print_cr("SuperWord::schedule found cycle in PacksetGraph:"); graph.print(true, false); tty->print_cr("removing all packs from packset."); } +#endif _packset.clear(); return; } #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_info()) { tty->print_cr("SuperWord::schedule: memops_schedule:"); memops_schedule.dump(); } @@ -2382,7 +2405,6 @@ bool SuperWord::output() { uint vlen = p->size(); uint vlen_in_bytes = 0; Node* vn = nullptr; - NOT_PRODUCT(if(is_trace_cmov()) {tty->print_cr("VPointer::output: %d executed first, %d executed last in pack", first->_idx, n->_idx); print_pack(p);}) int opc = n->Opcode(); if (n->is_Load()) { Node* ctl = n->in(MemNode::Control); @@ -2675,9 +2697,11 @@ bool SuperWord::output() { if (cl->has_passed_slp()) { uint slp_max_unroll_factor = cl->slp_max_unroll(); if (slp_max_unroll_factor == max_vlen) { +#ifndef PRODUCT if (TraceSuperWordLoopUnrollAnalysis) { tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte); } +#endif // For atomic unrolled loops which are vector mapped, instigate more unrolling cl->set_notpassed_slp(); // if vector resources are limited, do not allow additional unrolling @@ -3051,13 +3075,15 @@ bool SuperWord::construct_bb() { initialize_bb(); #ifndef PRODUCT - if (TraceSuperWord) { + if (is_trace_superword_info()) { print_bb(); tty->print_cr("\ndata entry nodes: %s", _data_entry.length() > 0 ? "" : "NONE"); for (int m = 0; m < _data_entry.length(); m++) { tty->print("%3d ", m); _data_entry.at(m)->dump(); } + } + if (is_trace_superword_memory_slices()) { tty->print_cr("\nmemory slices: %s", _mem_slice_head.length() > 0 ? "" : "NONE"); for (int m = 0; m < _mem_slice_head.length(); m++) { tty->print("%3d ", m); _mem_slice_head.at(m)->dump(); @@ -3124,9 +3150,11 @@ void SuperWord::compute_max_depth() { ct++; } while (again); - if (TraceSuperWord && Verbose) { +#ifndef PRODUCT + if (is_trace_superword_dependence_graph()) { tty->print_cr("compute_max_depth iterated: %d times", ct); } +#endif } BasicType SuperWord::longer_type_for_conversion(Node* n) { @@ -3186,9 +3214,11 @@ int SuperWord::max_vector_size_in_def_use_chain(Node* n) { // Normally the type of the add is integer, but for packed character // operations the type of the add needs to be char. void SuperWord::compute_vector_element_type() { - if (TraceSuperWord && Verbose) { +#ifndef PRODUCT + if (is_trace_superword_vector_element_type()) { tty->print_cr("\ncompute_velt_type:"); } +#endif // Initial type for (int i = 0; i < _block.length(); i++) { @@ -3264,7 +3294,7 @@ void SuperWord::compute_vector_element_type() { } } #ifndef PRODUCT - if (TraceSuperWord && Verbose) { + if (is_trace_superword_vector_element_type()) { for (int i = 0; i < _block.length(); i++) { Node* n = _block.at(i); velt_type(n)->dump(); @@ -3279,18 +3309,18 @@ void SuperWord::compute_vector_element_type() { // Alignment within a vector memory reference int SuperWord::memory_alignment(MemNode* s, int iv_adjust) { #ifndef PRODUCT - if ((TraceSuperWord && Verbose) || is_trace_alignment()) { + if (is_trace_superword_alignment()) { tty->print("SuperWord::memory_alignment within a vector memory reference for %d: ", s->_idx); s->dump(); } #endif VPointer p(s, phase(), lpt(), nullptr, false); if (!p.valid()) { - NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("VPointer::memory_alignment: VPointer p invalid, return bottom_align");) + NOT_PRODUCT(if(is_trace_superword_alignment()) tty->print_cr("SuperWord::memory_alignment: VPointer p invalid, return bottom_align");) return bottom_align; } int vw = get_vw_bytes_special(s); if (vw < 2) { - NOT_PRODUCT(if(is_trace_alignment()) tty->print_cr("VPointer::memory_alignment: vector_width_in_bytes < 2, return bottom_align");) + NOT_PRODUCT(if(is_trace_superword_alignment()) tty->print_cr("SuperWord::memory_alignment: vector_width_in_bytes < 2, return bottom_align");) return bottom_align; // No vectors for this type } int offset = p.offset_in_bytes(); @@ -3298,8 +3328,8 @@ int SuperWord::memory_alignment(MemNode* s, int iv_adjust) { int off_rem = offset % vw; int off_mod = off_rem >= 0 ? off_rem : off_rem + vw; #ifndef PRODUCT - if ((TraceSuperWord && Verbose) || is_trace_alignment()) { - tty->print_cr("VPointer::memory_alignment: off_rem = %d, off_mod = %d (offset = %d)", off_rem, off_mod, offset); + if (is_trace_superword_alignment()) { + tty->print_cr("SuperWord::memory_alignment: off_rem = %d, off_mod = %d (offset = %d)", off_rem, off_mod, offset); } #endif return off_mod; diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index a9da6d06ca4e9..c0a9c98858bea 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -241,14 +241,78 @@ class SuperWord : public ResourceObj { bool early_return() const { return _early_return; } #ifndef PRODUCT - bool is_debug() { return _vector_loop_debug > 0; } - bool is_trace_alignment() { return (_vector_loop_debug & 2) > 0; } - bool is_trace_mem_slice() { return (_vector_loop_debug & 4) > 0; } - bool is_trace_loop() { return (_vector_loop_debug & 8) > 0; } - bool is_trace_adjacent() { return (_vector_loop_debug & 16) > 0; } - bool is_trace_cmov() { return (_vector_loop_debug & 32) > 0; } - bool is_trace_align_vector() { return (_vector_loop_debug & 128) > 0; } + // TraceAutoVectorization and TraceSuperWord + bool is_trace_superword_precondition() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_PRECONDITION); + } + + bool is_trace_superword_vector_element_type() const { + // Too verbose for TraceSuperWord + return _vtrace.is_trace(TraceAutoVectorizationTag::SW_TYPES); + } + + bool is_trace_superword_alignment() const { + // Too verbose for TraceSuperWord + return _vtrace.is_trace(TraceAutoVectorizationTag::SW_ALIGNMENT); + } + + bool is_trace_superword_memory_slices() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_MEMORY_SLICES); + } + + bool is_trace_superword_dependence_graph() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_DEPENDENCE_GRAPH); + } + + bool is_trace_superword_adjacent_memops() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_ADJACENT_MEMOPS); + } + + bool is_trace_superword_rejections() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_REJECTIONS); + } + + bool is_trace_superword_packset() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_PACKSET); + } + + bool is_trace_superword_info() const { + return TraceSuperWord || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_INFO); + } + + bool is_trace_superword_verbose() const { + // Too verbose for TraceSuperWord + return _vtrace.is_trace(TraceAutoVectorizationTag::SW_VERBOSE); + } + + bool is_trace_superword_any() const { + return TraceSuperWord || + is_trace_align_vector() || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_PRECONDITION) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_TYPES) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_ALIGNMENT) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_MEMORY_SLICES) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_DEPENDENCE_GRAPH) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_ADJACENT_MEMOPS) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_REJECTIONS) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_PACKSET) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_INFO) || + _vtrace.is_trace(TraceAutoVectorizationTag::SW_VERBOSE); + } + + bool is_trace_align_vector() const { + return _vtrace.is_trace(TraceAutoVectorizationTag::ALIGN_VECTOR) || + is_trace_superword_verbose(); + } #endif + bool do_vector_loop() { return _do_vector_loop; } const GrowableArray& packset() const { return _packset; } @@ -265,9 +329,7 @@ class SuperWord : public ResourceObj { bool _do_vector_loop; // whether to do vectorization/simd style int _num_work_vecs; // Number of non memory vector operations int _num_reductions; // Number of reduction expressions applied -#ifndef PRODUCT - uintx _vector_loop_debug; // provide more printing in debug mode -#endif + NOT_PRODUCT(VTrace _vtrace); // Accessors Arena* arena() { return _arena; } diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp new file mode 100644 index 0000000000000..61cb1fe4bf3a6 --- /dev/null +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2024, 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. + * + */ + +#ifndef SHARE_OPTO_TRACEAUTOVECTORIZATIONTAG_HPP +#define SHARE_OPTO_TRACEAUTOVECTORIZATIONTAG_HPP + +#include "utilities/bitMap.inline.hpp" +#include "utilities/stringUtils.hpp" + +#define COMPILER_TRACE_AUTO_VECTORIZATION_TAG(flags) \ + flags(POINTER_ANALYSIS, "Trace VPointer") \ + flags(SW_PRECONDITION, "Trace SuperWord precondition") \ + flags(SW_TYPES, "Trace SuperWord::compute_vector_element_type") \ + flags(SW_ALIGNMENT, "Trace SuperWord alignment analysis") \ + flags(SW_MEMORY_SLICES, "Trace SuperWord memory slices") \ + flags(SW_DEPENDENCE_GRAPH, "Trace SuperWord::dependence_graph") \ + flags(SW_ADJACENT_MEMOPS, "Trace SuperWord::find_adjacent_refs") \ + flags(SW_REJECTIONS, "Trace SuperWord rejections (non vectorizations)") \ + flags(SW_PACKSET, "Trace SuperWord packset at different stages") \ + flags(SW_INFO, "Trace SuperWord info (equivalent to TraceSuperWord)") \ + flags(SW_VERBOSE, "Trace SuperWord verbose (all SW tags enabled)") \ + flags(ALIGN_VECTOR, "Trace AlignVector") \ + flags(ALL, "Trace everything (very verbose)") + +#define table_entry(name, description) name, +enum TraceAutoVectorizationTag { + COMPILER_TRACE_AUTO_VECTORIZATION_TAG(table_entry) + TRACE_AUTO_VECTORIZATION_TAG_NUM, + TRACE_AUTO_VECTORIZATION_TAG_NONE +}; +#undef table_entry + +static const char* tag_descriptions[] = { +#define array_of_labels(name, description) description, + COMPILER_TRACE_AUTO_VECTORIZATION_TAG(array_of_labels) +#undef array_of_labels +}; + +static const char* tag_names[] = { +#define array_of_labels(name, description) #name, + COMPILER_TRACE_AUTO_VECTORIZATION_TAG(array_of_labels) +#undef array_of_labels +}; + +static TraceAutoVectorizationTag find_tag(const char* str) { + for (int i = 0; i < TRACE_AUTO_VECTORIZATION_TAG_NUM; i++) { + if (strcmp(tag_names[i], str) == 0) { + return (TraceAutoVectorizationTag)i; + } + } + return TRACE_AUTO_VECTORIZATION_TAG_NONE; +} + +class TraceAutoVectorizationTagValidator { + private: + CHeapBitMap _tags; + bool _valid; + char* _bad; + bool _is_print_usage; + + public: + TraceAutoVectorizationTagValidator(ccstrlist option, bool is_print_usage) : + _tags(TRACE_AUTO_VECTORIZATION_TAG_NUM, mtCompiler), + _valid(true), + _bad(nullptr), + _is_print_usage(is_print_usage) + { + for (StringUtils::CommaSeparatedStringIterator iter(option); *iter != nullptr && _valid; ++iter) { + char const* tag_name = *iter; + if (strcmp("help", tag_name) == 0) { + if (_is_print_usage) { + print_help(); + } + continue; + } + bool set_bit = true; + // Check for "TAG" or "-TAG" + if (strncmp("-", tag_name, strlen("-")) == 0) { + tag_name++; + set_bit = false; + } + TraceAutoVectorizationTag tag = find_tag(tag_name); + if (TRACE_AUTO_VECTORIZATION_TAG_NONE == tag) { + // cap len to a value we know is enough for all tags + const size_t len = MIN2(strlen(*iter), 63) + 1; + _bad = NEW_C_HEAP_ARRAY(char, len, mtCompiler); + // strncpy always writes len characters. If the source string is + // shorter, the function fills the remaining bytes with nulls. + strncpy(_bad, *iter, len); + _valid = false; + } else if (ALL == tag) { + _tags.set_range(0, TRACE_AUTO_VECTORIZATION_TAG_NUM); + } else if (SW_VERBOSE == tag) { + _tags.at_put(SW_PRECONDITION, set_bit); + _tags.at_put(SW_TYPES, set_bit); + _tags.at_put(SW_ALIGNMENT, set_bit); + _tags.at_put(SW_MEMORY_SLICES, set_bit); + _tags.at_put(SW_DEPENDENCE_GRAPH, set_bit); + _tags.at_put(SW_ADJACENT_MEMOPS, set_bit); + _tags.at_put(SW_REJECTIONS, set_bit); + _tags.at_put(SW_PACKSET, set_bit); + _tags.at_put(SW_INFO, set_bit); + _tags.at_put(SW_VERBOSE, set_bit); + } else if (SW_INFO == tag) { + _tags.at_put(SW_PRECONDITION, set_bit); + _tags.at_put(SW_MEMORY_SLICES, set_bit); + _tags.at_put(SW_DEPENDENCE_GRAPH, set_bit); + _tags.at_put(SW_ADJACENT_MEMOPS, set_bit); + _tags.at_put(SW_REJECTIONS, set_bit); + _tags.at_put(SW_PACKSET, set_bit); + _tags.at_put(SW_INFO, set_bit); + } else { + assert(tag < TRACE_AUTO_VECTORIZATION_TAG_NUM, "out of bounds"); + _tags.at_put(tag, set_bit); + } + } + } + + ~TraceAutoVectorizationTagValidator() { + if (_bad != nullptr) { + FREE_C_HEAP_ARRAY(char, _bad); + } + } + + bool is_valid() const { return _valid; } + const char* what() const { return _bad; } + const CHeapBitMap& tags() const { + assert(is_valid(), "only read tags when valid"); + return _tags; + } + + static void print_help() { + tty->cr(); + tty->print_cr("Usage for CompileCommand TraceAutoVectorization:"); + tty->print_cr(" -XX:CompileCommand=TraceAutoVectorization,,"); + tty->print_cr(" %-22s %s", "tags", "descriptions"); + for (int i = 0; i < TRACE_AUTO_VECTORIZATION_TAG_NUM; i++) { + tty->print_cr(" %-22s %s", tag_names[i], tag_descriptions[i]); + } + tty->cr(); + } +}; + +#endif // SHARE_OPTO_TRACEAUTOVECTORIZATIONTAG_HPP diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 4794140ab0e45..5ff24750b9a75 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -46,7 +46,7 @@ VPointer::VPointer(const MemNode* mem, #endif _nstack(nstack), _analyze_only(analyze_only), _stack_idx(0) #ifndef PRODUCT - , _tracer((phase->C->directive()->VectorizeDebugOption & 2) > 0) + , _tracer(phase->C->directive()->trace_auto_vectorization_tags().at(TraceAutoVectorizationTag::POINTER_ANALYSIS)) #endif { NOT_PRODUCT(_tracer.ctor_1(mem);) diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 8e63b40d5ac48..5cf5a31b48d34 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -27,10 +27,27 @@ #include "opto/node.hpp" #include "opto/loopnode.hpp" +#include "opto/traceAutoVectorizationTag.hpp" // Code in this file and the vectorization.cpp contains shared logics and // utilities for C2's loop auto-vectorization. +#ifndef PRODUCT +// Access to TraceAutoVectorization tags +class VTrace : public StackObj { +private: + const CHeapBitMap &_trace_tags; + +public: + VTrace() : _trace_tags(Compile::current()->directive()->trace_auto_vectorization_tags()) {} + NONCOPYABLE(VTrace); + + bool is_trace(TraceAutoVectorizationTag tag) const { + return _trace_tags.at(tag); + } +}; +#endif + // A vectorization pointer (VPointer) has information about an address for // dependence checking and vector alignment. It's usually bound to a memory // operation in a counted loop for vectorizable analysis. diff --git a/src/hotspot/share/utilities/stringUtils.cpp b/src/hotspot/share/utilities/stringUtils.cpp index 3abebeec92aae..83ccfe308a9b1 100644 --- a/src/hotspot/share/utilities/stringUtils.cpp +++ b/src/hotspot/share/utilities/stringUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "jvm_io.h" +#include "memory/allocation.hpp" #include "utilities/debug.hpp" #include "utilities/stringUtils.hpp" @@ -122,3 +123,23 @@ bool StringUtils::is_star_match(const char* star_pattern, const char* str) { } return true; // all parts of pattern matched } + +StringUtils::CommaSeparatedStringIterator::~CommaSeparatedStringIterator() { + FREE_C_HEAP_ARRAY(char, _list); +} + +ccstrlist StringUtils::CommaSeparatedStringIterator::canonicalize(ccstrlist option_value) { + char* canonicalized_list = NEW_C_HEAP_ARRAY(char, strlen(option_value) + 1, mtCompiler); + int i = 0; + char current; + while ((current = option_value[i]) != '\0') { + if (current == '\n' || current == ' ') { + canonicalized_list[i] = ','; + } else { + canonicalized_list[i] = current; + } + i++; + } + canonicalized_list[i] = '\0'; + return canonicalized_list; +} diff --git a/src/hotspot/share/utilities/stringUtils.hpp b/src/hotspot/share/utilities/stringUtils.hpp index febfb227ebb9d..754624a6540d7 100644 --- a/src/hotspot/share/utilities/stringUtils.hpp +++ b/src/hotspot/share/utilities/stringUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -49,6 +49,33 @@ class StringUtils : AllStatic { // eg. str "_abc____def__" would match pattern "abc*def". // The matching is case insensitive. static bool is_star_match(const char* star_pattern, const char* str); + + class CommaSeparatedStringIterator { + private: + char* _token; + char* _saved_ptr; + char* _list; + + public: + CommaSeparatedStringIterator(ccstrlist option) { + // Immediately make a private copy of option, and + // replace spaces and newlines with comma. + _list = (char*) canonicalize(option); + _saved_ptr = _list; + _token = strtok_r(_saved_ptr, ",", &_saved_ptr); + } + + ~CommaSeparatedStringIterator(); + + const char* operator*() const { return _token; } + + CommaSeparatedStringIterator& operator++() { + _token = strtok_r(nullptr, ",", &_saved_ptr); + return *this; + } + + ccstrlist canonicalize(ccstrlist option_value); + }; }; #endif // SHARE_UTILITIES_STRINGUTILS_HPP diff --git a/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java b/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java index 6e23aa5d6e043..a20a9359111d6 100644 --- a/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java +++ b/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java @@ -52,7 +52,7 @@ public class TestInvalidCompileCommand { "-version" }, { - "-XX:CompileCommand=option,Test::test,VectorizeDebug,3", + "-XX:CompileCommand=option,Test::test,MemStat,3", "-version" }, { @@ -72,7 +72,7 @@ public class TestInvalidCompileCommand { "Missing type 'intx' before option 'RepeatCompilation'" }, { - "Missing type 'uintx' before option 'VectorizeDebug'" + "Missing type 'uintx' before option 'MemStat'" }, { "Missing type 'ccstrlist' before option 'ControlIntrinsic'"