driver/gen/ir: clang-format the world

This uses the LLVM style, which makes sense for sharing code
with other LLVM projects. The DMD code we use will soon all
be in D anyway.
This commit is contained in:
David Nadlinger 2015-11-01 22:09:44 +02:00
parent 123666cf89
commit 44b0f7b615
125 changed files with 28991 additions and 30602 deletions

View file

@ -16,443 +16,428 @@
#include "ir/irfunction.h"
#include <sstream>
JumpTarget::JumpTarget(llvm::BasicBlock* targetBlock, CleanupCursor cleanupScope,
Statement* targetStatement)
JumpTarget::JumpTarget(llvm::BasicBlock *targetBlock,
CleanupCursor cleanupScope, Statement *targetStatement)
: targetBlock(targetBlock), cleanupScope(cleanupScope),
targetStatement(targetStatement)
{}
targetStatement(targetStatement) {}
GotoJump::GotoJump(Loc loc, llvm::BasicBlock* sourceBlock,
llvm::BasicBlock* tentativeTarget, Identifier* targetLabel)
GotoJump::GotoJump(Loc loc, llvm::BasicBlock *sourceBlock,
llvm::BasicBlock *tentativeTarget, Identifier *targetLabel)
: sourceLoc(loc), sourceBlock(sourceBlock),
tentativeTarget(tentativeTarget), targetLabel(targetLabel)
{}
tentativeTarget(tentativeTarget), targetLabel(targetLabel) {}
CatchScope::CatchScope(llvm::Constant* classInfoPtr, llvm::BasicBlock* bodyBlock,
CleanupCursor cleanupScope)
: classInfoPtr(classInfoPtr), bodyBlock(bodyBlock), cleanupScope(cleanupScope)
{}
CatchScope::CatchScope(llvm::Constant *classInfoPtr,
llvm::BasicBlock *bodyBlock, CleanupCursor cleanupScope)
: classInfoPtr(classInfoPtr), bodyBlock(bodyBlock),
cleanupScope(cleanupScope) {}
namespace {
void executeCleanup(IRState* irs, CleanupScope& scope,
llvm::BasicBlock* sourceBlock, llvm::BasicBlock* continueWith
) {
if (scope.exitTargets.empty() || (
scope.exitTargets.size() == 1 &&
scope.exitTargets[0].branchTarget == continueWith
)) {
// We didn't need a branch selector before and still don't need one.
assert(!scope.branchSelector);
void executeCleanup(IRState *irs, CleanupScope &scope,
llvm::BasicBlock *sourceBlock,
llvm::BasicBlock *continueWith) {
if (scope.exitTargets.empty() ||
(scope.exitTargets.size() == 1 &&
scope.exitTargets[0].branchTarget == continueWith)) {
// We didn't need a branch selector before and still don't need one.
assert(!scope.branchSelector);
// Set up the unconditional branch at the end of the cleanup if we have
// not done so already.
if (scope.exitTargets.empty()) {
scope.exitTargets.push_back(CleanupExitTarget(continueWith));
llvm::BranchInst::Create(continueWith, scope.endBlock);
}
scope.exitTargets.front().sourceBlocks.push_back(sourceBlock);
return;
// Set up the unconditional branch at the end of the cleanup if we have
// not done so already.
if (scope.exitTargets.empty()) {
scope.exitTargets.push_back(CleanupExitTarget(continueWith));
llvm::BranchInst::Create(continueWith, scope.endBlock);
}
scope.exitTargets.front().sourceBlocks.push_back(sourceBlock);
return;
}
// We need a branch selector if we are here...
if (!scope.branchSelector) {
// ... and have not created one yet, so do so now.
scope.branchSelector = new llvm::AllocaInst(
llvm::Type::getInt32Ty(gIR->context()),
llvm::Twine("branchsel.") + scope.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.
auto &v = scope.exitTargets.front().sourceBlocks;
for (auto bb : v) {
new llvm::StoreInst(DtoConstUint(0), scope.branchSelector,
bb->getTerminator());
}
// We need a branch selector if we are here...
if (!scope.branchSelector) {
// ... and have not created one yet, so do so now.
scope.branchSelector = new llvm::AllocaInst(
llvm::Type::getInt32Ty(gIR->context()),
llvm::Twine("branchsel.") + scope.beginBlock->getName(),
irs->topallocapoint()
);
// And convert the BranchInst to the existing branch target to a
// SelectInst so we can append the other cases to it.
scope.endBlock->getTerminator()->eraseFromParent();
llvm::Value *sel =
new llvm::LoadInst(scope.branchSelector, "", scope.endBlock);
llvm::SwitchInst::Create(
sel, scope.exitTargets[0].branchTarget,
1, // Expected number of branches, only for pre-allocating.
scope.endBlock);
}
// Now we also need to store 0 to it to keep the paths that go to the
// only existing branch target the same.
auto& v = scope.exitTargets.front().sourceBlocks;
for (auto bb : v)
{
new llvm::StoreInst(DtoConstUint(0), scope.branchSelector,
bb->getTerminator());
}
// 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 < scope.exitTargets.size(); ++i) {
CleanupExitTarget &t = scope.exitTargets[i];
if (t.branchTarget == continueWith) {
new llvm::StoreInst(DtoConstUint(i), scope.branchSelector,
sourceBlock->getTerminator());
// And convert the BranchInst to the existing branch target to a
// SelectInst so we can append the other cases to it.
scope.endBlock->getTerminator()->eraseFromParent();
llvm::Value* sel = new llvm::LoadInst(scope.branchSelector, "",
scope.endBlock);
llvm::SwitchInst::Create(
sel,
scope.exitTargets[0].branchTarget,
1, // Expected number of branches, only for pre-allocating.
scope.endBlock
);
// 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;
}
}
// 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 < scope.exitTargets.size(); ++i) {
CleanupExitTarget& t = scope.exitTargets[i];
if (t.branchTarget == continueWith) {
new llvm::StoreInst(DtoConstUint(i), scope.branchSelector,
sourceBlock->getTerminator());
// We don't know this branch target yet, so add it to the SwitchInst...
llvm::ConstantInt *const selectorVal = DtoConstUint(scope.exitTargets.size());
llvm::cast<llvm::SwitchInst>(scope.endBlock->getTerminator())
->addCase(selectorVal, continueWith);
// 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);
// ... insert the store into the source block...
new llvm::StoreInst(selectorVal, scope.branchSelector,
sourceBlock->getTerminator());
return;
}
}
// We don't know this branch target yet, so add it to the SwitchInst...
llvm::ConstantInt* const selectorVal = DtoConstUint(scope.exitTargets.size());
llvm::cast<llvm::SwitchInst>(scope.endBlock->getTerminator())->addCase(
selectorVal, continueWith);
// ... insert the store into the source block...
new llvm::StoreInst(selectorVal, scope.branchSelector,
sourceBlock->getTerminator());
// ... and keep track of it (again, this is unnecessary right now as
// discussed in the above note).
scope.exitTargets.push_back(CleanupExitTarget(continueWith));
scope.exitTargets.back().sourceBlocks.push_back(sourceBlock);
// ... and keep track of it (again, this is unnecessary right now as
// discussed in the above note).
scope.exitTargets.push_back(CleanupExitTarget(continueWith));
scope.exitTargets.back().sourceBlocks.push_back(sourceBlock);
}
}
ScopeStack::~ScopeStack() {
// If there are still unresolved gotos left, it means that they were either
// down or "sideways" (i.e. down another branch) of the tree of all
// cleanup scopes, both of which are not allowed in D.
if (!topLevelUnresolvedGotos.empty()) {
for (const auto& i : topLevelUnresolvedGotos)
error(i.sourceLoc, "goto into try/finally scope is not allowed");
fatal();
}
// If there are still unresolved gotos left, it means that they were either
// down or "sideways" (i.e. down another branch) of the tree of all
// cleanup scopes, both of which are not allowed in D.
if (!topLevelUnresolvedGotos.empty()) {
for (const auto &i : topLevelUnresolvedGotos)
error(i.sourceLoc, "goto into try/finally scope is not allowed");
fatal();
}
}
void ScopeStack::pushCleanup(llvm::BasicBlock* beginBlock, llvm::BasicBlock* endBlock) {
cleanupScopes.push_back(CleanupScope(beginBlock, endBlock));
void ScopeStack::pushCleanup(llvm::BasicBlock *beginBlock,
llvm::BasicBlock *endBlock) {
cleanupScopes.push_back(CleanupScope(beginBlock, endBlock));
}
void ScopeStack::runCleanups(
CleanupCursor sourceScope,
CleanupCursor targetScope,
llvm::BasicBlock* continueWith
) {
assert(targetScope <= sourceScope);
void ScopeStack::runCleanups(CleanupCursor sourceScope,
CleanupCursor targetScope,
llvm::BasicBlock *continueWith) {
assert(targetScope <= sourceScope);
if (targetScope == sourceScope) {
// No cleanups to run, just branch to the next block.
irs->ir->CreateBr(continueWith);
return;
}
if (targetScope == sourceScope) {
// No cleanups to run, just branch to the next block.
irs->ir->CreateBr(continueWith);
return;
}
// Insert the unconditional branch to the first cleanup block.
irs->ir->CreateBr(cleanupScopes[sourceScope - 1].beginBlock);
// Insert the unconditional branch to the first cleanup block.
irs->ir->CreateBr(cleanupScopes[sourceScope - 1].beginBlock);
// Update all the control flow in the cleanups to make sure we end up where
// we want.
for (CleanupCursor i = sourceScope; i-- > targetScope;) {
llvm::BasicBlock* nextBlock = (i > targetScope) ?
cleanupScopes[i - 1].beginBlock : continueWith;
executeCleanup(irs, cleanupScopes[i], irs->scopebb(), nextBlock);
}
// Update all the control flow in the cleanups to make sure we end up where
// we want.
for (CleanupCursor i = sourceScope; i-- > targetScope;) {
llvm::BasicBlock *nextBlock =
(i > targetScope) ? cleanupScopes[i - 1].beginBlock : continueWith;
executeCleanup(irs, cleanupScopes[i], irs->scopebb(), nextBlock);
}
}
void ScopeStack::runAllCleanups(llvm::BasicBlock* continueWith) {
runCleanups(0, continueWith);
void ScopeStack::runAllCleanups(llvm::BasicBlock *continueWith) {
runCleanups(0, continueWith);
}
void ScopeStack::popCleanups(CleanupCursor targetScope) {
assert(targetScope <= currentCleanupScope());
if (targetScope == currentCleanupScope()) return;
assert(targetScope <= currentCleanupScope());
if (targetScope == currentCleanupScope())
return;
for (CleanupCursor i = currentCleanupScope(); i-- > targetScope;) {
// Any gotos that are still unresolved necessarily leave this scope.
// Thus, the cleanup needs to be executed.
for (const auto& gotoJump : currentUnresolvedGotos())
{
// Make the source resp. last cleanup branch to this one.
llvm::BasicBlock* tentative = gotoJump.tentativeTarget;
tentative->replaceAllUsesWith(cleanupScopes[i].beginBlock);
for (CleanupCursor i = currentCleanupScope(); i-- > targetScope;) {
// Any gotos that are still unresolved necessarily leave this scope.
// Thus, the cleanup needs to be executed.
for (const auto &gotoJump : currentUnresolvedGotos()) {
// Make the source resp. last cleanup branch to this one.
llvm::BasicBlock *tentative = gotoJump.tentativeTarget;
tentative->replaceAllUsesWith(cleanupScopes[i].beginBlock);
// And continue execution with the tentative target (we simply reuse
// it because there is no reason not to).
executeCleanup(irs, cleanupScopes[i], gotoJump.sourceBlock, tentative);
}
std::vector<GotoJump>& nextUnresolved = (i == 0) ?
topLevelUnresolvedGotos : cleanupScopes[i - 1].unresolvedGotos;
nextUnresolved.insert(
nextUnresolved.end(),
currentUnresolvedGotos().begin(),
currentUnresolvedGotos().end()
);
cleanupScopes.pop_back();
// And continue execution with the tentative target (we simply reuse
// it because there is no reason not to).
executeCleanup(irs, cleanupScopes[i], gotoJump.sourceBlock, tentative);
}
std::vector<GotoJump> &nextUnresolved =
(i == 0) ? topLevelUnresolvedGotos
: cleanupScopes[i - 1].unresolvedGotos;
nextUnresolved.insert(nextUnresolved.end(),
currentUnresolvedGotos().begin(),
currentUnresolvedGotos().end());
cleanupScopes.pop_back();
}
}
void ScopeStack::pushCatch(llvm::Constant* classInfoPtr,
llvm::BasicBlock* bodyBlock
) {
catchScopes.emplace_back(classInfoPtr, bodyBlock, currentCleanupScope());
currentLandingPads().push_back(nullptr);
void ScopeStack::pushCatch(llvm::Constant *classInfoPtr,
llvm::BasicBlock *bodyBlock) {
catchScopes.emplace_back(classInfoPtr, bodyBlock, currentCleanupScope());
currentLandingPads().push_back(nullptr);
}
void ScopeStack::popCatch() {
catchScopes.pop_back();
currentLandingPads().pop_back();
catchScopes.pop_back();
currentLandingPads().pop_back();
}
void ScopeStack::pushLoopTarget(Statement* loopStatement, llvm::BasicBlock* continueTarget,
llvm::BasicBlock* breakTarget
) {
continueTargets.emplace_back(continueTarget, currentCleanupScope(), loopStatement);
breakTargets.emplace_back(breakTarget, currentCleanupScope(), loopStatement);
void ScopeStack::pushLoopTarget(Statement *loopStatement,
llvm::BasicBlock *continueTarget,
llvm::BasicBlock *breakTarget) {
continueTargets.emplace_back(continueTarget, currentCleanupScope(),
loopStatement);
breakTargets.emplace_back(breakTarget, currentCleanupScope(), loopStatement);
}
void ScopeStack::popLoopTarget() {
continueTargets.pop_back();
breakTargets.pop_back();
continueTargets.pop_back();
breakTargets.pop_back();
}
void ScopeStack::pushBreakTarget(Statement* switchStatement,
llvm::BasicBlock* targetBlock
) {
breakTargets.push_back({targetBlock, currentCleanupScope(), switchStatement});
void ScopeStack::pushBreakTarget(Statement *switchStatement,
llvm::BasicBlock *targetBlock) {
breakTargets.push_back({targetBlock, currentCleanupScope(), switchStatement});
}
void ScopeStack::popBreakTarget() {
breakTargets.pop_back();
}
void ScopeStack::popBreakTarget() { breakTargets.pop_back(); }
void ScopeStack::addLabelTarget(Identifier* labelName,
llvm::BasicBlock* targetBlock
) {
labelTargets[labelName] = {targetBlock, currentCleanupScope(), 0};
void ScopeStack::addLabelTarget(Identifier *labelName,
llvm::BasicBlock *targetBlock) {
labelTargets[labelName] = {targetBlock, currentCleanupScope(), 0};
// See whether any of the unresolved gotos target this label, and resolve
// those that do.
std::vector<GotoJump>& unresolved = currentUnresolvedGotos();
size_t i = 0;
while (i < unresolved.size()) {
if (unresolved[i].targetLabel != labelName) {
++i;
continue;
}
unresolved[i].tentativeTarget->replaceAllUsesWith(targetBlock);
unresolved[i].tentativeTarget->eraseFromParent();
unresolved.erase(unresolved.begin() + i);
}
}
void ScopeStack::jumpToLabel(Loc loc, Identifier* labelName) {
// If we have already seen that label, branch to it, executing any cleanups
// as necessary.
auto it = labelTargets.find(labelName);
if (it != labelTargets.end()) {
runCleanups(it->second.cleanupScope, it->second.targetBlock);
return;
// See whether any of the unresolved gotos target this label, and resolve
// those that do.
std::vector<GotoJump> &unresolved = currentUnresolvedGotos();
size_t i = 0;
while (i < unresolved.size()) {
if (unresolved[i].targetLabel != labelName) {
++i;
continue;
}
llvm::BasicBlock* target =
llvm::BasicBlock::Create(irs->context(), "goto.unresolved", irs->topfunc());
irs->ir->CreateBr(target);
currentUnresolvedGotos().emplace_back(loc, irs->scopebb(), target, labelName);
unresolved[i].tentativeTarget->replaceAllUsesWith(targetBlock);
unresolved[i].tentativeTarget->eraseFromParent();
unresolved.erase(unresolved.begin() + i);
}
}
void ScopeStack::jumpToStatement(std::vector<JumpTarget>& targets,
Statement* loopOrSwitchStatement
) {
for (std::vector<JumpTarget>::reverse_iterator it = targets.rbegin(),
end = targets.rend();
it != end; ++it
) {
if (it->targetStatement == loopOrSwitchStatement) {
runCleanups(it->cleanupScope, it->targetBlock);
return;
}
void ScopeStack::jumpToLabel(Loc loc, Identifier *labelName) {
// If we have already seen that label, branch to it, executing any cleanups
// as necessary.
auto it = labelTargets.find(labelName);
if (it != labelTargets.end()) {
runCleanups(it->second.cleanupScope, it->second.targetBlock);
return;
}
llvm::BasicBlock *target = llvm::BasicBlock::Create(
irs->context(), "goto.unresolved", irs->topfunc());
irs->ir->CreateBr(target);
currentUnresolvedGotos().emplace_back(loc, irs->scopebb(), target, labelName);
}
void ScopeStack::jumpToStatement(std::vector<JumpTarget> &targets,
Statement *loopOrSwitchStatement) {
for (std::vector<JumpTarget>::reverse_iterator it = targets.rbegin(),
end = targets.rend();
it != end; ++it) {
if (it->targetStatement == loopOrSwitchStatement) {
runCleanups(it->cleanupScope, it->targetBlock);
return;
}
assert(false && "Target for labeled break not found.");
}
assert(false && "Target for labeled break not found.");
}
void ScopeStack::jumpToClosest(std::vector<JumpTarget>& targets) {
assert(!targets.empty() &&
"Encountered break/continue but no loop in scope.");
JumpTarget& t = targets.back();
runCleanups(t.cleanupScope, t.targetBlock);
void ScopeStack::jumpToClosest(std::vector<JumpTarget> &targets) {
assert(!targets.empty() &&
"Encountered break/continue but no loop in scope.");
JumpTarget &t = targets.back();
runCleanups(t.cleanupScope, t.targetBlock);
}
std::vector<GotoJump>& ScopeStack::currentUnresolvedGotos() {
return cleanupScopes.empty() ?
topLevelUnresolvedGotos :
cleanupScopes.back().unresolvedGotos;
std::vector<GotoJump> &ScopeStack::currentUnresolvedGotos() {
return cleanupScopes.empty() ? topLevelUnresolvedGotos
: cleanupScopes.back().unresolvedGotos;
}
std::vector<llvm::BasicBlock*>& ScopeStack::currentLandingPads() {
return cleanupScopes.empty() ?
topLevelLandingPads :
cleanupScopes.back().landingPads;
std::vector<llvm::BasicBlock *> &ScopeStack::currentLandingPads() {
return cleanupScopes.empty() ? topLevelLandingPads
: cleanupScopes.back().landingPads;
}
namespace {
llvm::LandingPadInst* createLandingPadInst(IRState* irs) {
LLType* retType = LLStructType::get(LLType::getInt8PtrTy(irs->context()),
LLType::getInt32Ty(irs->context()),
nullptr);
llvm::LandingPadInst *createLandingPadInst(IRState *irs) {
LLType *retType =
LLStructType::get(LLType::getInt8PtrTy(irs->context()),
LLType::getInt32Ty(irs->context()), nullptr);
#if LDC_LLVM_VER >= 307
LLFunction* currentFunction = irs->func()->func;
if (!currentFunction->hasPersonalityFn()) {
LLFunction* personalityFn = LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
currentFunction->setPersonalityFn(personalityFn);
}
return irs->ir->CreateLandingPad(retType, 0);
LLFunction *currentFunction = irs->func()->func;
if (!currentFunction->hasPersonalityFn()) {
LLFunction *personalityFn =
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
currentFunction->setPersonalityFn(personalityFn);
}
return irs->ir->CreateLandingPad(retType, 0);
#else
LLFunction* personalityFn = LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
return irs->ir->CreateLandingPad(retType, personalityFn, 0);
LLFunction *personalityFn =
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
return irs->ir->CreateLandingPad(retType, personalityFn, 0);
#endif
}
}
llvm::BasicBlock* ScopeStack::emitLandingPad() {
// save and rewrite scope
IRScope savedIRScope = irs->scope();
llvm::BasicBlock *ScopeStack::emitLandingPad() {
// save and rewrite scope
IRScope savedIRScope = irs->scope();
llvm::BasicBlock* beginBB = llvm::BasicBlock::Create(irs->context(),
"landingPad", irs->topfunc());
irs->scope() = IRScope(beginBB);
llvm::BasicBlock *beginBB =
llvm::BasicBlock::Create(irs->context(), "landingPad", irs->topfunc());
irs->scope() = IRScope(beginBB);
llvm::LandingPadInst* landingPad = createLandingPadInst(irs);
llvm::LandingPadInst *landingPad = createLandingPadInst(irs);
// Stash away the exception object pointer and selector value into their
// stack slots.
llvm::Value* ehPtr = DtoExtractValue(landingPad, 0);
if (!irs->func()->resumeUnwindBlock) {
irs->func()->resumeUnwindBlock = llvm::BasicBlock::Create(
irs->context(), "unwind.resume", irs->topfunc());
// Stash away the exception object pointer and selector value into their
// stack slots.
llvm::Value *ehPtr = DtoExtractValue(landingPad, 0);
if (!irs->func()->resumeUnwindBlock) {
irs->func()->resumeUnwindBlock = llvm::BasicBlock::Create(
irs->context(), "unwind.resume", irs->topfunc());
llvm::BasicBlock* oldBB = irs->scopebb();
irs->scope() = IRScope(irs->func()->resumeUnwindBlock);
llvm::BasicBlock *oldBB = irs->scopebb();
irs->scope() = IRScope(irs->func()->resumeUnwindBlock);
llvm::Function* resumeFn = LLVM_D_GetRuntimeFunction(Loc(),
irs->module, "_d_eh_resume_unwind");
irs->ir->CreateCall(resumeFn,
irs->ir->CreateLoad(irs->func()->getOrCreateEhPtrSlot()));
irs->ir->CreateUnreachable();
llvm::Function *resumeFn =
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_resume_unwind");
irs->ir->CreateCall(
resumeFn, irs->ir->CreateLoad(irs->func()->getOrCreateEhPtrSlot()));
irs->ir->CreateUnreachable();
irs->scope() = IRScope(oldBB);
}
irs->ir->CreateStore(ehPtr, irs->func()->getOrCreateEhPtrSlot());
irs->scope() = IRScope(oldBB);
}
irs->ir->CreateStore(ehPtr, irs->func()->getOrCreateEhPtrSlot());
llvm::Value* ehSelector = DtoExtractValue(landingPad, 1);
if (!irs->func()->ehSelectorSlot) {
irs->func()->ehSelectorSlot =
DtoRawAlloca(ehSelector->getType(), 0, "eh.selector");
}
irs->ir->CreateStore(ehSelector, irs->func()->ehSelectorSlot);
llvm::Value *ehSelector = DtoExtractValue(landingPad, 1);
if (!irs->func()->ehSelectorSlot) {
irs->func()->ehSelectorSlot =
DtoRawAlloca(ehSelector->getType(), 0, "eh.selector");
}
irs->ir->CreateStore(ehSelector, irs->func()->ehSelectorSlot);
// Add landingpad clauses, emit finallys and 'if' chain to catch the exception.
CleanupCursor lastCleanup = currentCleanupScope();
for (auto it = catchScopes.rbegin(), end = catchScopes.rend(); it != end; ++it) {
// Insert any cleanups in between the last catch we ran and this one.
assert(lastCleanup >= it->cleanupScope);
if (lastCleanup > it->cleanupScope) {
landingPad->setCleanup(true);
llvm::BasicBlock* afterCleanupBB = llvm::BasicBlock::Create(
irs->context(),
beginBB->getName() + llvm::Twine(".after.cleanup"),
irs->topfunc()
);
runCleanups(lastCleanup, it->cleanupScope, afterCleanupBB);
irs->scope() = IRScope(afterCleanupBB);
lastCleanup = it->cleanupScope;
}
// Add the ClassInfo reference to the landingpad instruction so it is
// emitted to the EH tables.
landingPad->addClause(it->classInfoPtr);
llvm::BasicBlock* mismatchBB = llvm::BasicBlock::Create(
irs->context(),
beginBB->getName() + llvm::Twine(".mismatch"),
irs->topfunc()
);
// "Call" llvm.eh.typeid.for, which gives us the eh selector value to compare with
llvm::Value* ehTypeId = irs->ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
DtoBitCast(it->classInfoPtr, getVoidPtrType()));
// Compare the selector value from the unwinder against the expected
// one and branch accordingly.
irs->ir->CreateCondBr(
irs->ir->CreateICmpEQ(
irs->ir->CreateLoad(irs->func()->ehSelectorSlot), ehTypeId),
it->bodyBlock,
mismatchBB
);
irs->scope() = IRScope(mismatchBB);
// Add landingpad clauses, emit finallys and 'if' chain to catch the
// exception.
CleanupCursor lastCleanup = currentCleanupScope();
for (auto it = catchScopes.rbegin(), end = catchScopes.rend(); it != end;
++it) {
// Insert any cleanups in between the last catch we ran and this one.
assert(lastCleanup >= it->cleanupScope);
if (lastCleanup > it->cleanupScope) {
landingPad->setCleanup(true);
llvm::BasicBlock *afterCleanupBB = llvm::BasicBlock::Create(
irs->context(), beginBB->getName() + llvm::Twine(".after.cleanup"),
irs->topfunc());
runCleanups(lastCleanup, it->cleanupScope, afterCleanupBB);
irs->scope() = IRScope(afterCleanupBB);
lastCleanup = it->cleanupScope;
}
// No catch matched. Execute all finallys and resume unwinding.
if (lastCleanup > 0) {
landingPad->setCleanup(true);
runCleanups(lastCleanup, 0, irs->func()->resumeUnwindBlock);
} else if (!catchScopes.empty()) {
// Directly convert the last mismatch branch into a branch to the
// unwind resume block.
irs->scopebb()->replaceAllUsesWith(irs->func()->resumeUnwindBlock);
irs->scopebb()->eraseFromParent();
} else {
irs->ir->CreateBr(irs->func()->resumeUnwindBlock);
}
// Add the ClassInfo reference to the landingpad instruction so it is
// emitted to the EH tables.
landingPad->addClause(it->classInfoPtr);
irs->scope() = savedIRScope;
return beginBB;
llvm::BasicBlock *mismatchBB = llvm::BasicBlock::Create(
irs->context(), beginBB->getName() + llvm::Twine(".mismatch"),
irs->topfunc());
// "Call" llvm.eh.typeid.for, which gives us the eh selector value to
// compare with
llvm::Value *ehTypeId =
irs->ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
DtoBitCast(it->classInfoPtr, getVoidPtrType()));
// Compare the selector value from the unwinder against the expected
// one and branch accordingly.
irs->ir->CreateCondBr(
irs->ir->CreateICmpEQ(irs->ir->CreateLoad(irs->func()->ehSelectorSlot),
ehTypeId),
it->bodyBlock, mismatchBB);
irs->scope() = IRScope(mismatchBB);
}
// No catch matched. Execute all finallys and resume unwinding.
if (lastCleanup > 0) {
landingPad->setCleanup(true);
runCleanups(lastCleanup, 0, irs->func()->resumeUnwindBlock);
} else if (!catchScopes.empty()) {
// Directly convert the last mismatch branch into a branch to the
// unwind resume block.
irs->scopebb()->replaceAllUsesWith(irs->func()->resumeUnwindBlock);
irs->scopebb()->eraseFromParent();
} else {
irs->ir->CreateBr(irs->func()->resumeUnwindBlock);
}
irs->scope() = savedIRScope;
return beginBB;
}
IrFunction::IrFunction(FuncDeclaration* fd) {
decl = fd;
IrFunction::IrFunction(FuncDeclaration *fd) {
decl = fd;
Type* t = fd->type->toBasetype();
assert(t->ty == Tfunction);
type = static_cast<TypeFunction*>(t);
Type *t = fd->type->toBasetype();
assert(t->ty == Tfunction);
type = static_cast<TypeFunction *>(t);
}
void IrFunction::setNeverInline() {
assert(!func->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::AlwaysInline) && "function can't be never- and always-inline at the same time");
func->addFnAttr(llvm::Attribute::NoInline);
assert(!func->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::AlwaysInline) &&
"function can't be never- and always-inline at the same time");
func->addFnAttr(llvm::Attribute::NoInline);
}
void IrFunction::setAlwaysInline() {
assert(!func->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoInline) && "function can't be never- and always-inline at the same time");
func->addFnAttr(llvm::Attribute::AlwaysInline);
assert(!func->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoInline) &&
"function can't be never- and always-inline at the same time");
func->addFnAttr(llvm::Attribute::AlwaysInline);
}
llvm::AllocaInst* IrFunction::getOrCreateEhPtrSlot() {
if (!ehPtrSlot) {
ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr");
}
return ehPtrSlot;
llvm::AllocaInst *IrFunction::getOrCreateEhPtrSlot() {
if (!ehPtrSlot) {
ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr");
}
return ehPtrSlot;
}
IrFunction* getIrFunc(FuncDeclaration* decl, bool create)
{
if (!isIrFuncCreated(decl) && create) {
assert(decl->ir.irFunc == NULL);
decl->ir.irFunc = new IrFunction(decl);
decl->ir.m_type = IrDsymbol::FuncType;
}
assert(decl->ir.irFunc != NULL);
return decl->ir.irFunc;
IrFunction *getIrFunc(FuncDeclaration *decl, bool create) {
if (!isIrFuncCreated(decl) && create) {
assert(decl->ir.irFunc == NULL);
decl->ir.irFunc = new IrFunction(decl);
decl->ir.m_type = IrDsymbol::FuncType;
}
assert(decl->ir.irFunc != NULL);
return decl->ir.irFunc;
}
bool isIrFuncCreated(FuncDeclaration* decl) {
int t = decl->ir.type();
assert(t == IrDsymbol::FuncType || t == IrDsymbol::NotSet);
return t == IrDsymbol::FuncType;
bool isIrFuncCreated(FuncDeclaration *decl) {
int t = decl->ir.type();
assert(t == IrDsymbol::FuncType || t == IrDsymbol::NotSet);
return t == IrDsymbol::FuncType;
}