diff options
Diffstat (limited to 'include/cps')
| -rw-r--r-- | include/cps/AST.h | 12 | ||||
| -rw-r--r-- | include/cps/CodeGen.h | 3 | ||||
| -rw-r--r-- | include/cps/ExceptionHandler.h | 48 | ||||
| -rw-r--r-- | include/cps/FileHandler.h | 7 | ||||
| -rw-r--r-- | include/cps/FunctionGen.h | 6 | ||||
| -rw-r--r-- | include/cps/Lexer.h | 7 | ||||
| -rw-r--r-- | include/cps/Parser.h | 1 | ||||
| -rw-r--r-- | include/cps/RuntimeCheck.h | 28 |
8 files changed, 86 insertions, 26 deletions
diff --git a/include/cps/AST.h b/include/cps/AST.h index d98613d..e3c6bc5 100644 --- a/include/cps/AST.h +++ b/include/cps/AST.h @@ -93,6 +93,18 @@ public: virtual ~StmtAST() = default; }; +class TryStmtAST : public StmtAST { + std::vector<std::unique_ptr<StmtAST>> Body, CatchBody; +public: + TryStmtAST(std::vector<std::unique_ptr<StmtAST>> Body, + std::vector<std::unique_ptr<StmtAST>> CatchBody) + : Body(std::move(Body)), CatchBody(std::move(CatchBody)) {} + const std::vector<std::unique_ptr<StmtAST>> &getBody() const { return Body; } + const std::vector<std::unique_ptr<StmtAST>> &getCatchBody() const { return CatchBody; } +}; + +class ThrowStmtAST : public StmtAST {}; + class DeclareStmtAST : public StmtAST { std::string Name; std::string Type; diff --git a/include/cps/CodeGen.h b/include/cps/CodeGen.h index 2c837fd..acd6cb2 100644 --- a/include/cps/CodeGen.h +++ b/include/cps/CodeGen.h @@ -19,6 +19,7 @@ namespace cps { class ArrayHandler; class FileHandler; +class ExceptionHandler; class CodeGen { std::unique_ptr<llvm::LLVMContext> TheContext; @@ -28,6 +29,7 @@ class CodeGen { std::unique_ptr<TypeSystem> Types; std::unique_ptr<ArrayHandler> Arrays; + std::unique_ptr<ExceptionHandler> Exceptions; std::unique_ptr<RuntimeCheck> RuntimeChecker; std::unique_ptr<FunctionGen> FuncGen; @@ -87,6 +89,7 @@ class CodeGen { void emitOutputValue(llvm::Value *Val, const TypeInfo *TypeInfo, bool AppendNewline = true); void emitIfStmt(IfStmtAST *Stmt); + void emitTryStmt(TryStmtAST *Stmt); void emitWhileStmt(WhileStmtAST *Stmt); void emitRepeatStmt(RepeatStmtAST *Stmt); void emitForStmt(ForStmtAST *Stmt); diff --git a/include/cps/ExceptionHandler.h b/include/cps/ExceptionHandler.h new file mode 100644 index 0000000..5c846ae --- /dev/null +++ b/include/cps/ExceptionHandler.h @@ -0,0 +1,48 @@ +#pragma once +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" +#include <map> +#include <vector> + +namespace cps { + +// C++ ABI exception emission. State is keyed by function because file helper +// bodies and user functions are emitted using the same builder as their caller. +class ExceptionHandler { + struct Handler { + llvm::BasicBlock *Target; + llvm::AllocaInst *Exception; + unsigned CatchDepth; + }; + struct FunctionState { + std::vector<Handler> Handlers; + unsigned CatchDepth = 0; + }; + + llvm::LLVMContext &Context; + llvm::IRBuilder<> &Builder; + llvm::Module &Module; + std::map<llvm::Function *, FunctionState> States; + llvm::FunctionCallee Allocate, Throw, BeginCatch, EndCatch, Personality; + llvm::GlobalVariable *IntTypeInfo = nullptr; + + void ensureRuntime(); + llvm::BasicBlock *emitUnwindDestination(); + +public: + ExceptionHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M) + : Context(C), Builder(B), Module(M) {} + + void prepareFunction(llvm::Function *F); + void pushHandler(llvm::BasicBlock *Target); + llvm::AllocaInst *popHandler(); + void beginCatch(llvm::AllocaInst *Exception); + void endCatch(); + void emitReturnCleanup(); + + llvm::Value *emitCall(llvm::FunctionCallee Callee, llvm::ArrayRef<llvm::Value *> Args, + const llvm::Twine &Name = ""); + void emitThrow(); +}; + +} // namespace cps diff --git a/include/cps/FileHandler.h b/include/cps/FileHandler.h index 3898a57..8b8ddf4 100644 --- a/include/cps/FileHandler.h +++ b/include/cps/FileHandler.h @@ -7,6 +7,7 @@ namespace cps { class RuntimeCheck; +class ExceptionHandler; // Emits the text-file runtime: a fixed-size open-file table plus internal // __cps_file_* helper functions, synthesized once on first use so programs @@ -20,6 +21,7 @@ class FileHandler { llvm::IRBuilder<> &Builder; llvm::Module &Module; RuntimeCheck &Checker; + ExceptionHandler &Exceptions; static constexpr uint64_t TableSize = 16; bool RuntimeEmitted = false; @@ -35,9 +37,6 @@ class FileHandler { llvm::GlobalVariable *FileModes = nullptr; // [TableSize x i8] 0 = free slot, else FileMode llvm::Value *ModeReadStr = nullptr, *ModeWriteStr = nullptr, *ModeAppendStr = nullptr; - llvm::Value *ErrOpenFail = nullptr, *ErrAlreadyOpen = nullptr, *ErrTableFull = nullptr, - *ErrNotOpen = nullptr, *ErrNotRead = nullptr, *ErrNotWrite = nullptr, - *ErrPastEof = nullptr; // synthesized helpers (internal linkage; pseudocode identifiers cannot // start with '_', so these names are un-collidable) @@ -60,7 +59,7 @@ class FileHandler { public: FileHandler(llvm::LLVMContext &Ctx, llvm::IRBuilder<> &B, llvm::Module &M, - RuntimeCheck &RC); + RuntimeCheck &RC, ExceptionHandler &EH); // NameStr/DataStr are already-coerced STRING ptrs; Line is the statement's // source line for runtime diagnostics. All methods null-check and bail; diff --git a/include/cps/FunctionGen.h b/include/cps/FunctionGen.h index d914162..a7cead5 100644 --- a/include/cps/FunctionGen.h +++ b/include/cps/FunctionGen.h @@ -12,6 +12,8 @@ namespace cps { +class ExceptionHandler; + // Array-parameter ABI: each rank-R array parameter is flattened into the // data pointer followed by kBoundArgsPerDim i64 bounds per dimension. inline constexpr unsigned kBoundArgsPerDim = 2; // lower, upper @@ -51,6 +53,7 @@ private: llvm::Module &Module; llvm::IRBuilder<> &Builder; TypeSystem &Types; + ExceptionHandler &Exceptions; std::map<std::string, SymbolInfo> &Symbols; bool &HadError; @@ -65,9 +68,10 @@ public: llvm::Module &M, llvm::IRBuilder<> &B, TypeSystem &TS, + ExceptionHandler &EH, std::map<std::string, SymbolInfo> &Sym, bool &HadErrorFlag) - : Context(C), Module(M), Builder(B), Types(TS), Symbols(Sym), HadError(HadErrorFlag) {} + : Context(C), Module(M), Builder(B), Types(TS), Exceptions(EH), Symbols(Sym), HadError(HadErrorFlag) {} llvm::Type *getLLVMType(const std::string &TypeName); diff --git a/include/cps/Lexer.h b/include/cps/Lexer.h index 3652df0..2876a58 100644 --- a/include/cps/Lexer.h +++ b/include/cps/Lexer.h @@ -88,7 +88,12 @@ enum Token { tok_class = -604, tok_endclass = -605, tok_public = -606, - tok_private = -607 + tok_private = -607, + + tok_try = -700, + tok_catch = -701, + tok_endtry = -702, + tok_throw = -703 }; class Lexer { diff --git a/include/cps/Parser.h b/include/cps/Parser.h index 7344015..49a9791 100644 --- a/include/cps/Parser.h +++ b/include/cps/Parser.h @@ -40,6 +40,7 @@ class Parser { std::optional<std::vector<std::unique_ptr<ExprAST>>> ParseExprList(char CloseDelim, bool AllowEmpty); void syncToStatementStart(); std::unique_ptr<StmtAST> ParseIfStmt(); + std::unique_ptr<StmtAST> ParseTryStmt(); std::unique_ptr<StmtAST> ParseWhileStmt(); std::unique_ptr<StmtAST> ParseRepeatStmt(); std::unique_ptr<StmtAST> ParseForStmt(); diff --git a/include/cps/RuntimeCheck.h b/include/cps/RuntimeCheck.h index 51a07aa..d9a69b6 100644 --- a/include/cps/RuntimeCheck.h +++ b/include/cps/RuntimeCheck.h @@ -7,24 +7,18 @@ namespace cps { +class ExceptionHandler; + class RuntimeCheck { - llvm::Module &TheModule; llvm::LLVMContext &TheContext; llvm::IRBuilder<> &Builder; - - llvm::FunctionCallee PrintfFunc; - llvm::FunctionCallee ExitFunc; - llvm::Value *DivZeroMsg; - llvm::Value *OutOfBoundsMsg; - llvm::Value *EnumRangeMsg; - llvm::Value *NullDerefMsg; - llvm::Value *ArrayArgBoundsMsg; - - void setupExternalFunctions(); - void emitErrorAndExit(llvm::Value *Condition, llvm::Value *Msg, int Line); + ExceptionHandler &Exceptions; public: - RuntimeCheck(llvm::Module &M, llvm::LLVMContext &C, llvm::IRBuilder<> &B); + RuntimeCheck(llvm::LLVMContext &C, llvm::IRBuilder<> &B, ExceptionHandler &EH); + + // Split the block, throwing an anonymous exception when Condition is true. + void emitCheck(llvm::Value *Condition); void emitDivZeroCheck(llvm::Value *Divisor, int Line); void emitIndexCheck(llvm::Value *Index, llvm::Value *Lower, llvm::Value *Upper, int Line); @@ -33,7 +27,7 @@ public: void emitEnumRangeCheck(llvm::Value *Ordinal, uint64_t ValueCount, const std::string &TypeName, int Line); - // Dereferencing an unset (null) pointer dies instead of segfaulting. + // Dereferencing an unset (null) pointer throws instead of segfaulting. void emitNullDerefCheck(llvm::Value *Ptr, int Line); // A bounded array parameter is a contract: the argument's runtime bounds @@ -41,12 +35,6 @@ public: void emitArrayArgBoundsCheck(llvm::Value *ActualLower, llvm::Value *ActualUpper, int64_t DeclaredLower, int64_t DeclaredUpper, int Line); - // Runtime-computed variant: FmtArgs are the printf varargs after Msg - // (e.g. {i32 line, ptr filename}). Needed when the failure site is inside - // a synthesized helper function, where the line number is an argument - // rather than a compile-time constant. - void emitErrorAndExit(llvm::Value *Condition, llvm::Value *Msg, - llvm::ArrayRef<llvm::Value *> FmtArgs); }; } |
