Example #1
0
void PerformanceDebugger::report_context(InlinedScope* s) {
  if (!DebugPerformance) return;
  Reporter r(this);
  GrowableArray<Expr*>* temps = s->contextTemporaries();
  const int len = temps->length();
  int nused = 0;
  for (int i = 0; i < len; i++) {
    PReg* r = temps->at(i)->preg();
    if (r->uplevelR() || r->uplevelW() || (r->isBlockPReg() && !r->isUnused())) nused++;
  }
  if (nused == 0) {
    str->print("  could not eliminate context of scope %s (fixable compiler restriction; should be eliminated)\n", s->key()->print_string());
  } else {
    str->print("  could not eliminate context of scope %s; temp(s) still used: ", s->key()->print_string());
    for (int j = 0; j < len; j++) {
      PReg* r = temps->at(j)->preg();
      if (r->uplevelR() || r->uplevelW()) {
	str->print("%d ", j);
      } else if (r->isBlockPReg() && !r->isUnused()) {
	str->print("%d (non-inlined block)", j);
      }
    }
    str->print("\n");
  } 
}
Example #2
0
 void SCodeScope::memoizeBlocks(stringOop sel) {
   // memoize block args so they aren't created for inlined cases
   fint top = exprStack->length();
   fint argc = sel->arg_count();
   for (fint i = 1; i <= argc; i++) {
     PReg* r = exprStack->nth(top - i)->preg();
     if (r->isBlockPReg()) ((BlockPReg*)r)->memoize();
   }
 }
Example #3
0
void CompiledLoop::findRegCandidates() {
  // Find the PRegs with the highest number of defs & uses in this loop.
  // Problem: we don't have a list of all PRegs used in the loop; in fact, we don't even have
  // a list of all nodes.
  // Solution: iterate through all BBs between start and end of loop (in code generation order)
  // and collect the defs and uses.  The BB ordering algorithm should make sure that the BBs
  // of the loop are consecutive.
  if (_bbs == NULL) _bbs = bbIterator->code_generation_order();
  GrowableArray<LoopRegCandidate*> candidates(PReg::currentNo, PReg::currentNo, NULL);
  const int len = _bbs->length();
  const BB* startBB = _startOfLoop->bb();
  int i;
  for (i = 0; _bbs->at(i) != startBB; i++) ;	// search for first BB
  const BB* endBB = _endOfLoop->bb();
  int ncalls = 0;

  // iterate through all BBs in the loop
  for (BB* bb = _bbs->at(i); bb != endBB; i++, bb = _bbs->at(i)) {
    const int n = bb->duInfo.info->length();
    if (bb->last->isCallNode()) ncalls++;
    for (int j = 0; j < n; j++) {
      DUInfo* info = bb->duInfo.info->at(j);
      PReg* r = info->reg;
      if (candidates.at(r->id()) == NULL) candidates.at_put(r->id(), new LoopRegCandidate(r));
      LoopRegCandidate* c = candidates.at(r->id());
      c->incDUs(info->uses.length(), info->defs.length());
    }
  }
  loopHeader()->set_nofCallsInLoop(ncalls);

  // find the top 2 candidates...
  LoopRegCandidate* first  = new LoopRegCandidate(NULL);
  LoopRegCandidate* second = new LoopRegCandidate(NULL);
  for (int j = candidates.length() - 1; j >= 0; j--) {
    LoopRegCandidate* c = candidates.at(j);
    if (c == NULL) continue;
    if (c->weight() > first->weight()) {
      second = first; first = c;
    } else if (c->weight() > second->weight()) {
      second = c;
    }
  }

  // ...and add them to the loop header 
  if (first->preg() != NULL) {
    loopHeader()->addRegisterCandidate(first);
    if (second->preg() != NULL) {
      loopHeader()->addRegisterCandidate(second);
    }
  } else {
    assert(second->preg() == NULL, "bad sorting");
  }
}
Example #4
0
Expr* PrimInliner::block_primitiveValue() {
  PReg* r = parameter(0)->preg();
  if (r->isBlockPReg()) {
    // we know the identity of the block -- inline it if possible
    Inliner* inliner = _gen->inliner();
    SendInfo* info = new SendInfo(_scope, parameter(0), _pdesc->selector());
    Expr* res = inliner->inlineBlockInvocation(info);
    if (res) return res;
  } 
  // could at least inline block invocation -- fix this later
  return NULL;
}
Example #5
0
  void BB::allocateTempRegisters(BitVector** hardwired, PRegBList* tempRegs,
                                 BitVectorBList* lives) {
    if (!nnodes) return;            // empty BB

    RegisterEqClassBList regClasses(nnodes + 1);
    regClasses.append(NULL);        // first reg class has index 1

    fint  use_count[NumRegisters], def_count[NumRegisters];
    for (fint i = 0; i < NumRegisters; i++) use_count[i] = def_count[i] = 0;

    allocate_to_preferred_candidates_if_possible(use_count, def_count);

    // allocate other temp regs (using the untouched temp regs of this BB)
    fint temp = 0;
    for (int i = 0; i < duInfo.info->length(); i++) {
      // collect temp regs 
      PReg* r = duInfo.info->nth(i)->reg;
      if (r->loc == UnAllocated && !r->isUnused() && r->isLocalTo(this)) {
        assert(r->dus.first()->index == i, "should be the same");
        for ( ; temp < NumTempRegs &&
             use_count[TempRegs[temp]] + def_count[TempRegs[temp]] > 0;
             temp++) ;
        if (temp == NumTempRegs) break;     // ran out of regs
        // ok, allocate TempRegs[temp] to the preg and equivalent pregs
        Location t = TempRegs[temp++];
        PReg* frst = r->regClass ? regClasses.nth(r->regClass)->first : r;
        for (PReg* pr = frst; pr; pr = pr->regClassLink) {
          doAlloc(pr, t);
          pr->regClass = 0;
        }
      }
      r->regClass = 0;
    }

    if (temp == NumTempRegs) {
      // ran out of temp regs with the simple strategy - try using slow
      // allocation algorithm
      slowAllocateTempRegisters(hardwired, tempRegs, lives);
    }
  }
Example #6
0
 void BB::pick_candidates_for_assignment_node(Node* n, fint use_count[], fint def_count[],
                                              RegCandidateBList &cands) {
   PReg* src = n->src();
   PReg* dest = n->dest();
   bool localSrc  = src ->isLocalTo(this);
   bool localDest = dest->isLocalTo(this);
   if ( isRegister(src->loc)) {
     if (dest->loc == UnAllocated && localDest) {
       // PR = PR2(reg)
       // allocate dest->loc to src->loc, but only if src->loc
       // isn't defined again
       cands.append(new RegCandidate(dest, src->loc, def_count[src->loc]));
     }
   } else if ( isRegister(dest->loc)) {
     if (src->loc == UnAllocated && localSrc) {
       // PR2(reg) = PR
       // should allocate src->loc to dest->loc, but only if dest->loc
       // has single definition (this one) and isn't used before
       // this point   [simplification]
       if (def_count[dest->loc] != 1 || use_count[dest->loc]) {
         // not eligible for special treatment
       } else {
         cands.append(new RegCandidate(src, dest->loc, 1));
       }
     }
   } else if (localSrc && localDest) {
     // both regs are local and unallocated - put them in same
     // equivalence class
     // fix this - should check for overlapping live ranges
     //        needed to say "if nonoverlapping live ranges(src, dest)"
     //        src->makeSameRegClass(dest, &regClasses);
     //        if (WizardMode) warning("basicBlock: happens");
   } else {
     // non-local registers - skip
   }
 }
Example #7
0
  void do_it(InlinedScope* s) {
    GrowableArray<NonTrivialNode*>* tests = s->typeTests();
    int len = tests->length();
    for (int i = 0; i < len; i++) {
      NonTrivialNode* n = tests->at(i);
      assert(n->doesTypeTests(), "shouldn't be in list");
      if (n->deleted) continue;
      if (n->hasUnknownCode()) continue;	  // can't optimize - expects other klasses, so would get uncommon trap at run-time
      if (!theLoop->isInLoop(n)) continue;	  // not in this loop
      GrowableArray<PReg*> regs(4);
      GrowableArray<GrowableArray<klassOop>*> klasses(4);
      n->collectTypeTests(regs, klasses);
      for (int j = 0; j < regs.length(); j++) {
	PReg* r = regs.at(j);
	if (theLoop->defsInLoop(r) == 0) {
	  // this test can be hoisted
	  if (CompilerDebug || PrintLoopOpts) cout(PrintLoopOpts)->print("*moving type test of %s at N%d out of loop\n", r->name(), n->id());
	  hoistableTests->append(new HoistedTypeTest(n, r, klasses.at(j)));
	}
      }
    }
  }
Example #8
0
void Compiler::computeBlockInfo() {
  FlagSetting(EliminateUnneededNodes, true);  // unused context nodes must be eliminated
  GrowableArray<InlinedScope*>* allContexts = new GrowableArray<InlinedScope*>(25);
  topScope->collectContextInfo(allContexts);
  // for now, just allocate all contexts as in interpreter
  // fix this later: collect all uplevel-accessed PRegs at same loop depth, form physical
  // contexts for these
  // also, if uplevel-read and single def --> could copy into context and keep
  // stack/register copy


  // remove all unused contexts 
  // need to iterate because removing a nested context may enable removal of a parent context
  // (could avoid iteration with topo sort, but there are few contexts anyway)
  bool changed = EliminateContexts;
  while (changed) {
    changed = false;
    for (int i = allContexts->length() - 1; i >= 0; i--) {
      InlinedScope* s = allContexts->at(i);
      if (s == NULL) continue;
      PReg* contextPR = s->context();
      assert(contextPR->isSinglyAssigned(), "should have exactly one def");
      GrowableArray<Expr*>* temps = s->contextTemporaries();
      bool noUplevelAccesses = true;
      // check if all context temps can be stack-allocated
      for (int j = temps->length() - 1; j >= 0; j--) {
	PReg* r = temps->at(j)->preg();
	if (r->uplevelR() || r->uplevelW()	    // this temp is still uplevel-accessed, so can't eliminate context
	    || (r->isBlockPReg() && !r->isUnused()) // this block still forces a context
	    ) {
	  noUplevelAccesses = false;
	  break;
	}
      }
      // TO DO: check if context is needed for NLRs
      // (noUplevelAccesses alone does not allow elimination)
      if (/*noUplevelAccesses || */contextPR->isSinglyUsed()) {
        // can eliminate context -- no uplevel-accessed vars
	// (single use is context initializer)
  	if (CompilerDebug) cout(PrintEliminateContexts)->print("%*s*eliminating context %s\n", s->depth, "", contextPR->safeName());
        contextPR->scope()->gen()->removeContextCreation();
	allContexts->at_put(i, NULL);	  // make code generator break if it tries to access this context
	changed = true;
      }
    }
  }

  // now collect all remaining contexts
  int i = allContexts->length();
  contextList = new GrowableArray<InlinedScope*>(i, i, NULL);
  while (i-- > 0) {
    // should merge several contexts into one physical context if possible
    // fix this later
    InlinedScope* s = allContexts->at(i);
    if (s == NULL) continue;
    PReg* contextPR = s->context();
    if (CompilerDebug) {
      cout(PrintEliminateContexts)->print("%*s*could not eliminate context %s in scope %s\n", 
      					  s->depth, "", contextPR->safeName(), s->key()->print_string());
    }
    reporter->report_context(s);
    contextList->at_put(i, s);
    ContextCreateNode* c = s->contextInitializer()->creator();
    c->set_contextNo(i);
    GrowableArray<Expr*>* temps = s->contextTemporaries();
    // allocate the temps in this context (but only if they're used)
    int ntemps = temps->length();
    int size = 0;
    for (int j = 0; j < ntemps; j++) {
      PReg* p = temps->at(j)->preg();
// should be:
//     if (p->isUsed() && (p->uplevelR() || p->uplevelW())) {
// but doesn't work yet (probably must fix set_self_via_context etc.)
// -Urs 6/96
      if (p->isUsed()) {
	// allocate p to context temp
	assert(p->scope() == s || p->isBlockPReg(), "oops");
	Location loc = Mapping::contextTemporary(i, size, s->scopeID());
	if (p->isBlockPReg()) {
	  // Blocks aren't actually assigned (at the PReg level) so that the inlining info
	  // isn't lost.  Thus we need to create a fake destination here if the context exists.
	  SAPReg* dest = new SAPReg(s, loc, true, true, PrologueBCI, EpilogueBCI);
	  Expr* e = new UnknownExpr(dest, NULL);
	  //contextPR->scope()->contextInitializer()->initialize(j, init);
	  temps->at_put(j, e);
	} else {
	  p->allocateTo(loc);
	}
	size++;
      }
    }
    c->set_sizeOfContext(size);
    if (size < ntemps && c->scope()->number_of_noninlined_blocks() > 0) {
      // this hasn't been exercised much 
      compiler_warning("while compiling %s: eliminated some context temps", key->print_string());
    }
  }

  // Compute the number of noninlined blocks for the nmethod and allocate 
  const int nblocks = topScope->number_of_noninlined_blocks();

  if (is_method_compile() || nblocks > 0) {
    // allocate nblocks+1 jumpTable entries
    const jumpTableID id = Universe::code->jump_table()->allocate(nblocks + 1);

    if (is_method_compile()) {
      main_jumpTable_id = id;
    } else {
      promoted_jumpTable_id = id;
    }

    // first is for nmethod itself
    int block_index = 1;
    for (int i = bbIterator->exposedBlks->length() - 1; i >= 0; i--) {
      BlockPReg* blk = bbIterator->exposedBlks->at(i);
      if (blk->isUsed()) {
        assert(block_index <= nblocks, "nblocks too small");
        blk->closure()->set_id(id.sub(block_index++));
      }
    }
    assert(nblocks + 1 == block_index, "just checking");
  }
}
Example #9
0
  // allocate PRegs that are used & defined solely within this BB
  void BB::slowAllocateTempRegisters(BitVector** hardwired, PRegBList* tempRegs,
                                     BitVectorBList* lives) {
    // clear temporary data structures
    tempRegs->clear();
    lives->clear();
    fint i;
    for (i = 0; i < NumTempRegs; i++) {
      hardwired[i]->setLength(nnodes);
      hardwired[i]->clear();
    }

    for (i = 0; i < duInfo.info->length(); i++) {
      // collect temp regs and hardwired temp regs
      PReg* r = duInfo.info->nth(i)->reg;
      if (r->isLocalTo(this)) {
        assert(r->dus.first()->index == i, "should be the same");
        if (r->isUnused()) {
          // unused register - ignore
        } else {
          DUInfo* info = duInfo.info->nth(r->dus.first()->index);
          tempRegs->append(r);
          BitVector* bv = new BitVector(nnodes);
          lives->append(bv);
          fint firstUse = 0, lastUse = nnodes - 1;
          duInfo.info->nth(i)->getLiveRange(firstUse, lastUse);
          bv->addFromTo(firstUse, lastUse);
        }
      } else if (isTempReg(r->loc)) {
        fint firstUse = 0, lastUse = nnodes - 1;
        if (!r->incorrectDU()) {
          duInfo.info->nth(i)->getLiveRange(firstUse, lastUse);
        } else {
          // can't really compute live range since the temp might be non-local
          // so assume it's live from first node til the end
        }
        hardwired[RegToTempNo[r->loc]]->addFromTo(firstUse, lastUse);
      }
    }

    // now, tempRegs holds all temp regs, and lives contains each register's
    // live range (one bit per node, 1 = reg is live); hardwired contains
    // the ranges where temp regs are already taken (e.g. for NLR, calls, etc)

    // cycle through the temp registers to (hopefully) allow more optimizations
    // later (e.g. scheduling)
    fint lastTemp = 0;
#   define nextTemp(n) (n == NumTempRegs - 1) ? 0 : n + 1

    for (i = 0; i < tempRegs->length(); i++) {
      // try to allocate tempRegs[i] to a temp register
      PReg* r = tempRegs->nth(i);
      if (r->loc != UnAllocated) {
        assert(r->regClass == 0, "should have been cleared");
        continue;
      }
      BitVector* liveRange = lives->nth(i);
      for (fint tempNo = lastTemp, ntries = 0; ntries < NumTempRegs;
           tempNo = nextTemp(tempNo), ntries++) {
        if (liveRange->isDisjointFrom(hardwired[tempNo])) {
          Location temp = TempRegs[tempNo];
          doAlloc(r, temp);
          hardwired[tempNo]->unionWith(liveRange);
          lastTemp = nextTemp(tempNo);
          break;
        }
      }
      if ( r->loc == UnAllocated
      && (PrintSICTempRegisterAllocation   
          ||   WizardMode  &&  TARGET_ARCH != I386_ARCH /* happens normally in I386; few regs */ )) {
        lprintf("*could NOT find temp assignment for local %s in BB%ld\n",
               r->name(), (void*)id());
      } else if (r->loc == UnAllocated) {
        if (PrintSICTempRegisterAllocation) lprintf("out of temp regs");
      }
      r->regClass = 0;
    }
  }
Example #10
0
void InlinedScope::generateDebugInfo() {
  // Generate debug info for the common parts of methods and blocks

  if (PrintDebugInfoGeneration) {
    if (isMethodScope()) {
      std->print_cr("self: %s", _self->preg()->name());
    } else {
      std->print_cr("no receiver (block method)");
    }
  }

  ScopeDescRecorder* rec = theCompiler->scopeDescRecorder();
  int len, i;

  if (!isLite()) {
    // temporaries
    if (hasTemporaries()) {
      len = _temporaries->length();
      for (i = 0; i < len; i++) {
        PReg* preg = _temporaries->at(i)->preg();
        rec->addTemporary(_scopeInfo, i, preg->createLogicalAddress());
	if (PrintDebugInfoGeneration) std->print_cr("temp[%2d]: %s", i, preg->name());
      }
    }
    // float temporaries
    if (hasFloatTemporaries()) {
      len = _floatTemporaries->length();
      for (i = 0; i < len; i++) {
        PReg* preg = _floatTemporaries->at(i)->preg();
        rec->addTemporary(_scopeInfo, i, preg->createLogicalAddress());
	if (PrintDebugInfoGeneration) std->print_cr("float[%2d]: %s", i, preg->name());
      }
    }
    // context temporaries
    if (allocatesInterpretedContext()) {
      len = _contextTemporaries->length();
      for (i = 0; i < len; i++) {
        PReg* preg = _contextTemporaries->at(i)->preg();
        rec->addContextTemporary(_scopeInfo, i, preg->createLogicalAddress());
	if (PrintDebugInfoGeneration) std->print_cr("c_temp[%2d]: %s", i, preg->name());
      }
    }
    // expr stack
    len = _exprStackElems->length();
    for (i = 0; i < len; i++) {
      Expr* elem = _exprStackElems->at(i);
      if (elem != NULL) {
        PReg* r = elem->preg()->cpReg();
        if (r->scope()->isSenderOrSame(this)) {
	  // Note: Is it still needed to create this info here, since the
	  //       PReg locations may change over time and thus produce more
	  //       debug info than actually needed for the new backend. Discuss
	  //       this with Lars.
          rec->addExprStack(_scopeInfo, i, r->createLogicalAddress());
          if (PrintDebugInfoGeneration) std->print_cr("expr[%2d]: %s", i, r->name());
        } else {
  	  // r's scope is too low (i.e. it's not actually live anymore)
	  // this can only happen if the expression is discarded; thus it's safe not to describe this entry
	  // Urs 5/96
	  // fix this: should check that bci (i) is statement end (or r is NoPReg)
        }
      }
    }
  }

  // subscopes
  len = _subScopes->length();
  for (i = 0; i < len; i++) {
    InlinedScope* s = _subScopes->at(i);
    if (PrintDebugInfoGeneration) std->print_cr("Subscope %d (id = %d):", i, s->scopeID());
    s->generateDebugInfo();
  }
}