Exemplo n.º 1
0
//
// Return true if this primitive function is safe for fast on optimization
// (e.g., no communication, no sync/single accesses)
//
static bool
isFastPrimitive(CallExpr *call, bool isLocal) {
  INT_ASSERT(call->primitive);
  // Check primitives for communication
  switch (call->primitive->tag) {
  case PRIM_UNKNOWN:
    // TODO: Return true for PRIM_UNKNOWNs that are side-effect free
    return false;

  case PRIM_NOOP:
  case PRIM_REF_TO_STRING:
  case PRIM_RETURN:
  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_GET_MEMBER:
  case PRIM_GET_SVEC_MEMBER:
  case PRIM_GET_PRIV_CLASS:
  case PRIM_NEW_PRIV_CLASS:

  case PRIM_CHECK_NIL:
  case PRIM_GET_REAL:
  case PRIM_GET_IMAG:

  case PRIM_ADDR_OF:
  case PRIM_LOCAL_CHECK:

  case PRIM_INIT_FIELDS:
  case PRIM_PTR_EQUAL:
  case PRIM_PTR_NOTEQUAL:
  case PRIM_CAST:

  case PRIM_BLOCK_LOCAL:

  case PRIM_ON_LOCALE_NUM:
  case PRIM_GET_SERIAL:
  case PRIM_SET_SERIAL:

  case PRIM_START_RMEM_FENCE:
  case PRIM_FINISH_RMEM_FENCE:

  case PRIM_STRING_COPY:
  case PRIM_C_STRING_FROM_STRING:
  case PRIM_CAST_TO_VOID_STAR:
  case PRIM_SIZEOF:

  case PRIM_GET_USER_LINE:
  case PRIM_GET_USER_FILE:
    DEBUG_PRINTF(" *** OK (default): %s\n", call->primitive->name);
    return true;

  case PRIM_MOVE:
  case PRIM_ASSIGN:
  case PRIM_ADD_ASSIGN:
  case PRIM_SUBTRACT_ASSIGN:
  case PRIM_MULT_ASSIGN:
  case PRIM_DIV_ASSIGN:
  case PRIM_MOD_ASSIGN:
  case PRIM_LSH_ASSIGN:
  case PRIM_RSH_ASSIGN:
  case PRIM_AND_ASSIGN:
  case PRIM_OR_ASSIGN:
  case PRIM_XOR_ASSIGN:
    if (!isCallExpr(call->get(2))) { // callExprs checked in calling function
      if (!call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) &&
          !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) {
        DEBUG_PRINTF(" *** OK (PRIM_MOVE 1): %s\n", call->primitive->name);
        return true;
      }
    } else {
      DEBUG_PRINTF(" *** OK (PRIM_MOVE 2): %s\n", call->primitive->name);
      // Not necessarily true, but we return true because
      // the callExpr will be checked in the calling function
      return true;
    }
    break;

// I think these can always return true. <hilde>
// But that works only if the remote get is removed from code generation.
  case PRIM_WIDE_GET_LOCALE:
  case PRIM_WIDE_GET_NODE:
  case PRIM_WIDE_GET_ADDR:
    // If this test is true, a remote get is required.
    if (!(call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) &&
          call->get(1)->getValType()->symbol->hasFlag(FLAG_WIDE_CLASS))) {
      DEBUG_PRINTF(" *** OK (PRIM_WIDE_GET_LOCALE, etc.): %s\n",
                   call->primitive->name);
      return true;
    }
    break;

  case PRIM_SET_UNION_ID:
  case PRIM_GET_UNION_ID:
  case PRIM_GET_MEMBER_VALUE:
  case PRIM_GET_SVEC_MEMBER_VALUE:
    if (!call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) {
      return true;
      DEBUG_PRINTF(" *** OK (PRIM_SET_UNION_ID, etc.): %s\n",
                   call->primitive->name);
    }
    break;

  case PRIM_ARRAY_SET:
  case PRIM_ARRAY_SET_FIRST:
  case PRIM_SETCID:
  case PRIM_TESTCID:
  case PRIM_GETCID:
  case PRIM_ARRAY_GET:
  case PRIM_ARRAY_GET_VALUE:
  case PRIM_DYNAMIC_CAST:
    if (!call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
      DEBUG_PRINTF(" *** OK (PRIM_ARRAY_SET, etc.): %s\n",
                   call->primitive->name);
      return true;
    }
    break;

  case PRIM_DEREF:
  case PRIM_SET_MEMBER:
  case PRIM_SET_SVEC_MEMBER:
    if (!call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) &&
        !call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
      DEBUG_PRINTF(" *** OK (PRIM_DEREF, etc.): %s\n", call->primitive->name);
      return true;
    }
    break;

  case PRIM_CHPL_COMM_GET:
  case PRIM_CHPL_COMM_PUT:
  case PRIM_CHPL_COMM_REMOTE_PREFETCH:
  case PRIM_CHPL_COMM_GET_STRD:
  case PRIM_CHPL_COMM_PUT_STRD:
    // These may involve communication, so are deemed slow.
    return false;

  case PRIM_SYNC_INIT: // Maybe fast?
  case PRIM_SYNC_DESTROY: // Maybe fast?
  case PRIM_SYNC_LOCK:
  case PRIM_SYNC_UNLOCK:
  case PRIM_SYNC_WAIT_FULL:
  case PRIM_SYNC_WAIT_EMPTY:
  case PRIM_SYNC_SIGNAL_FULL:
  case PRIM_SYNC_SIGNAL_EMPTY:
  case PRIM_SINGLE_INIT: // Maybe fast?
  case PRIM_SINGLE_DESTROY: // Maybe fast?
  case PRIM_SINGLE_LOCK:
  case PRIM_SINGLE_UNLOCK:
  case PRIM_SINGLE_WAIT_FULL:
  case PRIM_SINGLE_SIGNAL_FULL:

  case PRIM_WRITEEF:
  case PRIM_WRITEFF:
  case PRIM_WRITEXF:
  case PRIM_READFE:
  case PRIM_READFF:
  case PRIM_READXX:
  case PRIM_SYNC_IS_FULL:
  case PRIM_SINGLE_WRITEEF:
  case PRIM_SINGLE_READFF:
  case PRIM_SINGLE_READXX:
  case PRIM_SINGLE_IS_FULL:
   // These may block, so are deemed slow.
   return false;

  case PRIM_NEW:
  case PRIM_INIT:
  case PRIM_NO_INIT:
  case PRIM_TYPE_INIT:
  case PRIM_LOGICAL_FOLDER:
  case PRIM_TYPEOF:
  case PRIM_TYPE_TO_STRING:
  case PRIM_ENUM_MIN_BITS:
  case PRIM_ENUM_IS_SIGNED:
  case PRIM_IS_UNION_TYPE:
  case PRIM_IS_ATOMIC_TYPE:
  case PRIM_IS_SYNC_TYPE:
  case PRIM_IS_SINGLE_TYPE:
  case PRIM_IS_TUPLE_TYPE:
  case PRIM_IS_STAR_TUPLE_TYPE:
  case PRIM_IS_SUBTYPE:
  case PRIM_TUPLE_EXPAND:
  case PRIM_TUPLE_AND_EXPAND:
  case PRIM_QUERY:
  case PRIM_QUERY_PARAM_FIELD:
  case PRIM_QUERY_TYPE_FIELD:
  case PRIM_ERROR:
  case PRIM_WARNING:

  case PRIM_BLOCK_PARAM_LOOP:
  case PRIM_BLOCK_BEGIN:
  case PRIM_BLOCK_COBEGIN:
  case PRIM_BLOCK_COFORALL:
  case PRIM_BLOCK_ON:
  case PRIM_BLOCK_BEGIN_ON:
  case PRIM_BLOCK_COBEGIN_ON:
  case PRIM_BLOCK_COFORALL_ON:
  case PRIM_BLOCK_UNLOCAL:

  case PRIM_ACTUALS_LIST:
  case PRIM_YIELD:

  case PRIM_USE:
  case PRIM_USED_MODULES_LIST:

  case PRIM_WHEN:
  case PRIM_INT_ERROR:
  case PRIM_CAPTURE_FN:
  case PRIM_CREATE_FN_TYPE:

  case PRIM_NUM_FIELDS:
  case PRIM_FIELD_NUM_TO_NAME:
  case PRIM_FIELD_VALUE_BY_NUM:
  case PRIM_FIELD_ID_BY_NUM:
  case PRIM_FIELD_VALUE_BY_NAME:
    INT_FATAL("This primitive should have been removed from the tree by now.");
    break;

    // By themselves, loops are considered "fast".
  case PRIM_BLOCK_WHILEDO_LOOP:
  case PRIM_BLOCK_DOWHILE_LOOP:
  case PRIM_BLOCK_FOR_LOOP:
  case PRIM_BLOCK_C_FOR_LOOP:
    return true;
 
   // These don't block in the Chapel sense, but they may require a system
    // call so we don't consider them eligible.
    //
  case PRIM_FREE_TASK_LIST:
  case PRIM_ARRAY_ALLOC:
  case PRIM_ARRAY_FREE:
  case PRIM_ARRAY_FREE_ELTS:
  case PRIM_STRING_FROM_C_STRING:
    return false;

    // Temporarily unclassified (legacy) cases.
    // These formerly defaulted to false (slow), so we leave them
    // here until they are proven fast.
  case PRIM_GET_END_COUNT:
  case PRIM_SET_END_COUNT:
  case PRIM_PROCESS_TASK_LIST:
  case PRIM_EXECUTE_TASKS_IN_LIST:
  case PRIM_TO_LEADER:
  case PRIM_TO_FOLLOWER:
  case PRIM_DELETE:
  case PRIM_CALL_DESTRUCTOR:
  case PRIM_HEAP_REGISTER_GLOBAL_VAR:
  case PRIM_HEAP_BROADCAST_GLOBAL_VARS:
  case PRIM_PRIVATE_BROADCAST:
  case PRIM_RT_ERROR:
  case PRIM_RT_WARNING:
  case PRIM_FTABLE_CALL:
  case PRIM_VIRTUAL_METHOD_CALL:
    return false;

  default:
    INT_FATAL("Unhandled case.");
    break;
  }

  return isLocal;
}
Exemplo n.º 2
0
// Returns max local frame space to evaluate this expr
int locationExpr(Expr* expr, IpeEnv* env)
{
  int retval = 0;

  if (DefExpr* defExpr = toDefExpr(expr))
  {
    VarSymbol* var   = toVarSymbol(defExpr->sym);
    int        delta = 8;           // NOAKES  Size of every type is currently 8

    INT_ASSERT(var);

    env->locationSet(var);

    retval = delta;
  }

  else if (isCallExpr(expr) == true)
    retval = 0;

  else if (CondStmt*    stmt = toCondStmt(expr))
  {
    if (stmt->elseStmt == NULL)
    {
      retval = locationExpr(stmt->thenStmt, env);
    }

    else
    {
      int thenSize = locationExpr(stmt->thenStmt, env);
      int elseSize = locationExpr(stmt->elseStmt, env);

      retval = (thenSize > elseSize) ? thenSize : elseSize;
    }
  }

  else if (WhileDoStmt* stmt = toWhileDoStmt(expr))
  {
    Expr* body = stmt->body.get(1);

    INT_ASSERT(stmt->body.length == 1);
    INT_ASSERT(isBlockStmt(body));

    retval = locationExpr(body, env);
  }

  else if (BlockStmt* stmt = toBlockStmt(expr))
  {
    IpeBlockStmt* ipeStmt  = (IpeBlockStmt*) stmt;
    int           maxFrame = 0;
    IpeEnv        env(ipeStmt->scopeGet());

    for (int i = 1; i <= ipeStmt->body.length; i++)
    {
      int localSize = locationExpr(ipeStmt->body.get(i), &env);

      if (localSize > maxFrame)
        maxFrame = localSize;
    }

    retval = maxFrame;
  }

  else
  {
    AstDumpToNode logger(stdout, 3);

    printf("   locationExpr(Expr*, IpeEnv* env)  unsupported\n");
    printf("   ");
    expr->accept(&logger);
    printf("\n\n");

    env->describe(3);
    printf("\n\n");

    INT_ASSERT(false);
  }

  return retval;
}
Exemplo n.º 3
0
//
// Return NOT_FAST, NOT_LOCAL, IS_LOCAL, or IS_FAST.
//
static int
classifyPrimitive(CallExpr *call) {
  INT_ASSERT(call->primitive);
  // Check primitives for suitability for executeOnFast and for communication
  switch (call->primitive->tag) {
  case PRIM_UNKNOWN:
    // TODO: Return FAST_AND_LOCAL for PRIM_UNKNOWNs that are side-effect free
    return NOT_FAST_NOT_LOCAL;

  case PRIM_NOOP:
  case PRIM_REF_TO_STRING:
  case PRIM_RETURN:
  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_GET_MEMBER:
  case PRIM_GET_SVEC_MEMBER:
  case PRIM_NEW_PRIV_CLASS:

  case PRIM_CHECK_NIL:
  case PRIM_GET_REAL:
  case PRIM_GET_IMAG:

  case PRIM_ADDR_OF:
  case PRIM_SET_REFERENCE:
  case PRIM_LOCAL_CHECK:

  case PRIM_INIT_FIELDS:
  case PRIM_PTR_EQUAL:
  case PRIM_PTR_NOTEQUAL:
  case PRIM_CAST:

  case PRIM_BLOCK_LOCAL:

  case PRIM_ON_LOCALE_NUM:
  case PRIM_GET_SERIAL:
  case PRIM_SET_SERIAL:

  case PRIM_START_RMEM_FENCE:
  case PRIM_FINISH_RMEM_FENCE:

  case PRIM_CAST_TO_VOID_STAR:
  case PRIM_SIZEOF_BUNDLE:
  case PRIM_SIZEOF_DDATA_ELEMENT:

  case PRIM_GET_USER_LINE:
  case PRIM_GET_USER_FILE:
  case PRIM_LOOKUP_FILENAME:

  case PRIM_STACK_ALLOCATE_CLASS:

  case PRIM_CLASS_NAME_BY_ID:

  case PRIM_INVARIANT_START:
  case PRIM_NO_ALIAS_SET:
  case PRIM_COPIES_NO_ALIAS_SET:
    return FAST_AND_LOCAL;

  case PRIM_MOVE:
  case PRIM_ASSIGN:
  case PRIM_ADD_ASSIGN:
  case PRIM_SUBTRACT_ASSIGN:
  case PRIM_MULT_ASSIGN:
  case PRIM_DIV_ASSIGN:
  case PRIM_MOD_ASSIGN:
  case PRIM_LSH_ASSIGN:
  case PRIM_RSH_ASSIGN:
  case PRIM_AND_ASSIGN:
  case PRIM_OR_ASSIGN:
  case PRIM_XOR_ASSIGN:
    if (isCallExpr(call->get(2))) { // callExprs checked in calling function
      // Not necessarily true, but we return true because
      // the callExpr will be checked in the calling function
      return FAST_AND_LOCAL;
    } else {
      bool arg1wide = call->get(1)->isWideRef();
      bool arg2wide = call->get(2)->isWideRef();

      // If neither argument is a wide reference, OK: no communication
      if (!arg1wide && !arg2wide) {
        return FAST_AND_LOCAL;
      }

      if (call->isPrimitive(PRIM_MOVE)) {
        bool arg1ref = call->get(1)->isRef();
        bool arg2ref = call->get(2)->isRef();
        // Handle (move tmp:ref, other_tmp:wide_ref)
        // and    (move tmp:wide_ref, other_tmp:ref)
        // these does not require communication and merely adjust
        // the wideness of the ref.
        if ((arg1wide && arg2ref) || (arg1ref && arg2wide)) {
          return FAST_AND_LOCAL;
        }
      }

      // Otherwise, communication is required if we're not in a local block
      return FAST_NOT_LOCAL;
    }

  case PRIM_WIDE_MAKE:
    return FAST_NOT_LOCAL;

// I think these can always return true. <hilde>
// But that works only if the remote get is removed from code generation.
  case PRIM_WIDE_GET_LOCALE:
  case PRIM_WIDE_GET_NODE:
  case PRIM_WIDE_GET_ADDR:
    // If this test is true, a remote get is required.
    if (!(call->get(1)->isWideRef() &&
          call->get(1)->getValType()->symbol->hasFlag(FLAG_WIDE_CLASS))) {
      return FAST_AND_LOCAL;
    }
    return FAST_NOT_LOCAL;

  case PRIM_ARRAY_SHIFT_BASE_POINTER:
    // SHIFT_BASE_POINTER is fast as long as none of the
    // arguments are wide references.
    if (call->get(1)->isWideRef() ||
        call->get(2)->isWideRef() ||
        call->get(3)->isWideRef())
      return FAST_NOT_LOCAL;
    else
      return FAST_AND_LOCAL;

  case PRIM_SET_UNION_ID:
  case PRIM_GET_UNION_ID:
  case PRIM_GET_MEMBER_VALUE:
  case PRIM_GET_SVEC_MEMBER_VALUE:
    if (!call->get(1)->isWideRef()) {
      return FAST_AND_LOCAL;
    }
    return FAST_NOT_LOCAL;

  case PRIM_ARRAY_SET:
  case PRIM_ARRAY_SET_FIRST:
  case PRIM_SETCID:
  case PRIM_TESTCID:
  case PRIM_GETCID:
  case PRIM_ARRAY_GET:
  case PRIM_ARRAY_GET_VALUE:
  case PRIM_DYNAMIC_CAST:
    if (!call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
      return FAST_AND_LOCAL;
    }
    return FAST_NOT_LOCAL;

  case PRIM_DEREF:
  case PRIM_SET_MEMBER:
  case PRIM_SET_SVEC_MEMBER:
    if (!call->get(1)->isWideRef() &&
        !call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) {
      return FAST_AND_LOCAL;
    }
    return FAST_NOT_LOCAL;

  case PRIM_CHPL_COMM_GET:
  case PRIM_CHPL_COMM_BUFF_GET:
  case PRIM_CHPL_COMM_PUT:
  case PRIM_CHPL_COMM_ARRAY_GET:
  case PRIM_CHPL_COMM_ARRAY_PUT:
  case PRIM_CHPL_COMM_REMOTE_PREFETCH:
  case PRIM_CHPL_COMM_GET_STRD:
  case PRIM_CHPL_COMM_PUT_STRD:
    // These involve communication
    // MPF: Couldn't these be fast if in a local block?
    // Shouldn't this be return FAST_NOT_LOCAL ?
    return NOT_FAST_NOT_LOCAL;

  case PRIM_REDUCE_ASSIGN:
  case PRIM_NEW:

  case PRIM_INIT:
  case PRIM_INIT_FIELD:
  case PRIM_INIT_VAR:
  case PRIM_NO_INIT:
  case PRIM_TYPE_INIT:

  case PRIM_LOGICAL_FOLDER:
  case PRIM_LIFETIME_OF:
  case PRIM_TYPEOF:
  case PRIM_STATIC_TYPEOF:
  case PRIM_SCALAR_PROMOTION_TYPE:
  case PRIM_STATIC_FIELD_TYPE:
  case PRIM_TYPE_TO_STRING:
  case PRIM_IS_CLASS_TYPE:
  case PRIM_IS_RECORD_TYPE:
  case PRIM_IS_UNION_TYPE:
  case PRIM_IS_ATOMIC_TYPE:
  case PRIM_IS_EXTERN_TYPE:
  case PRIM_IS_TUPLE_TYPE:
  case PRIM_IS_STAR_TUPLE_TYPE:
  case PRIM_IS_SUBTYPE:
  case PRIM_IS_SUBTYPE_ALLOW_VALUES:
  case PRIM_IS_PROPER_SUBTYPE:
  case PRIM_IS_WIDE_PTR:
  case PRIM_TUPLE_EXPAND:
  case PRIM_QUERY:
  case PRIM_QUERY_PARAM_FIELD:
  case PRIM_QUERY_TYPE_FIELD:
  case PRIM_ERROR:
  case PRIM_WARNING:

  case PRIM_BLOCK_PARAM_LOOP:
  case PRIM_BLOCK_BEGIN:
  case PRIM_BLOCK_COBEGIN:
  case PRIM_BLOCK_COFORALL:
  case PRIM_BLOCK_ON:
  case PRIM_BLOCK_BEGIN_ON:
  case PRIM_BLOCK_COBEGIN_ON:
  case PRIM_BLOCK_COFORALL_ON:
  case PRIM_BLOCK_UNLOCAL:

  case PRIM_ACTUALS_LIST:
  case PRIM_YIELD:

  case PRIM_USED_MODULES_LIST:

  case PRIM_WHEN:
  case PRIM_CAPTURE_FN_FOR_C:
  case PRIM_CAPTURE_FN_FOR_CHPL:
  case PRIM_CREATE_FN_TYPE:

  case PRIM_NUM_FIELDS:
  case PRIM_IS_POD:
  case PRIM_FIELD_NUM_TO_NAME:
  case PRIM_FIELD_NAME_TO_NUM:
  case PRIM_FIELD_BY_NUM:

  case PRIM_TO_STANDALONE:
  case PRIM_IS_REF_ITER_TYPE:
  case PRIM_COERCE:
  case PRIM_CALL_RESOLVES:
  case PRIM_METHOD_CALL_RESOLVES:
  case PRIM_GET_COMPILER_VAR:
  case PRIM_ZIP:
  case PRIM_REQUIRE:
  case NUM_KNOWN_PRIMS:
  case PRIM_ITERATOR_RECORD_FIELD_VALUE_BY_FORMAL:
  case PRIM_ITERATOR_RECORD_SET_SHAPE:
  case PRIM_THROW:
  case PRIM_TRY_EXPR:
  case PRIM_TRYBANG_EXPR:
  case PRIM_CHECK_ERROR:
  case PRIM_TO_UNMANAGED_CLASS:
  case PRIM_TO_BORROWED_CLASS:
  case PRIM_NEEDS_AUTO_DESTROY:
  case PRIM_AUTO_DESTROY_RUNTIME_TYPE:
  case PRIM_GET_RUNTIME_TYPE_FIELD:
    INT_FATAL("This primitive should have been removed from the tree by now.");
    break;

    // By themselves, loops are considered "fast".
  case PRIM_BLOCK_WHILEDO_LOOP:
  case PRIM_BLOCK_DOWHILE_LOOP:
  case PRIM_BLOCK_FOR_LOOP:
  case PRIM_BLOCK_C_FOR_LOOP:
    return FAST_AND_LOCAL;

    // These don't block in the Chapel sense, but they may require a system
    // call so we don't consider them fast-eligible.
    // However, they are communication free.
    //
  case PRIM_STRING_COPY:
    return LOCAL_NOT_FAST;

  case PRIM_GET_END_COUNT:
  case PRIM_SET_END_COUNT:
  case PRIM_GET_DYNAMIC_END_COUNT:
  case PRIM_SET_DYNAMIC_END_COUNT:
    return FAST_AND_LOCAL;

    // Temporarily unclassified (legacy) cases.
    // These formerly defaulted to false (slow), so we leave them
    // here until they are proven fast.
  case PRIM_TO_LEADER:
  case PRIM_TO_FOLLOWER:
  case PRIM_CALL_DESTRUCTOR:
  case PRIM_HEAP_REGISTER_GLOBAL_VAR:
  case PRIM_HEAP_BROADCAST_GLOBAL_VARS:
  case PRIM_PRIVATE_BROADCAST:
  case PRIM_RT_ERROR:
  case PRIM_RT_WARNING:
  case PRIM_FTABLE_CALL:
  case PRIM_VIRTUAL_METHOD_CALL:
  case PRIM_INT_ERROR:
    return NOT_FAST_NOT_LOCAL;

  // no default, so that it is usually a C compilation
  // error when a primitive is added but not included here.
  }

  // At the end of the switch statement.
  // We get here if there is an unhandled primitive.
  INT_FATAL("Unhandled case.");
  return NOT_FAST_NOT_LOCAL;
}