Path: blob/master/src/hotspot/share/adlc/dfa.cpp
41144 views
/*1* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324// DFA.CPP - Method definitions for outputting the matcher DFA from ADLC25#include "adlc.hpp"2627//---------------------------Switches for debugging output---------------------28static bool debug_output = false;29static bool debug_output1 = false; // top level chain rules3031//---------------------------Production State----------------------------------32static const char *knownInvalid = "knownInvalid"; // The result does NOT have a rule defined33static const char *knownValid = "knownValid"; // The result must be produced by a rule34static const char *unknownValid = "unknownValid"; // Unknown (probably due to a child or predicate constraint)3536static const char *noConstraint = "noConstraint"; // No constraints seen so far37static const char *hasConstraint = "hasConstraint"; // Within the first constraint383940//------------------------------Production------------------------------------41// Track the status of productions for a particular result42class Production {43public:44const char *_result;45const char *_constraint;46const char *_valid;47Expr *_cost_lb; // Cost lower bound for this production48Expr *_cost_ub; // Cost upper bound for this production4950public:51Production(const char *result, const char *constraint, const char *valid);52~Production() {};5354void initialize(); // reset to be an empty container5556const char *valid() const { return _valid; }57Expr *cost_lb() const { return (Expr *)_cost_lb; }58Expr *cost_ub() const { return (Expr *)_cost_ub; }5960void print();61};626364//------------------------------ProductionState--------------------------------65// Track the status of all production rule results66// Reset for each root opcode (e.g., Op_RegI, Op_AddI, ...)67class ProductionState {68private:69Dict _production; // map result of production, char*, to information or NULL70const char *_constraint;7172public:73// cmpstr does string comparisions. hashstr computes a key.74ProductionState(Arena *arena) : _production(cmpstr, hashstr, arena) { initialize(); };75~ProductionState() { };7677void initialize(); // reset local and dictionary state7879const char *constraint();80void set_constraint(const char *constraint); // currently working inside of constraints8182const char *valid(const char *result); // unknownValid, or status for this production83void set_valid(const char *result); // if not constrained, set status to knownValid8485Expr *cost_lb(const char *result);86Expr *cost_ub(const char *result);87void set_cost_bounds(const char *result, const Expr *cost, bool has_state_check, bool has_cost_check);8889// Return the Production associated with the result,90// or create a new Production and insert it into the dictionary.91Production *getProduction(const char *result);9293void print();9495private:96// Disable public use of constructor, copy-ctor, ...97ProductionState( ) : _production(cmpstr, hashstr, Form::arena) { assert( false, "NotImplemented"); };98ProductionState( const ProductionState & ) : _production(cmpstr, hashstr, Form::arena) { assert( false, "NotImplemented"); }; // Deep-copy99};100101102//---------------------------Helper Functions----------------------------------103// cost_check template:104// 1) if (STATE__NOT_YET_VALID(EBXREGI) || _cost[EBXREGI] > c) {105// 2) DFA_PRODUCTION(EBXREGI, cmovI_memu_rule, c)106// 3) }107//108static void cost_check(FILE *fp, const char *spaces,109const char *arrayIdx, const Expr *cost, const char *rule, ProductionState &status) {110bool state_check = false; // true if this production needs to check validity111bool cost_check = false; // true if this production needs to check cost112bool cost_is_above_upper_bound = false; // true if this production is unnecessary due to high cost113bool cost_is_below_lower_bound = false; // true if this production replaces a higher cost production114115// Get information about this production116const Expr *previous_ub = status.cost_ub(arrayIdx);117if( !previous_ub->is_unknown() ) {118if( previous_ub->less_than_or_equal(cost) ) {119cost_is_above_upper_bound = true;120if( debug_output ) { fprintf(fp, "// Previous rule with lower cost than: %s === %s_rule costs %s\n", arrayIdx, rule, cost->as_string()); }121}122}123124const Expr *previous_lb = status.cost_lb(arrayIdx);125if( !previous_lb->is_unknown() ) {126if( cost->less_than_or_equal(previous_lb) ) {127cost_is_below_lower_bound = true;128if( debug_output ) { fprintf(fp, "// Previous rule with higher cost\n"); }129}130}131132// line 1)133// Check for validity and compare to other match costs134const char *validity_check = status.valid(arrayIdx);135if( validity_check == unknownValid ) {136fprintf(fp, "%sif (STATE__NOT_YET_VALID(%s) || _cost[%s] > %s) {\n", spaces, arrayIdx, arrayIdx, cost->as_string());137state_check = true;138cost_check = true;139}140else if( validity_check == knownInvalid ) {141if( debug_output ) { fprintf(fp, "%s// %s KNOWN_INVALID \n", spaces, arrayIdx); }142}143else if( validity_check == knownValid ) {144if( cost_is_above_upper_bound ) {145// production cost is known to be too high.146return;147} else if( cost_is_below_lower_bound ) {148// production will unconditionally overwrite a previous production that had higher cost149} else {150fprintf(fp, "%sif ( /* %s KNOWN_VALID || */ _cost[%s] > %s) {\n", spaces, arrayIdx, arrayIdx, cost->as_string());151cost_check = true;152}153}154155// line 2)156fprintf(fp, "%s DFA_PRODUCTION(%s, %s_rule, %s)", spaces, arrayIdx, rule, cost->as_string() );157if (validity_check == knownValid) {158if (cost_is_below_lower_bound) {159fprintf(fp, "\t // overwrites higher cost rule");160}161}162fprintf(fp, "\n");163164// line 3)165if( cost_check || state_check ) {166fprintf(fp, "%s}\n", spaces);167}168169status.set_cost_bounds(arrayIdx, cost, state_check, cost_check);170171// Update ProductionState172if( validity_check != knownValid ) {173// set State vector if not previously known174status.set_valid(arrayIdx);175}176}177178179//---------------------------child_test----------------------------------------180// Example:181// STATE__VALID_CHILD(_kids[0], FOO) && STATE__VALID_CHILD(_kids[1], BAR)182// Macro equivalent to: _kids[0]->valid(FOO) && _kids[1]->valid(BAR)183//184static void child_test(FILE *fp, MatchList &mList) {185if (mList._lchild) { // If left child, check it186const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild);187fprintf(fp, "STATE__VALID_CHILD(_kids[0], %s)", lchild_to_upper);188delete[] lchild_to_upper;189}190if (mList._lchild && mList._rchild) { // If both, add the "&&"191fprintf(fp, " && ");192}193if (mList._rchild) { // If right child, check it194const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild);195fprintf(fp, "STATE__VALID_CHILD(_kids[1], %s)", rchild_to_upper);196delete[] rchild_to_upper;197}198}199200//---------------------------calc_cost-----------------------------------------201// Example:202// unsigned int c = _kids[0]->_cost[FOO] + _kids[1]->_cost[BAR] + 5;203//204Expr *ArchDesc::calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status) {205fprintf(fp, "%sunsigned int c = ", spaces);206Expr *c = new Expr("0");207if (mList._lchild) { // If left child, add it in208const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild);209sprintf(Expr::buffer(), "_kids[0]->_cost[%s]", lchild_to_upper);210c->add(Expr::buffer());211delete[] lchild_to_upper;212}213if (mList._rchild) { // If right child, add it in214const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild);215sprintf(Expr::buffer(), "_kids[1]->_cost[%s]", rchild_to_upper);216c->add(Expr::buffer());217delete[] rchild_to_upper;218}219// Add in cost of this rule220const char *mList_cost = mList.get_cost();221c->add(mList_cost, *this);222223fprintf(fp, "%s;\n", c->as_string());224c->set_external_name("c");225return c;226}227228229//---------------------------gen_match-----------------------------------------230void ArchDesc::gen_match(FILE *fp, MatchList &mList, ProductionState &status, Dict &operands_chained_from) {231const char *spaces4 = " ";232const char *spaces6 = " ";233234fprintf(fp, "%s", spaces4);235// Only generate child tests if this is not a leaf node236bool has_child_constraints = mList._lchild || mList._rchild;237const char *predicate_test = mList.get_pred();238if (has_child_constraints || predicate_test) {239// Open the child-and-predicate-test braces240fprintf(fp, "if( ");241status.set_constraint(hasConstraint);242child_test(fp, mList);243// Only generate predicate test if one exists for this match244if (predicate_test) {245if (has_child_constraints) {246fprintf(fp," &&\n");247}248fprintf(fp, "%s %s", spaces6, predicate_test);249}250// End of outer tests251fprintf(fp," ) ");252} else {253// No child or predicate test needed254status.set_constraint(noConstraint);255}256257// End of outer tests258fprintf(fp,"{\n");259260// Calculate cost of this match261const Expr *cost = calc_cost(fp, spaces6, mList, status);262// Check against other match costs, and update cost & rule vectors263cost_check(fp, spaces6, ArchDesc::getMachOperEnum(mList._resultStr), cost, mList._opcode, status);264265// If this is a member of an operand class, update the class cost & rule266expand_opclass( fp, spaces6, cost, mList._resultStr, status);267268// Check if this rule should be used to generate the chains as well.269const char *rule = /* set rule to "Invalid" for internal operands */270strcmp(mList._opcode, mList._resultStr) ? mList._opcode : "Invalid";271272// If this rule produces an operand which has associated chain rules,273// update the operands with the chain rule + this rule cost & this rule.274chain_rule(fp, spaces6, mList._resultStr, cost, rule, operands_chained_from, status);275276// Close the child-and-predicate-test braces277fprintf(fp, " }\n");278279}280281282//---------------------------expand_opclass------------------------------------283// Chain from one result_type to all other members of its operand class284void ArchDesc::expand_opclass(FILE *fp, const char *indent, const Expr *cost,285const char *result_type, ProductionState &status) {286const Form *form = _globalNames[result_type];287OperandForm *op = form ? form->is_operand() : NULL;288if( op && op->_classes.count() > 0 ) {289if( debug_output ) { fprintf(fp, "// expand operand classes for operand: %s \n", (char *)op->_ident ); } // %%%%% Explanation290// Iterate through all operand classes which include this operand291op->_classes.reset();292const char *oclass;293// Expr *cCost = new Expr(cost);294while( (oclass = op->_classes.iter()) != NULL )295// Check against other match costs, and update cost & rule vectors296cost_check(fp, indent, ArchDesc::getMachOperEnum(oclass), cost, result_type, status);297}298}299300//---------------------------chain_rule----------------------------------------301// Starting at 'operand', check if we know how to automatically generate other results302void ArchDesc::chain_rule(FILE *fp, const char *indent, const char *operand,303const Expr *icost, const char *irule, Dict &operands_chained_from, ProductionState &status) {304305// Check if we have already generated chains from this starting point306if( operands_chained_from[operand] != NULL ) {307return;308} else {309operands_chained_from.Insert( operand, operand);310}311if( debug_output ) { fprintf(fp, "// chain rules starting from: %s and %s \n", (char *)operand, (char *)irule); } // %%%%% Explanation312313ChainList *lst = (ChainList *)_chainRules[operand];314if (lst) {315// printf("\nChain from <%s> at cost #%s\n",operand, icost ? icost : "_");316const char *result, *cost, *rule;317for(lst->reset(); (lst->iter(result,cost,rule)) == true; ) {318// Do not generate operands that are already available319if( operands_chained_from[result] != NULL ) {320continue;321} else {322// Compute the cost for previous match + chain_rule_cost323// total_cost = icost + cost;324Expr *total_cost = icost->clone(); // icost + cost325total_cost->add(cost, *this);326327// Check for transitive chain rules328Form *form = (Form *)_globalNames[rule];329if ( ! form->is_instruction()) {330// printf(" result=%s cost=%s rule=%s\n", result, total_cost, rule);331// Check against other match costs, and update cost & rule vectors332const char *reduce_rule = strcmp(irule,"Invalid") ? irule : rule;333cost_check(fp, indent, ArchDesc::getMachOperEnum(result), total_cost, reduce_rule, status);334chain_rule(fp, indent, result, total_cost, irule, operands_chained_from, status);335} else {336// printf(" result=%s cost=%s rule=%s\n", result, total_cost, rule);337// Check against other match costs, and update cost & rule vectors338cost_check(fp, indent, ArchDesc::getMachOperEnum(result), total_cost, rule, status);339chain_rule(fp, indent, result, total_cost, rule, operands_chained_from, status);340}341342// If this is a member of an operand class, update class cost & rule343expand_opclass( fp, indent, total_cost, result, status );344}345}346}347}348349//---------------------------prune_matchlist-----------------------------------350// Check for duplicate entries in a matchlist, and prune out the higher cost351// entry.352void ArchDesc::prune_matchlist(Dict &minimize, MatchList &mlist) {353354}355356//---------------------------buildDFA------------------------------------------357// DFA is a large switch with case statements for each ideal opcode encountered358// in any match rule in the ad file. Each case has a series of if's to handle359// the match or fail decisions. The matches test the cost function of that360// rule, and prune any cases which are higher cost for the same reduction.361// In order to generate the DFA we walk the table of ideal opcode/MatchList362// pairs generated by the ADLC front end to build the contents of the case363// statements (a series of if statements).364void ArchDesc::buildDFA(FILE* fp) {365int i;366// Remember operands that are the starting points for chain rules.367// Prevent cycles by checking if we have already generated chain.368Dict operands_chained_from(cmpstr, hashstr, Form::arena);369370// Hash inputs to match rules so that final DFA contains only one entry for371// each match pattern which is the low cost entry.372Dict minimize(cmpstr, hashstr, Form::arena);373374// Track status of dfa for each resulting production375// reset for each ideal root.376ProductionState status(Form::arena);377378// Output the start of the DFA method into the output file379380fprintf(fp, "\n");381fprintf(fp, "//------------------------- Source -----------------------------------------\n");382// Do not put random source code into the DFA.383// If there are constants which need sharing, put them in "source_hpp" forms.384// _source.output(fp);385fprintf(fp, "\n");386fprintf(fp, "//------------------------- Attributes -------------------------------------\n");387_attributes.output(fp);388fprintf(fp, "\n");389fprintf(fp, "//------------------------- Macros -----------------------------------------\n");390fprintf(fp, "#define DFA_PRODUCTION(result, rule, cost)\\\n");391fprintf(fp, " assert(rule < (1 << 15), \"too many rules\"); _cost[ (result) ] = cost; _rule[ (result) ] = (rule << 1) | 0x1;\n");392fprintf(fp, "\n");393394fprintf(fp, "//------------------------- DFA --------------------------------------------\n");395396fprintf(fp,397"// DFA is a large switch with case statements for each ideal opcode encountered\n"398"// in any match rule in the ad file. Each case has a series of if's to handle\n"399"// the match or fail decisions. The matches test the cost function of that\n"400"// rule, and prune any cases which are higher cost for the same reduction.\n"401"// In order to generate the DFA we walk the table of ideal opcode/MatchList\n"402"// pairs generated by the ADLC front end to build the contents of the case\n"403"// statements (a series of if statements).\n"404);405fprintf(fp, "\n");406fprintf(fp, "\n");407if (_dfa_small) {408// Now build the individual routines just like the switch entries in large version409// Iterate over the table of MatchLists, start at first valid opcode of 1410for (i = 1; i < _last_opcode; i++) {411if (_mlistab[i] == NULL) continue;412// Generate the routine header statement for this opcode413fprintf(fp, "void State::_sub_Op_%s(const Node *n){\n", NodeClassNames[i]);414// Generate body. Shared for both inline and out-of-line version415gen_dfa_state_body(fp, minimize, status, operands_chained_from, i);416// End of routine417fprintf(fp, "}\n");418}419}420fprintf(fp, "bool State::DFA");421fprintf(fp, "(int opcode, const Node *n) {\n");422fprintf(fp, " switch(opcode) {\n");423424// Iterate over the table of MatchLists, start at first valid opcode of 1425for (i = 1; i < _last_opcode; i++) {426if (_mlistab[i] == NULL) continue;427// Generate the case statement for this opcode428if (_dfa_small) {429fprintf(fp, " case Op_%s: { _sub_Op_%s(n);\n", NodeClassNames[i], NodeClassNames[i]);430} else {431fprintf(fp, " case Op_%s: {\n", NodeClassNames[i]);432// Walk the list, compacting it433gen_dfa_state_body(fp, minimize, status, operands_chained_from, i);434}435// Print the "break"436fprintf(fp, " break;\n");437fprintf(fp, " }\n");438}439440// Generate the default case for switch(opcode)441fprintf(fp, " \n");442fprintf(fp, " default:\n");443fprintf(fp, " tty->print(\"Default case invoked for: \\n\");\n");444fprintf(fp, " tty->print(\" opcode = %cd, \\\"%cs\\\"\\n\", opcode, NodeClassNames[opcode]);\n", '%', '%');445fprintf(fp, " return false;\n");446fprintf(fp, " }\n");447448// Return status, indicating a successful match.449fprintf(fp, " return true;\n");450// Generate the closing brace for method Matcher::DFA451fprintf(fp, "}\n");452Expr::check_buffers();453}454455456class dfa_shared_preds {457enum { count = 3 IA32_ONLY( + 1 ) };458459static bool _found[count];460static const char* _type [count];461static const char* _var [count];462static const char* _pred [count];463464static void check_index(int index) { assert( 0 <= index && index < count, "Invalid index"); }465466// Confirm that this is a separate sub-expression.467// Only need to catch common cases like " ... && shared ..."468// and avoid hazardous ones like "...->shared"469static bool valid_loc(char *pred, char *shared) {470// start of predicate is valid471if( shared == pred ) return true;472473// Check previous character and recurse if needed474char *prev = shared - 1;475char c = *prev;476switch( c ) {477case ' ':478case '\n':479return dfa_shared_preds::valid_loc(pred, prev);480case '!':481case '(':482case '<':483case '=':484return true;485case '"': // such as: #line 10 "myfile.ad"\n mypredicate486return true;487case '|':488if (prev != pred && *(prev-1) == '|') return true;489break;490case '&':491if (prev != pred && *(prev-1) == '&') return true;492break;493default:494return false;495}496497return false;498}499500public:501502static bool found(int index){ check_index(index); return _found[index]; }503static void set_found(int index, bool val) { check_index(index); _found[index] = val; }504static void reset_found() {505for( int i = 0; i < count; ++i ) { _found[i] = false; }506};507508static const char* type(int index) { check_index(index); return _type[index]; }509static const char* var (int index) { check_index(index); return _var [index]; }510static const char* pred(int index) { check_index(index); return _pred[index]; }511512// Check each predicate in the MatchList for common sub-expressions513static void cse_matchlist(MatchList *matchList) {514for( MatchList *mList = matchList; mList != NULL; mList = mList->get_next() ) {515Predicate* predicate = mList->get_pred_obj();516char* pred = mList->get_pred();517if( pred != NULL ) {518for(int index = 0; index < count; ++index ) {519const char *shared_pred = dfa_shared_preds::pred(index);520const char *shared_pred_var = dfa_shared_preds::var(index);521bool result = dfa_shared_preds::cse_predicate(predicate, shared_pred, shared_pred_var);522if( result ) dfa_shared_preds::set_found(index, true);523}524}525}526}527528// If the Predicate contains a common sub-expression, replace the Predicate's529// string with one that uses the variable name.530static bool cse_predicate(Predicate* predicate, const char *shared_pred, const char *shared_pred_var) {531bool result = false;532char *pred = predicate->_pred;533if( pred != NULL ) {534char *new_pred = pred;535for( char *shared_pred_loc = strstr(new_pred, shared_pred);536shared_pred_loc != NULL && dfa_shared_preds::valid_loc(new_pred,shared_pred_loc);537shared_pred_loc = strstr(new_pred, shared_pred) ) {538// Do not modify the original predicate string, it is shared539if( new_pred == pred ) {540new_pred = strdup(pred);541shared_pred_loc = strstr(new_pred, shared_pred);542}543// Replace shared_pred with variable name544strncpy(shared_pred_loc, shared_pred_var, strlen(shared_pred_var));545}546// Install new predicate547if( new_pred != pred ) {548predicate->_pred = new_pred;549result = true;550}551}552return result;553}554555// Output the hoisted common sub-expression if we found it in predicates556static void generate_cse(FILE *fp) {557for(int j = 0; j < count; ++j ) {558if( dfa_shared_preds::found(j) ) {559const char *shared_pred_type = dfa_shared_preds::type(j);560const char *shared_pred_var = dfa_shared_preds::var(j);561const char *shared_pred = dfa_shared_preds::pred(j);562fprintf(fp, " %s %s = %s;\n", shared_pred_type, shared_pred_var, shared_pred);563}564}565}566};567// shared predicates, _var and _pred entry should be the same length568bool dfa_shared_preds::_found[dfa_shared_preds::count] = { false, false, false IA32_ONLY(COMMA false) };569const char* dfa_shared_preds::_type [dfa_shared_preds::count] = { "int", "jlong", "intptr_t" IA32_ONLY(COMMA "bool") };570const char* dfa_shared_preds::_var [dfa_shared_preds::count] = { "_n_get_int__", "_n_get_long__", "_n_get_intptr_t__" IA32_ONLY(COMMA "Compile__current____select_24_bit_instr__") };571const char* dfa_shared_preds::_pred [dfa_shared_preds::count] = { "n->get_int()", "n->get_long()", "n->get_intptr_t()" IA32_ONLY(COMMA "Compile::current()->select_24_bit_instr()") };572573void ArchDesc::gen_dfa_state_body(FILE* fp, Dict &minimize, ProductionState &status, Dict &operands_chained_from, int i) {574// Start the body of each Op_XXX sub-dfa with a clean state.575status.initialize();576577// Walk the list, compacting it578MatchList* mList = _mlistab[i];579do {580// Hash each entry using inputs as key and pointer as data.581// If there is already an entry, keep the one with lower cost, and582// remove the other one from the list.583prune_matchlist(minimize, *mList);584// Iterate585mList = mList->get_next();586} while(mList != NULL);587588// Hoist previously specified common sub-expressions out of predicates589dfa_shared_preds::reset_found();590dfa_shared_preds::cse_matchlist(_mlistab[i]);591dfa_shared_preds::generate_cse(fp);592593mList = _mlistab[i];594595// Walk the list again, generating code596do {597// Each match can generate its own chains598operands_chained_from.Clear();599gen_match(fp, *mList, status, operands_chained_from);600mList = mList->get_next();601} while(mList != NULL);602// Fill in any chain rules which add instructions603// These can generate their own chains as well.604operands_chained_from.Clear(); //605if( debug_output1 ) { fprintf(fp, "// top level chain rules for: %s \n", (char *)NodeClassNames[i]); } // %%%%% Explanation606const Expr *zeroCost = new Expr("0");607chain_rule(fp, " ", (char *)NodeClassNames[i], zeroCost, "Invalid",608operands_chained_from, status);609}610611612613//------------------------------Expr------------------------------------------614Expr *Expr::_unknown_expr = NULL;615char Expr::string_buffer[STRING_BUFFER_LENGTH];616char Expr::external_buffer[STRING_BUFFER_LENGTH];617bool Expr::_init_buffers = Expr::init_buffers();618619Expr::Expr() {620_external_name = NULL;621_expr = "Invalid_Expr";622_min_value = Expr::Max;623_max_value = Expr::Zero;624}625Expr::Expr(const char *cost) {626_external_name = NULL;627628int intval = 0;629if( cost == NULL ) {630_expr = "0";631_min_value = Expr::Zero;632_max_value = Expr::Zero;633}634else if( ADLParser::is_int_token(cost, intval) ) {635_expr = cost;636_min_value = intval;637_max_value = intval;638}639else {640assert( strcmp(cost,"0") != 0, "Recognize string zero as an int");641_expr = cost;642_min_value = Expr::Zero;643_max_value = Expr::Max;644}645}646647Expr::Expr(const char *name, const char *expression, int min_value, int max_value) {648_external_name = name;649_expr = expression ? expression : name;650_min_value = min_value;651_max_value = max_value;652assert(_min_value >= 0 && _min_value <= Expr::Max, "value out of range");653assert(_max_value >= 0 && _max_value <= Expr::Max, "value out of range");654}655656Expr *Expr::clone() const {657Expr *cost = new Expr();658cost->_external_name = _external_name;659cost->_expr = _expr;660cost->_min_value = _min_value;661cost->_max_value = _max_value;662663return cost;664}665666void Expr::add(const Expr *c) {667// Do not update fields until all computation is complete668const char *external = compute_external(this, c);669const char *expr = compute_expr(this, c);670int min_value = compute_min (this, c);671int max_value = compute_max (this, c);672673_external_name = external;674_expr = expr;675_min_value = min_value;676_max_value = max_value;677}678679void Expr::add(const char *c) {680Expr *cost = new Expr(c);681add(cost);682}683684void Expr::add(const char *c, ArchDesc &AD) {685const Expr *e = AD.globalDefs()[c];686if( e != NULL ) {687// use the value of 'c' defined in <arch>.ad688add(e);689} else {690Expr *cost = new Expr(c);691add(cost);692}693}694695const char *Expr::compute_external(const Expr *c1, const Expr *c2) {696const char * result = NULL;697698// Preserve use of external name which has a zero value699if( c1->_external_name != NULL ) {700if( c2->is_zero() ) {701snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s", c1->as_string());702} else {703snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s+%s", c1->as_string(), c2->as_string());704}705string_buffer[STRING_BUFFER_LENGTH - 1] = '\0';706result = strdup(string_buffer);707}708else if( c2->_external_name != NULL ) {709if( c1->is_zero() ) {710snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s", c2->_external_name);711} else {712snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s + %s", c1->as_string(), c2->as_string());713}714string_buffer[STRING_BUFFER_LENGTH - 1] = '\0';715result = strdup(string_buffer);716}717return result;718}719720const char *Expr::compute_expr(const Expr *c1, const Expr *c2) {721if( !c1->is_zero() ) {722if( c2->is_zero() ) {723snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s", c1->_expr);724} else {725snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s+%s", c1->_expr, c2->_expr);726}727}728else if( !c2->is_zero() ) {729snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s", c2->_expr);730}731else {732sprintf( string_buffer, "0");733}734string_buffer[STRING_BUFFER_LENGTH - 1] = '\0';735char *cost = strdup(string_buffer);736737return cost;738}739740int Expr::compute_min(const Expr *c1, const Expr *c2) {741int v1 = c1->_min_value;742int v2 = c2->_min_value;743assert(0 <= v2 && v2 <= Expr::Max, "sanity");744assert(v1 <= Expr::Max - v2, "Invalid cost computation");745746return v1 + v2;747}748749750int Expr::compute_max(const Expr *c1, const Expr *c2) {751int v1 = c1->_max_value;752int v2 = c2->_max_value;753754// Check for overflow without producing UB. If v2 is positive755// and not larger than Max, the subtraction cannot underflow.756assert(0 <= v2 && v2 <= Expr::Max, "sanity");757if (v1 > Expr::Max - v2) {758return Expr::Max;759}760761return v1 + v2;762}763764void Expr::print() const {765if( _external_name != NULL ) {766printf(" %s == (%s) === [%d, %d]\n", _external_name, _expr, _min_value, _max_value);767} else {768printf(" %s === [%d, %d]\n", _expr, _min_value, _max_value);769}770}771772void Expr::print_define(FILE *fp) const {773assert( _external_name != NULL, "definition does not have a name");774assert( _min_value == _max_value, "Expect user definitions to have constant value");775fprintf(fp, "#define %s (%s) \n", _external_name, _expr);776fprintf(fp, "// value == %d \n", _min_value);777}778779void Expr::print_assert(FILE *fp) const {780assert( _external_name != NULL, "definition does not have a name");781assert( _min_value == _max_value, "Expect user definitions to have constant value");782fprintf(fp, " assert( %s == %d, \"Expect (%s) to equal %d\");\n", _external_name, _min_value, _expr, _min_value);783}784785Expr *Expr::get_unknown() {786if( Expr::_unknown_expr == NULL ) {787Expr::_unknown_expr = new Expr();788}789790return Expr::_unknown_expr;791}792793bool Expr::init_buffers() {794// Fill buffers with 0795for( int i = 0; i < STRING_BUFFER_LENGTH; ++i ) {796external_buffer[i] = '\0';797string_buffer[i] = '\0';798}799800return true;801}802803bool Expr::check_buffers() {804// returns 'true' if buffer use may have overflowed805bool ok = true;806for( int i = STRING_BUFFER_LENGTH - 100; i < STRING_BUFFER_LENGTH; ++i) {807if( external_buffer[i] != '\0' || string_buffer[i] != '\0' ) {808ok = false;809assert( false, "Expr:: Buffer overflow");810}811}812813return ok;814}815816817//------------------------------ExprDict---------------------------------------818// Constructor819ExprDict::ExprDict( CmpKey cmp, Hash hash, Arena *arena )820: _expr(cmp, hash, arena), _defines() {821}822ExprDict::~ExprDict() {823}824825// Return # of name-Expr pairs in dict826int ExprDict::Size(void) const {827return _expr.Size();828}829830// define inserts the given key-value pair into the dictionary,831// and records the name in order for later output, ...832const Expr *ExprDict::define(const char *name, Expr *expr) {833const Expr *old_expr = (*this)[name];834assert(old_expr == NULL, "Implementation does not support redefinition");835836_expr.Insert(name, expr);837_defines.addName(name);838839return old_expr;840}841842// Insert inserts the given key-value pair into the dictionary. The prior843// value of the key is returned; NULL if the key was not previously defined.844const Expr *ExprDict::Insert(const char *name, Expr *expr) {845return (Expr*)_expr.Insert((void*)name, (void*)expr);846}847848// Finds the value of a given key; or NULL if not found.849// The dictionary is NOT changed.850const Expr *ExprDict::operator [](const char *name) const {851return (Expr*)_expr[name];852}853854void ExprDict::print_defines(FILE *fp) {855fprintf(fp, "\n");856const char *name = NULL;857for( _defines.reset(); (name = _defines.iter()) != NULL; ) {858const Expr *expr = (const Expr*)_expr[name];859assert( expr != NULL, "name in ExprDict without matching Expr in dictionary");860expr->print_define(fp);861}862}863void ExprDict::print_asserts(FILE *fp) {864fprintf(fp, "\n");865fprintf(fp, " // Following assertions generated from definition section\n");866const char *name = NULL;867for( _defines.reset(); (name = _defines.iter()) != NULL; ) {868const Expr *expr = (const Expr*)_expr[name];869assert( expr != NULL, "name in ExprDict without matching Expr in dictionary");870expr->print_assert(fp);871}872}873874// Print out the dictionary contents as key-value pairs875static void dumpekey(const void* key) { fprintf(stdout, "%s", (char*) key); }876static void dumpexpr(const void* expr) { fflush(stdout); ((Expr*)expr)->print(); }877878void ExprDict::dump() {879_expr.print(dumpekey, dumpexpr);880}881882883//------------------------------ExprDict::private------------------------------884// Disable public use of constructor, copy-ctor, operator =, operator ==885ExprDict::ExprDict( ) : _expr(cmpkey,hashkey), _defines() {886assert( false, "NotImplemented");887}888ExprDict::ExprDict( const ExprDict & ) : _expr(cmpkey,hashkey), _defines() {889assert( false, "NotImplemented");890}891ExprDict &ExprDict::operator =( const ExprDict &rhs) {892assert( false, "NotImplemented");893_expr = rhs._expr;894return *this;895}896// == compares two dictionaries; they must have the same keys (their keys897// must match using CmpKey) and they must have the same values (pointer898// comparison). If so 1 is returned, if not 0 is returned.899bool ExprDict::operator ==(const ExprDict &d) const {900assert( false, "NotImplemented");901return false;902}903904905//------------------------------Production-------------------------------------906Production::Production(const char *result, const char *constraint, const char *valid) {907initialize();908_result = result;909_constraint = constraint;910_valid = valid;911}912913void Production::initialize() {914_result = NULL;915_constraint = NULL;916_valid = knownInvalid;917_cost_lb = Expr::get_unknown();918_cost_ub = Expr::get_unknown();919}920921void Production::print() {922printf("%s", (_result == NULL ? "NULL" : _result ) );923printf("%s", (_constraint == NULL ? "NULL" : _constraint ) );924printf("%s", (_valid == NULL ? "NULL" : _valid ) );925_cost_lb->print();926_cost_ub->print();927}928929930//------------------------------ProductionState--------------------------------931void ProductionState::initialize() {932_constraint = noConstraint;933934// reset each Production currently in the dictionary935DictI iter( &_production );936const void *x, *y = NULL;937for( ; iter.test(); ++iter) {938x = iter._key;939y = iter._value;940Production *p = (Production*)y;941if( p != NULL ) {942p->initialize();943}944}945}946947Production *ProductionState::getProduction(const char *result) {948Production *p = (Production *)_production[result];949if( p == NULL ) {950p = new Production(result, _constraint, knownInvalid);951_production.Insert(result, p);952}953954return p;955}956957void ProductionState::set_constraint(const char *constraint) {958_constraint = constraint;959}960961const char *ProductionState::valid(const char *result) {962return getProduction(result)->valid();963}964965void ProductionState::set_valid(const char *result) {966Production *p = getProduction(result);967968// Update valid as allowed by current constraints969if( _constraint == noConstraint ) {970p->_valid = knownValid;971} else {972if( p->_valid != knownValid ) {973p->_valid = unknownValid;974}975}976}977978Expr *ProductionState::cost_lb(const char *result) {979return getProduction(result)->cost_lb();980}981982Expr *ProductionState::cost_ub(const char *result) {983return getProduction(result)->cost_ub();984}985986void ProductionState::set_cost_bounds(const char *result, const Expr *cost, bool has_state_check, bool has_cost_check) {987Production *p = getProduction(result);988989if( p->_valid == knownInvalid ) {990// Our cost bounds are not unknown, just not defined.991p->_cost_lb = cost->clone();992p->_cost_ub = cost->clone();993} else if (has_state_check || _constraint != noConstraint) {994// The production is protected by a condition, so995// the cost bounds may expand.996// _cost_lb = min(cost, _cost_lb)997if( cost->less_than_or_equal(p->_cost_lb) ) {998p->_cost_lb = cost->clone();999}1000// _cost_ub = max(cost, _cost_ub)1001if( p->_cost_ub->less_than_or_equal(cost) ) {1002p->_cost_ub = cost->clone();1003}1004} else if (has_cost_check) {1005// The production has no condition check, but does1006// have a cost check that could reduce the upper1007// and/or lower bound.1008// _cost_lb = min(cost, _cost_lb)1009if( cost->less_than_or_equal(p->_cost_lb) ) {1010p->_cost_lb = cost->clone();1011}1012// _cost_ub = min(cost, _cost_ub)1013if( cost->less_than_or_equal(p->_cost_ub) ) {1014p->_cost_ub = cost->clone();1015}1016} else {1017// The costs are unconditionally set.1018p->_cost_lb = cost->clone();1019p->_cost_ub = cost->clone();1020}10211022}10231024// Print out the dictionary contents as key-value pairs1025static void print_key (const void* key) { fprintf(stdout, "%s", (char*) key); }1026static void print_production(const void* production) { fflush(stdout); ((Production*)production)->print(); }10271028void ProductionState::print() {1029_production.print(print_key, print_production);1030}103110321033