Beispiel #1
0
//
// Determine the index type for a ParamForLoop.
//
// This implementation creates a range with low/high values and then
// asks for its type.
//
Type* ParamForLoop::indexType()
{
  SymExpr*  lse     = lowExprGet();
  SymExpr*  hse     = highExprGet();
  CallExpr* range    = new CallExpr("chpl_build_bounded_range",
                                    lse->copy(), hse->copy());
  Type*     idxType = 0;

  insertBefore(range);

  resolveCall(range);

  if (FnSymbol* sym = range->isResolved())
  {
    resolveFormals(sym);

    DefExpr* formal = toDefExpr(sym->formals.get(1));

    if (toArgSymbol(formal->sym)->typeExpr)
      idxType = toArgSymbol(formal->sym)->typeExpr->body.tail->typeInfo();
    else
      idxType = formal->sym->type;

    range->remove();
  }
  else
  {
    INT_FATAL("unresolved range");
  }

  return idxType;
}
Beispiel #2
0
ConstInfo::ConstInfo(Symbol* s) {
  sym = s;
  fnUses = NULL;
  Qualifier q = sym->qualType().getQual();

  finalizedConstness = q == QUAL_CONST_REF || q == QUAL_CONST_VAL;
  if (ArgSymbol* arg = toArgSymbol(s)) {
    // Work around a bug where we can have an arg with the in-intent, but it's
    // a reference
    // BHARSH TODO: this shouldn't be possible in the qualified refs impl.
    if (arg->intent == INTENT_CONST_IN && arg->isRef()) {
      finalizedConstness = false;
    }

    // Since we know 'sym' is an ArgSymbol, initialize the uses of the
    // symbol's function.
    FnSymbol* fn = toFnSymbol(sym->defPoint->parentSymbol);
    fnUses = fn->firstSymExpr();
  }

  finalizedRefToConst = sym->hasFlag(FLAG_REF_TO_CONST);

  curTodo = 0;
  alreadyCalled = false;
}
Beispiel #3
0
static void
list_sym(Symbol* sym, bool type = true) {
  if (VarSymbol* var = toVarSymbol(sym)) {
    if (var->immediate) {
      if (var->immediate->const_kind == NUM_KIND_INT) {
        printf("%"PRId64" ", var->immediate->int_value());
        return;
      } else if (var->immediate->const_kind == CONST_KIND_STRING) {
        printf("\"%s\" ", var->immediate->v_string);
        return;
      }
    }
  }
  if (toFnSymbol(sym)) {
    printf("fn ");
  } else if (toArgSymbol(sym)) {
    printf("arg ");
  } else if (toTypeSymbol(sym)) {
    printf("type ");
  }
  printf("%s", sym->name);
  printf("[%d]", sym->id);
  if (!type) {
    printf(" ");
  } else if (FnSymbol* fn = toFnSymbol(sym)) {
    printf(":%s", fn->retType->symbol->name);
    printf("[%d] ", fn->retType->symbol->id);
  } else if (sym->type && sym->type->symbol) {
    printf(":%s", sym->type->symbol->name);
    printf("[%d] ", sym->type->symbol->id);
  } else {
    printf(" ");
  }
}
Beispiel #4
0
static void view_sym(Symbol* sym, bool number, int mark) {
  putchar('\'');
  if (sym->id == mark)
    printf("***");
  if (toFnSymbol(sym)) {
    printf("fn ");
  } else if (toArgSymbol(sym)) {
    printf("arg ");
  } else if (toTypeSymbol(sym)) {
    printf("type ");
  }
  printf("%s", sym->name);
  if (number)
    printf("[%d]", sym->id);
  if (FnSymbol* fn = toFnSymbol(sym)) {
    printf(":%s", fn->retType->symbol->name);
    if (number)
      printf("[%d]", fn->retType->symbol->id);
  } else if (sym->type && sym->type->symbol) {
    printf(":%s", sym->type->symbol->name);
    if (number)
      printf("[%d]", sym->type->symbol->id);
  }
  if (sym->hasFlag(FLAG_GENERIC))
    putchar('?');
  putchar('\'');
}
//
// A forall-intents variation on findOuterVars() in createTaskFunctions.cpp:
// Find all symbols used in 'block' and defined outside of it.
//
static void findOuterVars(BlockStmt* block, SymbolMap* uses) {
  std::vector<SymExpr*> symExprs;
  collectSymExprsSTL(block, symExprs);
  for_vector(SymExpr, symExpr, symExprs) {
    Symbol* sym = symExpr->var;
    if (toVarSymbol(sym) || toArgSymbol(sym))
      if (!isCorrespIndexVar(block, sym) && isOuterVar(sym, block))
        uses->put(sym,gNil);
  }
Beispiel #6
0
static const char*
block_explanation(BaseAST* ast, BaseAST* parentAst) {
  if (ArgSymbol* parentArg = toArgSymbol(parentAst)) {
    if (ast == parentArg->typeExpr)
      return "  typeExpr=";
    if (ast == parentArg->defaultExpr)
      return "  defaultExpr=";
    if (ast == parentArg->variableExpr)
      return "  variableExpr=";
  }
  return "";
}
//
// finds outer vars directly used in a function
//
static void
findOuterVars(FnSymbol* fn, SymbolMap* uses) {
  Vec<BaseAST*> asts;
  collect_asts(fn, asts);
  forv_Vec(BaseAST, ast, asts) {
    if (SymExpr* symExpr = toSymExpr(ast)) {
      Symbol* sym = symExpr->var;
      if (toVarSymbol(sym) || toArgSymbol(sym))
        if (isOuterVar(sym, fn))
          uses->put(sym,gNil);
    }
  }
}
Beispiel #8
0
bool IpeProcedure::isActualRef(Expr* actual) const
{
  bool retval = false;

  if (SymExpr* symExpr = toSymExpr(actual))
  {
    if (ArgSymbol* arg = toArgSymbol(symExpr->var))
    {
      retval = (arg->intent & INTENT_REF) ? true : false;
    }
  }


  return retval;
}
Beispiel #9
0
void
viewFlags(BaseAST* ast) {
  if (!viewFlagsShort && !viewFlagsName && !viewFlagsComment)
    viewFlagsName = true;
  if (Symbol* sym = toSymbol(ast)) {
    for (int flagNum = FLAG_FIRST; flagNum <= FLAG_LAST; flagNum++) {
      if (sym->flags[flagNum]) {
        if (viewFlagsName)
          printf("%s ", flagNames[flagNum]);
        if (viewFlagsPragma)
          printf("%s", flagPragma[flagNum] ? "ypr " : "npr ");
        if (viewFlagsShort)
          printf("\"%s\" ", flagShortNames[flagNum]);
        if (viewFlagsComment)
          printf("// %s",
                 *flagComments[flagNum] ? flagComments[flagNum] : "ncm");
        printf("\n");
      }
    }
    if (viewFlagsExtras) {
      if (VarSymbol* vs = toVarSymbol(sym)) {
        if (vs->immediate) {
          printf("immediate ");
          fprint_imm(stdout, *toVarSymbol(sym)->immediate, true);
          printf("\n");
        }
      } else if (ArgSymbol* as = toArgSymbol(sym)) {
        printf("%s arg\n", as->intentDescrString());
      } else if (toTypeSymbol(sym)) {
        printf("a TypeSymbol\n");
      } else if (FnSymbol* fs = toFnSymbol(sym)) {
        printf("fn %s(%d args) %s\n",
               fs->_this ? intentDescrString(fs->thisTag) : "",
               fs->numFormals(), retTagDescrString(fs->retTag));
      } else if (toEnumSymbol(sym)) {
        printf("an EnumSymbol\n");
      } else if (ModuleSymbol* ms = toModuleSymbol(sym)) {
        printf("module %s\n", modTagDescrString(ms->modTag));
      } else if (toLabelSymbol(sym)) {
        printf("a LabelSymbol\n");
      } else {
        printf("unknown symbol kind\n");
      }
    }
  } else {
    printf("[%d]: not a Symbol, has no flags\n", ast->id);
  }
}
Beispiel #10
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);
            }
          }
        }
      }
    }
  }
}
Beispiel #11
0
static void
log_ast_symbol(FILE* file, Symbol* sym, bool def) {
  if (log_need_space) putc(' ', file);
  log_need_space = false;

  if (def)
    if (ArgSymbol* arg = toArgSymbol(sym)) {
      log_need_space = true;
      switch (arg->intent) {
       case INTENT_IN:      fprintf(file, "in");        break;
       case INTENT_INOUT:   fprintf(file, "inout");     break;
       case INTENT_OUT:     fprintf(file, "out");       break;
       case INTENT_CONST:   fprintf(file, "const");     break;
       case INTENT_CONST_IN:  fprintf(file, "const in");  break;
       case INTENT_CONST_REF: fprintf(file, "const ref"); break;
       case INTENT_REF:     fprintf(file, "ref");       break;
       case INTENT_PARAM:   fprintf(file, "param");     break;
       case INTENT_TYPE:    fprintf(file, "type");      break;
      default: log_need_space = false; break;
      }
      log_write(file, true, "arg", true);
    }

  log_write(file, true, sym->name, true);

  if (fLogIds)
    fprintf(file, "[%d]", sym->id);

  if (def &&
      !toTypeSymbol(sym) &&
      sym->type &&
      sym->type->symbol &&
      sym->type != dtUnknown) {
    log_write(file, false, ":", false);
    log_ast_symbol(file, sym->type->symbol, false);
  }

  if (sym->hasFlag(FLAG_GENERIC))
    log_write(file, false, "?", false);

  log_need_space = true;
}
Beispiel #12
0
void Expr::replace(Expr* new_ast) {
  if (new_ast->parentSymbol || new_ast->parentExpr)
    INT_FATAL(new_ast, "Argument is already in AST in Expr::replace");
  if (new_ast->list)
    INT_FATAL(new_ast, "Argument is in a list in Expr::replace");
  if (list) {
    new_ast->next = next;
    new_ast->prev = prev;
    new_ast->list = list;
    if (next)
      next->prev = new_ast;
    else
      list->tail = new_ast;
    if (prev)
      prev->next = new_ast;
    else
      list->head = new_ast;
    next = NULL;
    prev = NULL;
    list = NULL;
  } else {
    callReplaceChild(this, new_ast);
  }

  Symbol* myParentSymbol = parentSymbol;
  Expr* myParentExpr = parentExpr;
  remove_help(this, 'p');
  insert_help(new_ast, myParentExpr, myParentSymbol);

  // Update the _this field in a FnSymbol if necessary.
  if (DefExpr* def = toDefExpr(this))
    if (ArgSymbol* arg = toArgSymbol(def->sym))
      if (FnSymbol* fn = toFnSymbol(myParentSymbol))
        if (fn->_this == arg)
          fn->_this = toDefExpr(new_ast)->sym;
}
Beispiel #13
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;
}
Beispiel #14
0
//
// Returns 'true' if 'sym' is (or should be) a const-ref.
// If 'sym' can be a const-ref, but is not, this function will change either
// the intent or qual of the Symbol to const-ref.
//
static bool inferConstRef(Symbol* sym) {
  INT_ASSERT(sym->isRef());
  bool wasConstRef = sym->qualType().getQual() == QUAL_CONST_REF;

  if (sym->defPoint->parentSymbol->hasFlag(FLAG_EXTERN)) {
    return wasConstRef;
  }

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

  bool isFirstCall = false;
  if (info->alreadyCalled == false) {
    isFirstCall = true;
    info->alreadyCalled = true;
  }

  bool isConstRef = true;

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

    CallExpr* call = toCallExpr(use->parentExpr);
    INT_ASSERT(call);

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

    if (call->isResolved()) {
      ArgSymbol* form = actual_to_formal(use);
      if (form->isRef() && !inferConstRef(form)) {
        isConstRef = false;
      }
    }
    else if (parent && isMoveOrAssign(parent)) {
      if (!canRHSBeConstRef(parent, use)) {
        isConstRef = false;
      }
    }
    else if (call->isPrimitive(PRIM_MOVE)) {
      //
      // Handles three cases:
      // 1) MOVE use value - writing to a reference, so 'use' cannot be const
      // 2) MOVE ref use - if the LHS is not const, use cannot be const either
      // 3) MOVE value use - a dereference of 'use'
      //
      if (use == call->get(1)) {
        // CASE 1
        if (!call->get(2)->isRef()) {
          isConstRef = false;
        }
      } else {
        // 'use' is the RHS of a MOVE
        if (call->get(1)->isRef()) {
          // CASE 2
          SymExpr* se = toSymExpr(call->get(1));
          INT_ASSERT(se);
          if (!inferConstRef(se->symbol())) {
            isConstRef = false;
          }
        }
        // else CASE 3: do nothing because isConstRef is already true
      }
    }
    else if (call->isPrimitive(PRIM_ASSIGN)) {
      if (use == call->get(1)) {
        isConstRef = false;
      }
    }
    else if (call->isPrimitive(PRIM_SET_MEMBER) ||
             call->isPrimitive(PRIM_SET_SVEC_MEMBER)) {
      // BHARSH 2016-11-02
      // In the expr (set_member base member rhs),
      // If use == base, I take the conservative approach and decide that 'use'
      // is not a const-ref. I'm not sure that we've decided what const means
      // for fields yet, so this seems safest.
      //
      // If use == rhs, then we would need to do analysis for the member field.
      // That's beyond the scope of what I'm attempting at the moment, so to
      // be safe we'll return false for that case.
      if (use == call->get(1) || use == call->get(3)) {
        isConstRef = false;
      } else {
        // use == member
        // If 'rhs' is not a ref, then we're writing into 'use'. Otherwise it's
        // a pointer copy and we don't care if 'rhs' is writable.
        if (!call->get(3)->isRef()) {
          isConstRef = false;
        }
      }
    } else {
      // To be safe, exit the loop with 'false' if we're unsure of how to
      // handle a primitive.
      isConstRef = false;
    }
  }

  if (isFirstCall) {
    if (isConstRef) {
      INT_ASSERT(info->finalizedConstness == false);
      if (ArgSymbol* arg = toArgSymbol(sym)) {
        arg->intent = INTENT_CONST_REF;
      } else {
        INT_ASSERT(isVarSymbol(sym));
        sym->qual = QUAL_CONST_REF;
      }
    }

    info->reset();
    info->finalizedConstness = true;
  } else if (!isConstRef) {
    info->finalizedConstness = true;
  }

  return isConstRef;
}
Beispiel #15
0
//
// DefExpr
//
bool AstDumpToHtml::enterDefExpr(DefExpr* node) {
  bool retval = true;

  if (isBlockStmt(node->parentExpr)) {
    fprintf(mFP, "<DL>\n");
  }

  fprintf(mFP, " ");

  if (FnSymbol* fn = toFnSymbol(node->sym)) {
    fprintf(mFP, "<UL CLASS =\"mktree\">\n<LI>");

    adjacent_passes(fn);

    fprintf(mFP, "<CHPLTAG=\"FN%d\">\n", fn->id);
    fprintf(mFP, "<B>function ");

    writeFnSymbol(fn);

    fprintf(mFP, "</B><UL>\n");

  } else if (isTypeSymbol(node->sym)) {
    if (toAggregateType(node->sym->type)) {
      fprintf(mFP, "<UL CLASS =\"mktree\">\n");
      fprintf(mFP, "<LI>");

      if (node->sym->hasFlag(FLAG_SYNC))
        fprintf(mFP, "<B>sync</B> ");

      if (node->sym->hasFlag(FLAG_SINGLE))
        fprintf(mFP, "<B>single</B> ");

      fprintf(mFP, "<B>type ");
      writeSymbol(node->sym, true);
      fprintf(mFP, "</B><UL>\n");

    } else {
      fprintf(mFP, "<B>type </B> ");
      writeSymbol(node->sym, true);
    }

  } else if (VarSymbol* vs = toVarSymbol(node->sym)) {
    if (vs->type->symbol->hasFlag(FLAG_SYNC))
      fprintf(mFP, "<B>sync </B>");

    if (vs->type->symbol->hasFlag(FLAG_SINGLE))
      fprintf(mFP, "<B>single </B>");

    fprintf(mFP, "<B>var </B> ");
    writeSymbol(node->sym, true);

  } else if (ArgSymbol* s = toArgSymbol(node->sym)) {
    switch (s->intent) {
      case INTENT_IN:        fprintf(mFP, "<B>in</B> ");        break;
      case INTENT_INOUT:     fprintf(mFP, "<B>inout</B> ");     break;
      case INTENT_OUT:       fprintf(mFP, "<B>out</B> ");       break;
      case INTENT_CONST:     fprintf(mFP, "<B>const</B> ");     break;
      case INTENT_CONST_IN:  fprintf(mFP, "<B>const in</B> ");  break;
      case INTENT_CONST_REF: fprintf(mFP, "<B>const ref</B> "); break;
      case INTENT_REF:       fprintf(mFP, "<B>ref</B> ");       break;
      case INTENT_PARAM:     fprintf(mFP, "<B>param</B> ");     break;
      case INTENT_TYPE:      fprintf(mFP, "<B>type</B> ");      break;
      case INTENT_BLANK:                                        break;
    }

    fprintf(mFP, "<B>arg</B> ");

    writeSymbol(node->sym, true);

  } else if (isLabelSymbol(node->sym)) {
    fprintf(mFP, "<B>label</B> ");
    writeSymbol(node->sym, true);

  } else if (isModuleSymbol(node->sym)) {
    fprintf(mFP, "</DL>\n");
    // Don't process nested modules -- they'll be handled at the top-level
    retval = false;

  } else {
    fprintf(mFP, "<B>def</B> ");
    writeSymbol(node->sym, true);
  }

  return retval;
}
Beispiel #16
0
void IpeEnv::describe(const char* pad, int index, LcnSymbol* var) const
{
  const char* symName  = var->name;
  const char* typeName = "";
  ArgSymbol*  argSym   = toArgSymbol(var);
  VarSymbol*  varSym   = toVarSymbol(var);

  if (var->type)
    typeName = var->type->symbol->name;

  printf("%s %5d: %-30s", pad, index, symName);

  if      (argSym                      != NULL)
  {
    if (argSym->intent & INTENT_REF)
      printf("ref   %-12s", typeName);
    else
      printf("arg   %-12s", typeName);
  }

  else if (varSym->immediate           != NULL)
    printf("const %-12s", typeName);

  else if (varSym->hasFlag(FLAG_CONST) == true)
    printf("const %-12s", typeName);

  else if (varSym->hasFlag(FLAG_PARAM) == true)
    printf("param %-12s", typeName);

  else
    printf("var   %-12s", typeName);

  if (var->depth() >= 0 && var->offset() >= 0)
    printf("%4d %4d ", var->depth(), var->offset());
  else
    printf("          ");

  if      (argSym != NULL && (argSym->intent & INTENT_REF) != 0)
  {
    if (mFrameData != NULL)
    {
      int       offset = argSym->offset();
      IpeValue* ref    = *((IpeValue**) (((char*) mFrameData) + offset));

      printf("0x%012lX", (long) ref);
    }
  }

  else if (var->offset() <    0)
    ;

  else if (var->type     == NULL)
    ;

  else if (var->type     == gIpeTypeType)
    printf("%s", symName);

  else if (var->type     == dtBool)
  {
    if (mDepth == 0 || mFrameData != NULL)
      printf("%s", (fetchBool(var) == true) ?  "true" : "false");
  }

  else if (var->type     == dtInt[INT_SIZE_64])
  {
    if (mDepth == 0 || mFrameData != NULL)
      printf("%8ld", fetchInteger(var));
  }

  else if (var->type     == dtReal[FLOAT_SIZE_64])
  {
    if (mDepth == 0 || mFrameData != NULL)
      printf("   %8.2f", fetchReal(var));
  }

  else if (var->type     == gIpeTypeModule)
  {
    if (mDepth == 0 || mFrameData != NULL)
    {
      IpeModule* value = (IpeModule*) fetchPtr(var);

      printf("#<IpeModule    %-20s 0x%012lX>", value->name(), (long) value);
    }
  }

  else if (var->type     == gIpeTypeProcedure)
  {
    if (mDepth == 0 || mFrameData != NULL)
    {
      IpeProcedure* value = (IpeProcedure*) fetchPtr(var);

      if (value->methodCount() == 1)
        printf("#<IpeProcedure %-20s with %3d method  0x%012lX>",
               value->name(),
               value->methodCount(),
               (long) value);
      else
        printf("#<IpeProcedure %-20s with %3d methods 0x%012lX>",
               value->name(),
               value->methodCount(),
               (long) value);
    }
  }

  else
    printf("Really??  Really??");

  printf("\n");
}