C:\hotspot-69087d08d473\src\share\vm/adlc/adlc.hpp
#ifndef SHARE_VM_ADLC_ADLC_HPP
#define SHARE_VM_ADLC_ADLC_HPP
#include "stdio.h"
#include "stdlib.h"
#include <iostream>
#include "string.h"
#include "ctype.h"
#include "stdarg.h"
#include <sys/types.h>
#if _MSC_VER >= 1300
using namespace std;
#endif
#if _MSC_VER >= 1400
#define strdup _strdup
#endif
#ifdef _WIN32
#ifndef _INTPTR_T_DEFINED
#ifdef _WIN64
typedef __int64 intptr_t;
#else
typedef int intptr_t;
#endif
#define _INTPTR_T_DEFINED
#endif
#ifndef _UINTPTR_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef unsigned int uintptr_t;
#endif
#define _UINTPTR_T_DEFINED
#endif
#endif // _WIN32
#if defined(LINUX) || defined(_ALLBSD_SOURCE)
#include <inttypes.h>
#endif // LINUX || _ALLBSD_SOURCE
#define uint32 unsigned int
#define uint unsigned int
#include "opto/opcodes.hpp"
#undef assert
#define assert(cond, msg) { if (!(cond)) { fprintf(stderr, "assert fails %s %d: %s\n", __FILE__, __LINE__, msg); abort(); }}
#undef max
#define max(a, b) (((a)>(b)) ? (a) : (b))
#include "arena.hpp"
#include "opto/adlcVMDeps.hpp"
#include "filebuff.hpp"
#include "dict2.hpp"
#include "forms.hpp"
#include "formsopt.hpp"
#include "formssel.hpp"
#include "archDesc.hpp"
#include "adlparse.hpp"
extern ArchDesc* globalAD;
#endif // SHARE_VM_ADLC_ADLC_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/adlparse.cpp
#include "adlc.hpp"
ADLParser::ADLParser(FileBuff& buffer, ArchDesc& archDesc)
: _buf(buffer), _AD(archDesc),
_globalNames(archDesc.globalNames()) {
_AD._syntax_errs = _AD._semantic_errs = 0; // No errors so far this file
_AD._warnings = 0; // No warnings either
_curline = _ptr = NULL; // No pointers into buffer yet
_preproc_depth = 0;
_preproc_not_taken = 0;
_AD._preproc_list.add_signal();
}
ADLParser::~ADLParser() {
if (!_AD._quiet_mode)
fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n");
#ifndef ASSERT
fprintf(stderr, "**************************************************************\n");
fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n");
fprintf(stderr, "**************************************************************\n");
#endif
if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) {
if (!_AD._quiet_mode)
fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" );
}
else {
if( _AD._syntax_errs ) { // Any syntax errors?
fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs);
if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n");
else fprintf(stderr,".\n\n");
}
if( _AD._semantic_errs ) { // Any semantic errors?
fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs);
if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n");
else fprintf(stderr,".\n\n");
}
if( _AD._warnings ) { // Any warnings?
fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings);
if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n");
else fprintf(stderr,".\n\n");
}
}
if (!_AD._quiet_mode)
fprintf(stderr,"-----------------------------------------------------------------------------\n");
_AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine
}
void ADLParser::parse() {
char *ident;
for( next_line(); _curline != NULL; next_line()) {
_ptr = _curline; // Reset ptr to start of new line
skipws(); // Skip any leading whitespace
ident = get_ident(); // Get first token
if (ident == NULL) { // Empty line
continue; // Get the next line
}
if (!strcmp(ident, "instruct")) instr_parse();
else if (!strcmp(ident, "operand")) oper_parse();
else if (!strcmp(ident, "opclass")) opclass_parse();
else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();
else if (!strcmp(ident, "op_attrib")) op_attr_parse();
else if (!strcmp(ident, "source")) source_parse();
else if (!strcmp(ident, "source_hpp")) source_hpp_parse();
else if (!strcmp(ident, "register")) reg_parse();
else if (!strcmp(ident, "frame")) frame_parse();
else if (!strcmp(ident, "encode")) encode_parse();
else if (!strcmp(ident, "pipeline")) pipe_parse();
else if (!strcmp(ident, "definitions")) definitions_parse();
else if (!strcmp(ident, "peephole")) peep_parse();
else if (!strcmp(ident, "#line")) preproc_line();
else if (!strcmp(ident, "#define")) preproc_define();
else if (!strcmp(ident, "#undef")) preproc_undef();
else {
parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident);
}
}
RegisterForm *regBlock = _AD.get_registers();
if (regBlock == NULL) {
parse_err(SEMERR, "Did not declare 'register' definitions");
}
regBlock->addSpillRegClass();
if (_preproc_depth != 0) {
parse_err(SYNERR, "End of file inside #ifdef");
}
if (_globalNames[AttributeForm::_ins_cost] == NULL) {
parse_err(SEMERR, "Did not declare 'ins_cost' attribute");
}
if (_globalNames[AttributeForm::_op_cost] == NULL) {
parse_err(SEMERR, "Did not declare 'op_cost' attribute");
}
}
void ADLParser::instr_parse(void) {
char *ident;
InstructForm *instr;
MatchRule *rule;
int match_rules_cnt = 0;
if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL )
return;
instr = new InstructForm(ident); // Create new instruction form
instr->_linenum = linenum();
_globalNames.Insert(ident, instr); // Add name to the name table
if (_AD._adl_debug > 1)
fprintf(stderr,"Parsing Instruction Form %s\n", ident);
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' in instruct definition\n");
}
else get_oplist(instr->_parameters, instr->_localNames);
skipws(); // Skip leading whitespace
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '{')) ) {
parse_err(SYNERR, "missing '%%{' in instruction definition\n");
return;
}
next_char(); // Maintain the invariant
do {
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
continue;
}
if (!strcmp(ident, "predicate")) instr->_predicate = pred_parse();
else if (!strcmp(ident, "match")) {
rule = instr->_matrule;
if (rule == NULL) {
rule = match_parse(instr->_localNames);
if (rule) {
instr->_matrule = rule;
if( instr->is_ideal_control() ) {
rule->_result = "Universe";
}
matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
}
} else {
while (rule->_next != NULL)
rule = rule->_next;
rule->_next = match_parse(instr->_localNames);
if (rule->_next) {
rule = rule->_next;
if( instr->is_ideal_control() ) {
parse_err(SYNERR, "unique match rule expected for %s\n", rule->_name);
return;
}
assert(match_rules_cnt < 100," too many match rule clones");
char* buf = (char*) malloc(strlen(instr->_ident) + 4);
sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++);
rule->_result = buf;
matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
}
}
}
else if (!strcmp(ident, "encode")) {
parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
}
else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);
else if (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr);
else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
else if (!strcmp(ident, "effect")) effect_parse(instr);
else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
else if (!strcmp(ident, "constraint")) {
parse_err(SYNERR, "Instructions do not specify a constraint\n");
}
else if (!strcmp(ident, "construct")) {
parse_err(SYNERR, "Instructions do not specify a construct\n");
}
else if (!strcmp(ident, "format")) instr->_format = format_parse();
else if (!strcmp(ident, "interface")) {
parse_err(SYNERR, "Instructions do not specify an interface\n");
}
else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);
else { // Done with staticly defined parts of instruction definition
const Form *form = _globalNames[ident];
AttributeForm *attr = form ? form->is_attribute() : NULL;
if (attr && (attr->_atype == INS_ATTR)) {
Attribute *temp = attr_parse(ident);
temp->_next = instr->_attribs;
instr->_attribs = temp;
} else {
parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of"
" an instruction attribute at %s\n", ident);
}
}
skipws();
} while(_curchar != '%');
next_char();
if (_curchar != '}') {
parse_err(SYNERR, "missing '%%}' in instruction definition\n");
return;
}
adjust_set_rule(instr);
if (_AD._pipeline) {
if (instr->expands() || instr->postalloc_expands()) {
if (instr->_ins_pipe) {
parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\";"
" ins_pipe will be unused\n", instr->_ident);
}
} else {
if (!instr->_ins_pipe) {
parse_err(WARN, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident);
}
}
}
_AD.addForm(instr);
rule = instr->_matrule;
if (rule != NULL) {
rule = rule->_next;
while (rule != NULL) {
ident = (char*)rule->_result;
InstructForm *clone = new InstructForm(ident, instr, rule); // Create new instruction form
_globalNames.Insert(ident, clone); // Add name to the name table
if (_AD._adl_debug > 1)
fprintf(stderr,"Parsing Instruction Form %s\n", ident);
adjust_set_rule(clone);
_AD.addForm(clone);
rule = rule->_next;
clone->_matrule->_next = NULL; // One match rule per clone
}
}
}
void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_ident, int& match_rules_cnt) {
int count = 0;
rule->count_commutative_op(count);
if (count > 0) {
rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);
}
}
void ADLParser::adjust_set_rule(InstructForm *instr) {
if (instr->_matrule == NULL || instr->_matrule->_rChild == NULL) return;
const char *rch = instr->_matrule->_rChild->_opType;
const Form *frm = _globalNames[rch];
if( (! strcmp(instr->_matrule->_opType,"Set")) &&
frm && frm->is_operand() && (! frm->ideal_only()) ) {
unsigned position = 0;
const char *result = NULL;
const char *name = NULL;
const char *optype = NULL;
MatchNode *right = instr->_matrule->_rChild;
if (right->base_operand(position, _globalNames, result, name, optype)) {
position = 1;
const char *result2 = NULL;
const char *name2 = NULL;
const char *optype2 = NULL;
if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) {
if (instr->_predicate != NULL)
parse_err(SYNERR, "ADLC does not support instruction chain rules with predicates");
ChainList *lst = (ChainList *)_AD._chainRules[optype];
if (lst == NULL) {
lst = new ChainList();
_AD._chainRules.Insert(optype, lst);
}
if (!lst->search(instr->_matrule->_lChild->_opType)) {
const char *cost = instr->cost();
if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
}
if( frm->is_operand() == NULL || frm->is_operand()->_predicate == NULL ) {
lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
}
}
lst = (ChainList *)_AD._chainRules[result];
if (lst == NULL) {
lst = new ChainList();
_AD._chainRules.Insert(result, lst);
}
if (!lst->search(instr->_matrule->_lChild->_opType)) {
const char *cost = instr->cost();
if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
}
lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
}
} else {
OperandForm *rightOp = _globalNames[right->_opType]->is_operand();
if( rightOp ) {
const Form *rightRoot = _globalNames[rightOp->_matrule->_opType];
if( rightRoot && rightRoot->ideal_only() ) {
const char *chain_op = NULL;
if( rightRoot->is_instruction() )
chain_op = rightOp->_ident;
if( chain_op ) {
ChainList *lst = (ChainList *)_AD._chainRules[chain_op];
if (lst == NULL) {
lst = new ChainList();
_AD._chainRules.Insert(chain_op, lst);
}
const char *cost = instr->cost();
if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
}
lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
}
}
}
} // end chain rule from right-tree's ideal root
}
}
}
void ADLParser::oper_parse(void) {
char *ident;
OperandForm *oper;
AttributeForm *attr;
MatchRule *rule;
skipws();
if( (ident = get_unique_ident(_globalNames,"operand")) == NULL )
return;
oper = new OperandForm(ident); // Create new operand form
oper->_linenum = linenum();
_globalNames.Insert(ident, oper); // Add name to the name table
if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Operand Form %s\n", ident);
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' in operand definition\n");
return;
}
else get_oplist(oper->_parameters, oper->_localNames); // Parse the component operand list
skipws();
if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block
parse_err(SYNERR, "missing '%%{' in operand definition\n");
return;
}
next_char(); next_char(); // Skip over "%{" symbol
do {
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
continue;
}
if (!strcmp(ident, "predicate")) oper->_predicate = pred_parse();
else if (!strcmp(ident, "match")) {
rule = oper->_matrule;
if (rule) {
while (rule->_next) rule = rule->_next;
rule->_next = match_parse(oper->_localNames);
if (rule->_next) {
rule->_next->_result = oper->_ident;
}
}
else {
oper->_matrule = match_parse(oper->_localNames);
if (oper->_matrule) {
oper->_matrule->_result = oper->_ident;
}
}
}
else if (!strcmp(ident, "encode")) oper->_interface = interface_parse();
else if (!strcmp(ident, "ins_encode")) {
parse_err(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");
}
else if (!strcmp(ident, "opcode")) {
parse_err(SYNERR, "Operands do not specify an opcode\n");
}
else if (!strcmp(ident, "effect")) {
parse_err(SYNERR, "Operands do not specify an effect\n");
}
else if (!strcmp(ident, "expand")) {
parse_err(SYNERR, "Operands do not specify an expand\n");
}
else if (!strcmp(ident, "rewrite")) {
parse_err(SYNERR, "Operands do not specify a rewrite\n");
}
else if (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse();
else if (!strcmp(ident, "construct")) oper->_construct = construct_parse();
else if (!strcmp(ident, "format")) oper->_format = format_parse();
else if (!strcmp(ident, "interface")) oper->_interface = interface_parse();
else if (((attr = _globalNames[ident]->is_attribute()) != NULL) &&
(attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident);
else {
parse_err(SYNERR, "expected one of - constraint, predicate, match, encode, format, construct, or the name of a defined operand attribute at %s\n", ident);
}
skipws();
} while(_curchar != '%');
next_char();
if (_curchar != '}') {
parse_err(SYNERR, "missing '%%}' in operand definition\n");
return;
}
_AD.addForm(oper);
}
void ADLParser::opclass_parse(void) {
char *ident;
OpClassForm *opc;
OperandForm *opForm;
skipws();
if( (ident = get_unique_ident(_globalNames,"opclass")) == NULL )
return;
opc = new OpClassForm(ident); // Create new operand class form
_globalNames.Insert(ident, opc); // Add name to the name table
if (_AD._adl_debug > 1)
fprintf(stderr,"Parsing Operand Class Form %s\n", ident);
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' in operand definition\n");
return;
}
do {
next_char(); // Skip past open paren or comma
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
continue;
}
const Form *form = _globalNames[ident];
opForm = form ? form->is_operand() : NULL;
if ( opForm ) {
opc->_oplst.addName(ident); // Add operand to opclass list
opForm->_classes.addName(opc->_ident);// Add opclass to operand list
}
else {
parse_err(SYNERR, "expected name of a defined operand at %s\n", ident);
}
skipws(); // skip trailing whitespace
} while (_curchar == ','); // Check for the comma
if (_curchar != ')') {
parse_err(SYNERR, "missing ')' or ',' in opclass definition\n");
return;
}
next_char(); // Consume the ')'
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in opclass definition\n");
return;
}
next_char(); // Consume the ';'
_AD.addForm(opc);
}
void ADLParser::ins_attr_parse(void) {
char *ident;
char *aexpr;
AttributeForm *attrib;
skipws(); // Skip leading whitespace
if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL )
return;
if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Ins_Attribute Form %s\n", ident);
skipws(); // Skip whitespace
if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {
parse_err(SYNERR, "missing '(' in ins_attrib definition\n");
return;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
return;
}
next_char(); // Advance past the ';'
attrib = new AttributeForm(ident, INS_ATTR, aexpr);
_globalNames.Insert(ident, attrib); // Add name to the name table
_AD.addForm(attrib);
}
void ADLParser::op_attr_parse(void) {
char *ident;
char *aexpr;
AttributeForm *attrib;
skipws(); // Skip leading whitespace
if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL )
return;
if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Op_Attribute Form %s\n", ident);
skipws(); // Skip whitespace
if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {
parse_err(SYNERR, "missing '(' in op_attrib definition\n");
return;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in op_attrib definition\n");
return;
}
next_char(); // Advance past the ';'
attrib = new AttributeForm(ident, OP_ATTR, aexpr);
_globalNames.Insert(ident, attrib);
_AD.addForm(attrib);
}
void ADLParser::definitions_parse(void) {
skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') {
next_char(); next_char(); // Skip "%{"
skipws();
while (_curchar != '%' && *(_ptr+1) != '}') {
char *token = get_ident();
if (token == NULL) {
parse_err(SYNERR, "missing identifier inside definitions block.\n");
return;
}
if (strcmp(token,"int_def")==0) { int_def_parse(); }
skipws();
}
}
else {
parse_err(SYNERR, "Missing %%{ ... %%} block after definitions keyword.\n");
return;
}
}
void ADLParser::int_def_parse(void) {
char *name = NULL; // Name of definition
char *value = NULL; // its value,
int int_value = -1; // positive values only
char *description = NULL; // textual description
skipws(); // Skip whitespace
name = get_ident();
if (name == NULL) {
parse_err(SYNERR, "missing definition name after int_def\n");
return;
}
skipws();
if (_curchar == '(') {
next_char();
value = get_ident();
if (value == NULL) {
parse_err(SYNERR, "missing value in int_def\n");
return;
}
if( !is_int_token(value, int_value) ) {
parse_err(SYNERR, "value in int_def is not recognized as integer\n");
return;
}
skipws();
if (_curchar == ',') {
next_char(); // skip ','
description = get_expr("int_def description", ")");
if (description == NULL) {
parse_err(SYNERR, "invalid or missing description in int_def\n");
return;
}
trim(description);
}
if (_curchar != ')') {
parse_err(SYNERR, "missing ')' in register definition statement\n");
return;
}
next_char();
}
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' after int_def\n");
return;
}
next_char(); // move past ';'
if (_AD._adl_debug > 1) {
fprintf(stderr,"int_def: %s ( %s, %s )\n", name,
(value), (description ? description : ""));
}
Expr *expr = new Expr(name, description, int_value, int_value);
const Expr *old_expr = _AD.globalDefs().define(name, expr);
if (old_expr != NULL) {
parse_err(SYNERR, "Duplicate definition\n");
return;
}
return;
}
void ADLParser::source_parse(void) {
SourceForm *source; // Encode class for instruction/operand
char *rule = NULL; // String representation of encode rule
skipws(); // Skip leading whitespace
if ( (rule = find_cpp_block("source block")) == NULL ) {
parse_err(SYNERR, "incorrect or missing block for 'source'.\n");
return;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Source Form: %s\n", rule);
source = new SourceForm(rule); // Build new Source object
_AD.addForm(source);
}
void ADLParser::source_hpp_parse(void) {
char *rule = NULL; // String representation of encode rule
skipws(); // Skip leading whitespace
if ( (rule = find_cpp_block("source_hpp block")) == NULL ) {
parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n");
return;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);
if (_AD.get_registers() == NULL) {
PreHeaderForm* pre_header = new PreHeaderForm(rule);
_AD.addForm(pre_header);
} else {
HeaderForm* header = new HeaderForm(rule);
_AD.addForm(header);
}
}
void ADLParser::reg_parse(void) {
RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding
if (regBlock == NULL) {
regBlock = new RegisterForm(); // Build new Source object
_AD.addForm(regBlock);
}
skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') {
next_char(); next_char(); // Skip "%{"
skipws();
while (_curchar != '%' && *(_ptr+1) != '}') {
char *token = get_ident();
if (token == NULL) {
parse_err(SYNERR, "missing identifier inside register block.\n");
return;
}
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; }
skipws();
}
}
else {
parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');
return;
}
}
void ADLParser::encode_parse(void) {
EncodeForm *encBlock; // Information about instruction/operand encoding
_AD.getForm(&encBlock);
if ( encBlock == NULL) {
encBlock = new EncodeForm(); // Build new Source object
_AD.addForm(encBlock);
}
skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') {
next_char(); next_char(); // Skip "%{"
skipws();
while (_curchar != '%' && *(_ptr+1) != '}') {
char *token = get_ident();
if (token == NULL) {
parse_err(SYNERR, "missing identifier inside encoding block.\n");
return;
}
if (strcmp(token,"enc_class")==0) { enc_class_parse(); }
skipws();
}
}
else {
parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');
return;
}
}
void ADLParser::enc_class_parse(void) {
char *ec_name; // Name of encoding class being defined
skipws(); // Skip whitespace
ec_name = get_ident();
if (ec_name == NULL) {
parse_err(SYNERR, "missing encoding class name after encode.\n");
return;
}
EncClass *encoding = _AD._encode->add_EncClass(ec_name);
encoding->_linenum = linenum();
skipws(); // Skip leading whitespace
if (_curchar == '(') {
do {
char *pType = NULL; // parameter type
char *pName = NULL; // parameter name
next_char(); // skip open paren & comma characters
skipws();
if (_curchar == ')') break;
pType = get_ident();
if (pType == NULL) {
parse_err(SYNERR, "parameter type expected at %c\n", _curchar);
return;
}
skipws();
pName = get_ident();
if (pName == NULL) {
parse_err(SYNERR, "parameter name expected at %c\n", _curchar);
return;
}
encoding->add_parameter( pType, pName );
skipws();
} while(_curchar == ',');
if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");
else {
next_char(); // Skip ')'
}
} // Done with parameter list
skipws();
if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block
parse_err(SYNERR, "missing '%c{' in enc_class definition\n", '%');
return;
}
next_char(); // Skip '%'
next_char(); // Skip '{'
enc_class_parse_block(encoding, ec_name);
}
void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {
skipws_no_preproc(); // Skip leading whitespace
if (_AD._adlocation_debug) {
encoding->add_code(get_line_string());
}
while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else {
next_char_or_line();
}
}
if ( start != _ptr ) {
encoding->add_code(start);
}
if (_curchar == '$') {
char* rep_var = get_rep_var_ident_dup();
encoding->add_rep_var(rep_var);
}
} // end while part of format description
next_char(); // Skip '%'
next_char(); // Skip '}'
skipws();
if (_AD._adlocation_debug) {
encoding->add_code(end_line_marker());
}
if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name);
}
void ADLParser::frame_parse(void) {
FrameForm *frame; // Information about stack-frame layout
char *desc = NULL; // String representation of frame
skipws(); // Skip leading whitespace
frame = new FrameForm(); // Build new Frame object
skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') {
next_char(); next_char(); // Skip "%{"
skipws();
while (_curchar != '%' && *(_ptr+1) != '}') {
char *token = get_ident();
if (token == NULL) {
parse_err(SYNERR, "missing identifier inside frame block.\n");
return;
}
if (strcmp(token,"stack_direction")==0) {
stack_dir_parse(frame);
}
if (strcmp(token,"sync_stack_slots")==0) {
sync_stack_slots_parse(frame);
}
if (strcmp(token,"frame_pointer")==0) {
frame_pointer_parse(frame, false);
}
if (strcmp(token,"interpreter_frame_pointer")==0) {
interpreter_frame_pointer_parse(frame, false);
}
if (strcmp(token,"inline_cache_reg")==0) {
inline_cache_parse(frame, false);
}
if (strcmp(token,"compiler_method_oop_reg")==0) {
parse_err(WARN, "Using obsolete Token, compiler_method_oop_reg");
skipws();
}
if (strcmp(token,"interpreter_method_oop_reg")==0) {
interpreter_method_oop_parse(frame, false);
}
if (strcmp(token,"cisc_spilling_operand_name")==0) {
cisc_spilling_operand_name_parse(frame, false);
}
if (strcmp(token,"stack_alignment")==0) {
stack_alignment_parse(frame);
}
if (strcmp(token,"return_addr")==0) {
return_addr_parse(frame, false);
}
if (strcmp(token,"in_preserve_stack_slots")==0) {
preserve_stack_parse(frame);
}
if (strcmp(token,"out_preserve_stack_slots")==0) {
parse_err(WARN, "Using obsolete token, out_preserve_stack_slots");
skipws();
}
if (strcmp(token,"varargs_C_out_slots_killed")==0) {
frame->_varargs_C_out_slots_killed = parse_one_arg("varargs C out slots killed");
}
if (strcmp(token,"calling_convention")==0) {
frame->_calling_convention = calling_convention_parse();
}
if (strcmp(token,"return_value")==0) {
frame->_return_value = return_value_parse();
}
if (strcmp(token,"c_frame_pointer")==0) {
frame_pointer_parse(frame, true);
}
if (strcmp(token,"c_return_addr")==0) {
return_addr_parse(frame, true);
}
if (strcmp(token,"c_calling_convention")==0) {
frame->_c_calling_convention = calling_convention_parse();
}
if (strcmp(token,"c_return_value")==0) {
frame->_c_return_value = return_value_parse();
}
skipws();
}
}
else {
parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');
return;
}
if(frame->_frame_pointer == NULL) {
parse_err(SYNERR, "missing frame pointer definition in frame section.\n");
return;
}
if(frame->_alignment == NULL) {
parse_err(SYNERR, "missing alignment definition in frame section.\n");
return;
}
if(frame->_return_addr == NULL) {
parse_err(SYNERR, "missing return address location in frame section.\n");
return;
}
if(frame->_in_preserve_slots == NULL) {
parse_err(SYNERR, "missing stack slot preservation definition in frame section.\n");
return;
}
if(frame->_varargs_C_out_slots_killed == NULL) {
parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n");
return;
}
if(frame->_calling_convention == NULL) {
parse_err(SYNERR, "missing calling convention definition in frame section.\n");
return;
}
if(frame->_return_value == NULL) {
parse_err(SYNERR, "missing return value definition in frame section.\n");
return;
}
if(frame->_c_frame_pointer == NULL) {
frame->_c_frame_pointer = frame->_frame_pointer;
}
if(frame->_c_return_addr == NULL) {
frame->_c_return_addr = frame->_return_addr;
frame->_c_return_addr_loc = frame->_return_addr_loc;
}
if(frame->_c_calling_convention == NULL) {
frame->_c_calling_convention = frame->_calling_convention;
}
if(frame->_c_return_value == NULL) {
frame->_c_return_value = frame->_return_value;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Frame Form: %s\n", desc);
_AD.addForm(frame);
}
void ADLParser::stack_dir_parse(FrameForm *frame) {
char *direction = parse_one_arg("stack direction entry");
if (strcmp(direction, "TOWARDS_LOW") == 0) {
frame->_direction = false;
}
else if (strcmp(direction, "TOWARDS_HIGH") == 0) {
frame->_direction = true;
}
else {
parse_err(SYNERR, "invalid value inside stack direction entry.\n");
return;
}
}
void ADLParser::sync_stack_slots_parse(FrameForm *frame) {
frame->_sync_stack_slots = parse_one_arg("sync stack slots entry");
}
void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) {
char *frame_pointer = parse_one_arg("frame pointer entry");
if (native) { frame->_c_frame_pointer = frame_pointer; }
else { frame->_frame_pointer = frame_pointer; }
}
void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) {
frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry");
}
void ADLParser::inline_cache_parse(FrameForm *frame, bool native) {
frame->_inline_cache_reg = parse_one_arg("inline cache reg entry");
}
void ADLParser::interpreter_method_oop_parse(FrameForm *frame, bool native) {
frame->_interpreter_method_oop_reg = parse_one_arg("method oop reg entry");
}
void ADLParser::cisc_spilling_operand_name_parse(FrameForm *frame, bool native) {
frame->_cisc_spilling_operand_name = parse_one_arg("cisc spilling operand name");
}
void ADLParser::stack_alignment_parse(FrameForm *frame) {
char *alignment = parse_one_arg("stack alignment entry");
frame->_alignment = alignment;
}
char *ADLParser::parse_one_arg(const char *description) {
char *token = NULL;
if(_curchar == '(') {
next_char();
skipws();
token = get_expr(description, ")");
if (token == NULL) {
parse_err(SYNERR, "missing value inside %s.\n", description);
return NULL;
}
next_char(); // skip the close paren
if(_curchar != ';') { // check for semi-colon
parse_err(SYNERR, "missing %c in.\n", ';', description);
return NULL;
}
next_char(); // skip the semi-colon
}
else {
parse_err(SYNERR, "Missing %c in.\n", '(', description);
return NULL;
}
trim(token);
return token;
}
void ADLParser::return_addr_parse(FrameForm *frame, bool native) {
bool in_register = true;
if(_curchar == '(') {
next_char();
skipws();
char *token = get_ident();
if (token == NULL) {
parse_err(SYNERR, "missing value inside return address entry.\n");
return;
}
if (strcmp(token, "REG") == 0) {
in_register = true;
}
else if (strcmp(token, "STACK") == 0) {
in_register = false;
}
else {
parse_err(SYNERR, "invalid value inside return_address entry.\n");
return;
}
if (native) { frame->_c_return_addr_loc = in_register; }
else { frame->_return_addr_loc = in_register; }
skipws();
char *token2 = get_expr("return address entry", ")");
if (token2 == NULL) {
parse_err(SYNERR, "missing value inside return address entry.\n");
return;
}
next_char(); // skip the close paren
if (native) { frame->_c_return_addr = token2; }
else { frame->_return_addr = token2; }
if(_curchar != ';') { // check for semi-colon
parse_err(SYNERR, "missing %c in return address entry.\n", ';');
return;
}
next_char(); // skip the semi-colon
}
else {
parse_err(SYNERR, "Missing %c in return_address entry.\n", '(');
}
}
void ADLParser::preserve_stack_parse(FrameForm *frame) {
if(_curchar == '(') {
char *token = get_paren_expr("preserve_stack_slots");
frame->_in_preserve_slots = token;
if(_curchar != ';') { // check for semi-colon
parse_err(SYNERR, "missing %c in preserve stack slot entry.\n", ';');
return;
}
next_char(); // skip the semi-colon
}
else {
parse_err(SYNERR, "Missing %c in preserve stack slot entry.\n", '(');
}
}
char *ADLParser::calling_convention_parse() {
char *desc = NULL; // String representation of calling_convention
skipws(); // Skip leading whitespace
if ( (desc = find_cpp_block("calling convention block")) == NULL ) {
parse_err(SYNERR, "incorrect or missing block for 'calling_convention'.\n");
}
return desc;
}
char *ADLParser::return_value_parse() {
char *desc = NULL; // String representation of calling_convention
skipws(); // Skip leading whitespace
if ( (desc = find_cpp_block("return value block")) == NULL ) {
parse_err(SYNERR, "incorrect or missing block for 'return_value'.\n");
}
return desc;
}
void ADLParser::ins_pipe_parse(InstructForm &instr) {
char * ident;
skipws();
if ( _curchar != '(' ) { // Check for delimiter
parse_err(SYNERR, "missing \"(\" in ins_pipe definition\n");
return;
}
next_char();
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
return;
}
skipws();
if ( _curchar != ')' ) { // Check for delimiter
parse_err(SYNERR, "missing \")\" in ins_pipe definition\n");
return;
}
next_char(); // skip the close paren
if(_curchar != ';') { // check for semi-colon
parse_err(SYNERR, "missing %c in return value entry.\n", ';');
return;
}
next_char(); // skip the semi-colon
if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) {
parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", ident);
return;
}
_AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident);
instr._ins_pipe = ident;
return;
}
void ADLParser::pipe_parse(void) {
PipelineForm *pipeline; // Encode class for instruction/operand
char * ident;
pipeline = new PipelineForm(); // Build new Source object
_AD.addForm(pipeline);
skipws(); // Skip leading whitespace
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '{')) ) {
parse_err(SYNERR, "missing '%%{' in pipeline definition\n");
return;
}
next_char(); // Maintain the invariant
do {
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
continue;
}
if (!strcmp(ident, "resources" )) resource_parse(*pipeline);
else if (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline);
else if (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline);
else if (!strcmp(ident, "define")) {
skipws();
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '{')) ) {
parse_err(SYNERR, "expected '%%{'\n");
return;
}
next_char(); skipws();
char *node_class = get_ident();
if (node_class == NULL) {
parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
return;
}
skipws();
if (_curchar != ',' && _curchar != '=') {
parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
break;
}
next_char(); skipws();
char *pipe_class = get_ident();
if (pipe_class == NULL) {
parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
return;
}
if (_curchar != ';' ) {
parse_err(SYNERR, "expected `;`, found '%c'\n", _curchar);
break;
}
next_char(); // Skip over semi-colon
skipws();
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '}')) ) {
parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);
}
next_char();
if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) {
parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", pipe_class);
return;
}
_AD._pipeline->_classdict[pipe_class]->is_pipeclass()->_instructs.addName(node_class);
MachNodeForm *machnode = new MachNodeForm(node_class); // Create new machnode form
machnode->_machnode_pipe = pipe_class;
_AD.addForm(machnode);
}
else if (!strcmp(ident, "attributes")) {
bool vsi_seen = false;
skipws();
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '{')) ) {
parse_err(SYNERR, "expected '%%{'\n");
return;
}
next_char(); skipws();
while (_curchar != '%') {
ident = get_ident();
if (ident == NULL)
break;
if (!strcmp(ident, "variable_size_instructions")) {
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
pipeline->_variableSizeInstrs = true;
vsi_seen = true;
continue;
}
if (!strcmp(ident, "fixed_size_instructions")) {
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
pipeline->_variableSizeInstrs = false;
vsi_seen = true;
continue;
}
if (!strcmp(ident, "branch_has_delay_slot")) {
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
pipeline->_branchHasDelaySlot = true;
continue;
}
if (!strcmp(ident, "max_instructions_per_bundle")) {
skipws();
if (_curchar != '=') {
parse_err(SYNERR, "expected `=`\n");
break;
}
next_char(); skipws();
pipeline->_maxInstrsPerBundle = get_int();
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
if (!strcmp(ident, "max_bundles_per_cycle")) {
skipws();
if (_curchar != '=') {
parse_err(SYNERR, "expected `=`\n");
break;
}
next_char(); skipws();
pipeline->_maxBundlesPerCycle = get_int();
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
if (!strcmp(ident, "instruction_unit_size")) {
skipws();
if (_curchar != '=') {
parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
break;
}
next_char(); skipws();
pipeline->_instrUnitSize = get_int();
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
if (!strcmp(ident, "bundle_unit_size")) {
skipws();
if (_curchar != '=') {
parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
break;
}
next_char(); skipws();
pipeline->_bundleUnitSize = get_int();
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
if (!strcmp(ident, "instruction_fetch_unit_size")) {
skipws();
if (_curchar != '=') {
parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
break;
}
next_char(); skipws();
pipeline->_instrFetchUnitSize = get_int();
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
if (!strcmp(ident, "instruction_fetch_units")) {
skipws();
if (_curchar != '=') {
parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
break;
}
next_char(); skipws();
pipeline->_instrFetchUnits = get_int();
skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
if (!strcmp(ident, "nops")) {
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar);
break;
}
next_char(); skipws();
while (_curchar != ')') {
ident = get_ident();
if (ident == NULL) {
parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar);
break;
}
pipeline->_noplist.addName(ident);
pipeline->_nopcnt++;
skipws();
if (_curchar == ',') {
next_char(); skipws();
}
}
next_char(); skipws();
if (_curchar == ';') {
next_char(); skipws();
}
continue;
}
parse_err(SYNERR, "unknown specifier \"%s\"\n", ident);
}
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '}')) ) {
parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);
}
next_char(); skipws();
if (pipeline->_maxInstrsPerBundle == 0)
parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n");
if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0)
parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n");
if (pipeline->_instrFetchUnitSize == 0)
parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n");
if (pipeline->_instrFetchUnits == 0)
parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n");
if (!vsi_seen)
parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n");
}
else { // Done with staticly defined parts of instruction definition
parse_err(SYNERR, "expected one of \"resources\", \"pipe_desc\", \"pipe_class\", found \"%s\"\n", ident);
return;
}
skipws();
if (_curchar == ';')
skipws();
} while(_curchar != '%');
next_char();
if (_curchar != '}') {
parse_err(SYNERR, "missing \"%%}\" in pipeline definition\n");
return;
}
next_char();
}
void ADLParser::resource_parse(PipelineForm &pipeline) {
ResourceForm *resource;
char * ident;
char * expr;
unsigned mask;
pipeline._rescount = 0;
skipws(); // Skip leading whitespace
if (_curchar != '(') {
parse_err(SYNERR, "missing \"(\" in resource definition\n");
return;
}
do {
next_char(); // Skip "(" or ","
ident = get_ident(); // Grab next identifier
if (_AD._adl_debug > 1) {
if (ident != NULL) {
fprintf(stderr, "resource_parse: identifier: %s\n", ident);
}
}
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
return;
}
skipws();
if (_curchar != '=') {
mask = (1 << pipeline._rescount++);
}
else {
next_char(); skipws();
expr = get_ident(); // Grab next identifier
if (expr == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
return;
}
resource = (ResourceForm *) pipeline._resdict[expr];
if (resource == NULL) {
parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);
return;
}
mask = resource->mask();
skipws();
while (_curchar == '|') {
next_char(); skipws();
expr = get_ident(); // Grab next identifier
if (expr == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
return;
}
resource = (ResourceForm *) pipeline._resdict[expr]; // Look up the value
if (resource == NULL) {
parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);
return;
}
mask |= resource->mask();
skipws();
}
}
resource = new ResourceForm(mask);
pipeline._resdict.Insert(ident, resource);
pipeline._reslist.addName(ident);
} while (_curchar == ',');
if (_curchar != ')') {
parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
return;
}
next_char(); // Skip ")"
if (_curchar == ';')
next_char(); // Skip ";"
}
void ADLParser::pipe_desc_parse(PipelineForm &pipeline) {
char * ident;
skipws(); // Skip leading whitespace
if (_curchar != '(') {
parse_err(SYNERR, "missing \"(\" in pipe_desc definition\n");
return;
}
do {
next_char(); // Skip "(" or ","
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
return;
}
pipeline._stages.addName(ident);
pipeline._stagecnt++;
skipws();
} while (_curchar == ',');
if (_curchar != ')') {
parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
return;
}
next_char(); // Skip ")"
if (_curchar == ';')
next_char(); // Skip ";"
}
void ADLParser::pipe_class_parse(PipelineForm &pipeline) {
PipeClassForm *pipe_class;
char * ident;
char * stage;
char * read_or_write;
int is_write;
int is_read;
OperandForm *oper;
skipws(); // Skip leading whitespace
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
return;
}
pipe_class = new PipeClassForm(ident, ++pipeline._classcnt);
pipeline._classdict.Insert(ident, pipe_class);
pipeline._classlist.addName(ident);
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing \"(\" in pipe_class definition\n");
}
else get_oplist(pipe_class->_parameters, pipe_class->_localNames);
skipws(); // Skip leading whitespace
if ( (_curchar != '%')
|| ( next_char(), (_curchar != '{')) ) {
parse_err(SYNERR, "missing \"%%{\" in pipe_class definition\n");
return;
}
next_char();
do {
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
continue;
}
skipws();
if (!strcmp(ident, "fixed_latency")) {
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing \"(\" in latency definition\n");
return;
}
next_char(); skipws();
if( !isdigit(_curchar) ) {
parse_err(SYNERR, "number expected for \"%c\" in latency definition\n", _curchar);
return;
}
int fixed_latency = get_int();
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "missing \")\" in latency definition\n");
return;
}
next_char(); skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" in latency definition\n");
return;
}
pipe_class->setFixedLatency(fixed_latency);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "zero_instructions") ||
!strcmp(ident, "no_instructions")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" in latency definition\n");
return;
}
pipe_class->setInstructionCount(0);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "one_instruction_with_delay_slot") ||
!strcmp(ident, "single_instruction_with_delay_slot")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" in latency definition\n");
return;
}
pipe_class->setInstructionCount(1);
pipe_class->setBranchDelay(true);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "one_instruction") ||
!strcmp(ident, "single_instruction")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" in latency definition\n");
return;
}
pipe_class->setInstructionCount(1);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "instructions_in_first_bundle") ||
!strcmp(ident, "instruction_count")) {
skipws();
int number_of_instructions = 1;
if (_curchar != '(') {
parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
number_of_instructions = get_int();
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" in latency definition\n");
return;
}
pipe_class->setInstructionCount(number_of_instructions);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "multiple_bundles")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" after multiple bundles\n");
return;
}
pipe_class->setMultipleBundles(true);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "has_delay_slot")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n");
return;
}
pipe_class->setBranchDelay(true);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "force_serialization")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" after \"force_serialization\"\n");
return;
}
pipe_class->setForceSerialization(true);
next_char(); skipws();
continue;
}
if (!strcmp(ident, "may_have_no_code")) {
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing \";\" after \"may_have_no_code\"\n");
return;
}
pipe_class->setMayHaveNoCode(true);
next_char(); skipws();
continue;
}
const Form *parm = pipe_class->_localNames[ident];
if (parm != NULL) {
oper = parm->is_operand();
if (oper == NULL && !parm->is_opclass()) {
parse_err(SYNERR, "operand name expected at %s\n", ident);
continue;
}
if (_curchar != ':') {
parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
stage = get_ident();
if (stage == NULL) {
parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);
continue;
}
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);
continue;
}
next_char();
read_or_write = get_ident();
if (read_or_write == NULL) {
parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);
continue;
}
is_read = strcmp(read_or_write, "read") == 0;
is_write = strcmp(read_or_write, "write") == 0;
if (!is_read && !is_write) {
parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);
continue;
}
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
int more_instrs = 0;
if (_curchar == '+') {
next_char(); skipws();
if (_curchar < '0' || _curchar > '9') {
parse_err(SYNERR, "<number> expected at \"%c\"\n", _curchar);
continue;
}
while (_curchar >= '0' && _curchar <= '9') {
more_instrs *= 10;
more_instrs += _curchar - '0';
next_char();
}
skipws();
}
PipeClassOperandForm *pipe_operand = new PipeClassOperandForm(stage, is_write, more_instrs);
pipe_class->_localUsage.Insert(ident, pipe_operand);
if (_curchar == '%')
continue;
if (_curchar != ';') {
parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
continue;
}
const Form *res = pipeline._resdict[ident];
if (res != NULL) {
int cyclecnt = 1;
if (_curchar != ':') {
parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
stage = get_ident();
if (stage == NULL) {
parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);
continue;
}
skipws();
if (_curchar == '(') {
next_char();
cyclecnt = get_int();
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
}
PipeClassResourceForm *resource = new PipeClassResourceForm(ident, stage, cyclecnt);
int stagenum = pipeline._stages.index(stage);
if (pipeline._maxcycleused < (stagenum+cyclecnt))
pipeline._maxcycleused = (stagenum+cyclecnt);
pipe_class->_resUsage.addForm(resource);
if (_curchar == '%')
continue;
if (_curchar != ';') {
parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);
continue;
}
next_char(); skipws();
continue;
}
parse_err(SYNERR, "resource expected at \"%s\"\n", ident);
return;
} while(_curchar != '%');
next_char();
if (_curchar != '}') {
parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n");
return;
}
next_char();
}
void ADLParser::peep_parse(void) {
Peephole *peep; // Pointer to current peephole rule form
char *desc = NULL; // String representation of rule
skipws(); // Skip leading whitespace
peep = new Peephole(); // Build new Peephole object
skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') {
next_char(); next_char(); // Skip "%{"
skipws();
while (_curchar != '%' && *(_ptr+1) != '}') {
char *token = get_ident();
if (token == NULL) {
parse_err(SYNERR, "missing identifier inside peephole rule.\n");
return;
}
if (strcmp(token,"peepmatch")==0) {
peep_match_parse(*peep); }
else if (strcmp(token,"peepconstraint")==0) {
peep_constraint_parse(*peep); }
else if (strcmp(token,"peepreplace")==0) {
peep_replace_parse(*peep); }
else {
parse_err(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token);
}
skipws();
}
}
else {
parse_err(SYNERR, "Missing %%{ ... %%} block after peephole keyword.\n");
return;
}
next_char(); // Skip past '%'
next_char(); // Skip past '}'
}
Constraint *ADLParser::constraint_parse(void) {
char *func;
char *arg;
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing constraint expression, (...)\n");
return NULL;
}
next_char(); // Skip past '('
skipws();
func = get_ident();
if (func == NULL) {
parse_err(SYNERR, "missing function in constraint expression.\n");
return NULL;
}
if (strcmp(func,"ALLOC_IN_RC")==0
|| strcmp(func,"IS_R_CLASS")==0) {
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' for constraint function's argument.\n");
return NULL;
}
next_char();
skipws();
arg = get_ident();
if (arg == NULL) {
parse_err(SYNERR, "missing argument for constraint function %s\n",func);
return NULL;
}
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg);
return NULL;
}
next_char();
} else {
parse_err(SYNERR, "Invalid constraint function %s\n",func);
return NULL;
}
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' for constraint function %s\n",func);
return NULL;
}
next_char();
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "Missing ';' after constraint.\n");
return NULL;
}
next_char();
Constraint *constraint = new Constraint(func,arg);
return constraint;
}
ConstructRule *ADLParser::construct_parse(void) {
return NULL;
}
void ADLParser::reg_def_parse(void) {
char *rname; // Name of register being defined
skipws(); // Skip whitespace
rname = get_ident();
if (rname == NULL) {
parse_err(SYNERR, "missing register name after reg_def\n");
return;
}
skipws();
char *callconv = NULL;
char *c_conv = NULL;
char *idealtype = NULL;
char *encoding = NULL;
char *concrete = NULL;
if (_curchar == '(') {
next_char();
callconv = get_ident();
if (callconv == NULL) {
parse_err(SYNERR, "missing register calling convention value\n");
return;
}
if(strcmp(callconv, "SOC") && strcmp(callconv,"SOE") &&
strcmp(callconv, "NS") && strcmp(callconv, "AS")) {
parse_err(SYNERR, "invalid value for register calling convention\n");
}
skipws();
if (_curchar != ',') {
parse_err(SYNERR, "missing comma in register definition statement\n");
return;
}
next_char();
c_conv = get_ident();
if (c_conv == NULL) {
parse_err(SYNERR, "missing register native calling convention value\n");
return;
}
if(strcmp(c_conv, "SOC") && strcmp(c_conv,"SOE") &&
strcmp(c_conv, "NS") && strcmp(c_conv, "AS")) {
parse_err(SYNERR, "invalid value for register calling convention\n");
}
skipws();
if (_curchar != ',') {
parse_err(SYNERR, "missing comma in register definition statement\n");
return;
}
next_char();
skipws();
idealtype = get_ident();
if (idealtype == NULL) {
parse_err(SYNERR, "missing register save type value\n");
return;
}
skipws();
if (_curchar != ',') {
parse_err(SYNERR, "missing comma in register definition statement\n");
return;
}
next_char();
skipws();
encoding = get_expr("encoding", ",");
if (encoding == NULL) {
parse_err(SYNERR, "missing register encoding value\n");
return;
}
trim(encoding);
if (_curchar != ',') {
parse_err(SYNERR, "missing comma in register definition statement\n");
return;
}
next_char();
skipws();
concrete = get_expr("concrete", ")");
if (concrete == NULL) {
parse_err(SYNERR, "missing vm register name value\n");
return;
}
if (_curchar != ')') {
parse_err(SYNERR, "missing ')' in register definition statement\n");
return;
}
next_char();
}
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' after reg_def\n");
return;
}
next_char(); // move past ';'
if (_AD._adl_debug > 1) {
fprintf(stderr,"Register Definition: %s ( %s, %s %s )\n", rname,
(callconv ? callconv : ""), (c_conv ? c_conv : ""), concrete);
}
_AD._register->addRegDef(rname, callconv, c_conv, idealtype, encoding, concrete);
return;
}
void ADLParser::reg_class_parse(void) {
char *cname; // Name of register class being defined
skipws(); // Skip leading whitespace
cname = get_ident();
if (cname == NULL) {
parse_err(SYNERR, "missing register class name after 'reg_class'\n");
return;
}
if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname);
skipws();
if (_curchar == '(') {
RegClass* reg_class = _AD._register->addRegClass<RegClass>(cname);
next_char(); // Skip '('
skipws();
while (_curchar != ')') {
char *rname = get_ident();
if (rname==NULL) {
parse_err(SYNERR, "missing identifier inside reg_class list.\n");
return;
}
RegDef *regDef = _AD._register->getRegDef(rname);
if (!regDef) {
parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname);
} else {
reg_class->addReg(regDef); // add regDef to regClass
}
skipws();
if (_curchar == ',') {
next_char(); // Skip trailing ','
skipws();
}
}
next_char(); // Skip closing ')'
} else if (_curchar == '%') {
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->set_code_snippet(code);
return;
}
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");
return;
}
next_char(); // Skip trailing ';'
return;
}
void ADLParser::reg_class_dynamic_parse(void) {
char *cname; // Name of dynamic register class being defined
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();
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");
}
}
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;
}
void ADLParser::alloc_class_parse(void) {
char *name; // Name of allocation class being defined
skipws(); // Skip leading whitespace
name = get_ident();
if (name == NULL) {
parse_err(SYNERR, "missing allocation class name after 'reg_class'\n");
return;
}
if (_AD._adl_debug >1) fprintf(stderr,"Allocation Class: %s\n", name);
AllocClass *alloc_class = _AD._register->addAllocClass(name);
skipws();
if (_curchar == '(') {
next_char(); // Skip '('
skipws();
while (_curchar != ')') {
char *rname = get_ident();
if (rname==NULL) {
parse_err(SYNERR, "missing identifier inside reg_class list.\n");
return;
}
RegDef *regDef = _AD._register->getRegDef(rname);
if (regDef) {
alloc_class->addReg(regDef); // add regDef to allocClass
} else {
parse_err(SYNERR, "name %s should be a previously defined reg_def.\n", rname);
return;
}
skipws();
if (_curchar == ',') {
next_char(); // Skip trailing ','
skipws();
}
}
next_char(); // Skip closing ')'
}
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");
return;
}
next_char(); // Skip trailing ';'
return;
}
InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){
char *token = NULL;
int lparen = 0; // keep track of parenthesis nesting depth
int rparen = 0; // position of instruction at this depth
InstructForm *inst_seen = NULL;
while ( lparen >= rparen ) {
skipws();
if (_curchar == '(') {
++lparen;
next_char();
( void ) peep_match_child_parse(match, parent, position, rparen);
}
else if (_curchar == ')') {
++rparen;
if( rparen == lparen ) { // IF rparen matches an lparen I've seen
next_char(); // move past ')'
} else { // ELSE leave ')' for parent
assert( rparen == lparen + 1, "Should only see one extra ')'");
if( ! inst_seen ) { // record signal entry
match.add_instruction( parent, position, NameList::_signal, input );
++position;
}
return inst_seen;
}
}
else if ((token = get_ident_dup()) != NULL) {
const Form *form = _AD._globalNames[token];
if (form) {
InstructForm *inst = form->is_instruction();
if( inst_seen == NULL ) {
inst_seen = inst;
}
if (inst) {
match.add_instruction( parent, position, token, input );
parent = position;
++position;
} else {
parse_err(SYNERR, "instruction name expected at identifier %s.\n",
token);
return inst_seen;
}
}
else {
parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
return NULL;
}
}
else {
parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
return NULL;
}
} // end while
assert( false, "ShouldNotReachHere();");
return NULL;
}
void ADLParser::peep_match_parse(Peephole &peep) {
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' at start of peepmatch rule.\n");
return;
}
next_char(); // skip '('
PeepMatch *match = new PeepMatch(_ptr);
int parent = -1; // parent of root
int position = 0; // zero-based positions
int input = 0; // input position in parent's operands
InstructForm *root= peep_match_child_parse( *match, parent, position, input);
if( root == NULL ) {
parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n");
return;
}
if( _curchar != ')' ) {
parse_err(SYNERR, "missing ')' at end of peepmatch.\n");
return;
}
next_char(); // skip ')'
skipws();
if( _curchar != ';' ) {
parse_err(SYNERR, "missing ';' at end of peepmatch.\n");
return;
}
next_char(); // skip ';'
peep.add_match(match);
root->append_peephole(&peep);
}
void ADLParser::peep_constraint_parse(Peephole &peep) {
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' at start of peepconstraint rule.\n");
return;
}
else {
next_char(); // Skip '('
}
skipws();
while( _curchar != ')' ) {
int left_inst = get_int();
skipws();
if( _curchar != '.' ) {
parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");
return;
}
next_char(); // Skip '.'
char *left_op = get_ident_dup();
skipws();
char *relation = get_relation_dup();
skipws();
int right_inst; // Right-instructions's number
if( isdigit(_curchar) ) {
right_inst = get_int();
skipws();
if( _curchar != '.' ) {
parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");
return;
}
next_char(); // Skip '.'
} else {
right_inst = -1; // Flag as being a register constraint
}
char *right_op = get_ident_dup();
PeepConstraint *constraint = new PeepConstraint( left_inst, left_op,
relation,
right_inst, right_op );
peep.append_constraint( constraint );
skipws();
if( _curchar == ',' ) {
next_char(); // Skip ','
skipws();
}
else if( _curchar != ')' ) {
parse_err(SYNERR, "expected ',' or ')' after peephole constraint.\n");
return;
}
} // end while( processing constraints )
next_char(); // Skip ')'
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' at end of peepconstraint.\n");
return;
}
next_char(); // Skip trailing ';'
}
void ADLParser::peep_replace_parse(Peephole &peep) {
int lparen = 0; // keep track of parenthesis nesting depth
int rparen = 0; // keep track of parenthesis nesting depth
int icount = 0; // count of instructions in rule for naming
char *str = NULL;
char *token = NULL;
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' at start of peepreplace rule.\n");
return;
}
else {
lparen++;
next_char();
}
char *inst = get_ident_dup();
const Form *form = _AD._globalNames[inst];
if( form == NULL || form->is_instruction() == NULL ) {
parse_err(SYNERR, "Instruction name expected at start of peepreplace.\n");
return;
}
PeepReplace *replace = new PeepReplace(str);
replace->add_instruction( inst );
skipws();
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' at peepreplace root's operand-list.\n");
return;
}
else {
lparen++;
next_char();
}
skipws();
while( _curchar != ')' ) {
int inst_num = get_int();
skipws();
if( _curchar != '.' ) {
parse_err(SYNERR, "missing '.' in peepreplace after instruction number.\n");
return;
}
next_char(); // Skip '.'
char *inst_op = get_ident_dup();
if( inst_op == NULL ) {
parse_err(SYNERR, "missing operand identifier in peepreplace.\n");
return;
}
replace->add_operand( inst_num, inst_op );
skipws();
}
skipws();
assert( _curchar == ')', "While loop should have advanced to ')'.");
next_char(); // Skip ')'
skipws();
if( _curchar != ')' ) {
parse_err(SYNERR, "missing ')' at end of peepmatch.\n");
parse_err(SYNERR, "Support one replacement instruction.\n");
return;
}
next_char(); // Skip ')'
skipws();
if( _curchar != ';' ) {
parse_err(SYNERR, "missing ';' at end of peepreplace.\n");
return;
}
next_char(); // skip ';'
peep.add_replace( replace );
}
Predicate *ADLParser::pred_parse(void) {
Predicate *predicate; // Predicate class for operand
char *rule = NULL; // String representation of predicate
skipws(); // Skip leading whitespace
int line = linenum();
if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {
parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");
return NULL;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule);
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in predicate definition\n");
return NULL;
}
next_char(); // Point after the terminator
predicate = new Predicate(rule); // Build new predicate object
skipws();
return predicate;
}
void ADLParser::ins_encode_parse_block(InstructForm& inst) {
const char* prefix = "__ins_encode_";
char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
sprintf(ec_name, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
EncClass* encoding = _AD._encode->add_EncClass(ec_name);
encoding->_linenum = linenum();
const char* param = NULL;
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
OpClassForm* opForm = inst._localNames[param]->is_opclass();
assert(opForm != NULL, "sanity");
encoding->add_parameter(opForm->_ident, param);
}
if (!inst._is_postalloc_expand) {
encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
}
ins_encode_parse_block_impl(inst, encoding, ec_name);
InsEncode* encrule = new InsEncode(); // Encode class for instruction
NameAndList* params = encrule->add_encode(ec_name);
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
params->add_entry(param);
}
if (inst._insencode != NULL) {
parse_err(SYNERR, "Multiple ins_encode sections defined\n");
return;
}
inst._insencode = encrule;
}
void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) {
skipws_no_preproc(); // Skip leading whitespace
if (_AD._adlocation_debug) {
encoding->add_code(get_line_string());
}
while ((_curchar != '%') && (*(_ptr+1) != '}')) {
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else {
next_char_or_line();
}
}
if (start != _ptr) {
encoding->add_code(start);
}
if (_curchar == '$') {
char* rep_var = get_rep_var_ident_dup();
encoding->add_rep_var(rep_var);
skipws();
if (strcmp(rep_var, "constanttablebase") == 0) {
inst.set_needs_constant_base(true);
if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {
inst.set_is_mach_constant(true);
}
if (_curchar == '(') {
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
"(only constantaddress and constantoffset)", ec_name);
return;
}
}
else if ((strcmp(rep_var, "constantaddress") == 0) ||
(strcmp(rep_var, "constantoffset") == 0)) {
inst.set_is_mach_constant(true);
if (_curchar == '(') constant_parse(inst);
}
}
} // end while part of format description
next_char(); // Skip '%'
next_char(); // Skip '}'
skipws();
if (_AD._adlocation_debug) {
encoding->add_code(end_line_marker());
}
if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
}
void ADLParser::ins_encode_parse(InstructForm& inst) {
skipws(); // Skip whitespace
if (_curchar != '(') {
if ((_curchar == '%') && (*(_ptr+1) == '{')) {
next_char(); // Skip '%'
next_char(); // Skip '{'
ins_encode_parse_block(inst);
return;
}
parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n");
return;
}
next_char(); // move past '('
skipws();
InsEncode *encrule = new InsEncode(); // Encode class for instruction
encrule->_linenum = linenum();
char *ec_name = NULL; // String representation of encode rule
while (_curchar != ')') {
ec_name = get_ident();
if (ec_name == NULL) {
parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");
return;
}
EncClass *encode_class = _AD._encode->encClass(ec_name);
if (encode_class == NULL) {
}
NameAndList *params = encrule->add_encode(ec_name);
skipws();
if ( _curchar == '(' ) {
next_char(); // move past '(' for parameters
while (_curchar != ')') {
char *param = get_ident_or_literal_constant("encoding operand");
if ( param != NULL ) {
if (strcmp(param, "constanttablebase") == 0) {
inst.set_needs_constant_base(true);
if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {
inst.set_is_mach_constant(true);
}
if (_curchar == '(') {
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
"(only constantaddress and constantoffset)", ec_name);
return;
}
} else {
if ( (inst._localNames[param] == NULL) &&
!ADLParser::is_literal_constant(param) &&
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
return;
}
}
params->add_entry(param);
skipws();
if (_curchar == ',' ) {
next_char(); // move past ',' between parameters
skipws(); // Skip to next parameter
}
else if (_curchar == ')') {
}
else {
parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",
ec_name);
return;
}
} else {
skipws();
if (_curchar == ',') {
parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
return;
}
if (_curchar != ')') {
parse_err(SYNERR, "Expected ')' after encode parameters.\n");
return;
}
}
} // WHILE loop collecting parameters
next_char(); // move past ')' at end of parameters
} // done with parameter list for encoding
skipws(); // move to character after parameters
if ( _curchar == ',' ) {
next_char(); // move past ',' between encode methods
skipws();
}
else if ( _curchar != ')' ) {
parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);
return;
}
} // done parsing ins_encode methods and their parameters
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");
return;
}
next_char(); // move past ')'
skipws(); // Skip leading whitespace
if ( _curchar != ';' ) {
parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");
return;
}
next_char(); // move past ';'
skipws(); // be friendly to oper_parse()
if (inst._insencode != NULL) {
parse_err(SYNERR, "Multiple ins_encode sections defined\n");
return;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);
inst._insencode = encrule;
}
void ADLParser::postalloc_expand_parse(InstructForm& inst) {
inst._is_postalloc_expand = true;
skipws(); // Skip whitespace.
if (_curchar != '(') {
if ((_curchar == '%') && (*(_ptr+1) == '{')) {
next_char(); // Skip '%'
next_char(); // Skip '{'
ins_encode_parse_block(inst);
return;
}
parse_err(SYNERR, "missing '(' in postalloc_expand definition\n");
return;
}
next_char(); // Move past '('.
skipws();
InsEncode *encrule = new InsEncode(); // Encode class for instruction.
encrule->_linenum = linenum();
char *ec_name = NULL; // String representation of encode rule.
if (_curchar != ')') {
ec_name = get_ident();
if (ec_name == NULL) {
parse_err(SYNERR, "Invalid postalloc_expand class name after 'postalloc_expand('.\n");
return;
}
EncClass *encode_class = _AD._encode->encClass(ec_name);
NameAndList *params = encrule->add_encode(ec_name);
skipws();
if (_curchar == '(') {
next_char(); // Move past '(' for parameters.
while (_curchar != ')') {
char *param = get_ident_or_literal_constant("encoding operand");
if (param != NULL) {
if (strcmp(param, "constanttablebase") == 0) {
inst.set_needs_constant_base(true);
if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {
inst.set_is_mach_constant(true);
}
if (_curchar == '(') {
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
"(only constantaddress and constantoffset)", ec_name);
return;
}
}
else if ((strcmp(param, "constantaddress") == 0) ||
(strcmp(param, "constantoffset") == 0)) {
inst.set_is_mach_constant(true);
if (_curchar == '(') constant_parse(inst);
}
else if ((inst._localNames[param] == NULL) &&
!ADLParser::is_literal_constant(param) &&
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {
parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
return;
}
params->add_entry(param);
skipws();
if (_curchar == ',') {
next_char(); // Move past ',' between parameters.
skipws(); // Skip to next parameter.
} else if (_curchar == ')') {
} else {
parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", ec_name);
return;
}
} else {
skipws();
if (_curchar == ',') {
parse_err(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);
return;
}
if (_curchar != ')') {
parse_err(SYNERR, "Expected ')' after postalloc_expand parameters.\n");
return;
}
}
} // WHILE loop collecting parameters.
next_char(); // Move past ')' at end of parameters.
} // Done with parameter list for encoding.
skipws(); // Move to character after parameters.
if (_curchar != ')') {
parse_err(SYNERR, "Expected ')' after postalloc_expand %s.\n", ec_name);
return;
}
} // Done parsing postalloc_expand method and their parameters.
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' at end of postalloc_expand description.\n");
return;
}
next_char(); // Move past ')'.
skipws(); // Skip leading whitespace.
if (_curchar != ';') {
parse_err(SYNERR, "Missing ';' at end of postalloc_expand.\n");
return;
}
next_char(); // Move past ';'.
skipws(); // Be friendly to oper_parse().
if (_AD._adl_debug > 1) fprintf(stderr, "Instruction postalloc_expand: %s\n", ec_name);
inst._insencode = encrule;
}
void ADLParser::constant_parse(InstructForm& inst) {
const char* prefix = "__constant_";
char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
sprintf(ec_name, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
EncClass* encoding = _AD._encode->add_EncClass(ec_name);
encoding->_linenum = linenum();
const char* param = NULL;
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
OpClassForm* opForm = inst._localNames[param]->is_opclass();
assert(opForm != NULL, "sanity");
encoding->add_parameter(opForm->_ident, param);
}
constant_parse_expression(encoding, ec_name);
InsEncode* encrule = new InsEncode(); // Encode class for instruction
NameAndList* params = encrule->add_encode(ec_name);
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
params->add_entry(param);
}
inst._constant = encrule;
}
void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
skipws();
if (_AD._adlocation_debug) {
encoding->add_code(get_line_string());
}
encoding->add_code(" _constant = C->constant_table().add");
encoding->add_code("(this, ");
next_char(); // Skip '('
int parens_depth = 1;
while (parens_depth > 0) {
if (_curchar == '(') {
parens_depth++;
encoding->add_code("(");
next_char();
}
else if (_curchar == ')') {
parens_depth--;
if (parens_depth > 0)
encoding->add_code(")");
next_char();
}
else {
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) {
next_char();
}
if (start != _ptr) {
encoding->add_code(start);
}
if (_curchar == '$') {
char* rep_var = get_rep_var_ident_dup();
encoding->add_rep_var(rep_var);
}
}
}
encoding->add_code(");");
if (_AD._adlocation_debug) {
encoding->add_code(end_line_marker());
}
if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
}
char* ADLParser::size_parse(InstructForm *instr) {
char* sizeOfInstr = NULL;
skipws();
sizeOfInstr = get_paren_expr("size expression");
if (sizeOfInstr == NULL) {
parse_err(SYNERR, "size of opcode expected at %c\n", _curchar);
return NULL;
}
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
return NULL;
}
next_char(); // Advance past the ';'
skipws(); // necessary for instr_parse()
if (_AD._adl_debug > 1) {
if (sizeOfInstr != NULL) {
fprintf(stderr,"size of opcode: %s\n", sizeOfInstr);
}
}
return sizeOfInstr;
}
Opcode * ADLParser::opcode_parse(InstructForm *instr) {
char *primary = NULL;
char *secondary = NULL;
char *tertiary = NULL;
char *val = NULL;
Opcode *opcode = NULL;
skipws();
if (_curchar != '(') { // Check for parenthesized operand list
parse_err(SYNERR, "missing '(' in expand instruction declaration\n");
return NULL;
}
next_char(); // skip open paren
skipws();
if (_curchar != ')') {
if ( ((primary = get_ident_or_literal_constant("primary opcode")) == NULL) ) {
parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar);
return NULL;
}
skipws();
if (_curchar == ',') {
next_char();
skipws();
if ( ((secondary = get_ident_or_literal_constant("secondary opcode")) == NULL) ) {
parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar);
return NULL;
}
skipws();
if (_curchar == ',') {
next_char();
skipws();
if ( ((tertiary = get_ident_or_literal_constant("tertiary opcode")) == NULL) ) {
parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar);
return NULL;
}
skipws();
}
}
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' in opcode description\n");
return NULL;
}
}
next_char(); // Skip ')'
skipws();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
return NULL;
}
next_char(); // Advance past the ';'
skipws(); // necessary for instr_parse()
if (_AD._adl_debug > 1) {
if (primary != NULL) fprintf(stderr,"primary opcode: %s\n", primary);
if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary);
if (tertiary != NULL) fprintf(stderr,"tertiary opcode: %s\n", tertiary);
}
opcode = new Opcode(primary, secondary, tertiary);
return opcode;
}
Interface *ADLParser::interface_parse(void) {
char *iface_name = NULL; // Name of interface class being used
char *iface_code = NULL; // Describe components of this class
skipws(); // Skip whitespace
if (_curchar != '(') {
parse_err(SYNERR, "Missing '(' at start of interface description.\n");
return NULL;
}
next_char(); // move past '('
skipws();
iface_name = get_ident();
if (iface_name == NULL) {
parse_err(SYNERR, "missing interface name after 'interface'.\n");
return NULL;
}
skipws();
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' after name of interface.\n");
return NULL;
}
next_char(); // move past ')'
Interface *inter = NULL;
skipws();
if ( _curchar != ';' ) {
if ( strcmp(iface_name,"MEMORY_INTER") == 0 ) {
inter = mem_interface_parse();
}
else if ( strcmp(iface_name,"COND_INTER") == 0 ) {
inter = cond_interface_parse();
}
if ( _curchar == ';' ) {
parse_err(SYNERR, "Extra ';' after defining interface block.\n");
next_char(); // Skip ';'
return NULL;
}
} else {
next_char(); // move past ';'
if ( strcmp(iface_name,"REG_INTER") == 0 ) {
inter = new RegInterface();
}
else if ( strcmp(iface_name,"CONST_INTER") == 0 ) {
inter = new ConstInterface();
}
}
skipws(); // be friendly to oper_parse()
if (_AD._adl_debug > 1) fprintf(stderr,"Interface Form: %s\n", iface_name);
return inter;
}
Interface *ADLParser::mem_interface_parse(void) {
char *base = NULL;
char *index = NULL;
char *scale = NULL;
char *disp = NULL;
if (_curchar != '%') {
parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
return NULL;
}
next_char(); // Skip '%'
if (_curchar != '{') {
parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
return NULL;
}
next_char(); // Skip '{'
skipws();
do {
char *field = get_ident();
if (field == NULL) {
parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
return NULL;
}
if ( strcmp(field,"base") == 0 ) {
base = interface_field_parse();
}
else if ( strcmp(field,"index") == 0 ) {
index = interface_field_parse();
}
else if ( strcmp(field,"scale") == 0 ) {
scale = interface_field_parse();
}
else if ( strcmp(field,"disp") == 0 ) {
disp = interface_field_parse();
}
else {
parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
return NULL;
}
} while( _curchar != '%' );
next_char(); // Skip '%'
if ( _curchar != '}' ) {
parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
return NULL;
}
next_char(); // Skip '}'
Interface *inter = new MemInterface(base, index, scale, disp);
return inter;
}
Interface *ADLParser::cond_interface_parse(void) {
char *equal;
char *not_equal;
char *less;
char *greater_equal;
char *less_equal;
char *greater;
char *overflow;
char *no_overflow;
const char *equal_format = "eq";
const char *not_equal_format = "ne";
const char *less_format = "lt";
const char *greater_equal_format = "ge";
const char *less_equal_format = "le";
const char *greater_format = "gt";
const char *overflow_format = "o";
const char *no_overflow_format = "no";
if (_curchar != '%') {
parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
return NULL;
}
next_char(); // Skip '%'
if (_curchar != '{') {
parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
return NULL;
}
next_char(); // Skip '{'
skipws();
do {
char *field = get_ident();
if (field == NULL) {
parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
return NULL;
}
if ( strcmp(field,"equal") == 0 ) {
equal = interface_field_parse(&equal_format);
}
else if ( strcmp(field,"not_equal") == 0 ) {
not_equal = interface_field_parse(¬_equal_format);
}
else if ( strcmp(field,"less") == 0 ) {
less = interface_field_parse(&less_format);
}
else if ( strcmp(field,"greater_equal") == 0 ) {
greater_equal = interface_field_parse(&greater_equal_format);
}
else if ( strcmp(field,"less_equal") == 0 ) {
less_equal = interface_field_parse(&less_equal_format);
}
else if ( strcmp(field,"greater") == 0 ) {
greater = interface_field_parse(&greater_format);
}
else if ( strcmp(field,"overflow") == 0 ) {
overflow = interface_field_parse(&overflow_format);
}
else if ( strcmp(field,"no_overflow") == 0 ) {
no_overflow = interface_field_parse(&no_overflow_format);
}
else {
parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
return NULL;
}
} while( _curchar != '%' );
next_char(); // Skip '%'
if ( _curchar != '}' ) {
parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
return NULL;
}
next_char(); // Skip '}'
Interface *inter = new CondInterface(equal, equal_format,
not_equal, not_equal_format,
less, less_format,
greater_equal, greater_equal_format,
less_equal, less_equal_format,
greater, greater_format,
overflow, overflow_format,
no_overflow, no_overflow_format);
return inter;
}
char *ADLParser::interface_field_parse(const char ** format) {
char *iface_field = NULL;
skipws(); // Skip whitespace
if (_curchar != '(') {
parse_err(SYNERR, "Missing '(' at start of interface field.\n");
return NULL;
}
next_char(); // move past '('
skipws();
if ( _curchar != '0' && _curchar != '$' ) {
parse_err(SYNERR, "missing or invalid interface field contents.\n");
return NULL;
}
iface_field = get_rep_var_ident();
if (iface_field == NULL) {
parse_err(SYNERR, "missing or invalid interface field contents.\n");
return NULL;
}
skipws();
if (format != NULL && _curchar == ',') {
next_char();
skipws();
if (_curchar != '"') {
parse_err(SYNERR, "Missing '\"' in field format .\n");
return NULL;
}
next_char();
char *start = _ptr; // Record start of the next string
while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
if (_curchar == '\\') next_char(); // superquote
if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!
next_char();
}
if (_curchar != '"') {
parse_err(SYNERR, "Missing '\"' at end of field format .\n");
return NULL;
}
if ( start != _ptr ) {
}
next_char();
skipws();
}
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' after interface field.\n");
return NULL;
}
next_char(); // move past ')'
skipws();
if ( _curchar != ';' ) {
parse_err(SYNERR, "Missing ';' at end of interface field.\n");
return NULL;
}
next_char(); // move past ';'
skipws(); // be friendly to interface_parse()
return iface_field;
}
MatchRule *ADLParser::match_parse(FormDict &operands) {
MatchRule *match; // Match Rule class for instruction/operand
char *cnstr = NULL; // Code for constructor
int depth = 0; // Counter for matching parentheses
int numleaves = 0; // Counter for number of leaves in rule
MatchNode *mnode = matchNode_parse(operands, depth, numleaves, true);
skipws(); // Skip whitespace
if ( _curchar == ';' ) { // Semicolon is valid terminator
cnstr = NULL; // no constructor for this form
next_char(); // Move past the ';', replaced with '\0'
}
else if ((cnstr = find_cpp_block("match constructor")) == NULL ) {
parse_err(SYNERR, "invalid construction of match rule\n"
"Missing ';' or invalid '%%{' and '%%}' constructor\n");
return NULL; // No MatchRule to return
}
if (_AD._adl_debug > 1)
if (cnstr) fprintf(stderr,"Match Constructor: %s\n", cnstr);
match = new MatchRule(_AD, mnode, depth, cnstr, numleaves);
skipws(); // Skip any trailing whitespace
return match; // Return MatchRule object
}
FormatRule* ADLParser::format_parse(void) {
char *desc = NULL;
FormatRule *format = (new FormatRule(desc));
skipws(); // Skip whitespace
if ( _curchar == ';' ) { // Semicolon is valid terminator
desc = NULL; // no constructor for this form
next_char(); // Move past the ';', replaced with '\0'
}
else if ( _curchar == '%' && *(_ptr+1) == '{') {
next_char(); // Move past the '%'
next_char(); // Move past the '{'
skipws();
if (_curchar == '$') {
char* ident = get_rep_var_ident();
if (strcmp(ident, "$$template") == 0) return template_parse();
parse_err(SYNERR, "Unknown \"%s\" directive in format", ident);
return NULL;
}
if ( _curchar == '"' ) {
next_char(); // Move past the initial '"'
if( _curchar == '"' ) { // Handle empty format string case
format->_strings.addName(_ptr);
}
while ( true ) {
if ( _curchar == '%' || _curchar == '\n' ) {
if ( _curchar != '"' ) {
parse_err(SYNERR, "missing '\"' at end of format block");
return NULL;
}
}
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
if (_curchar == '\\') {
next_char(); // superquote
if ((_curchar == '$') || (_curchar == '%'))
}
if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!
next_char();
}
if ( start != _ptr ) {
format->_strings.addName(start);
}
if ( _curchar == '$' ) {
next_char(); // Move past the '$'
char* rep_var = get_ident(); // Nil terminate the variable name
rep_var = strdup(rep_var);// Copy the string
format->_rep_vars.addName(rep_var);
format->_strings.addName(NameList::_signal);
}
if ( _curchar == '"') {
next_char(); // Move past the '"'
skipws(); // Skip white space before next string token
if ( _curchar != '"') {
break;
} else {
next_char();
}
}
} // end while part of format description
skipws(); // Move to closing '%}'
if ( _curchar != '%' ) {
parse_err(SYNERR, "non-blank characters between closing '\"' and '%%' in format");
return NULL;
}
} // Done with format description inside
skipws();
if ( _curchar != '%' || *(_ptr+1) != '}' ) {
parse_err(SYNERR, "missing '%%}' at end of format block");
return NULL;
}
next_char(); // Move past the '%'
next_char(); // Move past the '}'
}
else { // parameter list alone must terminate with a ';'
parse_err(SYNERR, "missing ';' after Format expression");
return NULL;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);
skipws();
return format;
}
FormatRule* ADLParser::template_parse(void) {
char *desc = NULL;
FormatRule *format = (new FormatRule(desc));
skipws();
while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {
{
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else {
next_char_or_line();
}
}
if ( start != _ptr ) {
format->_strings.addName(NameList::_signal2);
format->_strings.addName(start);
}
}
if ( _curchar == '$' ) {
char *rep_var = get_rep_var_ident_dup();
if (strcmp(rep_var, "$emit") == 0) {
next_char();
next_char();
skipws();
if ( _curchar == '"' ) {
next_char(); // Move past the initial '"'
if( _curchar == '"' ) { // Handle empty format string case
format->_strings.addName(_ptr);
}
while ( true ) {
if ( _curchar == '%' || _curchar == '\n' ) {
parse_err(SYNERR, "missing '\"' at end of format block");
return NULL;
}
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
if (_curchar == '\\') next_char(); // superquote
if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!
next_char();
}
if ( start != _ptr ) {
format->_strings.addName(start);
}
if ( _curchar == '$' ) {
next_char(); // Move past the '$'
char* next_rep_var = get_ident(); // Nil terminate the variable name
next_rep_var = strdup(next_rep_var);// Copy the string
format->_rep_vars.addName(next_rep_var);
format->_strings.addName(NameList::_signal);
}
if ( _curchar == '"') {
next_char(); // Move past the '"'
skipws(); // Skip white space before next string token
if ( _curchar != '"') {
break;
} else {
next_char();
}
}
} // end while part of format description
}
} else {
format->_rep_vars.addName(rep_var);
format->_strings.addName(NameList::_signal3);
}
} // end while part of format description
}
skipws();
if ( _curchar != '%' || *(_ptr+1) != '}' ) {
parse_err(SYNERR, "missing '%%}' at end of format block");
return NULL;
}
next_char(); // Move past the '%'
next_char(); // Move past the '}'
if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);
skipws();
return format;
}
void ADLParser::effect_parse(InstructForm *instr) {
char* desc = NULL;
skipws(); // Skip whitespace
if (_curchar != '(') {
parse_err(SYNERR, "missing '(' in effect definition\n");
return;
}
else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call);
if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in Effect definition\n");
}
next_char(); // Skip ';'
}
ExpandRule* ADLParser::expand_parse(InstructForm *instr) {
char *ident, *ident2;
NameAndList *instr_and_operands = NULL;
ExpandRule *exp = new ExpandRule();
skipws(); // Skip leading whitespace
if ((_curchar != '%')
|| (next_char(), (_curchar != '{')) ) { // If not open block
parse_err(SYNERR, "missing '%%{' in expand definition\n");
return(NULL);
}
next_char(); // Maintain the invariant
do {
ident = get_ident(); // Grab next identifier
if (ident == NULL) {
parse_err(SYNERR, "identifier expected at %c\n", _curchar);
continue;
}
const Form *form = _globalNames[ident];
bool parse_oper = false;
bool parse_ins = false;
if (form == NULL) {
skipws();
if (_curchar == '(') parse_ins = true;
} else if (form->is_instruction()) {
parse_ins = true;
} else if (form->is_operand()) {
parse_oper = true;
} else {
parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);
continue;
}
if (parse_oper) {
OperandForm *oper = form->is_operand();
if (oper == NULL) {
parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);
continue;
}
skipws();
ident = get_unique_ident(instr->_localNames,"Operand");
if (ident == NULL) {
parse_err(SYNERR, "identifier expected at %c\n", _curchar);
continue;
}
exp->_newopers.addName(ident);
instr->_localNames.Insert(ident, oper);
char *c = NULL;
skipws();
if (_curchar == '%') { // Need a constructor for the operand
c = find_cpp_block("Operand Constructor");
if (c == NULL) {
parse_err(SYNERR, "Invalid code block for operand constructor\n", _curchar);
continue;
}
exp->_newopconst.Insert(ident, c);
}
else if (_curchar != ';') { // If no constructor, need a ;
parse_err(SYNERR, "Missing ; in expand rule operand declaration\n");
continue;
}
else next_char(); // Skip the ;
skipws();
}
else {
assert(parse_ins, "sanity");
instr_and_operands = new NameAndList(ident);
skipws();
if (_curchar != '(') { // Check for parenthesized operand list
parse_err(SYNERR, "missing '(' in expand instruction declaration\n");
continue;
}
do {
next_char(); // skip open paren & comma characters
skipws();
if (_curchar == ')') break;
ident2 = get_ident();
skipws();
if (ident2 == NULL) {
parse_err(SYNERR, "identifier expected at %c\n", _curchar);
continue;
} // Check that you have a valid operand
const Form *form2 = instr->_localNames[ident2];
if (!form2) {
parse_err(SYNERR, "operand name expected at %s\n", ident2);
continue;
}
OperandForm *oper = form2->is_operand();
if (oper == NULL && !form2->is_opclass()) {
parse_err(SYNERR, "operand name expected at %s\n", ident2);
continue;
} // Add operand to list
instr_and_operands->add_entry(ident2);
} while(_curchar == ',');
if (_curchar != ')') {
parse_err(SYNERR, "missing ')'in expand instruction declaration\n");
continue;
}
next_char();
if (_curchar != ';') {
parse_err(SYNERR, "missing ';'in expand instruction declaration\n");
continue;
}
next_char();
exp->add_instruction(instr_and_operands);
skipws();
}
} while(_curchar != '%');
next_char();
if (_curchar != '}') {
parse_err(SYNERR, "missing '%%}' in expand rule definition\n");
return(NULL);
}
next_char();
if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n");
skipws();
return (exp);
}
RewriteRule* ADLParser::rewrite_parse(void) {
char* params = NULL;
char* desc = NULL;
skipws(); // Skip whitespace
if ((params = get_paren_expr("rewrite parameters")) == NULL) {
parse_err(SYNERR, "missing '(' in rewrite rule\n");
return NULL;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params);
skipws();
if ( (desc = find_cpp_block("rewrite block")) == NULL ) {
parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n");
return NULL;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite Rule: %s\n", desc);
skipws();
return (new RewriteRule(params,desc));
}
Attribute *ADLParser::attr_parse(char* ident) {
Attribute *attrib; // Attribute class
char *cost = NULL; // String representation of cost attribute
skipws(); // Skip leading whitespace
if ( (cost = get_paren_expr("attribute")) == NULL ) {
parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n");
return NULL;
}
if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost);
if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in attribute definition\n");
return NULL;
}
next_char(); // Point after the terminator
skipws();
attrib = new Attribute(ident,cost,INS_ATTR); // Build new predicate object
return attrib;
}
MatchNode *ADLParser::matchNode_parse(FormDict &operands, int &depth, int &numleaves, bool atroot) {
int lParens = depth;
int rParens = depth;
MatchNode *lChild = NULL;
MatchNode *rChild = NULL;
char *token; // Identifier which may be opcode or operand
if (cur_char() != '(')
return NULL;
next_char(); // advance past '('
token = get_ident(); // Get identifier, opcode
if (token == NULL) {
parse_err(SYNERR, "missing opcode in match expression\n");
return NULL;
}
for (int i = _last_machine_leaf + 1; i < _last_opcode; i++) {
if (strcmp(token, NodeClassNames[i]) == 0) {
_AD.has_match_rule(i, true);
}
}
const char *result = NULL; // Result type will be filled in later
const char *name = token; // local name associated with this node
const char *operation = token; // remember valid operation for later
const Form *form = operands[token];
OpClassForm *opcForm = form ? form->is_opclass() : NULL;
if (opcForm != NULL) {
if (!opcForm->ideal_only()) {
operation = opcForm->_ident;
result = operation; // Operands result in their own type
}
else name = NULL;
}
skipws();
if (cur_char() != ')') {
if (strcmp(operation,"Set"))
lChild = matchChild_parse(operands, lParens, numleaves, false);
else
lChild = matchChild_parse(operands, lParens, numleaves, true);
skipws();
if (cur_char() != ')' ) {
if(strcmp(operation, "Set"))
rChild = matchChild_parse(operands,rParens,numleaves,false);
else
rChild = matchChild_parse(operands,rParens,numleaves,true);
}
}
skipws();
if (cur_char() != ')') {
parse_err(SYNERR, "missing ')' in match expression\n");
return NULL;
}
next_char(); // skip the ')'
MatchNode* mroot = new MatchNode(_AD,result,name,operation,lChild,rChild);
if (!atroot) {
mroot->build_internalop();
}
depth = (lParens > rParens) ? lParens : rParens;
return mroot;
}
MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) {
MatchNode *child = NULL;
const char *result = NULL;
const char *token = NULL;
const char *opType = NULL;
if (cur_char() == '(') { // child is an operation
++parens;
child = matchNode_parse(operands, parens, numleaves, atroot);
}
else { // child is an operand
token = get_ident();
const Form *form = operands[token];
OpClassForm *opcForm = form ? form->is_opclass() : NULL;
if (opcForm != NULL) {
opType = opcForm->_ident;
result = opcForm->_ident; // an operand's result matches its type
} else {
parse_err(SYNERR, "undefined operand %s in match rule\n", token);
return NULL;
}
if (opType == NULL) {
parse_err(SYNERR, "missing type for argument '%s'\n", token);
}
child = new MatchNode(_AD, result, token, opType);
++numleaves;
}
return child;
}
char* ADLParser::find_cpp_block(const char* description) {
char *next; // Pointer for finding block delimiters
char* cppBlock = NULL; // Beginning of C++ code block
if (_curchar == '%') { // Encoding is a C++ expression
next_char();
if (_curchar != '{') {
parse_err(SYNERR, "missing '{' in %s \n", description);
return NULL;
}
next_char(); // Skip block delimiter
skipws_no_preproc(); // Skip leading whitespace
cppBlock = _ptr; // Point to start of expression
int line = linenum();
next = _ptr + 1;
while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) {
next_char_or_line();
next = _ptr+1; // Maintain the next pointer
} // Grab string
if (_curchar == '\0') {
parse_err(SYNERR, "invalid termination of %s \n", description);
return NULL;
}
_ptr += 2; // Skip block delimiter
_curchar = *_ptr; // Maintain invariant
if (_AD._adlocation_debug) {
char* location = get_line_string(line);
char* end_loc = end_line_marker();
char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1);
strcpy(result, location);
strcat(result, cppBlock);
strcat(result, end_loc);
cppBlock = result;
free(location);
}
}
return cppBlock;
}
char* ADLParser::get_expr(const char *desc, const char *stop_chars) {
char* expr = NULL;
int paren = 0;
expr = _ptr;
while (paren > 0 || !strchr(stop_chars, _curchar)) {
if (_curchar == '(') { // Down level of nesting
paren++; // Bump the parenthesis counter
next_char(); // maintain the invariant
}
else if (_curchar == ')') { // Up one level of nesting
if (paren == 0) {
parse_err(SYNERR, "too many )'s, did not find %s after %s\n",
stop_chars, desc);
return NULL;
}
paren--; // Drop the parenthesis counter
next_char(); // Maintain the invariant
}
else if (_curchar == '"' || _curchar == '\'') {
int qchar = _curchar;
while (true) {
next_char();
if (_curchar == qchar) { next_char(); break; }
if (_curchar == '\\') next_char(); // superquote
if (_curchar == '\n' || _curchar == '\0') {
parse_err(SYNERR, "newline in string in %s\n", desc);
return NULL;
}
}
}
else if (_curchar == '%' && (_ptr[1] == '{' || _ptr[1] == '}')) {
parse_err(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc);
return NULL;
}
else if (_curchar == '\0') {
parse_err(SYNERR, "unexpected EOF in %s\n", desc);
return NULL;
}
else {
char* pre_skip_ptr = _ptr;
skipws();
if (pre_skip_ptr == _ptr) {
next_char();
} else if (pre_skip_ptr+strlen(pre_skip_ptr) != _ptr+strlen(_ptr)) {
parse_err(SYNERR, "unimplemented: preprocessor must not elide subexpression in %s", desc);
}
}
}
assert(strchr(stop_chars, _curchar), "non-null return must be at stop-char");
return expr;
}
char *ADLParser::get_paren_expr(const char *description, bool include_location) {
int line = linenum();
if (_curchar != '(') // Escape if not valid starting position
return NULL;
next_char(); // Skip the required initial paren.
char *token2 = get_expr(description, ")");
if (_curchar == ')')
next_char(); // Skip required final paren.
int junk = 0;
if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) {
char* location = get_line_string(line);
char* end_loc = end_line_marker();
char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1);
strcpy(result, location);
strcat(result, token2);
strcat(result, end_loc);
token2 = result;
free(location);
}
return token2;
}
char *ADLParser::get_ident_common(bool do_preproc) {
register char c;
char *start; // Pointer to start of token
char *end; // Pointer to end of token
if( _curline == NULL ) // Return NULL at EOF.
return NULL;
skipws_common(do_preproc); // Skip whitespace before identifier
start = end = _ptr; // Start points at first character
end--; // unwind end by one to prepare for loop
do {
end++; // Increment end pointer
c = *end; // Grab character to test
} while ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))
|| ((c >= '0') && (c <= '9'))
|| ((c == '_')) || ((c == ':')) || ((c == '#')) );
if (start == end) { // We popped out on the first try
if (strlen(start) > 24) {
char buf[32];
strncpy(buf, start, 20);
buf[20] = '\0';
strcat(buf, "[...]");
parse_err(SYNERR, "Identifier expected, but found '%s'.", buf);
} else {
parse_err(SYNERR, "Identifier expected, but found '%s'.", start);
}
start = NULL;
}
else {
_curchar = c; // Save the first character of next token
}
_ptr = end; // Reset _ptr to point to next char after token
if (do_preproc && start != NULL) {
const char* def = _AD.get_preproc_def(start);
if (def != NULL && strcmp(def, start)) {
const char* def1 = def;
const char* def2 = _AD.get_preproc_def(def1);
if (def2 != NULL && strcmp(def2, def1)) {
def = def2;
const char* def3 = _AD.get_preproc_def(def2);
if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {
parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s",
start, def1, def2, def3);
}
}
start = strdup(def);
}
}
return start; // Pointer to token in filebuf
}
char *ADLParser::get_ident_dup(void) {
char *ident = get_ident();
if( ident != NULL ) {
ident = strdup(ident); // Copy the string
}
return ident;
}
char *ADLParser::get_ident_or_literal_constant(const char* description) {
char* param = NULL;
skipws();
if (_curchar == '(') {
param = get_paren_expr(description);
if (param[0] != '(') {
char* buf = (char*) malloc(strlen(param) + 3);
sprintf(buf, "(%s)", param);
param = buf;
}
assert(is_literal_constant(param),
"expr must be recognizable as a constant");
} else {
param = get_ident();
}
return param;
}
char *ADLParser::get_rep_var_ident(void) {
char *rep_var = _ptr;
if ( _curchar == '$' ) {
next_char();
}
if ( _curchar == '$' ) {
next_char();
}
if ( _curchar == '$' ) {
next_char();
}
if( _curchar == '$' ) {
parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
next_char();
return NULL;
}
char *rep_var_name = get_ident();
assert( rep_var_name != NULL,
"Missing identifier after replacement variable indicator '$'");
return rep_var;
}
char *ADLParser::get_rep_var_ident_dup(void) {
if( _curchar != '$' ) return NULL;
next_char(); // Move past the '$'
char *rep_var = _ptr; // Remember starting point
if ( _curchar == '$' ) {
next_char();
}
if ( _curchar == '$' ) {
next_char();
}
if( _curchar == '$' ) {
parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
next_char();
return NULL;
}
char *rep_var_name = get_ident();
assert( rep_var_name != NULL,
"Missing identifier after replacement variable indicator '$'");
rep_var = strdup(rep_var); // Copy the string
return rep_var;
}
char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){
char* ident = get_ident();
if (ident == NULL) {
parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar);
}
else {
if (dict[ident] != NULL) {
parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription);
ident = NULL;
}
}
return ident;
}
int ADLParser::get_int(void) {
register char c;
char *start; // Pointer to start of token
char *end; // Pointer to end of token
int result; // Storage for integer result
if( _curline == NULL ) // Return NULL at EOF.
return 0;
skipws(); // Skip whitespace before identifier
start = end = _ptr; // Start points at first character
c = *end; // Grab character to test
while ((c >= '0') && (c <= '9')
|| ((c == '-') && (end == start))) {
end++; // Increment end pointer
c = *end; // Grab character to test
}
if (start == end) { // We popped out on the first try
parse_err(SYNERR, "integer expected at %c\n", c);
result = 0;
}
else {
_curchar = c; // Save the first character of next token
result = atoi(start); // Convert the string to an integer
}
_ptr = end;
return result; // integer
}
char *ADLParser::get_relation_dup(void) {
char *result = NULL; // relational operator being returned
if( _curline == NULL ) // Return NULL at EOF.
return NULL;
skipws(); // Skip whitespace before relation
char *start = _ptr; // Store start of relational operator
char first = *_ptr; // the first character
if( (first == '=') || (first == '!') || (first == '<') || (first == '>') ) {
next_char();
char second = *_ptr; // the second character
if( (second == '=') ) {
next_char();
char tmp = *_ptr;
result = strdup(start); // Duplicate the string
} else {
parse_err(SYNERR, "relational operator expected at %s\n", _ptr);
}
} else {
parse_err(SYNERR, "relational operator expected at %s\n", _ptr);
}
return result;
}
void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) {
OpClassForm *opclass = NULL;
char *ident = NULL;
do {
next_char(); // skip open paren & comma characters
skipws();
if (_curchar == ')') break;
ident = get_ident();
if (ident == NULL) {
parse_err(SYNERR, "optype identifier expected at %c\n", _curchar);
return;
}
else {
const Form *form = _globalNames[ident];
if( form == NULL ) {
parse_err(SYNERR, "undefined operand type %s\n", ident);
return;
}
OpClassForm *opc = form->is_opclass();
OperandForm *oper = form->is_operand();
if((oper == NULL) && (opc == NULL)) {
parse_err(SYNERR, "identifier %s not operand type\n", ident);
return;
}
opclass = opc;
}
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Type: %s\t", ident);
if( (ident = get_unique_ident(operands, "operand")) == NULL) {
return;
}
if( _globalNames[ident] != NULL ) {
parse_err(SYNERR, "Reuse of global name %s as operand.\n",ident);
return;
}
operands.Insert(ident, opclass);
parameters.addName(ident);
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
skipws();
} while(_curchar == ',');
if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");
else {
next_char(); // set current character position past the close paren
}
}
void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) {
OperandForm *opForm;
Effect *eForm;
char *ident;
do {
next_char(); // skip open paren & comma characters
skipws();
if (_curchar == ')') break;
ident = get_ident();
if (ident == NULL) {
parse_err(SYNERR, "effect type identifier expected at %c\n", _curchar);
return;
}
else {
const Form *form = _globalNames[ident];
if( form == NULL ) {
parse_err(SYNERR, "undefined effect type %s\n", ident);
return;
}
else {
if( (eForm = form->is_effect()) == NULL) {
parse_err(SYNERR, "identifier %s not effect type\n", ident);
return;
}
}
}
if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
skipws();
if (eForm->is(Component::CALL)) {
if (_AD._adl_debug > 1) fprintf(stderr, "\n");
has_call = true;
} else {
if( (ident = get_unique_ident(effects, "effect")) == NULL) {
parse_err(SYNERR, "missing operand identifier in effect list\n");
return;
}
const Form *form = operands[ident];
opForm = form ? form->is_operand() : NULL;
if( opForm == NULL ) {
if( form && form->is_opclass() ) {
const char* cname = form->is_opclass()->_ident;
parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);
} else {
parse_err(SYNERR, "undefined operand %s in effect list\n", ident);
}
return;
}
effects.Insert(ident, eForm);
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
}
skipws();
} while(_curchar == ',');
if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");
else {
next_char(); // set current character position past the close paren
}
}
void ADLParser::preproc_line(void) {
int line = get_int();
skipws_no_preproc();
const char* file = NULL;
if (_curchar == '"') {
next_char(); // Move past the initial '"'
file = _ptr;
while (true) {
if (_curchar == '\n') {
parse_err(SYNERR, "missing '\"' at end of #line directive");
return;
}
if (_curchar == '"') {
next_char();
skipws_no_preproc();
break;
}
next_char();
}
}
ensure_end_of_line();
if (file != NULL)
_AD._ADL_file._name = file;
_buf.set_linenum(line);
}
void ADLParser::preproc_define(void) {
char* flag = get_ident_no_preproc();
skipws_no_preproc();
char* def = get_ident_no_preproc();
_AD.set_preproc_def(flag, def);
skipws_no_preproc();
if (_curchar != '\n') {
parse_err(SYNERR, "non-identifier in preprocessor definition\n");
}
}
void ADLParser::preproc_undef(void) {
char* flag = get_ident_no_preproc();
skipws_no_preproc();
ensure_end_of_line();
_AD.set_preproc_def(flag, NULL);
}
void ADLParser::parse_err(int flag, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
if (flag == 1)
_AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);
else if (flag == 2)
_AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);
else
_AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args);
int error_char = _curchar;
char* error_ptr = _ptr+1;
for(;*_ptr != '\n'; _ptr++) ; // Skip to the end of the current line
_curchar = '\n';
va_end(args);
_AD._no_output = 1;
if (flag == 1) {
char* error_tail = strchr(error_ptr, '\n');
char tem = *error_ptr;
error_ptr[-1] = '\0';
char* error_head = error_ptr-1;
while (error_head > _curline && *error_head) --error_head;
if (error_tail) *error_tail = '\0';
fprintf(stderr, "Error Context: %s>>>%c<<<%s\n",
error_head, error_char, error_ptr);
if (error_tail) *error_tail = '\n';
error_ptr[-1] = tem;
}
}
void ADLParser::ensure_start_of_line(void) {
if (_curchar == '\n') { next_line(); return; }
assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),
"Must be able to find which line we are in" );
for (char *s = _curline; s < _ptr; s++) {
if (*s > ' ') {
parse_err(SYNERR, "'%c' must be at beginning of line\n", _curchar);
break;
}
}
}
void ADLParser::ensure_end_of_line(void) {
skipws_no_preproc();
if (_curchar != '\n' && _curchar != '\0') {
parse_err(SYNERR, "garbage char '%c' at end of line\n", _curchar);
} else {
next_char_or_line();
}
}
bool ADLParser::handle_preproc_token() {
assert(*_ptr == '#', "must be at start of preproc");
ensure_start_of_line();
next_char();
skipws_no_preproc();
char* start_ident = _ptr;
char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc();
if (ident == NULL) {
parse_err(SYNERR, "expected preprocessor command, got end of line\n");
} else if (!strcmp(ident, "ifdef") ||
!strcmp(ident, "ifndef")) {
char* flag = get_ident_no_preproc();
ensure_end_of_line();
bool flag_def = preproc_taken() && (_AD.get_preproc_def(flag) != NULL);
bool now_taken = !strcmp(ident, "ifdef") ? flag_def : !flag_def;
begin_if_def(now_taken);
} else if (!strcmp(ident, "if")) {
if (preproc_taken())
parse_err(SYNERR, "unimplemented: #%s %s", ident, _ptr+1);
next_line();
begin_if_def(true);
} else if (!strcmp(ident, "else")) {
ensure_end_of_line();
invert_if_def();
} else if (!strcmp(ident, "endif")) {
ensure_end_of_line();
end_if_def();
} else if (preproc_taken()) {
_ptr = start_ident;
_curchar = *--_ptr;
if( _curchar != '#' ) {
parse_err(SYNERR, "no space allowed after # in #define or #undef");
assert(_curchar == '#', "no space allowed after # in #define or #undef");
}
return false;
}
return true;
}
void ADLParser::skipws_common(bool do_preproc) {
char *start = _ptr;
char *next = _ptr + 1;
if (*_ptr == '\0') {
if (_curchar > ' ') return;
if (_curchar == '\n') {
if (!do_preproc) return; // let caller handle the newline
next_line();
_ptr = _curline; next = _ptr + 1;
}
else if (_curchar == '#' ||
(_curchar == '/' && (*next == '/' || *next == '*'))) {
parse_err(SYNERR, "unimplemented: comment token in a funny place");
}
}
while(_curline != NULL) { // Check for end of file
if (*_ptr == '\n') { // keep proper track of new lines
if (!do_preproc) break; // let caller handle the newline
next_line();
_ptr = _curline; next = _ptr + 1;
}
else if ((*_ptr == '/') && (*next == '/')) // C++ comment
do { _ptr++; next++; } while(*_ptr != '\n'); // So go to end of line
else if ((*_ptr == '/') && (*next == '*')) { // C comment
_ptr++; next++;
do {
_ptr++; next++;
if (*_ptr == '\n') { // keep proper track of new lines
next_line(); // skip newlines within comments
if (_curline == NULL) { // check for end of file
parse_err(SYNERR, "end-of-file detected inside comment\n");
break;
}
_ptr = _curline; next = _ptr + 1;
}
} while(!((*_ptr == '*') && (*next == '/'))); // Go to end of comment
_ptr = ++next; next++; // increment _ptr past comment end
}
else if (do_preproc && *_ptr == '#') {
bool preproc_handled = handle_preproc_token();
if (!preproc_handled) {
if (preproc_taken()) {
return; // short circuit
}
++_ptr; // skip the preprocessor character
}
next = _ptr+1;
} else if(*_ptr > ' ' && !(do_preproc && !preproc_taken())) {
break;
}
else if (*_ptr == '"' || *_ptr == '\'') {
assert(do_preproc, "only skip strings if doing preproc");
int qchar = *_ptr;
while (true) {
++_ptr;
if (*_ptr == qchar) { ++_ptr; break; }
if (*_ptr == '\\') ++_ptr;
if (*_ptr == '\n' || *_ptr == '\0') {
parse_err(SYNERR, "newline in string");
break;
}
}
next = _ptr + 1;
}
else { ++_ptr; ++next; }
}
if( _curline != NULL ) // at end of file _curchar isn't valid
_curchar = *_ptr; // reset _curchar to maintain invariant
}
char ADLParser::cur_char() {
return (_curchar);
}
void ADLParser::next_char() {
if (_curchar == '\n') parse_err(WARN, "must call next_line!");
_curchar = *++_ptr;
}
void ADLParser::next_char_or_line() {
if ( _curchar != '\n' ) {
_curchar = *++_ptr;
} else {
next_line();
_ptr = _curline;
_curchar = *_ptr; // maintain invariant
}
}
void ADLParser::next_line() {
_curline = _buf.get_line();
_curchar = ' ';
}
char* ADLParser::get_line_string(int linenum) {
const char* file = _AD._ADL_file._name;
int line = linenum ? linenum : this->linenum();
char* location = (char *)malloc(strlen(file) + 100);
sprintf(location, "\n#line %d \"%s\"\n", line, file);
return location;
}
bool ADLParser::is_literal_constant(const char *param) {
if (param[0] == 0) return false; // null string
if (param[0] == '(') return true; // parenthesized expression
if (param[0] == '0' && (param[1] == 'x' || param[1] == 'X')) {
int i = 2;
do {
if( !ADLParser::is_hex_digit(*(param+i)) ) return false;
++i;
} while( *(param+i) != 0 );
return true;
}
return false;
}
bool ADLParser::is_hex_digit(char digit) {
return ((digit >= '0') && (digit <= '9'))
||((digit >= 'a') && (digit <= 'f'))
||((digit >= 'A') && (digit <= 'F'));
}
bool ADLParser::is_int_token(const char* token, int& intval) {
const char* cp = token;
while (*cp != '\0' && *cp <= ' ') cp++;
if (*cp == '-') cp++;
int ndigit = 0;
while (*cp >= '0' && *cp <= '9') { cp++; ndigit++; }
while (*cp != '\0' && *cp <= ' ') cp++;
if (ndigit == 0 || *cp != '\0') {
return false;
}
intval = atoi(token);
return true;
}
static const char* skip_expr_ws(const char* str) {
const char * cp = str;
while (cp[0]) {
if (cp[0] <= ' ') {
++cp;
} else if (cp[0] == '#') {
++cp;
while (cp[0] == ' ') ++cp;
assert(0 == strncmp(cp, "line", 4), "must be a #line directive");
const char* eol = strchr(cp, '\n');
assert(eol != NULL, "must find end of line");
if (eol == NULL) eol = cp + strlen(cp);
cp = eol;
} else {
break;
}
}
return cp;
}
bool ADLParser::equivalent_expressions(const char* str1, const char* str2) {
if (str1 == str2)
return true;
else if (str1 == NULL || str2 == NULL)
return false;
const char* cp1 = str1;
const char* cp2 = str2;
char in_quote = '\0';
while (cp1[0] && cp2[0]) {
if (!in_quote) {
const char* cp1a = skip_expr_ws(cp1);
const char* cp2a = skip_expr_ws(cp2);
if (cp1a > cp1 && cp2a > cp2) {
cp1 = cp1a; cp2 = cp2a;
continue;
}
if (cp1a > cp1 || cp2a > cp2) break; // fail
}
if (cp1[0] != cp2[0]) break; // fail
char ch = cp1[0];
cp1++; cp2++;
if (in_quote && ch == '\\') {
if (cp1[0] != cp2[0]) break; // fail
if (!cp1[0]) break;
cp1++; cp2++;
}
if (in_quote && ch == in_quote) {
in_quote = '\0';
} else if (!in_quote && (ch == '"' || ch == '\'')) {
in_quote = ch;
}
}
return (!cp1[0] && !cp2[0]);
}
void ADLParser::trim(char* &token) {
while (*token <= ' ') token++;
char* end = token + strlen(token);
while (end > token && *(end-1) <= ' ') --end;
}
C:\hotspot-69087d08d473\src\share\vm/adlc/adlparse.hpp
#ifndef SHARE_VM_ADLC_ADLPARSE_HPP
#define SHARE_VM_ADLC_ADLPARSE_HPP
class Form;
class InstructForm;
class OperandForm;
class OpClassForm;
class AttributeForm;
class RegisterForm;
class PipelineForm;
class SourceForm;
class Peephole;
class Component;
class Predicate;
class MatchRule;
class Encode;
class Attribute;
class Effect;
class ExpandRule;
class RewriteRule;
class Constraint;
class ConstructRule;
class RegDef;
class RegClass;
class CodeSnippetRegClass;
class ConditionalRegClass;
class AllocClass;
class ResourceForm;
class PipeDesc;
class PipeClass;
class RegList;
class PeepMatch;
class PeepConstraint;
class PeepReplace;
extern char *toUpper(const char *str);
class ADLParser {
protected:
char *_curline; // Start of current line
char *_ptr; // Pointer into current location in File Buffer
char _curchar; // Current character from buffer
FormDict &_globalNames; // Global names
enum { _preproc_limit = 20 };
int _preproc_depth; // How deep are we into ifdefs?
int _preproc_not_taken; // How deep in not-taken ifdefs?
bool _preproc_taken[_preproc_limit]; // Are we taking this ifdef level?
bool _preproc_else[_preproc_limit]; // Did this level have an else yet?
void instr_parse(void); // Parse instruction definitions
void oper_parse(void); // Parse operand definitions
void opclass_parse(void); // Parse operand class definitions
void ins_attr_parse(void); // Parse instruction attrubute definitions
void op_attr_parse(void); // Parse operand attrubute definitions
void source_parse(void); // Parse source section
void source_hpp_parse(void); // Parse source_hpp section
void reg_parse(void); // Parse register section
void encode_parse(void); // Parse encoding section
void frame_parse(void); // Parse frame section
void pipe_parse(void); // Parse pipeline section
void definitions_parse(void); // Parse definitions section
void peep_parse(void); // Parse peephole rule definitions
void preproc_line(void); // Parse a #line statement
void preproc_define(void); // Parse a #define statement
void preproc_undef(void); // Parse an #undef statement
void adjust_set_rule(InstructForm *instr);
void matchrule_clone_and_swap(MatchRule *rule, const char* instr_ident, int& match_rules_cnt);
void enc_class_parse(void); // Parse encoding class definition
void enc_class_parse_block(EncClass* encoding, char* ec_name);
void stack_dir_parse(FrameForm *frame); // Parse the stack direction entry
void sync_stack_slots_parse(FrameForm *frame);
void frame_pointer_parse(FrameForm *frame, bool native);
void interpreter_frame_pointer_parse(FrameForm *frame, bool native);
void inline_cache_parse(FrameForm *frame, bool native);
void interpreter_arg_ptr_parse(FrameForm *frame, bool native);
void interpreter_method_oop_parse(FrameForm *frame, bool native);
void cisc_spilling_operand_name_parse(FrameForm *frame, bool native);
void stack_alignment_parse(FrameForm *frame);
void return_addr_parse(FrameForm *frame, bool native);
void preserve_stack_parse(FrameForm *frame);
char *calling_convention_parse();
char *return_value_parse();
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
void int_def_parse(void); // Parse an integer definition
void resource_parse(PipelineForm &pipe); // Parse resource definition
void pipe_desc_parse(PipelineForm &pipe); // Parse pipeline description definition
void pipe_class_parse(PipelineForm &pipe); // Parse pipeline class definition
void peep_match_parse(Peephole &peep); // Parse the peephole match rule
void peep_constraint_parse(Peephole &peep);// Parse the peephole constraints
void peep_replace_parse(Peephole &peep); // Parse peephole replacement rule
InstructForm *peep_match_child_parse(PeepMatch &match, int parent, int &position, int input);
Predicate *pred_parse(void); // Parse predicate rule
MatchRule *match_parse(FormDict &operands);
MatchNode *matchNode_parse(FormDict &operands, int &depth,
int &numleaves, bool atroot);
MatchNode *matchChild_parse(FormDict &operands, int &depth,
int &numleaves, bool atroot);
Attribute *attr_parse(char *ident);// Parse instr/operand attribute rule
void ins_encode_parse(InstructForm &inst);
void ins_encode_parse_block(InstructForm &inst);
void ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name);
void postalloc_expand_parse(InstructForm &inst);
void constant_parse(InstructForm& inst);
void constant_parse_expression(EncClass* encoding, char* ec_name);
Opcode *opcode_parse(InstructForm *insr); // Parse instruction opcode
char *size_parse(InstructForm *insr); // Parse instruction size
Interface *interface_parse(); // Parse operand interface rule
Interface *mem_interface_parse(); // Parse memory interface rule
Interface *cond_interface_parse(); // Parse conditional interface rule
char *interface_field_parse(const char** format = NULL);// Parse field contents
FormatRule *format_parse(void); // Parse format rule
FormatRule *template_parse(void); // Parse format rule
void effect_parse(InstructForm *instr); // Parse effect rule
ExpandRule *expand_parse(InstructForm *instr); // Parse expand rule
RewriteRule *rewrite_parse(void); // Parse rewrite rule
Constraint *constraint_parse(void); // Parse constraint rule
ConstructRule *construct_parse(void); // Parse construct rule
void ins_pipe_parse(InstructForm &instr); // Parse ins_pipe rule
void begin_if_def(bool taken) {
assert(_preproc_depth < _preproc_limit, "#ifdef nesting limit");
int ppn = _preproc_depth++;
_preproc_taken[ppn] = taken;
if (!_preproc_taken[ppn]) _preproc_not_taken += 1;
_preproc_else[ppn] = false;
}
void invert_if_def() {
assert(_preproc_depth > 0, "#ifdef matching");
int ppn = _preproc_depth - 1;
assert(!_preproc_else[ppn], "multiple #else lines");
_preproc_else[ppn] = true;
if (!_preproc_taken[ppn]) _preproc_not_taken -= 1;
_preproc_taken[ppn] = !_preproc_taken[ppn];
if (!_preproc_taken[ppn]) _preproc_not_taken += 1;
}
void end_if_def() {
assert(_preproc_depth > 0, "#ifdef matching");
int ppn = --_preproc_depth;
if (!_preproc_taken[ppn]) _preproc_not_taken -= 1;
}
bool preproc_taken() {
return _preproc_not_taken == 0;
}
bool handle_preproc_token();
char *parse_one_arg(const char *description);
char *get_ident() { return get_ident_common(true); }
char *get_ident_no_preproc() { return get_ident_common(false); }
char *get_ident_common(bool do_preproc); // Grab it from the file buffer
char *get_ident_dup(void); // Grab a duplicate of the identifier
char *get_ident_or_literal_constant(const char* description);
char *get_unique_ident(FormDict &dict, const char *nameDescription);
char *get_rep_var_ident(void);
char *get_rep_var_ident_dup(void);
int get_int(void);
char *get_relation_dup(void);
void get_oplist(NameList ¶meters, FormDict &operands);// Parse type-operand pairs
void get_effectlist(FormDict &effects, FormDict &operands, bool& has_call); // Parse effect-operand pairs
char *get_paren_expr(const char *description, bool include_location = false);
char *get_expr(const char *description, const char *stop_chars);
char *find_cpp_block(const char *description); // Parse a C++ code block
void parse_err(int flag, const char *fmt, ...);
char *get_line_string(int linenum = 0);
char *end_line_marker() { return (char*)"\n#line 999999\n"; }
inline char cur_char(void);
inline void next_char(void);
inline void next_char_or_line(void);
inline void next_line(void);
void ensure_start_of_line(void);
void ensure_end_of_line(void);
void skipws() { skipws_common(true); }
void skipws_no_preproc() { skipws_common(false); }
void skipws_common(bool do_preproc);
FileBuff &_buf; // File buffer to be parsed
ArchDesc &_AD; // Architecture Description being built
public:
ADLParser(FileBuff &buf, ArchDesc &archDesc); // Create new ADLParser object
~ADLParser(); // Destroy ADLParser object
void parse(void); // Do the parsing & build forms lists
int linenum() { return _buf.linenum(); }
static bool is_literal_constant(const char *hex_string);
static bool is_hex_digit(char digit);
static bool is_int_token(const char* token, int& intval);
static bool equivalent_expressions(const char* str1, const char* str2);
static void trim(char* &token); // trim leading & trailing spaces
};
#endif // SHARE_VM_ADLC_ADLPARSE_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/archDesc.cpp
#include "adlc.hpp"
static FILE *errfile = stderr;
inline char toUpper(char lower) {
return (('a' <= lower && lower <= 'z') ? ((char) (lower + ('A'-'a'))) : lower);
}
char *toUpper(const char *str) {
char *upper = new char[strlen(str)+1];
char *result = upper;
const char *end = str + strlen(str);
for (; str < end; ++str, ++upper) {
*upper = toUpper(*str);
}
*upper = '\0';
return result;
}
ChainList::ChainList() {
}
void ChainList::insert(const char *name, const char *cost, const char *rule) {
_name.addName(name);
_cost.addName(cost);
_rule.addName(rule);
}
bool ChainList::search(const char *name) {
return _name.search(name);
}
void ChainList::reset() {
_name.reset();
_cost.reset();
_rule.reset();
}
bool ChainList::iter(const char * &name, const char * &cost, const char * &rule) {
bool notDone = false;
const char *n = _name.iter();
const char *c = _cost.iter();
const char *r = _rule.iter();
if (n && c && r) {
notDone = true;
name = n;
cost = c;
rule = r;
}
return notDone;
}
void ChainList::dump() {
output(stderr);
}
void ChainList::output(FILE *fp) {
fprintf(fp, "\nChain Rules: output resets iterator\n");
const char *cost = NULL;
const char *name = NULL;
const char *rule = NULL;
bool chains_exist = false;
for(reset(); (iter(name,cost,rule)) == true; ) {
fprintf(fp, "Chain to <%s> at cost #%s using %s_rule\n",name, cost ? cost : "0", rule);
}
reset();
if( ! chains_exist ) {
fprintf(fp, "No entries in this ChainList\n");
}
}
bool MatchList::search(const char *opc, const char *res, const char *lch,
const char *rch, Predicate *pr) {
bool tmp = false;
if ((res == _resultStr) || (res && _resultStr && !strcmp(res, _resultStr))) {
if ((lch == _lchild) || (lch && _lchild && !strcmp(lch, _lchild))) {
if ((rch == _rchild) || (rch && _rchild && !strcmp(rch, _rchild))) {
char * predStr = get_pred();
char * prStr = pr?pr->_pred:NULL;
if (ADLParser::equivalent_expressions(prStr, predStr)) {
return true;
}
}
}
}
if (_next) {
tmp = _next->search(opc, res, lch, rch, pr);
}
return tmp;
}
void MatchList::dump() {
output(stderr);
}
void MatchList::output(FILE *fp) {
fprintf(fp, "\nMatchList output is Unimplemented();\n");
}
ArchDesc::ArchDesc()
: _globalNames(cmpstr,hashstr, Form::arena),
_globalDefs(cmpstr,hashstr, Form::arena),
_preproc_table(cmpstr,hashstr, Form::arena),
_idealIndex(cmpstr,hashstr, Form::arena),
_internalOps(cmpstr,hashstr, Form::arena),
_internalMatch(cmpstr,hashstr, Form::arena),
_chainRules(cmpstr,hashstr, Form::arena),
_cisc_spill_operand(NULL),
_needs_clone_jvms(false) {
for( int i=0; i<_last_opcode; ++i ) {
_mlistab[i] = NULL;
}
initKeywords(_globalNames); // Initialize the Name Table with keywords
initBaseOpTypes();
_TotalLines = 0;
_no_output = 0;
_quiet_mode = 0;
_disable_warnings = 0;
_dfa_debug = 0;
_dfa_small = 0;
_adl_debug = 0;
_adlocation_debug = 0;
_internalOpCounter = 0;
_cisc_spill_debug = false;
_short_branch_debug = false;
for (int i = 0; i < _last_opcode; i++) {
_has_match_rule[i] = false;
}
_syntax_errs = 0;
_semantic_errs = 0;
_warnings = 0;
_internal_errs = 0;
_ADL_file._name = NULL; _ADL_file._fp = NULL;
_DFA_file._name = NULL; _DFA_file._fp = NULL;
_HPP_file._name = NULL; _HPP_file._fp = NULL;
_CPP_file._name = NULL; _CPP_file._fp = NULL;
_bug_file._name = "bugs.out"; _bug_file._fp = NULL;
_register = NULL;
_encode = NULL;
_pipeline = NULL;
_frame = NULL;
}
ArchDesc::~ArchDesc() {
}
void ArchDesc::addForm(PreHeaderForm *ptr) { _pre_header.addForm(ptr); };
void ArchDesc::addForm(HeaderForm *ptr) { _header.addForm(ptr); };
void ArchDesc::addForm(SourceForm *ptr) { _source.addForm(ptr); };
void ArchDesc::addForm(EncodeForm *ptr) { _encode = ptr; };
void ArchDesc::addForm(InstructForm *ptr) { _instructions.addForm(ptr); };
void ArchDesc::addForm(MachNodeForm *ptr) { _machnodes.addForm(ptr); };
void ArchDesc::addForm(OperandForm *ptr) { _operands.addForm(ptr); };
void ArchDesc::addForm(OpClassForm *ptr) { _opclass.addForm(ptr); };
void ArchDesc::addForm(AttributeForm *ptr) { _attributes.addForm(ptr); };
void ArchDesc::addForm(RegisterForm *ptr) { _register = ptr; };
void ArchDesc::addForm(FrameForm *ptr) { _frame = ptr; };
void ArchDesc::addForm(PipelineForm *ptr) { _pipeline = ptr; };
void ArchDesc::generateMatchLists() {
inspectOperands();
inspectInstructions();
}
void ArchDesc::inspectOperands() {
_operands.reset();
OperandForm *op;
for( ; (op = (OperandForm*)_operands.iter()) != NULL;) {
op->build_components();
if ( op->_matrule == NULL ) continue;
check_optype(op->_matrule);
build_chain_rule(op);
MatchRule &mrule = *op->_matrule;
Predicate *pred = op->_predicate;
const char *rootOp = op->_ident;
mrule._machType = rootOp;
if (strcmp(rootOp,"Universe")==0) continue;
if (strcmp(rootOp,"label")==0) continue;
assert( strcmp(rootOp,"sReg") != 0, "Disable untyped 'sReg'");
if (strcmp(rootOp,"sRegI")==0) continue;
if (strcmp(rootOp,"sRegP")==0) continue;
if (strcmp(rootOp,"sRegF")==0) continue;
if (strcmp(rootOp,"sRegD")==0) continue;
if (strcmp(rootOp,"sRegL")==0) continue;
const char *costStr = op->cost();
const char *defaultCost =
((AttributeForm*)_globalNames[AttributeForm::_op_cost])->_attrdef;
const char *cost = costStr? costStr : defaultCost;
const char *result = op->reduce_result();
bool has_root = false;
buildMatchList(op->_matrule, result, rootOp, pred, cost);
}
}
void ArchDesc::inspectInstructions() {
_instructions.reset();
InstructForm *instr;
for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {
instr->build_components();
if ( instr->_matrule == NULL ) continue;
MatchRule &mrule = *instr->_matrule;
Predicate *pred = instr->build_predicate();
const char *rootOp = instr->_ident;
mrule._machType = rootOp;
const char *costStr = instr->cost();
const char *defaultCost =
((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
const char *cost = costStr? costStr : defaultCost;
const char *result = instr->reduce_result();
if ( instr->is_ideal_branch() && instr->label_position() == -1 ||
!instr->is_ideal_branch() && instr->label_position() != -1) {
syntax_err(instr->_linenum, "%s: Only branches to a label are supported\n", rootOp);
}
Attribute *attr = instr->_attribs;
while (attr != NULL) {
if (strcmp(attr->_ident,"ins_short_branch") == 0 &&
attr->int_val(*this) != 0) {
if (!instr->is_ideal_branch() || instr->label_position() == -1) {
syntax_err(instr->_linenum, "%s: Only short branch to a label is supported\n", rootOp);
}
instr->set_short_branch(true);
} else if (strcmp(attr->_ident,"ins_alignment") == 0 &&
attr->int_val(*this) != 0) {
instr->set_alignment(attr->int_val(*this));
}
attr = (Attribute *)attr->_next;
}
if (!instr->is_short_branch()) {
buildMatchList(instr->_matrule, result, mrule._machType, pred, cost);
}
}
}
static int setsResult(MatchRule &mrule) {
if (strcmp(mrule._name,"Set") == 0) return 1;
return 0;
}
const char *ArchDesc::getMatchListIndex(MatchRule &mrule) {
if (setsResult(mrule)) {
return mrule._rChild->_opType;
} else {
return mrule._opType;
}
}
const char *ArchDesc::reduceLeft(char *internalName) {
const char *left = NULL;
MatchNode *mnode = (MatchNode*)_internalMatch[internalName];
if (mnode->_lChild) {
mnode = mnode->_lChild;
left = mnode->_internalop ? mnode->_internalop : mnode->_opType;
}
return left;
}
const char *ArchDesc::reduceRight(char *internalName) {
const char *right = NULL;
MatchNode *mnode = (MatchNode*)_internalMatch[internalName];
if (mnode->_rChild) {
mnode = mnode->_rChild;
right = mnode->_internalop ? mnode->_internalop : mnode->_opType;
}
return right;
}
void ArchDesc::check_optype(MatchRule *mrule) {
MatchRule *rule = mrule;
}
void ArchDesc::add_chain_rule_entry(const char *src, const char *cost,
const char *result) {
ChainList *lst = (ChainList *)_chainRules[src];
if (lst == NULL) {
lst = new ChainList();
_chainRules.Insert(src, lst);
}
if (!lst->search(result)) {
if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_op_cost])->_attrdef;
}
lst->insert(result, cost, result);
}
}
void ArchDesc::build_chain_rule(OperandForm *oper) {
MatchRule *rule;
if ((oper->_matrule) && (oper->_matrule->_lChild == NULL) &&
(oper->_matrule->_rChild == NULL)) {
{
const Form *form = _globalNames[oper->_matrule->_opType];
if ((form) && form->is_operand() &&
(form->ideal_only() == false)) {
add_chain_rule_entry(oper->_matrule->_opType, oper->cost(), oper->_ident);
}
}
if (oper->_matrule->_next) {
rule = oper->_matrule;
do {
rule = rule->_next;
const Form *form = _globalNames[rule->_opType];
if ((form) && form->is_operand() &&
(form->ideal_only() == false)) {
add_chain_rule_entry(rule->_opType, oper->cost(), oper->_ident);
}
} while(rule->_next != NULL);
}
}
else if ((oper->_matrule) && (oper->_matrule->_next)) {
rule = oper->_matrule;
do {
rule = rule->_next;
const Form *form = _globalNames[rule->_opType];
if ((form) && form->is_operand() &&
(form->ideal_only() == false)) {
assert( oper->cost(), "This case expects NULL cost, not default cost");
add_chain_rule_entry(rule->_opType, oper->cost(), oper->_ident);
}
} while(rule->_next != NULL);
}
}
void ArchDesc::buildMatchList(MatchRule *mrule, const char *resultStr,
const char *rootOp, Predicate *pred,
const char *cost) {
const char *leftstr, *rightstr;
MatchNode *mnode;
leftstr = rightstr = NULL;
if ( mrule->is_chain_rule(_globalNames) ) {
return;
}
intptr_t index = _last_opcode;
const char *indexStr = getMatchListIndex(*mrule);
index = (intptr_t)_idealIndex[indexStr];
if (index == 0) {
fprintf(stderr, "Ideal node missing: %s\n", indexStr);
assert(index != 0, "Failed lookup of ideal node\n");
}
if (index >= _last_opcode) {
fprintf(stderr, "Invalid match rule %s <-- ( %s )\n",
resultStr ? resultStr : " ",
rootOp ? rootOp : " ");
assert(index < _last_opcode, "Matching item not in ideal graph\n");
return;
}
if (!strcmp(mrule->_opType, "Set")) {
mnode = mrule->_rChild;
buildMList(mnode, rootOp, resultStr, pred, cost);
return;
}
mnode = mrule->_lChild;
if (mnode) {
buildMList(mnode, NULL, NULL, NULL, NULL);
leftstr = mnode->_internalop ? mnode->_internalop : mnode->_opType;
}
mnode = mrule->_rChild;
if (mnode) {
buildMList(mnode, NULL, NULL, NULL, NULL);
rightstr = mnode->_internalop ? mnode->_internalop : mnode->_opType;
}
if ((_mlistab[index] == NULL) ||
(_mlistab[index] &&
!_mlistab[index]->search(rootOp, resultStr, leftstr, rightstr, pred))) {
MatchList *mList =
new MatchList(_mlistab[index], pred, cost,
rootOp, resultStr, leftstr, rightstr);
_mlistab[index] = mList;
}
}
void ArchDesc::buildMList(MatchNode *node, const char *rootOp,
const char *resultOp, Predicate *pred,
const char *cost) {
const char *leftstr, *rightstr;
const char *resultop;
const char *opcode;
MatchNode *mnode;
Form *form;
leftstr = rightstr = NULL;
if ((node) && (node->_lChild == NULL) && (node->_rChild == NULL) &&
((form = (Form *)_globalNames[node->_opType]) != NULL) &&
(!form->ideal_only())) {
return;
}
intptr_t index = _last_opcode;
const char *indexStr = node ? node->_opType : (char *) " ";
index = (intptr_t)_idealIndex[indexStr];
if (index == 0) {
fprintf(stderr, "error: operand \"%s\" not found\n", indexStr);
assert(0, "fatal error");
}
mnode = node->_lChild;
if (mnode) {
buildMList(mnode, NULL, NULL, NULL, NULL);
leftstr = mnode->_internalop ? mnode->_internalop : mnode->_opType;
}
mnode = node->_rChild;
if (mnode) {
buildMList(mnode, NULL, NULL, NULL, NULL);
rightstr = mnode->_internalop ? mnode->_internalop : mnode->_opType;
}
if (rootOp == NULL) {
opcode = (node->_internalop) ? node->_internalop : node->_opType;
} else {
opcode = rootOp;
}
if (resultOp == NULL) {
resultop = (node->_internalop) ? node->_internalop : node->_opType;
}
else resultop = resultOp;
if ((_mlistab[index] == NULL) || (_mlistab[index] &&
!_mlistab[index]->search(opcode, resultop, leftstr, rightstr, pred))) {
MatchList *mList =
new MatchList(_mlistab[index],pred,cost,
opcode, resultop, leftstr, rightstr);
_mlistab[index] = mList;
}
}
int ArchDesc::operandFormCount() {
int count = 0; _operands.reset();
OperandForm *cur;
for( ; (cur = (OperandForm*)_operands.iter()) != NULL; ) {
if (cur->_matrule != NULL) ++count;
};
return count;
}
int ArchDesc::opclassFormCount() {
int count = 0; _operands.reset();
OpClassForm *cur;
for( ; (cur = (OpClassForm*)_opclass.iter()) != NULL; ) {
++count;
};
return count;
}
int ArchDesc::instructFormCount() {
int count = 0; _instructions.reset();
InstructForm *cur;
for( ; (cur = (InstructForm*)_instructions.iter()) != NULL; ) {
if (cur->_matrule != NULL) ++count;
};
return count;
}
char* ArchDesc::get_preproc_def(const char* flag) {
SourceForm* deff = NULL;
if (flag != NULL)
deff = (SourceForm*) _preproc_table[flag];
return (deff == NULL) ? NULL : deff->_code;
}
void ArchDesc::set_preproc_def(const char* flag, const char* def) {
SourceForm* deff = (SourceForm*) _preproc_table[flag];
if (deff == NULL) {
deff = new SourceForm(NULL);
_preproc_table.Insert(flag, deff);
_preproc_list.addName(flag); // this supports iteration
}
deff->_code = (char*) def;
}
bool ArchDesc::verify() {
if (_register)
assert( _register->verify(), "Register declarations failed verification");
if (!_quiet_mode)
fprintf(stderr,"\n");
if (!_quiet_mode)
fprintf(stderr,"---------------------------- Verify Instructions ----------------------------\n");
_instructions.verify();
if (!_quiet_mode)
fprintf(stderr,"\n");
return true;
}
void ArchDesc::dump() {
_pre_header.dump();
_header.dump();
_source.dump();
if (_register) _register->dump();
fprintf(stderr,"\n");
fprintf(stderr,"------------------ Dump Operands ---------------------\n");
_operands.dump();
fprintf(stderr,"\n");
fprintf(stderr,"------------------ Dump Operand Classes --------------\n");
_opclass.dump();
fprintf(stderr,"\n");
fprintf(stderr,"------------------ Dump Attributes ------------------\n");
_attributes.dump();
fprintf(stderr,"\n");
fprintf(stderr,"------------------ Dump Instructions -----------------\n");
_instructions.dump();
if ( _encode ) {
fprintf(stderr,"------------------ Dump Encodings --------------------\n");
_encode->dump();
}
if (_pipeline) _pipeline->dump();
}
void ArchDesc::initKeywords(FormDict& names) {
names.Insert("instruct", NULL);
names.Insert("operand", NULL);
names.Insert("attribute", NULL);
names.Insert("source", NULL);
names.Insert("register", NULL);
names.Insert("pipeline", NULL);
names.Insert("constraint", NULL);
names.Insert("predicate", NULL);
names.Insert("encode", NULL);
names.Insert("enc_class", NULL);
names.Insert("interface", NULL);
names.Insert("opcode", NULL);
names.Insert("ins_encode", NULL);
names.Insert("match", NULL);
names.Insert("effect", NULL);
names.Insert("expand", NULL);
names.Insert("rewrite", NULL);
names.Insert("reg_def", NULL);
names.Insert("reg_class", NULL);
names.Insert("alloc_class", NULL);
names.Insert("resource", NULL);
names.Insert("pipe_class", NULL);
names.Insert("pipe_desc", NULL);
}
void ArchDesc::internal_err(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
_internal_errs += emit_msg(0, INTERNAL_ERR, 0, fmt, args);
va_end(args);
_no_output = 1;
}
void ArchDesc::syntax_err(int lineno, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
_internal_errs += emit_msg(0, SYNERR, lineno, fmt, args);
va_end(args);
_no_output = 1;
}
int ArchDesc::emit_msg(int quiet, int flag, int line, const char *fmt,
va_list args) {
static int last_lineno = -1;
int i;
const char *pref;
switch(flag) {
case 0: pref = "Warning: "; break;
case 1: pref = "Syntax Error: "; break;
case 2: pref = "Semantic Error: "; break;
case 3: pref = "Internal Error: "; break;
default: assert(0, ""); break;
}
if (line == last_lineno) return 0;
last_lineno = line;
if (!quiet) { /* no output if in quiet mode */
i = fprintf(errfile, "%s(%d) ", _ADL_file._name, line);
while (i++ <= 15) fputc(' ', errfile);
fprintf(errfile, "%-8s:", pref);
vfprintf(errfile, fmt, args);
fprintf(errfile, "\n");
fflush(errfile);
}
return 1;
}
static const char *getRegMask(const char *reg_class_name) {
if( reg_class_name == NULL ) return "RegMask::Empty";
if (strcmp(reg_class_name,"Universe")==0) {
return "RegMask::Empty";
} else if (strcmp(reg_class_name,"stack_slots")==0) {
return "(Compile::current()->FIRST_STACK_mask())";
} else {
char *rc_name = toUpper(reg_class_name);
const char *mask = "_mask";
int length = (int)strlen(rc_name) + (int)strlen(mask) + 5;
char *regMask = new char[length];
sprintf(regMask,"%s%s()", rc_name, mask);
delete[] rc_name;
return regMask;
}
}
const char *ArchDesc::reg_class_to_reg_mask(const char *rc_name) {
const char *reg_mask = "RegMask::Empty";
if( _register ) {
RegClass *reg_class = _register->getRegClass(rc_name);
if (reg_class == NULL) {
syntax_err(0, "Use of an undefined register class %s", rc_name);
return reg_mask;
}
reg_mask = getRegMask(rc_name);
}
return reg_mask;
}
const char *ArchDesc::reg_mask(OperandForm &opForm) {
const char *regMask = "RegMask::Empty";
const char *result_class = opForm.constrained_reg_class();
if (result_class == NULL) {
opForm.dump();
syntax_err(opForm._linenum,
"Use of an undefined result class for operand: %s",
opForm._ident);
abort();
}
regMask = reg_class_to_reg_mask( result_class );
return regMask;
}
const char *ArchDesc::reg_mask(InstructForm &inForm) {
const char *result = inForm.reduce_result();
if (result == NULL) {
syntax_err(inForm._linenum,
"Did not find result operand or RegMask"
" for this instruction: %s",
inForm._ident);
abort();
}
if( strcmp(result,"Universe")==0 ) {
return "RegMask::Empty";
}
Form *form = (Form*)_globalNames[result];
if (form == NULL) {
syntax_err(inForm._linenum,
"Did not find result operand for result: %s", result);
abort();
}
OperandForm *oper = form->is_operand();
if (oper == NULL) {
syntax_err(inForm._linenum, "Form is not an OperandForm:");
form->dump();
abort();
}
return reg_mask( *oper );
}
char *ArchDesc::stack_or_reg_mask(OperandForm &opForm) {
const char *reg_mask_name = reg_mask(opForm);
if (reg_mask_name == NULL) {
syntax_err(opForm._linenum,
"Did not find reg_mask for opForm: %s",
opForm._ident);
abort();
}
const char *stack_or = "STACK_OR_";
int length = (int)strlen(stack_or) + (int)strlen(reg_mask_name) + 1;
char *result = new char[length];
sprintf(result,"%s%s", stack_or, reg_mask_name);
return result;
}
void ArchDesc::set_stack_or_reg(const char *reg_class_name) {
if( _register ) {
RegClass *reg_class = _register->getRegClass(reg_class_name);
reg_class->set_stack_version(true);
}
}
const char *ArchDesc::getIdealType(const char *idealOp) {
char last_char = 0;
const char *ptr = idealOp;
for (; *ptr != '\0'; ++ptr) {
last_char = *ptr;
}
if (strncmp(idealOp, "Vec",3)==0) {
switch(last_char) {
case 'S': return "TypeVect::VECTS";
case 'D': return "TypeVect::VECTD";
case 'X': return "TypeVect::VECTX";
case 'Y': return "TypeVect::VECTY";
default:
internal_err("Vector type %s with unrecognized type\n",idealOp);
}
}
switch(last_char) {
case 'I': return "TypeInt::INT";
case 'P': return "TypePtr::BOTTOM";
case 'N': return "TypeNarrowOop::BOTTOM";
case 'F': return "Type::FLOAT";
case 'D': return "Type::DOUBLE";
case 'L': return "TypeLong::LONG";
case 's': return "TypeInt::CC /*flags*/";
default:
return NULL;
break;
}
return NULL;
}
OperandForm *ArchDesc::constructOperand(const char *ident,
bool ideal_only) {
OperandForm *opForm = new OperandForm(ident, ideal_only);
_globalNames.Insert(ident, opForm);
addForm(opForm);
return opForm;
}
void ArchDesc::initBaseOpTypes() {
for (int i = 1; i < _last_machine_leaf; ++i) {
char *ident = (char *)NodeClassNames[i];
constructOperand(ident, true);
}
for ( int j = _last_machine_leaf+1; j < _last_opcode; ++j) {
char *ident = (char *)NodeClassNames[j];
if(!strcmp(ident, "ConI") || !strcmp(ident, "ConP") ||
!strcmp(ident, "ConN") || !strcmp(ident, "ConNKlass") ||
!strcmp(ident, "ConF") || !strcmp(ident, "ConD") ||
!strcmp(ident, "ConL") || !strcmp(ident, "Con" ) ||
!strcmp(ident, "Bool") ) {
constructOperand(ident, true);
}
else {
InstructForm *insForm = new InstructForm(ident, true);
_globalNames.Insert(ident,insForm);
addForm(insForm);
}
}
{ OperandForm *opForm;
const char *ident = "Universe";
opForm = constructOperand(ident, false);
ident = "label";
opForm = constructOperand(ident, false);
opForm = constructOperand("sRegI", false);
opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots");
opForm = constructOperand("sRegP", false);
opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots");
opForm = constructOperand("sRegF", false);
opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots");
opForm = constructOperand("sRegD", false);
opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots");
opForm = constructOperand("sRegL", false);
opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots");
ident = "method";
opForm = constructOperand(ident, false);
}
{
const char *ident = "USE";
Effect *eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "DEF";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "USE_DEF";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "KILL";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "USE_KILL";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "TEMP";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "CALL";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
}
int idealIndex = 0;
for (idealIndex = 1; idealIndex < _last_machine_leaf; ++idealIndex) {
const char *idealName = NodeClassNames[idealIndex];
_idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex);
}
for ( idealIndex = _last_machine_leaf+1;
idealIndex < _last_opcode; ++idealIndex) {
const char *idealName = NodeClassNames[idealIndex];
_idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex);
}
}
void ArchDesc::addSunCopyright(char* legal, int size, FILE *fp) {
size_t count = fwrite(legal, 1, size, fp);
assert(count == (size_t) size, "copyright info truncated");
fprintf(fp,"\n");
fprintf(fp,"// Machine Generated File. Do Not Edit!\n");
fprintf(fp,"\n");
}
void ArchDesc::addIncludeGuardStart(ADLFILE &adlfile, const char* guardString) {
fprintf(adlfile._fp, "\n");
fprintf(adlfile._fp, "#ifndef %s\n", guardString);
fprintf(adlfile._fp, "#define %s\n", guardString);
fprintf(adlfile._fp, "\n");
}
void ArchDesc::addIncludeGuardEnd(ADLFILE &adlfile, const char* guardString) {
fprintf(adlfile._fp, "\n");
fprintf(adlfile._fp, "#endif // %s\n", guardString);
}
void ArchDesc::addInclude(ADLFILE &adlfile, const char* fileName) {
fprintf(adlfile._fp, "#include \"%s\"\n", fileName);
}
void ArchDesc::addInclude(ADLFILE &adlfile, const char* includeDir, const char* fileName) {
fprintf(adlfile._fp, "#include \"%s/%s\"\n", includeDir, fileName);
}
void ArchDesc::addPreprocessorChecks(FILE *fp) {
const char* flag;
_preproc_list.reset();
if (_preproc_list.count() > 0 && !_preproc_list.current_is_signal()) {
fprintf(fp, "// Check consistency of C++ compilation with ADLC options:\n");
}
for (_preproc_list.reset(); (flag = _preproc_list.iter()) != NULL; ) {
if (_preproc_list.current_is_signal()) break;
char* def = get_preproc_def(flag);
fprintf(fp, "// Check adlc ");
if (def)
fprintf(fp, "-D%s=%s\n", flag, def);
else fprintf(fp, "-U%s\n", flag);
fprintf(fp, "#%s %s\n",
def ? "ifndef" : "ifdef", flag);
fprintf(fp, "# error \"%s %s be defined\"\n",
flag, def ? "must" : "must not");
fprintf(fp, "#endif // %s\n", flag);
}
}
const char *ArchDesc::machOperEnum(const char *opName) {
return ArchDesc::getMachOperEnum(opName);
}
const char *ArchDesc::getMachOperEnum(const char *opName) {
return (opName ? toUpper(opName) : opName);
}
void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) {
fprintf(fp_hpp, "// Mapping from machine-independent opcode to boolean\n");
fprintf(fp_hpp, "// Flag cases where machine needs cloned values or instructions\n");
fprintf(fp_hpp, "extern const char must_clone[];\n");
fprintf(fp_hpp, "\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "// Mapping from machine-independent opcode to boolean\n");
fprintf(fp_cpp, "const char must_clone[] = {\n");
for (int idealIndex = 0; idealIndex < _last_opcode; ++idealIndex) {
int must_clone = 0;
const char *idealName = NodeClassNames[idealIndex];
if ( strcmp(idealName,"CmpI") == 0
|| strcmp(idealName,"CmpU") == 0
|| strcmp(idealName,"CmpP") == 0
|| strcmp(idealName,"CmpN") == 0
|| strcmp(idealName,"CmpL") == 0
|| strcmp(idealName,"CmpUL") == 0
|| strcmp(idealName,"CmpD") == 0
|| strcmp(idealName,"CmpF") == 0
|| strcmp(idealName,"FastLock") == 0
|| strcmp(idealName,"FastUnlock") == 0
|| strcmp(idealName,"OverflowAddI") == 0
|| strcmp(idealName,"OverflowAddL") == 0
|| strcmp(idealName,"OverflowSubI") == 0
|| strcmp(idealName,"OverflowSubL") == 0
|| strcmp(idealName,"OverflowMulI") == 0
|| strcmp(idealName,"OverflowMulL") == 0
|| strcmp(idealName,"Bool") == 0
|| strcmp(idealName,"Binary") == 0 ) {
must_clone = 1;
}
fprintf(fp_cpp, " %d%s // %s: %d\n", must_clone,
(idealIndex != (_last_opcode - 1)) ? "," : " // no trailing comma",
idealName, idealIndex);
}
fprintf(fp_cpp, "};\n");
}
C:\hotspot-69087d08d473\src\share\vm/adlc/archDesc.hpp
#ifndef SHARE_VM_ADLC_ARCHDESC_HPP
#define SHARE_VM_ADLC_ARCHDESC_HPP
#define WARN 0
#define SYNERR 1
#define SEMERR 2
#define INTERNAL_ERR 3
class OutputMap;
class ProductionState;
class Expr;
typedef BufferedFile ADLFILE;
class ChainList {
NameList _name;
NameList _cost;
NameList _rule;
public:
void insert(const char *name, const char *cost, const char *rule);
bool search(const char *name);
void reset();
bool iter(const char * &name, const char * &cost, const char * &rule);
void dump();
void output(FILE *fp);
ChainList();
~ChainList();
};
class MatchList {
private:
MatchList *_next;
Predicate *_pred; // Predicate which applies to this match rule
const char *_cost;
public:
const char *_opcode;
const char *_resultStr;
const char *_lchild;
const char *_rchild;
MatchList(MatchList *nxt, Predicate *prd): _next(nxt), _pred(prd), _cost(NULL){
_resultStr = _lchild = _rchild = _opcode = NULL; }
MatchList(MatchList *nxt, Predicate *prd, const char *cost,
const char *opcode, const char *resultStr, const char *lchild,
const char *rchild)
: _next(nxt), _pred(prd), _cost(cost), _opcode(opcode),
_resultStr(resultStr), _lchild(lchild), _rchild(rchild) { }
MatchList *get_next(void) { return _next; }
char *get_pred(void) { return (_pred?_pred->_pred:NULL); }
Predicate *get_pred_obj(void) { return _pred; }
const char *get_cost(void) { return _cost == NULL ? "0" :_cost; }
bool search(const char *opc, const char *res, const char *lch,
const char *rch, Predicate *pr);
void dump();
void output(FILE *fp);
};
class ArchDesc {
private:
FormDict _globalNames; // Global names
Dict _idealIndex; // Map ideal names to index in enumeration
ExprDict _globalDefs; // Global definitions, #defines
int _internalOpCounter; // Internal Operand Counter
FormList _header; // List of Source Code Forms for hpp file
FormList _pre_header; // ditto for the very top of the hpp file
FormList _source; // List of Source Code Forms for output
FormList _instructions; // List of Instruction Forms for output
FormList _machnodes; // List of Node Classes (special for pipelining)
FormList _operands; // List of Operand Forms for output
FormList _opclass; // List of Operand Class Forms for output
FormList _attributes; // List of Attribute Forms for parsing
RegisterForm *_register; // Only one Register Form allowed
FrameForm *_frame; // Describe stack-frame layout
EncodeForm *_encode; // Only one Encode Form allowed
PipelineForm *_pipeline; // Pipeline Form for output
bool _has_match_rule[_last_opcode]; // found AD rule for ideal node in <arch>.ad
MatchList *_mlistab[_last_opcode]; // Array of MatchLists
OperandForm *_cisc_spill_operand;
bool _needs_clone_jvms;
void gen_match(FILE *fp, MatchList &mlist, ProductionState &status, Dict &operands_chained_from);
void chain_rule(FILE *fp, const char *indent, const char *ideal,
const Expr *icost, const char *irule,
Dict &operands_chained_from, ProductionState &status);
void expand_opclass(FILE *fp, const char *indent, const Expr *cost,
const char *result_type, ProductionState &status);
Expr *calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status);
void prune_matchlist(Dict &minimize, MatchList &mlist);
void buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *indent);
public:
ArchDesc();
~ArchDesc();
int _TotalLines; // Line Counter
int _no_output; // Flag to disable output of DFA, etc.
int _quiet_mode; // Do not output banner messages, etc.
int _disable_warnings; // Do not output warning messages
int _dfa_debug; // Debug Flag for generated DFA
int _dfa_small; // Debug Flag for generated DFA
int _adl_debug; // Debug Flag for ADLC
int _adlocation_debug; // Debug Flag to use ad file locations
bool _cisc_spill_debug; // Debug Flag to see cisc-spill-instructions
bool _short_branch_debug; // Debug Flag to see short branch instructions
int _syntax_errs; // Count of syntax errors
int _semantic_errs; // Count of semantic errors
int _warnings; // Count warnings
int _internal_errs; // Count of internal errors
void has_match_rule(int opc, const bool b) { _has_match_rule[opc] = b; }
ADLFILE _ADL_file; // Input Architecture Description File
ADLFILE _DFA_file; // File for definition of Matcher::DFA
ADLFILE _HPP_file; // File for ArchNode class declarations
ADLFILE _CPP_file; // File for ArchNode class defintions
ADLFILE _CPP_CLONE_file; // File for MachNode/Oper clone defintions
ADLFILE _CPP_EXPAND_file; // File for MachNode expand methods
ADLFILE _CPP_FORMAT_file; // File for MachNode/Oper format defintions
ADLFILE _CPP_GEN_file; // File for MachNode/Oper generator methods
ADLFILE _CPP_MISC_file; // File for miscellaneous MachNode/Oper tables & methods
ADLFILE _CPP_PEEPHOLE_file; // File for MachNode peephole methods
ADLFILE _CPP_PIPELINE_file; // File for MachNode pipeline defintions
ADLFILE _VM_file; // File for constants needed in VM code
ADLFILE _bug_file; // DFA debugging file
int open_file(bool required, ADLFILE & adf, const char *action);
void close_file(int delete_out, ADLFILE & adf);
int open_files(void);
void close_files(int delete_out);
Dict _chainRules; // Maps user operand names to ChainRules
Dict _internalOps; // Maps match strings to internal operand names
NameList _internalOpNames; // List internal operand names
Dict _internalMatch; // Map internal name to its MatchNode
NameList _preproc_list; // Preprocessor flag names
FormDict _preproc_table;// Preprocessor flag bindings
char* get_preproc_def(const char* flag);
void set_preproc_def(const char* flag, const char* def);
FormDict& globalNames() {return _globalNames;} // map global names to forms
void initKeywords(FormDict& globals); // Add keywords to global name table
ExprDict& globalDefs() {return _globalDefs;} // map global names to expressions
OperandForm *constructOperand(const char *ident, bool ideal_only);
void initBaseOpTypes(); // Import predefined base types.
void addForm(PreHeaderForm *ptr); // Add objects to pre-header list
void addForm(HeaderForm *ptr); // Add objects to header list
void addForm(SourceForm *ptr); // Add objects to source list
void addForm(EncodeForm *ptr); // Add objects to encode list
void addForm(InstructForm *ptr); // Add objects to the instruct list
void addForm(OperandForm *ptr); // Add objects to the operand list
void addForm(OpClassForm *ptr); // Add objects to the opclasss list
void addForm(AttributeForm *ptr); // Add objects to the attributes list
void addForm(RegisterForm *ptr); // Add objects to the register list
void addForm(FrameForm *ptr); // Add objects to the frame list
void addForm(PipelineForm *ptr); // Add objects to the pipeline list
void addForm(MachNodeForm *ptr); // Add objects to the machnode list
int operandFormCount(); // Count number of OperandForms defined
int opclassFormCount(); // Count number of OpClassForms defined
int instructFormCount(); // Count number of InstructForms defined
inline void getForm(EncodeForm **ptr) { *ptr = _encode; }
bool verify();
void dump();
void check_optype(MatchRule *mrule);
void build_chain_rule(OperandForm *oper);
void add_chain_rule_entry(const char *src, const char *cost,
const char *result);
const char *getMatchListIndex(MatchRule &mrule);
void generateMatchLists(); // Build MatchList array and populate it
void inspectOperands(); // Build MatchLists for all operands
void inspectOpClasses(); // Build MatchLists for all operands
void inspectInstructions(); // Build MatchLists for all operands
void buildDFA(FILE *fp); // Driver for constructing the DFA
void gen_dfa_state_body(FILE *fp, Dict &minmize, ProductionState &status, Dict &chained, int i); // Driver for constructing the DFA state bodies
const char *reduceLeft (char *internalName);
const char *reduceRight(char *internalName);
const char *machOperEnum(const char *opName); // create dense index names using static function
static const char *getMachOperEnum(const char *opName);// create dense index name
void buildMachOperEnum(FILE *fp_hpp);// dense enumeration for operands
void buildMachOpcodesEnum(FILE *fp_hpp);// enumeration for MachOpers & MachNodes
RegisterForm *get_registers() { return _register; }
const char *reg_mask(OperandForm &opForm);
const char *reg_mask(InstructForm &instForm);
const char *reg_class_to_reg_mask(const char *reg_class);
char *stack_or_reg_mask(OperandForm &opForm); // name of cisc_spillable version
void set_stack_or_reg(const char *reg_class_name); // for cisc-spillable reg classes
void declare_register_masks(FILE *fp_cpp);
void build_register_masks(FILE *fp_cpp);
void buildMachRegisterNumbers(FILE *fp_hpp);
void buildMachRegisterEncodes(FILE *fp_hpp);
void declareRegSizes(FILE *fp_hpp);
void declare_pipe_classes(FILE *fp_hpp);
void build_pipeline_enums(FILE *fp_cpp);
void build_pipe_classes(FILE *fp_cpp);
void build_map(OutputMap &map);
void buildReduceMaps(FILE *fp_hpp, FILE *fp_cpp);
void buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp);
void addSunCopyright(char* legal, int size, FILE *fp);
void addIncludeGuardStart(ADLFILE &adlfile, const char* guardString);
void addIncludeGuardEnd(ADLFILE &adlfile, const char* guardString);
void addInclude(ADLFILE &adlfile, const char* fileName);
void addInclude(ADLFILE &adlfile, const char* includeDir, const char* fileName);
void addPreprocessorChecks(FILE *fp);
void addPreHeaderBlocks(FILE *fp_hpp);
void addHeaderBlocks(FILE *fp_hpp);
void addSourceBlocks(FILE *fp_cpp);
void generate_needs_clone_jvms(FILE *fp_cpp);
void generate_adlc_verification(FILE *fp_cpp);
void defineStateClass(FILE *fp);
void buildMachOperGenerator(FILE *fp_cpp);
void buildMachNodeGenerator(FILE *fp_cpp);
void defineExpand (FILE *fp, InstructForm *node);
void definePeephole (FILE *fp, InstructForm *node);
void defineSize (FILE *fp, InstructForm &node);
public:
void defineEvalConstant(FILE *fp, InstructForm &node);
void defineEmit (FILE *fp, InstructForm &node);
void define_postalloc_expand(FILE *fp, InstructForm &node);
void define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,
const char *name, const char *encoding);
const char *getIdealType(const char *idealOp);
void declareClasses(FILE *fp_hpp);
void defineClasses(FILE *fp_cpp);
void internal_err( const char *fmt, ...);
void syntax_err ( int lineno, const char *fmt, ...);
int emit_msg(int quiet, int flag, int linenum, const char *fmt,
va_list args);
void buildInstructMatchCheck(FILE *fp_cpp) const;
void buildFrameMethods(FILE *fp_cpp);
void build_cisc_spill_instructions(FILE *fp_hpp, FILE *fp_cpp);
void identify_cisc_spill_instructions();
void identify_short_branches();
void identify_unique_operands();
void set_cisc_spill_operand(OperandForm *opForm) { _cisc_spill_operand = opForm; }
OperandForm *cisc_spill_operand() { return _cisc_spill_operand; }
bool can_cisc_spill() { return _cisc_spill_operand != NULL; }
protected:
void buildMatchList(MatchRule *mrule, const char *resultStr,
const char *rootOp, Predicate *pred, const char *cost);
void buildMList(MatchNode *node, const char *rootOp, const char *resultOp,
Predicate *pred, const char *cost);
friend class ADLParser;
};
class OutputMap {
protected:
FILE *_hpp;
FILE *_cpp;
FormDict &_globals;
ArchDesc &_AD;
const char *_name;
public:
OutputMap (FILE *decl_file, FILE *def_file, FormDict &globals, ArchDesc &AD, const char *name)
: _hpp(decl_file), _cpp(def_file), _globals(globals), _AD(AD), _name(name) {};
FILE *decl_file() { return _hpp; }
FILE *def_file() { return _cpp; }
enum position { BEGIN_OPERANDS,
BEGIN_OPCLASSES,
BEGIN_INTERNALS,
BEGIN_INSTRUCTIONS,
BEGIN_INST_CHAIN_RULES,
END_INST_CHAIN_RULES,
BEGIN_REMATERIALIZE,
END_REMATERIALIZE,
END_INSTRUCTIONS
};
virtual void declaration() {}
virtual void definition() {}
virtual void closing() { fprintf(_cpp, "};\n"); }
virtual void map(OperandForm &oper) { }
virtual void map(OpClassForm &opc) { }
virtual void map(char *internal_name) { }
virtual bool do_instructions() { return true; }
virtual void map(InstructForm &inst) { }
virtual void record_position(OutputMap::position place, int index) {}
};
#endif // SHARE_VM_ADLC_ARCHDESC_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/arena.cpp
#include "adlc.hpp"
void* Chunk::operator new(size_t requested_size, size_t length) throw() {
return CHeapObj::operator new(requested_size + length);
}
void Chunk::operator delete(void* p, size_t length) {
CHeapObj::operator delete(p);
}
Chunk::Chunk(size_t length) {
_next = NULL; // Chain on the linked list
_len = length; // Save actual size
}
void Chunk::chop() {
Chunk *k = this;
while( k ) {
Chunk *tmp = k->_next;
memset(k, 0xBAADBABE, k->_len);
free(k); // Free chunk (was malloc'd)
k = tmp;
}
}
void Chunk::next_chop() {
_next->chop();
_next = NULL;
}
Arena::Arena( size_t init_size ) {
init_size = (init_size+3) & ~3;
_first = _chunk = new (init_size) Chunk(init_size);
_hwm = _chunk->bottom(); // Save the cached hwm, max
_max = _chunk->top();
set_size_in_bytes(init_size);
}
Arena::Arena() {
_first = _chunk = new (Chunk::init_size) Chunk(Chunk::init_size);
_hwm = _chunk->bottom(); // Save the cached hwm, max
_max = _chunk->top();
set_size_in_bytes(Chunk::init_size);
}
Arena::Arena( Arena *a )
: _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) {
set_size_in_bytes(a->size_in_bytes());
}
size_t Arena::used() const {
size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this Chunk
register Chunk *k = _first;
while( k != _chunk) { // Whilst have Chunks in a row
sum += k->_len; // Total size of this Chunk
k = k->_next; // Bump along to next Chunk
}
return sum; // Return total consumed space.
}
void* Arena::grow( size_t x ) {
size_t len = max(x, Chunk::size);
register Chunk *k = _chunk; // Get filled-up chunk address
_chunk = new (len) Chunk(len);
if( k ) k->_next = _chunk; // Append new chunk to end of linked list
else _first = _chunk;
_hwm = _chunk->bottom(); // Save the cached hwm, max
_max = _chunk->top();
set_size_in_bytes(size_in_bytes() + len);
void* result = _hwm;
_hwm += x;
return result;
}
void *Arena::Acalloc( size_t items, size_t x ) {
size_t z = items*x; // Total size needed
void *ptr = Amalloc(z); // Get space
memset( ptr, 0, z ); // Zap space
return ptr; // Return space
}
void *Arena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) {
char *c_old = (char*)old_ptr; // Handy name
if( new_size <= old_size ) { // Shrink in-place
if( c_old+old_size == _hwm) // Attempt to free the excess bytes
_hwm = c_old+new_size; // Adjust hwm
return c_old;
}
if( (c_old+old_size == _hwm) && // Adjusting recent thing
(c_old+new_size <= _max) ) { // Still fits where it sits
_hwm = c_old+new_size; // Adjust hwm
return c_old; // Return old pointer
}
void *new_ptr = Amalloc(new_size);
memcpy( new_ptr, c_old, old_size );
Afree(c_old,old_size); // Mostly done to keep stats accurate
return new_ptr;
}
Arena *Arena::reset(void) {
Arena *a = new Arena(this); // New empty arena
_first = _chunk = NULL; // Normal, new-arena initialization
_hwm = _max = NULL;
return a; // Return Arena with guts
}
bool Arena::contains( const void *ptr ) const {
if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm )
return true; // Check for in this chunk
for( Chunk *c = _first; c; c = c->_next )
if( (void*)c->bottom() <= ptr && ptr < (void*)c->top())
return true; // Check for every chunk in Arena
return false; // Not in any Chunk, so not in Arena
}
void* CHeapObj::operator new(size_t size) throw() {
return (void *) malloc(size);
}
void CHeapObj::operator delete(void* p){
free(p);
}
C:\hotspot-69087d08d473\src\share\vm/adlc/arena.hpp
#ifndef SHARE_VM_ADLC_ARENA_HPP
#define SHARE_VM_ADLC_ARENA_HPP
class CHeapObj {
public:
void* operator new(size_t size) throw();
void operator delete(void* p);
void* new_array(size_t size);
};
class ValueObj {
public:
void* operator new(size_t size) throw();
void operator delete(void* p);
};
class AllStatic {
public:
void* operator new(size_t size) throw();
void operator delete(void* p);
};
class Chunk: public CHeapObj {
private:
void operator delete(void* p);
public:
void* operator new(size_t size, size_t length) throw();
void operator delete(void* p, size_t length);
Chunk(size_t length);
enum {
init_size = 1*1024, // Size of first chunk
size = 32*1024 // Default size of an Arena chunk (following the first)
};
Chunk* _next; // Next Chunk in list
size_t _len; // Size of this Chunk
void chop(); // Chop this chunk
void next_chop(); // Chop next chunk
char* bottom() const { return ((char*) this) + sizeof(Chunk); }
char* top() const { return bottom() + _len; }
};
class Arena: public CHeapObj {
protected:
friend class ResourceMark;
friend class HandleMark;
friend class NoHandleMark;
Chunk *_first; // First chunk
Chunk *_chunk; // current chunk
char *_hwm, *_max; // High water mark and max in current chunk
void* grow(size_t x); // Get a new Chunk of at least size x
size_t _size_in_bytes; // Size of arena (used for memory usage tracing)
public:
Arena();
Arena(size_t init_size);
Arena(Arena *old);
~Arena() { _first->chop(); }
char* hwm() const { return _hwm; }
void* Amalloc(size_t x) {
#ifdef _LP64
x = (x + (8-1)) & ((unsigned)(-8));
#else
x = (x + (4-1)) & ((unsigned)(-4));
#endif
if (_hwm + x > _max) {
return grow(x);
} else {
char *old = _hwm;
_hwm += x;
return old;
}
}
void *Amalloc_4(size_t x) {
assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" );
if (_hwm + x > _max) {
return grow(x);
} else {
char *old = _hwm;
_hwm += x;
return old;
}
}
void Afree(void *ptr, size_t size) {
if (((char*)ptr) + size == _hwm) _hwm = (char*)ptr;
}
void *Acalloc( size_t items, size_t x );
void *Arealloc( void *old_ptr, size_t old_size, size_t new_size );
Arena *reset(void);
bool contains( const void *ptr ) const;
size_t used() const;
size_t size_in_bytes() const { return _size_in_bytes; }
void set_size_in_bytes(size_t size) { _size_in_bytes = size; }
};
#endif // SHARE_VM_ADLC_ARENA_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/dfa.cpp
#include "adlc.hpp"
static bool debug_output = false;
static bool debug_output1 = false; // top level chain rules
static const char *sLeft = "_kids[0]";
static const char *sRight = "_kids[1]";
static const char *dfa_production = "DFA_PRODUCTION";
static const char *dfa_production_set_valid = "DFA_PRODUCTION__SET_VALID";
static const char *knownInvalid = "knownInvalid"; // The result does NOT have a rule defined
static const char *knownValid = "knownValid"; // The result must be produced by a rule
static const char *unknownValid = "unknownValid"; // Unknown (probably due to a child or predicate constraint)
static const char *noConstraint = "noConstraint"; // No constraints seen so far
static const char *hasConstraint = "hasConstraint"; // Within the first constraint
class Production {
public:
const char *_result;
const char *_constraint;
const char *_valid;
Expr *_cost_lb; // Cost lower bound for this production
Expr *_cost_ub; // Cost upper bound for this production
public:
Production(const char *result, const char *constraint, const char *valid);
~Production() {};
void initialize(); // reset to be an empty container
const char *valid() const { return _valid; }
Expr *cost_lb() const { return (Expr *)_cost_lb; }
Expr *cost_ub() const { return (Expr *)_cost_ub; }
void print();
};
class ProductionState {
private:
Dict _production; // map result of production, char*, to information or NULL
const char *_constraint;
public:
ProductionState(Arena *arena) : _production(cmpstr, hashstr, arena) { initialize(); };
~ProductionState() { };
void initialize(); // reset local and dictionary state
const char *constraint();
void set_constraint(const char *constraint); // currently working inside of constraints
const char *valid(const char *result); // unknownValid, or status for this production
void set_valid(const char *result); // if not constrained, set status to knownValid
Expr *cost_lb(const char *result);
Expr *cost_ub(const char *result);
void set_cost_bounds(const char *result, const Expr *cost, bool has_state_check, bool has_cost_check);
Production *getProduction(const char *result);
void print();
private:
ProductionState( ) : _production(cmpstr, hashstr, Form::arena) { assert( false, "NotImplemented"); };
ProductionState( const ProductionState & ) : _production(cmpstr, hashstr, Form::arena) { assert( false, "NotImplemented"); }; // Deep-copy
};
static void cost_check(FILE *fp, const char *spaces,
const char *arrayIdx, const Expr *cost, const char *rule, ProductionState &status) {
bool state_check = false; // true if this production needs to check validity
bool cost_check = false; // true if this production needs to check cost
bool cost_is_above_upper_bound = false; // true if this production is unnecessary due to high cost
bool cost_is_below_lower_bound = false; // true if this production replaces a higher cost production
const Expr *previous_ub = status.cost_ub(arrayIdx);
if( !previous_ub->is_unknown() ) {
if( previous_ub->less_than_or_equal(cost) ) {
cost_is_above_upper_bound = true;
if( debug_output ) { fprintf(fp, "// Previous rule with lower cost than: %s === %s_rule costs %s\n", arrayIdx, rule, cost->as_string()); }
}
}
const Expr *previous_lb = status.cost_lb(arrayIdx);
if( !previous_lb->is_unknown() ) {
if( cost->less_than_or_equal(previous_lb) ) {
cost_is_below_lower_bound = true;
if( debug_output ) { fprintf(fp, "// Previous rule with higher cost\n"); }
}
}
const char *validity_check = status.valid(arrayIdx);
if( validity_check == unknownValid ) {
fprintf(fp, "%sif (STATE__NOT_YET_VALID(%s) || _cost[%s] > %s) {\n", spaces, arrayIdx, arrayIdx, cost->as_string());
state_check = true;
cost_check = true;
}
else if( validity_check == knownInvalid ) {
if( debug_output ) { fprintf(fp, "%s// %s KNOWN_INVALID \n", spaces, arrayIdx); }
}
else if( validity_check == knownValid ) {
if( cost_is_above_upper_bound ) {
return;
} else if( cost_is_below_lower_bound ) {
} else {
fprintf(fp, "%sif ( /* %s KNOWN_VALID || */ _cost[%s] > %s) {\n", spaces, arrayIdx, arrayIdx, cost->as_string());
cost_check = true;
}
}
const char *production = (validity_check == knownValid) ? dfa_production : dfa_production_set_valid;
fprintf(fp, "%s %s(%s, %s_rule, %s)", spaces, production, arrayIdx, rule, cost->as_string() );
if( validity_check == knownValid ) {
if( cost_is_below_lower_bound ) { fprintf(fp, "\t // overwrites higher cost rule"); }
}
fprintf(fp, "\n");
if( cost_check || state_check ) {
fprintf(fp, "%s}\n", spaces);
}
status.set_cost_bounds(arrayIdx, cost, state_check, cost_check);
if( validity_check != knownValid ) {
status.set_valid(arrayIdx);
}
}
static void child_test(FILE *fp, MatchList &mList) {
if (mList._lchild) { // If left child, check it
const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild);
fprintf(fp, "STATE__VALID_CHILD(_kids[0], %s)", lchild_to_upper);
delete[] lchild_to_upper;
}
if (mList._lchild && mList._rchild) { // If both, add the "&&"
fprintf(fp, " && ");
}
if (mList._rchild) { // If right child, check it
const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild);
fprintf(fp, "STATE__VALID_CHILD(_kids[1], %s)", rchild_to_upper);
delete[] rchild_to_upper;
}
}
Expr *ArchDesc::calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status) {
fprintf(fp, "%sunsigned int c = ", spaces);
Expr *c = new Expr("0");
if (mList._lchild) { // If left child, add it in
const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild);
sprintf(Expr::buffer(), "_kids[0]->_cost[%s]", lchild_to_upper);
c->add(Expr::buffer());
delete[] lchild_to_upper;
}
if (mList._rchild) { // If right child, add it in
const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild);
sprintf(Expr::buffer(), "_kids[1]->_cost[%s]", rchild_to_upper);
c->add(Expr::buffer());
delete[] rchild_to_upper;
}
const char *mList_cost = mList.get_cost();
c->add(mList_cost, *this);
fprintf(fp, "%s;\n", c->as_string());
c->set_external_name("c");
return c;
}
void ArchDesc::gen_match(FILE *fp, MatchList &mList, ProductionState &status, Dict &operands_chained_from) {
const char *spaces4 = " ";
const char *spaces6 = " ";
fprintf(fp, "%s", spaces4);
bool has_child_constraints = mList._lchild || mList._rchild;
const char *predicate_test = mList.get_pred();
if (has_child_constraints || predicate_test) {
fprintf(fp, "if( ");
status.set_constraint(hasConstraint);
child_test(fp, mList);
if (predicate_test) {
if (has_child_constraints) {
fprintf(fp," &&\n");
}
fprintf(fp, "%s %s", spaces6, predicate_test);
}
fprintf(fp," ) ");
} else {
status.set_constraint(noConstraint);
}
fprintf(fp,"{\n");
const Expr *cost = calc_cost(fp, spaces6, mList, status);
cost_check(fp, spaces6, ArchDesc::getMachOperEnum(mList._resultStr), cost, mList._opcode, status);
expand_opclass( fp, spaces6, cost, mList._resultStr, status);
const char *rule = /* set rule to "Invalid" for internal operands */
strcmp(mList._opcode,mList._resultStr) ? mList._opcode : "Invalid";
chain_rule(fp, spaces6, mList._resultStr, cost, rule, operands_chained_from, status);
fprintf(fp, " }\n");
}
void ArchDesc::expand_opclass(FILE *fp, const char *indent, const Expr *cost,
const char *result_type, ProductionState &status) {
const Form *form = _globalNames[result_type];
OperandForm *op = form ? form->is_operand() : NULL;
if( op && op->_classes.count() > 0 ) {
if( debug_output ) { fprintf(fp, "// expand operand classes for operand: %s \n", (char *)op->_ident ); } // %%%%% Explanation
op->_classes.reset();
const char *oclass;
while( (oclass = op->_classes.iter()) != NULL )
cost_check(fp, indent, ArchDesc::getMachOperEnum(oclass), cost, result_type, status);
}
}
void ArchDesc::chain_rule(FILE *fp, const char *indent, const char *operand,
const Expr *icost, const char *irule, Dict &operands_chained_from, ProductionState &status) {
if( operands_chained_from[operand] != NULL ) {
return;
} else {
operands_chained_from.Insert( operand, operand);
}
if( debug_output ) { fprintf(fp, "// chain rules starting from: %s and %s \n", (char *)operand, (char *)irule); } // %%%%% Explanation
ChainList *lst = (ChainList *)_chainRules[operand];
if (lst) {
const char *result, *cost, *rule;
for(lst->reset(); (lst->iter(result,cost,rule)) == true; ) {
if( operands_chained_from[result] != NULL ) {
continue;
} else {
Expr *total_cost = icost->clone(); // icost + cost
total_cost->add(cost, *this);
Form *form = (Form *)_globalNames[rule];
if ( ! form->is_instruction()) {
const char *reduce_rule = strcmp(irule,"Invalid") ? irule : rule;
cost_check(fp, indent, ArchDesc::getMachOperEnum(result), total_cost, reduce_rule, status);
chain_rule(fp, indent, result, total_cost, irule, operands_chained_from, status);
} else {
cost_check(fp, indent, ArchDesc::getMachOperEnum(result), total_cost, rule, status);
chain_rule(fp, indent, result, total_cost, rule, operands_chained_from, status);
}
expand_opclass( fp, indent, total_cost, result, status );
}
}
}
}
void ArchDesc::prune_matchlist(Dict &minimize, MatchList &mlist) {
}
void ArchDesc::buildDFA(FILE* fp) {
int i;
Dict operands_chained_from(cmpstr, hashstr, Form::arena);
Dict minimize(cmpstr, hashstr, Form::arena);
ProductionState status(Form::arena);
fprintf(fp, "\n");
fprintf(fp, "//------------------------- Source -----------------------------------------\n");
fprintf(fp, "\n");
fprintf(fp, "//------------------------- Attributes -------------------------------------\n");
_attributes.output(fp);
fprintf(fp, "\n");
fprintf(fp, "//------------------------- Macros -----------------------------------------\n");
fprintf(fp, "#define %s(result, rule, cost)\\\n", dfa_production);
fprintf(fp, " _cost[ (result) ] = cost; _rule[ (result) ] = rule;\n");
fprintf(fp, "\n");
fprintf(fp, "#define %s(result, rule, cost)\\\n", dfa_production_set_valid);
fprintf(fp, " %s( (result), (rule), (cost) ); STATE__SET_VALID( (result) );\n", dfa_production);
fprintf(fp, "\n");
fprintf(fp, "//------------------------- DFA --------------------------------------------\n");
fprintf(fp,
"// DFA is a large switch with case statements for each ideal opcode encountered\n"
"// in any match rule in the ad file. Each case has a series of if's to handle\n"
"// the match or fail decisions. The matches test the cost function of that\n"
"// rule, and prune any cases which are higher cost for the same reduction.\n"
"// In order to generate the DFA we walk the table of ideal opcode/MatchList\n"
"// pairs generated by the ADLC front end to build the contents of the case\n"
"// statements (a series of if statements).\n"
);
fprintf(fp, "\n");
fprintf(fp, "\n");
if (_dfa_small) {
for (i = 1; i < _last_opcode; i++) {
if (_mlistab[i] == NULL) continue;
fprintf(fp, "void State::_sub_Op_%s(const Node *n){\n", NodeClassNames[i]);
gen_dfa_state_body(fp, minimize, status, operands_chained_from, i);
fprintf(fp, "}\n");
}
}
fprintf(fp, "bool State::DFA");
fprintf(fp, "(int opcode, const Node *n) {\n");
fprintf(fp, " switch(opcode) {\n");
for (i = 1; i < _last_opcode; i++) {
if (_mlistab[i] == NULL) continue;
if (_dfa_small) {
fprintf(fp, " case Op_%s: { _sub_Op_%s(n);\n", NodeClassNames[i], NodeClassNames[i]);
} else {
fprintf(fp, " case Op_%s: {\n", NodeClassNames[i]);
gen_dfa_state_body(fp, minimize, status, operands_chained_from, i);
}
fprintf(fp, " break;\n");
fprintf(fp, " }\n");
}
fprintf(fp, " \n");
fprintf(fp, " default:\n");
fprintf(fp, " tty->print(\"Default case invoked for: \\n\");\n");
fprintf(fp, " tty->print(\" opcode = %cd, \\\"%cs\\\"\\n\", opcode, NodeClassNames[opcode]);\n", '%', '%');
fprintf(fp, " return false;\n");
fprintf(fp, " }\n");
fprintf(fp, " return true;\n");
fprintf(fp, "}\n");
Expr::check_buffers();
}
class dfa_shared_preds {
enum { count = 4 };
static bool _found[count];
static const char* _type [count];
static const char* _var [count];
static const char* _pred [count];
static void check_index(int index) { assert( 0 <= index && index < count, "Invalid index"); }
static bool valid_loc(char *pred, char *shared) {
if( shared == pred ) return true;
char *prev = shared - 1;
char c = *prev;
switch( c ) {
case ' ':
case '\n':
return dfa_shared_preds::valid_loc(pred, prev);
case '!':
case '(':
case '<':
case '=':
return true;
case '"': // such as: #line 10 "myfile.ad"\n mypredicate
return true;
case '|':
if( prev != pred && *(prev-1) == '|' ) return true;
case '&':
if( prev != pred && *(prev-1) == '&' ) return true;
default:
return false;
}
return false;
}
public:
static bool found(int index){ check_index(index); return _found[index]; }
static void set_found(int index, bool val) { check_index(index); _found[index] = val; }
static void reset_found() {
for( int i = 0; i < count; ++i ) { _found[i] = false; }
};
static const char* type(int index) { check_index(index); return _type[index]; }
static const char* var (int index) { check_index(index); return _var [index]; }
static const char* pred(int index) { check_index(index); return _pred[index]; }
static void cse_matchlist(MatchList *matchList) {
for( MatchList *mList = matchList; mList != NULL; mList = mList->get_next() ) {
Predicate* predicate = mList->get_pred_obj();
char* pred = mList->get_pred();
if( pred != NULL ) {
for(int index = 0; index < count; ++index ) {
const char *shared_pred = dfa_shared_preds::pred(index);
const char *shared_pred_var = dfa_shared_preds::var(index);
bool result = dfa_shared_preds::cse_predicate(predicate, shared_pred, shared_pred_var);
if( result ) dfa_shared_preds::set_found(index, true);
}
}
}
}
static bool cse_predicate(Predicate* predicate, const char *shared_pred, const char *shared_pred_var) {
bool result = false;
char *pred = predicate->_pred;
if( pred != NULL ) {
char *new_pred = pred;
for( char *shared_pred_loc = strstr(new_pred, shared_pred);
shared_pred_loc != NULL && dfa_shared_preds::valid_loc(new_pred,shared_pred_loc);
shared_pred_loc = strstr(new_pred, shared_pred) ) {
if( new_pred == pred ) {
new_pred = strdup(pred);
shared_pred_loc = strstr(new_pred, shared_pred);
}
strncpy(shared_pred_loc, shared_pred_var, strlen(shared_pred_var));
}
if( new_pred != pred ) {
predicate->_pred = new_pred;
result = true;
}
}
return result;
}
static void generate_cse(FILE *fp) {
for(int j = 0; j < count; ++j ) {
if( dfa_shared_preds::found(j) ) {
const char *shared_pred_type = dfa_shared_preds::type(j);
const char *shared_pred_var = dfa_shared_preds::var(j);
const char *shared_pred = dfa_shared_preds::pred(j);
fprintf(fp, " %s %s = %s;\n", shared_pred_type, shared_pred_var, shared_pred);
}
}
}
};
bool dfa_shared_preds::_found[dfa_shared_preds::count]
= { false, false, false, false };
const char* dfa_shared_preds::_type[dfa_shared_preds::count]
= { "int", "jlong", "intptr_t", "bool" };
const char* dfa_shared_preds::_var [dfa_shared_preds::count]
= { "_n_get_int__", "_n_get_long__", "_n_get_intptr_t__", "Compile__current____select_24_bit_instr__" };
const char* dfa_shared_preds::_pred[dfa_shared_preds::count]
= { "n->get_int()", "n->get_long()", "n->get_intptr_t()", "Compile::current()->select_24_bit_instr()" };
void ArchDesc::gen_dfa_state_body(FILE* fp, Dict &minimize, ProductionState &status, Dict &operands_chained_from, int i) {
status.initialize();
MatchList* mList = _mlistab[i];
do {
prune_matchlist(minimize, *mList);
mList = mList->get_next();
} while(mList != NULL);
dfa_shared_preds::reset_found();
dfa_shared_preds::cse_matchlist(_mlistab[i]);
dfa_shared_preds::generate_cse(fp);
mList = _mlistab[i];
do {
operands_chained_from.Clear();
gen_match(fp, *mList, status, operands_chained_from);
mList = mList->get_next();
} while(mList != NULL);
operands_chained_from.Clear(); //
if( debug_output1 ) { fprintf(fp, "// top level chain rules for: %s \n", (char *)NodeClassNames[i]); } // %%%%% Explanation
const Expr *zeroCost = new Expr("0");
chain_rule(fp, " ", (char *)NodeClassNames[i], zeroCost, "Invalid",
operands_chained_from, status);
}
Expr *Expr::_unknown_expr = NULL;
char Expr::string_buffer[STRING_BUFFER_LENGTH];
char Expr::external_buffer[STRING_BUFFER_LENGTH];
bool Expr::_init_buffers = Expr::init_buffers();
Expr::Expr() {
_external_name = NULL;
_expr = "Invalid_Expr";
_min_value = Expr::Max;
_max_value = Expr::Zero;
}
Expr::Expr(const char *cost) {
_external_name = NULL;
int intval = 0;
if( cost == NULL ) {
_expr = "0";
_min_value = Expr::Zero;
_max_value = Expr::Zero;
}
else if( ADLParser::is_int_token(cost, intval) ) {
_expr = cost;
_min_value = intval;
_max_value = intval;
}
else {
assert( strcmp(cost,"0") != 0, "Recognize string zero as an int");
_expr = cost;
_min_value = Expr::Zero;
_max_value = Expr::Max;
}
}
Expr::Expr(const char *name, const char *expression, int min_value, int max_value) {
_external_name = name;
_expr = expression ? expression : name;
_min_value = min_value;
_max_value = max_value;
assert(_min_value >= 0 && _min_value <= Expr::Max, "value out of range");
assert(_max_value >= 0 && _max_value <= Expr::Max, "value out of range");
}
Expr *Expr::clone() const {
Expr *cost = new Expr();
cost->_external_name = _external_name;
cost->_expr = _expr;
cost->_min_value = _min_value;
cost->_max_value = _max_value;
return cost;
}
void Expr::add(const Expr *c) {
const char *external = compute_external(this, c);
const char *expr = compute_expr(this, c);
int min_value = compute_min (this, c);
int max_value = compute_max (this, c);
_external_name = external;
_expr = expr;
_min_value = min_value;
_max_value = max_value;
}
void Expr::add(const char *c) {
Expr *cost = new Expr(c);
add(cost);
}
void Expr::add(const char *c, ArchDesc &AD) {
const Expr *e = AD.globalDefs()[c];
if( e != NULL ) {
add(e);
} else {
Expr *cost = new Expr(c);
add(cost);
}
}
const char *Expr::compute_external(const Expr *c1, const Expr *c2) {
const char * result = NULL;
if( c1->_external_name != NULL ) {
sprintf( string_buffer, "%s", c1->as_string());
if( !c2->is_zero() ) {
strcat( string_buffer, "+");
strcat( string_buffer, c2->as_string());
}
result = strdup(string_buffer);
}
else if( c2->_external_name != NULL ) {
if( !c1->is_zero() ) {
sprintf( string_buffer, "%s", c1->as_string());
strcat( string_buffer, " + ");
} else {
string_buffer[0] = '\0';
}
strcat( string_buffer, c2->_external_name );
result = strdup(string_buffer);
}
return result;
}
const char *Expr::compute_expr(const Expr *c1, const Expr *c2) {
if( !c1->is_zero() ) {
sprintf( string_buffer, "%s", c1->_expr);
if( !c2->is_zero() ) {
strcat( string_buffer, "+");
strcat( string_buffer, c2->_expr);
}
}
else if( !c2->is_zero() ) {
sprintf( string_buffer, "%s", c2->_expr);
}
else {
sprintf( string_buffer, "0");
}
char *cost = strdup(string_buffer);
return cost;
}
int Expr::compute_min(const Expr *c1, const Expr *c2) {
int v1 = c1->_min_value;
int v2 = c2->_min_value;
assert(0 <= v2 && v2 <= Expr::Max, "sanity");
assert(v1 <= Expr::Max - v2, "Invalid cost computation");
return v1 + v2;
}
int Expr::compute_max(const Expr *c1, const Expr *c2) {
int v1 = c1->_max_value;
int v2 = c2->_max_value;
assert(0 <= v2 && v2 <= Expr::Max, "sanity");
if (v1 > Expr::Max - v2) {
return Expr::Max;
}
return v1 + v2;
}
void Expr::print() const {
if( _external_name != NULL ) {
printf(" %s == (%s) === [%d, %d]\n", _external_name, _expr, _min_value, _max_value);
} else {
printf(" %s === [%d, %d]\n", _expr, _min_value, _max_value);
}
}
void Expr::print_define(FILE *fp) const {
assert( _external_name != NULL, "definition does not have a name");
assert( _min_value == _max_value, "Expect user definitions to have constant value");
fprintf(fp, "#define %s (%s) \n", _external_name, _expr);
fprintf(fp, "// value == %d \n", _min_value);
}
void Expr::print_assert(FILE *fp) const {
assert( _external_name != NULL, "definition does not have a name");
assert( _min_value == _max_value, "Expect user definitions to have constant value");
fprintf(fp, " assert( %s == %d, \"Expect (%s) to equal %d\");\n", _external_name, _min_value, _expr, _min_value);
}
Expr *Expr::get_unknown() {
if( Expr::_unknown_expr == NULL ) {
Expr::_unknown_expr = new Expr();
}
return Expr::_unknown_expr;
}
bool Expr::init_buffers() {
for( int i = 0; i < STRING_BUFFER_LENGTH; ++i ) {
external_buffer[i] = '\0';
string_buffer[i] = '\0';
}
return true;
}
bool Expr::check_buffers() {
bool ok = true;
for( int i = STRING_BUFFER_LENGTH - 100; i < STRING_BUFFER_LENGTH; ++i) {
if( external_buffer[i] != '\0' || string_buffer[i] != '\0' ) {
ok = false;
assert( false, "Expr:: Buffer overflow");
}
}
return ok;
}
ExprDict::ExprDict( CmpKey cmp, Hash hash, Arena *arena )
: _expr(cmp, hash, arena), _defines() {
}
ExprDict::~ExprDict() {
}
int ExprDict::Size(void) const {
return _expr.Size();
}
const Expr *ExprDict::define(const char *name, Expr *expr) {
const Expr *old_expr = (*this)[name];
assert(old_expr == NULL, "Implementation does not support redefinition");
_expr.Insert(name, expr);
_defines.addName(name);
return old_expr;
}
const Expr *ExprDict::Insert(const char *name, Expr *expr) {
return (Expr*)_expr.Insert((void*)name, (void*)expr);
}
const Expr *ExprDict::operator [](const char *name) const {
return (Expr*)_expr[name];
}
void ExprDict::print_defines(FILE *fp) {
fprintf(fp, "\n");
const char *name = NULL;
for( _defines.reset(); (name = _defines.iter()) != NULL; ) {
const Expr *expr = (const Expr*)_expr[name];
assert( expr != NULL, "name in ExprDict without matching Expr in dictionary");
expr->print_define(fp);
}
}
void ExprDict::print_asserts(FILE *fp) {
fprintf(fp, "\n");
fprintf(fp, " // Following assertions generated from definition section\n");
const char *name = NULL;
for( _defines.reset(); (name = _defines.iter()) != NULL; ) {
const Expr *expr = (const Expr*)_expr[name];
assert( expr != NULL, "name in ExprDict without matching Expr in dictionary");
expr->print_assert(fp);
}
}
static void dumpekey(const void* key) { fprintf(stdout, "%s", (char*) key); }
static void dumpexpr(const void* expr) { fflush(stdout); ((Expr*)expr)->print(); }
void ExprDict::dump() {
_expr.print(dumpekey, dumpexpr);
}
ExprDict::ExprDict( ) : _expr(cmpkey,hashkey), _defines() {
assert( false, "NotImplemented");
}
ExprDict::ExprDict( const ExprDict & ) : _expr(cmpkey,hashkey), _defines() {
assert( false, "NotImplemented");
}
ExprDict &ExprDict::operator =( const ExprDict &rhs) {
assert( false, "NotImplemented");
_expr = rhs._expr;
return *this;
}
bool ExprDict::operator ==(const ExprDict &d) const {
assert( false, "NotImplemented");
return false;
}
Production::Production(const char *result, const char *constraint, const char *valid) {
initialize();
_result = result;
_constraint = constraint;
_valid = valid;
}
void Production::initialize() {
_result = NULL;
_constraint = NULL;
_valid = knownInvalid;
_cost_lb = Expr::get_unknown();
_cost_ub = Expr::get_unknown();
}
void Production::print() {
printf("%s", (_result == NULL ? "NULL" : _result ) );
printf("%s", (_constraint == NULL ? "NULL" : _constraint ) );
printf("%s", (_valid == NULL ? "NULL" : _valid ) );
_cost_lb->print();
_cost_ub->print();
}
void ProductionState::initialize() {
_constraint = noConstraint;
DictI iter( &_production );
const void *x, *y = NULL;
for( ; iter.test(); ++iter) {
x = iter._key;
y = iter._value;
Production *p = (Production*)y;
if( p != NULL ) {
p->initialize();
}
}
}
Production *ProductionState::getProduction(const char *result) {
Production *p = (Production *)_production[result];
if( p == NULL ) {
p = new Production(result, _constraint, knownInvalid);
_production.Insert(result, p);
}
return p;
}
void ProductionState::set_constraint(const char *constraint) {
_constraint = constraint;
}
const char *ProductionState::valid(const char *result) {
return getProduction(result)->valid();
}
void ProductionState::set_valid(const char *result) {
Production *p = getProduction(result);
if( _constraint == noConstraint ) {
p->_valid = knownValid;
} else {
if( p->_valid != knownValid ) {
p->_valid = unknownValid;
}
}
}
Expr *ProductionState::cost_lb(const char *result) {
return getProduction(result)->cost_lb();
}
Expr *ProductionState::cost_ub(const char *result) {
return getProduction(result)->cost_ub();
}
void ProductionState::set_cost_bounds(const char *result, const Expr *cost, bool has_state_check, bool has_cost_check) {
Production *p = getProduction(result);
if( p->_valid == knownInvalid ) {
p->_cost_lb = cost->clone();
p->_cost_ub = cost->clone();
} else if (has_state_check || _constraint != noConstraint) {
if( cost->less_than_or_equal(p->_cost_lb) ) {
p->_cost_lb = cost->clone();
}
if( p->_cost_ub->less_than_or_equal(cost) ) {
p->_cost_ub = cost->clone();
}
} else if (has_cost_check) {
if( cost->less_than_or_equal(p->_cost_lb) ) {
p->_cost_lb = cost->clone();
}
if( cost->less_than_or_equal(p->_cost_ub) ) {
p->_cost_ub = cost->clone();
}
} else {
p->_cost_lb = cost->clone();
p->_cost_ub = cost->clone();
}
}
static void print_key (const void* key) { fprintf(stdout, "%s", (char*) key); }
static void print_production(const void* production) { fflush(stdout); ((Production*)production)->print(); }
void ProductionState::print() {
_production.print(print_key, print_production);
}
C:\hotspot-69087d08d473\src\share\vm/adlc/dict2.cpp
#include "adlc.hpp"
#define MAXID 20
static char initflag = 0; // True after 1st initialization
static char shft[MAXID + 1] = {1,2,3,4,5,6,7,1,2,3,4,5,6,7,1,2,3,4,5,6,7};
static short xsum[MAXID];
class bucket {
public:
int _cnt, _max; // Size of bucket
const void **_keyvals; // Array of keys and values
};
Dict::Dict(CmpKey initcmp, Hash inithash) : _hash(inithash), _cmp(initcmp), _arena(NULL) {
init();
}
Dict::Dict(CmpKey initcmp, Hash inithash, Arena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) {
init();
}
void Dict::init() {
int i;
if (!initflag) { // Not initializated yet?
xsum[0] = (short) ((1 << shft[0]) + 1); // Initialize
for( i = 1; i < MAXID; i++) {
xsum[i] = (short) ((1 << shft[i]) + 1 + xsum[i-1]);
}
initflag = 1; // Never again
}
_size = 16; // Size is a power of 2
_cnt = 0; // Dictionary is empty
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket) * _size);
memset(_bin, 0, sizeof(bucket) * _size);
}
Dict::~Dict() {
}
void Dict::Clear() {
_cnt = 0; // Empty contents
for( int i=0; i<_size; i++ )
_bin[i]._cnt = 0; // Empty buckets, but leave allocated
}
void Dict::doubhash(void) {
int oldsize = _size;
_size <<= 1; // Double in size
_bin = (bucket*)_arena->Arealloc( _bin, sizeof(bucket)*oldsize, sizeof(bucket)*_size );
memset( &_bin[oldsize], 0, oldsize*sizeof(bucket) );
for( int i=0; i < oldsize; i++) { // For complete OLD table do
bucket *b = &_bin[i]; // Handy shortcut for _bin[i]
if( !b->_keyvals ) continue; // Skip empties fast
bucket *nb = &_bin[i+oldsize]; // New bucket shortcut
int j = b->_max; // Trim new bucket to nearest power of 2
while( j > b->_cnt ) j >>= 1; // above old bucket _cnt
if( !j ) j = 1; // Handle zero-sized buckets
nb->_max = j<<1;
nb->_keyvals = (const void**)_arena->Amalloc_4( sizeof(void *)*nb->_max*2 );
int nbcnt = 0;
for( j=0; j<b->_cnt; j++ ) { // Rehash all keys in this bucket
const void *key = b->_keyvals[j+j];
if( (_hash( key ) & (_size-1)) != i ) { // Moving to hi bucket?
nb->_keyvals[nbcnt+nbcnt] = key;
nb->_keyvals[nbcnt+nbcnt+1] = b->_keyvals[j+j+1];
nb->_cnt = nbcnt = nbcnt+1;
b->_cnt--; // Remove key/value from lo bucket
b->_keyvals[j+j ] = b->_keyvals[b->_cnt+b->_cnt ];
b->_keyvals[j+j+1] = b->_keyvals[b->_cnt+b->_cnt+1];
j--; // Hash compacted element also
}
} // End of for all key-value pairs in bucket
} // End of for all buckets
}
Dict::Dict( const Dict &d ) : _size(d._size), _cnt(d._cnt), _hash(d._hash),_cmp(d._cmp), _arena(d._arena) {
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket)*_size);
memcpy( _bin, d._bin, sizeof(bucket)*_size );
for( int i=0; i<_size; i++ ) {
if( !_bin[i]._keyvals ) continue;
_bin[i]._keyvals=(const void**)_arena->Amalloc_4( sizeof(void *)*_bin[i]._max*2);
memcpy( _bin[i]._keyvals, d._bin[i]._keyvals,_bin[i]._cnt*2*sizeof(void*));
}
}
Dict &Dict::operator =( const Dict &d ) {
if( _size < d._size ) { // If must have more buckets
_arena = d._arena;
_bin = (bucket*)_arena->Arealloc( _bin, sizeof(bucket)*_size, sizeof(bucket)*d._size );
memset( &_bin[_size], 0, (d._size-_size)*sizeof(bucket) );
_size = d._size;
}
for( int i=0; i<_size; i++ ) // All buckets are empty
_bin[i]._cnt = 0; // But leave bucket allocations alone
_cnt = d._cnt;
for(int k=0; k<_size; k++ ) {
bucket *b = &d._bin[k]; // Shortcut to source bucket
for( int j=0; j<b->_cnt; j++ )
Insert( b->_keyvals[j+j], b->_keyvals[j+j+1] );
}
return *this;
}
const void *Dict::Insert(const void *key, const void *val) {
int hash = _hash( key ); // Get hash key
int i = hash & (_size-1); // Get hash key, corrected for size
bucket *b = &_bin[i]; // Handy shortcut
for( int j=0; j<b->_cnt; j++ )
if( !_cmp(key,b->_keyvals[j+j]) ) {
const void *prior = b->_keyvals[j+j+1];
b->_keyvals[j+j ] = key; // Insert current key-value
b->_keyvals[j+j+1] = val;
return prior; // Return prior
}
if( ++_cnt > _size ) { // Hash table is full
doubhash(); // Grow whole table if too full
i = hash & (_size-1); // Rehash
b = &_bin[i]; // Handy shortcut
}
if( b->_cnt == b->_max ) { // Must grow bucket?
if( !b->_keyvals ) {
b->_max = 2; // Initial bucket size
b->_keyvals = (const void**)_arena->Amalloc_4( sizeof(void *)*b->_max*2 );
} else {
b->_keyvals = (const void**)_arena->Arealloc( b->_keyvals, sizeof(void *)*b->_max*2, sizeof(void *)*b->_max*4 );
b->_max <<= 1; // Double bucket
}
}
b->_keyvals[b->_cnt+b->_cnt ] = key;
b->_keyvals[b->_cnt+b->_cnt+1] = val;
b->_cnt++;
return NULL; // Nothing found prior
}
const void *Dict::Delete(void *key) {
int i = _hash( key ) & (_size-1); // Get hash key, corrected for size
bucket *b = &_bin[i]; // Handy shortcut
for( int j=0; j<b->_cnt; j++ )
if( !_cmp(key,b->_keyvals[j+j]) ) {
const void *prior = b->_keyvals[j+j+1];
b->_cnt--; // Remove key/value from lo bucket
b->_keyvals[j+j ] = b->_keyvals[b->_cnt+b->_cnt ];
b->_keyvals[j+j+1] = b->_keyvals[b->_cnt+b->_cnt+1];
_cnt--; // One less thing in table
return prior;
}
return NULL;
}
const void *Dict::operator [](const void *key) const {
int i = _hash( key ) & (_size-1); // Get hash key, corrected for size
bucket *b = &_bin[i]; // Handy shortcut
for( int j=0; j<b->_cnt; j++ )
if( !_cmp(key,b->_keyvals[j+j]) )
return b->_keyvals[j+j+1];
return NULL;
}
int Dict::operator ==(const Dict &d2) const {
if( _cnt != d2._cnt ) return 0;
if( _hash != d2._hash ) return 0;
if( _cmp != d2._cmp ) return 0;
for( int i=0; i < _size; i++) { // For complete hash table do
bucket *b = &_bin[i]; // Handy shortcut
if( b->_cnt != d2._bin[i]._cnt ) return 0;
if( memcmp(b->_keyvals, d2._bin[i]._keyvals, b->_cnt*2*sizeof(void*) ) )
return 0; // Key-value pairs must match
}
return 1; // All match, is OK
}
static void printvoid(const void* x) { printf("%p", x); }
void Dict::print() {
print(printvoid, printvoid);
}
void Dict::print(PrintKeyOrValue print_key, PrintKeyOrValue print_value) {
for( int i=0; i < _size; i++) { // For complete hash table do
bucket *b = &_bin[i]; // Handy shortcut
for( int j=0; j<b->_cnt; j++ ) {
print_key( b->_keyvals[j+j ]);
printf(" -> ");
print_value(b->_keyvals[j+j+1]);
printf("\n");
}
}
}
int hashstr(const void *t) {
register char c, k = 0;
register int sum = 0;
register const char *s = (const char *)t;
while (((c = s[k]) != '\0') && (k < MAXID-1)) { // Get characters till nul
c = (char) ((c << 1) + 1); // Characters are always odd!
sum += c + (c << shft[k++]); // Universal hash function
}
assert(k < (MAXID), "Exceeded maximum name length");
return (int)((sum+xsum[k]) >> 1); // Hash key, un-modulo'd table size
}
int hashptr(const void *key) {
#ifdef __TURBOC__
return (int)((intptr_t)key >> 16);
#else // __TURBOC__
return (int)((intptr_t)key >> 2);
#endif
}
int hashkey(const void *key) {
return (int)((intptr_t)key);
}
int cmpstr(const void *k1, const void *k2) {
return strcmp((const char *)k1,(const char *)k2);
}
int cmpkey(const void *key1, const void *key2) {
if (key1 == key2) return 0;
intptr_t delta = (intptr_t)key1 - (intptr_t)key2;
if (delta > 0) return 1;
return -1;
}
void DictI::reset( const Dict *dict ) {
_d = dict; // The dictionary
_i = (int)-1; // Before the first bin
_j = 0; // Nothing left in the current bin
++(*this); // Step to first real value
}
void DictI::operator ++(void) {
if( _j-- ) { // Still working in current bin?
_key = _d->_bin[_i]._keyvals[_j+_j];
_value = _d->_bin[_i]._keyvals[_j+_j+1];
return;
}
while( ++_i < _d->_size ) { // Else scan for non-zero bucket
_j = _d->_bin[_i]._cnt;
if( !_j ) continue;
_j--;
_key = _d->_bin[_i]._keyvals[_j+_j];
_value = _d->_bin[_i]._keyvals[_j+_j+1];
return;
}
_key = _value = NULL;
}
C:\hotspot-69087d08d473\src\share\vm/adlc/dict2.hpp
#ifndef SHARE_VM_ADLC_DICT2_HPP
#define SHARE_VM_ADLC_DICT2_HPP
class Dict;
typedef int (*CmpKey)(const void *key1, const void *key2);
typedef int (*Hash)(const void *key);
typedef void (*PrintKeyOrValue)(const void *key_or_value);
typedef void (*FuncDict)(const void *key, const void *val, Dict *d);
class Dict { // Dictionary structure
private:
class Arena *_arena; // Where to draw storage from
class bucket *_bin; // Hash table is array of buckets
int _size; // Size (# of slots) in hash table
int _cnt; // Number of key-value pairs in hash table
const Hash _hash; // Hashing function
const CmpKey _cmp; // Key comparison function
void doubhash( void ); // Double hash table size
public:
friend class DictI; // Friendly iterator function
Dict( CmpKey cmp, Hash hash );
Dict( CmpKey cmp, Hash hash, Arena *arena );
void init();
~Dict();
Dict( const Dict & ); // Deep-copy guts
Dict &operator =( const Dict & );
void Clear();
int Size(void) const { return _cnt; }
const void *Insert(const void *key, const void *val); // A new key-value
const void *Delete(void *key); // Delete & return old
const void *operator [](const void *key) const; // Do a lookup
int operator ==(const Dict &d) const; // Compare dictionaries for equal
void print();
void print(PrintKeyOrValue print_key, PrintKeyOrValue print_value);
};
int hashstr(const void *s); // Nice string hash
int hashptr(const void *key);
int hashkey(const void *key);
int cmpstr(const void *k1, const void *k2);
int cmpkey(const void *key1, const void *key2);
class DictI {
private:
const Dict *_d; // Dictionary being iterated over
int _i; // Counter over the bins
int _j; // Counter inside each bin
public:
const void *_key, *_value; // Easy access to the key-value pair
DictI( const Dict *d ) {reset(d);}; // Create a new iterator
void reset( const Dict *dict ); // Reset existing iterator
void operator ++(void); // Increment iterator
int test(void) { return _i<_d->_size;} // Test for end of iteration
};
#endif // SHARE_VM_ADLC_DICT2_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/filebuff.cpp
#include "adlc.hpp"
using namespace std;
FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(archDesc) {
_err = fseek(_fp->_fp, 0, SEEK_END); // Seek to end of file
if (_err) {
file_error(SEMERR, 0, "File seek error reading input file");
exit(1); // Exit on seek error
}
_filepos = ftell(_fp->_fp); // Find offset of end of file
_bufferSize = _filepos + 5; // Filepos points to last char, so add padding
_err = fseek(_fp->_fp, 0, SEEK_SET); // Reset to beginning of file
if (_err) {
file_error(SEMERR, 0, "File seek error reading input file\n");
exit(1); // Exit on seek error
}
_filepos = ftell(_fp->_fp); // Reset current file position
_linenum = 0;
_bigbuf = new char[_bufferSize]; // Create buffer to hold text for parser
if( !_bigbuf ) {
file_error(SEMERR, 0, "Buffer allocation failed\n");
exit(1); // Exit on allocation failure
}
_buf = _bigbuf+1; // Skip sentinel
_bufmax = _buf; // Buffer is empty
_bufeol = _bigbuf; // _bufeol points at sentinel
_filepos = -1; // filepos is in sync with _bufeol
_bufoff = _offset = 0L; // Offset at file start
_bufmax += fread(_buf, 1, _bufferSize-2, _fp->_fp); // Fill buffer & set end value
if (_bufmax == _buf) {
file_error(SEMERR, 0, "File read error, no input read\n");
exit(1); // Exit on read error
}
}
FileBuff::~FileBuff() {
delete _bigbuf;
}
char *FileBuff::get_line(void) {
char *retval;
if (_bufeol >= _bufmax) return NULL;
_linenum++;
retval = ++_bufeol; // return character following end of previous line
if (*retval == '\0') return NULL; // Check for EOF sentinel
for(_filepos++; *_bufeol != '\n'; _bufeol++)
_filepos++; // keep filepos in sync with _bufeol
return retval;
}
void FileBuff::file_error(int flag, int linenum, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
switch (flag) {
case 0: _AD._warnings += _AD.emit_msg(0, flag, linenum, fmt, args);
case 1: _AD._syntax_errs += _AD.emit_msg(0, flag, linenum, fmt, args);
case 2: _AD._semantic_errs += _AD.emit_msg(0, flag, linenum, fmt, args);
default: assert(0, ""); break;
}
va_end(args);
_AD._no_output = 1;
}
C:\hotspot-69087d08d473\src\share\vm/adlc/filebuff.hpp
#ifndef SHARE_VM_ADLC_FILEBUFF_HPP
#define SHARE_VM_ADLC_FILEBUFF_HPP
#include <iostream>
using namespace std;
class BufferedFile {
public:
const char *_name;
FILE *_fp;
inline BufferedFile() { _name = NULL; _fp = NULL; };
inline ~BufferedFile() {};
};
class ArchDesc;
class FileBuff {
private:
long _bufferSize; // Size of text holding buffer.
long _offset; // Expected filepointer offset.
long _bufoff; // Start of buffer file offset
char *_buf; // The buffer itself.
char *_bigbuf; // The buffer plus sentinels; actual heap area
char *_bufmax; // A pointer to the buffer end sentinel
char *_bufeol; // A pointer to the last complete line end
int _err; // Error flag for file seek/read operations
long _filepos; // Current offset from start of file
int _linenum;
ArchDesc& _AD; // Reference to Architecture Description
void file_error(int flag, int linenum, const char *fmt, ...);
public:
const BufferedFile *_fp; // File to be buffered
FileBuff(BufferedFile *fp, ArchDesc& archDesc); // Constructor
~FileBuff(); // Destructor
char *get_line(void);
int linenum() const { return _linenum; }
void set_linenum(int line) { _linenum = line; }
long getoff(const char* s) { return _bufoff + (long)(s - _buf); }
};
#endif // SHARE_VM_ADLC_FILEBUFF_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/forms.cpp
#include "adlc.hpp"
Arena *Form::arena = Form::generate_arena(); // = Form::generate_arena();
Arena *Form::generate_arena() {
return (new Arena);
}
const char *NameList::_signal = "$$SIGNAL$$";
const char *NameList::_signal2 = "$$SIGNAL2$$";
const char *NameList::_signal3 = "$$SIGNAL3$$";
NameList::NameList() : _cur(0), _max(4), _iter(0), _justReset(true) {
_names = (const char**)malloc(_max*sizeof(char*));
}
NameList::~NameList() {
}
void NameList::addName(const char *name) {
if (_cur == _max) _names =(const char**)realloc(_names,(_max *=2)*sizeof(char*));
_names[_cur++] = name;
}
void NameList::add_signal() {
addName( _signal );
}
void NameList::clear() {
_cur = 0;
_iter = 0;
_justReset = true;
}
int NameList::count() const { return _cur; }
void NameList::reset() { _iter = 0; _justReset = true;}
const char *NameList::iter() {
if (_justReset) {_justReset=false; return (_iter < _cur ? _names[_iter] : NULL);}
else return (_iter <_cur-1 ? _names[++_iter] : NULL);
}
const char *NameList::current() { return (_iter < _cur ? _names[_iter] : NULL); }
const char *NameList::peek(int skip) { return (_iter + skip < _cur ? _names[_iter + skip] : NULL); }
bool NameList::current_is_signal() {
const char *entry = current();
return is_signal(entry);
}
bool NameList::is_signal(const char *entry) {
return ( (strcmp(entry,NameList::_signal) == 0) ? true : false);
}
bool NameList::search(const char *name) {
const char *entry;
for(reset(); (entry = iter()) != NULL; ) {
if(!strcmp(entry,name)) return true;
}
return false;
}
int NameList::index(const char *name) {
int cnt = 0;
const char *entry;
for(reset(); (entry = iter()) != NULL; ) {
if(!strcmp(entry,name)) return cnt;
cnt++;
}
return Not_in_list;
}
const char *NameList::name(intptr_t index) {
return ( index < _cur ? _names[index] : NULL);
}
void NameList::dump() { output(stderr); }
void NameList::output(FILE *fp) {
fprintf(fp, "\n");
const char *name = NULL;
int iter = 0;
bool justReset = true;
while( ( name = (justReset ?
(justReset=false, (iter < _cur ? _names[iter] : NULL)) :
(iter < _cur-1 ? _names[++iter] : NULL)) )
!= NULL ) {
fprintf( fp, " %s,\n", name);
}
fprintf(fp, "\n");
}
NameAndList::NameAndList(char *name) : _name(name) {
}
NameAndList::~NameAndList() {
}
void NameAndList::add_entry(const char *entry) {
_list.addName(entry);
}
const char *NameAndList::name() const { return _name; }
void NameAndList::reset() { _list.reset(); }
const char *NameAndList::iter() { return _list.iter(); }
const char *NameAndList::operator[](int index) {
assert( index >= 0, "Internal Error(): index less than 0.");
_list.reset();
const char *entry = _list.iter();
for ( int position = 0; position != index; ++position ) {
entry = _list.iter();
}
return entry;
}
void NameAndList::dump() { output(stderr); }
void NameAndList::output(FILE *fp) {
fprintf(fp, "\n");
fprintf(fp, "Name == %s", (_name ? _name : "") );
const char *name;
fprintf(fp, " (");
for (reset(); (name = iter()) != NULL;) {
fprintf(fp, " %s,\n", name);
}
fprintf(fp, ")");
fprintf(fp, "\n");
}
OpClassForm *Form::is_opclass() const {
return NULL;
}
OperandForm *Form::is_operand() const {
return NULL;
}
InstructForm *Form::is_instruction() const {
return NULL;
}
MachNodeForm *Form::is_machnode() const {
return NULL;
}
AttributeForm *Form::is_attribute() const {
return NULL;
}
Effect *Form::is_effect() const {
return NULL;
}
ResourceForm *Form::is_resource() const {
return NULL;
}
PipeClassForm *Form::is_pipeclass() const {
return NULL;
}
Form::DataType Form::ideal_to_const_type(const char *name) const {
if( name == NULL ) { return Form::none; }
if (strcmp(name,"ConI")==0) return Form::idealI;
if (strcmp(name,"ConP")==0) return Form::idealP;
if (strcmp(name,"ConN")==0) return Form::idealN;
if (strcmp(name,"ConNKlass")==0) return Form::idealNKlass;
if (strcmp(name,"ConL")==0) return Form::idealL;
if (strcmp(name,"ConF")==0) return Form::idealF;
if (strcmp(name,"ConD")==0) return Form::idealD;
if (strcmp(name,"Bool")==0) return Form::idealI;
return Form::none;
}
Form::DataType Form::ideal_to_sReg_type(const char *name) const {
if( name == NULL ) { return Form::none; }
if (strcmp(name,"sRegI")==0) return Form::idealI;
if (strcmp(name,"sRegP")==0) return Form::idealP;
if (strcmp(name,"sRegF")==0) return Form::idealF;
if (strcmp(name,"sRegD")==0) return Form::idealD;
if (strcmp(name,"sRegL")==0) return Form::idealL;
return Form::none;
}
Form::DataType Form::ideal_to_Reg_type(const char *name) const {
if( name == NULL ) { return Form::none; }
if (strcmp(name,"RegI")==0) return Form::idealI;
if (strcmp(name,"RegP")==0) return Form::idealP;
if (strcmp(name,"RegF")==0) return Form::idealF;
if (strcmp(name,"RegD")==0) return Form::idealD;
if (strcmp(name,"RegL")==0) return Form::idealL;
return Form::none;
}
Form::DataType Form::is_load_from_memory(const char *opType) const {
if( strcmp(opType,"LoadB")==0 ) return Form::idealB;
if( strcmp(opType,"LoadUB")==0 ) return Form::idealB;
if( strcmp(opType,"LoadUS")==0 ) return Form::idealC;
if( strcmp(opType,"LoadD")==0 ) return Form::idealD;
if( strcmp(opType,"LoadD_unaligned")==0 ) return Form::idealD;
if( strcmp(opType,"LoadF")==0 ) return Form::idealF;
if( strcmp(opType,"LoadI")==0 ) return Form::idealI;
if( strcmp(opType,"LoadKlass")==0 ) return Form::idealP;
if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealNKlass;
if( strcmp(opType,"LoadL")==0 ) return Form::idealL;
if( strcmp(opType,"LoadL_unaligned")==0 ) return Form::idealL;
if( strcmp(opType,"LoadPLocked")==0 ) return Form::idealP;
if( strcmp(opType,"LoadP")==0 ) return Form::idealP;
if( strcmp(opType,"LoadN")==0 ) return Form::idealN;
if( strcmp(opType,"LoadRange")==0 ) return Form::idealI;
if( strcmp(opType,"LoadS")==0 ) return Form::idealS;
if( strcmp(opType,"LoadVector")==0 ) return Form::idealV;
assert( strcmp(opType,"Load") != 0, "Must type Loads" );
return Form::none;
}
Form::DataType Form::is_store_to_memory(const char *opType) const {
if( strcmp(opType,"StoreB")==0) return Form::idealB;
if( strcmp(opType,"StoreCM")==0) return Form::idealB;
if( strcmp(opType,"StoreC")==0) return Form::idealC;
if( strcmp(opType,"StoreD")==0) return Form::idealD;
if( strcmp(opType,"StoreF")==0) return Form::idealF;
if( strcmp(opType,"StoreI")==0) return Form::idealI;
if( strcmp(opType,"StoreL")==0) return Form::idealL;
if( strcmp(opType,"StoreP")==0) return Form::idealP;
if( strcmp(opType,"StoreN")==0) return Form::idealN;
if( strcmp(opType,"StoreNKlass")==0) return Form::idealNKlass;
if( strcmp(opType,"StoreVector")==0 ) return Form::idealV;
assert( strcmp(opType,"Store") != 0, "Must type Stores" );
return Form::none;
}
Form::InterfaceType Form::interface_type(FormDict &globals) const {
return Form::no_interface;
}
FormList::~FormList() {
};
FormDict::FormDict( CmpKey cmp, Hash hash, Arena *arena )
: _form(cmp, hash, arena) {
}
FormDict::~FormDict() {
}
int FormDict::Size(void) const {
return _form.Size();
}
const Form *FormDict::Insert(const char *name, Form *form) {
return (Form*)_form.Insert((void*)name, (void*)form);
}
const Form *FormDict::operator [](const char *name) const {
return (Form*)_form[name];
}
FormDict::FormDict( ) : _form(cmpkey,hashkey) {
assert( false, "NotImplemented");
}
FormDict::FormDict( const FormDict & fd) : _form(fd._form) {
}
FormDict &FormDict::operator =( const FormDict &rhs) {
assert( false, "NotImplemented");
_form = rhs._form;
return *this;
}
bool FormDict::operator ==(const FormDict &d) const {
assert( false, "NotImplemented");
return false;
}
static void dumpkey (const void* key) { fprintf(stdout, "%s", (char*) key); }
static void dumpform(const void* form) { fflush(stdout); ((Form*)form)->dump(); }
void FormDict::dump() {
_form.print(dumpkey, dumpform);
}
SourceForm::SourceForm(char* code) : _code(code) { }; // Constructor
SourceForm::~SourceForm() {
}
void SourceForm::dump() { // Debug printer
output(stderr);
}
void SourceForm::output(FILE *fp) {
fprintf(fp,"\n//%s\n%s\n",classname(),(_code?_code:""));
}
C:\hotspot-69087d08d473\src\share\vm/adlc/forms.hpp
#ifndef SHARE_VM_ADLC_FORMS_HPP
#define SHARE_VM_ADLC_FORMS_HPP
#define TRUE 1
#define FALSE 0
#define INS_ATTR 0
#define OP_ATTR 1
class Form;
class InstructForm;
class MachNodeForm;
class OperandForm;
class OpClassForm;
class AttributeForm;
class RegisterForm;
class PipelineForm;
class SourceForm;
class EncodeForm;
class Component;
class Constraint;
class Predicate;
class MatchRule;
class Attribute;
class Effect;
class ExpandRule;
class RewriteRule;
class ConstructRule;
class FormatRule;
class Peephole;
class EncClass;
class Interface;
class RegInterface;
class ConstInterface;
class MemInterface;
class CondInterface;
class Opcode;
class InsEncode;
class RegDef;
class RegClass;
class CodeSnippetRegClass;
class ConditionalRegClass;
class AllocClass;
class ResourceForm;
class PipeClassForm;
class PeepMatch;
class PeepConstraint;
class PeepReplace;
class MatchList;
class ArchDesc;
class FormDict {
private:
Dict _form; // map names, char*, to their Form* or NULL
FormDict( );
FormDict &operator =( const FormDict & );
bool operator ==(const FormDict &d) const; // Compare dictionaries for equal
public:
FormDict( CmpKey cmp, Hash hash, Arena *arena );
FormDict( const FormDict & fd ); // Deep-copy guts
~FormDict();
int Size(void) const;
const Form *Insert(const char *name, Form *form); // A new key-value
const Form *operator [](const char *name) const; // Do a lookup
void dump();
};
class Form {
public:
static Arena *arena; // arena used by forms
private:
static Arena *generate_arena(); // allocate arena used by forms
protected:
int _ftype; // Indicator for derived class type
public:
Form *_next; // Next pointer for form lists
int _linenum; // Line number for debugging
virtual OpClassForm *is_opclass() const;
virtual OperandForm *is_operand() const;
virtual InstructForm *is_instruction() const;
virtual MachNodeForm *is_machnode() const;
virtual AttributeForm *is_attribute() const;
virtual Effect *is_effect() const;
virtual ResourceForm *is_resource() const;
virtual PipeClassForm *is_pipeclass() const;
virtual bool is_cisc_reg(FormDict &globals) const { return false; }
virtual bool is_cisc_mem(FormDict &globals) const { return false; }
Form(int formType=0, int line=0)
: _next(NULL), _linenum(line), _ftype(formType) { };
virtual ~Form() {};
virtual bool ideal_only() const {
assert(0,"Check of ideal status on non-instruction/operand form.\n");
return FALSE;
}
virtual bool verify() { return true; }
virtual void dump() { output(stderr); } // Debug printer
virtual void output(FILE *fp) { fprintf(fp,"Form Output"); }
public:
enum DataType {
none = 0, // Not a simple type
idealI = 1, // Integer type
idealP = 2, // Pointer types, oop(s)
idealL = 3, // Long type
idealF = 4, // Float type
idealD = 5, // Double type
idealB = 6, // Byte type
idealC = 7, // Char type
idealS = 8, // String type
idealN = 9, // Narrow oop types
idealNKlass = 10, // Narrow klass types
idealV = 11 // Vector type
};
Form::DataType ideal_to_const_type(const char *ideal_type_name) const;
Form::DataType ideal_to_sReg_type(const char *name) const;
Form::DataType ideal_to_Reg_type(const char *name) const;
Form::DataType is_load_from_memory(const char *opType) const;
Form::DataType is_store_to_memory(const char *opType) const;
enum CallType {
invalid_type = 0, // invalid call type
JAVA_STATIC = 1, // monomorphic entry
JAVA_DYNAMIC = 2, // possibly megamorphic, inline cache call
JAVA_COMPILED = 3, // callee will be compiled java
JAVA_INTERP = 4, // callee will be executed by interpreter
JAVA_NATIVE = 5, // native entrypoint
JAVA_RUNTIME = 6, // runtime entrypoint
JAVA_LEAF = 7 // calling leaf
};
enum InterfaceType {
no_interface = 0, // unknown or inconsistent interface type
constant_interface = 1, // interface to constants
register_interface = 2, // interface to registers
memory_interface = 3, // interface to memory
conditional_interface = 4 // interface for condition codes
};
virtual Form::InterfaceType interface_type(FormDict &globals) const;
enum CiscSpillInfo {
Not_cisc_spillable = AdlcVMDeps::Not_cisc_spillable,
Maybe_cisc_spillable = 0,
Is_cisc_spillable = 1
};
enum {
INS,
OPER,
OPCLASS,
SRC,
ADEF,
REG,
PIPE,
CNST,
PRED,
ATTR,
MAT,
ENC,
FOR,
EXP,
REW,
EFF,
RDEF,
RCL,
ACL,
RES,
PCL,
PDEF,
REGL,
RESL,
STAL,
COMP,
PEEP,
RESO
};
};
class FormList {
private:
Form *_root;
Form *_tail;
Form *_cur;
int _justReset; // Set immediately after reset
Form *_cur2; // Nested iterator
int _justReset2;
public:
void addForm(Form * entry) {
if (_tail==NULL) { _root = _tail = _cur = entry;}
else { _tail->_next = entry; _tail = entry;}
};
Form * current() { return _cur; };
Form * iter() { if (_justReset) _justReset = 0;
else if (_cur) _cur = _cur->_next;
return _cur;};
void reset() { if (_root) {_cur = _root; _justReset = 1;} };
Form * current2(){ return _cur2; };
Form * iter2() { if (_justReset2) _justReset2 = 0;
else if (_cur2) _cur2 = _cur2->_next;
return _cur2;};
void reset2() { if (_root) {_cur2 = _root; _justReset2 = 1;} };
int count() {
int count = 0; reset();
for( Form *cur; (cur = iter()) != NULL; ) { ++count; };
return count;
}
void dump() {
reset();
Form *cur;
for(; (cur = iter()) != NULL; ) {
cur->dump();
};
}
bool verify() {
bool verified = true;
reset();
Form *cur;
for(; (cur = iter()) != NULL; ) {
if ( ! cur->verify() ) verified = false;
};
return verified;
}
void output(FILE* fp) {
reset();
Form *cur;
for( ; (cur = iter()) != NULL; ) {
cur->output(fp);
};
}
FormList() { _justReset = 1; _justReset2 = 1; _root = NULL; _tail = NULL; _cur = NULL; _cur2 = NULL;};
~FormList();
};
class NameList {
friend class PreserveIter;
private:
int _cur; // Insert next entry here; count of entries
int _max; // Number of spaces allocated
const char **_names; // Array of names
protected:
int _iter; // position during iteration
bool _justReset; // Set immediately after reset
public:
static const char *_signal; // reserved user-defined string
static const char *_signal2; // reserved user-defined string
static const char *_signal3; // reserved user-defined string
enum { Not_in_list = -1 };
void addName(const char *name);
void add_signal();
void clear(); // Remove all entries
int count() const;
void reset(); // Reset iteration
const char *iter(); // after reset(), first element : else next
const char *current(); // return current element in iteration.
const char *peek(int skip = 1); // returns element + skip in iteration if there is one
bool current_is_signal(); // Return 'true' if current entry is signal
bool is_signal(const char *entry); // Return true if entry is a signal
bool search(const char *); // Search for a name in the list
int index(const char *); // Return index of name in list
const char *name (intptr_t index);// Return name at index in list
void dump(); // output to stderr
void output(FILE *fp); // Output list of names to 'fp'
NameList();
~NameList();
};
class PreserveIter {
private:
NameList* _list;
int _iter;
bool _justReset;
public:
PreserveIter(NameList* nl) {
_list = nl;
_iter = _list->_iter;
_justReset = _list->_justReset;
}
~PreserveIter() {
_list->_iter = _iter;
_list->_justReset = _justReset;
}
};
class NameAndList {
private:
const char *_name;
NameList _list;
public:
NameAndList(char *name);
~NameAndList();
void add_entry(const char *entry);
const char *name() const;
void reset();
const char *iter();
int count() { return _list.count(); }
const char *operator[](int index);
void dump(); // output to stderr
void output(FILE *fp); // Output list of names to 'fp'
};
class ComponentList : private NameList {
private:
int _matchcnt; // Count of match rule operands
public:
void operator delete( void *ptr ) {}
void insert(Component *component, bool mflag);
void insert(const char *name, const char *opType, int usedef, bool mflag);
int count();
int match_count() { return _matchcnt; } // Get count of match rule opers
Component *iter(); // after reset(), first element : else next
Component *match_iter(); // after reset(), first element : else next
Component *post_match_iter(); // after reset(), first element : else next
void reset(); // Reset iteration
Component *current(); // return current element in iteration.
Component *operator[](int position);
Component *at(int position) { return (*this)[position]; }
const Component *search(const char *name);
int num_operands();
int operand_position(const char *name, int usedef, Form *fm);
int operand_position(const char *name);
int operand_position_format(const char *name, Form *fm);
int label_position();
int method_position();
void dump(); // output to stderr
void output(FILE *fp); // Output list of names to 'fp'
ComponentList();
~ComponentList();
};
class SourceForm : public Form {
private:
public:
char *_code; // Buffer for storing code text
SourceForm(char* code);
~SourceForm();
virtual const char* classname() { return "SourceForm"; }
void dump(); // Debug printer
void output(FILE *fp); // Write output files
};
class HeaderForm : public SourceForm {
public:
HeaderForm(char* code) : SourceForm(code) { }
virtual const char* classname() { return "HeaderForm"; }
};
class PreHeaderForm : public SourceForm {
public:
PreHeaderForm(char* code) : SourceForm(code) { }
virtual const char* classname() { return "PreHeaderForm"; }
};
#define STRING_BUFFER_LENGTH 2048
class Expr {
public:
enum {
Zero = 0,
Max = 0x7fffffff
};
const char *_external_name; // if !NULL, then print this instead of _expr
const char *_expr;
int _min_value;
int _max_value;
Expr();
Expr(const char *cost);
Expr(const char *name, const char *expression, int min_value, int max_value);
Expr *clone() const;
bool is_unknown() const { return (this == Expr::get_unknown()); }
bool is_zero() const { return (_min_value == Expr::Zero && _max_value == Expr::Zero); }
bool less_than_or_equal(const Expr *c) const { return (_max_value <= c->_min_value); }
void add(const Expr *c);
void add(const char *c);
void add(const char *c, ArchDesc &AD); // check if 'c' is defined in <arch>.ad
void set_external_name(const char *name) { _external_name = name; }
const char *as_string() const { return (_external_name != NULL ? _external_name : _expr); }
void print() const;
void print_define(FILE *fp) const;
void print_assert(FILE *fp) const;
static Expr *get_unknown(); // Returns pointer to shared unknown cost instance
static char *buffer() { return &external_buffer[0]; }
static bool init_buffers(); // Fill buffers with 0
static bool check_buffers(); // if buffer use may have overflowed, assert
private:
static Expr *_unknown_expr;
static char string_buffer[STRING_BUFFER_LENGTH];
static char external_buffer[STRING_BUFFER_LENGTH];
static bool _init_buffers;
const char *compute_expr(const Expr *c1, const Expr *c2); // cost as string after adding 'c1' and 'c2'
int compute_min (const Expr *c1, const Expr *c2); // minimum after adding 'c1' and 'c2'
int compute_max (const Expr *c1, const Expr *c2); // maximum after adding 'c1' and 'c2'
const char *compute_external(const Expr *c1, const Expr *c2); // external name after adding 'c1' and 'c2'
};
class ExprDict {
private:
Dict _expr; // map names, char*, to their Expr* or NULL
NameList _defines; // record the order of definitions entered with define call
ExprDict( );
ExprDict( const ExprDict & ); // Deep-copy guts
ExprDict &operator =( const ExprDict & );
bool operator ==(const ExprDict &d) const; // Compare dictionaries for equal
public:
ExprDict( CmpKey cmp, Hash hash, Arena *arena );
~ExprDict();
int Size(void) const;
const Expr *define(const char *name, Expr *expr);
const Expr *Insert(const char *name, Expr *expr); // A new key-value
const Expr *operator [](const char *name) const; // Do a lookup
void print_defines(FILE *fp);
void print_asserts(FILE *fp);
void dump();
};
#endif // SHARE_VM_ADLC_FORMS_HPP
C:\hotspot-69087d08d473\src\share\vm/adlc/formsopt.cpp
#include "adlc.hpp"
int RegisterForm::_reg_ctr = 0;
RegisterForm::RegisterForm()
: _regDef(cmpstr,hashstr, Form::arena),
_regClass(cmpstr,hashstr, Form::arena),
_allocClass(cmpstr,hashstr, Form::arena) {
}
RegisterForm::~RegisterForm() {
}
void RegisterForm::addRegDef(char *name, char *callingConv, char *c_conv,
char *idealtype, char *encoding, char* concrete) {
RegDef *regDef = new RegDef(name, callingConv, c_conv, idealtype, encoding, concrete);
_rdefs.addName(name);
_regDef.Insert(name,regDef);
}
template <typename T>
T* RegisterForm::addRegClass(const char* className) {
T* regClass = new T(className);
_rclasses.addName(className);
_regClass.Insert(className, regClass);
return regClass;
}
template RegClass* RegisterForm::addRegClass<RegClass>(const char* className);
template CodeSnippetRegClass* RegisterForm::addRegClass<CodeSnippetRegClass>(const char* className);
template ConditionalRegClass* RegisterForm::addRegClass<ConditionalRegClass>(const char* className);
AllocClass *RegisterForm::addAllocClass(char *className) {
AllocClass *allocClass = new AllocClass(className);
_aclasses.addName(className);
_allocClass.Insert(className,allocClass);
return allocClass;
}
void RegisterForm::addSpillRegClass() {
_reg_ctr = (_reg_ctr+7) & ~7;
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);
}
void RegisterForm::reset_RegDefs() {
_current_ac = NULL;
_aclasses.reset();
}
RegDef *RegisterForm::iter_RegDefs() {
if ( _current_ac == NULL ) {
const char *ac_name = _aclasses.iter();
if( ac_name == NULL ) return NULL; // No more allocation classes
_current_ac = (AllocClass*)_allocClass[ac_name];
_current_ac->_regDefs.reset();
assert( _current_ac != NULL, "Name must match an allocation class");
}
const char *rd_name = _current_ac->_regDefs.iter();
if( rd_name == NULL ) {
_current_ac = NULL;
return iter_RegDefs();
}
RegDef *reg_def = (RegDef*)_current_ac->_regDef[rd_name];
assert( reg_def != NULL, "Name must match a register definition");
return reg_def;
}
RegDef *RegisterForm::getRegDef(const char *regName) {
RegDef *regDef = (RegDef*)_regDef[regName];
return regDef;
}
RegClass *RegisterForm::getRegClass(const char *className) {
RegClass *regClass = (RegClass*)_regClass[className];
return regClass;
}
bool RegisterForm::verify() {
bool valid = true;
const char *rc_name = NULL;
_rclasses.reset();
while ( (rc_name = _rclasses.iter()) != NULL ) {
RegClass *reg_class = getRegClass(rc_name);
assert( reg_class != NULL, "InternalError() no matching register class");
} // end of RegClasses
RegDef *reg_def = NULL;
reset_RegDefs();
uint num_register_zero = 0;
while ( (reg_def = iter_RegDefs()) != NULL ) {
if( reg_def->register_num() == 0 ) ++num_register_zero;
}
if( num_register_zero > 1 ) {
fprintf(stderr,
"ERROR: More than one register has been assigned register-number 0.\n"
"Probably because a register has not been entered into an allocation class.\n");
}
return valid;
}
int RegisterForm::RegMask_Size() {
int words_for_regs = (_reg_ctr + 31)>>5;
return (words_for_regs + 3 + 1) & ~1;
}
void RegisterForm::dump() { // Debug printer
output(stderr);
}
void RegisterForm::output(FILE *fp) { // Write info to output files
const char *name;
fprintf(fp,"\n");
fprintf(fp,"-------------------- Dump RegisterForm --------------------\n");
for(_rdefs.reset(); (name = _rdefs.iter()) != NULL;) {
((RegDef*)_regDef[name])->output(fp);
}
fprintf(fp,"\n");
for (_rclasses.reset(); (name = _rclasses.iter()) != NULL;) {
((RegClass*)_regClass[name])->output(fp);
}
fprintf(fp,"\n");
for (_aclasses.reset(); (name = _aclasses.iter()) != NULL;) {
((AllocClass*)_allocClass[name])->output(fp);
}
fprintf(fp,"-------------------- end RegisterForm --------------------\n");
}
RegDef::RegDef(char *regname, char *callconv, char *c_conv, char * idealtype, char * encode, char * concrete)
: _regname(regname), _callconv(callconv), _c_conv(c_conv),
_idealtype(idealtype),
_register_encode(encode),
_concrete(concrete),
_register_num(0) {
}
RegDef::~RegDef() { // Destructor
}
void RegDef::set_register_num(uint32 register_num) {
_register_num = register_num;
}
const char* RegDef::register_encode() const {
return _register_encode;
}
uint32 RegDef::register_num() const {
return _register_num;
}
void RegDef::dump() {
output(stderr);
}
void RegDef::output(FILE *fp) { // Write info to output files
fprintf(fp,"RegDef: %s (%s) encode as %s using number %d\n",
_regname, (_callconv?_callconv:""), _register_encode, _register_num);
fprintf(fp,"\n");
}
RegClass::RegClass(const char* classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr, hashstr, Form::arena) {
}
RegClass::~RegClass() {
delete _classid;
}
void RegClass::addReg(RegDef *regDef) {
_regDefs.addName(regDef->_regname);
_regDef.Insert((void*)regDef->_regname, regDef);
}
uint RegClass::size() const {
return _regDef.Size();
}
const RegDef *RegClass::get_RegDef(const char *rd_name) const {
return (const RegDef*)_regDef[rd_name];
}
void RegClass::reset() {
_regDefs.reset();
}
const char *RegClass::rd_name_iter() {
return _regDefs.iter();
}
RegDef *RegClass::RegDef_iter() {
const char *rd_name = rd_name_iter();
RegDef *reg_def = rd_name ? (RegDef*)_regDef[rd_name] : NULL;
return reg_def;
}
const RegDef* RegClass::find_first_elem() {
const RegDef* first = NULL;
const RegDef* def = NULL;
reset();
while ((def = RegDef_iter()) != NULL) {
if (first == NULL || def->register_num() < first->register_num()) {
first = def;
}
}
assert(first != NULL, "empty mask?");
return first;;
}
int RegClass::regs_in_word( int wordnum, bool stack_also ) {
int word = 0;
const char *name;
for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) {
int rnum = ((RegDef*)_regDef[name])->register_num();
if( (rnum >> 5) == wordnum )
word |= (1 << (rnum & 31));
}
if( stack_also ) {
for( int i = 0; i < 32; i++ )
if( wordnum*32+i >= RegisterForm::_reg_ctr )
word |= (1 << i);
}
return word;
}
void RegClass::dump() {
output(stderr);
}
void RegClass::output(FILE *fp) { // Write info to output files
fprintf(fp,"RegClass: %s\n",_classid);
const char *name;
for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) {
((RegDef*)_regDef[name])->output(fp);
}
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(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(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(char *classid) : _classid(classid), _regDef(cmpstr,hashstr, Form::arena) {
}
void AllocClass::addReg(RegDef *regDef) {
assert( regDef != NULL, "Can not add a NULL to an allocation class");
regDef->set_register_num( RegisterForm::_reg_ctr++ );
_regDefs.addName(regDef->_regname);
_regDef.Insert((void*)regDef->_regname, regDef);
}
void AllocClass::dump() {
output(stderr);
}
void AllocClass::output(FILE *fp) { // Write info to output files
fprintf(fp,"AllocClass: %s \n",_classid);
const char *name;
for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) {
((RegDef*)_regDef[name])->output(fp);
}
fprintf(fp,"--- done with entries for alloc_class %s\n\n",_classid);
}
FrameForm::FrameForm() {
_frame_pointer = NULL;
_c_frame_pointer = NULL;
_alignment = NULL;
_return_addr = NULL;
_c_return_addr = NULL;
_in_preserve_slots = NULL;
_varargs_C_out_slots_killed = NULL;
_calling_convention = NULL;
_c_calling_convention = NULL;
_return_value = NULL;
_c_return_value = NULL;
_interpreter_frame_pointer_reg = NULL;
}
FrameForm::~FrameForm() {
}
void FrameForm::dump() {
output(stderr);
}
void FrameForm::output(FILE *fp) { // Write info to output files
fprintf(fp,"\nFrame:\n");
}
PipelineForm::PipelineForm()
: _reslist ()
, _resdict (cmpstr, hashstr, Form::arena)
, _classdict (cmpstr, hashstr, Form::arena)
, _rescount (0)
, _maxcycleused (0)
, _stages ()
, _stagecnt (0)
, _classlist ()
, _classcnt (0)
, _noplist ()
, _nopcnt (0)
, _variableSizeInstrs (false)
, _branchHasDelaySlot (false)
, _maxInstrsPerBundle (0)
, _maxBundlesPerCycle (1)
, _instrUnitSize (0)
, _bundleUnitSize (0)
, _instrFetchUnitSize (0)
, _instrFetchUnits (0) {
}
PipelineForm::~PipelineForm() {
}
void PipelineForm::dump() {
output(stderr);
}
void PipelineForm::output(FILE *fp) { // Write info to output files
const char *res;
const char *stage;
const char *cls;
const char *nop;
int count = 0;
fprintf(fp,"\nPipeline:");
if (_variableSizeInstrs)
if (_instrUnitSize > 0)
fprintf(fp," variable-sized instructions in %d byte units", _instrUnitSize);
else
fprintf(fp," variable-sized instructions");
else
if (_instrUnitSize > 0)
fprintf(fp," fixed-sized instructions of %d bytes", _instrUnitSize);
else if (_bundleUnitSize > 0)
fprintf(fp," fixed-sized bundles of %d bytes", _bundleUnitSize);
else
fprintf(fp," fixed-sized instructions");
if (_branchHasDelaySlot)
fprintf(fp,", branch has delay slot");
if (_maxInstrsPerBundle > 0)
fprintf(fp,", max of %d instruction%s in parallel",
_maxInstrsPerBundle, _maxInstrsPerBundle > 1 ? "s" : "");
if (_maxBundlesPerCycle > 0)
fprintf(fp,", max of %d bundle%s in parallel",
_maxBundlesPerCycle, _maxBundlesPerCycle > 1 ? "s" : "");
if (_instrFetchUnitSize > 0 && _instrFetchUnits)
fprintf(fp, ", fetch %d x % d bytes per cycle", _instrFetchUnits, _instrFetchUnitSize);
fprintf(fp,"\nResource:");
for ( _reslist.reset(); (res = _reslist.iter()) != NULL; )
fprintf(fp," %s(0x%08x)", res, _resdict[res]->is_resource()->mask());
fprintf(fp,"\n");
fprintf(fp,"\nDescription:\n");
for ( _stages.reset(); (stage = _stages.iter()) != NULL; )
fprintf(fp," %s(%d)", stage, count++);
fprintf(fp,"\n");
fprintf(fp,"\nClasses:\n");
for ( _classlist.reset(); (cls = _classlist.iter()) != NULL; )
_classdict[cls]->is_pipeclass()->output(fp);
fprintf(fp,"\nNop Instructions:");
for ( _noplist.reset(); (nop = _noplist.iter()) != NULL; )
fprintf(fp, " \"%s\"", nop);
fprintf(fp,"\n");
}
ResourceForm::ResourceForm(unsigned resmask)
: _resmask(resmask) {
}
ResourceForm::~ResourceForm() {
}
ResourceForm *ResourceForm::is_resource() const {
return (ResourceForm *)(this);
}
void ResourceForm::dump() {
output(stderr);
}
void ResourceForm::output(FILE *fp) { // Write info to output files
fprintf(fp, "resource: 0x%08x;\n", mask());
}
void PipeClassOperandForm::dump() {
output(stderr);
}
void PipeClassOperandForm::output(FILE *fp) { // Write info to output files
fprintf(stderr,"PipeClassOperandForm: %s", _stage);
fflush(stderr);
if (_more_instrs > 0)
fprintf(stderr,"+%d", _more_instrs);
fprintf(stderr," (%s)\n", _iswrite ? "write" : "read");
fflush(stderr);
fprintf(fp,"PipeClassOperandForm: %s", _stage);
if (_more_instrs > 0)
fprintf(fp,"+%d", _more_instrs);
fprintf(fp," (%s)\n", _iswrite ? "write" : "read");
}
void PipeClassResourceForm::dump() {
output(stderr);
}
void PipeClassResourceForm::output(FILE *fp) { // Write info to output files
fprintf(fp,"PipeClassResourceForm: %s at stage %s for %d cycles\n",
_resource, _stage, _cycles);
}
PipeClassForm::PipeClassForm(const char *id, int num)
: _ident(id)
, _num(num)
, _localNames(cmpstr, hashstr, Form::arena)
, _localUsage(cmpstr, hashstr, Form::arena)
, _has_fixed_latency(0)
, _fixed_latency(0)
, _instruction_count(0)
, _has_multiple_bundles(false)
, _has_branch_delay_slot(false)
, _force_serialization(false)
, _may_have_no_code(false) {
}
PipeClassForm::~PipeClassForm() {
}
PipeClassForm *PipeClassForm::is_pipeclass() const {
return (PipeClassForm *)(this);
}
void PipeClassForm::dump() {
output(stderr);
}
void PipeClassForm::output(FILE *fp) { // Write info to output files
fprintf(fp,"PipeClassForm: #%03d", _num);
if (_ident)
fprintf(fp," \"%s\":", _ident);
if (_has_fixed_latency)
fprintf(fp," latency %d", _fixed_latency);
if (_force_serialization)
fprintf(fp, ", force serialization");
if (_may_have_no_code)
fprintf(fp, ", may have no code");
fprintf(fp, ", %d instruction%s\n", InstructionCount(), InstructionCount() != 1 ? "s" : "");
}
int Peephole::_peephole_counter = 0;
Peephole::Peephole() : _match(NULL), _constraint(NULL), _replace(NULL), _next(NULL) {
_peephole_number = _peephole_counter++;
}
Peephole::~Peephole() {
}
void Peephole::append_peephole(Peephole *next_peephole) {
if( _next == NULL ) {
_next = next_peephole;
} else {
_next->append_peephole( next_peephole );
}
}
void Peephole::add_match(PeepMatch *match) {
assert( _match == NULL, "fatal()" );
_match = match;
}
void Peephole::append_constraint(PeepConstraint *next_constraint) {
if( _constraint == NULL ) {
_constraint = next_constraint;
} else {
_constraint->append( next_constraint );
}
}
void Peephole::add_replace(PeepReplace *replace) {
assert( _replace == NULL, "fatal()" );
_replace = replace;
}
void Peephole::dump() {
output(stderr);
}
void Peephole::output(FILE *fp) { // Write info to output files
fprintf(fp,"Peephole:\n");
if( _match != NULL ) _match->output(fp);
if( _constraint != NULL ) _constraint->output(fp);
if( _replace != NULL ) _replace->output(fp);
if( _next ) _next->output(fp);
}
PeepMatch::PeepMatch(char *rule) : _max_position(0), _rule(rule) {
}
PeepMatch::~PeepMatch() {
}
void PeepMatch::add_instruction(int parent, int position, const char *name,
int input) {
if( position > _max_position ) _max_position = position;
_parent.addName((char*) (intptr_t) parent);
_position.addName((char*) (intptr_t) position);
_instrs.addName(name);
_input.addName((char*) (intptr_t) input);
}
int PeepMatch::max_position() {
return _max_position;
}
const char *PeepMatch::instruction_name(int position) {
return _instrs.name(position);
}
void PeepMatch::reset() {
_parent.reset();
_position.reset();
_instrs.reset();
_input.reset();
}
void PeepMatch::next_instruction(int &parent, int &position, const char* &name, int &input) {
parent = (int) (intptr_t) _parent.iter();
position = (int) (intptr_t) _position.iter();
name = _instrs.iter();
input = (int) (intptr_t) _input.iter();
}
bool PeepMatch::is_placeholder() {
return _instrs.current_is_signal();
}
void PeepMatch::dump() {
output(stderr);
}
void PeepMatch::output(FILE *fp) { // Write info to output files
fprintf(fp,"PeepMatch:\n");
}
PeepConstraint::PeepConstraint(int left_inst, char* left_op, char* relation,
int right_inst, char* right_op)
: _left_inst(left_inst), _left_op(left_op), _relation(relation),
_right_inst(right_inst), _right_op(right_op), _next(NULL) {}
PeepConstraint::~PeepConstraint() {
}
bool PeepConstraint::constrains_instruction(int position) {
if( _left_inst == position ) return true;
if( _right_inst == position ) return true;
if( _next == NULL ) return false;
else return _next->constrains_instruction(position);
}
void PeepConstraint::append(PeepConstraint *next_constraint) {
if( _next == NULL ) {
_next = next_constraint;
} else {
_next->append( next_constraint );
}
}
PeepConstraint *PeepConstraint::next() {
return _next;
}
void PeepConstraint::dump() {
output(stderr);
}
void PeepConstraint::output(FILE *fp) { // Write info to output files
fprintf(fp,"PeepConstraint:\n");
}
PeepReplace::PeepReplace(char *rule) : _rule(rule) {
}
PeepReplace::~PeepReplace() {
}
void PeepReplace::add_instruction(char *root) {
_instruction.addName(root);
_operand_inst_num.add_signal();
_operand_op_name.add_signal();
}
void PeepReplace::add_operand( int inst_num, char *inst_operand ) {
_instruction.add_signal();
_operand_inst_num.addName((char*) (intptr_t) inst_num);
_operand_op_name.addName(inst_operand);
}
void PeepReplace::reset() {
_instruction.reset();
_operand_inst_num.reset();
_operand_op_name.reset();
}
void PeepReplace::next_instruction(const char* &inst){
inst = _instruction.iter();
int inst_num = (int) (intptr_t) _operand_inst_num.iter();
const char* inst_operand = _operand_op_name.iter();
}
void PeepReplace::next_operand(int &inst_num, const char* &inst_operand) {
const char* inst = _instruction.iter();
inst_num = (int) (intptr_t) _operand_inst_num.iter();
inst_operand = _operand_op_name.iter();
}
void PeepReplace::dump() {
output(stderr);
}
void PeepReplace::output(FILE *fp) { // Write info to output files
fprintf(fp,"PeepReplace:\n");
}
C:\hotspot-69087d08d473\src\share\vm/adlc/formsopt.hpp
#ifndef SHARE_VM_ADLC_FORMSOPT_HPP
#define SHARE_VM_ADLC_FORMSOPT_HPP
class Form;
class InstructForm;
class OperandForm;
class OpClassForm;
class AttributeForm;
class RegisterForm;
class PipelineForm;
class SourceForm;
class EncodeForm;
class Component;
class Constraint;
class Predicate;
class MatchRule;
class Attribute;
class Effect;
class ExpandRule;
class RewriteRule;
class ConstructRule;
class FormatRule;
class Peephole;
class PeepMatch;
class PeepConstraint;
class EncClass;
class Interface;
class RegInterface;
class ConstInterface;
class MemInterface;
class CondInterface;
class Opcode;
class InsEncode;
class RegDef;
class RegClass;
class CodeSnippetRegClass;
class ConditionalRegClass;
class AllocClass;
class ResourceForm;
class PipeClassForm;
class PipeClassOperandForm;
class PipeClassResourceForm;
class PeepMatch;
class PeepConstraint;
class PeepReplace;
class MatchList;
class ArchDesc;
class RegisterForm : public Form {
private:
AllocClass *_current_ac; // State used by iter_RegDefs()
public:
NameList _rdefs; // List of register definition names
Dict _regDef; // map register name to RegDef*
NameList _rclasses; // List of register class names
Dict _regClass; // map register class name to RegClass*
NameList _aclasses; // List of allocation class names
Dict _allocClass; // Dictionary of allocation classes
static int _reg_ctr; // Register counter
static int RegMask_Size(); // Compute RegMask size
RegisterForm();
~RegisterForm();
void addRegDef(char *regName, char *callingConv, char *c_conv,
char * idealtype, char *encoding, char* concreteName);
template<typename T> T* addRegClass(const char* className);
AllocClass *addAllocClass(char *allocName);
void addSpillRegClass();
void reset_RegDefs();
RegDef *iter_RegDefs();
RegDef *getRegDef (const char *regName);
RegClass *getRegClass(const char *className);
uint reg_mask(char *register_class);
bool verify();
void dump(); // Debug printer
void output(FILE *fp); // Write info to output files
};
class RegDef : public Form {
public:
const char *_regname; // ADLC (Opto) Register name
const char *_callconv; // Calling convention
const char *_c_conv; // Native calling convention, 'C'
const char *_idealtype; // Ideal Type for register save/restore
const char *_concrete; // concrete register name
private:
const char *_register_encode; // The register encoding
uint32 _register_num; // Which register am I
public:
RegDef(char *regname, char *callconv, char *c_conv,
char *idealtype, char *encoding, char *concrete);
~RegDef(); // Destructor
void set_register_num(uint32 new_register_num);
const char *register_encode() const;
uint32 register_num() const;
void dump(); // Debug printer
void output(FILE *fp); // Write info to output files
};
class RegClass : public Form {
public:
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
public:
RegClass(const char *classid);// Constructor
virtual ~RegClass();
void addReg(RegDef *regDef); // Add a register to this class
uint size() const; // Number of registers in class
int regs_in_word( int wordnum, bool stack_also );
const RegDef *get_RegDef(const char *regDef_name) const;
const RegDef* find_first_elem();
void reset(); // Reset the following two iterators
RegDef *RegDef_iter(); // which move jointly,
const char *rd_name_iter(); // invoking either advances both.
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);
};
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) {
return;
}
};
class ConditionalRegClass : public RegClass {
protected:
char* _condition_code; // C++ condition code to dynamically determine which register class to use.
RegClass* _rclasses[2]; // 0 is the register class selected if the condition code returns true
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) {
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;
}
};
ssssss01
最新推荐文章于 2024-09-08 10:25:07 发布