From a44f1246dbe24fc813a212a5ef3f5811b1d6402a Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sun, 26 Jul 2026 17:42:08 +0000 Subject: feat: whole arrays (and records) as FUNCTION/PROCEDURE parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parameter syntax lands end-to-end: ARRAY OF T (rank 1, bounds travel with the argument) and ARRAY[l:u,...] OF T (any rank, literal bounds as a checked contract). Element type and rank must match exactly. - Flattened ABI: each rank-R array parameter becomes a data pointer plus kBoundArgsPerDim i64 bounds per dimension. The callee rebuilds ArrayMetadata from those bounds (ArrayHandler::bindArrayParameter via a binder callback injected by CodeGen, so FunctionGen stays ignorant of the array subsystem); the checked-indexing pipeline is reused unchanged. - BYVAL (the CIE default) copies the whole buffer at callee entry (malloc+memcpy, never freed — consistent with the string policy) so callee writes stay invisible; BYREF binds the caller's buffer. - Bounded-parameter contract: compile-time comparison when the caller's bounds are constants, else a runtime [Fatal] check (RuntimeCheck::emitArrayArgBoundsCheck). - marshalCallArgs gains the array branch and a call-site line number (CallStmtAST now carries one); whole-array-to-scalar keeps a clear error, FUNCTION RETURNS ARRAY is a dedicated parse error. - Verified: BYREF fill/sort-style mutation, BYVAL copy invisibility, 2-D bounded params, ARRAY OF with field writes through the parameter, bounds-contract mismatches at compile time and run time. Co-Authored-By: Claude Fable 5 --- lib/CodeGen/FunctionGen.cc | 59 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 14 deletions(-) (limited to 'lib/CodeGen/FunctionGen.cc') diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index cbaee75..77a37ec 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -42,6 +42,24 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vectorsetName(P.Name); + if (P.IsArray) { + // Data pointer + kBoundArgsPerDim bounds per dimension; binding + // into the array subsystem is delegated to the injected binder. + std::vector LBs, UBs; + for (int D = 1; D <= P.Rank; ++D) { + Value *LB = &(*AI); + ++AI; + LB->setName(P.Name + kLowerBoundSuffix + std::to_string(D)); + Value *UB = &(*AI); + ++AI; + UB->setName(P.Name + kUpperBoundSuffix + std::to_string(D)); + LBs.push_back(LB); + UBs.push_back(UB); + } + if (BindArrayParam) BindArrayParam(P, ArgVal, LBs, UBs); + continue; + } + if (P.Mode == PassMode::ByRef) { Symbols[P.Name] = {ArgVal, P.TypeName, false}; continue; @@ -86,18 +104,27 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { std::vector ArgTypes; for (const ParamDecl &P : Proto->getParams()) { + ParamSig PS; + PS.TypeName = P.TypeName; + PS.IsByRef = P.Mode == PassMode::ByRef; + PS.IsArray = P.IsArray; + PS.Rank = P.Rank; + PS.DeclaredBounds = P.DeclaredBounds; + if (P.IsArray) { - fprintf(stderr, "Error: Array parameters are not implemented yet (parameter '%s' of %s)\n", - P.Name.c_str(), Proto->getName().c_str()); - HadError = true; - return nullptr; - } - Type *T = getLLVMType(P.TypeName); - if (P.Mode == PassMode::ByRef) { - T = T->getPointerTo(); + getLLVMType(P.TypeName); // diagnose an unknown element type + ArgTypes.push_back(PointerType::getUnqual(Context)); // data pointer + for (unsigned D = 0; D < static_cast(P.Rank) * kBoundArgsPerDim; ++D) { + ArgTypes.push_back(Type::getInt64Ty(Context)); + } + } else { + Type *T = getLLVMType(P.TypeName); + if (PS.IsByRef) { + T = T->getPointerTo(); + } + ArgTypes.push_back(T); } - ArgTypes.push_back(T); - Sig.Params.emplace_back(P.TypeName, P.Mode == PassMode::ByRef); + Sig.Params.push_back(std::move(PS)); } Type *RetType = getLLVMType(Proto->getReturnType()); @@ -117,10 +144,14 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { // wins and the second is rejected by emitFunctionDef. Signatures.emplace(Proto->getName(), std::move(Sig)); - unsigned Idx = 0; - for (auto &Arg : F->args()) { - if (Idx < Proto->getParams().size()) { - Arg.setName(Proto->getParams()[Idx++].Name); + Function::arg_iterator AI = F->arg_begin(); + for (const ParamDecl &P : Proto->getParams()) { + if (AI == F->arg_end()) break; + (AI++)->setName(P.Name); + for (int D = 1; P.IsArray && D <= P.Rank && AI != F->arg_end(); ++D) { + (AI++)->setName(P.Name + kLowerBoundSuffix + std::to_string(D)); + if (AI != F->arg_end()) + (AI++)->setName(P.Name + kUpperBoundSuffix + std::to_string(D)); } } return F; -- cgit v1.3.1-4-g156e