예제 #1
0
static bool
symExprIsSetByUse(SymExpr* use) {
  if (CallExpr* call = toCallExpr(use->parentExpr)) {
    if (FnSymbol* fn = call->resolvedFunction()) {
      ArgSymbol* formal = actual_to_formal(use);

      if (formal->intent == INTENT_INOUT || formal->intent == INTENT_OUT) {
        // Shouldn't this be a Def, not a Use, then?
        INT_ASSERT(0);
        return true;
      }

      if (formal->type->symbol->hasFlag(FLAG_REF) &&
          (fn->hasFlag(FLAG_ALLOW_REF) ||
           formal->hasFlag(FLAG_WRAP_WRITTEN_FORMAL))) {
        // This case has to do with wrapper functions (promotion?)
        return true;
      }

    } else if (call->isPrimitive(PRIM_SET_MEMBER)) {
      // PRIM_SET_MEMBER to set the pointer inside of a reference
      // counts as "setter"
      // the below conditional would better be isRefType()
      if (!call->get(2)->typeInfo()->refType) {
        return true;
      }

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

      // It is not necessary to use the 'ref' version
      // if the function result is returned by 'const ref'.
      if (inFn->retTag == RET_CONST_REF) return false;
      // MPF: it seems to cause problems to return false
      // here when inFn->retTag is RET_VALUE.
      // TODO: can we add
      //if (inFn->retTag == RET_VALUE) return false;
      return true;
    }
  }

  return false;
}
예제 #2
0
//
// ref: The reference symbol we will test to see if it is only used as an
// actual where the corresponding formal has FLAG_RETARG.
//
// defCall: The CallExpr where 'ref' is set from a PRIM_ADDR_OF or
// PRIM_SET_REFERENCE. This call will be ignored while considering uses of
// the 'ref' Symbol.
//
static bool onlyUsedForRetarg(Symbol* ref, CallExpr* defCall) {
  bool isRetArgOnly = true;

  INT_ASSERT(ref->isRef());
  INT_ASSERT(defCall != NULL);

  for_SymbolSymExprs(use, ref) {
    if (use->parentExpr == defCall) {
      continue;
    }

    CallExpr* call = toCallExpr(use->parentExpr);
    if (call->isResolved()) {
      ArgSymbol* form = actual_to_formal(use);
      if (form->hasFlag(FLAG_RETARG) == false) {
        isRetArgOnly = false;
      }
    } else {
      isRetArgOnly = false;
    }
  }

  return isRetArgOnly;
}
예제 #3
0
// Note: This function is currently not recursive
static bool inferConst(Symbol* sym) {
  INT_ASSERT(!sym->isRef());
  const bool wasConstVal = sym->qualType().getQual() == QUAL_CONST_VAL;

  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 || wasConstVal) {
    return wasConstVal;
  }

  bool isConstVal = true;
  int numDefs = 0;

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

    CallExpr* call = toCallExpr(use->parentExpr);
    if (call == NULL) {
      // Could be a DefExpr, or the condition for a while loop.
      // BHARSH: I'm not sure of all the possibilities
      continue;
    }

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

    if (call->isResolved()) {
      ArgSymbol* form = actual_to_formal(use);

      //
      // If 'sym' is constructed through a _retArg, we can consider that to
      // be a single 'def'.
      //
      if (form->hasFlag(FLAG_RETARG)) {
        numDefs += 1;
      }
      else if (form->isRef()) {
        if (!inferConstRef(form)) {
          isConstVal = false;
        }
      }
    }
    else if (parent && isMoveOrAssign(parent)) {
      if (call->isPrimitive(PRIM_ADDR_OF) ||
          call->isPrimitive(PRIM_SET_REFERENCE)) {
        Symbol* LHS = toSymExpr(parent->get(1))->symbol();
        INT_ASSERT(LHS->isRef());

        if (onlyUsedForRetarg(LHS, parent)) {
          numDefs += 1;
        }
        else if (!inferConstRef(LHS)) {
          isConstVal = false;
        }
      }
    }
    else if (isMoveOrAssign(call)) {
      if (use == call->get(1)) {
        numDefs += 1;
      }
    } else {
      // To be safe, exit the loop with 'false' if we're unsure of how to
      // handle a primitive.
      isConstVal = false;
    }

    if (numDefs > 1) {
      isConstVal = false;
    }
  }

  if (isConstVal && !info->finalizedConstness) {
    if (ArgSymbol* arg = toArgSymbol(sym)) {
      INT_ASSERT(arg->intent & INTENT_FLAG_IN);
      arg->intent = INTENT_CONST_IN;
    } else {
      INT_ASSERT(isVarSymbol(sym));
      sym->qual = QUAL_CONST_VAL;
    }
  }

  info->reset();
  info->finalizedConstness = true;

  return isConstVal;
}
예제 #4
0
// This routine returns true if the value of the given symbol may have changed
// due to execution of the containing expression.
// If the symbol is a reference, this means that the address to which the
// symbol points will be changed, not the value contained in that address.  See
// isRefUse() for that case.
// To be conservative, the routine should return true by default and then
// select the cases where we are sure nothing has changed.
static bool needsKilling(SymExpr* se, std::set<Symbol*>& liveRefs)
{
  INT_ASSERT(se->isRef() == false);
  if (toGotoStmt(se->parentExpr)) {
    return false;
  }

  if (toCondStmt(se->parentExpr)) {
    return false;
  }

  if (toBlockStmt(se->parentExpr)) {
    return false;
  }

  if (isDefExpr(se->parentExpr)) {
    return false;
  }

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

  if (FnSymbol* fn = call->resolvedFunction())
  {
    // Skip the "base" symbol.
    if (se->symbol() == fn)
    {
      return false;
    }

    ArgSymbol* arg = actual_to_formal(se);

    if (arg->intent == INTENT_OUT   ||
        arg->intent == INTENT_INOUT ||
        arg->intent == INTENT_REF   ||
        arg->hasFlag(FLAG_ARG_THIS)) // Todo: replace with arg intent check?
    {
      liveRefs.insert(se->symbol());
      return true;
    }

    if (isRecordWrappedType(arg->type))
    {
      return true;
    }

    return false;
  }
  else
  {
    const bool isFirstActual = call->get(1) == se;
    if ((call->isPrimitive(PRIM_MOVE) || call->isPrimitive(PRIM_ASSIGN))
        && isFirstActual)
    {
      return true;
    }

    if (isOpEqualPrim(call) && isFirstActual)
    {
      return true;
    }

    if (call->isPrimitive(PRIM_SET_MEMBER) && isFirstActual)
    {
      return true;
    }

    if (call->isPrimitive(PRIM_ARRAY_SET) ||
        call->isPrimitive(PRIM_ARRAY_SET_FIRST))
    {
      if (isFirstActual)
      {
        return true;
      }

      return false;
    }

    if (call->isPrimitive(PRIM_GET_MEMBER))
    {
      // This creates an alias to a portion of the first arg.
      // We could track this as a reference and invalidate a pair containing
      // this symbol when the ref is dereferenced.  But for now, we want to
      // preserve the mapping ref = &value in the RefMap, so having a (ref,
      // value) pair also possibly mean ref = &(value.subfield) does not quite
      // fit.
      // We could keep the ability to do (deref ref) <- value substitution by
      // keeping a separate map for "true" references, or by performing those
      // substitutions in a separate pass.
      // For now, we treat subfield extraction as evidence of a future change
      // to the symbol itself, and use that fact to remove it from
      // consideration in copy propagation.
      if (isFirstActual)
      {
        // We select just the case where the referent is passed by value,
        // because in the other case, the address of the object is not
        // returned, so that means that the address (i.e. the value of the
        // reference variable) does not change.
        return true;
      }

      return false;
    }

    if (call->isPrimitive(PRIM_ADDR_OF) ||
        call->isPrimitive(PRIM_SET_REFERENCE)) {
      liveRefs.insert(se->symbol());
      return true;
    }

    return false;
  }

  INT_ASSERT(0); // Should never get here.

  return true;
}