Single ret point in functions, so that a ret is always in the codepath.
This commit is contained in:
parent
3278f12028
commit
0c3702ea34
|
@ -49,6 +49,8 @@ using llvm::getGlobalContext;
|
||||||
|
|
||||||
struct BitcodeEmitter::Private {
|
struct BitcodeEmitter::Private {
|
||||||
llvm::Value *retval = nullptr;
|
llvm::Value *retval = nullptr;
|
||||||
|
llvm::AllocaInst *funcRetval = nullptr;
|
||||||
|
llvm::BasicBlock *funcExit = nullptr;
|
||||||
|
|
||||||
llvm::IRBuilder<> builder = llvm::IRBuilder<>(getGlobalContext());
|
llvm::IRBuilder<> builder = llvm::IRBuilder<>(getGlobalContext());
|
||||||
Scope<std::string, llvm::AllocaInst*> scope;
|
Scope<std::string, llvm::AllocaInst*> scope;
|
||||||
|
@ -60,6 +62,12 @@ llvm::AllocaInst* allocateVar(llvm::Function *func, Id const& name, llvm::Type *
|
||||||
return builder.CreateAlloca(type, 0, name.getValue().c_str());
|
return builder.CreateAlloca(type, 0, name.getValue().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
llvm::AllocaInst* allocateReturnVariable(llvm::Function *func) {
|
||||||
|
llvm::IRBuilder<> builder(&func->getEntryBlock(), func->getEntryBlock().begin());
|
||||||
|
return builder.CreateAlloca(func->getReturnType(), 0, "result");
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
llvm::Value* isTrue(llvm::IRBuilder<> &builder, llvm::Value* test, llvm::Twine const& label="") {
|
llvm::Value* isTrue(llvm::IRBuilder<> &builder, llvm::Value* test, llvm::Twine const& label="") {
|
||||||
return builder.CreateICmpNE(
|
return builder.CreateICmpNE(
|
||||||
|
@ -237,11 +245,12 @@ bool BitcodeEmitter::emit(Return const& node) {
|
||||||
if (node.getExpression()) {
|
if (node.getExpression()) {
|
||||||
GUARDED(node.getExpression()->emit(this));
|
GUARDED(node.getExpression()->emit(this));
|
||||||
llvm::Type *type = d->builder.GetInsertBlock()->getParent()->getReturnType();
|
llvm::Type *type = d->builder.GetInsertBlock()->getParent()->getReturnType();
|
||||||
d->builder.CreateRet(coerce(d, d->retval, type));
|
assert(d->funcRetval != nullptr);
|
||||||
} else {
|
d->builder.CreateStore(coerce(d, d->retval, type), d->funcRetval);
|
||||||
d->builder.CreateRetVoid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d->builder.CreateBr(d->funcExit);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,7 +561,6 @@ bool BitcodeEmitter::emit(Function const& node) {
|
||||||
GUARDED(node.getPrototype().emit(this));
|
GUARDED(node.getPrototype().emit(this));
|
||||||
llvm::Function *func = dynamic_cast<llvm::Function*>(d->retval);
|
llvm::Function *func = dynamic_cast<llvm::Function*>(d->retval);
|
||||||
|
|
||||||
d->scope.enter();
|
|
||||||
assert(func != nullptr);
|
assert(func != nullptr);
|
||||||
|
|
||||||
llvm::BasicBlock *bb = llvm::BasicBlock::Create(
|
llvm::BasicBlock *bb = llvm::BasicBlock::Create(
|
||||||
|
@ -560,6 +568,13 @@ bool BitcodeEmitter::emit(Function const& node) {
|
||||||
);
|
);
|
||||||
d->builder.SetInsertPoint(bb);
|
d->builder.SetInsertPoint(bb);
|
||||||
|
|
||||||
|
bool isNotVoid = node.getPrototype().getType() != Type::VOID;
|
||||||
|
|
||||||
|
d->funcRetval = isNotVoid? allocateReturnVariable(func): nullptr;
|
||||||
|
d->funcExit = llvm::BasicBlock::Create(getGlobalContext(), "return");
|
||||||
|
|
||||||
|
d->scope.enter();
|
||||||
|
|
||||||
auto argToAlloc = func->arg_begin();
|
auto argToAlloc = func->arg_begin();
|
||||||
for (FunArg const& arg: node.getPrototype().getArgs()) {
|
for (FunArg const& arg: node.getPrototype().getArgs()) {
|
||||||
llvm::AllocaInst *alloc = allocateVar(
|
llvm::AllocaInst *alloc = allocateVar(
|
||||||
|
@ -574,10 +589,20 @@ bool BitcodeEmitter::emit(Function const& node) {
|
||||||
GUARDED(stat.emit(this));
|
GUARDED(stat.emit(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyFunction(*func);
|
|
||||||
|
|
||||||
d->scope.leave();
|
d->scope.leave();
|
||||||
|
|
||||||
|
d->builder.CreateBr(d->funcExit);
|
||||||
|
func->getBasicBlockList().push_back(d->funcExit);
|
||||||
|
d->builder.SetInsertPoint(d->funcExit);
|
||||||
|
|
||||||
|
if (isNotVoid) {
|
||||||
|
d->builder.CreateRet(d->builder.CreateLoad(d->funcRetval));
|
||||||
|
} else {
|
||||||
|
d->builder.CreateRetVoid();
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyFunction(*func);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +626,6 @@ bool BitcodeEmitter::emit(Program const& program) {
|
||||||
|
|
||||||
if (program.getMain()) {
|
if (program.getMain()) {
|
||||||
GUARDED(program.getMain()->emit(this));
|
GUARDED(program.getMain()->emit(this));
|
||||||
d->builder.CreateRetVoid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
Reference in New Issue
Block a user