diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-27 13:27:14 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-27 13:27:14 +0000 |
| commit | 0dd0b0908300eee08a06ee51d9eb48b85fd97d74 (patch) | |
| tree | 8e18df810a1d88f686f2b85ed2f05e3aa0985119 /lib/CodeGen | |
| parent | 790e0fd7c5a81b9a27a6d84e0f3f4c7a0b17d04b (diff) | |
refactor(memory)!: move allocation functions into memory.cps
Route keyword NEW and DELETE through the same library runtime and retain
allocation tracking, runtime diagnostics and exception behavior.
BREAKING CHANGE: -no-std programs using NEW or DELETE must explicitly import memory.cps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/Builtins.h | 3 | ||||
| -rw-r--r-- | lib/CodeGen/CallGen.cc | 1 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 4 | ||||
| -rw-r--r-- | lib/CodeGen/ConstructorGen.cc | 4 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 36 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 3 | ||||
| -rw-r--r-- | lib/CodeGen/MemoryGen.cc | 30 | ||||
| -rw-r--r-- | lib/CodeGen/MemoryHandler.cc | 159 | ||||
| -rw-r--r-- | lib/CodeGen/StatementGen.cc | 5 |
9 files changed, 36 insertions, 209 deletions
diff --git a/lib/CodeGen/Builtins.h b/lib/CodeGen/Builtins.h index 84ba765..66ac9e4 100644 --- a/lib/CodeGen/Builtins.h +++ b/lib/CodeGen/Builtins.h @@ -15,9 +15,6 @@ struct BuiltinInfo { inline constexpr BuiltinInfo Builtins[] = { {"EOF", 1, "BOOLEAN"}, - {"MALLOC", 1, "C_TYPE(\"void*\")"}, - {"REALLOC", 2, "C_TYPE(\"void*\")"}, - {"FREE", 1, "C_TYPE(\"void*\")"}, {"INT", 1, "INTEGER"}, }; diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc index 30f0d61..f3a6a9d 100644 --- a/lib/CodeGen/CallGen.cc +++ b/lib/CodeGen/CallGen.cc @@ -2,7 +2,6 @@ #include "cps/CodeGen.h" #include "cps/ArrayHandler.h" #include "cps/FileHandler.h" -#include "cps/MemoryHandler.h" #include "cps/ExceptionHandler.h" #include "Builtins.h" #include "TemplateClone.h" diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 64ed7c4..49b470c 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -2,7 +2,6 @@ #include "cps/CodeGen.h" #include "cps/ArrayHandler.h" #include "cps/FileHandler.h" -#include "cps/MemoryHandler.h" #include "cps/ExceptionHandler.h" #include "Builtins.h" #include "TemplateClone.h" @@ -61,9 +60,6 @@ CodeGen::CodeGen() { Files = std::make_unique<FileHandler>(*TheContext, *Builder, *TheModule, *RuntimeChecker, *Exceptions); - Memory = std::make_unique<MemoryHandler>(*TheContext, *Builder, *TheModule, *Types, - *RuntimeChecker, *Exceptions); - // Array parameters are bound into ArrayHandler through this inversion so // FunctionGen never sees the array subsystem. FuncGen->setArrayParamBinder( diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc index f598494..b029385 100644 --- a/lib/CodeGen/ConstructorGen.cc +++ b/lib/CodeGen/ConstructorGen.cc @@ -1,5 +1,4 @@ #include "cps/CodeGen.h" -#include "cps/MemoryHandler.h" #include "cps/ExceptionHandler.h" #include "cps/TypeAST.h" #include <climits> @@ -165,7 +164,8 @@ void CodeGen::emitAssignment(const LValueInfo &Target, ExprAST *Expr, const Symb // a non-null object address (MALLOC(0) deliberately returns null). Size = Builder->CreateSelect(Builder->CreateICmpEQ(Size, ConstantInt::get(Size->getType(), 0)), ConstantInt::get(Size->getType(), 1), Size); - Value *Object = Memory->emitAllocate(Size, New->getLine()); + Value *Object = emitMemoryCall("_memory_impl_malloc", Size, New->getLine()); + if (!Object) return; Builder->CreateStore(Types->getZeroValue(Class->Name), Object); if (!emitConstruct(Class->Name, Object, New->getArgs(), New->getLine())) return; if (Symbol && Symbol->IsReference) { diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc index 18c934d..9f68a82 100644 --- a/lib/CodeGen/ExpressionGen.cc +++ b/lib/CodeGen/ExpressionGen.cc @@ -1,13 +1,10 @@ #include "cps/CodeGen.h" #include "cps/ArrayHandler.h" #include "cps/FileHandler.h" -#include "cps/MemoryHandler.h" #include "cps/Lexer.h" #include "cps/TypeAST.h" #include "cps/Operator.h" #include "Builtins.h" -#include <climits> -#include <cstddef> using namespace llvm; using namespace cps; @@ -300,23 +297,6 @@ Value *CodeGen::emitCall(const std::string &Callee, return nullptr; } } - if (Name == "MALLOC") { - Value *Size = emitAllocationSize(ArgExprs[0].get()); - if (!Size) return nullptr; - return Memory->emitAllocate(Size, Line); - } - if (Name == "REALLOC") { - Value *Address = emitCoercedExpr(ArgExprs[0].get(), resolveType("C_TYPE(\"void*\")")); - if (!Address) return nullptr; - Value *Size = emitAllocationSize(ArgExprs[1].get()); - if (!Size) return nullptr; - return Memory->emitResize(Address, Size, Line); - } - if (Name == "FREE") { - Value *Address = emitCoercedExpr(ArgExprs[0].get(), resolveType("C_TYPE(\"void*\")")); - if (!Address) return nullptr; - return Memory->emitRelease(Address, Line); - } if (Name == "INT") return emitIntBuiltin(ArgExprs[0].get(), Line); if (Name == "EOF") { Value *FileName = emitFileNameOperand(ArgExprs[0].get(), "EOF"); @@ -354,19 +334,3 @@ Value *CodeGen::emitIntBuiltin(ExprAST *Arg, int Line) { RuntimeChecker->emitCheck(OutOfRange, Msg, {RuntimeChecker->lineValue(Line)}); return Builder->CreateFPToSI(V, Type::getInt64Ty(*TheContext), "int_value"); } - -Value *CodeGen::emitAllocationSize(ExprAST *Expr) { - SaveAndRestore<int> Location(DiagnosticLine, Expr->getLine() ? Expr->getLine() : DiagnosticLine); - const TypeInfo *Info = getExprTypeInfo(Expr); - if (isWholeArrayVar(Expr) || !Info || - !(Info->Kind == TypeKind::Integer || - (Info->Kind == TypeKind::CScalar && Info->isIntegral()))) { - reportError("Allocation size must be INTEGER or a C integer"); - return nullptr; - } - Value *Size = emitExpr(Expr); - if (!Size) return nullptr; - auto *SizeTy = Type::getIntNTy(*TheContext, sizeof(std::size_t) * CHAR_BIT); - return Builder->CreateIntCast(Size, SizeTy, - Info->Kind == TypeKind::Integer || Info->CSigned, "allocation_size"); -} diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index 2e927f9..c162b46 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -158,7 +158,8 @@ bool FunctionGen::validatePrototype(PrototypeAST *Proto) { return false; } if (Proto->getOwnerClass().empty()) { - if (!Proto->isExternal() && isReservedRuntimeName(Proto->getName())) { + // OVERLOAD symbols carry a signature and cannot replace libc symbols. + if (!Proto->isExternal() && !Proto->isOverload() && isReservedRuntimeName(Proto->getName())) { reportError("'%s' is a reserved runtime symbol and cannot be a FUNCTION/PROCEDURE name", Proto->getName().c_str()); return false; diff --git a/lib/CodeGen/MemoryGen.cc b/lib/CodeGen/MemoryGen.cc new file mode 100644 index 0000000..453f137 --- /dev/null +++ b/lib/CodeGen/MemoryGen.cc @@ -0,0 +1,30 @@ +#include "cps/CodeGen.h" + +using namespace llvm; +using namespace cps; + +// Keyword NEW/DELETE use the same visible C helpers as memory.cps. Ordinary +// MALLOC/REALLOC/FREE calls are resolved entirely through the library. +Value *CodeGen::emitMemoryCall(const char *Name, Value *Argument, int Line) { + SaveAndRestore<int> Location(DiagnosticLine, Line); + auto Declarations = FuncGen->getOverloads(Name); + if (Declarations.empty()) { + reportError("NEW/DELETE requires memory.cps; include the memory library"); + return nullptr; + } + const FuncSig &Sig = *Declarations.front(); + bool Allocate = sameIdentifier(Name, "_memory_impl_malloc"); + bool Validate = sameIdentifier(Name, "_memory_impl_validate"); + const TypeInfo *Parameter = resolveType(Allocate ? "C_TYPE(\"unsigned long long\")" + : "C_TYPE(\"void*\")"); + const TypeInfo *Result = resolveType(Validate ? "VOID" : "C_TYPE(\"void*\")"); + if (!Sig.IsExternal || Sig.IsVariadic || Sig.Params.size() != 1 || + Sig.Params[0].IsArray || Sig.Params[0].IsByRef || + !Types->sameType(Sig.Params[0].TypeName, Parameter->Name) || + !Types->sameType(Sig.ReturnTypeName, Result->Name)) { + reportError("Invalid memory runtime declaration for %s", Name); + return nullptr; + } + if (Allocate) Argument = Builder->CreateIntCast(Argument, Parameter->LLVMType, false); + return FuncGen->emitCall(Sig, {Argument}); +} diff --git a/lib/CodeGen/MemoryHandler.cc b/lib/CodeGen/MemoryHandler.cc deleted file mode 100644 index 7cb62b3..0000000 --- a/lib/CodeGen/MemoryHandler.cc +++ /dev/null @@ -1,159 +0,0 @@ -#include "cps/MemoryHandler.h" -#include "cps/ExceptionHandler.h" -#include "cps/RuntimeCheck.h" -#include "cps/TypeSystem.h" -#include <climits> -#include <cstddef> - -using namespace llvm; -using namespace cps; - -Function *MemoryHandler::createHelper(const char *Name, ArrayRef<Type *> Args) { - auto *F = Function::Create(FunctionType::get(PointerType::getUnqual(Context), Args, false), - Function::InternalLinkage, Name, Module); - Exceptions.prepareFunction(F); - Builder.SetInsertPoint(BasicBlock::Create(Context, "entry", F)); - return F; -} - -void MemoryHandler::ensureRuntime() { - if (AllocateFn) return; - IRBuilderBase::InsertPointGuard Guard(Builder); - auto *Ptr = PointerType::getUnqual(Context); - auto *I32 = Type::getInt32Ty(Context); - SizeTy = Type::getIntNTy(Context, sizeof(std::size_t) * CHAR_BIT); - NodeTy = StructType::create(Context, {Ptr, Ptr}, "__cps_memory_node"); - Head = new GlobalVariable(Module, Ptr, false, GlobalValue::InternalLinkage, - ConstantPointerNull::get(Ptr), "__cps_memory_head"); - Malloc = Module.getOrInsertFunction("malloc", FunctionType::get(Ptr, {SizeTy}, false)); - Free = Module.getOrInsertFunction("free", FunctionType::get(Type::getVoidTy(Context), {Ptr}, false)); - Realloc = Module.getOrInsertFunction("realloc", FunctionType::get(Ptr, {Ptr, SizeTy}, false)); - AllocationError = Builder.CreateGlobalString("[Fatal] line %d: Memory allocation failed\n", - "err_allocation", 0, &Module); - TrackingError = Builder.CreateGlobalString("[Fatal] line %d: Allocation tracking failed\n", - "err_tracking", 0, &Module); - InvalidAddress = Builder.CreateGlobalString("[Fatal] line %d: Invalid memory address (not an active allocation)\n", - "err_memory_address", 0, &Module); - FindFn = createHelper("__cps_memory_find", {Ptr, I32}); - buildFind(); - AllocateFn = createHelper("__cps_memory_allocate", {SizeTy, I32}); - buildAllocate(); - ReleaseFn = createHelper("__cps_memory_release", {Ptr, I32}); - buildRelease(); - ResizeFn = createHelper("__cps_memory_resize", {Ptr, SizeTy, I32}); - buildResize(); -} - -// Return the address of the list link that owns the matching node. This also -// lets release unlink the head or an interior node through the same operation. -void MemoryHandler::buildFind() { - auto *Ptr = PointerType::getUnqual(Context); - Value *Address = FindFn->getArg(0), *Line = FindFn->getArg(1); - auto *Entry = Builder.GetInsertBlock(); - auto *Loop = BasicBlock::Create(Context, "search", FindFn); - auto *Found = BasicBlock::Create(Context, "found", FindFn); - Builder.CreateBr(Loop); - Builder.SetInsertPoint(Loop); - auto *Link = Builder.CreatePHI(Ptr, 2, "link"); - Link->addIncoming(Head, Entry); - Value *Node = Builder.CreateLoad(Ptr, Link, "node"); - Checker.emitCheck(Builder.CreateIsNull(Node), InvalidAddress, {Line}); - Value *Stored = Builder.CreateLoad(Ptr, Builder.CreateStructGEP(NodeTy, Node, 0)); - Value *NextLink = Builder.CreateStructGEP(NodeTy, Node, 1); - Link->addIncoming(NextLink, Builder.GetInsertBlock()); - Builder.CreateCondBr(Builder.CreateICmpEQ(Stored, Address), Found, Loop); - Builder.SetInsertPoint(Found); - Builder.CreateRet(Link); -} - -void MemoryHandler::buildAllocate() { - auto *Ptr = PointerType::getUnqual(Context); - Value *Size = AllocateFn->getArg(0), *Line = AllocateFn->getArg(1); - auto *Zero = BasicBlock::Create(Context, "zero_size", AllocateFn); - auto *Allocate = BasicBlock::Create(Context, "allocate", AllocateFn); - Builder.CreateCondBr(Builder.CreateICmpEQ(Size, ConstantInt::get(SizeTy, 0)), Zero, Allocate); - Builder.SetInsertPoint(Zero); - Builder.CreateRet(ConstantPointerNull::get(Ptr)); - Builder.SetInsertPoint(Allocate); - Value *NodeSize = Builder.CreateIntCast(Types.getSizeOfConstant(NodeTy), SizeTy, false); - Value *Node = Builder.CreateCall(Malloc, {NodeSize}, "new_node"); - Checker.emitCheck(Builder.CreateIsNull(Node), TrackingError, {Line}); - Value *Address = Builder.CreateCall(Malloc, {Size}, "allocation"); - Value *Failed = Builder.CreateIsNull(Address); - auto *Cleanup = BasicBlock::Create(Context, "cleanup_node", AllocateFn); - auto *Checked = BasicBlock::Create(Context, "check_allocation", AllocateFn); - Builder.CreateCondBr(Failed, Cleanup, Checked); - Builder.SetInsertPoint(Cleanup); - Builder.CreateCall(Free, {Node}); - Builder.CreateBr(Checked); - Builder.SetInsertPoint(Checked); - Checker.emitCheck(Failed, AllocationError, {Line}); - Builder.CreateStore(Address, Builder.CreateStructGEP(NodeTy, Node, 0)); - Builder.CreateStore(Builder.CreateLoad(Ptr, Head), Builder.CreateStructGEP(NodeTy, Node, 1)); - Builder.CreateStore(Node, Head); - Builder.CreateRet(Address); -} - -void MemoryHandler::buildRelease() { - auto *Ptr = PointerType::getUnqual(Context); - Value *Address = ReleaseFn->getArg(0), *Line = ReleaseFn->getArg(1); - auto *Done = BasicBlock::Create(Context, "done", ReleaseFn); - auto *Release = BasicBlock::Create(Context, "release", ReleaseFn); - Builder.CreateCondBr(Builder.CreateIsNull(Address), Done, Release); - Builder.SetInsertPoint(Release); - Value *Link = Exceptions.emitCall(FindFn, {Address, Line}, "link"); - Value *Node = Builder.CreateLoad(Ptr, Link); - Value *Next = Builder.CreateLoad(Ptr, Builder.CreateStructGEP(NodeTy, Node, 1)); - Builder.CreateStore(Next, Link); - Builder.CreateCall(Free, {Address}); - Builder.CreateCall(Free, {Node}); - Builder.CreateBr(Done); - Builder.SetInsertPoint(Done); - Builder.CreateRet(Address); -} - -Value *MemoryHandler::emitAllocate(Value *Size, int Line) { - ensureRuntime(); - return Exceptions.emitCall(AllocateFn, {Size, Checker.lineValue(Line)}, "allocated"); -} - -Value *MemoryHandler::emitRelease(Value *Address, int Line) { - ensureRuntime(); - return Exceptions.emitCall(ReleaseFn, {Address, Checker.lineValue(Line)}, "released"); -} - -void MemoryHandler::buildResize() { - auto *Ptr = PointerType::getUnqual(Context); - Value *Address = ResizeFn->getArg(0), *Size = ResizeFn->getArg(1), *Line = ResizeFn->getArg(2); - auto *Allocate = BasicBlock::Create(Context, "allocate", ResizeFn); - auto *Validate = BasicBlock::Create(Context, "validate", ResizeFn); - auto *Release = BasicBlock::Create(Context, "release", ResizeFn); - auto *Resize = BasicBlock::Create(Context, "resize", ResizeFn); - Builder.CreateCondBr(Builder.CreateIsNull(Address), Allocate, Validate); - Builder.SetInsertPoint(Allocate); - Builder.CreateRet(Exceptions.emitCall(AllocateFn, {Size, Line}, "allocation")); - Builder.SetInsertPoint(Validate); - Value *Link = Exceptions.emitCall(FindFn, {Address, Line}, "link"); - Value *Node = Builder.CreateLoad(Ptr, Link); - Builder.CreateCondBr(Builder.CreateICmpEQ(Size, ConstantInt::get(SizeTy, 0)), Release, Resize); - Builder.SetInsertPoint(Release); - Exceptions.emitCall(ReleaseFn, {Address, Line}); - Builder.CreateRet(ConstantPointerNull::get(Ptr)); - Builder.SetInsertPoint(Resize); - Value *NewAddress = Builder.CreateCall(Realloc, {Address, Size}, "resized"); - // libc preserves the original block on nonzero-size failure. Leave the - // tracking entry untouched until the check has succeeded as well. - Checker.emitCheck(Builder.CreateIsNull(NewAddress), AllocationError, {Line}); - Builder.CreateStore(NewAddress, Builder.CreateStructGEP(NodeTy, Node, 0)); - Builder.CreateRet(NewAddress); -} - -Value *MemoryHandler::emitResize(Value *Address, Value *Size, int Line) { - ensureRuntime(); - return Exceptions.emitCall(ResizeFn, {Address, Size, Checker.lineValue(Line)}, "resized"); -} - -void MemoryHandler::emitValidate(Value *Address, int Line) { - ensureRuntime(); - Exceptions.emitCall(FindFn, {Address, Checker.lineValue(Line)}); -} diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc index c161049..3cacfe9 100644 --- a/lib/CodeGen/StatementGen.cc +++ b/lib/CodeGen/StatementGen.cc @@ -2,7 +2,6 @@ #include "cps/ArrayHandler.h" #include "cps/FileAST.h" #include "cps/FileHandler.h" -#include "cps/MemoryHandler.h" #include "cps/ExceptionHandler.h" #include "cps/TypeAST.h" #include "cps/TemplateAST.h" @@ -54,9 +53,9 @@ void CodeGen::emitStmtImpl(StmtAST *Stmt) { reportError("DELETE requires a class object"); return; } - Memory->emitValidate(Object.Addr, Stmt->getLine()); + if (!emitMemoryCall("_memory_impl_validate", Object.Addr, Stmt->getLine())) return; if (emitDestroy(Object.TypeName, Object.Addr, Stmt->getLine())) - Memory->emitRelease(Object.Addr, Stmt->getLine()); + emitMemoryCall("_memory_impl_free", Object.Addr, Stmt->getLine()); return; } if (auto *Try = dynamic_cast<TryStmtAST*>(Stmt)) { |
