Single ret point in functions, so that a ret is always in the codepath.

This commit is contained in:
Stefano Sanfilippo 2015-03-09 12:33:10 +01:00
parent 3278f12028
commit 0c3702ea34

View File

@ -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;