# HG changeset patch # User zmajo # Date 1427450262 -3600 # Node ID 6f5c48bd9b823ea8ee54155d7bdc78c0e3562089 # Parent ae37510357b4a9b5cf6fae7b5b201a8f0defed1f 8075798: Allow ADLC register class to depend on runtime conditions also for cisc-spillable classes Summary: Introduce a new register class, reg_class_dynamic, that supports also cist-spillable masks. Reviewed-by: kvn, dlong, roland diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/adlparse.cpp --- a/hotspot/src/share/vm/adlc/adlparse.cpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/adlparse.cpp Fri Mar 27 10:57:42 2015 +0100 @@ -800,6 +800,7 @@ } if (strcmp(token,"reg_def")==0) { reg_def_parse(); } else if (strcmp(token,"reg_class")==0) { reg_class_parse(); } + else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); } else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); } else if (strcmp(token,"#define")==0) { preproc_define(); } else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; } @@ -2323,11 +2324,12 @@ // Debug Stuff if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname); - RegClass *reg_class = _AD._register->addRegClass(cname); - - // Collect registers in class skipws(); if (_curchar == '(') { + // A register list is defined for the register class. + // Collect registers into a generic RegClass register class. + RegClass* reg_class = _AD._register->addRegClass(cname); + next_char(); // Skip '(' skipws(); while (_curchar != ')') { @@ -2352,12 +2354,15 @@ } next_char(); // Skip closing ')' } else if (_curchar == '%') { + // A code snippet is defined for the register class. + // Collect the code snippet into a CodeSnippetRegClass register class. + CodeSnippetRegClass* reg_class = _AD._register->addRegClass(cname); char *code = find_cpp_block("reg class"); if (code == NULL) { parse_err(SYNERR, "missing code declaration for reg class.\n"); return; } - reg_class->_user_defined = code; + reg_class->set_code_snippet(code); return; } @@ -2374,6 +2379,87 @@ return; } +//------------------------------reg_class_dynamic_parse------------------------ +void ADLParser::reg_class_dynamic_parse(void) { + char *cname; // Name of dynamic register class being defined + + // Get register class name + skipws(); + cname = get_ident(); + if (cname == NULL) { + parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n"); + return; + } + + if (_AD._adl_debug > 1) { + fprintf(stdout, "Dynamic Register Class: %s\n", cname); + } + + skipws(); + if (_curchar != '(') { + parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n"); + return; + } + next_char(); + skipws(); + + // Collect two register classes and the C++ code representing the condition code used to + // select between the two classes into a ConditionalRegClass register class. + ConditionalRegClass* reg_class = _AD._register->addRegClass(cname); + int i; + for (i = 0; i < 2; i++) { + char* name = get_ident(); + if (name == NULL) { + parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n"); + return; + } + RegClass* rc = _AD._register->getRegClass(name); + if (rc == NULL) { + parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name); + } else { + reg_class->set_rclass_at_index(i, rc); + } + + skipws(); + if (_curchar == ',') { + next_char(); + skipws(); + } else { + parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n"); + } + } + + // Collect the condition code. + skipws(); + if (_curchar == '%') { + char* code = find_cpp_block("reg class dynamic"); + if (code == NULL) { + parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n"); + return; + } + reg_class->set_condition_code(code); + } else { + parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n"); + return; + } + + skipws(); + if (_curchar != ')') { + parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n"); + return; + } + next_char(); + + skipws(); + if (_curchar != ';') { + parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n"); + return; + } + next_char(); // Skip trailing ';' + + return; +} + //------------------------------alloc_class_parse------------------------------ void ADLParser::alloc_class_parse(void) { char *name; // Name of allocation class being defined diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/adlparse.hpp --- a/hotspot/src/share/vm/adlc/adlparse.hpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/adlparse.hpp Fri Mar 27 10:57:42 2015 +0100 @@ -53,6 +53,8 @@ // ***** Register Section ***** class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; // ***** Pipeline Section ***** @@ -125,6 +127,7 @@ // Parse components of the register section void reg_def_parse(void); // Parse register definition void reg_class_parse(void); // Parse register class definition + void reg_class_dynamic_parse(void); // Parse dynamic register class definition void alloc_class_parse(void); // Parse allocation class definition // Parse components of the definition section diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/archDesc.cpp --- a/hotspot/src/share/vm/adlc/archDesc.cpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/archDesc.cpp Fri Mar 27 10:57:42 2015 +0100 @@ -908,7 +908,7 @@ void ArchDesc::set_stack_or_reg(const char *reg_class_name) { if( _register ) { RegClass *reg_class = _register->getRegClass(reg_class_name); - reg_class->_stack_or_reg = true; + reg_class->set_stack_version(true); } } diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/forms.hpp --- a/hotspot/src/share/vm/adlc/forms.hpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/forms.hpp Fri Mar 27 10:57:42 2015 +0100 @@ -68,6 +68,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/formsopt.cpp --- a/hotspot/src/share/vm/adlc/formsopt.cpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/formsopt.cpp Fri Mar 27 10:57:42 2015 +0100 @@ -47,13 +47,19 @@ } // record a new register class -RegClass *RegisterForm::addRegClass(const char *className) { - RegClass *regClass = new RegClass(className); +template +T* RegisterForm::addRegClass(const char* className) { + T* regClass = new T(className); _rclasses.addName(className); - _regClass.Insert(className,regClass); + _regClass.Insert(className, regClass); return regClass; } +// Explicit instantiation for all supported register classes. +template RegClass* RegisterForm::addRegClass(const char* className); +template CodeSnippetRegClass* RegisterForm::addRegClass(const char* className); +template ConditionalRegClass* RegisterForm::addRegClass(const char* className); + // record a new register class AllocClass *RegisterForm::addAllocClass(char *className) { AllocClass *allocClass = new AllocClass(className); @@ -67,9 +73,9 @@ void RegisterForm::addSpillRegClass() { // Stack slots start at the next available even register number. _reg_ctr = (_reg_ctr+7) & ~7; - const char *rc_name = "stack_slots"; - RegClass *reg_class = new RegClass(rc_name); - reg_class->_stack_or_reg = true; + const char *rc_name = "stack_slots"; + RegClass* reg_class = new RegClass(rc_name); + reg_class->set_stack_version(true); _rclasses.addName(rc_name); _regClass.Insert(rc_name,reg_class); } @@ -224,9 +230,11 @@ //------------------------------RegClass--------------------------------------- // Construct a register class into which registers will be inserted -RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena), - _user_defined(NULL) -{ +RegClass::RegClass(const char* classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr, hashstr, Form::arena) { +} + +RegClass::~RegClass() { + delete _classid; } // record a register in this class @@ -305,6 +313,91 @@ fprintf(fp,"--- done with entries for reg_class %s\n\n",_classid); } +void RegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + if (_stack_or_reg) { + fprintf(fp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); + } + delete[] rc_name_to_upper; +} + +void RegClass::build_register_masks(FILE* fp) { + int len = RegisterForm::RegMask_Size(); + const char *prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); + + int i; + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, false)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, false)); + + if (_stack_or_reg) { + fprintf(fp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); + for(i = 0; i < len - 1; i++) { + fprintf(fp," 0x%x,", regs_in_word(i, true)); + } + fprintf(fp," 0x%x );\n", regs_in_word(i, true)); + } + delete[] rc_name_to_upper; +} + +//------------------------------CodeSnippetRegClass--------------------------- +CodeSnippetRegClass::CodeSnippetRegClass(const char* classid) : RegClass(classid), _code_snippet(NULL) { +} + +CodeSnippetRegClass::~CodeSnippetRegClass() { + delete _code_snippet; +} + +void CodeSnippetRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, _code_snippet); + delete[] rc_name_to_upper; +} + +//------------------------------ConditionalRegClass--------------------------- +ConditionalRegClass::ConditionalRegClass(const char *classid) : RegClass(classid), _condition_code(NULL) { +} + +ConditionalRegClass::~ConditionalRegClass() { + delete _condition_code; +} + +void ConditionalRegClass::declare_register_masks(FILE* fp) { + const char* prefix = ""; + const char* rc_name_to_upper = toUpper(_classid); + const char* rclass_0_to_upper = toUpper(_rclasses[0]->_classid); + const char* rclass_1_to_upper = toUpper(_rclasses[1]->_classid); + fprintf(fp, "inline const RegMask &%s%s_mask() {" + " return (%s) ?" + " %s%s_mask() :" + " %s%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + if (_stack_or_reg) { + fprintf(fp, "inline const RegMask &%sSTACK_OR_%s_mask() {" + " return (%s) ?" + " %sSTACK_OR_%s_mask() :" + " %sSTACK_OR_%s_mask(); }\n", + prefix, rc_name_to_upper, + _condition_code, + prefix, rclass_0_to_upper, + prefix, rclass_1_to_upper); + } + delete[] rc_name_to_upper; + delete[] rclass_0_to_upper; + delete[] rclass_1_to_upper; + return; +} //------------------------------AllocClass------------------------------------- AllocClass::AllocClass(char *classid) : _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/formsopt.hpp --- a/hotspot/src/share/vm/adlc/formsopt.hpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/formsopt.hpp Fri Mar 27 10:57:42 2015 +0100 @@ -60,6 +60,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeClassForm; @@ -98,7 +100,8 @@ void addRegDef(char *regName, char *callingConv, char *c_conv, char * idealtype, char *encoding, char* concreteName); - RegClass *addRegClass(const char *className); + template T* addRegClass(const char* className); + AllocClass *addAllocClass(char *allocName); void addSpillRegClass(); @@ -154,17 +157,28 @@ }; //------------------------------RegClass--------------------------------------- +// Generic register class. This register class is the internal representation +// for the following .ad file format: +// +// reg_class ptr(RAX, RBX, ...); +// +// where ptr is the name of the register class, RAX and RBX are registers. +// +// This register class allows registers to be spilled onto the stack. Spilling +// is allowed is field _stack_or_reg is true. class RegClass : public Form { public: // Public Data const char *_classid; // Name of class NameList _regDefs; // List of registers in class Dict _regDef; // Dictionary of registers in class +protected: bool _stack_or_reg; // Allowed on any stack slot - char* _user_defined; +public: // Public Methods RegClass(const char *classid);// Constructor + virtual ~RegClass(); void addReg(RegDef *regDef); // Add a register to this class @@ -183,6 +197,115 @@ void dump(); // Debug printer void output(FILE *fp); // Write info to output files + + virtual bool has_stack_version() { + return _stack_or_reg; + } + virtual void set_stack_version(bool flag) { + _stack_or_reg = flag; + } + + virtual void declare_register_masks(FILE* fp); + virtual void build_register_masks(FILE* fp); +}; + +//------------------------------CodeSnippetRegClass---------------------------- +// Register class that has an user-defined C++ code snippet attached to it +// to determine at runtime which register class to use. This register class is +// the internal representation for the following .ad file format: +// +// reg_class actual_dflt_reg %{ +// if (VM_Version::has_vfp3_32()) { +// return DFLT_REG_mask(); +// } else { +// return DFLT_LOW_REG_mask(); +// } +// %} +// +// where DFLT_REG_mask() and DFLT_LOW_REG_mask() are the internal names of the +// masks of register classes dflt_reg and dflt_low_reg. +// +// The attached code snippet can select also between more than two register classes. +// This register class can be, however, used only if the register class is not +// cisc-spillable (i.e., the registers of this class are not allowed on the stack, +// which is equivalent with _stack_or_reg being false). +class CodeSnippetRegClass : public RegClass { +protected: + char* _code_snippet; +public: + CodeSnippetRegClass(const char* classid);// Constructor + ~CodeSnippetRegClass(); + + void set_code_snippet(char* code) { + _code_snippet = code; + } + char* code_snippet() { + return _code_snippet; + } + void set_stack_version(bool flag) { + assert(false, "User defined register classes are not allowed to spill to the stack."); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } +}; + +//------------------------------ConditionalRegClass---------------------------- +// Register class that has two register classes and a runtime condition attached +// to it. The condition is evaluated at runtime and either one of the register +// attached register classes is selected. This register class is the internal +// representation for the following .ad format: +// +// reg_class_dynamic actual_dflt_reg(dflt_reg, low_reg, +// %{ VM_Version::has_vfp3_32() }% +// ); +// +// This example is equivalent to the example used with the CodeSnippetRegClass +// register class. A ConditionalRegClass works also if a register class is cisc-spillable +// (i.e., _stack_or_reg is true), but if can select only between two register classes. +class ConditionalRegClass : public RegClass { +protected: + // reference to condition code + char* _condition_code; // C++ condition code to dynamically determine which register class to use. + + // Example syntax (equivalent to previous example): + // + // reg_class actual_dflt_reg(dflt_reg, low_reg, + // %{ VM_Version::has_vfp3_32() }% + // ); + // reference to conditional register classes + RegClass* _rclasses[2]; // 0 is the register class selected if the condition code returns true + // 1 is the register class selected if the condition code returns false +public: + ConditionalRegClass(const char* classid);// Constructor + ~ConditionalRegClass(); + + virtual void set_stack_version(bool flag) { + RegClass::set_stack_version(flag); + assert((_rclasses[0] != NULL), "Register class NULL for condition code == true"); + assert((_rclasses[1] != NULL), "Register class NULL for condition code == false"); + _rclasses[0]->set_stack_version(flag); + _rclasses[1]->set_stack_version(flag); + } + void declare_register_masks(FILE* fp); + void build_register_masks(FILE* fp) { + // We do not need to generate register masks because we select at runtime + // between register masks generated for other register classes. + return; + } + void set_rclass_at_index(int index, RegClass* rclass) { + assert((0 <= index && index < 2), "Condition code can select only between two register classes"); + _rclasses[index] = rclass; + } + void set_condition_code(char* code) { + _condition_code = code; + } + char* condition_code() { + return _condition_code; + } }; //------------------------------AllocClass------------------------------------- diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/formssel.hpp --- a/hotspot/src/share/vm/adlc/formssel.hpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/formssel.hpp Fri Mar 27 10:57:42 2015 +0100 @@ -59,6 +59,8 @@ class InsEncode; class RegDef; class RegClass; +class CodeSnippetRegClass; +class ConditionalRegClass; class AllocClass; class ResourceForm; class PipeDesc; diff -r ae37510357b4 -r 6f5c48bd9b82 hotspot/src/share/vm/adlc/output_c.cpp --- a/hotspot/src/share/vm/adlc/output_c.cpp Mon Mar 23 11:20:38 2015 +0000 +++ b/hotspot/src/share/vm/adlc/output_c.cpp Fri Mar 27 10:57:42 2015 +0100 @@ -138,26 +138,9 @@ fprintf(fp_hpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - const char* rc_name_to_upper = toUpper(rc_name); - - if (reg_class->_user_defined == NULL) { - fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } else { - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, reg_class->_user_defined); - } - - if (reg_class->_stack_or_reg) { - assert(reg_class->_user_defined == NULL, "no user defined reg class here"); - fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); - fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); - } - delete[] rc_name_to_upper; - + reg_class->declare_register_masks(fp_hpp); } } } @@ -173,35 +156,9 @@ fprintf(fp_cpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { - const char *prefix = ""; RegClass *reg_class = _register->getRegClass(rc_name); assert(reg_class, "Using an undefined register class"); - - if (reg_class->_user_defined != NULL) { - continue; - } - - int len = RegisterForm::RegMask_Size(); - const char* rc_name_to_upper = toUpper(rc_name); - fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); - - { - int i; - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,", reg_class->regs_in_word(i, false)); - } - fprintf(fp_cpp," 0x%x );\n", reg_class->regs_in_word(i, false)); - } - - if (reg_class->_stack_or_reg) { - int i; - fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); - for(i = 0; i < len - 1; i++) { - fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i, true)); - } - fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i, true)); - } - delete[] rc_name_to_upper; + reg_class->build_register_masks(fp_cpp); } } }