<commit_before>/*
 * Copyright 2004-2014 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ForLoop.h"

#include "astutil.h"
#include "AstVisitor.h"
#include "build.h"
#include "codegen.h"

#include <algorithm>

/************************************ | *************************************
*                                                                           *
* Helper functions to optimize anonymous range iteration                    *
*                                                                           *
************************************* | ************************************/

/*
 * 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 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 the original, unchanged
 * iteratorExpr is returned.
 */
static Expr* tryToUseDirectRangeIterator(Expr* iteratorExpr) {
  CallExpr* range = NULL;
  Expr* stride = NULL;
  if (CallExpr* call = toCallExpr(iteratorExpr)) {
    // grab the stride if we have a strided ranges
    if (call->isNamed("by")) {
      range = toCallExpr(call->get(1)->copy());
      stride = toExpr(call->get(2)->copy());
    } else {
      range = call;
    }
    // see if we're looking at a _build_range for an anonymous range
    if (range && range->isNamed("chpl_build_bounded_range")) {
      Expr* low = range->get(1)->copy();
      Expr* high = range->get(2)->copy();
      // replace the range construction with a direct range iterator
      if (stride) {
        iteratorExpr = (new CallExpr("_direct_range_iter", low, high, stride));
      } else {
        SymExpr* noStr = new SymExpr(new_IntSymbol(1));
        iteratorExpr = (new CallExpr("_direct_range_iter", low, high, noStr));
      }
    }
  }
  return iteratorExpr;
}

static Expr* optimizeRangeIteration(Expr* iteratorExpr, bool zippered) {
  iteratorExpr = tryToUseDirectRangeIterator(iteratorExpr);
  // for zippered iterators, try to replace each iterator of the tuple
  if (zippered) {
    if (CallExpr* call = toCallExpr(iteratorExpr)) {
      if (call->isNamed("_build_tuple")) {
        for_actuals(actual, call) {
          actual->replace(tryToUseDirectRangeIterator(actual->copy()));
        }
      }
    }
  }
  return iteratorExpr;
}

/************************************ | *************************************
*                                                                           *<commit_msg>Update brace style to match existing ones in ForLoop.cpp<commit_after>/*
 * Copyright 2004-2014 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ForLoop.h"

#include "astutil.h"
#include "AstVisitor.h"
#include "build.h"
#include "codegen.h"

#include <algorithm>

/************************************ | *************************************
*                                                                           *
* Helper functions to optimize anonymous range iteration                    *
*                                                                           *
************************************* | ************************************/

/*
 * 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, the original, unchanged
 * iteratorExpr is returned.
 */
static Expr* tryToUseDirectRangeIterator(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("by"))
    {
      range = toCallExpr(call->get(1)->copy());
      stride = toExpr(call->get(2)->copy());
    }
    else
    {
      range = call;
    }
    // see if we're looking at an anonymous iter for a bounded range
    if (range && range->isNamed("chpl_build_bounded_range"))
    {
      Expr* low = range->get(1)->copy();
      Expr* high = range->get(2)->copy();
      // replace the range construction with a direct range iterator
      if (stride)
      {
        iteratorExpr = (new CallExpr("_direct_range_iter", low, high, stride));
      }
      else
      {
        SymExpr* noStr = new SymExpr(new_IntSymbol(1));
        iteratorExpr = (new CallExpr("_direct_range_iter", low, high, noStr));
      }
    }
  }
  return iteratorExpr;
}

static Expr* optimizeRangeIteration(Expr* iteratorExpr, bool zippered)
{
  iteratorExpr = tryToUseDirectRangeIterator(iteratorExpr);
  // for zippered iterators, try to replace each iterator of the tuple
  if (zippered)
  {
    if (CallExpr* call = toCallExpr(iteratorExpr))
    {
      if (call->isNamed("_build_tuple"))
      {
        for_actuals(actual, call)
        {
          actual->replace(tryToUseDirectRangeIterator(actual->copy()));
        }
      }
    }
  }
  return iteratorExpr;
}

/************************************ | *************************************
*                                                                           *
{'fraction_non_alphanumeric': 0.14075673452601276, 'fraction_numerical': 0.012852148879292617, 'mean_word_length': 2.5959334565619225, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3708908', 'n_tokens_mistral': 2697, 'n_tokens_neox': 2535, 'n_words': 1071}