1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
//===-- funcgenstate.cpp --------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/funcgenstate.h"
#include "dmd/identifier.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/ms-cxx-helper.h"
#include "gen/runtime.h"
#include "ir/irfunction.h"
JumpTarget::JumpTarget(llvm::BasicBlock *targetBlock,
CleanupCursor cleanupScope, Statement *targetStatement)
: targetBlock(targetBlock), cleanupScope(cleanupScope),
targetStatement(targetStatement) {}
JumpTargets::JumpTargets(TryCatchFinallyScopes &scopes) : scopes(scopes) {}
void JumpTargets::pushLoopTarget(Statement *loopStatement,
llvm::BasicBlock *continueTarget,
llvm::BasicBlock *breakTarget) {
continueTargets.emplace_back(continueTarget, scopes.currentCleanupScope(),
loopStatement);
breakTargets.emplace_back(breakTarget, scopes.currentCleanupScope(),
loopStatement);
}
void JumpTargets::popLoopTarget() {
continueTargets.pop_back();
breakTargets.pop_back();
}
void JumpTargets::pushBreakTarget(Statement *switchStatement,
llvm::BasicBlock *targetBlock) {
breakTargets.push_back(
{targetBlock, scopes.currentCleanupScope(), switchStatement});
}
void JumpTargets::popBreakTarget() { breakTargets.pop_back(); }
void JumpTargets::addLabelTarget(Identifier *labelName,
llvm::BasicBlock *targetBlock) {
labelTargets[labelName] = {targetBlock, scopes.currentCleanupScope(),
nullptr};
// See whether any of the unresolved gotos target this label, and resolve
// those that do.
scopes.tryResolveGotos(labelName, targetBlock);
}
void JumpTargets::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()) {
scopes.runCleanups(it->second.cleanupScope, it->second.targetBlock);
} else {
scopes.registerUnresolvedGoto(loc, labelName);
}
}
void JumpTargets::jumpToStatement(std::vector<JumpTarget> &targets,
Statement *loopOrSwitchStatement) {
for (auto it = targets.rbegin(), end = targets.rend(); it != end; ++it) {
if (it->targetStatement == loopOrSwitchStatement) {
scopes.runCleanups(it->cleanupScope, it->targetBlock);
return;
}
}
assert(false && "Target for labeled break not found.");
}
void JumpTargets::jumpToClosest(std::vector<JumpTarget> &targets) {
assert(!targets.empty() &&
"Encountered break/continue but no loop in scope.");
JumpTarget &t = targets.back();
scopes.runCleanups(t.cleanupScope, t.targetBlock);
}
llvm::BasicBlock *SwitchCaseTargets::get(Statement *stmt) {
auto it = targetBBs.find(stmt);
assert(it != targetBBs.end());
return it->second;
}
llvm::BasicBlock *SwitchCaseTargets::getOrCreate(Statement *stmt,
const llvm::Twine &name,
IRState &irs) {
auto &bb = targetBBs[stmt];
if (!bb)
bb = irs.insertBB(name);
return bb;
}
FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
irs(irs) {}
LLCallBasePtr FuncGenState::callOrInvoke(llvm::Value *callee,
llvm::FunctionType *calleeType,
llvm::ArrayRef<llvm::Value *> args,
const char *name, bool isNothrow) {
// If this is a direct call, we might be able to use the callee attributes
// to our advantage.
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
// Ignore 'nothrow' if there are active catch blocks handling non-Exception
// Throwables.
if (isNothrow && scopes.isCatchingNonExceptions())
isNothrow = false;
// Intrinsics don't support invoking and 'nounwind' functions don't need it.
const bool doesNotThrow =
isNothrow || global.params.betterC ||
(calleeFn && (calleeFn->isIntrinsic() || calleeFn->doesNotThrow()));
// calls inside a funclet must be annotated with its value
llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;
#if LDC_LLVM_VER >= 1100
llvm::FunctionCallee calleeArg(calleeType, callee);
#else
auto calleeArg = callee;
#endif
if (doesNotThrow || scopes.empty()) {
auto call = irs.ir->CreateCall(calleeArg, args, BundleList, name);
if (calleeFn) {
call->setAttributes(calleeFn->getAttributes());
}
return call;
}
llvm::BasicBlock *landingPad = scopes.getLandingPad();
llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
auto invoke = irs.ir->CreateInvoke(calleeArg, postinvoke, landingPad, args,
BundleList, name);
if (calleeFn) {
invoke->setAttributes(calleeFn->getAttributes());
}
irs.ir->SetInsertPoint(postinvoke);
return invoke;
}
|