Beispiel #1
0
bool ReturnByRef::isTransformableFunction(FnSymbol* fn)
{
  bool retval = false;

  if (AggregateType* type = toAggregateType(fn->retType))
  {
    if      (fn->hasFlag(FLAG_INIT_COPY_FN) == true)
      retval = false;

    else if (fn->hasFlag(FLAG_AUTO_COPY_FN) == true)
      retval = false;

    // Function is an iterator "helper"
    else if (fn->hasFlag(FLAG_AUTO_II)      == true)
      retval = false;

    // Can't transform extern functions
    else if (fn->hasFlag(FLAG_EXTERN)       == true)
      retval = false;

    // Noakes: 2016/02/24.  Only "user defined records" for now
    else if (isUserDefinedRecord(type)      == true)
      retval = true;

    else
      retval = false;
  }

  return retval;
}
Beispiel #2
0
//
// Consider a function that takes a formal of type Record by const ref
// and that returns that value from the function.  The compiler inserts
// a PRIM_MOVE operation.
//
// This work-around inserts an autoCopy to compensate
//
void ReturnByRef::updateAssignmentsFromRefArgToValue(FnSymbol* fn)
{
  std::vector<CallExpr*> callExprs;

  collectCallExprs(fn, callExprs);

  for (size_t i = 0; i < callExprs.size(); i++)
  {
    CallExpr* move = callExprs[i];

    if (move->isPrimitive(PRIM_MOVE) == true)
    {
      SymExpr* lhs = toSymExpr(move->get(1));
      SymExpr* rhs = toSymExpr(move->get(2));

      if (lhs != NULL && rhs != NULL)
      {
        VarSymbol* symLhs = toVarSymbol(lhs->symbol());
        ArgSymbol* symRhs = toArgSymbol(rhs->symbol());

        if (symLhs != NULL && symRhs != NULL)
        {
          if (isUserDefinedRecord(symLhs->type) == true &&
              symRhs->type                      == symLhs->type)
          {
            if (symLhs->hasFlag(FLAG_ARG_THIS) == false &&
                (symRhs->intent == INTENT_REF ||
                 symRhs->intent == INTENT_CONST_REF))
            {
              SET_LINENO(move);

              CallExpr* autoCopy = NULL;

              rhs->remove();
              autoCopy = new CallExpr(autoCopyMap.get(symRhs->type), rhs);
              move->insertAtTail(autoCopy);
            }
          }
        }
      }
    }
  }
}
// Walk backwards from the current statement to determine if a sequence of
// moves have copied a variable that is marked for auto destruction in to
// the dedicated return-temp within the current scope.
//
// Note that the value we are concerned about may be copied in to one or
// more temporary variables between being copied to the return temp.
static VarSymbol* variableToExclude(FnSymbol* fn, Expr* refStmt) {
  VarSymbol* retVar = toVarSymbol(fn->getReturnSymbol());
  VarSymbol* retval = NULL;

  if (retVar != NULL) {
    if (isUserDefinedRecord(retVar)    == true ||
        fn->hasFlag(FLAG_INIT_COPY_FN) == true) {
      VarSymbol* needle = retVar;
      Expr*      expr   = refStmt;

      // Walk backwards looking for the variable that is being returned
      while (retval == NULL && expr != NULL && needle != NULL) {
        if (CallExpr* move = toCallExpr(expr)) {
          if (move->isPrimitive(PRIM_MOVE) == true) {
            SymExpr*   lhs    = toSymExpr(move->get(1));
            VarSymbol* lhsVar = toVarSymbol(lhs->symbol());

            if (needle == lhsVar) {
              if (SymExpr* rhs = toSymExpr(move->get(2))) {
                VarSymbol* rhsVar = toVarSymbol(rhs->symbol());

                if (isAutoDestroyedVariable(rhsVar) == true) {
                  retval = rhsVar;
                } else {
                  needle = rhsVar;
                }
              } else {
                needle = NULL;
              }
            }
          }
        }

        expr = expr->prev;
      }
    }
  }

  return retval;
}
Beispiel #4
0
void ReturnByRef::updateAssignmentsFromRefTypeToValue(FnSymbol* fn)
{
  std::vector<CallExpr*> callExprs;

  collectCallExprs(fn, callExprs);

  Map<Symbol*,Vec<SymExpr*>*> defMap;
  Map<Symbol*,Vec<SymExpr*>*> useMap;
  buildDefUseMaps(fn, defMap, useMap);

  for (size_t i = 0; i < callExprs.size(); i++)
  {
    CallExpr* move = callExprs[i];

    if (move->isPrimitive(PRIM_MOVE) == true)
    {
      SymExpr*  symLhs  = toSymExpr (move->get(1));
      CallExpr* callRhs = toCallExpr(move->get(2));

      if (symLhs && callRhs && callRhs->isPrimitive(PRIM_DEREF))
      {
        VarSymbol* varLhs = toVarSymbol(symLhs->symbol());
        SymExpr*   symRhs = toSymExpr(callRhs->get(1));
        VarSymbol* varRhs = toVarSymbol(symRhs->symbol());

        // MPF 2016-10-02: It seems to me that this code should also handle the
        // case that symRhs is an ArgSymbol, but adding that caused problems
        // in the handling of out argument intents.

        if (varLhs != NULL && varRhs != NULL)
        {
          if (isUserDefinedRecord(varLhs->type) == true &&
              varRhs->type                      == varLhs->type->refType)
          {

            // HARSHBARGER 2015-12-11:
            // `init_untyped_var` in the `normalize` pass may insert an
            // initCopy, which means that we should not insert an autocopy
            // for that same variable.
            bool initCopied = false;
            for_uses(use, useMap, varLhs) {
              if (CallExpr* call = toCallExpr(use->parentExpr)) {
                if (FnSymbol* parentFn = call->isResolved()) {
                  if (parentFn->hasFlag(FLAG_INIT_COPY_FN)) {
                    initCopied = true;
                    break;
                  }
                }
              }
            }

            if (!initCopied) {
              SET_LINENO(move);

              SymExpr*  lhsCopy0 = symLhs->copy();
              SymExpr*  lhsCopy1 = symLhs->copy();
              FnSymbol* autoCopy = autoCopyMap.get(varLhs->type);
              CallExpr* copyExpr = new CallExpr(autoCopy, lhsCopy0);
              CallExpr* moveExpr = new CallExpr(PRIM_MOVE,lhsCopy1, copyExpr);

              move->insertAfter(moveExpr);
            }
          }
        }
      }