diff options
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/FileHandler.cc | 33 | ||||
| -rw-r--r-- | lib/CodeGen/RuntimeCheck.cc | 50 |
3 files changed, 67 insertions, 18 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index b86a0ae..7e463db 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -71,7 +71,7 @@ CodeGen::CodeGen() { Types = std::make_unique<TypeSystem>(*TheContext); Exceptions = std::make_unique<ExceptionHandler>(*TheContext, *Builder, *TheModule); - RuntimeChecker = std::make_unique<RuntimeCheck>(*TheContext, *Builder, *Exceptions); + RuntimeChecker = std::make_unique<RuntimeCheck>(*TheModule, *TheContext, *Builder, *Exceptions); Arrays = std::make_unique<ArrayHandler>(*TheContext, *Builder, diff --git a/lib/CodeGen/FileHandler.cc b/lib/CodeGen/FileHandler.cc index f2e7824..ba32771 100644 --- a/lib/CodeGen/FileHandler.cc +++ b/lib/CodeGen/FileHandler.cc @@ -58,6 +58,21 @@ void FileHandler::setupGlobals() { ModeReadStr = Builder.CreateGlobalString("r", "file_mode_r", 0, &Module); ModeWriteStr = Builder.CreateGlobalString("w", "file_mode_w", 0, &Module); ModeAppendStr = Builder.CreateGlobalString("a", "file_mode_a", 0, &Module); + + ErrOpenFail = Builder.CreateGlobalString( + "[Fatal] line %d: Cannot open file '%s'\n", "err_file_open", 0, &Module); + ErrAlreadyOpen = Builder.CreateGlobalString( + "[Fatal] line %d: File '%s' is already open\n", "err_file_already_open", 0, &Module); + ErrTableFull = Builder.CreateGlobalString( + "[Fatal] line %d: Too many open files\n", "err_file_table_full", 0, &Module); + ErrNotOpen = Builder.CreateGlobalString( + "[Fatal] line %d: File '%s' is not open\n", "err_file_not_open", 0, &Module); + ErrNotRead = Builder.CreateGlobalString( + "[Fatal] line %d: File '%s' is not open for READ\n", "err_file_not_read", 0, &Module); + ErrNotWrite = Builder.CreateGlobalString( + "[Fatal] line %d: File '%s' is not open for WRITE\n", "err_file_not_write", 0, &Module); + ErrPastEof = Builder.CreateGlobalString( + "[Fatal] line %d: Read past end of file '%s'\n", "err_file_past_eof", 0, &Module); } void FileHandler::ensureRuntime() { @@ -95,11 +110,11 @@ Value *FileHandler::emitSlotGEP(GlobalVariable *Table, Type *ElemTy, Value *Idx) } // Shared prologue of every helper that operates on an already-open file: -// look the name up, throw on a miss, return the slot index. +// look the name up, report and throw on a miss, return the slot index. Value *FileHandler::emitLookupOrFail(Value *Name, Value *Line) { Value *Idx = Builder.CreateCall(FindFn, {Name}, "slot"); Value *NotOpen = Builder.CreateICmpSLT(Idx, ConstantInt::get(Context, APInt(64, 0)), "not_open"); - Checker.emitCheck(NotOpen); + Checker.emitCheck(NotOpen, ErrNotOpen, {Line, Name}); return Idx; } @@ -171,7 +186,7 @@ void FileHandler::buildOpenFn() { Value *Existing = Builder.CreateCall(FindFn, {Name}, "existing"); Value *AlreadyOpen = Builder.CreateICmpSGE(Existing, ConstantInt::get(Context, APInt(64, 0)), "already_open"); - Checker.emitCheck(AlreadyOpen); + Checker.emitCheck(AlreadyOpen, ErrAlreadyOpen, {Line, Name}); // First-free-slot scan; SlotVar stays -1 when the table is full. AllocaInst *IdxVar = Builder.CreateAlloca(I64, nullptr, "idx"); @@ -208,7 +223,7 @@ void FileHandler::buildOpenFn() { Builder.SetInsertPoint(AfterBB); Value *Slot = Builder.CreateLoad(I64, SlotVar, "free_slot"); Value *NoFree = Builder.CreateICmpSLT(Slot, ConstantInt::get(Context, APInt(64, 0)), "table_full"); - Checker.emitCheck(NoFree); + Checker.emitCheck(NoFree, ErrTableFull, {Line}); // Branch-free fopen-mode selection: 1 -> "r", 2 -> "w", 3 -> "a". Value *IsWrite = Builder.CreateICmpEQ(Mode, ConstantInt::get(I8, uint8_t(FileMode::Write))); @@ -218,7 +233,7 @@ void FileHandler::buildOpenFn() { Value *Handle = Builder.CreateCall(FopenFunc, {Name, ModeStr}, "handle"); Value *OpenFailed = Builder.CreateICmpEQ(Handle, ConstantPointerNull::get(PtrTy), "open_failed"); - Checker.emitCheck(OpenFailed); + Checker.emitCheck(OpenFailed, ErrOpenFail, {Line, Name}); Builder.CreateStore(Name, emitSlotGEP(FileNames, PtrTy, Slot)); Builder.CreateStore(Handle, emitSlotGEP(FileHandles, PtrTy, Slot)); @@ -244,13 +259,13 @@ void FileHandler::buildReadFn() { Value *Idx = emitLookupOrFail(Name, Line); Value *Mode = Builder.CreateLoad(I8, emitSlotGEP(FileModes, I8, Idx), "mode"); Value *NotRead = Builder.CreateICmpNE(Mode, ConstantInt::get(I8, uint8_t(FileMode::Read)), "not_read"); - Checker.emitCheck(NotRead); + Checker.emitCheck(NotRead, ErrNotRead, {Line, Name}); Value *Handle = Builder.CreateLoad(PtrTy, emitSlotGEP(FileHandles, PtrTy, Idx), "handle"); Value *MinusOne = ConstantInt::get(Context, APInt(32, -1, /*isSigned=*/true)); Value *Peek = Builder.CreateCall(FgetcFunc, {Handle}, "peek"); Value *AtEof = Builder.CreateICmpEQ(Peek, MinusOne, "at_eof"); - Checker.emitCheck(AtEof); + Checker.emitCheck(AtEof, ErrPastEof, {Line, Name}); Builder.CreateCall(UngetcFunc, {Peek, Handle}); // Growing buffer: cap doubles, always leaving room for byte + NUL. @@ -348,7 +363,7 @@ void FileHandler::buildWriteFn() { Value *Idx = emitLookupOrFail(Name, Line); Value *Mode = Builder.CreateLoad(I8, emitSlotGEP(FileModes, I8, Idx), "mode"); Value *IsReadMode = Builder.CreateICmpEQ(Mode, ConstantInt::get(I8, uint8_t(FileMode::Read)), "read_only"); - Checker.emitCheck(IsReadMode); + Checker.emitCheck(IsReadMode, ErrNotWrite, {Line, Name}); Value *Handle = Builder.CreateLoad(PtrTy, emitSlotGEP(FileHandles, PtrTy, Idx), "handle"); Builder.CreateCall(FputsFunc, {Data, Handle}); @@ -394,7 +409,7 @@ void FileHandler::buildEofFn() { Value *Idx = emitLookupOrFail(Name, Line); Value *Mode = Builder.CreateLoad(I8, emitSlotGEP(FileModes, I8, Idx), "mode"); Value *NotRead = Builder.CreateICmpNE(Mode, ConstantInt::get(I8, uint8_t(FileMode::Read)), "not_read"); - Checker.emitCheck(NotRead); + Checker.emitCheck(NotRead, ErrNotRead, {Line, Name}); Value *Handle = Builder.CreateLoad(PtrTy, emitSlotGEP(FileHandles, PtrTy, Idx), "handle"); Value *Ch = Builder.CreateCall(FgetcFunc, {Handle}, "c"); diff --git a/lib/CodeGen/RuntimeCheck.cc b/lib/CodeGen/RuntimeCheck.cc index 2954af0..215702e 100644 --- a/lib/CodeGen/RuntimeCheck.cc +++ b/lib/CodeGen/RuntimeCheck.cc @@ -8,16 +8,46 @@ using namespace llvm; using namespace cps; -RuntimeCheck::RuntimeCheck(LLVMContext &C, IRBuilder<> &B, ExceptionHandler &EH) - : TheContext(C), Builder(B), Exceptions(EH) {} +RuntimeCheck::RuntimeCheck(Module &M, LLVMContext &C, IRBuilder<> &B, ExceptionHandler &EH) + : TheModule(M), TheContext(C), Builder(B), Exceptions(EH) { + setupExternalFunctions(); +} + +void RuntimeCheck::setupExternalFunctions() { + std::vector<Type*> PrintfArgs; + PrintfArgs.push_back(PointerType::getUnqual(TheContext)); + FunctionType *PrintfType = FunctionType::get(Type::getInt32Ty(TheContext), PrintfArgs, true); + PrintfFunc = TheModule.getOrInsertFunction("printf", PrintfType); + + DivZeroMsg = Builder.CreateGlobalString("[Fatal] line %d: Division by zero\n", "err_div_zero", 0, &TheModule); + OutOfBoundsMsg = Builder.CreateGlobalString("[Fatal] line %d: Array index out of bounds\n", "err_bounds", 0, &TheModule); + EnumRangeMsg = Builder.CreateGlobalString("[Fatal] line %d: Value out of range for enum %s\n", "err_enum_range", 0, &TheModule); + NullDerefMsg = Builder.CreateGlobalString("[Fatal] line %d: Dereference of an unset pointer\n", "err_null_deref", 0, &TheModule); + ArrayArgBoundsMsg = Builder.CreateGlobalString( + "[Fatal] line %d: Array argument bounds [%lld:%lld] do not match the declared parameter bounds [%lld:%lld]\n", + "err_arr_arg_bounds", 0, &TheModule); +} + +void RuntimeCheck::emitCheck(Value *Condition, Value *Msg, int Line) { + emitCheck(Condition, Msg, {ConstantInt::get(TheContext, APInt(32, Line))}); +} -void RuntimeCheck::emitCheck(Value *Condition) { +void RuntimeCheck::emitCheck(Value *Condition, Value *Msg, ArrayRef<Value *> FmtArgs) { Function *TheFunction = Builder.GetInsertBlock()->getParent(); + BasicBlock *FailBB = BasicBlock::Create(TheContext, "check_fail", TheFunction); BasicBlock *ContBB = BasicBlock::Create(TheContext, "check_cont", TheFunction); + Builder.CreateCondBr(Condition, FailBB, ContBB); + Builder.SetInsertPoint(FailBB); + std::vector<Value*> PrintArgs; + PrintArgs.push_back(Msg); + PrintArgs.insert(PrintArgs.end(), FmtArgs.begin(), FmtArgs.end()); + Builder.CreateCall(PrintfFunc, PrintArgs); + Exceptions.emitThrow(); + Builder.SetInsertPoint(ContBB); } @@ -28,7 +58,7 @@ void RuntimeCheck::emitDivZeroCheck(Value *Divisor, int Line) { } else { IsZero = Builder.CreateICmpEQ(Divisor, ConstantInt::get(Divisor->getType(), 0), "is_zero"); } - emitCheck(IsZero); + emitCheck(IsZero, DivZeroMsg, Line); } void RuntimeCheck::emitIndexCheck(Value *Index, Value *Lower, Value *Upper, int Line) { @@ -36,7 +66,7 @@ void RuntimeCheck::emitIndexCheck(Value *Index, Value *Lower, Value *Upper, int Value *TooHigh = Builder.CreateICmpSGT(Index, Upper, "too_high"); Value *OutOfBounds = Builder.CreateOr(TooLow, TooHigh, "out_of_bounds"); - emitCheck(OutOfBounds); + emitCheck(OutOfBounds, OutOfBoundsMsg, Line); } void RuntimeCheck::emitEnumRangeCheck(Value *Ordinal, uint64_t ValueCount, @@ -48,14 +78,16 @@ void RuntimeCheck::emitEnumRangeCheck(Value *Ordinal, uint64_t ValueCount, Value *TooHigh = Builder.CreateICmpSGE(Ordinal, Hi, "enum_too_high"); Value *OutOfRange = Builder.CreateOr(TooLow, TooHigh, "enum_out_of_range"); - emitCheck(OutOfRange); + Value *NameStr = Builder.CreateGlobalString(TypeName, "enum_name", 0, &TheModule); + emitCheck(OutOfRange, EnumRangeMsg, + {ConstantInt::get(TheContext, APInt(32, Line)), NameStr}); } void RuntimeCheck::emitNullDerefCheck(Value *Ptr, int Line) { Value *IsNull = Builder.CreateICmpEQ(Ptr, ConstantPointerNull::get(PointerType::getUnqual(TheContext)), "ptr_is_null"); - emitCheck(IsNull); + emitCheck(IsNull, NullDerefMsg, Line); } void RuntimeCheck::emitArrayArgBoundsCheck(Value *ActualLower, Value *ActualUpper, @@ -67,5 +99,7 @@ void RuntimeCheck::emitArrayArgBoundsCheck(Value *ActualLower, Value *ActualUppe Value *HiDiff = Builder.CreateICmpNE(ActualUpper, DeclHi, "arg_hi_ne"); Value *Mismatch = Builder.CreateOr(LoDiff, HiDiff, "arg_bounds_ne"); - emitCheck(Mismatch); + emitCheck(Mismatch, ArrayArgBoundsMsg, + {ConstantInt::get(TheContext, APInt(32, Line)), + ActualLower, ActualUpper, DeclLo, DeclHi}); } |
