Пример #1
0
static IntentTag constIntentForType(Type* t) {
  if (isSyncType(t) ||
      isRecordWrappedType(t) ||  // domain, array, or distribution
      isRecord(t) ||  // may eventually want to decide based on size
      is_string_type(t)) {  
    return INTENT_CONST_REF;
  } else if (is_bool_type(t) ||
             is_int_type(t) ||
             is_uint_type(t) ||
             is_real_type(t) ||
             is_imag_type(t) ||
             is_complex_type(t) ||
             is_enum_type(t) ||
             isClass(t) ||
             isUnion(t) ||
             isAtomicType(t) ||
             t == dtOpaque ||
             t == dtTaskID ||
             t == dtFile ||
             t == dtTaskList ||
             t == dtNil ||
             t == dtStringC ||
             t == dtStringCopy ||
             t->symbol->hasFlag(FLAG_EXTERN)) {
    return INTENT_CONST_IN;
  }
  INT_FATAL(t, "Unhandled type in constIntentForType()");
  return INTENT_CONST;
}
Пример #2
0
void buildDefaultFunctions() {
  build_chpl_entry_points();

  SET_LINENO(rootModule); // todo - remove reset_ast_loc() calls below?

  std::vector<BaseAST*> asts;
  collect_asts(rootModule, asts);
  for_vector(BaseAST, ast, asts) {
    if (TypeSymbol* type = toTypeSymbol(ast)) {
      // Here we build default functions that are always generated (even when
      // the type symbol has FLAG_NO_DEFAULT_FUNCTIONS attached).
      if (AggregateType* ct = toAggregateType(type->type)) {
        buildFieldAccessorFunctions(ct);

        if (!ct->symbol->hasFlag(FLAG_REF))
          buildDefaultDestructor(ct);
        // Classes should use the nil:<type> _defaultOf method unless they
        // do not inherit from object.  For those types and records, call
        // we need a more complicated _defaultOf method generated by the
        // compiler
        if (!ct->isClass() || ct->symbol->hasFlag(FLAG_NO_OBJECT))
          build_record_init_function(ct);
      }

      if (type->hasFlag(FLAG_NO_DEFAULT_FUNCTIONS))
        continue;

      // Here we build default functions that respect the "no default
      // functions" pragma.
      if (AggregateType* ct = toAggregateType(type->type))
      {
        buildDefaultReadWriteFunctions(ct);

        if (isRecord(ct)) {
          if (!isRecordWrappedType(ct)) {
            build_record_equality_function(ct);
            build_record_inequality_function(ct);
          }
          build_record_assignment_function(ct);
          build_record_cast_function(ct);
          build_record_copy_function(ct);
          build_record_hash_function(ct);
        }
        if (isUnion(ct))
          build_union_assignment_function(ct);
      }
      else if (EnumType* et = toEnumType(type->type)) {
        //buildDefaultReadFunction(et);
        buildStringCastFunction(et);

        build_enum_cast_function(et);
        build_enum_assignment_function(et);
        build_enum_first_function(et);
        build_enum_enumerate_function(et);
      }
      else
      {
        // The type is a simple type.

        // Other simple types are handled explicitly in the module code.
        // But to avoid putting a catch-all case there to implement assignment
        // for extern types that are simple (as far as we can tell), we build
        // definitions for those assignments here.
        if (type->hasFlag(FLAG_EXTERN)) {
          build_extern_init_function(type->type);
          build_extern_assignment_function(type->type);
        }
      }
    }
  }
}
Пример #3
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;
}