<commit_before>/*
 * This file is released under terms of BSD license
 * See LICENSE file for more information
 */

package cx2x.translator.transformation.loop;

import cx2x.translator.language.ClawLanguage;
import cx2x.translator.language.ClawReshapeInfo;
import cx2x.translator.language.helper.TransformationHelper;
import cx2x.xcodeml.exception.IllegalTransformationException;
import cx2x.xcodeml.helper.XnodeUtil;
import cx2x.xcodeml.transformation.BlockTransformation;
import cx2x.xcodeml.transformation.Transformation;
import cx2x.xcodeml.transformation.Transformer;
import cx2x.xcodeml.xnode.Xcode;
import cx2x.xcodeml.xnode.XcodeProgram;
import cx2x.xcodeml.xnode.XfunctionDefinition;
import cx2x.xcodeml.xnode.Xnode;

import java.util.ArrayList;
import java.util.List;

/**
 * A LoopHoist transformation is an independent transformation over a
 * structured block. It performs loop fusion in the given block as well as do
 * start statement hoisting.
 *
 * @author clementval
 */
public class LoopHoist extends BlockTransformation {

  private final List<LoopHoistDoStmtGroup> _doGroup;
  private final ClawLanguage _startClaw, _endClaw;
  private int _nestedLevel;

  /**
   * Constructs a new LoopHoist triggered from a specific directive.
   * @param startDirective The directive that triggered the loop hoist
   *                       transformation.
   * @param endDirective   The directive that end the structured block.
   */
  public LoopHoist(ClawLanguage startDirective, ClawLanguage endDirective) {
    super(startDirective, endDirective);
    _startClaw = startDirective;
    _endClaw = endDirective;
    _doGroup = new ArrayList<>();
  }

  /**
   * @see Transformation#analyze(XcodeProgram, Transformer)
   */
  @Override
  public boolean analyze(XcodeProgram xcodeml, Transformer transformer) {
    int _pragmaDepthLevel = XnodeUtil.getDepth(_startClaw.getPragma());
    _nestedLevel = _startClaw.getHoistInductionVars().size();

    // Find all the group of nested loops that can be part of the hoisting
    List<Xnode> statements =
        XnodeUtil.findDoStatement(_startClaw.getPragma(),
            _endClaw.getPragma(), _startClaw.getHoistInductionVars());

    if(statements.size() == 0){
      xcodeml.addError("No do statement group meets the criteria of hoisting.",
          _startClaw.getPragma().getLineNo());
      return false;
    }

    for(int i = 0; i < statements.size(); i++){
      Xnode[] group = new Xnode[_nestedLevel];
      LoopHoistDoStmtGroup g = new LoopHoistDoStmtGroup(group);
      try {
        reloadDoStmts(g, statements.get(i));
      } catch (IllegalTransformationException e) {
        xcodeml.addError("Group " + i + " of do statements do not meet the" +
                " criteria of loop hoisting (Group index starts at 0).",
            _startClaw.getPragma().getLineNo());
        return false;
      }

      LoopHoistDoStmtGroup crtGroup = new LoopHoistDoStmtGroup(group);
      int depth = XnodeUtil.getDepth(group[0]);
      if(depth != _pragmaDepthLevel){
        Xnode tmpIf = XnodeUtil.findParent(Xcode.FIFSTATEMENT, group[0]);
        Xnode tmpSelect = XnodeUtil.findParent(Xcode.FSELECTCASESTATEMENT, group[0]);
        if(tmpIf == null && tmpSelect == null){
          xcodeml.addError("Group " + i + " is nested in an unsupported " +
              "statement for loop hoisting (Group index starts at 0).",
              _startClaw.getPragma().getLineNo());
          return false;
        }

        int ifDepth = XnodeUtil.getDepth(tmpIf);
        int selectDepth = XnodeUtil.getDepth(tmpSelect);
        if ((_pragmaDepthLevel <= ifDepth || _pragmaDepthLevel <= selectDepth)
            && (ifDepth < depth || selectDepth < depth)){
          crtGroup.setExtraction();
        } else {
          xcodeml.addError("Group " + i + " is nested in an unsupported " +
              "statement for loop hoisting or depth is too high " +
              "(Group index starts at 0).",
              _startClaw.getPragma().getLineNo());
          return false;
        }
      }
      _doGroup.add(crtGroup);
    }

    LoopHoistDoStmtGroup master = _doGroup.get(0);
    for (int i = 1; i < _doGroup.size(); ++i){
      LoopHoistDoStmtGroup next = _doGroup.get(i);
      for(int j = 0; j < master.getDoStmts().length; ++j){
        // Iteration range are identical, just merge
        if(j == 0
            && (
              !XnodeUtil.hasSameIndexRange(master.getDoStmts()[j],
                next.getDoStmts()[j])
              && XnodeUtil.hasSameIndexRangeBesidesLower(master.getDoStmts()[j],
                next.getDoStmts()[j])
            )
          )
        {
          // Iteration range are identical besides lower-bound, if creation
          next.setIfStatement();
        } else if(!XnodeUtil.hasSameIndexRange(master.getDoStmts()[j],
            next.getDoStmts()[j]))
        {
          // Iteration range are too different, stop analysis
          xcodeml.addError("Iteration range of do statements group " + i +
                  " differs from group 0. Loop hoisting aborted.",
              _startClaw.getPragma().getLineNo());
          return false;
        }
      }
    }


    // Check reshape mandatory points
    if(_startClaw.hasReshapeClause()) {
      XfunctionDefinition fctDef =
          XnodeUtil.findParentFunction(_startClaw.getPragma());
      if(fctDef == null){
        xcodeml.addError("Unable to find the function/subroutine/module " +
            "definition including the current directive",
            _startClaw.getPragma().getLineNo()
        );
        return false;
      }
      
      for (ClawReshapeInfo r : _startClaw.getReshapeClauseValues()) {
        if (!fctDef.getSymbolTable().contains(r.getArrayName()) ||
            !fctDef.getDeclarationTable().contains(r.getArrayName())) {
          xcodeml.addError(String.format("Reshape variable %s not found in " +
              "the definition of %s", r.getArrayName(),
              fctDef.getName().getValue()), _startClaw.getPragma().getLineNo()
          );
          return false;
        }
      }
    }
    return true;
  }

  /**
   * @see Transformation#canBeTransformedWith(Transformation)
   */
  @Override
  public boolean canBeTransformedWith(Transformation transformation) {
    return false;
  }

  /**<commit_msg>Adapt reshape clause check for nested fct definition<commit_after>/*
 * This file is released under terms of BSD license
 * See LICENSE file for more information
 */

package cx2x.translator.transformation.loop;

import cx2x.translator.language.ClawLanguage;
import cx2x.translator.language.ClawReshapeInfo;
import cx2x.translator.language.helper.TransformationHelper;
import cx2x.xcodeml.exception.IllegalTransformationException;
import cx2x.xcodeml.helper.XnodeUtil;
import cx2x.xcodeml.transformation.BlockTransformation;
import cx2x.xcodeml.transformation.Transformation;
import cx2x.xcodeml.transformation.Transformer;
import cx2x.xcodeml.xnode.Xcode;
import cx2x.xcodeml.xnode.XcodeProgram;
import cx2x.xcodeml.xnode.XfunctionDefinition;
import cx2x.xcodeml.xnode.Xnode;

import java.util.ArrayList;
import java.util.List;

/**
 * A LoopHoist transformation is an independent transformation over a
 * structured block. It performs loop fusion in the given block as well as do
 * start statement hoisting.
 *
 * @author clementval
 */
public class LoopHoist extends BlockTransformation {

  private final List<LoopHoistDoStmtGroup> _doGroup;
  private final ClawLanguage _startClaw, _endClaw;
  private int _nestedLevel;

  /**
   * Constructs a new LoopHoist triggered from a specific directive.
   * @param startDirective The directive that triggered the loop hoist
   *                       transformation.
   * @param endDirective   The directive that end the structured block.
   */
  public LoopHoist(ClawLanguage startDirective, ClawLanguage endDirective) {
    super(startDirective, endDirective);
    _startClaw = startDirective;
    _endClaw = endDirective;
    _doGroup = new ArrayList<>();
  }

  /**
   * @see Transformation#analyze(XcodeProgram, Transformer)
   */
  @Override
  public boolean analyze(XcodeProgram xcodeml, Transformer transformer) {
    int _pragmaDepthLevel = XnodeUtil.getDepth(_startClaw.getPragma());
    _nestedLevel = _startClaw.getHoistInductionVars().size();

    // Find all the group of nested loops that can be part of the hoisting
    List<Xnode> statements =
        XnodeUtil.findDoStatement(_startClaw.getPragma(),
            _endClaw.getPragma(), _startClaw.getHoistInductionVars());

    if(statements.size() == 0){
      xcodeml.addError("No do statement group meets the criteria of hoisting.",
          _startClaw.getPragma().getLineNo());
      return false;
    }

    for(int i = 0; i < statements.size(); i++){
      Xnode[] group = new Xnode[_nestedLevel];
      LoopHoistDoStmtGroup g = new LoopHoistDoStmtGroup(group);
      try {
        reloadDoStmts(g, statements.get(i));
      } catch (IllegalTransformationException e) {
        xcodeml.addError("Group " + i + " of do statements do not meet the" +
                " criteria of loop hoisting (Group index starts at 0).",
            _startClaw.getPragma().getLineNo());
        return false;
      }

      LoopHoistDoStmtGroup crtGroup = new LoopHoistDoStmtGroup(group);
      int depth = XnodeUtil.getDepth(group[0]);
      if(depth != _pragmaDepthLevel){
        Xnode tmpIf = XnodeUtil.findParent(Xcode.FIFSTATEMENT, group[0]);
        Xnode tmpSelect = XnodeUtil.findParent(Xcode.FSELECTCASESTATEMENT, group[0]);
        if(tmpIf == null && tmpSelect == null){
          xcodeml.addError("Group " + i + " is nested in an unsupported " +
              "statement for loop hoisting (Group index starts at 0).",
              _startClaw.getPragma().getLineNo());
          return false;
        }

        int ifDepth = XnodeUtil.getDepth(tmpIf);
        int selectDepth = XnodeUtil.getDepth(tmpSelect);
        if ((_pragmaDepthLevel <= ifDepth || _pragmaDepthLevel <= selectDepth)
            && (ifDepth < depth || selectDepth < depth)){
          crtGroup.setExtraction();
        } else {
          xcodeml.addError("Group " + i + " is nested in an unsupported " +
              "statement for loop hoisting or depth is too high " +
              "(Group index starts at 0).",
              _startClaw.getPragma().getLineNo());
          return false;
        }
      }
      _doGroup.add(crtGroup);
    }

    LoopHoistDoStmtGroup master = _doGroup.get(0);
    for (int i = 1; i < _doGroup.size(); ++i){
      LoopHoistDoStmtGroup next = _doGroup.get(i);
      for(int j = 0; j < master.getDoStmts().length; ++j){
        // Iteration range are identical, just merge
        if(j == 0
            && (
              !XnodeUtil.hasSameIndexRange(master.getDoStmts()[j],
                next.getDoStmts()[j])
              && XnodeUtil.hasSameIndexRangeBesidesLower(master.getDoStmts()[j],
                next.getDoStmts()[j])
            )
          )
        {
          // Iteration range are identical besides lower-bound, if creation
          next.setIfStatement();
        } else if(!XnodeUtil.hasSameIndexRange(master.getDoStmts()[j],
            next.getDoStmts()[j]))
        {
          // Iteration range are too different, stop analysis
          xcodeml.addError("Iteration range of do statements group " + i +
                  " differs from group 0. Loop hoisting aborted.",
              _startClaw.getPragma().getLineNo());
          return false;
        }
      }
    }


    // Check reshape mandatory points
    if(_startClaw.hasReshapeClause()) {
      XfunctionDefinition fctDef =
          XnodeUtil.findParentFunction(_startClaw.getPragma());
      if(fctDef == null){
        xcodeml.addError("Unable to find the function/subroutine/module " +
            "definition including the current directive",
            _startClaw.getPragma().getLineNo()
        );
        return false;
      }

      for (ClawReshapeInfo r : _startClaw.getReshapeClauseValues()) {
        if (!fctDef.getSymbolTable().contains(r.getArrayName()) ||
            !fctDef.getDeclarationTable().contains(r.getArrayName()))
        {
          // Check in the parent def if present
          if(!checkUpperDefinition(fctDef, r.getArrayName())){
            xcodeml.addError(String.format("Reshape variable %s not found in " +
                    "the definition of %s", r.getArrayName(),
                fctDef.getName().getValue()), _startClaw.getPragma().getLineNo()
            );
            return false;
          }
        }
      }
    }
    return true;
  }

  /**
   * Check whether the id is present in the parent function definition if the
   * current fct definition is nested.
   * @param fctDef Current function definition.
   * @param name   Id to be looked for.
   * @return True if the id has been found. False otherwise.
   */
  private boolean checkUpperDefinition(XfunctionDefinition fctDef, String name)
  {
    XfunctionDefinition upperDef = XnodeUtil.findParentFunction(fctDef);
    if (upperDef == null) {
      return false;
    }
    return !(!upperDef.getSymbolTable().contains(name)
        || !upperDef.getDeclarationTable().contains(name))
        || checkUpperDefinition(upperDef, name);
  }

  /**
   * @see Transformation#canBeTransformedWith(Transformation)
   */
  @Override
  public boolean canBeTransformedWith(Transformation transformation) {
    return false;
  }

  /**
{'fraction_non_alphanumeric': 0.1026842144397353, 'fraction_numerical': 0.003866458472748903, 'mean_word_length': 2.7392271337225464, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1372207', 'n_tokens_mistral': 4076, 'n_tokens_neox': 3930, 'n_words': 929}