diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-16 09:44:47 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-16 09:44:47 +0000 |
| commit | 533d95d4b54ff2139468d38a7162e5ca3a40a7f6 (patch) | |
| tree | e79b5ccb1fafca7ccf5e7198309289f3b07a42b1 /lib/CodeGen/ArrayParameters.cc | |
| parent | 2d84c01c1ccbb0a746f103d167ed7f3448b4a349 (diff) | |
refactor(arrays): separate parameter and output emission
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/ArrayParameters.cc')
| -rw-r--r-- | lib/CodeGen/ArrayParameters.cc | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/CodeGen/ArrayParameters.cc b/lib/CodeGen/ArrayParameters.cc new file mode 100644 index 0000000..09017c9 --- /dev/null +++ b/lib/CodeGen/ArrayParameters.cc @@ -0,0 +1,123 @@ +#include "cps/ArrayHandler.h" +#include "cps/CodeGen.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include <cstdio> + +using namespace llvm; +using namespace cps; + +void ArrayHandler::bindArrayParameter(const std::string &Name, + const std::string &ElemTypeName, + Value *DataPtr, + const std::vector<Value*> &LBs, + const std::vector<Value*> &UBs, + bool MakeCopy, + CodeGen &CG) { + const TypeInfo *ElemInfo = Types.resolve(ElemTypeName); + if (!ElemInfo || !ElemInfo->LLVMType || ElemInfo->isVoid()) { + CG.reportError("Unknown array element type %s", ElemTypeName.c_str()); + return; + } + + std::vector<Value*> Multipliers; + Value *TotalElements = nullptr; + computeDimsAndMultipliers(Name, LBs, UBs, Multipliers, TotalElements); + + ArrayMetadata Meta; + Meta.Rank = static_cast<int>(LBs.size()); + Meta.ElementTypeName = ElemInfo->Name; + Meta.ElementType = ElemInfo->LLVMType; + Meta.ElementSizeC = Types.getSizeOfConstant(ElemInfo->LLVMType); + Meta.LowerBounds = LBs; + Meta.UpperBounds = UBs; + Meta.Multipliers = std::move(Multipliers); + ArrayTable[Name] = Meta; + + Value *Ptr = DataPtr; + if (MakeCopy) { + // BYVAL: whole-buffer copy so callee writes stay invisible to the + // caller. The copy is malloc'd and never freed, consistent with the + // project-wide string policy. + Value *TotalBytes = Builder->CreateMul(TotalElements, Meta.ElementSizeC, + Name + "_copy_bytes"); + Value *Copy = Builder->CreateCall(MallocFunc, TotalBytes, Name + "_copy"); + FunctionType *MemcpyType = FunctionType::get( + PointerType::getUnqual(*TheContext), + {PointerType::getUnqual(*TheContext), PointerType::getUnqual(*TheContext), + Type::getInt64Ty(*TheContext)}, + false); + FunctionCallee MemcpyFunc = TheModule->getOrInsertFunction("memcpy", MemcpyType); + Builder->CreateCall(MemcpyFunc, {Copy, DataPtr, TotalBytes}); + Ptr = Copy; + } + + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + AllocaInst *Alloca = CG.CreateEntryBlockAlloca(TheFunction, PointerType::getUnqual(*TheContext), Name); + Builder->CreateStore(Ptr, Alloca); + + CG.registerSymbol(Name, Alloca, ElemInfo->Name, true); +} + +bool ArrayHandler::emitArrayArgument(ExprAST *ArgExpr, + const std::string &ElemTypeName, + int Rank, + const std::vector<std::pair<int64_t, int64_t>> &DeclaredBounds, + const std::string &Callee, + int Line, + CodeGen &CG, + std::vector<Value*> &Out) { + auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr); + const ArrayMetadata *Meta = Var ? getMetadata(Var->getName()) : nullptr; + if (!Meta) { + CG.reportError("Argument to %s must be a whole array variable (ARRAY OF %s)", + Callee.c_str(), ElemTypeName.c_str()); + return false; + } + if (!CG.resolveType(Meta->ElementTypeName)->sameType(CG.resolveType(ElemTypeName))) { + CG.reportError("Array argument %s to %s must have element type %s (got %s)", + Var->getName().c_str(), Callee.c_str(), + ElemTypeName.c_str(), Meta->ElementTypeName.c_str()); + return false; + } + if (Meta->Rank != Rank) { + CG.reportError("Array argument %s to %s must have %d dimension%s (got %d)", + Var->getName().c_str(), Callee.c_str(), + Rank, Rank == 1 ? "" : "s", Meta->Rank); + return false; + } + + // Bounded parameters are a contract: verified at compile time when the + // caller's bounds are constants (the common case), at run time otherwise. + for (size_t D = 0; D < DeclaredBounds.size(); ++D) { + int64_t DeclLo = DeclaredBounds[D].first; + int64_t DeclHi = DeclaredBounds[D].second; + auto *ActLo = dyn_cast<ConstantInt>(Meta->LowerBounds[D]); + auto *ActHi = dyn_cast<ConstantInt>(Meta->UpperBounds[D]); + if (ActLo && ActHi) { + if (ActLo->getSExtValue() != DeclLo || ActHi->getSExtValue() != DeclHi) { + CG.reportError("Array argument %s to %s has bounds [%lld:%lld] but the parameter declares [%lld:%lld]", + Var->getName().c_str(), Callee.c_str(), + static_cast<long long>(ActLo->getSExtValue()), + static_cast<long long>(ActHi->getSExtValue()), + static_cast<long long>(DeclLo), + static_cast<long long>(DeclHi)); + return false; + } + } else { + RuntimeChecker.emitArrayArgBoundsCheck(Meta->LowerBounds[D], Meta->UpperBounds[D], + DeclLo, DeclHi, Line); + } + } + + Value *DataPtr = getArrayBasePointer(Var->getName()); + if (!DataPtr) return false; + Out.push_back(DataPtr); + for (int D = 0; D < Rank; ++D) { + Out.push_back(Meta->LowerBounds[D]); + Out.push_back(Meta->UpperBounds[D]); + } + return true; +} |
