/* * 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; }
/* * 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)); } } }
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); }