aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CodeGen.cc2
-rw-r--r--lib/CodeGen/ConstructorGen.cc16
-rw-r--r--lib/CodeGen/ExceptionHandler.cc46
-rw-r--r--lib/CodeGen/FunctionGen.cc14
4 files changed, 51 insertions, 27 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 8117434..0107910 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -186,7 +186,7 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
}
if (!Builder->GetInsertBlock()->hasTerminator()) {
- Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0)));
+ Exceptions->recordExit(Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0))));
}
finishStackObjects(F);
diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc
index c0e50ac..e1033c3 100644
--- a/lib/CodeGen/ConstructorGen.cc
+++ b/lib/CodeGen/ConstructorGen.cc
@@ -1,5 +1,6 @@
#include "cps/CodeGen.h"
#include "cps/MemoryHandler.h"
+#include "cps/ExceptionHandler.h"
#include "cps/TypeAST.h"
#include <climits>
#include <cstddef>
@@ -168,19 +169,8 @@ void CodeGen::emitStackObjectCleanup(const StackObject &Object) {
}
void CodeGen::finishStackObjects(Function *F) {
- IRBuilderBase::InsertPointGuard Guard(*Builder);
- std::vector<Instruction *> Exits;
- for (auto &BB : *F)
- if (BB.hasTerminator() && isa<ReturnInst>(BB.getTerminator()))
- Exits.push_back(BB.getTerminator());
- for (auto *Exit : Exits) {
- // Keep the original terminator in a continuation while cleanup builds branches.
- auto *BB = Exit->getParent();
- auto *Continuation = BB->splitBasicBlock(Exit->getIterator(), "after_destruction");
- BB->getTerminator()->eraseFromParent();
- Builder->SetInsertPoint(BB);
+ Exceptions->fillCleanups(F, [this] {
for (auto It = StackObjects.rbegin(); It != StackObjects.rend(); ++It)
emitStackObjectCleanup(*It);
- Builder->CreateBr(Continuation);
- }
+ });
}
diff --git a/lib/CodeGen/ExceptionHandler.cc b/lib/CodeGen/ExceptionHandler.cc
index 21eb011..3f69417 100644
--- a/lib/CodeGen/ExceptionHandler.cc
+++ b/lib/CodeGen/ExceptionHandler.cc
@@ -1,6 +1,7 @@
#include "cps/ExceptionHandler.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/Support/SaveAndRestore.h"
#include <cassert>
using namespace llvm;
@@ -72,15 +73,50 @@ void ExceptionHandler::endCatch() {
if (!Builder.GetInsertBlock()->hasTerminator()) Builder.CreateCall(EndCatch);
}
-void ExceptionHandler::emitReturnCleanup() {
+Instruction *ExceptionHandler::emitReturnCleanup() {
auto &State = States[Builder.GetInsertBlock()->getParent()];
- for (unsigned I = 0; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch);
+ Instruction *First = nullptr;
+ for (unsigned I = 0; I < State.CatchDepth; ++I) {
+ auto *Call = Builder.CreateCall(EndCatch);
+ if (!First) First = Call;
+ }
+ return First;
+}
+
+void ExceptionHandler::enableCleanups(Function *F) {
+ // Enable before emitting any call: a later DECLARE can already be alive
+ // when an earlier call executes again through a loop back edge.
+ States[F].HasCleanups = true;
+}
+
+void ExceptionHandler::recordExit(Instruction *Before, bool Unwinding) {
+ auto *F = Before->getFunction();
+ CleanupPoints[F].push_back({Before, States[F], Unwinding});
+}
+
+void ExceptionHandler::fillCleanups(Function *F, const std::function<void()> &Destroy) {
+ IRBuilderBase::InsertPointGuard Guard(Builder);
+ SaveAndRestore<FunctionState> StateGuard(States[F]);
+ auto &Points = CleanupPoints[F];
+ // Filling a normal exit may add an unwind point for a throwing destructor.
+ for (size_t I = 0; I < Points.size(); ++I) {
+ auto Point = Points[I];
+ States[F] = Point.State;
+ SaveAndRestore<bool> UnwindGuard(FillingUnwind, Point.Unwinding);
+ auto *BB = Point.Before->getParent();
+ auto *Continuation = BB->splitBasicBlock(Point.Before->getIterator(), "after_destruction");
+ BB->getTerminator()->eraseFromParent();
+ Builder.SetInsertPoint(BB);
+ Destroy();
+ Builder.CreateBr(Continuation);
+ }
+ Points.clear();
}
BasicBlock *ExceptionHandler::emitUnwindDestination() {
auto *F = Builder.GetInsertBlock()->getParent();
auto &State = States[F];
- if (State.Handlers.empty() && State.CatchDepth == 0) return nullptr;
+ if (FillingUnwind || (State.Handlers.empty() && State.CatchDepth == 0 && !State.HasCleanups)) return nullptr;
ensureRuntime();
F->setPersonalityFn(cast<Constant>(Personality.getCallee()));
auto Saved = Builder.saveIP();
@@ -91,7 +127,7 @@ BasicBlock *ExceptionHandler::emitUnwindDestination() {
const Handler *Handler = State.Handlers.empty() ? nullptr : &State.Handlers.back();
unsigned TargetDepth = Handler ? Handler->CatchDepth : 0;
if (Handler) LP->addClause(ConstantPointerNull::get(PointerType::getUnqual(Context)));
- if (State.CatchDepth > TargetDepth) LP->setCleanup(true);
+ if (!Handler || State.CatchDepth > TargetDepth) LP->setCleanup(true);
// Finish catches we are leaving before entering the outer handler (or
// resuming propagation through a function with no local handler).
for (unsigned I = TargetDepth; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch);
@@ -99,7 +135,7 @@ BasicBlock *ExceptionHandler::emitUnwindDestination() {
Builder.CreateStore(Builder.CreateExtractValue(LP, 0), Handler->Exception);
Builder.CreateBr(Handler->Target);
} else {
- Builder.CreateResume(LP);
+ recordExit(Builder.CreateResume(LP), true);
}
Builder.restoreIP(Saved);
return Unwind;
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index 9d9f60d..59e9bbe 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -212,6 +212,7 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
BasicBlock *BB = BasicBlock::Create(Context, "entry", TheFunction);
Builder.SetInsertPoint(BB);
+ Exceptions.enableCleanups(TheFunction);
IdentifierMap<SymbolInfo> OldSymbols = Symbols;
Symbols.clear();
@@ -243,9 +244,9 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
if (!Builder.GetInsertBlock()->hasTerminator()) {
if (sameIdentifier(Proto->getReturnType(), "VOID")) {
- Builder.CreateRetVoid();
+ Exceptions.recordExit(Builder.CreateRetVoid());
} else {
- Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType()));
+ Exceptions.recordExit(Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType())));
}
}
@@ -278,10 +279,7 @@ llvm::Value *FunctionGen::emitCall(const std::string &Callee, const std::vector<
}
void FunctionGen::emitReturn(ReturnStmtAST *Ret, llvm::Value *RetVal) {
- Exceptions.emitReturnCleanup();
- if (RetVal) {
- Builder.CreateRet(RetVal);
- } else {
- Builder.CreateRetVoid();
- }
+ Instruction *CatchCleanup = Exceptions.emitReturnCleanup();
+ Instruction *RetInst = RetVal ? Builder.CreateRet(RetVal) : Builder.CreateRetVoid();
+ Exceptions.recordExit(CatchCleanup ? CatchCleanup : RetInst);
}