/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// ADLPARSE.CPP - Architecture Description Language Parser // Authors: Chris Vick and Mike Paleczny #include"adlc.hpp"
//----------------------------ADLParser---------------------------------------- // Create a new ADL parser
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;
// Delimit command-line definitions from in-file definitions:
_AD._preproc_list.add_signal();
}
//------------------------------~ADLParser------------------------------------- // Delete an ADL parser.
ADLParser::~ADLParser() { if (!_AD._quiet_mode)
fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n"); #ifndef ASSERT if (!_AD._quiet_mode) {
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
// Write out information we have stored // // UNIXism == fsync(stderr);
}
//------------------------------parse------------------------------------------ // Each top-level keyword should appear as the first non-whitespace on a line. // void ADLParser::parse() { char *ident;
// Iterate over the lines in the file buffer parsing Level 1 objects 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(); elseif (!strcmp(ident, "operand")) oper_parse(); elseif (!strcmp(ident, "opclass")) opclass_parse(); elseif (!strcmp(ident, "ins_attrib")) ins_attr_parse(); elseif (!strcmp(ident, "op_attrib")) op_attr_parse(); elseif (!strcmp(ident, "source")) source_parse(); elseif (!strcmp(ident, "source_hpp")) source_hpp_parse(); elseif (!strcmp(ident, "register")) reg_parse(); elseif (!strcmp(ident, "frame")) frame_parse(); elseif (!strcmp(ident, "encode")) encode_parse(); elseif (!strcmp(ident, "pipeline")) pipe_parse(); elseif (!strcmp(ident, "definitions")) definitions_parse(); elseif (!strcmp(ident, "peephole")) peep_parse(); elseif (!strcmp(ident, "#line")) preproc_line(); elseif (!strcmp(ident, "#define")) preproc_define(); elseif (!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);
}
} // Add reg_class spill_regs after parsing.
RegisterForm *regBlock = _AD.get_registers(); if (regBlock == NULL) {
parse_err(SEMERR, "Did not declare 'register' definitions");
}
regBlock->addSpillRegClass();
regBlock->addDynamicRegClass();
// Done with parsing, check consistency.
if (_preproc_depth != 0) {
parse_err(SYNERR, "End of file inside #ifdef");
}
// AttributeForms ins_cost and op_cost must be defined for default behaviour 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");
}
}
// ******************** Private Level 1 Parse Functions ******************** //------------------------------instr_parse------------------------------------ // Parse the contents of an instruction definition, build the InstructForm to // represent that instruction, and add it to the InstructForm list. void ADLParser::instr_parse(void) { char *ident;
InstructForm *instr;
MatchRule *rule; int match_rules_cnt = 0;
// First get the name of the instruction 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 // Debugging Stuff if (_AD._adl_debug > 1)
fprintf(stderr,"Parsing Instruction Form %s\n", ident);
// Then get the operands
skipws(); if (_curchar != '(') {
parse_err(SYNERR, "missing '(' in instruct definition\n");
} // Parse the operand list else get_oplist(instr->_parameters, instr->_localNames);
skipws(); // Skip leading whitespace // Check for block delimiter 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(); elseif (!strcmp(ident, "match")) { // Allow one instruction have several match rules.
rule = instr->_matrule; if (rule == NULL) { // This is first match rule encountered
rule = match_parse(instr->_localNames); if (rule) {
instr->_matrule = rule; // Special case the treatment of Control instructions. if( instr->is_ideal_control() ) { // Control instructions return a special result, 'Universe'
rule->_result = "Universe";
} // Check for commutative operations with tree operands.
matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
}
} else { // Find the end of the match rule list while (rule->_next != NULL)
rule = rule->_next; // Add the new match rule to the list
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*) AdlAllocateHeap(strlen(instr->_ident) + 4);
sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++);
rule->_result = buf; // Check for commutative operations with tree operands.
matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
}
}
} elseif (!strcmp(ident, "encode")) {
parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
} elseif (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr); // Parse late expand keyword. elseif (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr); elseif (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr); elseif (!strcmp(ident, "size")) instr->_size = size_parse(instr); elseif (!strcmp(ident, "effect")) effect_parse(instr); elseif (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr); elseif (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse(); elseif (!strcmp(ident, "constraint")) {
parse_err(SYNERR, "Instructions do not specify a constraint\n");
} elseif (!strcmp(ident, "construct")) {
parse_err(SYNERR, "Instructions do not specify a construct\n");
} elseif (!strcmp(ident, "format")) instr->_format = format_parse(); elseif (!strcmp(ident, "interface")) {
parse_err(SYNERR, "Instructions do not specify an interface\n");
} elseif (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr); else { // Done with statically defined parts of instruction definition // Check identifier to see if it is the name of an attribute const Form *form = _globalNames[ident];
AttributeForm *attr = form ? form->is_attribute() : NULL; if (attr && (attr->_atype == INS_ATTR)) { // Insert the new attribute into the linked list.
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;
} // Check for "Set" form of chain rule
adjust_set_rule(instr); if (_AD._pipeline) { // No pipe required for late expand. 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);
}
}
} // Add instruction to tail of instruction list
_AD.addForm(instr);
// Create instruction form for each additional match rule
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 // Debugging Stuff if (_AD._adl_debug > 1)
fprintf(stderr,"Parsing Instruction Form %s\n", ident); // Check for "Set" form of chain rule
adjust_set_rule(clone); // Add instruction to tail of instruction list
_AD.addForm(clone);
rule = rule->_next;
clone->_matrule->_next = NULL; // One match rule per clone
}
}
}
//------------------------------matchrule_clone_and_swap----------------------- // Check for commutative operations with subtree operands, // create clones and swap operands. void ADLParser::matchrule_clone_and_swap(MatchRule* rule, constchar* instr_ident, int& match_rules_cnt) { // Check for commutative operations with tree operands. int count = 0;
rule->count_commutative_op(count); if (count > 0) { // Clone match rule and swap commutative operation's operands.
rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);
}
}
//------------------------------adjust_set_rule-------------------------------- // Check for "Set" form of chain rule void ADLParser::adjust_set_rule(InstructForm *instr) { if (instr->_matrule == NULL || instr->_matrule->_rChild == NULL) return; constchar *rch = instr->_matrule->_rChild->_opType; const Form *frm = _globalNames[rch]; if( (! strcmp(instr->_matrule->_opType,"Set")) &&
frm && frm->is_operand() && (! frm->ideal_only()) ) { // Previous implementation, which missed leaP*, but worked for loadCon* unsigned position = 0; constchar *result = NULL; constchar *name = NULL; constchar *optype = NULL;
MatchNode *right = instr->_matrule->_rChild; if (right->base_operand(position, _globalNames, result, name, optype)) {
position = 1; constchar *result2 = NULL; constchar *name2 = NULL; constchar *optype2 = NULL; // Can not have additional base operands in right side of match! 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"); // Chain from input _ideal_operand_type_, // Needed for shared roots of match-trees
ChainList *lst = (ChainList *)_AD._chainRules[optype]; if (lst == NULL) {
lst = new ChainList();
_AD._chainRules.Insert(optype, lst);
} if (!lst->search(instr->_matrule->_lChild->_opType)) { constchar *cost = instr->cost(); if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
} // The ADLC does not support chaining from the ideal operand type // of a predicated user-defined operand if( frm->is_operand() == NULL || frm->is_operand()->_predicate == NULL ) {
lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
}
} // Chain from input _user_defined_operand_type_,
lst = (ChainList *)_AD._chainRules[result]; if (lst == NULL) {
lst = new ChainList();
_AD._chainRules.Insert(result, lst);
} if (!lst->search(instr->_matrule->_lChild->_opType)) { constchar *cost = instr->cost(); if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
} // It is safe to chain from the top-level user-defined operand even // if it has a predicate, since the predicate is checked before // the user-defined type is available.
lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
}
} else { // May have instruction chain rule if root of right-tree is an ideal
OperandForm *rightOp = _globalNames[right->_opType]->is_operand(); if( rightOp ) { const Form *rightRoot = _globalNames[rightOp->_matrule->_opType]; if( rightRoot && rightRoot->ideal_only() ) { constchar *chain_op = NULL; if( rightRoot->is_instruction() )
chain_op = rightOp->_ident; if( chain_op ) { // Look-up the operation in chain rule table
ChainList *lst = (ChainList *)_AD._chainRules[chain_op]; if (lst == NULL) {
lst = new ChainList();
_AD._chainRules.Insert(chain_op, lst);
} // if (!lst->search(instr->_matrule->_lChild->_opType)) { constchar *cost = instr->cost(); if (cost == NULL) {
cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
} // This chains from a top-level operand whose predicate, if any, // has been checked.
lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident); // }
}
}
}
} // end chain rule from right-tree's ideal root
}
}
}
// First get the name of the operand
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
// Debugging Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Operand Form %s\n", ident);
// Get the component operands
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(); // Check for block delimiter 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(); elseif (!strcmp(ident, "match")) { // Find the end of the match rule list
rule = oper->_matrule; if (rule) { while (rule->_next) rule = rule->_next; // Add the new match rule to the list
rule->_next = match_parse(oper->_localNames); if (rule->_next) {
rule->_next->_result = oper->_ident;
}
} else { // This is first match rule encountered
oper->_matrule = match_parse(oper->_localNames); if (oper->_matrule) {
oper->_matrule->_result = oper->_ident;
}
}
} elseif (!strcmp(ident, "encode")) oper->_interface = interface_parse(); elseif (!strcmp(ident, "ins_encode")) {
parse_err(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");
} elseif (!strcmp(ident, "opcode")) {
parse_err(SYNERR, "Operands do not specify an opcode\n");
} elseif (!strcmp(ident, "effect")) {
parse_err(SYNERR, "Operands do not specify an effect\n");
} elseif (!strcmp(ident, "expand")) {
parse_err(SYNERR, "Operands do not specify an expand\n");
} elseif (!strcmp(ident, "rewrite")) {
parse_err(SYNERR, "Operands do not specify a rewrite\n");
} elseif (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse(); elseif (!strcmp(ident, "construct")) oper->_construct = construct_parse(); elseif (!strcmp(ident, "format")) oper->_format = format_parse(); elseif (!strcmp(ident, "interface")) oper->_interface = interface_parse(); // Check identifier to see if it is the name of an attribute elseif (((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;
} // Add operand to tail of operand list
_AD.addForm(oper);
}
//------------------------------opclass_parse---------------------------------- // Operand Classes are a block with a comma delimited list of operand names void ADLParser::opclass_parse(void) { char *ident;
OpClassForm *opc;
OperandForm *opForm;
// First get the name of the operand class
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
// Debugging Stuff if (_AD._adl_debug > 1)
fprintf(stderr,"Parsing Operand Class Form %s\n", ident);
// Get the list of operands
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;
} // Check identifier to see if it is the name of an operand 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 // Check for closing ')' if (_curchar != ')') {
parse_err(SYNERR, "missing ')' or ',' in opclass definition\n"); return;
}
next_char(); // Consume the ')'
skipws(); // Check for closing ';' if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in opclass definition\n"); return;
}
next_char(); // Consume the ';' // Add operand to tail of operand list
_AD.addForm(opc);
}
// get name for the instruction attribute
skipws(); // Skip leading whitespace if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL ) return; // Debugging Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Ins_Attribute Form %s\n", ident);
// Get default value of the instruction attribute
skipws(); // Skip whitespace if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {
parse_err(SYNERR, "missing '(' in ins_attrib definition\n"); return;
} // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
// Check for terminator if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in ins_attrib definition\n"); return;
}
next_char(); // Advance past the ';'
// Construct the attribute, record global name, and store in ArchDesc
attrib = new AttributeForm(ident, INS_ATTR, aexpr);
_globalNames.Insert(ident, attrib); // Add name to the name table
_AD.addForm(attrib);
}
// get name for the operand attribute
skipws(); // Skip leading whitespace if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL ) return; // Debugging Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Op_Attribute Form %s\n", ident);
// Get default value of the instruction attribute
skipws(); // Skip whitespace if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {
parse_err(SYNERR, "missing '(' in op_attrib definition\n"); return;
} // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
// Check for terminator if (_curchar != ';') {
parse_err(SYNERR, "missing ';' in op_attrib definition\n"); return;
}
next_char(); // Advance past the ';'
// Construct the attribute, record global name, and store in ArchDesc
attrib = new AttributeForm(ident, OP_ATTR, aexpr);
_globalNames.Insert(ident, attrib);
_AD.addForm(attrib);
}
//------------------------------definitions_parse----------------------------------- void ADLParser::definitions_parse(void) {
skipws(); // Skip leading whitespace if (_curchar == '%' && *(_ptr+1) == '{') {
next_char(); next_char(); // Skip "%{"
skipws(); while (_curchar != '%' && *(_ptr+1) != '}') { // Process each definition until finding closing string "%}" 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(); } // if (strcmp(token,"str_def")==0) { str_def_parse(); }
skipws();
}
} else {
parse_err(SYNERR, "Missing %%{ ... %%} block after definitions keyword.\n"); return;
}
}
// Get definition name
skipws(); // Skip whitespace
name = get_ident(); if (name == NULL) {
parse_err(SYNERR, "missing definition name after int_def\n"); return;
}
// Check for value of int_def dname( integer_value [, string_expression ] )
skipws(); if (_curchar == '(') {
// Parse the integer value.
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();
// Check for description 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();
}
// Check for closing ';'
skipws(); if (_curchar != ';') {
parse_err(SYNERR, "missing ';' after int_def\n"); return;
}
next_char(); // move past ';'
// Record new definition.
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;
}
//------------------------------source_parse----------------------------------- 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;
} // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Source Form: %s\n", rule);
source = new SourceForm(rule); // Build new Source object
_AD.addForm(source); // skipws();
}
//------------------------------source_hpp_parse------------------------------- // Parse a source_hpp %{ ... %} block. // The code gets stuck into the ad_<arch>.hpp file. // If the source_hpp block appears before the register block in the AD // file, it goes up at the very top of the ad_<arch>.hpp file, so that // it can be used by register encodings, etc. Otherwise, it goes towards // the bottom, where it's useful as a global definition to *.cpp files. 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;
} // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);
if (_AD.get_registers() == NULL) { // Very early in the file, before reg_defs, we collect pre-headers.
PreHeaderForm* pre_header = new PreHeaderForm(rule);
_AD.addForm(pre_header);
} else { // Normally, we collect header info, placed at the bottom of the hpp file.
HeaderForm* header = new HeaderForm(rule);
_AD.addForm(header);
}
}
//------------------------------reg_parse-------------------------------------- void ADLParser::reg_parse(void) {
RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding if (regBlock == NULL) { // Create the RegisterForm for the architecture description.
regBlock = new RegisterForm(); // Build new Source object
_AD.addForm(regBlock);
}
//------------------------------encode_parse----------------------------------- void ADLParser::encode_parse(void) {
EncodeForm *encBlock; // Information about instruction/operand encoding
_AD.getForm(&encBlock); if ( encBlock == NULL) { // Create the EncodeForm for the architecture description.
encBlock = new EncodeForm(); // Build new Source object
_AD.addForm(encBlock);
}
//------------------------------enc_class_parse-------------------------------- void ADLParser::enc_class_parse(void) { char *ec_name; // Name of encoding class being defined
// Get encoding class name
skipws(); // Skip whitespace
ec_name = get_ident(); if (ec_name == NULL) {
parse_err(SYNERR, "missing encoding class name after encode.\n"); return;
}
skipws(); // Skip leading whitespace // Check for optional parameter list if (_curchar == '(') { do { char *pType = NULL; // parameter type char *pName = NULL; // parameter name
next_char(); // skip open paren & comma characters
skipws(); if (_curchar == ')') break;
// Get parameter type
pType = get_ident(); if (pType == NULL) {
parse_err(SYNERR, "parameter type expected at %c\n", _curchar); return;
}
skipws(); // Get parameter name
pName = get_ident(); if (pName == NULL) {
parse_err(SYNERR, "parameter name expected at %c\n", _curchar); return;
}
// Record parameter type and name
encoding->add_parameter( pType, pName );
skipws();
} while(_curchar == ',');
if (_curchar != ')') parse_err(SYNERR, "missing ')'\n"); else {
next_char(); // Skip ')'
}
} // Done with parameter list
skipws(); // Check for block starting delimiters 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 // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block if (_AD._adlocation_debug) {
encoding->add_code(get_line_string());
}
// Collect the parts of the encode description // (1) strings that are passed through to output // (2) replacement/substitution variable, preceded by a '$' while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {
// (1) // Check if there is a string to pass through to output char *start = _ptr; // Record start of the next string while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { // If at the start of a comment, skip past it if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else { // ELSE advance to the next character, or start of the next line
next_char_or_line();
}
} // If a string was found, terminate it and record in EncClass if ( start != _ptr ) {
*_ptr = '\0'; // Terminate the string
encoding->add_code(start);
}
// (2) // If we are at a replacement variable, // copy it and record in EncClass if (_curchar == '$') { // Found replacement Variable char* rep_var = get_rep_var_ident_dup(); // Add flag to _strings list indicating we should check _rep_vars
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());
}
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
// Check ident for validity if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) {
parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", ident); return;
}
// Add this instruction to the list in the pipeline class
_AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident);
// Set the name of the pipeline class in the instruction
instr._ins_pipe = ident; return;
}
//------------------------------pipe_parse------------------------------------- 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 // Check for block delimiter 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); elseif (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline); elseif (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline); elseif (!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
// Check ident for validity if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) {
parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", pipe_class); return;
}
// Add this machine node to the list in the pipeline class
_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;
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 statically 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;
}
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;
}
if (ident == NULL) {
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar); return;
}
// Create a record for the pipe_class
pipe_class = new PipeClassForm(ident, ++pipeline._classcnt);
pipeline._classdict.Insert(ident, pipe_class);
pipeline._classlist.addName(ident);
// Then get the operands
skipws(); if (_curchar != '(') {
parse_err(SYNERR, "missing \"(\" in pipe_class definition\n");
} // Parse the operand list else get_oplist(pipe_class->_parameters, pipe_class->_localNames);
skipws(); // Skip leading whitespace // Check for block delimiter 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Die Arbeitsteilung ist notwendig ...
Die farbliche Syntaxdarstellung ist noch experimentell.