From 1ab6bd434f560e0cc34a85079949e3839c59568f Mon Sep 17 00:00:00 2001 From: Kuai Wei Date: Wed, 28 Feb 2024 08:44:49 +0000 Subject: [PATCH] 8326135: Enhance adlc to report unused operands Reviewed-by: kvn, vlivanov --- src/hotspot/share/adlc/archDesc.cpp | 95 +++++++++++++++++++++++- src/hotspot/share/adlc/archDesc.hpp | 3 +- src/hotspot/share/adlc/forms.cpp | 19 ++++- src/hotspot/share/adlc/forms.hpp | 18 ++++- src/hotspot/share/adlc/formsopt.cpp | 40 +++++++++- src/hotspot/share/adlc/formsopt.hpp | 11 ++- src/hotspot/share/adlc/formssel.cpp | 109 ++++++++++++++++++++++++++++ src/hotspot/share/adlc/formssel.hpp | 13 +++- src/hotspot/share/adlc/main.cpp | 5 +- 9 files changed, 305 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/adlc/archDesc.cpp b/src/hotspot/share/adlc/archDesc.cpp index d27bf086560..93fa7451dc0 100644 --- a/src/hotspot/share/adlc/archDesc.cpp +++ b/src/hotspot/share/adlc/archDesc.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 1997, 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 @@ // archDesc.cpp - Internal format for architecture definition +#include #include "adlc.hpp" static FILE *errfile = stderr; @@ -684,6 +685,98 @@ bool ArchDesc::verify() { return true; } +class MarkUsageFormClosure : public FormClosure { +private: + ArchDesc* _ad; + std::unordered_set *_visited; + +public: + MarkUsageFormClosure(ArchDesc* ad, std::unordered_set *visit_map) { + _ad = ad; + _visited = visit_map; + } + virtual ~MarkUsageFormClosure() = default; + + virtual void do_form(Form *form) { + if (_visited->find(form) == _visited->end()) { + _visited->insert(form); + form->forms_do(this); + } + } + + virtual void do_form_by_name(const char* name) { + const Form* form = _ad->globalNames()[name]; + if (form) { + do_form(const_cast(form)); + return; + } + RegisterForm* regs = _ad->get_registers(); + if (regs->getRegClass(name)) { + do_form(regs->getRegClass(name)); + return; + } + } +}; + +// check unused operands +bool ArchDesc::check_usage() { + std::unordered_set visited; + MarkUsageFormClosure callback(this, &visited); + _instructions.reset(); + // iterate all instruction to mark used form + InstructForm* instr; + for ( ; (instr = (InstructForm*)_instructions.iter()) != nullptr; ) { + callback.do_form(instr); + } + + // these forms are coded in OperandForm::is_user_name_for_sReg + // it may happen no instruction use these operands, like stackSlotP in aarch64, + // but we can not desclare they are useless. + callback.do_form_by_name("stackSlotI"); + callback.do_form_by_name("stackSlotP"); + callback.do_form_by_name("stackSlotD"); + callback.do_form_by_name("stackSlotF"); + callback.do_form_by_name("stackSlotL"); + + // sReg* are initial created by adlc in ArchDesc::initBaseOpTypes() + // In ARM, no definition or usage in adfile, but they are reported as unused + callback.do_form_by_name("sRegI"); + callback.do_form_by_name("sRegP"); + callback.do_form_by_name("sRegD"); + callback.do_form_by_name("sRegF"); + callback.do_form_by_name("sRegL"); + + // special generic vector operands only used in Matcher::pd_specialize_generic_vector_operand +#if defined(AARCH64) + callback.do_form_by_name("vecA"); + callback.do_form_by_name("vecD"); + callback.do_form_by_name("vecX"); +#elif defined(AMD64) + callback.do_form_by_name("vecS"); + callback.do_form_by_name("vecD"); + callback.do_form_by_name("vecX"); + callback.do_form_by_name("vecY"); + callback.do_form_by_name("vecZ"); + callback.do_form_by_name("legVecS"); + callback.do_form_by_name("legVecD"); + callback.do_form_by_name("legVecX"); + callback.do_form_by_name("legVecY"); + callback.do_form_by_name("legVecZ"); +#endif + + int cnt = 0; + _operands.reset(); + OperandForm* operand; + for ( ; (operand = (OperandForm*)_operands.iter()) != nullptr; ) { + if(visited.find(operand) == visited.end() && !operand->ideal_only()) { + fprintf(stderr, "\nWarning: unused operand (%s)", operand->_ident); + cnt++; + } + } + if (cnt) fprintf(stderr, "\n-------Warning: total %d unused operands\n", cnt); + + return true; +} void ArchDesc::dump() { _pre_header.dump(); diff --git a/src/hotspot/share/adlc/archDesc.hpp b/src/hotspot/share/adlc/archDesc.hpp index 42369f6c2d1..99e4947e110 100644 --- a/src/hotspot/share/adlc/archDesc.hpp +++ b/src/hotspot/share/adlc/archDesc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -226,6 +226,7 @@ public: inline void getForm(EncodeForm **ptr) { *ptr = _encode; } bool verify(); + bool check_usage(); void dump(); // Helper utility that gets MatchList components from inside MatchRule diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp index fd8e5c4fd50..068d745254e 100644 --- a/src/hotspot/share/adlc/forms.cpp +++ b/src/hotspot/share/adlc/forms.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -362,6 +362,15 @@ void FormDict::dump() { _form.print(dumpkey, dumpform); } +void FormDict::forms_do(FormClosure* f) {; + DictI iter(&_form); + for( ; iter.test(); ++iter ) { + Form* form = (Form*) iter._value; + assert(form != nullptr, "sanity"); + f->do_form(form); + } +} + //------------------------------SourceForm------------------------------------- SourceForm::SourceForm(char* code) : _code(code) { }; // Constructor SourceForm::~SourceForm() { @@ -374,3 +383,11 @@ void SourceForm::dump() { // Debug printer void SourceForm::output(FILE *fp) { fprintf(fp,"\n//%s\n%s\n",classname(),(_code?_code:"")); } + +void FormClosure::do_form(Form* form) { + assert(false, "should not reach here"); +} + +void FormClosure::do_form_by_name(const char* name) { + assert(false, "should not reach here"); +} diff --git a/src/hotspot/share/adlc/forms.hpp b/src/hotspot/share/adlc/forms.hpp index c3dd85eb98b..a82b9bbb338 100644 --- a/src/hotspot/share/adlc/forms.hpp +++ b/src/hotspot/share/adlc/forms.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -58,6 +58,7 @@ class Flag; class RewriteRule; class ConstructRule; class FormatRule; +class FormClosure; class Peephole; class EncClass; class Interface; @@ -114,6 +115,8 @@ public: const Form *operator [](const char *name) const; // Do a lookup void dump(); + // iterate child forms recursively + void forms_do(FormClosure *f); }; // ***** Master Class for ADL Parser Forms ***** @@ -163,6 +166,9 @@ public: // Write info to output files virtual void output(FILE *fp) { fprintf(fp,"Form Output"); } + // iterate child forms recursively + virtual void forms_do (FormClosure* f) { return; } + public: // ADLC types, match the last character on ideal operands and instructions enum DataType { @@ -255,6 +261,16 @@ public: }; +class FormClosure { +public: + FormClosure() = default; + virtual ~FormClosure() = default; + + virtual void do_form(Form* form); + virtual void do_form_by_name(const char* name); +}; + + //------------------------------FormList--------------------------------------- class FormList { private: diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 13d29ef3947..e1e4ed96c2e 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.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 @@ -198,6 +198,20 @@ void RegisterForm::output(FILE *fp) { // Write info to output files fprintf(fp,"-------------------- end RegisterForm --------------------\n"); } +void RegisterForm::forms_do(FormClosure *f) { + const char *name = nullptr; + if (_current_ac) f->do_form(_current_ac); + for(_rdefs.reset(); (name = _rdefs.iter()) != nullptr;) { + f->do_form((RegDef*)_regDef[name]); + } + for (_rclasses.reset(); (name = _rclasses.iter()) != nullptr;) { + f->do_form((RegClass*)_regClass[name]); + } + for (_aclasses.reset(); (name = _aclasses.iter()) != nullptr;) { + f->do_form((AllocClass*)_allocClass[name]); + } +} + //------------------------------RegDef----------------------------------------- // Constructor RegDef::RegDef(char *regname, char *callconv, char *c_conv, char * idealtype, char * encode, char * concrete) @@ -322,6 +336,13 @@ void RegClass::output(FILE *fp) { // Write info to output files fprintf(fp,"--- done with entries for reg_class %s\n\n",_classid); } +void RegClass::forms_do(FormClosure *f) { + const char *name = nullptr; + for( _regDefs.reset(); (name = _regDefs.iter()) != nullptr; ) { + f->do_form((RegDef*)_regDef[name]); + } +} + void RegClass::declare_register_masks(FILE* fp) { const char* prefix = ""; const char* rc_name_to_upper = toUpper(_classid); @@ -436,6 +457,14 @@ void AllocClass::output(FILE *fp) { // Write info to output files fprintf(fp,"--- done with entries for alloc_class %s\n\n",_classid); } +void AllocClass::forms_do(FormClosure* f) { + const char *name; + for(_regDefs.reset(); (name = _regDefs.iter()) != nullptr;) { + f->do_form((RegDef*)_regDef[name]); + } + return; +} + //==============================Frame Handling================================= //------------------------------FrameForm-------------------------------------- FrameForm::FrameForm() { @@ -706,6 +735,15 @@ void Peephole::output(FILE *fp) { // Write info to output files if( _next ) _next->output(fp); } +void Peephole::forms_do(FormClosure *f) { + if (_predicate) f->do_form(_predicate); + if (_match) f->do_form(_match); + if (_procedure) f->do_form(_procedure); + if (_constraint) f->do_form(_constraint); + if (_replace) f->do_form(_replace); + return; +} + //----------------------------PeepPredicate------------------------------------ PeepPredicate::PeepPredicate(const char* rule) : _rule(rule) { } diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index 1a2b5dadd30..d183a46b875 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.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 @@ -123,6 +123,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure* f); }; //------------------------------RegDef----------------------------------------- @@ -199,6 +200,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure* f); virtual bool has_stack_version() { return _stack_or_reg; @@ -305,6 +307,11 @@ public: char* condition_code() { return _condition_code; } + + virtual void forms_do(FormClosure* f) { + if (_rclasses[0]) f->do_form(_rclasses[0]); + if (_rclasses[1]) f->do_form(_rclasses[1]); + } }; //------------------------------AllocClass------------------------------------- @@ -325,6 +332,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure* f); }; @@ -568,6 +576,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure* f); }; class PeepPredicate : public Form { diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index ecbf472c59e..be97547f8ce 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1498,6 +1498,24 @@ void InstructForm::output(FILE *fp) { if (_peephole) _peephole->output(fp); } +void InstructForm::forms_do(FormClosure *f) { + if (_cisc_spill_alternate) f->do_form(_cisc_spill_alternate); + if (_short_branch_form) f->do_form(_short_branch_form); + _localNames.forms_do(f); + if (_matrule) f->do_form(_matrule); + if (_opcode) f->do_form(_opcode); + if (_insencode) f->do_form(_insencode); + if (_constant) f->do_form(_constant); + if (_attribs) f->do_form(_attribs); + if (_predicate) f->do_form(_predicate); + _effects.forms_do(f); + if (_exprule) f->do_form(_exprule); + if (_rewrule) f->do_form(_rewrule); + if (_format) f->do_form(_format); + if (_peephole) f->do_form(_peephole); + assert(_components.count() == 0, "skip components"); +} + void MachNodeForm::dump() { output(stderr); } @@ -1615,6 +1633,14 @@ void EncodeForm::output(FILE *fp) { // Write info to output files } fprintf(fp,"-------------------- end EncodeForm --------------------\n"); } + +void EncodeForm::forms_do(FormClosure* f) { + const char *name; + for (_eclasses.reset(); (name = _eclasses.iter()) != nullptr;) { + f->do_form((EncClass*)_encClass[name]); + } +} + //------------------------------EncClass--------------------------------------- EncClass::EncClass(const char *name) : _localNames(cmpstr,hashstr, Form::arena), _name(name) { @@ -1705,6 +1731,15 @@ void EncClass::output(FILE *fp) { } +void EncClass::forms_do(FormClosure *f) { + _parameter_type.reset(); + const char *type = _parameter_type.iter(); + for ( ; type != nullptr ; type = _parameter_type.iter() ) { + f->do_form_by_name(type); + } + _localNames.forms_do(f); +} + //------------------------------Opcode----------------------------------------- Opcode::Opcode(char *primary, char *secondary, char *tertiary) : _primary(primary), _secondary(secondary), _tertiary(tertiary) { @@ -1835,6 +1870,15 @@ void InsEncode::output(FILE *fp) { fprintf(fp,"\n"); } +void InsEncode::forms_do(FormClosure *f) { + _encoding.reset(); + NameAndList *encoding = (NameAndList*)_encoding.iter(); + for( ; encoding != nullptr; encoding = (NameAndList*)_encoding.iter() ) { + // just check name, other operands will be checked as instruction parameters + f->do_form_by_name(encoding->name()); + } +} + //------------------------------Effect----------------------------------------- static int effect_lookup(const char *name) { if (!strcmp(name, "USE")) return Component::USE; @@ -1968,6 +2012,19 @@ void ExpandRule::output(FILE *fp) { // Write info to output files } } +void ExpandRule::forms_do(FormClosure *f) { + NameAndList *expand_instr = nullptr; + // Iterate over the instructions 'node' expands into + for(reset_instructions(); (expand_instr = iter_instructions()) != nullptr; ) { + f->do_form_by_name(expand_instr->name()); + } + _newopers.reset(); + const char* oper = _newopers.iter(); + for(; oper != nullptr; oper = _newopers.iter()) { + f->do_form_by_name(oper); + } +} + //------------------------------RewriteRule------------------------------------ RewriteRule::RewriteRule(char* params, char* block) : _tempParams(params), _tempBlock(block) { }; // Constructor @@ -1984,6 +2041,12 @@ void RewriteRule::output(FILE *fp) { // Write info to output files (_tempBlock?_tempBlock:"")); } +void RewriteRule::forms_do(FormClosure *f) { + if (_condition) f->do_form(_condition); + if (_instrs) f->do_form(_instrs); + if (_opers) f->do_form(_opers); +} + //==============================MachNodes====================================== //------------------------------MachNodeForm----------------------------------- @@ -2066,6 +2129,13 @@ void OpClassForm::output(FILE *fp) { fprintf(fp,"\n"); } +void OpClassForm::forms_do(FormClosure* f) { + const char *name; + for(_oplst.reset(); (name = _oplst.iter()) != nullptr;) { + f->do_form_by_name(name); + } +} + //==============================Operands======================================= //------------------------------OperandForm------------------------------------ @@ -2691,6 +2761,22 @@ void OperandForm::output(FILE *fp) { if (_format) _format->dump(); } +void OperandForm::forms_do(FormClosure* f) { + if (_matrule) f->do_form(_matrule); + if (_interface) f->do_form(_interface); + if (_attribs) f->do_form(_attribs); + if (_predicate) f->do_form(_predicate); + if (_constraint) f->do_form(_constraint); + if (_construct) f->do_form(_construct); + if (_format) f->do_form(_format); + _localNames.forms_do(f); + const char* opclass = nullptr; + for ( _classes.reset(); (opclass = _classes.iter()) != nullptr; ) { + f->do_form_by_name(opclass); + } + assert(_components.count() == 0, "skip _compnets"); +} + //------------------------------Constraint------------------------------------- Constraint::Constraint(const char *func, const char *arg) : _func(func), _arg(arg) { @@ -2712,6 +2798,10 @@ void Constraint::output(FILE *fp) { // Write info to output files fprintf(fp,"Constraint: %s ( %s )\n", _func, _arg); } +void Constraint::forms_do(FormClosure *f) { + f->do_form_by_name(_arg); +} + //------------------------------Predicate-------------------------------------- Predicate::Predicate(char *pr) : _pred(pr) { @@ -3539,6 +3629,12 @@ void MatchNode::output(FILE *fp) { } } +void MatchNode::forms_do(FormClosure *f) { + f->do_form_by_name(_name); + if (_lChild) f->do_form(_lChild); + if (_rChild) f->do_form(_rChild); +} + int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { static const char *needs_ideal_memory_list[] = { "StoreI","StoreL","StoreP","StoreN","StoreNKlass","StoreD","StoreF" , @@ -3608,6 +3704,7 @@ int InstructForm::needs_base_oop_edge(FormDict &globals) const { } + //-------------------------cisc spilling methods------------------------------- // helper routines and methods for detecting cisc-spilling instructions //-------------------------cisc_spill_merge------------------------------------ @@ -4334,6 +4431,18 @@ void MatchRule::output(FILE *fp) { fprintf(fp,"\n"); } +void MatchRule::forms_do(FormClosure* f) { + // keep sync with MatchNode::forms_do + f->do_form_by_name(_name); + if (_lChild) f->do_form(_lChild); + if (_rChild) f->do_form(_rChild); + + // handle next rule + if (_next) { + f->do_form(_next); + } +} + //------------------------------Attribute-------------------------------------- Attribute::Attribute(char *id, char* val, int type) : _ident(id), _val(val), _atype(type) { diff --git a/src/hotspot/share/adlc/formssel.hpp b/src/hotspot/share/adlc/formssel.hpp index eabd94c323a..61d0fb40f18 100644 --- a/src/hotspot/share/adlc/formssel.hpp +++ b/src/hotspot/share/adlc/formssel.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 @@ -310,6 +310,7 @@ public: virtual void dump(); // Debug printer virtual void output(FILE *fp); // Write to output files + virtual void forms_do(FormClosure *f); }; //------------------------------EncodeForm------------------------------------- @@ -333,6 +334,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure *f); }; //------------------------------EncClass--------------------------------------- @@ -377,6 +379,7 @@ public: bool verify(); void dump(); void output(FILE *fp); + virtual void forms_do(FormClosure* f); }; //------------------------------MachNode--------------------------------------- @@ -468,6 +471,7 @@ public: void dump(); void output(FILE *fp); + virtual void forms_do(FormClosure *f); }; //------------------------------Effect----------------------------------------- @@ -515,6 +519,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure *f); }; //---------------------------------Flag---------------------------------------- @@ -554,6 +559,7 @@ public: ~RewriteRule(); // Destructor void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure* f); }; @@ -584,6 +590,7 @@ public: virtual bool ideal_only() const; virtual void dump(); // Debug printer virtual void output(FILE *fp); // Write to output files + virtual void forms_do(FormClosure* f); }; //------------------------------OperandForm------------------------------------ @@ -711,6 +718,7 @@ public: virtual void dump(); // Debug printer virtual void output(FILE *fp); // Write to output files + virtual void forms_do(FormClosure* f); }; //------------------------------Constraint------------------------------------- @@ -729,6 +737,7 @@ public: void dump(); // Debug printer void output(FILE *fp); // Write info to output files + virtual void forms_do(FormClosure* f); }; //------------------------------Predicate-------------------------------------- @@ -1014,6 +1023,7 @@ public: void dump(); void output(FILE *fp); + virtual void forms_do(FormClosure* f); }; //------------------------------MatchRule-------------------------------------- @@ -1075,6 +1085,7 @@ public: void dump(); void output_short(FILE *fp); void output(FILE *fp); + virtual void forms_do(FormClosure* f); }; //------------------------------Attribute-------------------------------------- diff --git a/src/hotspot/share/adlc/main.cpp b/src/hotspot/share/adlc/main.cpp index 4d1c5491044..fd270b09443 100644 --- a/src/hotspot/share/adlc/main.cpp +++ b/src/hotspot/share/adlc/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -186,6 +186,9 @@ int main(int argc, char *argv[]) // Verify that the results of the parse are consistent AD.verify(); + // Check defined operands are used + AD.check_usage(); + // Prepare to generate the result files: AD.generateMatchLists(); AD.identify_unique_operands();