Exemple #1
0
/*
 * Attempts to replace iteration over simple anonymous ranges with calls to
 * direct iterators that take low, high and stride as arguments. This is to
 * avoid the cost of constructing ranges, and if the stride is known at compile
 * time, provide a more optimized iterator that uses "<, <=, >, or >=" as the
 * relational operator.
 *
 * This is only meant to replace anonymous range iteration for "simple" bounded
 * ranges. Simple means it's a range of the form "low..high" or "low..high by
 * stride". Anything more complex is ignored with the thinking that this should
 * optimize the most common range iterators, but it could be expanded to handle
 * more cases.
 *
 * An alternative is to update scalar replacement of aggregates to work on
 * ranges, which should be able to achieve similar results as this optimization
 * while handling all ranges, including non-anonymous ranges.
 *
 * Will optimize things like:
 * - "for i in 1..10"
 * - "for i in 1..10+1"
 * - "var lo=1, hi=10;for i in lo..hi"
 * - "for i in 1..10 by 2"
 * - "for (i, j) in zip(1..10 by 2, 1..10 by -2)"
 * - "for (i, j) in zip(A, 1..10 by 2)" // will optimize range iter still
 * - "coforall i in 1..10 by 2"         // works for coforalls as well
 *
 * Will not optimize ranges like:
 * - "for in in (1..)"             // doesn't handle unbounded ranges
 * - "for i in 1..10 by 2 by 2"    // doesn't handle more than one by operator
 * - "for i in 1..10 align 2"      // doesn't handle align operator
 * - "for i in 1..#10"             // doesn't handle # operator
 * - "var r = 1..10"; for i in r"  // not an anonymous range
 * - "forall i in 1..10"           // does not get applied to foralls
 *
 * Note that this function is pretty fragile because it relies on names of
 * functions/iterators as well as the arguments and order of those
 * functions/iterators but there's not really a way around it this early in
 * compilation. If the iterator can't be replaced, it is left unchanged.
 */
static void tryToReplaceWithDirectRangeIterator(Expr* iteratorExpr)
{
  CallExpr* range = NULL;
  Expr* stride = NULL;
  if (CallExpr* call = toCallExpr(iteratorExpr))
  {
    // grab the stride if we have a strided range
    if (call->isNamed("chpl_by"))
    {
      range = toCallExpr(call->get(1)->copy());
      stride = toExpr(call->get(2)->copy());
    }
    // assume the call is the range (checked below) and set default stride
    else
    {
      range = call;
      stride = new SymExpr(new_IntSymbol(1));
    }
    // see if we're looking at a builder for a bounded range. the builder is
    // iteratable since range has these() iterators
    if (range && range->isNamed("chpl_build_bounded_range"))
    {
      // replace the range construction with a direct range iterator
      Expr* low = range->get(1)->copy();
      Expr* high = range->get(2)->copy();
      iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride));
    }
  }
}
//
// Find the _waitEndCount and _endCountFree calls that comes after 'fromHere'.
// Since these two calls come together, it is prettier to insert
// our stuff after the latter.
//
static Expr* findTailInsertionPoint(Expr* fromHere, bool isCoforall) {
  Expr* curr = fromHere;
  if (isCoforall) curr = curr->parentExpr;
  CallExpr* result = NULL;
  while ((curr = curr->next)) {
    if (CallExpr* call = toCallExpr(curr))
      if (call->isNamed("_waitEndCount")) {
        result = call;
        break;
      }
  }
  INT_ASSERT(result);
  CallExpr* freeEC = toCallExpr(result->next);
  // Currently these two calls come together.
  INT_ASSERT(freeEC && freeEC->isNamed("_endCountFree"));
  return freeEC;
}
Exemple #3
0
/*
 * Attempts to replace iteration over simple anonymous ranges with calls to
 * direct iterators that take low, high and stride as arguments. This is to
 * avoid the cost of constructing ranges, and if the stride is known at compile
 * time, provide a more optimized iterator that uses "<, <=, >, or >=" as the
 * relational operator.
 *
 * This is only meant to replace anonymous range iteration for "simple" ranges.
 * Simple means it's a range of the form "low..high", "low..high by stride", or
 * "low..#count". Anything more complex is ignored with the thinking that this
 * should optimize the most common range iterators, but it could be expanded to
 * handle more cases.
 *
 * An alternative is to update scalar replacement of aggregates to work on
 * ranges, which should be able to achieve similar results as this optimization
 * while handling all ranges, including non-anonymous ranges.
 *
 * This function will optimize things like:
 * - "for i in 1..10"
 * - "for i in 1..10+1"
 * - "var lo=1, hi=10;for i in lo..hi"
 * - "for i in 1..10 by 2"
 * - "for i in 1..#10"
 * - "for (i, j) in zip(1..10 by 2, 1..10 by -2)"
 * - "for (i, j) in zip(A, 1..10 by 2)" // will optimize range iter still
 * - "coforall i in 1..10 by 2"         // works for coforalls as well
 *
 * Will not optimize ranges like:
 * - "for in in (1..)"             // doesn't handle unbounded ranges
 * - "for i in 1..10 by 2 by 2"    // doesn't handle more than one by operator
 * - "for i in 1..10 align 2"      // doesn't handle align operator
 * - "for i in (1..10)#2"          // doesn't handle bounded counted ranges
 * - "for i in 1..#10 by 2"        // doesn't handle strided and counted ranges
 * - "var r = 1..10"; for i in r"  // not an anonymous range
 * - "forall i in 1..10"           // doesn't get applied to foralls
 *
 * Note that this function is pretty fragile because it relies on names of
 * functions/iterators as well as the arguments and order of those
 * functions/iterators but there's not really a way around it this early in
 * compilation. If the iterator can't be replaced, it is left unchanged.
 */
static void tryToReplaceWithDirectRangeIterator(Expr* iteratorExpr)
{
  if (CallExpr* call = toCallExpr(iteratorExpr))
  {
    CallExpr* range = NULL;
    Expr* stride = NULL;
    Expr* count = NULL;
    // grab the stride if we have a strided range
    if (call->isNamed("chpl_by"))
    {
      range = toCallExpr(call->get(1)->copy());
      stride = toExpr(call->get(2)->copy());
    }
    // or grab the count if we have a counted range and set unit stride
    else if (call->isNamed("#"))
    {
      range = toCallExpr(call->get(1)->copy());
      count = toExpr(call->get(2)->copy());
      stride = new SymExpr(new_IntSymbol(1));
    }
    // or assume the call is the range (checked below) and set unit stride
    else
    {
      range = call;
      stride = new SymExpr(new_IntSymbol(1));
    }

    //
    // see if we're looking at a range builder. The builder is iteratable since
    // range has these() iterators
    //

    // replace fully bounded (and possibly strided range) with a direct range
    // iter. e.g. replace:
    //
    //   `low..high by stride`
    //
    // with:
    //
    // `chpl_direct_range_iter(low, high, stride)`
    if (range && range->isNamed("chpl_build_bounded_range"))
    {
      // replace the range construction with a direct range iterator
      Expr* low = range->get(1)->copy();
      Expr* high = range->get(2)->copy();
      iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride));
    }

    // replace a counted, low bounded range with unit stride with an equivalent
    // direct range iter. e.g. replace:
    //
    //   `low..#count` (which is equivalent to `low..low+count-1`)
    //
    // with:
    //
    //   `chpl_direct_range_iter(low, low+count-1, 1)`
    else if (count && range && range->isNamed("chpl_build_low_bounded_range"))
    {
      Expr* low = range->get(1)->copy();
      Expr* high = new CallExpr("-", new CallExpr("+", low->copy(), count), new_IntSymbol(1));
      iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride));
    }
  }
}
Exemple #4
0
BlockStmt* ParamForLoop::buildParamForLoop(VarSymbol* indexVar,
                                           Expr*      range,
                                           BlockStmt* stmts)
{
  VarSymbol*   lowVar     = newParamVar();
  VarSymbol*   highVar    = newParamVar();
  VarSymbol*   strideVar  = newParamVar();

  LabelSymbol* breakLabel = new LabelSymbol("_breakLabel");
  LabelSymbol* continueLabel  = new LabelSymbol("_unused_continueLabel");

  CallExpr*    call       = toCallExpr(range);
  Expr*        low        = NULL;
  Expr*        high       = NULL;
  Expr*        stride     = NULL;

  BlockStmt*   outer      = new BlockStmt();

  if (call && call->isNamed("chpl_by"))
  {
    stride = call->get(2)->remove();
    call   = toCallExpr(call->get(1));
  }
  else
  {
    stride = new SymExpr(new_IntSymbol(1));
  }

  if (call && call->isNamed("chpl_build_bounded_range"))
  {
    low    = call->get(1)->remove();
    high   = call->get(1)->remove();
  }
  else
  {
    USR_FATAL(range, "iterators for param-for-loops must be bounded literal ranges");
  }

  outer->insertAtTail(new DefExpr(indexVar, new_IntSymbol((int64_t) 0)));

  outer->insertAtTail(new DefExpr(lowVar));
  outer->insertAtTail(new CallExpr(PRIM_MOVE, lowVar,    low));

  outer->insertAtTail(new DefExpr(highVar));
  outer->insertAtTail(new CallExpr(PRIM_MOVE, highVar,   high));

  outer->insertAtTail(new DefExpr(strideVar));
  outer->insertAtTail(new CallExpr(PRIM_MOVE, strideVar, stride));

  outer->insertAtTail(new ParamForLoop(indexVar,
                                       lowVar,
                                       highVar,
                                       strideVar,
                                       continueLabel,
                                       breakLabel,
                                       stmts));

  // this continueLabel will be replaced by a per-iteration one.
  outer->insertAtTail(new DefExpr(continueLabel));
  outer->insertAtTail(new DefExpr(breakLabel));

  return buildChapelStmt(outer);
}