#pragma once #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include #include #include #include namespace cps { class ExceptionHandler; class RuntimeCheck { llvm::Module &TheModule; llvm::LLVMContext &TheContext; llvm::IRBuilder<> &Builder; llvm::FunctionCallee FprintfFunc; llvm::FunctionCallee StderrFunc; // Windows: __acrt_iob_func(2) llvm::GlobalVariable *StderrVar; // elsewhere: the C library's stderr ExceptionHandler &Exceptions; std::function LibraryLookup; llvm::GlobalVariable *UserLine; llvm::Value *DivZeroMsg; llvm::Value *OutOfBoundsMsg; llvm::Value *EnumRangeMsg; llvm::Value *NullDerefMsg; llvm::Value *ArrayArgBoundsMsg; void setupExternalFunctions(); void emitCheck(llvm::Value *Condition, llvm::Value *Msg, int Line); public: RuntimeCheck(llvm::Module &M, llvm::LLVMContext &C, llvm::IRBuilder<> &B, ExceptionHandler &EH); void setLibraryLookup(std::function Lookup) { LibraryLookup = std::move(Lookup); } llvm::Value *lineValue(int Line); void setUserLine(int Line); // Format a runtime diagnostic (printf-style) and write it to stderr. void emitStderr(llvm::Value *Msg, llvm::ArrayRef FmtArgs = {}); void emitDivZeroCheck(llvm::Value *Divisor, int Line); void emitIndexCheck(llvm::Value *Index, llvm::Value *Lower, llvm::Value *Upper, int Line); // Enum +/- INTEGER results must stay inside the enum's value range. void emitEnumRangeCheck(llvm::Value *Ordinal, uint64_t ValueCount, const std::string &TypeName, int Line); // 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 // must equal the declared ones. void emitArrayArgBoundsCheck(llvm::Value *ActualLower, llvm::Value *ActualUpper, int64_t DeclaredLower, int64_t DeclaredUpper, int Line); // Print the diagnostic to stderr, then throw an anonymous exception on failure. // 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 emitCheck(llvm::Value *Condition, llvm::Value *Msg, llvm::ArrayRef FmtArgs); }; }