Exemple #1
0
llvm::BasicBlock *CleanupScope::runCopying(IRState &irs,
                                           llvm::BasicBlock *sourceBlock,
                                           llvm::BasicBlock *continueWith,
                                           llvm::BasicBlock *unwindTo,
                                           llvm::Value *funclet) {
  if (isCatchSwitchBlock(beginBlock()))
    return continueWith;
  if (exitTargets.empty()) {
    if (!endBlock()->getTerminator())
      // Set up the unconditional branch at the end of the cleanup
      llvm::BranchInst::Create(continueWith, endBlock());
  } else {
    // check whether we have an exit target with the same continuation
    for (CleanupExitTarget &tgt : exitTargets)
      if (tgt.branchTarget == continueWith) {
        tgt.sourceBlocks.push_back(sourceBlock);
        return tgt.cleanupBlocks.front();
      }
  }

  // reuse the original IR if not unwinding and not already used
  bool useOriginal = unwindTo == nullptr && funclet == nullptr;
  for (CleanupExitTarget &tgt : exitTargets) {
    if (tgt.cleanupBlocks.front() == beginBlock()) {
      useOriginal = false;
      break;
    }
  }

  // append new target
  exitTargets.emplace_back(continueWith);
  auto &exitTarget = exitTargets.back();
  exitTarget.sourceBlocks.push_back(sourceBlock);

  if (useOriginal) {
    // change the continuation target if the initial branch was created
    // by another instance with unwinding
    if (continueWith)
      if (auto term = endBlock()->getTerminator())
        if (auto succ = term->getSuccessor(0))
          if (succ != continueWith)
            remapBlocksValue(blocks, succ, continueWith);
    exitTarget.cleanupBlocks = blocks;
  } else {
    // clone the code
    cloneBlocks(blocks, exitTarget.cleanupBlocks, continueWith, unwindTo,
                funclet);
  }
  return exitTarget.cleanupBlocks.front();
}
Exemple #2
0
void Context::beginFunction(const Text &s)
{
    beginBlock(s);
}
Exemple #3
0
llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock,
                                    llvm::BasicBlock *continueWith) {
#if LDC_LLVM_VER >= 308
  if (useMSVCEH())
    return runCopying(irs, sourceBlock, continueWith);
#endif

  if (exitTargets.empty() || (exitTargets.size() == 1 &&
                              exitTargets[0].branchTarget == continueWith)) {
    // We didn't need a branch selector before and still don't need one.
    assert(!branchSelector);

    // Set up the unconditional branch at the end of the cleanup if we have
    // not done so already.
    if (exitTargets.empty()) {
      exitTargets.emplace_back(continueWith);
      llvm::BranchInst::Create(continueWith, endBlock());
    }
    exitTargets.front().sourceBlocks.push_back(sourceBlock);
    return beginBlock();
  }

  // We need a branch selector if we are here...
  if (!branchSelector) {
    // ... and have not created one yet, so do so now.
    branchSelector = new llvm::AllocaInst(llvm::Type::getInt32Ty(irs.context()),
#if LDC_LLVM_VER >= 500
                                          irs.module.getDataLayout().getAllocaAddrSpace(),
#endif
                                          llvm::Twine("branchsel.") +
                                              beginBlock()->getName(),
                                          irs.topallocapoint());

    // Now we also need to store 0 to it to keep the paths that go to the
    // only existing branch target the same.
    for (auto bb : exitTargets.front().sourceBlocks) {
      new llvm::StoreInst(DtoConstUint(0), branchSelector, bb->getTerminator());
    }

    // And convert the BranchInst to the existing branch target to a
    // SelectInst so we can append the other cases to it.
    endBlock()->getTerminator()->eraseFromParent();
    llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock());
    llvm::SwitchInst::Create(
        sel, exitTargets[0].branchTarget,
        1, // Expected number of branches, only for pre-allocating.
        endBlock());
  }

  // If we already know this branch target, figure out the branch selector
  // value and simply insert the store into the source block (prior to the
  // last instruction, which is the branch to the first cleanup).
  for (unsigned i = 0; i < exitTargets.size(); ++i) {
    CleanupExitTarget &t = exitTargets[i];
    if (t.branchTarget == continueWith) {
      new llvm::StoreInst(DtoConstUint(i), branchSelector,
                          sourceBlock->getTerminator());

      // Note: Strictly speaking, keeping this up to date would not be
      // needed right now, because we never to any optimizations that
      // require changes to the source blocks after the initial conversion
      // from one to two branch targets. Keeping this around for now to
      // ease future development, but may be removed to save some work.
      t.sourceBlocks.push_back(sourceBlock);

      return beginBlock();
    }
  }

  // We don't know this branch target yet, so add it to the SwitchInst...
  llvm::ConstantInt *const selectorVal = DtoConstUint(exitTargets.size());
  llvm::cast<llvm::SwitchInst>(endBlock()->getTerminator())
      ->addCase(selectorVal, continueWith);

  // ... insert the store into the source block...
  new llvm::StoreInst(selectorVal, branchSelector,
                      sourceBlock->getTerminator());

  // ... and keep track of it (again, this is unnecessary right now as
  // discussed in the above note).
  exitTargets.emplace_back(continueWith);
  exitTargets.back().sourceBlocks.push_back(sourceBlock);

  return beginBlock();
}