Polaris: expression_util.cc Source File

expression_util.cc

Go to the documentation of this file.
00001 ///
00002 ///
00003 #include "expression_util.h"
00004 
00005 #include "../Expression/Expression.h"
00006 #include "../Expression/UnaryExpr.h"
00007 #include "../Symbol/Symbol.h"
00008 #include "../Symbol/VariableSymbol.h"
00009 #include "../ArrayDims.h"
00010 #include "../Monotonicity.h"
00011 #include "../Range/StmtRanges.h"
00012 #include "../Range/Relation.h"
00013 #include "../Statement/Statement.h"
00014 #include "../Traverser.h"
00015 #include "../macros.h"
00016 
00017 
00018 /// is_expr_variable
00019 ///
00020 /// This routine returns True if a variable appears somewhere in the
00021 /// given expression.
00022 
00023 Boolean is_expr_variable(const Expression & e)
00024 {
00025     if (e.op() == ID_OP)
00026         return True;
00027 
00028     for (Iterator<Expression> iter = e.arg_list(); iter.valid(); ++iter) {
00029     if (is_expr_variable(iter.current()))
00030         return True;
00031     }
00032     
00033     return False;
00034 }
00035 
00036 
00037 /// is_var_in_expr
00038 /// Return true if the given variable occurs somewhere within the given
00039 /// expression.
00040 
00041 Boolean
00042 is_var_in_expr(const Expression & e, const Symbol & var)
00043 {
00044     if (e.op() == ID_OP)
00045         return (&e.symbol() == &var);
00046 
00047     for (Iterator<Expression> iter = e.arg_list(); iter.valid(); ++iter) {
00048     if (is_var_in_expr(iter.current(), var))
00049         return True;
00050     }
00051 
00052     return False;
00053 }
00054 
00055 
00056 /// contains_func_call
00057 /// Return TRUE if the given statement contains a function call
00058 
00059 Boolean
00060 contains_func_call(const Statement & stmt)
00061 {
00062     Iterator<Expression> iter 
00063         = (CASTAWAY(Statement &) stmt).iterate_expressions();
00064 
00065     for (; iter.valid(); ++iter)
00066         if (!iter.current().is_side_effect_free())
00067             return True;
00068 
00069     return False;
00070 }
00071 
00072 
00073 /// is_int_scalar
00074 /// Return true if the given symbol is an integer scalar variable.
00075 
00076 Boolean
00077 is_int_scalar(const Symbol & sym)
00078 {
00079     return (sym.sym_class() == VARIABLE_CLASS
00080             && sym.type().data_type() == INTEGER_TYPE
00081             && !sym.is_array());
00082 }
00083 
00084 
00085 /// replace_parameters
00086 /// Return an expression will all parameter replaced by there values.
00087 /// The function takes ownership of the expression and give ownership
00088 /// of the resulting expression.
00089  
00090 Expression *
00091 replace_parameters(Expression *expr) 
00092 {
00093     if (! expr)
00094         return 0;
00095 
00096     if (expr->op() == ID_OP) {
00097         if (expr->symbol().sym_class() == SYMBOLIC_CONSTANT_CLASS) {
00098             Expression *old_subst = expr->symbol().expr_ref()->clone();
00099             Expression *new_subst = replace_parameters(old_subst);
00100 
00101             delete expr;
00102 
00103             return new_subst;
00104         }
00105     }
00106     else {
00107         List<Expression> & args = expr->arg_list();
00108 
00109         for (Mutator<Expression> mutr = args; mutr.valid(); ++mutr) {
00110       Assign<Expression> expr_as(mutr.assign());
00111       expr_as = replace_parameters( mutr.pull() );
00112     }
00113     }
00114 
00115     return expr;
00116 }
00117 
00118 
00119 /// Return the expression which is the stride due to the given
00120 /// identifier (given as an IDExpr).  This is the stride assuming
00121 /// the index value advances by 1.  Assuming the index is "I",
00122 /// the method is to substitute "I+1" for "I" in the expression
00123 /// and subtract.  Note that if the result is a function of I,
00124 /// then the stride is not constant, but varies with the value
00125 /// of I.
00126 
00127 
00128 Expression *
00129 extract_stride( Expression * expr, const Expression & index_id )
00130 {
00131     Expression * plus_one = substitute_var( expr->clone(), 
00132                        *(index_id.base_variable_ref()),
00133                        *add( index_id.clone(), constant(1) ) );
00134 
00135     return  simplify( sub( plus_one, expr->clone() ) );
00136 }
00137 
00138 
00139 /// Linearize the given expression, and offset the subscript
00140 /// expression so that subscript 0 represents the first element
00141 /// of the array.
00142 
00143 Expression *
00144 linearize_zero_registered( Expression * expr, VariableSymbol & sym )
00145 {
00146     
00147     /// ...  Get the dimension information for the symbol
00148 
00149     ArrayDims & src_dim = sym.dim();
00150     int         src_dims = src_dim.entries();
00151 
00152     List<Expression> & src_subs_list = expr->arg_list();
00153 
00154     /// ...  Calculate initial offset
00155 
00156     Expression     *src_exl;
00157     Expression     *src_exu;
00158     Expression     *offset;
00159 
00160     if (src_dims>1) {
00161         src_exl = src_dim[src_dims - 1].lower_ref();
00162 
00163         if (src_exl)
00164             src_exl = src_exl->clone();
00165         else
00166             src_exl = constant(1);
00167 
00168         /// ...  Absorb src_exl as subexpression of offset
00169 
00170         offset = sub(src_subs_list[src_dims - 1].clone(), src_exl);
00171 
00172         for (int i = src_dims - 2; i>0; --i) {
00173             src_exl = src_dim[i].lower_ref();
00174 
00175             if (src_exl)
00176                 src_exl = src_exl->clone();
00177             else
00178                 src_exl = constant(1);
00179 
00180             src_exu = src_dim[i].upper_ref();
00181 
00182             if (src_exu)
00183                 src_exu = src_exu->clone();
00184             else
00185                 src_exu = constant(1);
00186 
00187             /// ...  Absorb src_exl and src_exu as subexpressions of offset
00188 
00189             offset = add(mul(add(sub(src_exu, src_exl), constant(1)),
00190                              offset),
00191                          sub(src_subs_list[i].clone(), src_exl->clone()));
00192         }
00193     }
00194     else {
00195         offset = constant(0);
00196     }
00197 
00198     src_exl = src_dim[0].lower_ref();
00199 
00200     if (src_exl)
00201         src_exl = src_exl->clone();
00202     else
00203         src_exl = constant(1);
00204 
00205     src_exu = src_dim[0].upper_ref();
00206 
00207     if (src_exu)
00208         src_exu = src_exu->clone();
00209     else
00210         src_exu = constant(1);
00211 
00212     /// ...  Absorb src_exl and src_exu as subexpressions of offset
00213 
00214     offset = add(mul(add(sub(src_exu, src_exl), constant(1)),
00215                      offset),
00216                  sub(src_subs_list[0].clone(), src_exl->clone()));
00217 
00218     return simplify(offset);
00219 }
00220 
00221 /// Give the offset in elements (translated to making zero the first
00222 /// element) of the last array element
00223 
00224 Expression *
00225 last_element_offset ( VariableSymbol & sym )
00226 {
00227     
00228     /// ...  Get the dimension information for the symbol
00229 
00230     ArrayDims & src_dim = sym.dim();
00231     int         src_dims = src_dim.entries();
00232 
00233     /// ...  Calculate initial offset
00234 
00235     Expression     *src_exl;
00236     Expression     *src_exu;
00237     Expression     *offset;
00238 
00239     if (src_dims>1) {
00240         src_exu = src_dim[src_dims - 1].upper_ref();
00241 
00242     /// ...  If the upper bound of the array is unknown, 
00243     /// ...  pass along that fact to the caller.
00244 
00245     if (src_exu == 0) return omega();
00246 
00247         src_exl = src_dim[src_dims - 1].lower_ref();
00248 
00249         if (src_exl)
00250             src_exl = src_exl->clone();
00251         else
00252             src_exl = constant(1);
00253 
00254         /// ...  Absorb src_exl as subexpression of offset
00255 
00256         offset = sub(src_exu->clone(), src_exl);
00257 
00258         for (int i = src_dims - 2; i>0; --i) {
00259             src_exl = src_dim[i].lower_ref();
00260 
00261             if (src_exl)
00262                 src_exl = src_exl->clone();
00263             else
00264                 src_exl = constant(1);
00265 
00266             src_exu = src_dim[i].upper_ref();
00267 
00268             if (src_exu)
00269                 src_exu = src_exu->clone();
00270             else
00271                 src_exu = constant(1);
00272 
00273             /// ...  Absorb src_exl and src_exu as subexpressions of offset
00274 
00275             offset = add(mul(add(sub(src_exu, src_exl), constant(1)),
00276                              offset),
00277                          sub(src_exu->clone(), src_exl->clone()));
00278         }
00279     }
00280     else {
00281         offset = constant(0);
00282     }
00283 
00284     src_exl = src_dim[0].lower_ref();
00285 
00286     if (src_exl)
00287         src_exl = src_exl->clone();
00288     else
00289         src_exl = constant(1);
00290 
00291     src_exu = src_dim[0].upper_ref();
00292 
00293     if (src_exu)
00294         src_exu = src_exu->clone();
00295     else
00296         src_exu = constant(1);
00297 
00298     /// ...  Absorb src_exl and src_exu as subexpressions of offset
00299 
00300     offset = add(mul(add(sub(src_exu, src_exl), constant(1)),
00301                      offset),
00302                  sub(src_exu->clone(), src_exl->clone()));
00303 
00304     return simplify(offset);
00305 }
00306 
00307 /// Given an expr which is (-1)*a, change into -a
00308 
00309 Expression *
00310 _replace_mul_minus_one (Expression *expr)
00311 {
00312     /// ...  First, get rid of the -1
00313 
00314     for (Mutator<Expression> mutexpr = expr->arg_list();
00315      mutexpr.valid();
00316      ++mutexpr) {
00317     
00318     if ((mutexpr.current().op() == INTEGER_CONSTANT_OP) &&
00319         (mutexpr.current().value() == -1)) {
00320         mutexpr.del();
00321     }
00322     }
00323 
00324     /// ...  Now, pull the first sub-expression of expr
00325     /// ...  so that we can replace it with "UnaryMinus(expr)"
00326 
00327     Mutator<Expression> mutexpr2 = expr->arg_list();
00328     Assign<Expression> asexpr2(mutexpr2.assign());
00329     Expression *expr2 = mutexpr2.pull();
00330     Expression *new_expr = 
00331     new UnaryExpr(U_MINUS_OP, expr2->type(), expr2);
00332     asexpr2 = new_expr;
00333 
00334     return expr;
00335 }
00336 
00337 /// Boolean function used for Traverser in replace_mul_minus_one( expr )
00338 /// below.
00339 
00340 Boolean
00341 _is_mul_minus_one (const Expression & expr)
00342 {
00343     if (expr.op() == MULT_OP) {
00344     for (Iterator<Expression> ex_iter = expr.arg_list();
00345          ex_iter.valid();
00346          ++ex_iter) {
00347 
00348         if ((ex_iter.current().op() == INTEGER_CONSTANT_OP) &&
00349         (ex_iter.current().value() == -1)) {
00350 
00351         /// ...  Multiplying by -1
00352 
00353         return True;
00354         }
00355     }
00356     return False;
00357     } else {
00358     return False;
00359     }
00360 }
00361 
00362 /// Replace (-1)*expr with -expr wherever it appears in the expr
00363 
00364 Expression *
00365 replace_mul_minus_one( Expression * expr )
00366 {
00367     Expression * newexpr;
00368 
00369     for (Traverser trav(*expr, _is_mul_minus_one);
00370      trav.valid();
00371      ++trav) {
00372         
00373     /// ...  Found a MULTIPLY by -1
00374 
00375     if (!trav.top_level()) {
00376 
00377         Assign<Expression> asexpr(trav.assign());
00378         asexpr = _replace_mul_minus_one(trav.pull());
00379 
00380     } else {
00381         newexpr = _replace_mul_minus_one(expr);
00382         return replace_mul_minus_one( newexpr );
00383     }
00384     }
00385     return expr;
00386 }
00387 
00388 Monotonicity *
00389 test_monotonicity (RangeAccessor & range_acc,
00390            Symbol & index, 
00391            Expression * stride,
00392            Expression * expr)
00393 {
00394     Monotonicity * mono = new Monotonicity( );
00395 
00396     if (is_var_in_expr( *expr, index )) {
00397     mono->set_varying();
00398 
00399     /// ...  Form the possible new stride expression
00400     /// ...     new_stride = start(I = I+loop_stride) - start(I)
00401     
00402     Expression *index_plus_stride = add(id(index),
00403                         stride->clone());
00404 
00405     Expression * expr_stride = simplify(sub(substitute_var(expr->clone(), 
00406                                    index, 
00407                                    *index_plus_stride),
00408                         expr->clone()));
00409 
00410     /// ...  Do a cheap comparison, if possible
00411 
00412     if (expr_stride->op() == INTEGER_CONSTANT_OP) {
00413         int val = expr_stride->value();
00414         if (val < 0) {
00415         mono->set_negative();
00416         } else if (val > 0) {
00417         mono->set_positive();
00418         } else {  /// ...  val == 0
00419         mono->set_constant();
00420         }
00421         return mono;
00422     }
00423 
00424     /// ...  Compare the expression with 0
00425     Relation rel = range_acc.compare(*expr_stride, *constant(0));
00426 
00427     delete index_plus_stride;
00428     delete expr_stride;
00429     
00430     if (rel.is_less_than()) {
00431         mono->set_negative();
00432     } else if (rel.is_greater_than()) {
00433         mono->set_positive();
00434     } else {
00435         mono->set_unknown_dir();
00436     }
00437 //      /// ...  monotonicity unknown - try recursive approach
00438 //      List<Monotonicity> mono_list;
00439 //      for (Iterator<Expression> iter = expr.arg_list();
00440 //       iter.valid();
00441 //       ++iter) {
00442 ///
00443 //      /// ...  Make a list of the monotonicity of each sub-expression
00444 //      mono_list.ins_last(test_monotonic(range_acc,
00445 //                        index,
00446 //                        stride,
00447 //                        &(iter.current())));
00448 //      }
00449 //      switch (expr->op()) 
00450 //      {
00451 //      case DIV_OP:
00452 //      case MUL_OP:
00453 //          {
00454 //          bool constant = true;
00455 //          bool pos = true;
00456 //          bool unknown_dir = false;
00457 //          for (Iterator<Monotonicity> m_iter = mono_list;
00458 //               m_iter.valid();
00459 //               ++m_iter) {
00460 ///
00461 //              Monotonicity & mv = m_iter.current();
00462 ///
00463 //              if (mv.varying() || mv.unknown_mov()) {
00464 //              constant = false;
00465 //              }
00466 //              if (mv.negative()) positive = !positive;
00467 //              if (mv.unknown_dir()) unknown_dir = true;
00468 //          }
00469 //          if (constant) {
00470 //              mono->set_constant();
00471 //          }
00472 //          if (unknown_dir) {
00473 //              mono->set_unknown_dir();
00474 //          } else {
00475 //              if (positive) {
00476 //              mono->set_positive();
00477 //              } else {
00478 //              mono->set_negative();
00479 //              }
00480 //          }
00481 //          break;
00482 //          }
00483 //      case ADD_OP:
00484 //          {
00485 //          int pos = 0;
00486 //          int neg = 0;
00487 //          bool constant = true;
00488 //          bool unknown_dir = false;
00489 //          for (Iterator<Monotonicity> m_iter = mono_list;
00490 //               m_iter.valid();
00491 //               ++m_iter) {
00492 ///
00493 //              Monotonicity & mv = m_iter.current();
00494 ///
00495 //              if (mv.varying() || mv.unknown_mov()) {
00496 //              constant = false;
00497 //              }
00498 //              if (mv.negative()) ++neg;
00499 //              if (mv.positive()) ++pos;
00500 //              if (mv.unknown_dir()) unknown_dir = true;
00501 //          }
00502 //          if (constant) {
00503 //              mono->set_constant();
00504 //          }
00505 //          if (unknown_dir) {
00506 //              mono->set_unknown_dir();
00507 //          } else {
00508 //              if ((pos == 0) && (neg > 0)) {
00509 //              mono->set_negative();
00510 //              } else if ((neg == 0) && (pos > 0)) {
00511 //              mono->set_positive();
00512 //              } else { /// ...  Combination of pos and neg
00513 //              mono->set_unknown_dir();
00514 //              }
00515 //          }
00516 //          break;
00517 //          }
00518 //      case SUB_OP:
00519 //          {
00520 //          Monotonicity & mv0 = mono_list[0];
00521 //          Monotonicity & mv1 = mono_list[1];
00522 ///
00523 //          if (mv0.varying() || mv0.unknown_mov() ||
00524 //              mv1.varying() || mv1.unknown_mov()) {
00525 //              constant = false;
00526 //          }
00527 //          if (mv0.negative() && mv1.positive()) {
00528 //              mono->set_negative();
00529 //          } else if (mv0.positive() && mv1.negative()) {
00530 //              mono->set_positive();
00531 //          } else {
00532 //              mono->set_unknown_dir();
00533 //          }
00534 //          if (constant) {
00535 //              mono->set_constant();
00536 //          }
00537 //          if (unknown_dir) {
00538 //              mono->set_unknown_dir();
00539 //          } else {
00540 //              if ((pos == 0) && (neg > 0)) {
00541 //              mono->set_negative();
00542 //              } else if ((neg == 0) && (pos > 0)) {
00543 //              mono->set_positive();
00544 //              } else { /// ...  Combination of pos and neg
00545 //              mono->set_unknown_dir();
00546 //              }
00547 //          }
00548 //          break;
00549 //          }
00550 //      case :
00551 //          
00552 //  }
00553 ///
00554 ///
00555     } else { 
00556     mono->set_constant();
00557 
00558 //  /// ...  Compare the expression with 0
00559 //  Relation rel = range_d_acc.compare(*expr, *constant(0));
00560 ///
00561 //  if (rel.is_less_than()) {
00562 //      mono->set_negative();
00563 //  } else if (rel.is_greater_than()) {
00564 //      mono->set_positive();
00565 //  } else {
00566 //      mono->set_unknown_dir();
00567 //  }
00568     }
00569     return mono;
00570 }   
00571 
00572 /// Test the divides property by dividing, simplifying and checking
00573 /// if it's a constant, then it divides if the value is non-zero.
00574 /// if it's not a constant, then it divides as long as the top-level
00575 /// operator is not a DIV_OP.
00576 
00577 AR_CERTAINTY
00578 expr_divides ( Expression & divide_by, Expression & divide_into )
00579 {
00580   bool divi=false;
00581 
00582   if (_ar_logging && _ar_logging % 11 == 0) {
00583     arlog << ">>expr_divides-- Does " << divide_by << " DIVIDE " << divide_into << " ??";
00584   }
00585   if (is_integer_one(divide_by)) {
00586     divi = true;
00587   } else {
00588     if (is_integer_constant(divide_by) && 
00589     is_integer_constant(divide_into)) {
00590       if (divide_into.value() % divide_by.value() == 0) {
00591     if (_ar_logging && _ar_logging % 11 == 0) {
00592       arlog << ": YES!" << endl;
00593     }
00594     return AR_YES;
00595       } else {
00596     if (_ar_logging && _ar_logging % 11 == 0) {
00597       arlog << ": NO!" << endl;
00598     }
00599     return AR_NO;
00600       }
00601     } else {
00602       Expression * expr = simplify ( div(divide_into.clone(),
00603                      divide_by.clone() ) );
00604       if (expr->op() == INTEGER_CONSTANT_OP) {
00605     divi = (expr->value() != 0);
00606       } else {
00607     if (expr->op() == EXP_OP) {
00608       if ((expr->arg_list()[1].op() == INTEGER_CONSTANT_OP) &&
00609           (expr->arg_list()[1].value() >= 0)) {
00610         divi = true;
00611       } else {
00612         divi = false;
00613       }   
00614     } else {
00615       divi = expr->op() != DIV_OP;
00616     }
00617       }
00618       
00619       delete expr;
00620     }
00621   }
00622 
00623   if (divi) {
00624     if (_ar_logging && _ar_logging % 11 == 0) {
00625       arlog << ": YES!" << endl;
00626     }
00627     return AR_YES;
00628   } else {
00629     if (_ar_logging && _ar_logging % 11 == 0) {
00630       arlog << ": NOT SURE" << endl;
00631     }
00632     return AR_UNSURE;
00633   }
00634 }
00635 
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:05:52 2005