Ejemplo n.º 1
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();
            }
          }
        }
      }
    }
Ejemplo n.º 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);
            }
          }
        }
      }
    }
  }
}
Ejemplo n.º 3
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);
            }
          }
        }
      }
Ejemplo n.º 4
0
static bool
markFastSafeFn(FnSymbol *fn, int recurse, Vec<FnSymbol*> *visited) {
  if (fn->hasFlag(FLAG_FAST_ON))
    return true;

  if (fn->hasFlag(FLAG_EXPORT))
    return true;

  if (fn->hasFlag(FLAG_EXTERN)) {
    // consider a pragma to indicate that it would be "fast"
    return false;
  }

  if (fn->hasFlag(FLAG_NON_BLOCKING))
    return false;

  visited->add_exclusive(fn);

  std::vector<CallExpr*> calls;

  collectCallExprs(fn, calls);

  for_vector(CallExpr, call, calls) {
    DEBUG_PRINTF("\tcall %p (id=%d): ", call, call->id);
    bool isLocal = fn->hasFlag(FLAG_LOCAL_FN) || inLocalBlock(call);

    if (!call->primitive) {
      DEBUG_PRINTF("(non-primitive CALL)\n");
      if ((recurse>0) && call->isResolved()) {
        if (call->isResolved()->hasFlag(FLAG_ON_BLOCK)) {
          visited->add_exclusive(call->isResolved());
          call->isResolved()->removeFlag(FLAG_FAST_ON);
          DEBUG_PRINTF("%d: recurse FAILED (nested on block, id=%d).\n",
                       recurse-1, call->id);
          return false;
        }
        if (!visited->in(call->isResolved())) {
          DEBUG_PRINTF("%d: recurse %p (block=%p, id=%d)\n", recurse-1,
                       call->isResolved(), call->isResolved()->body,
                       call->isResolved()->id);
          DEBUG_PRINTF("\tlength=%d\n", call->isResolved()->body->length());
          if (!markFastSafeFn(call->isResolved(), recurse-1, visited)) {
            DEBUG_PRINTF("%d: recurse FAILED (id=%d).\n", recurse-1, call->id);
            return false;
          }
        } else {
          DEBUG_PRINTF("%d: recurse ALREADY VISITED %p (id=%d)\n", recurse-1,
                       call->isResolved(), call->isResolved()->id);
          DEBUG_PRINTF("\tlength=%d\n", call->isResolved()->body->length());
        }
        DEBUG_PRINTF("%d: recurse DONE.\n", recurse-1);
      } else {
        // No function calls allowed
        DEBUG_PRINTF("%d: recurse FAILED (%s, id=%d).\n", recurse-1,
                     recurse == 1 ? "too deep" : "function not resolved",
                     call->id);
        return false;
      }
    } else if (isFastPrimitive(call, isLocal)) {
      DEBUG_PRINTF(" (FAST primitive CALL)\n");
    } else {
      DEBUG_PRINTF("%d: FAILED (non-FAST primitive CALL: %s, id=%d)\n",
                   recurse-1, call->primitive->name, call->id);
      return false;
    }
  }
Ejemplo n.º 5
0
static int
markFastSafeFn(FnSymbol *fn, int recurse, std::set<FnSymbol*>& visited) {

  // First, handle functions we've already visited.
  if (visited.count(fn) != 0) {
    if (fn->hasFlag(FLAG_FAST_ON))
      return FAST_AND_LOCAL;
    if (fn->hasFlag(FLAG_LOCAL_FN))
      return LOCAL_NOT_FAST;
    return NOT_FAST_NOT_LOCAL;
  }

  // Now, add fn to the set of visited functions,
  // since we will categorize it now.
  visited.insert(fn);

  // Next, classify extern functions
  if (fn->hasFlag(FLAG_EXTERN)) {
    if (fn->hasFlag(FLAG_FAST_ON_SAFE_EXTERN)) {
      // Make sure the FAST_ON and LOCAL_FN flags are set.
      fn->addFlag(FLAG_FAST_ON);
      fn->addFlag(FLAG_LOCAL_FN);
      return FAST_AND_LOCAL;
    } else if(fn->hasFlag(FLAG_LOCAL_FN)) {
      return LOCAL_NOT_FAST;
    } else {
      // Other extern functions are not fast or local.
      return NOT_FAST_NOT_LOCAL;
    }
  }

  // Next, go through function bodies.
  // We will set maybefast=false if we see something in the function
  //  that is local but not suitable for a signal handler
  //  (mostly allocation or locking).
  // We will return NOT_FAST_NOT_LOCAL immediately if we see something
  // in the function that is not local.
  bool maybefast = true;

  if (fn->hasFlag(FLAG_NON_BLOCKING))
    maybefast = false;

  std::vector<CallExpr*> calls;

  collectCallExprs(fn, calls);

  for_vector(CallExpr, call, calls) {
    bool inLocal = fn->hasFlag(FLAG_LOCAL_FN) || inLocalBlock(call);

    if (call->primitive) {
      int is = classifyPrimitive(call, inLocal);

      if (!isLocal(is)) {
        // FAST_NOT_LOCAL or NOT_FAST_NOT_LOCAL
        return NOT_FAST_NOT_LOCAL;
      }

      // is == FAST_AND_LOCAL requires no action
      if (is == LOCAL_NOT_FAST) {
        maybefast = false;
      }

    } else {
      if (recurse<=0 || !call->isResolved()) {
        // didn't resolve or past too much recursion.
        // No function calls allowed
        return NOT_FAST_NOT_LOCAL;

      } else {
        // Handle nested 'on' statements
        if (call->resolvedFunction()->hasFlag(FLAG_ON_BLOCK)) {
          if (inLocal) {
            maybefast = false;
          } else {
            return NOT_FAST_NOT_LOCAL;
          }
        }

        // is the call to a fast/local function?
        int is = markFastSafeFn(call->resolvedFunction(),
                                recurse - 1,
                                visited);

        // Remove NOT_LOCAL parts if it's in a local block
        is = setLocal(is, inLocal);

        if (!isLocal(is)) {
          return NOT_FAST_NOT_LOCAL;
        }

        if (is == LOCAL_NOT_FAST) {
          maybefast = false;
        }
        // otherwise, possibly still fast.
      }
    }
  }