duke@435: // twisti@1038: // Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. duke@435: // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: // duke@435: // This code is free software; you can redistribute it and/or modify it duke@435: // under the terms of the GNU General Public License version 2 only, as duke@435: // published by the Free Software Foundation. duke@435: // duke@435: // This code is distributed in the hope that it will be useful, but WITHOUT duke@435: // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: // version 2 for more details (a copy is included in the LICENSE file that duke@435: // accompanied this code). duke@435: // duke@435: // You should have received a copy of the GNU General Public License version duke@435: // 2 along with this work; if not, write to the Free Software Foundation, duke@435: // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: // duke@435: // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: // CA 95054 USA or visit www.sun.com if you need additional information or duke@435: // have any questions. duke@435: // duke@435: // duke@435: duke@435: duke@435: // archDesc.cpp - Internal format for architecture definition duke@435: #include "adlc.hpp" duke@435: duke@435: static FILE *errfile = stderr; duke@435: duke@435: //--------------------------- utility functions ----------------------------- duke@435: inline char toUpper(char lower) { duke@435: return (('a' <= lower && lower <= 'z') ? (lower + ('A'-'a')) : lower); duke@435: } duke@435: char *toUpper(const char *str) { duke@435: char *upper = new char[strlen(str)+1]; duke@435: char *result = upper; duke@435: const char *end = str + strlen(str); duke@435: for (; str < end; ++str, ++upper) { duke@435: *upper = toUpper(*str); duke@435: } duke@435: *upper = '\0'; duke@435: return result; duke@435: } duke@435: duke@435: // Utilities to characterize effect statements duke@435: static bool is_def(int usedef) { duke@435: switch(usedef) { duke@435: case Component::DEF: duke@435: case Component::USE_DEF: return true; break; duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: static bool is_use(int usedef) { duke@435: switch(usedef) { duke@435: case Component::USE: duke@435: case Component::USE_DEF: duke@435: case Component::USE_KILL: return true; break; duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: static bool is_kill(int usedef) { duke@435: switch(usedef) { duke@435: case Component::KILL: duke@435: case Component::USE_KILL: return true; break; duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: //---------------------------ChainList Methods------------------------------- duke@435: ChainList::ChainList() { duke@435: } duke@435: duke@435: void ChainList::insert(const char *name, const char *cost, const char *rule) { duke@435: _name.addName(name); duke@435: _cost.addName(cost); duke@435: _rule.addName(rule); duke@435: } duke@435: duke@435: bool ChainList::search(const char *name) { duke@435: return _name.search(name); duke@435: } duke@435: duke@435: void ChainList::reset() { duke@435: _name.reset(); duke@435: _cost.reset(); duke@435: _rule.reset(); duke@435: } duke@435: duke@435: bool ChainList::iter(const char * &name, const char * &cost, const char * &rule) { duke@435: bool notDone = false; duke@435: const char *n = _name.iter(); duke@435: const char *c = _cost.iter(); duke@435: const char *r = _rule.iter(); duke@435: duke@435: if (n && c && r) { duke@435: notDone = true; duke@435: name = n; duke@435: cost = c; duke@435: rule = r; duke@435: } duke@435: duke@435: return notDone; duke@435: } duke@435: duke@435: void ChainList::dump() { duke@435: output(stderr); duke@435: } duke@435: duke@435: void ChainList::output(FILE *fp) { duke@435: fprintf(fp, "\nChain Rules: output resets iterator\n"); duke@435: const char *cost = NULL; duke@435: const char *name = NULL; duke@435: const char *rule = NULL; duke@435: bool chains_exist = false; duke@435: for(reset(); (iter(name,cost,rule)) == true; ) { duke@435: fprintf(fp, "Chain to <%s> at cost #%s using %s_rule\n",name, cost ? cost : "0", rule); duke@435: // // Check for transitive chain rules duke@435: // Form *form = (Form *)_globalNames[rule]; duke@435: // if (form->is_instruction()) { duke@435: // // chain_rule(fp, indent, name, cost, rule); duke@435: // chain_rule(fp, indent, name, cost, rule); duke@435: // } duke@435: } duke@435: reset(); duke@435: if( ! chains_exist ) { duke@435: fprintf(fp, "No entries in this ChainList\n"); duke@435: } duke@435: } duke@435: duke@435: duke@435: //---------------------------MatchList Methods------------------------------- duke@435: bool MatchList::search(const char *opc, const char *res, const char *lch, duke@435: const char *rch, Predicate *pr) { duke@435: bool tmp = false; duke@435: if ((res == _resultStr) || (res && _resultStr && !strcmp(res, _resultStr))) { duke@435: if ((lch == _lchild) || (lch && _lchild && !strcmp(lch, _lchild))) { duke@435: if ((rch == _rchild) || (rch && _rchild && !strcmp(rch, _rchild))) { duke@435: char * predStr = get_pred(); duke@435: char * prStr = pr?pr->_pred:NULL; jrose@910: if (ADLParser::equivalent_expressions(prStr, predStr)) { duke@435: return true; duke@435: } duke@435: } duke@435: } duke@435: } duke@435: if (_next) { duke@435: tmp = _next->search(opc, res, lch, rch, pr); duke@435: } duke@435: return tmp; duke@435: } duke@435: duke@435: duke@435: void MatchList::dump() { duke@435: output(stderr); duke@435: } duke@435: duke@435: void MatchList::output(FILE *fp) { duke@435: fprintf(fp, "\nMatchList output is Unimplemented();\n"); duke@435: } duke@435: duke@435: duke@435: //---------------------------ArchDesc Constructor and Destructor------------- duke@435: duke@435: ArchDesc::ArchDesc() duke@435: : _globalNames(cmpstr,hashstr, Form::arena), duke@435: _globalDefs(cmpstr,hashstr, Form::arena), duke@435: _preproc_table(cmpstr,hashstr, Form::arena), duke@435: _idealIndex(cmpstr,hashstr, Form::arena), duke@435: _internalOps(cmpstr,hashstr, Form::arena), duke@435: _internalMatch(cmpstr,hashstr, Form::arena), duke@435: _chainRules(cmpstr,hashstr, Form::arena), duke@435: _cisc_spill_operand(NULL) { duke@435: duke@435: // Initialize the opcode to MatchList table with NULLs duke@435: for( int i=0; i<_last_opcode; ++i ) { duke@435: _mlistab[i] = NULL; duke@435: } duke@435: duke@435: // Set-up the global tables duke@435: initKeywords(_globalNames); // Initialize the Name Table with keywords duke@435: duke@435: // Prime user-defined types with predefined types: Set, RegI, RegF, ... duke@435: initBaseOpTypes(); duke@435: duke@435: // Initialize flags & counters duke@435: _TotalLines = 0; duke@435: _no_output = 0; duke@435: _quiet_mode = 0; duke@435: _disable_warnings = 0; duke@435: _dfa_debug = 0; duke@435: _dfa_small = 0; duke@435: _adl_debug = 0; duke@435: _adlocation_debug = 0; duke@435: _internalOpCounter = 0; duke@435: _cisc_spill_debug = false; duke@435: _short_branch_debug = false; duke@435: duke@435: // Initialize match rule flags duke@435: for (int i = 0; i < _last_opcode; i++) { duke@435: _has_match_rule[i] = false; duke@435: } duke@435: duke@435: // Error/Warning Counts duke@435: _syntax_errs = 0; duke@435: _semantic_errs = 0; duke@435: _warnings = 0; duke@435: _internal_errs = 0; duke@435: duke@435: // Initialize I/O Files duke@435: _ADL_file._name = NULL; _ADL_file._fp = NULL; duke@435: // Machine dependent output files kvn@868: _DFA_file._name = NULL; _DFA_file._fp = NULL; kvn@868: _HPP_file._name = NULL; _HPP_file._fp = NULL; kvn@868: _CPP_file._name = NULL; _CPP_file._fp = NULL; duke@435: _bug_file._name = "bugs.out"; _bug_file._fp = NULL; duke@435: duke@435: // Initialize Register & Pipeline Form Pointers duke@435: _register = NULL; duke@435: _encode = NULL; duke@435: _pipeline = NULL; duke@435: } duke@435: duke@435: ArchDesc::~ArchDesc() { duke@435: // Clean-up and quit duke@435: duke@435: } duke@435: duke@435: //---------------------------ArchDesc methods: Public ---------------------- duke@435: // Store forms according to type duke@435: void ArchDesc::addForm(PreHeaderForm *ptr) { _pre_header.addForm(ptr); }; duke@435: void ArchDesc::addForm(HeaderForm *ptr) { _header.addForm(ptr); }; duke@435: void ArchDesc::addForm(SourceForm *ptr) { _source.addForm(ptr); }; duke@435: void ArchDesc::addForm(EncodeForm *ptr) { _encode = ptr; }; duke@435: void ArchDesc::addForm(InstructForm *ptr) { _instructions.addForm(ptr); }; duke@435: void ArchDesc::addForm(MachNodeForm *ptr) { _machnodes.addForm(ptr); }; duke@435: void ArchDesc::addForm(OperandForm *ptr) { _operands.addForm(ptr); }; duke@435: void ArchDesc::addForm(OpClassForm *ptr) { _opclass.addForm(ptr); }; duke@435: void ArchDesc::addForm(AttributeForm *ptr) { _attributes.addForm(ptr); }; duke@435: void ArchDesc::addForm(RegisterForm *ptr) { _register = ptr; }; duke@435: void ArchDesc::addForm(FrameForm *ptr) { _frame = ptr; }; duke@435: void ArchDesc::addForm(PipelineForm *ptr) { _pipeline = ptr; }; duke@435: duke@435: // Build MatchList array and construct MatchLists duke@435: void ArchDesc::generateMatchLists() { duke@435: // Call inspection routines to populate array duke@435: inspectOperands(); duke@435: inspectInstructions(); duke@435: } duke@435: duke@435: // Build MatchList structures for operands duke@435: void ArchDesc::inspectOperands() { duke@435: duke@435: // Iterate through all operands duke@435: _operands.reset(); duke@435: OperandForm *op; duke@435: for( ; (op = (OperandForm*)_operands.iter()) != NULL;) { duke@435: // Construct list of top-level operands (components) duke@435: op->build_components(); duke@435: duke@435: // Ensure that match field is defined. duke@435: if ( op->_matrule == NULL ) continue; duke@435: duke@435: // Type check match rules duke@435: check_optype(op->_matrule); duke@435: duke@435: // Construct chain rules duke@435: build_chain_rule(op); duke@435: duke@435: MatchRule &mrule = *op->_matrule; duke@435: Predicate *pred = op->_predicate; duke@435: duke@435: // Grab the machine type of the operand duke@435: const char *rootOp = op->_ident; duke@435: mrule._machType = rootOp; duke@435: duke@435: // Check for special cases duke@435: if (strcmp(rootOp,"Universe")==0) continue; duke@435: if (strcmp(rootOp,"label")==0) continue; duke@435: // !!!!! !!!!! duke@435: assert( strcmp(rootOp,"sReg") != 0, "Disable untyped 'sReg'"); duke@435: if (strcmp(rootOp,"sRegI")==0) continue; duke@435: if (strcmp(rootOp,"sRegP")==0) continue; duke@435: if (strcmp(rootOp,"sRegF")==0) continue; duke@435: if (strcmp(rootOp,"sRegD")==0) continue; duke@435: if (strcmp(rootOp,"sRegL")==0) continue; duke@435: duke@435: // Cost for this match duke@435: const char *costStr = op->cost(); duke@435: const char *defaultCost = duke@435: ((AttributeForm*)_globalNames[AttributeForm::_op_cost])->_attrdef; duke@435: const char *cost = costStr? costStr : defaultCost; duke@435: duke@435: // Find result type for match. duke@435: const char *result = op->reduce_result(); duke@435: bool has_root = false; duke@435: duke@435: // Construct a MatchList for this entry duke@435: buildMatchList(op->_matrule, result, rootOp, pred, cost); duke@435: } duke@435: } duke@435: duke@435: // Build MatchList structures for instructions duke@435: void ArchDesc::inspectInstructions() { duke@435: duke@435: // Iterate through all instructions duke@435: _instructions.reset(); duke@435: InstructForm *instr; duke@435: for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) { duke@435: // Construct list of top-level operands (components) duke@435: instr->build_components(); duke@435: duke@435: // Ensure that match field is defined. duke@435: if ( instr->_matrule == NULL ) continue; duke@435: duke@435: MatchRule &mrule = *instr->_matrule; duke@435: Predicate *pred = instr->build_predicate(); duke@435: duke@435: // Grab the machine type of the operand duke@435: const char *rootOp = instr->_ident; duke@435: mrule._machType = rootOp; duke@435: duke@435: // Cost for this match duke@435: const char *costStr = instr->cost(); duke@435: const char *defaultCost = duke@435: ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef; duke@435: const char *cost = costStr? costStr : defaultCost; duke@435: duke@435: // Find result type for match duke@435: const char *result = instr->reduce_result(); duke@435: duke@435: Attribute *attr = instr->_attribs; duke@435: while (attr != NULL) { duke@435: if (strcmp(attr->_ident,"ins_short_branch") == 0 && duke@435: attr->int_val(*this) != 0) { duke@435: instr->set_short_branch(true); duke@435: } else if (strcmp(attr->_ident,"ins_alignment") == 0 && duke@435: attr->int_val(*this) != 0) { duke@435: instr->set_alignment(attr->int_val(*this)); duke@435: } duke@435: attr = (Attribute *)attr->_next; duke@435: } duke@435: duke@435: if (!instr->is_short_branch()) { duke@435: buildMatchList(instr->_matrule, result, mrule._machType, pred, cost); duke@435: } duke@435: } duke@435: } duke@435: duke@435: static int setsResult(MatchRule &mrule) { duke@435: if (strcmp(mrule._name,"Set") == 0) return 1; duke@435: return 0; duke@435: } duke@435: duke@435: const char *ArchDesc::getMatchListIndex(MatchRule &mrule) { duke@435: if (setsResult(mrule)) { duke@435: // right child duke@435: return mrule._rChild->_opType; duke@435: } else { duke@435: // first entry duke@435: return mrule._opType; duke@435: } duke@435: } duke@435: duke@435: duke@435: //------------------------------result of reduction---------------------------- duke@435: duke@435: duke@435: //------------------------------left reduction--------------------------------- duke@435: // Return the left reduction associated with an internal name duke@435: const char *ArchDesc::reduceLeft(char *internalName) { duke@435: const char *left = NULL; duke@435: MatchNode *mnode = (MatchNode*)_internalMatch[internalName]; duke@435: if (mnode->_lChild) { duke@435: mnode = mnode->_lChild; duke@435: left = mnode->_internalop ? mnode->_internalop : mnode->_opType; duke@435: } duke@435: return left; duke@435: } duke@435: duke@435: duke@435: //------------------------------right reduction-------------------------------- duke@435: const char *ArchDesc::reduceRight(char *internalName) { duke@435: const char *right = NULL; duke@435: MatchNode *mnode = (MatchNode*)_internalMatch[internalName]; duke@435: if (mnode->_rChild) { duke@435: mnode = mnode->_rChild; duke@435: right = mnode->_internalop ? mnode->_internalop : mnode->_opType; duke@435: } duke@435: return right; duke@435: } duke@435: duke@435: duke@435: //------------------------------check_optype----------------------------------- duke@435: void ArchDesc::check_optype(MatchRule *mrule) { duke@435: MatchRule *rule = mrule; duke@435: duke@435: // !!!!! duke@435: // // Cycle through the list of match rules duke@435: // while(mrule) { duke@435: // // Check for a filled in type field duke@435: // if (mrule->_opType == NULL) { duke@435: // const Form *form = operands[_result]; duke@435: // OpClassForm *opcForm = form ? form->is_opclass() : NULL; duke@435: // assert(opcForm != NULL, "Match Rule contains invalid operand name."); duke@435: // } duke@435: // char *opType = opcForm->_ident; duke@435: // } duke@435: } duke@435: duke@435: //------------------------------add_chain_rule_entry-------------------------- duke@435: void ArchDesc::add_chain_rule_entry(const char *src, const char *cost, duke@435: const char *result) { duke@435: // Look-up the operation in chain rule table duke@435: ChainList *lst = (ChainList *)_chainRules[src]; duke@435: if (lst == NULL) { duke@435: lst = new ChainList(); duke@435: _chainRules.Insert(src, lst); duke@435: } duke@435: if (!lst->search(result)) { duke@435: if (cost == NULL) { duke@435: cost = ((AttributeForm*)_globalNames[AttributeForm::_op_cost])->_attrdef; duke@435: } duke@435: lst->insert(result, cost, result); duke@435: } duke@435: } duke@435: duke@435: //------------------------------build_chain_rule------------------------------- duke@435: void ArchDesc::build_chain_rule(OperandForm *oper) { duke@435: MatchRule *rule; duke@435: duke@435: // Check for chain rules here duke@435: // If this is only a chain rule duke@435: if ((oper->_matrule) && (oper->_matrule->_lChild == NULL) && duke@435: (oper->_matrule->_rChild == NULL)) { duke@435: twisti@1038: { twisti@1038: const Form *form = _globalNames[oper->_matrule->_opType]; twisti@1038: if ((form) && form->is_operand() && twisti@1038: (form->ideal_only() == false)) { twisti@1038: add_chain_rule_entry(oper->_matrule->_opType, oper->cost(), oper->_ident); twisti@1038: } duke@435: } duke@435: // Check for additional chain rules duke@435: if (oper->_matrule->_next) { duke@435: rule = oper->_matrule; duke@435: do { duke@435: rule = rule->_next; duke@435: // Any extra match rules after the first must be chain rules duke@435: const Form *form = _globalNames[rule->_opType]; duke@435: if ((form) && form->is_operand() && duke@435: (form->ideal_only() == false)) { duke@435: add_chain_rule_entry(rule->_opType, oper->cost(), oper->_ident); duke@435: } duke@435: } while(rule->_next != NULL); duke@435: } duke@435: } duke@435: else if ((oper->_matrule) && (oper->_matrule->_next)) { duke@435: // Regardles of whether the first matchrule is a chain rule, check the list duke@435: rule = oper->_matrule; duke@435: do { duke@435: rule = rule->_next; duke@435: // Any extra match rules after the first must be chain rules duke@435: const Form *form = _globalNames[rule->_opType]; duke@435: if ((form) && form->is_operand() && duke@435: (form->ideal_only() == false)) { duke@435: assert( oper->cost(), "This case expects NULL cost, not default cost"); duke@435: add_chain_rule_entry(rule->_opType, oper->cost(), oper->_ident); duke@435: } duke@435: } while(rule->_next != NULL); duke@435: } duke@435: duke@435: } duke@435: duke@435: //------------------------------buildMatchList--------------------------------- duke@435: // operands and instructions provide the result duke@435: void ArchDesc::buildMatchList(MatchRule *mrule, const char *resultStr, duke@435: const char *rootOp, Predicate *pred, duke@435: const char *cost) { duke@435: const char *leftstr, *rightstr; duke@435: MatchNode *mnode; duke@435: duke@435: leftstr = rightstr = NULL; duke@435: // Check for chain rule, and do not generate a match list for it duke@435: if ( mrule->is_chain_rule(_globalNames) ) { duke@435: return; duke@435: } duke@435: duke@435: // Identify index position among ideal operands duke@435: intptr_t index = _last_opcode; duke@435: const char *indexStr = getMatchListIndex(*mrule); duke@435: index = (intptr_t)_idealIndex[indexStr]; duke@435: if (index == 0) { duke@435: fprintf(stderr, "Ideal node missing: %s\n", indexStr); duke@435: assert(index != 0, "Failed lookup of ideal node\n"); duke@435: } duke@435: duke@435: // Check that this will be placed appropriately in the DFA duke@435: if (index >= _last_opcode) { duke@435: fprintf(stderr, "Invalid match rule %s <-- ( %s )\n", duke@435: resultStr ? resultStr : " ", duke@435: rootOp ? rootOp : " "); duke@435: assert(index < _last_opcode, "Matching item not in ideal graph\n"); duke@435: return; duke@435: } duke@435: duke@435: duke@435: // Walk the MatchRule, generating MatchList entries for each level duke@435: // of the rule (each nesting of parentheses) duke@435: // Check for "Set" duke@435: if (!strcmp(mrule->_opType, "Set")) { duke@435: mnode = mrule->_rChild; duke@435: buildMList(mnode, rootOp, resultStr, pred, cost); duke@435: return; duke@435: } duke@435: // Build MatchLists for children duke@435: // Check each child for an internal operand name, and use that name duke@435: // for the parent's matchlist entry if it exists duke@435: mnode = mrule->_lChild; duke@435: if (mnode) { duke@435: buildMList(mnode, NULL, NULL, NULL, NULL); duke@435: leftstr = mnode->_internalop ? mnode->_internalop : mnode->_opType; duke@435: } duke@435: mnode = mrule->_rChild; duke@435: if (mnode) { duke@435: buildMList(mnode, NULL, NULL, NULL, NULL); duke@435: rightstr = mnode->_internalop ? mnode->_internalop : mnode->_opType; duke@435: } duke@435: // Search for an identical matchlist entry already on the list duke@435: if ((_mlistab[index] == NULL) || duke@435: (_mlistab[index] && duke@435: !_mlistab[index]->search(rootOp, resultStr, leftstr, rightstr, pred))) { duke@435: // Place this match rule at front of list duke@435: MatchList *mList = duke@435: new MatchList(_mlistab[index], pred, cost, duke@435: rootOp, resultStr, leftstr, rightstr); duke@435: _mlistab[index] = mList; duke@435: } duke@435: } duke@435: duke@435: // Recursive call for construction of match lists duke@435: void ArchDesc::buildMList(MatchNode *node, const char *rootOp, duke@435: const char *resultOp, Predicate *pred, duke@435: const char *cost) { duke@435: const char *leftstr, *rightstr; duke@435: const char *resultop; duke@435: const char *opcode; duke@435: MatchNode *mnode; duke@435: Form *form; duke@435: duke@435: leftstr = rightstr = NULL; duke@435: // Do not process leaves of the Match Tree if they are not ideal duke@435: if ((node) && (node->_lChild == NULL) && (node->_rChild == NULL) && duke@435: ((form = (Form *)_globalNames[node->_opType]) != NULL) && duke@435: (!form->ideal_only())) { duke@435: return; duke@435: } duke@435: duke@435: // Identify index position among ideal operands duke@435: intptr_t index = _last_opcode; duke@435: const char *indexStr = node ? node->_opType : (char *) " "; duke@435: index = (intptr_t)_idealIndex[indexStr]; duke@435: if (index == 0) { duke@435: fprintf(stderr, "error: operand \"%s\" not found\n", indexStr); duke@435: assert(0, "fatal error"); duke@435: } duke@435: duke@435: // Build MatchLists for children duke@435: // Check each child for an internal operand name, and use that name duke@435: // for the parent's matchlist entry if it exists duke@435: mnode = node->_lChild; duke@435: if (mnode) { duke@435: buildMList(mnode, NULL, NULL, NULL, NULL); duke@435: leftstr = mnode->_internalop ? mnode->_internalop : mnode->_opType; duke@435: } duke@435: mnode = node->_rChild; duke@435: if (mnode) { duke@435: buildMList(mnode, NULL, NULL, NULL, NULL); duke@435: rightstr = mnode->_internalop ? mnode->_internalop : mnode->_opType; duke@435: } duke@435: // Grab the string for the opcode of this list entry duke@435: if (rootOp == NULL) { duke@435: opcode = (node->_internalop) ? node->_internalop : node->_opType; duke@435: } else { duke@435: opcode = rootOp; duke@435: } duke@435: // Grab the string for the result of this list entry duke@435: if (resultOp == NULL) { duke@435: resultop = (node->_internalop) ? node->_internalop : node->_opType; duke@435: } duke@435: else resultop = resultOp; duke@435: // Search for an identical matchlist entry already on the list duke@435: if ((_mlistab[index] == NULL) || (_mlistab[index] && duke@435: !_mlistab[index]->search(opcode, resultop, leftstr, rightstr, pred))) { duke@435: // Place this match rule at front of list duke@435: MatchList *mList = duke@435: new MatchList(_mlistab[index],pred,cost, duke@435: opcode, resultop, leftstr, rightstr); duke@435: _mlistab[index] = mList; duke@435: } duke@435: } duke@435: duke@435: // Count number of OperandForms defined duke@435: int ArchDesc::operandFormCount() { duke@435: // Only interested in ones with non-NULL match rule duke@435: int count = 0; _operands.reset(); duke@435: OperandForm *cur; duke@435: for( ; (cur = (OperandForm*)_operands.iter()) != NULL; ) { duke@435: if (cur->_matrule != NULL) ++count; duke@435: }; duke@435: return count; duke@435: } duke@435: duke@435: // Count number of OpClassForms defined duke@435: int ArchDesc::opclassFormCount() { duke@435: // Only interested in ones with non-NULL match rule duke@435: int count = 0; _operands.reset(); duke@435: OpClassForm *cur; duke@435: for( ; (cur = (OpClassForm*)_opclass.iter()) != NULL; ) { duke@435: ++count; duke@435: }; duke@435: return count; duke@435: } duke@435: duke@435: // Count number of InstructForms defined duke@435: int ArchDesc::instructFormCount() { duke@435: // Only interested in ones with non-NULL match rule duke@435: int count = 0; _instructions.reset(); duke@435: InstructForm *cur; duke@435: for( ; (cur = (InstructForm*)_instructions.iter()) != NULL; ) { duke@435: if (cur->_matrule != NULL) ++count; duke@435: }; duke@435: return count; duke@435: } duke@435: duke@435: duke@435: //------------------------------get_preproc_def-------------------------------- duke@435: // Return the textual binding for a given CPP flag name. duke@435: // Return NULL if there is no binding, or it has been #undef-ed. duke@435: char* ArchDesc::get_preproc_def(const char* flag) { duke@435: SourceForm* deff = (SourceForm*) _preproc_table[flag]; duke@435: return (deff == NULL) ? NULL : deff->_code; duke@435: } duke@435: duke@435: duke@435: //------------------------------set_preproc_def-------------------------------- duke@435: // Change or create a textual binding for a given CPP flag name. duke@435: // Giving NULL means the flag name is to be #undef-ed. duke@435: // In any case, _preproc_list collects all names either #defined or #undef-ed. duke@435: void ArchDesc::set_preproc_def(const char* flag, const char* def) { duke@435: SourceForm* deff = (SourceForm*) _preproc_table[flag]; duke@435: if (deff == NULL) { duke@435: deff = new SourceForm(NULL); duke@435: _preproc_table.Insert(flag, deff); duke@435: _preproc_list.addName(flag); // this supports iteration duke@435: } duke@435: deff->_code = (char*) def; duke@435: } duke@435: duke@435: duke@435: bool ArchDesc::verify() { duke@435: duke@435: if (_register) duke@435: assert( _register->verify(), "Register declarations failed verification"); duke@435: if (!_quiet_mode) duke@435: fprintf(stderr,"\n"); duke@435: // fprintf(stderr,"---------------------------- Verify Operands ---------------\n"); duke@435: // _operands.verify(); duke@435: // fprintf(stderr,"\n"); duke@435: // fprintf(stderr,"---------------------------- Verify Operand Classes --------\n"); duke@435: // _opclass.verify(); duke@435: // fprintf(stderr,"\n"); duke@435: // fprintf(stderr,"---------------------------- Verify Attributes ------------\n"); duke@435: // _attributes.verify(); duke@435: // fprintf(stderr,"\n"); duke@435: if (!_quiet_mode) duke@435: fprintf(stderr,"---------------------------- Verify Instructions ----------------------------\n"); duke@435: _instructions.verify(); duke@435: if (!_quiet_mode) duke@435: fprintf(stderr,"\n"); duke@435: // if ( _encode ) { duke@435: // fprintf(stderr,"---------------------------- Verify Encodings --------------\n"); duke@435: // _encode->verify(); duke@435: // } duke@435: duke@435: //if (_pipeline) _pipeline->verify(); duke@435: duke@435: return true; duke@435: } duke@435: duke@435: duke@435: void ArchDesc::dump() { duke@435: _pre_header.dump(); duke@435: _header.dump(); duke@435: _source.dump(); duke@435: if (_register) _register->dump(); duke@435: fprintf(stderr,"\n"); duke@435: fprintf(stderr,"------------------ Dump Operands ---------------------\n"); duke@435: _operands.dump(); duke@435: fprintf(stderr,"\n"); duke@435: fprintf(stderr,"------------------ Dump Operand Classes --------------\n"); duke@435: _opclass.dump(); duke@435: fprintf(stderr,"\n"); duke@435: fprintf(stderr,"------------------ Dump Attributes ------------------\n"); duke@435: _attributes.dump(); duke@435: fprintf(stderr,"\n"); duke@435: fprintf(stderr,"------------------ Dump Instructions -----------------\n"); duke@435: _instructions.dump(); duke@435: if ( _encode ) { duke@435: fprintf(stderr,"------------------ Dump Encodings --------------------\n"); duke@435: _encode->dump(); duke@435: } duke@435: if (_pipeline) _pipeline->dump(); duke@435: } duke@435: duke@435: duke@435: //------------------------------init_keywords---------------------------------- duke@435: // Load the kewords into the global name table duke@435: void ArchDesc::initKeywords(FormDict& names) { duke@435: // Insert keyword strings into Global Name Table. Keywords have a NULL value duke@435: // field for quick easy identification when checking identifiers. duke@435: names.Insert("instruct", NULL); duke@435: names.Insert("operand", NULL); duke@435: names.Insert("attribute", NULL); duke@435: names.Insert("source", NULL); duke@435: names.Insert("register", NULL); duke@435: names.Insert("pipeline", NULL); duke@435: names.Insert("constraint", NULL); duke@435: names.Insert("predicate", NULL); duke@435: names.Insert("encode", NULL); duke@435: names.Insert("enc_class", NULL); duke@435: names.Insert("interface", NULL); duke@435: names.Insert("opcode", NULL); duke@435: names.Insert("ins_encode", NULL); duke@435: names.Insert("match", NULL); duke@435: names.Insert("effect", NULL); duke@435: names.Insert("expand", NULL); duke@435: names.Insert("rewrite", NULL); duke@435: names.Insert("reg_def", NULL); duke@435: names.Insert("reg_class", NULL); duke@435: names.Insert("alloc_class", NULL); duke@435: names.Insert("resource", NULL); duke@435: names.Insert("pipe_class", NULL); duke@435: names.Insert("pipe_desc", NULL); duke@435: } duke@435: duke@435: duke@435: //------------------------------internal_err---------------------------------- duke@435: // Issue a parser error message, and skip to the end of the current line duke@435: void ArchDesc::internal_err(const char *fmt, ...) { duke@435: va_list args; duke@435: duke@435: va_start(args, fmt); duke@435: _internal_errs += emit_msg(0, INTERNAL_ERR, 0, fmt, args); duke@435: va_end(args); duke@435: duke@435: _no_output = 1; duke@435: } duke@435: duke@435: //------------------------------syntax_err---------------------------------- duke@435: // Issue a parser error message, and skip to the end of the current line duke@435: void ArchDesc::syntax_err(int lineno, const char *fmt, ...) { duke@435: va_list args; duke@435: duke@435: va_start(args, fmt); duke@435: _internal_errs += emit_msg(0, SYNERR, lineno, fmt, args); duke@435: va_end(args); duke@435: duke@435: _no_output = 1; duke@435: } duke@435: duke@435: //------------------------------emit_msg--------------------------------------- duke@435: // Emit a user message, typically a warning or error duke@435: int ArchDesc::emit_msg(int quiet, int flag, int line, const char *fmt, duke@435: va_list args) { duke@435: static int last_lineno = -1; duke@435: int i; duke@435: const char *pref; duke@435: duke@435: switch(flag) { duke@435: case 0: pref = "Warning: "; break; duke@435: case 1: pref = "Syntax Error: "; break; duke@435: case 2: pref = "Semantic Error: "; break; duke@435: case 3: pref = "Internal Error: "; break; duke@435: default: assert(0, ""); break; duke@435: } duke@435: duke@435: if (line == last_lineno) return 0; duke@435: last_lineno = line; duke@435: duke@435: if (!quiet) { /* no output if in quiet mode */ duke@435: i = fprintf(errfile, "%s(%d) ", _ADL_file._name, line); duke@435: while (i++ <= 15) fputc(' ', errfile); duke@435: fprintf(errfile, "%-8s:", pref); duke@435: vfprintf(errfile, fmt, args); duke@435: fprintf(errfile, "\n"); } duke@435: return 1; duke@435: } duke@435: duke@435: duke@435: // --------------------------------------------------------------------------- duke@435: //--------Utilities to build mappings for machine registers ------------------ duke@435: // --------------------------------------------------------------------------- duke@435: duke@435: // Construct the name of the register mask. duke@435: static const char *getRegMask(const char *reg_class_name) { duke@435: if( reg_class_name == NULL ) return "RegMask::Empty"; duke@435: duke@435: if (strcmp(reg_class_name,"Universe")==0) { duke@435: return "RegMask::Empty"; duke@435: } else if (strcmp(reg_class_name,"stack_slots")==0) { duke@435: return "(Compile::current()->FIRST_STACK_mask())"; duke@435: } else { duke@435: char *rc_name = toUpper(reg_class_name); duke@435: const char *mask = "_mask"; duke@435: int length = (int)strlen(rc_name) + (int)strlen(mask) + 3; duke@435: char *regMask = new char[length]; duke@435: sprintf(regMask,"%s%s", rc_name, mask); duke@435: return regMask; duke@435: } duke@435: } duke@435: duke@435: // Convert a register class name to its register mask. duke@435: const char *ArchDesc::reg_class_to_reg_mask(const char *rc_name) { duke@435: const char *reg_mask = "RegMask::Empty"; duke@435: duke@435: if( _register ) { duke@435: RegClass *reg_class = _register->getRegClass(rc_name); duke@435: if (reg_class == NULL) { duke@435: syntax_err(0, "Use of an undefined register class %s", rc_name); duke@435: return reg_mask; duke@435: } duke@435: duke@435: // Construct the name of the register mask. duke@435: reg_mask = getRegMask(rc_name); duke@435: } duke@435: duke@435: return reg_mask; duke@435: } duke@435: duke@435: duke@435: // Obtain the name of the RegMask for an OperandForm duke@435: const char *ArchDesc::reg_mask(OperandForm &opForm) { duke@435: const char *regMask = "RegMask::Empty"; duke@435: duke@435: // Check constraints on result's register class duke@435: const char *result_class = opForm.constrained_reg_class(); duke@435: if (!result_class) opForm.dump(); duke@435: assert( result_class, "Resulting register class was not defined for operand"); duke@435: regMask = reg_class_to_reg_mask( result_class ); duke@435: duke@435: return regMask; duke@435: } duke@435: duke@435: // Obtain the name of the RegMask for an InstructForm duke@435: const char *ArchDesc::reg_mask(InstructForm &inForm) { duke@435: const char *result = inForm.reduce_result(); duke@435: assert( result, duke@435: "Did not find result operand or RegMask for this instruction"); duke@435: duke@435: // Instructions producing 'Universe' use RegMask::Empty duke@435: if( strcmp(result,"Universe")==0 ) { duke@435: return "RegMask::Empty"; duke@435: } duke@435: duke@435: // Lookup this result operand and get its register class duke@435: Form *form = (Form*)_globalNames[result]; duke@435: assert( form, "Result operand must be defined"); duke@435: OperandForm *oper = form->is_operand(); coleenp@548: if (oper == NULL) form->dump(); duke@435: assert( oper, "Result must be an OperandForm"); duke@435: return reg_mask( *oper ); duke@435: } duke@435: duke@435: duke@435: // Obtain the STACK_OR_reg_mask name for an OperandForm duke@435: char *ArchDesc::stack_or_reg_mask(OperandForm &opForm) { duke@435: // name of cisc_spillable version duke@435: const char *reg_mask_name = reg_mask(opForm); duke@435: assert( reg_mask_name != NULL, "called with incorrect opForm"); duke@435: duke@435: const char *stack_or = "STACK_OR_"; duke@435: int length = (int)strlen(stack_or) + (int)strlen(reg_mask_name) + 1; duke@435: char *result = new char[length]; duke@435: sprintf(result,"%s%s", stack_or, reg_mask_name); duke@435: duke@435: return result; duke@435: } duke@435: duke@435: // Record that the register class must generate a stack_or_reg_mask duke@435: void ArchDesc::set_stack_or_reg(const char *reg_class_name) { duke@435: if( _register ) { duke@435: RegClass *reg_class = _register->getRegClass(reg_class_name); duke@435: reg_class->_stack_or_reg = true; duke@435: } duke@435: } duke@435: duke@435: duke@435: // Return the type signature for the ideal operation duke@435: const char *ArchDesc::getIdealType(const char *idealOp) { duke@435: // Find last character in idealOp, it specifies the type duke@435: char last_char = 0; duke@435: const char *ptr = idealOp; duke@435: for( ; *ptr != '\0'; ++ptr) { duke@435: last_char = *ptr; duke@435: } duke@435: duke@435: // !!!!! duke@435: switch( last_char ) { duke@435: case 'I': return "TypeInt::INT"; duke@435: case 'P': return "TypePtr::BOTTOM"; coleenp@548: case 'N': return "TypeNarrowOop::BOTTOM"; duke@435: case 'F': return "Type::FLOAT"; duke@435: case 'D': return "Type::DOUBLE"; duke@435: case 'L': return "TypeLong::LONG"; duke@435: case 's': return "TypeInt::CC /*flags*/"; duke@435: default: duke@435: return NULL; duke@435: // !!!!! duke@435: // internal_err("Ideal type %s with unrecognized type\n",idealOp); duke@435: break; duke@435: } duke@435: duke@435: return NULL; duke@435: } duke@435: duke@435: duke@435: duke@435: OperandForm *ArchDesc::constructOperand(const char *ident, duke@435: bool ideal_only) { duke@435: OperandForm *opForm = new OperandForm(ident, ideal_only); duke@435: _globalNames.Insert(ident, opForm); duke@435: addForm(opForm); duke@435: duke@435: return opForm; duke@435: } duke@435: duke@435: duke@435: // Import predefined base types: Set = 1, RegI, RegP, ... duke@435: void ArchDesc::initBaseOpTypes() { duke@435: // Create OperandForm and assign type for each opcode. duke@435: for (int i = 1; i < _last_machine_leaf; ++i) { duke@435: char *ident = (char *)NodeClassNames[i]; duke@435: constructOperand(ident, true); duke@435: } duke@435: // Create InstructForm and assign type for each ideal instruction. duke@435: for ( int j = _last_machine_leaf+1; j < _last_opcode; ++j) { duke@435: char *ident = (char *)NodeClassNames[j]; coleenp@548: if(!strcmp(ident, "ConI") || !strcmp(ident, "ConP") || !strcmp(ident, "ConN") || duke@435: !strcmp(ident, "ConF") || !strcmp(ident, "ConD") || duke@435: !strcmp(ident, "ConL") || !strcmp(ident, "Con" ) || duke@435: !strcmp(ident, "Bool") ) { duke@435: constructOperand(ident, true); duke@435: } duke@435: else { duke@435: InstructForm *insForm = new InstructForm(ident, true); duke@435: // insForm->_opcode = nextUserOpType(ident); duke@435: _globalNames.Insert(ident,insForm); duke@435: addForm(insForm); duke@435: } duke@435: } duke@435: duke@435: { OperandForm *opForm; duke@435: // Create operand type "Universe" for return instructions. duke@435: const char *ident = "Universe"; duke@435: opForm = constructOperand(ident, false); duke@435: duke@435: // Create operand type "label" for branch targets duke@435: ident = "label"; duke@435: opForm = constructOperand(ident, false); duke@435: duke@435: // !!!!! Update - when adding a new sReg/stackSlot type duke@435: // Create operand types "sReg[IPFDL]" for stack slot registers duke@435: opForm = constructOperand("sRegI", false); duke@435: opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots"); duke@435: opForm = constructOperand("sRegP", false); duke@435: opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots"); duke@435: opForm = constructOperand("sRegF", false); duke@435: opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots"); duke@435: opForm = constructOperand("sRegD", false); duke@435: opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots"); duke@435: opForm = constructOperand("sRegL", false); duke@435: opForm->_constraint = new Constraint("ALLOC_IN_RC", "stack_slots"); duke@435: duke@435: // Create operand type "method" for call targets duke@435: ident = "method"; duke@435: opForm = constructOperand(ident, false); duke@435: } duke@435: duke@435: // Create Effect Forms for each of the legal effects duke@435: // USE, DEF, USE_DEF, KILL, USE_KILL duke@435: { duke@435: const char *ident = "USE"; duke@435: Effect *eForm = new Effect(ident); duke@435: _globalNames.Insert(ident, eForm); duke@435: ident = "DEF"; duke@435: eForm = new Effect(ident); duke@435: _globalNames.Insert(ident, eForm); duke@435: ident = "USE_DEF"; duke@435: eForm = new Effect(ident); duke@435: _globalNames.Insert(ident, eForm); duke@435: ident = "KILL"; duke@435: eForm = new Effect(ident); duke@435: _globalNames.Insert(ident, eForm); duke@435: ident = "USE_KILL"; duke@435: eForm = new Effect(ident); duke@435: _globalNames.Insert(ident, eForm); duke@435: ident = "TEMP"; duke@435: eForm = new Effect(ident); duke@435: _globalNames.Insert(ident, eForm); duke@435: } duke@435: duke@435: // duke@435: // Build mapping from ideal names to ideal indices duke@435: int idealIndex = 0; duke@435: for (idealIndex = 1; idealIndex < _last_machine_leaf; ++idealIndex) { duke@435: const char *idealName = NodeClassNames[idealIndex]; twisti@1038: _idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex); duke@435: } duke@435: for ( idealIndex = _last_machine_leaf+1; duke@435: idealIndex < _last_opcode; ++idealIndex) { duke@435: const char *idealName = NodeClassNames[idealIndex]; twisti@1038: _idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex); duke@435: } duke@435: duke@435: } duke@435: duke@435: duke@435: //---------------------------addSUNcopyright------------------------------- duke@435: // output SUN copyright info duke@435: void ArchDesc::addSunCopyright(char* legal, int size, FILE *fp) { duke@435: fwrite(legal, size, 1, fp); duke@435: fprintf(fp,"\n"); duke@435: fprintf(fp,"// Machine Generated File. Do Not Edit!\n"); duke@435: fprintf(fp,"\n"); duke@435: } duke@435: duke@435: //---------------------------machineDependentIncludes-------------------------- duke@435: // output #include declarations for machine specific files duke@435: void ArchDesc::machineDependentIncludes(ADLFILE &adlfile) { duke@435: const char *basename = adlfile._name; duke@435: const char *cp; duke@435: for (cp = basename; *cp; cp++) duke@435: if (*cp == '/') basename = cp+1; duke@435: duke@435: // Build #include lines duke@435: fprintf(adlfile._fp, "\n"); duke@435: fprintf(adlfile._fp, "#include \"incls/_precompiled.incl\"\n"); duke@435: fprintf(adlfile._fp, "#include \"incls/_%s.incl\"\n",basename); duke@435: fprintf(adlfile._fp, "\n"); duke@435: duke@435: } duke@435: duke@435: duke@435: //---------------------------addPreprocessorChecks----------------------------- duke@435: // Output C preprocessor code to verify the backend compilation environment. duke@435: // The idea is to force code produced by "adlc -DHS64" to be compiled by a duke@435: // command of the form "CC ... -DHS64 ...", so that any #ifdefs in the source duke@435: // blocks select C code that is consistent with adlc's selections of AD code. duke@435: void ArchDesc::addPreprocessorChecks(FILE *fp) { duke@435: const char* flag; duke@435: _preproc_list.reset(); duke@435: if (_preproc_list.count() > 0 && !_preproc_list.current_is_signal()) { duke@435: fprintf(fp, "// Check consistency of C++ compilation with ADLC options:\n"); duke@435: } duke@435: for (_preproc_list.reset(); (flag = _preproc_list.iter()) != NULL; ) { duke@435: if (_preproc_list.current_is_signal()) break; duke@435: char* def = get_preproc_def(flag); duke@435: fprintf(fp, "// Check adlc "); duke@435: if (def) duke@435: fprintf(fp, "-D%s=%s\n", flag, def); duke@435: else fprintf(fp, "-U%s\n", flag); duke@435: fprintf(fp, "#%s %s\n", duke@435: def ? "ifndef" : "ifdef", flag); duke@435: fprintf(fp, "# error \"%s %s be defined\"\n", duke@435: flag, def ? "must" : "must not"); duke@435: fprintf(fp, "#endif // %s\n", flag); duke@435: } duke@435: } duke@435: duke@435: duke@435: // Convert operand name into enum name duke@435: const char *ArchDesc::machOperEnum(const char *opName) { duke@435: return ArchDesc::getMachOperEnum(opName); duke@435: } duke@435: duke@435: // Convert operand name into enum name duke@435: const char *ArchDesc::getMachOperEnum(const char *opName) { duke@435: return (opName ? toUpper(opName) : opName); duke@435: } duke@435: duke@435: //---------------------------buildMustCloneMap----------------------------- duke@435: // Flag cases when machine needs cloned values or instructions duke@435: void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) { duke@435: // Build external declarations for mappings duke@435: fprintf(fp_hpp, "// Mapping from machine-independent opcode to boolean\n"); duke@435: fprintf(fp_hpp, "// Flag cases where machine needs cloned values or instructions\n"); duke@435: fprintf(fp_hpp, "extern const char must_clone[];\n"); duke@435: fprintf(fp_hpp, "\n"); duke@435: duke@435: // Build mapping from ideal names to ideal indices duke@435: fprintf(fp_cpp, "\n"); duke@435: fprintf(fp_cpp, "// Mapping from machine-independent opcode to boolean\n"); duke@435: fprintf(fp_cpp, "const char must_clone[] = {\n"); duke@435: for (int idealIndex = 0; idealIndex < _last_opcode; ++idealIndex) { duke@435: int must_clone = 0; duke@435: const char *idealName = NodeClassNames[idealIndex]; duke@435: // Previously selected constants for cloning duke@435: // !!!!! duke@435: // These are the current machine-dependent clones duke@435: if ( strcmp(idealName,"CmpI") == 0 duke@435: || strcmp(idealName,"CmpU") == 0 duke@435: || strcmp(idealName,"CmpP") == 0 coleenp@548: || strcmp(idealName,"CmpN") == 0 duke@435: || strcmp(idealName,"CmpL") == 0 duke@435: || strcmp(idealName,"CmpD") == 0 duke@435: || strcmp(idealName,"CmpF") == 0 duke@435: || strcmp(idealName,"FastLock") == 0 duke@435: || strcmp(idealName,"FastUnlock") == 0 duke@435: || strcmp(idealName,"Bool") == 0 duke@435: || strcmp(idealName,"Binary") == 0 ) { duke@435: // Removed ConI from the must_clone list. CPUs that cannot use duke@435: // large constants as immediates manifest the constant as an duke@435: // instruction. The must_clone flag prevents the constant from duke@435: // floating up out of loops. duke@435: must_clone = 1; duke@435: } duke@435: fprintf(fp_cpp, " %d%s // %s: %d\n", must_clone, duke@435: (idealIndex != (_last_opcode - 1)) ? "," : " // no trailing comma", duke@435: idealName, idealIndex); duke@435: } duke@435: // Finish defining table duke@435: fprintf(fp_cpp, "};\n"); duke@435: }