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
--- 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<RegClass>(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<CodeSnippetRegClass>(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<ConditionalRegClass>(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
--- 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
--- 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);
}
}
--- 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;
--- 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 <typename T>
+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<RegClass>(const char* className);
+template CodeSnippetRegClass* RegisterForm::addRegClass<CodeSnippetRegClass>(const char* className);
+template ConditionalRegClass* RegisterForm::addRegClass<ConditionalRegClass>(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) {
--- 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<typename T> 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-------------------------------------
--- 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;
--- 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);
}
}
}