예제 #1
0
//
// 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));
}
예제 #2
0
static void checkErrorHandling(FnSymbol* fn, implicitThrowsReasons_t* reasons)
{
  if (strcmp(fn->name, "deinit") == 0) {
    if (fn->throwsError())
      USR_FATAL_CONT(fn, "deinit is not permitted to throw");
  }

  error_checking_mode_t mode = computeErrorCheckingMode(fn);
  INT_ASSERT(mode != ERROR_MODE_UNKNOWN);

  ErrorCheckingVisitor visit(fn->throwsError(), mode, reasons);

  fn->body->accept(&visit);
}
예제 #3
0
/*
 * Returns true if `e` has no side effects. Checked side effects are:
 *  - Read/write to a global
 *  - Is/contains essential primitive
 *  - If it's a call to functions with ref arguments
 *  - If the LHS of a PRIM_MOVE appears in the exprToMove
 *
 * For now, this is a very conservative analysis. A more precise analysis
 * could distinguish between reads and writes to memory and to take into
 * account alias analysis.
 */
bool SafeExprAnalysis::exprHasNoSideEffects(Expr* e, Expr* exprToMove) {
  if(safeExprCache.count(e) > 0) {
    return safeExprCache[e];
  }
  if(CallExpr* ce = toCallExpr(e)) {
    if(!ce->isPrimitive()) {
      FnSymbol* fnSym = ce->theFnSymbol();
      const bool cachedSafeFn = safeFnCache.count(fnSym);
      if(!cachedSafeFn) {
        const bool retval = fnHasNoSideEffects(fnSym);
        safeFnCache[fnSym] = retval;
        return retval;
      }
      return safeFnCache[fnSym];
    }
    else {
      //primitive
      if(! isSafePrimitive(ce)){
        safeExprCache[e] = false;
        return false;
      }
      else if (exprToMove != NULL) {
        //
        // Exposed by AST pattern like this:
        //          |---|------- `exprToMove`
        // (move T (+ A B))
        // (move A B) -------- `ce`
        // (move B T)
        //
        // Without this check could turn into:
        //
        // (move A B)
        // (move B (+ A B))
        //
        // Which is incorrect.
        //
        if (ce->isPrimitive(PRIM_MOVE)) {
          INT_ASSERT(isSymExpr(ce->get(1)));
          std::vector<SymExpr*> syms;
          collectSymExprs(exprToMove, syms);
          for_vector(SymExpr, s, syms) {
            if (s->symbol() == toSymExpr(ce->get(1))->symbol()) {
              safeExprCache[e] = false;
              return false;
            }
          }
        }
      }
    }
  }
예제 #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_VALUE:
    case PRIM_GET_SVEC_MEMBER_VALUE:
      if (LHS->isRef() == false &&
          isClass(LHS->typeInfo()) == false) {
        return true;
      }
      // fallthrough
    case PRIM_GET_MEMBER:
    case PRIM_GET_SVEC_MEMBER:
    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()) {
        return inferConstRef(LHS->symbol());
      }
    }
    default:
      break;
  }
  return isSafeRefPrimitive(use);
}
예제 #5
0
파일: IpeEnv.cpp 프로젝트: jcazzie/chapel
void IpeEnv::storeFoo(LcnSymbol* sym, IpeValue value)
{
#if 0
  if      (sym->type == dtBools[BOOL_SIZE_SYS])
  {
    storeBool(sym, value.boolGet());
  }

  else if (sym->type == dtInt[INT_SIZE_64])
  {
    storeInteger(sym, value.integerGet());
  }

  else if (sym->type == dtReal[FLOAT_SIZE_64])
  {
    storeReal(sym, value.realGet());
  }

  else
  {
    AstDumpToNode logger(stdout, 3);

    printf("\n\n");
    printf("   IpeEnv::store(LcnSymbol*) Unsupported\n");

    printf("   ");
    sym->accept(&logger);
    printf("\n\n");

    INT_ASSERT(false);

  }
#endif

  INT_ASSERT(false);
}
예제 #6
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;
}
예제 #7
0
//
// Do a breadth first search starting from functions generated for local blocks
// for all function calls in each level of the search, if they directly cause
// communication, add a local temp that isn't wide. If it is a resolved call,
// meaning that it isn't a primitive or external function, clone it and add it
// to the queue of functions to handle at the next iteration of the BFS.
//
static void handleLocalBlocks() {
  Map<FnSymbol*,FnSymbol*> cache; // cache of localized functions
  Vec<BlockStmt*> queue; // queue of blocks to localize

  forv_Vec(BlockStmt, block, gBlockStmts) {
    if (block->parentSymbol) {
      // NOAKES 2014/11/25 Transitional.  Avoid calling blockInfoGet()
      if (block->isLoopStmt() == true) {

      } else if (block->blockInfoGet()) {
        if (block->blockInfoGet()->isPrimitive(PRIM_BLOCK_LOCAL)) {
          queue.add(block);
        }
      }
    }
  }

  forv_Vec(BlockStmt, block, queue) {
    std::vector<CallExpr*> calls;
    collectCallExprs(block, calls);
    for_vector(CallExpr, call, calls) {
      localizeCall(call);
      if (FnSymbol* fn = call->isResolved()) {
        SET_LINENO(fn);
        if (FnSymbol* alreadyLocal = cache.get(fn)) {
          call->baseExpr->replace(new SymExpr(alreadyLocal));
        } else {
          if (!fn->hasFlag(FLAG_EXTERN)) {
            FnSymbol* local = fn->copy();
            local->addFlag(FLAG_LOCAL_FN);
            local->name = astr("_local_", fn->name);
            local->cname = astr("_local_", fn->cname);
            fn->defPoint->insertBefore(new DefExpr(local));
            call->baseExpr->replace(new SymExpr(local));
            queue.add(local->body);
            cache.put(fn, local);
            cache.put(local, local); // to handle recursion
            if (local->retType->symbol->hasFlag(FLAG_WIDE_REF)) {
              CallExpr* ret = toCallExpr(local->body->body.tail);
              INT_ASSERT(ret && ret->isPrimitive(PRIM_RETURN));
              // Capture the return expression in a local temp.
              insertLocalTemp(ret->get(1));
              local->retType = ret->get(1)->typeInfo();
            }
          }
        }
      }
    }
예제 #8
0
static void lowerErrorHandling(FnSymbol* fn)
{
  ArgSymbol*   outError = NULL;
  LabelSymbol* epilogue = NULL;

  if (fn->throwsError()) {
    SET_LINENO(fn);

    outError = addOutErrorArg(fn);
    epilogue = fn->getOrCreateEpilogueLabel();
    INT_ASSERT(epilogue); // throws requires an epilogue
  }

  ErrorHandlingVisitor visitor = ErrorHandlingVisitor(outError, epilogue);
  fn->accept(&visitor);
}
예제 #9
0
파일: foralls.cpp 프로젝트: rchyena/chapel
// This is intended to mimick Expr::remove(), without 'this' being an Expr.
void ForallIntents::removeFI(Expr* parentB) {
  // If this fails need to use trace_remove() instead of remove_help()
  // - see Expr::remove().
  INT_ASSERT(parentB->parentSymbol);

  // "Remove" all ASTs that 'this' contains.
#define REMOVE(dest) if (dest) remove_help(dest, 'r')

  for_vector(Expr, var, fiVars) REMOVE(var);
  for_riSpecs_vector(ri, this)  REMOVE(ri);
  REMOVE(iterRec);
  REMOVE(leadIdx);
  REMOVE(leadIdxCopy);

#undef REMOVE    
}
예제 #10
0
std::string genMakefileEnvCache(void) {
  std::string result;
  std::map<std::string, const char*>::iterator env;

  for (env = envMap.begin(); env != envMap.end(); ++env) {
    const std::string& key = env->first;
    const char* oldPrefix = "CHPL_";
    const char* newPrefix = "CHPL_MAKE_";
    INT_ASSERT(key.substr(0, strlen(oldPrefix)) == oldPrefix);
    std::string keySuffix = key.substr(strlen(oldPrefix), std::string::npos);
    std::string chpl_make_key = newPrefix + keySuffix;
    result += chpl_make_key + "=" + std::string(env->second) + "|";
  }

  return result;
}
예제 #11
0
// This is a placeholder
void IpeModule::initialize()
{
  if      (mState == kLoaded       || mState == kResolving)
    INT_ASSERT(false);

  else if (mState == kInitializing || mState == kInitialized)
    ;

  else
  {
    mState = kInitializing;

    mEnv->initializeUsedModules();

    mState = kInitialized;
  }
}
예제 #12
0
파일: primitive.cpp 프로젝트: Remit/chapel
static Type*
returnInfoArrayIndexValue(CallExpr* call) {
  SymExpr* sym = toSymExpr(call->get(1));
  INT_ASSERT(sym);
  Type* type = sym->var->type;
  if (type->symbol->hasFlag(FLAG_WIDE_CLASS))
    type = type->getField("addr")->type;
  if (!type->substitutions.n)
    INT_FATAL(call, "bad primitive");
  // Is this conditional necessary?  Can just assume condition is true?
  if (type->symbol->hasFlag(FLAG_DATA_CLASS)) {
    return toTypeSymbol(getDataClassType(type->symbol))->type;
  }
  else {
    return toTypeSymbol(type->substitutions.v[0].value)->type;
  }
}
예제 #13
0
//
// Returns true if 'use' appears in a non-side-effecting primitive.
//
static bool isSafeRefPrimitive(SymExpr* use) {
  CallExpr* call = toCallExpr(use->parentExpr);
  INT_ASSERT(call);

  switch (call->primitive->tag) {
    case PRIM_ADDR_OF:
    case PRIM_SET_REFERENCE:
    case PRIM_DEREF:
    case PRIM_WIDE_GET_LOCALE:
    case PRIM_NOOP:
    case PRIM_UNARY_MINUS:
    case PRIM_UNARY_PLUS:
    case PRIM_UNARY_NOT:
    case PRIM_UNARY_LNOT:
    case PRIM_ADD:
    case PRIM_SUBTRACT:
    case PRIM_MULT:
    case PRIM_DIV:
    case PRIM_MOD:
    case PRIM_LSH:
    case PRIM_RSH:
    case PRIM_EQUAL:
    case PRIM_NOTEQUAL:
    case PRIM_LESSOREQUAL:
    case PRIM_GREATEROREQUAL:
    case PRIM_LESS:
    case PRIM_GREATER:
    case PRIM_AND:
    case PRIM_OR:
    case PRIM_XOR:
    case PRIM_POW:
    case PRIM_MIN:
    case PRIM_MAX:
    case PRIM_CHECK_NIL:
    case PRIM_LOCAL_CHECK:
    case PRIM_PTR_EQUAL:
    case PRIM_PTR_NOTEQUAL:
    case PRIM_SIZEOF_BUNDLE:
    case PRIM_SIZEOF_DDATA_ELEMENT:
    case PRIM_WIDE_GET_NODE:
      return true;
    default:
      return false;
  }
}
예제 #14
0
IpeModuleRoot* IpeModuleRoot::allocate()
{
  if (sRootModule == 0)
  {
    ModuleSymbol* modSym = createDeclaration();

    sRootModule = new IpeModuleRoot(modSym);

    sRootModule->init();
  }
  else
  {
    printf("Fatal error:: IpeModuleRoot:allocate has already been executed\n");
    INT_ASSERT(false);
  }

  return sRootModule;
}
예제 #15
0
// 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;
}
예제 #16
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;
}
예제 #17
0
파일: foralls.cpp 프로젝트: rchyena/chapel
static TFITag it2tfi(Expr* ref, IntentTag intent) {
  switch (intent) {
  case INTENT_IN:        return TFI_IN;
  case INTENT_CONST:     return TFI_CONST;
  case INTENT_CONST_IN:  return TFI_CONST_IN;
  case INTENT_REF:       return TFI_REF;
  case INTENT_CONST_REF: return TFI_CONST_REF;
  case INTENT_BLANK:     return TFI_DEFAULT;

  case INTENT_OUT:
  case INTENT_INOUT:
  case INTENT_PARAM:
  case INTENT_TYPE:
    USR_FATAL_CONT(ref, "%s is not supported in a 'with' clause",
                        intentDescrString(intent));
    return TFI_DEFAULT;
  }
  INT_ASSERT(false); // unexpected IntentTag; 'intent' contains garbage?
  return TFI_DEFAULT; // dummy
}
예제 #18
0
파일: postFold.cpp 프로젝트: DawidvC/chapel
Expr* postFold(Expr* expr) {
  SET_LINENO(expr);

  Expr* retval = expr;

  INT_ASSERT(expr->inTree());

  if (CallExpr* call = toCallExpr(expr)) {
    if (call->isResolved() == true) {
      retval = postFoldNormal(call);

    } else if (call->isPrimitive() == true) {
      retval = postFoldPrimop(call);
    }

  } else if (SymExpr* sym = toSymExpr(expr)) {
    retval = postFoldSymExpr(sym);
  }

  return retval;
}
예제 #19
0
int IpeScopeMethod::locationSet(ArgSymbol* arg) const
{
  int offset =  0;
  int retval = -1;

  for (size_t i = 0; i < mVariables.size() && retval == -1; i++)
  {
    if (mVariables[i] == arg)
    {
      retval = offset;
      arg->locationSet(1, offset);
    }
    else
    {
      offset = offset + 8;
    }
  }

  INT_ASSERT(retval >= 0);

  return retval;
}
예제 #20
0
const char* IpeModuleRoot::pathNameForFile(ModTag moduleType, const char* fileName)
{
  const char* retval = NULL;

  switch (moduleType)
  {
    case MOD_INTERNAL:
      retval = pathNameForInternalFile(fileName);
      break;

    case MOD_STANDARD:
      retval = pathNameForStandardFile(fileName);
      break;

    case MOD_USER:
      retval = NULL;
      INT_ASSERT(false);
      break;
  }

  return retval;
}
예제 #21
0
IpeModule* IpeModuleRoot::create(ModuleSymbol* sym)
{
  IpeModule* retval = NULL;

  switch (sym->modTag)
  {
    case MOD_INTERNAL:
      retval = new IpeModuleInternal(sRootModule, sym);
      break;

    case MOD_STANDARD:
      retval = new IpeModuleStandard(sRootModule, sym);
      break;

    case MOD_USER:
      retval = NULL;
      INT_ASSERT(false);
      break;
  }

  return retval;
}
예제 #22
0
static bool feedsIntoForallIterableExpr(FnSymbol* fn, SymExpr* use) {
  if (CallExpr* call = callingExpr(use))
  {
    if (isForallIterExpr(call))
      return true;

    if (FnSymbol* useFn = toFnSymbol(use->parentSymbol))
      // Does 'useFn' return the value of 'use' ?
      if (useFn->retType == fn->retType &&
          isReturnedValue(useFn, use))
      {
        bool forForall = false;
        bool otherUse  = false;
        for_SymbolSymExprs(use2, useFn) {
          CallExpr* call2 = callingExpr(use2);
          if (isForallIterExpr(call2)) forForall = true;
          else                          otherUse = true;
        }

        INT_ASSERT(!(forForall && otherUse));
        return forForall;
      }
예제 #23
0
파일: LoopStmt.cpp 프로젝트: rlugojr/chapel
// If vectorization is enabled and this loop is order independent, codegen
// CHPL_PRAGMA_IVDEP. This method is a no-op if vectorization is off, or the
// loop is not order independent.
void LoopStmt::codegenOrderIndependence()
{
  if (fNoVectorize == false && isOrderIndependent())
  {
    GenInfo* info = gGenInfo;

    // Note: This *must* match the macro definitions provided in the runtime
    std:: string ivdepStr = "CHPL_PRAGMA_IVDEP";
    if (fReportOrderIndependentLoops)
    {
      ModuleSymbol *mod = toModuleSymbol(this->getModule());
      INT_ASSERT(mod);

      if (developer || mod->modTag == MOD_USER)
      {
        printf("Adding %s to %s for %s:%d\n", ivdepStr.c_str(),
            this->astTagAsString(), mod->name, this->linenum());
      }
    }

    info->cStatements.push_back(ivdepStr+'\n');
  }
}
예제 #24
0
  // Scan the SymExprs in the current block, looking for ones that can be replaced.
  for_vector(SymExpr, se, symExprs)
  {
    if (se->isRef()) continue;

    // Replace an alias with its definition, using the current set of
    // available pairs.
    if (isUse(se))
    {
      // See if there is an (alias,def) pair.
      AvailableMap::iterator alias_def_pair = available.find(se->symbol());
      // If so, replace the alias with its definition.
      if (alias_def_pair != available.end())
      {
        DEBUG_COPYPROP("Replacing %s[%d] with %s[%d]\n",
               alias_def_pair->first->name, alias_def_pair->first->id,
               alias_def_pair->second->name, alias_def_pair->second->id);

        INT_ASSERT(alias_def_pair->first != alias_def_pair->second);
        se->setSymbol(alias_def_pair->second);
        ++s_repl_count;
      }
    }
  }
//
// Removes gotos where the label immediately follows the goto and
// unused labels
//
void removeUnnecessaryGotos(FnSymbol* fn) {
  std::vector<BaseAST*> asts;
  std::set<BaseAST*> labels;
  collect_asts_STL(fn, asts);
  for_vector(BaseAST, ast, asts) {
    if (GotoStmt* gotoStmt = toGotoStmt(ast)) {
      DefExpr* def = toDefExpr(gotoStmt->next);
      SymExpr* label = toSymExpr(gotoStmt->label);
      INT_ASSERT(label);
      if (def && def->sym == label->var)
        gotoStmt->remove();
      else
        labels.insert(label->var);
    }
  }

  for_vector(BaseAST, ast2, asts) {
    if (DefExpr* def = toDefExpr(ast2))
      if (LabelSymbol* label = toLabelSymbol(def->sym))
        if (labels.find(label) == labels.end())
          def->remove();
  }
}
예제 #26
0
파일: vec.cpp 프로젝트: jcazzie/chapel
// binary search over intervals
static int
i_find(Intervals *i, int x) {
  INT_ASSERT(i->n);
  int l = 0, h = i->n;
 Lrecurse:
  if (h <= l + 2) {
    if (h <= l)
      return -(l + 1);
    if (x < i->v[l] || x > i->v[l + 1])
      return -(l + 1);
    return h;
  }
  int m = (((h - l) / 4) * 2) + l;
  if (x > i->v[m + 1]) {
    l = m;
    goto Lrecurse;
  }
  if (x < i->v[m]) {    
    h = m;
    goto Lrecurse;
  }
  return (l + 1);
}
//
// A forall-intents variation on isOuterVar() in createTaskFunctions.cpp:
// Is 'sym' defined outside 'block'?
//
static bool isOuterVar(Symbol* sym, BlockStmt* block) {
  if (sym->isParameter()               || // includes isImmediate()
      sym->hasFlag(FLAG_TEMP)          || // exclude these

      // Consts need no special semantics for begin/cobegin/coforall/on.
      // Implementation-wise, it is uniform with consts in nested functions.
      sym->hasFlag(FLAG_CONST)         ||

      // NB 'type' formals do not have INTENT_TYPE
      sym->hasFlag(FLAG_TYPE_VARIABLE)     // 'type' aliases or formals
  ) {
    // these are either not variables or not defined outside of 'fn'
    return false;
  }

  DefExpr*  defPt = sym->defPoint;
  Expr* parentExp = defPt->parentExpr;

  while (true) {
    if (!parentExp) {
      Symbol* parentSym = defPt->parentSymbol;
      if (isModuleSymbol(parentSym))
        // We reached the outermost level and did not come across 'block'.
        return true;

      defPt     = parentSym->defPoint;
      parentExp = defPt->parentExpr;
      continue;
    }
    if (parentExp == block)
      return false;

    parentExp = parentExp->parentExpr;
  }
  INT_ASSERT(false);
  return false; // dummy
}
예제 #28
0
//
// Attempts to replace references with the variables the references point to,
// provided the references have a single definition.
//
// For example:
// var foo : int;
// ref A : int;
// (move A (addr-of foo))
//
// (move B (deref A))     --->    (move B foo)
//
void
eliminateSingleAssignmentReference(Map<Symbol*,Vec<SymExpr*>*>& defMap,
                                   Map<Symbol*,Vec<SymExpr*>*>& useMap,
                                   Symbol* var) {
  if (CallExpr* move = findRefDef(defMap, var)) {
    if (CallExpr* rhs = toCallExpr(move->get(2))) {
      if (rhs->isPrimitive(PRIM_ADDR_OF) || rhs->isPrimitive(PRIM_SET_REFERENCE)) {
        bool stillAlive = false;
        for_uses(se, useMap, var) {
          CallExpr* parent = toCallExpr(se->parentExpr);
          SET_LINENO(se);
          if (parent && (parent->isPrimitive(PRIM_DEREF) || isDerefMove(parent))) {
            SymExpr* se = toSymExpr(rhs->get(1)->copy());
            INT_ASSERT(se);
            Expr* toReplace = parent;
            if (isMoveOrAssign(parent)) {
              toReplace = parent->get(2);
            }
            toReplace->replace(se);
            ++s_ref_repl_count;
            addUse(useMap, se);
          } else if (parent &&
                     (parent->isPrimitive(PRIM_GET_MEMBER_VALUE) ||
                      parent->isPrimitive(PRIM_GET_MEMBER) ||
                      parent->isPrimitive(PRIM_GET_MEMBER_VALUE) ||
                      parent->isPrimitive(PRIM_GET_MEMBER))) {
            SymExpr* se = toSymExpr(rhs->get(1)->copy());
            INT_ASSERT(se);
            parent->get(1)->replace(se);
            ++s_ref_repl_count;
            addUse(useMap, se);
          }
          else if (parent && (parent->isPrimitive(PRIM_MOVE) || parent->isPrimitive(PRIM_SET_REFERENCE))) {
            CallExpr* rhsCopy = rhs->copy();
            if (parent->isPrimitive(PRIM_SET_REFERENCE)) {
              // Essentially a pointer copy like a (move refA refB)
              parent = toCallExpr(parent->parentExpr);
              INT_ASSERT(parent && isMoveOrAssign(parent));
            }
            parent->get(2)->replace(rhsCopy);
            ++s_ref_repl_count;
            SymExpr* se = toSymExpr(rhsCopy->get(1));
            INT_ASSERT(se);
            addUse(useMap, se);
            // BHARSH TODO: Is it possible to handle the following case safely
            // for PRIM_ASSIGN?
            //
            // ref i_foo : T;
            // (move i_foo (set reference bar))
            // (= call_tmp i_foo)
            //
            // Should that turn into (= call_tmp bar)?
          } else if (parent && parent->isPrimitive(PRIM_ASSIGN) && parent->get(1) == se) {
            // for_defs should handle this case
          } else if (parent && parent->isResolved()) {
            stillAlive = true;
            // TODO -- a reference argument can be passed directly
          } else {
            stillAlive = true;
          }
        }
        for_defs(se, defMap, var) {
          CallExpr* parent = toCallExpr(se->parentExpr);
          SET_LINENO(se);
          if (parent == move)
            continue;
          if (parent && isMoveOrAssign(parent)) {
            SymExpr* se = toSymExpr(rhs->get(1)->copy());
            INT_ASSERT(se);
            parent->get(1)->replace(se);
            ++s_ref_repl_count;
            addDef(defMap, se);
          } else
            stillAlive = true;
        }
        if (!stillAlive) {
          var->defPoint->remove();
          Vec<SymExpr*>* defs = defMap.get(var);
          if (defs == NULL) {
            INT_FATAL(var, "Expected var to be defined");
          }
          // Remove the first definition from the AST.
          defs->v[0]->getStmtExpr()->remove();
        }
      } else if (rhs->isPrimitive(PRIM_GET_MEMBER) ||
예제 #29
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;
}
예제 #30
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;
}