Beispiel #1
0
static Expr* postFoldPrimop(CallExpr* call) {
  Expr* retval = call;

  if (call->isPrimitive(PRIM_MOVE) == true) {
    retval = postFoldMove(call);

  } else if (call->isPrimitive(PRIM_QUERY_TYPE_FIELD)  == true ||
             call->isPrimitive(PRIM_QUERY_PARAM_FIELD) == true) {
    SymExpr* classWrap = toSymExpr(call->get(1));

    if (AggregateType* at = toAggregateType(classWrap->symbol()->type)) {
      const char*  memberName = get_string(call->get(2));
      Vec<Symbol*> keys;

      at->substitutions.get_keys(keys);

      forv_Vec(Symbol, key, keys) {
        if (strcmp(memberName, key->name) == 0) {
          // If there is a substitution for it, replace this call with that
          // substitution
          if (Symbol* value = at->substitutions.get(key)) {
            retval = new SymExpr(value);

            call->replace(retval);
          }
        }
      }

    } else {
Beispiel #2
0
void CallInfo::haltNotWellFormed() const {
  for (int i = 1; i <= call->numActuals(); i++) {
    Expr* actual = call->get(i);

    if (NamedExpr* named = toNamedExpr(actual)) {
      actual = named->actual;
    }

    SymExpr* se = toSymExpr(actual);
    INT_ASSERT(se);

    Symbol*  sym = se->symbol();
    Type*    t   = sym->type;

    if (t == dtUnknown && sym->hasFlag(FLAG_TYPE_VARIABLE) == false) {
      USR_FATAL(call,
                "use of '%s' before encountering its definition, "
                "type unknown",
                sym->name);

    } else if (t->symbol->hasFlag(FLAG_GENERIC) == true) {
      INT_FATAL(call,
                "the type of the actual argument '%s' is generic",
                sym->name);
    }
  }
}
Beispiel #3
0
//
// Determine the index type for a ParamForLoop.
//
// This implementation creates a range with low/high values and then
// asks for its type.
//
Type* ParamForLoop::indexType()
{
  SymExpr*  lse     = lowExprGet();
  SymExpr*  hse     = highExprGet();
  CallExpr* range    = new CallExpr("chpl_build_bounded_range",
                                    lse->copy(), hse->copy());
  Type*     idxType = 0;

  insertBefore(range);

  resolveCall(range);

  if (FnSymbol* sym = range->isResolved())
  {
    resolveFormals(sym);

    DefExpr* formal = toDefExpr(sym->formals.get(1));

    if (toArgSymbol(formal->sym)->typeExpr)
      idxType = toArgSymbol(formal->sym)->typeExpr->body.tail->typeInfo();
    else
      idxType = formal->sym->type;

    range->remove();
  }
  else
  {
    INT_FATAL("unresolved range");
  }

  return idxType;
}
Beispiel #4
0
//
// Assumes 'parent' is a PRIM_MOVE or PRIM_ASSIGN
//
// Returns false if the LHS of the move/assign indicates that the rhs cannot
// be a const-ref. For example, if we have a case like this:
//
// (move A, (set-reference B))
//
// where 'A' and 'B' are references, B cannot be a const-ref if A is not a
// const-ref.
//
// In the case of a dereference, (move A, (deref B)), this function will return
// true because we're simply reading B.
//
static bool canRHSBeConstRef(CallExpr* parent, SymExpr* use) {
  INT_ASSERT(isMoveOrAssign(parent));
  SymExpr* LHS = toSymExpr(parent->get(1));
  CallExpr* rhs = toCallExpr(parent->get(2));
  INT_ASSERT(rhs);
  switch (rhs->primitive->tag) {
    case PRIM_GET_MEMBER:
    case PRIM_GET_MEMBER_VALUE:
    case PRIM_GET_SVEC_MEMBER:
    case PRIM_GET_SVEC_MEMBER_VALUE:
    case PRIM_GET_REAL:
    case PRIM_GET_IMAG:
    case PRIM_ADDR_OF:
    case PRIM_SET_REFERENCE: {
      // If LHS is a reference and is not a const-ref, the reference in 'rhs'
      // should not be considered a const-ref either.
      //
      // For the get-member primitives, I intend this to be a safe approach
      // until we know what const-ref means for fields. Basically, if any field
      // might be modified I do not consider the base object to be const-ref.
      //
      // Note that the get-*-value primitives may return a reference if the
      // field is a reference.
      if (LHS->isRef()) {
        if (!inferConstRef(LHS->symbol())) {
          return false;
        }
      }
    }
    default:
      break;
  }
  return isSafeRefPrimitive(use);
}
Beispiel #5
0
// Mark the variables listed in 'with' clauses, if any, with tiMark markers.
// Same as markOuterVarsWithIntents() in implementForallIntents.cpp,
// except uses byrefVars instead of forallIntents.
static void markOuterVarsWithIntents(CallExpr* byrefVars, SymbolMap& uses) {
  if (!byrefVars) return;
  Symbol* marker = NULL;

  // Keep in sync with setupForallIntents() - the actuals alternate:
  //  (tiMark arg | reduce opExpr), task-intent variable [, repeat]
  for_actuals(actual, byrefVars) {
    SymExpr* se = toSymExpr(actual);
    INT_ASSERT(se); // comes as an UnresolvedSymExpr from the parser,
                    // should have been resolved in ScopeResolve
                    // or it is a SymExpr over a tiMark ArgSymbol
                    //                 or over chpl__reduceGlob
    Symbol* var = se->symbol();
    if (marker) {
      SymbolMapElem* elem = uses.get_record(var);
      if (elem) {
        elem->value = marker;
      } else {
        if (isVarSymbol(marker)) {
          // this is a globalOp created in setupOneReduceIntent()
          INT_ASSERT(!strcmp(marker->name, "chpl__reduceGlob"));
          USR_WARN(byrefVars, "the variable '%s' is given a reduce intent and not mentioned in the loop body - it will have the unit value after the loop", var->name);
        }
      }
      marker = NULL;
    } else {
      marker = var;
      INT_ASSERT(marker);  // otherwise the alternation logic will not work
    }
  }
//
// The argument expr is a use of a wide reference. Insert a check to ensure
// that it is on the current locale, then drop its wideness by moving the
// addr field into a non-wide of otherwise the same type. Then, replace its
// use with the non-wide version.
//
static void insertLocalTemp(Expr* expr) {
  SymExpr* se = toSymExpr(expr);
  Expr* stmt = expr->getStmtExpr();
  INT_ASSERT(se && stmt);
  SET_LINENO(se);
  VarSymbol* var = newTemp(astr("local_", se->var->name),
                           se->var->type->getField("addr")->type);
  if (!fNoLocalChecks) {
    stmt->insertBefore(new CallExpr(PRIM_LOCAL_CHECK, se->copy()));
  }
  stmt->insertBefore(new DefExpr(var));
  stmt->insertBefore(new CallExpr(PRIM_MOVE, var, se->copy()));
  se->replace(new SymExpr(var));
}
Beispiel #7
0
static bool
removeIdentityDefs(Symbol* sym) {
  bool change = false;

  for_defs(def, defMap, sym) {
    CallExpr* move = toCallExpr(def->parentExpr);
    if (move && isMoveOrAssign(move)) {
      SymExpr* rhs = toSymExpr(move->get(2));
      if (rhs && def->symbol() == rhs->symbol()) {
        move->remove();
        change = true;
      }
    }
  }
Beispiel #8
0
  forv_Vec(CallExpr, call, gCallExprs) {
    if (call->isPrimitive(PRIM_CHECK_ERROR)) {
      SET_LINENO(call);

      SymExpr* errSe   = toSymExpr(call->get(1));
      Symbol*  errorVar= errSe->symbol();

      VarSymbol* errorExistsVar = newTemp("errorExists", dtBool);
      DefExpr*   def            = new DefExpr(errorExistsVar);
      CallExpr*  errorExists    = new CallExpr(PRIM_NOTEQUAL, errorVar, gNil);
      CallExpr*  move = new CallExpr(PRIM_MOVE, errorExistsVar, errorExists);

      Expr* stmt = call->getStmtExpr();
      stmt->insertBefore(def);
      def->insertAfter(move);
      call->replace(new SymExpr(errorExistsVar));
    }
  }
// Find the block stmt that encloses the target of this gotoStmt
static BlockStmt* findBlockForTarget(GotoStmt* stmt) {
  BlockStmt* retval = NULL;

  if (stmt != NULL && stmt->isGotoReturn() == false) {
    SymExpr* labelSymExpr = toSymExpr(stmt->label);
    Expr*    ptr          = labelSymExpr->symbol()->defPoint;

    while (ptr != NULL && isBlockStmt(ptr) == false) {
      ptr = ptr->parentExpr;
    }

    retval = toBlockStmt(ptr);

    INT_ASSERT(retval);
  }

  return retval;
}
Beispiel #10
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);
            }
          }
        }
      }
    }
  }
}
Beispiel #11
0
static QualifiedType
returnInfoGetMember(CallExpr* call) {
  AggregateType* ct = toAggregateType(call->get(1)->typeInfo());
  if (ct->symbol->hasFlag(FLAG_REF))
    ct = toAggregateType(ct->getValType());
  if (!ct)
    INT_FATAL(call, "bad member primitive");
  SymExpr* sym = toSymExpr(call->get(2));
  if (!sym)
    INT_FATAL(call, "bad member primitive");
  VarSymbol* var = toVarSymbol(sym->symbol());
  if (!var)
    INT_FATAL(call, "bad member primitive");
  if (var->immediate) {
    const char* name = var->immediate->v_string;
    for_fields(field, ct) {
      if (!strcmp(field->name, name))
        return field->qualType();
    }
  } else
    return sym->qualType();
// 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;
}
//
// Functions have an informal epilogue defined by code that
//
//   1) appears after a common "return label" (if present)
//   2) copies values to out/in-out formals
//
// We must      destroy the primaries before (1).
// We choose to destroy the primaries before (2).
//
// This code detects the start of (2)
//
bool AutoDestroyScope::handlingFormalTemps(const Expr* stmt) const {
  bool retval = false;

  if (mLocalsHandled == false) {
    if (const CallExpr* call = toConstCallExpr(stmt)) {
      if (FnSymbol* fn = call->resolvedFunction()) {
        if (fn->hasFlag(FLAG_ASSIGNOP) == true && call->numActuals() == 2) {
          SymExpr* lhs = toSymExpr(call->get(1));
          SymExpr* rhs = toSymExpr(call->get(2));

          if (lhs                                      != NULL &&
              rhs                                      != NULL &&
              isArgSymbol(lhs->symbol())               == true &&
              rhs->symbol()->hasFlag(FLAG_FORMAL_TEMP) == true) {
            retval = true;
          }
        }
      }
    }
  }

  return retval;
}
Beispiel #14
0
// This routine looks for loops in which the condition variable is *not*
// updated within the body of the loop, and issues a warning for places
// in the code where that occurs.
void WhileStmt::checkConstLoops()
{
  SymExpr* tmpVar  = condExprForTmpVariableGet();

  // Get the loop condition variable.
  if (VarSymbol* condSym = toVarSymbol(tmpVar->symbol()))
  {
    // Look for definitions of the loop condition variable
    // within the body of the loop.
    if (SymExpr* condDef = getWhileCondDef(condSym))
    {
      // Get the call expression that updates the condition variable.
      if (CallExpr* outerCall = toCallExpr(condDef->parentExpr))
      {
        // Assume the outer call is a move expression and that its LHS is
        // the (SymExpr that contains the) loop condition variable.
        if (outerCall->get(1) == condDef)
        {
          if (outerCall->isPrimitive(PRIM_MOVE))
          {
            // Expect the update to be the result of a call to _cond_test.
            if (CallExpr* innerCall = toCallExpr(outerCall->get(2)))
            {
              FnSymbol* fn = innerCall->resolvedFunction();

              if (innerCall->numActuals()        == 1 &&
                  strcmp(fn->name, "_cond_test") == 0)
              {
                checkWhileLoopCondition(innerCall->get(1));
              }
              else
              {
                INT_FATAL(innerCall,
                          "Expected the update of a loop conditional "
                          "to be piped through _cond_test().");
              }
            }

            // The RHS of the move can also be a SymExpr as the result of param
            // folding ...
            else if (SymExpr* moveSrc = toSymExpr(outerCall->get(2)))
            {
              // ... in which case, the literal should be 'true' or 'false'.
              if (moveSrc->symbol() == gTrue)
              {
                // while true do ... ;  -- probably OK.
                // User said to loop forever ... .
              }

              else if (moveSrc->symbol() == gFalse)
              {
                // while false do ...; -- probably nothing to worry about
                // We probably don't get here unless fRemoveUnreachableBlocks
                // is false.
              }

              else
              {
                INT_FATAL(moveSrc,
                          "Expected const loop condition variable to be "
                          "true or false.");
              }
            }

            else
            {
              // The RHS was neither a CallExpr nor a SymExpr.
              INT_FATAL(outerCall,
                        "Invalid RHS in a loop condition variable update "
                        "expression.");
            }
          }

          else
          {
            INT_FATAL(outerCall,
                      "Expected a loop condition variable update to "
                      "be a MOVE.");
          }
        }
        else
        {
          // Note that this being true depends on the compiler inserting a temp
          // that is the result of applying _cond_test to a more-general loop
          // conditional expression.
          // Copy propagation could potentially make this false again....
          INT_FATAL(condDef,
                    "Expected loop condition variable to be only "
                    "updated (not read).");
        }
      }

      else
      {
        INT_FATAL(condDef,
                  "The update of a loop condition variable could not "
                  "be converted to a call.");
      }
    }
    else
    {
      // There was no update of the loop condition variable in the
      // body of the loop.
      // It could be an infinite loop, or it could have a
      // 'break' or 'return' in it.
    }
  }

  else
  {
    INT_FATAL(tmpVar,
              "The loop condition variable could not be converted "
              "to a VarSymbol.");
  }
}
Beispiel #15
0
static bool inferRefToConst(Symbol* sym) {
  INT_ASSERT(sym->isRef());

  bool isConstRef = sym->qualType().getQual() == QUAL_CONST_REF;
  const bool wasRefToConst = sym->hasFlag(FLAG_REF_TO_CONST);

  ConstInfo* info = infoMap[sym];

  // If this ref isn't const, then it can't point to a const thing
  if (info == NULL) {
    return false;
  } else if (info->finalizedRefToConst || wasRefToConst || !isConstRef) {
    return wasRefToConst;
  }

  bool isFirstCall = false;
  if (info->alreadyCalled == false) {
    isFirstCall = true;
    info->alreadyCalled = true;
  }

  bool isRefToConst = true;

  if (isArgSymbol(sym)) {
    // Check each call and set isRefToConst to false if any actual is not a ref
    // to a const.
    FnSymbol* fn = toFnSymbol(sym->defPoint->parentSymbol);
    if (fn->hasFlag(FLAG_VIRTUAL) ||
        fn->hasFlag(FLAG_EXPORT)  ||
        fn->hasFlag(FLAG_EXTERN)) {
      // Not sure how to best handle virtual calls, so simply set false for now
      //
      // For export or extern functions, return false because we don't have
      // all the information about how the function is called.
      isRefToConst = false;
    } else {
      // Need this part to be re-entrant in case of recursive functions
      while (info->fnUses != NULL && isRefToConst) {
        SymExpr* se = info->fnUses;
        info->fnUses = se->symbolSymExprsNext;

        CallExpr* call = toCallExpr(se->parentExpr);
        INT_ASSERT(call && call->isResolved());

        Symbol* actual = toSymExpr(formal_to_actual(call, sym))->symbol();

        if (actual->isRef()) {
          // I don't think we technically need to skip if the actual is the
          // same symbol as the formal, but it makes things simpler.
          if (actual != sym && !inferRefToConst(actual)) {
            isRefToConst = false;
          }
        } else {
          // Passing a non-ref actual to a reference formal is currently
          // considered to be the same as an addr-of
          if (actual->qualType().getQual() != QUAL_CONST_VAL) {
            isRefToConst = false;
          }
        }
      }
    }
  }

  while (info->hasMore() && isRefToConst) {
    SymExpr* use = info->next();

    CallExpr* call = toCallExpr(use->parentExpr);
    if (call == NULL) continue;

    if (isMoveOrAssign(call)) {
      if (use == call->get(1)) {
        if (SymExpr* se = toSymExpr(call->get(2))) {
          if (se->isRef() && !inferRefToConst(se->symbol())) {
            isRefToConst = false;
          }
        }
        else {
          CallExpr* RHS = toCallExpr(call->get(2));
          INT_ASSERT(RHS);
          if (RHS->isPrimitive(PRIM_ADDR_OF) ||
              RHS->isPrimitive(PRIM_SET_REFERENCE)) {
            SymExpr* src = toSymExpr(RHS->get(1));
            if (src->isRef()) {
              if (!inferRefToConst(src->symbol())) {
                isRefToConst = false;
              }
            } else {
              if (src->symbol()->qualType().getQual() != QUAL_CONST_VAL) {
                isRefToConst = false;
              }
            }
          } else {
            isRefToConst = false;
          }
        }
      }
    }
    else if (call->isResolved()) {
      isRefToConst = true;
    }
    else {
      isRefToConst = isSafeRefPrimitive(use);
    }
  }

  if (isFirstCall) {
    if (isRefToConst) {
      INT_ASSERT(info->finalizedRefToConst == false);
      sym->addFlag(FLAG_REF_TO_CONST);
    }

    info->reset();
    info->finalizedRefToConst = true;
  } else if (!isRefToConst) {
    info->finalizedRefToConst = true;
  }

  return isRefToConst;
}
Beispiel #16
0
//
// Returns 'true' if 'sym' is (or should be) a const-ref.
// If 'sym' can be a const-ref, but is not, this function will change either
// the intent or qual of the Symbol to const-ref.
//
static bool inferConstRef(Symbol* sym) {
  INT_ASSERT(sym->isRef());
  bool wasConstRef = sym->qualType().getQual() == QUAL_CONST_REF;

  if (sym->defPoint->parentSymbol->hasFlag(FLAG_EXTERN)) {
    return wasConstRef;
  }

  ConstInfo* info = infoMap[sym];

  // 'info' may be null if the argument is never used. In that case we can
  // consider 'sym' to be a const-ref. By letting the rest of the function
  // proceed, we'll fix up the qualifier for such symbols at the end.
  if (info == NULL) {
    return true;
  } else if (info->finalizedConstness || wasConstRef) {
    return wasConstRef;
  }

  bool isFirstCall = false;
  if (info->alreadyCalled == false) {
    isFirstCall = true;
    info->alreadyCalled = true;
  }

  bool isConstRef = true;

  while (info->hasMore() && isConstRef) {
    SymExpr* use = info->next();

    CallExpr* call = toCallExpr(use->parentExpr);
    INT_ASSERT(call);

    CallExpr* parent = toCallExpr(call->parentExpr);

    if (call->isResolved()) {
      ArgSymbol* form = actual_to_formal(use);
      if (form->isRef() && !inferConstRef(form)) {
        isConstRef = false;
      }
    }
    else if (parent && isMoveOrAssign(parent)) {
      if (!canRHSBeConstRef(parent, use)) {
        isConstRef = false;
      }
    }
    else if (call->isPrimitive(PRIM_MOVE)) {
      //
      // Handles three cases:
      // 1) MOVE use value - writing to a reference, so 'use' cannot be const
      // 2) MOVE ref use - if the LHS is not const, use cannot be const either
      // 3) MOVE value use - a dereference of 'use'
      //
      if (use == call->get(1)) {
        // CASE 1
        if (!call->get(2)->isRef()) {
          isConstRef = false;
        }
      } else {
        // 'use' is the RHS of a MOVE
        if (call->get(1)->isRef()) {
          // CASE 2
          SymExpr* se = toSymExpr(call->get(1));
          INT_ASSERT(se);
          if (!inferConstRef(se->symbol())) {
            isConstRef = false;
          }
        }
        // else CASE 3: do nothing because isConstRef is already true
      }
    }
    else if (call->isPrimitive(PRIM_ASSIGN)) {
      if (use == call->get(1)) {
        isConstRef = false;
      }
    }
    else if (call->isPrimitive(PRIM_SET_MEMBER) ||
             call->isPrimitive(PRIM_SET_SVEC_MEMBER)) {
      // BHARSH 2016-11-02
      // In the expr (set_member base member rhs),
      // If use == base, I take the conservative approach and decide that 'use'
      // is not a const-ref. I'm not sure that we've decided what const means
      // for fields yet, so this seems safest.
      //
      // If use == rhs, then we would need to do analysis for the member field.
      // That's beyond the scope of what I'm attempting at the moment, so to
      // be safe we'll return false for that case.
      if (use == call->get(1) || use == call->get(3)) {
        isConstRef = false;
      } else {
        // use == member
        // If 'rhs' is not a ref, then we're writing into 'use'. Otherwise it's
        // a pointer copy and we don't care if 'rhs' is writable.
        if (!call->get(3)->isRef()) {
          isConstRef = false;
        }
      }
    } else {
      // To be safe, exit the loop with 'false' if we're unsure of how to
      // handle a primitive.
      isConstRef = false;
    }
  }

  if (isFirstCall) {
    if (isConstRef) {
      INT_ASSERT(info->finalizedConstness == false);
      if (ArgSymbol* arg = toArgSymbol(sym)) {
        arg->intent = INTENT_CONST_REF;
      } else {
        INT_ASSERT(isVarSymbol(sym));
        sym->qual = QUAL_CONST_REF;
      }
    }

    info->reset();
    info->finalizedConstness = true;
  } else if (!isConstRef) {
    info->finalizedConstness = true;
  }

  return isConstRef;
}
Beispiel #17
0
static
bool symExprIsUsedAsConstRef(SymExpr* use) {
  if (CallExpr* call = toCallExpr(use->parentExpr)) {
    if (FnSymbol* calledFn = call->resolvedFunction()) {
      ArgSymbol* formal = actual_to_formal(use);

      // generally, use const-ref-return if passing to const ref formal
      if (formal->intent == INTENT_CONST_REF) {
        // but make an exception for initCopy calls
        if (calledFn->hasFlag(FLAG_INIT_COPY_FN))
          return false;

        // TODO: tuples of types with blank intent
        // being 'in' should perhaps use the value version.
        return true;
      }

    } else if (call->isPrimitive(PRIM_RETURN) ||
               call->isPrimitive(PRIM_YIELD)) {
      FnSymbol* inFn = toFnSymbol(call->parentSymbol);

      // use const-ref-return if returning by const ref intent
      if (inFn->retTag == RET_CONST_REF)
        return true;

    } else if (call->isPrimitive(PRIM_WIDE_GET_LOCALE) ||
               call->isPrimitive(PRIM_WIDE_GET_NODE)) {
      // If we are extracting a field from the wide pointer,
      // we need to keep it as a pointer.

      // use const-ref-return if querying locale
      return true;

    } else {
      // Check for the case that sym is moved to a compiler-introduced
      // variable, possibly with PRIM_MOVE tmp, PRIM_ADDR_OF sym
      if (call->isPrimitive(PRIM_ADDR_OF) ||
          call->isPrimitive(PRIM_SET_REFERENCE) ||
          call->isPrimitive(PRIM_GET_MEMBER) ||
          call->isPrimitive(PRIM_GET_SVEC_MEMBER))
        call = toCallExpr(call->parentExpr);

      if (call->isPrimitive(PRIM_MOVE)) {
        SymExpr* lhs = toSymExpr(call->get(1));
        Symbol* lhsSymbol = lhs->symbol();

        if (lhsSymbol->hasFlag(FLAG_REF_VAR)) {
          // intended to handle 'const ref'
          // it would be an error to reach this point if it is not const
          INT_ASSERT(lhsSymbol->hasFlag(FLAG_CONST));
          return true;
        }

        if (lhs != use &&
            lhsSymbol->isRef() &&
            symbolIsUsedAsConstRef(lhsSymbol))
          return true;
      }
    }
  }
  return false;
}
//
// If call has the potential to cause communication, assert that the wide
// reference that might cause communication is local and remove its wide-ness
//
// The organization of this function follows the order of CallExpr::codegen()
// leaving out primitives that don't communicate.
//
static void localizeCall(CallExpr* call) {
  if (call->primitive) {
    switch (call->primitive->tag) {
    case PRIM_ARRAY_SET: /* Fallthru */
    case PRIM_ARRAY_SET_FIRST:
      if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
        insertLocalTemp(call->get(1));
      }
      break;
    case PRIM_MOVE:
    case PRIM_ASSIGN: // Not sure about this one.
      if (CallExpr* rhs = toCallExpr(call->get(2))) {
        if (rhs->isPrimitive(PRIM_DEREF)) {
          if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) ||
              rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
            insertLocalTemp(rhs->get(1));
            if (!rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_REF)) {
              INT_ASSERT(rhs->get(1)->typeInfo() == dtString);
              // special handling for wide strings
              rhs->replace(rhs->get(1)->remove());
            }
          }
          break;
        } 
        else if (rhs->isPrimitive(PRIM_GET_MEMBER) ||
                   rhs->isPrimitive(PRIM_GET_SVEC_MEMBER) ||
                   rhs->isPrimitive(PRIM_GET_MEMBER_VALUE) ||
                   rhs->isPrimitive(PRIM_GET_SVEC_MEMBER_VALUE)) {
          if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) ||
              rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
            SymExpr* sym = toSymExpr(rhs->get(2));
            INT_ASSERT(sym);
            if (!sym->var->hasFlag(FLAG_SUPER_CLASS)) {
              insertLocalTemp(rhs->get(1));
            }
          }
          break;
        } else if (rhs->isPrimitive(PRIM_ARRAY_GET) ||
                   rhs->isPrimitive(PRIM_ARRAY_GET_VALUE)) {
          if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
            SymExpr* lhs = toSymExpr(call->get(1));
            Expr* stmt = call->getStmtExpr();
            INT_ASSERT(lhs && stmt);

            SET_LINENO(stmt);
            insertLocalTemp(rhs->get(1));
            VarSymbol* localVar = NULL;
            if (rhs->isPrimitive(PRIM_ARRAY_GET))
              localVar = newTemp(astr("local_", lhs->var->name),
                                 lhs->var->type->getField("addr")->type);
            else
              localVar = newTemp(astr("local_", lhs->var->name),
                                 lhs->var->type);
            stmt->insertBefore(new DefExpr(localVar));
            lhs->replace(new SymExpr(localVar));
            stmt->insertAfter(new CallExpr(PRIM_MOVE, lhs,
                                           new SymExpr(localVar)));
          }
          break;
        } else if (rhs->isPrimitive(PRIM_GET_UNION_ID)) {
          if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) {
            insertLocalTemp(rhs->get(1));
          }
          break;
        } else if (rhs->isPrimitive(PRIM_TESTCID) ||
                   rhs->isPrimitive(PRIM_GETCID)) {
          if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
            insertLocalTemp(rhs->get(1));
          }
          break;
        }
        ;
      }
      if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) &&
          !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
        break;
      }
      if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) &&
          !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) &&
          !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_REF)) {
        insertLocalTemp(call->get(1));
      }
      break;
    case PRIM_DYNAMIC_CAST:
      if (call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
        insertLocalTemp(call->get(2));
        if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) ||
            call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) {
          toSymExpr(call->get(1))->var->type = call->get(1)->typeInfo()->getField("addr")->type;
        }
      }
      break;
    case PRIM_SETCID:
      if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
        insertLocalTemp(call->get(1));
      }
      break;
    case PRIM_SET_UNION_ID:
      if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) {
        insertLocalTemp(call->get(1));
      }
      break;
    case PRIM_SET_MEMBER:
    case PRIM_SET_SVEC_MEMBER:
      if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) ||
          call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) {
        insertLocalTemp(call->get(1));
      }
      break;
    default:
      break;
    }
  }
}
Beispiel #19
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);
            }
          }
        }
      }
Beispiel #20
0
bool CallInfo::isWellFormed(CallExpr* callExpr) {
  bool retval = true;

  call = callExpr;

  if (SymExpr* se = toSymExpr(call->baseExpr)) {
    name = se->symbol()->name;

  } else if (UnresolvedSymExpr* use = toUnresolvedSymExpr(call->baseExpr)) {
    name = use->unresolved;
  }

  if (call->numActuals() >= 2) {
    if (SymExpr* se = toSymExpr(call->get(1))) {
      if (se->symbol() == gModuleToken) {
        se->remove();

        se = toSymExpr(call->get(1));
        INT_ASSERT(se);

        ModuleSymbol* mod = toModuleSymbol(se->symbol());
        INT_ASSERT(mod);

        se->remove();

        scope = mod->block;
      }
    }
  }

  for (int i = 1; i <= call->numActuals() && retval == true; i++) {
    Expr* actual = call->get(i);

    if (NamedExpr* named = toNamedExpr(actual)) {
      actualNames.add(named->name);

      actual = named->actual;

    } else {
      actualNames.add(NULL);
    }

    SymExpr* se = toSymExpr(actual);

    INT_ASSERT(se);

    Symbol*  sym = se->symbol();
    Type*    t   = sym->type;

    if (t == dtUnknown && sym->hasFlag(FLAG_TYPE_VARIABLE) == false) {
      retval = false;

    } else if (t->symbol->hasFlag(FLAG_GENERIC) == true) {
      // The _this actual to an initializer may be generic
      if (strcmp(name, "init") == 0 && i == 2) {
        actuals.add(sym);

      } else {
        retval = false;
      }

    } else {
      actuals.add(sym);
    }
  }

  return retval;
}