From 31e443264ac621b812ec5a1a5b0f4b67e4cc25e3 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 04:40:15 +0000 Subject: refactor(codegen): move call marshalling and resolution into CallGen.cc Pure move of both marshalCallArgs overloads, emitVariadicArgument and resolveCall out of CodeGen.cc; no behavior change. Co-Authored-By: Claude Sonnet 5.5 --- lib/CodeGen/CodeGen.cc | 259 ------------------------------------------------- 1 file changed, 259 deletions(-) (limited to 'lib/CodeGen/CodeGen.cc') diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 4137761..d81c4ff 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -373,262 +373,3 @@ void CodeGen::compile(const std::vector &Sources) { void CodeGen::print(raw_ostream &Output) { TheModule->print(Output, nullptr); } - -// Collects the arguments for a call to a user FUNCTION/PROCEDURE, dispatching -// on the *declared* signature: BYREF parameters take the variable's alloca, -// BYVAL parameters are evaluated and coerced to the declared parameter type. -bool CodeGen::marshalCallArgs(const FuncSig &Signature, - const std::vector> &ArgExprs, - int Line, - std::vector &Out) { - std::vector Args; - for (const auto &Arg : ArgExprs) Args.push_back(Arg.get()); - return marshalCallArgs(Signature, Args, Line, Out); -} - -bool CodeGen::marshalCallArgs(const FuncSig &Signature, - const std::vector &ArgExprs, - int Line, std::vector &Out) { - SaveAndRestore Location(DiagnosticLine, Line ? Line : DiagnosticLine); - const FuncSig *Sig = &Signature; - const std::string &Callee = Sig->Name; - if (Sig->IsVariadic ? ArgExprs.size() < Sig->Params.size() : ArgExprs.size() != Sig->Params.size()) { - reportError("Incorrect # arguments passed to %s", Callee.c_str()); - return false; - } - - std::vector Transfers; - for (size_t i = 0; i < ArgExprs.size(); ++i) { - if (i >= Sig->Params.size()) { - Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1); - if (!V) return false; - Out.push_back(V); - continue; - } - const ParamSig &P = Sig->Params[i]; - const std::string &TypeName = P.TypeName; - bool IsByRef = P.IsByRef; - ExprAST *ArgExpr = ArgExprs[i]; - - if (P.IsArray) { - if (!Arrays->emitArrayArgument(ArgExpr, P.TypeName, P.Rank, P.DeclaredBounds, - Callee, Line, *this, Out)) { - return false; - } - continue; - } - - // A whole-array argument against a scalar parameter is always a user - // error (and would smash the data pointer if let through). - if (auto *Var = dynamic_cast(ArgExpr)) { - const SymbolInfo *Info = getSymbolInfo(Var->getName()); - if (Info && Info->IsArray) { - reportError("Cannot pass whole array %s to %s; the parameter is not an array (declare it ARRAY OF %s)", - Var->getName().c_str(), Callee.c_str(), TypeName.c_str()); - return false; - } - } - - if (IsByRef) { - auto *Var = dynamic_cast(ArgExpr); - bool InternalBinding = Signature.Prototype && - (sameIdentifier(Signature.Prototype->getName(), "NEW") || - Signature.Prototype->getOperator() == tok_assign); - if (!Var && InternalBinding) { - const TypeInfo *Actual = getExprTypeInfo(ArgExpr); - if (!Actual || !Actual->sameType(resolveType(TypeName))) { - reportError("BYREF argument to %s has an incompatible type", Callee.c_str()); - return false; - } - if (isObjectLValue(ArgExpr)) { - LValueInfo LV; - if (!emitLValue(ArgExpr, LV)) return false; - Out.push_back(LV.Addr); - } else { - Value *Storage = materializeOperatorReceiver(emitExpr(ArgExpr), Actual); - if (!Storage) return false; - Out.push_back(Storage); - } - continue; - } - if (!Var) { - reportError("BYREF argument to %s must be a variable", Callee.c_str()); - return false; - } - const SymbolInfo *Info = getSymbolInfo(Var->getName()); - if (!Info) { - reportError("Unknown variable %s in BYREF call", Var->getName().c_str()); - return false; - } - const TypeInfo *ParameterType = resolveType(TypeName); - if (!(InternalBinding && ParameterType && ParameterType->isString()) && - !requireWritable(*Info, Var->getName())) return false; - // BYREF aliases the storage, so the types must match exactly. - if (!Types->sameType(Info->TypeName, TypeName)) { - reportError("BYREF argument %s to %s must be of type %s (got %s)", - Var->getName().c_str(), Callee.c_str(), - TypeName.c_str(), Info->TypeName.c_str()); - return false; - } - Out.push_back(symbolAddress(*Info)); - } else { - Value *V = emitOwnedValue(ArgExpr, resolveType(TypeName), Transfers); - if (!V) return false; - Out.push_back(V); - } - } - transferObjects(Transfers); - return true; -} - -// C default argument promotions for the variadic part of an EXTERN call; only -// C values are accepted, matching the explicit-cast rule for C/pseudocode. -Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position) { - const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr); - if (!Info || !Info->isC() || Info->isVoid()) { - reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str()); - return nullptr; - } - Value *V = emitExpr(Expr); - if (!V || Info->Kind != TypeKind::CScalar) return V; - if (Info->isReal()) { - const TypeInfo *Double = resolveType("C_DOUBLE"); - return Info->CRank < Double->CRank ? convertNumericValue(V, Info, Double) : V; - } - return convertNumericValue(V, Info, Types->promoteCScalar(Info)); -} - -// Resolve using static source types only; argument evaluation belongs to marshalling. -const FuncSig *CodeGen::resolveCall(const std::string &Name, - const std::vector> &Args, - const std::vector *Explicit) { - auto Overloads = FuncGen->getOverloads(Name); - bool HasTemplates = hasFunctionTemplate(Name); - bool HasExplicit = Explicit && !Explicit->empty(); - if (HasExplicit && !HasTemplates) { - reportError("Explicit template arguments require a function template: %s", Name.c_str()); - return nullptr; - } - if (Overloads.empty() && !HasTemplates) { - reportError("Call to undefined function %s", Name.c_str()); - return nullptr; - } - if (!HasTemplates && Overloads.size() == 1 && !Overloads.front()->IsOverload) return Overloads.front(); - // Visible EXTERN redeclarations are identical by construction. - if (!HasTemplates && Overloads.front()->IsExternal) return Overloads.front(); - struct ArgumentType { const TypeInfo *Type; int Rank; }; - std::vector Actual; - std::string Key; - for (const auto &Arg : Args) { - const ArrayMetadata *Array = nullptr; - if (auto *Var = dynamic_cast(Arg.get())) { - const SymbolInfo *Symbol = getSymbolInfo(Var->getName()); - if (Symbol && Symbol->IsArray) Array = Arrays->getMetadata(Var->getName()); - } - const TypeInfo *Type = Array ? Types->resolve(Array->ElementTypeName) : getExprTypeInfo(Arg.get()); - int Rank = Array ? Array->Rank : 0; - Actual.push_back({Type, Rank}); - if (!Key.empty()) Key += ", "; - if (Rank) Key += "ARRAY" + std::to_string(Rank) + " OF "; - Key += Type ? Type->Name : "?"; - } - const FuncSig *Ordinary = nullptr; - for (const FuncSig *Sig : Overloads) { - if (HasExplicit) break; - if (Sig->Params.size() != Actual.size()) continue; - bool Match = true; - for (size_t I = 0; I < Actual.size(); ++I) { - const ParamSig &P = Sig->Params[I]; - if (Actual[I].Rank != (P.IsArray ? P.Rank : 0) || !Actual[I].Type || - !Actual[I].Type->sameType(Types->resolve(P.TypeName))) { - Match = false; - break; - } - } - if (Match) { - if (Ordinary && HasTemplates) { - reportError("Ambiguous call to %s(%s)", Name.c_str(), Key.c_str()); - return nullptr; - } - Ordinary = Sig; - if (!HasTemplates) return Sig; - } - } - if (Ordinary) return Ordinary; - if (HasTemplates) { - // A matching non-variadic template wins before any variadic candidate. - for (bool Variadic : {false, true}) { - const TemplateDefinition *Selected = nullptr; - detail::TemplateBindings SelectedBindings; - for (const auto &Definition : Templates.at(Name)) { - auto *Function = Definition.Decl->getFunction(); - if (!Function || Definition.Decl->isVariadic() != Variadic || !isVisible(Definition.OwnerUnit)) continue; - const auto &Params = Function->getProto()->getParams(); - const auto &TemplateParams = Definition.Decl->getParams(); - bool HasPackParam = !Params.empty() && Params.back().IsPack; - size_t FixedCount = Params.size() - HasPackParam; - if (HasPackParam ? Actual.size() < FixedCount : Actual.size() != FixedCount) continue; - detail::TemplateBindings Bindings; - for (const auto &Param : TemplateParams) Bindings.emplace(Param.Name, std::vector{}); - SaveAndRestore Speculation(SpeculativeTemplateResolution, true); - bool Match = true; - if (HasExplicit) { - size_t FixedTypes = TemplateParams.size() - Variadic; - if (!Variadic && Explicit->size() > FixedTypes) continue; - for (size_t I = 0; I < Explicit->size(); ++I) { - auto Type = canonicalTemplateArgument((*Explicit)[I]); - if (!Type) { Match = false; break; } - Bindings.at(TemplateParams[std::min(I, FixedTypes)].Name).push_back(*Type); - } - } - if (!Match) continue; - for (size_t I = 0; I < FixedCount; ++I) { - const auto &P = Params[I]; - const TypeInfo *Type = Actual[I].Type; - if (!Type || Type->isVoid() || Actual[I].Rank != (P.IsArray ? P.Rank : 0)) { Match = false; break; } - auto Binding = Bindings.find(P.TypeName); - if (Binding != Bindings.end()) { - if (Binding->second.empty()) Binding->second.push_back(Type->Name); - else if (!Type->sameType(resolveType(Binding->second.front()))) { Match = false; break; } - } - } - if (HasPackParam) { - auto &Pack = Bindings.at(Params.back().TypeName); - // Explicit pack types constrain a prefix; deduction fills the rest. - if (Pack.size() > Actual.size() - FixedCount) Match = false; - for (size_t I = FixedCount; Match && I < Actual.size(); ++I) { - const TypeInfo *Type = Actual[I].Type; - size_t Index = I - FixedCount; - if (!Type || Type->isVoid() || Actual[I].Rank) { Match = false; break; } - if (Index < Pack.size()) { - if (!Type->sameType(resolveType(Pack[Index]))) Match = false; - } else Pack.push_back(Type->Name); - } - } - for (const auto &Param : TemplateParams) - if (!Param.IsPack && Bindings.at(Param.Name).empty()) Match = false; - if (!Match) continue; - // Composite parameter types can use bindings deduced at later positions, - // but do not themselves contribute deductions. - detail::TemplateClone Substitute(Bindings, [&](int, const std::string &) { Match = false; }); - for (size_t I = 0; I < FixedCount; ++I) { - const auto &TypeName = Params[I].TypeName; - auto Binding = Bindings.find(TypeName); - std::string Expected = Binding != Bindings.end() ? Binding->second.front() - : TypeName.find('<') != std::string::npos ? Substitute.type(TypeName) : TypeName; - if (!Match || !Actual[I].Type->sameType(resolveType(Expected))) { Match = false; break; } - } - if (!Match) continue; - if (Selected) { - reportError("Ambiguous call to %s(%s)", Name.c_str(), Key.c_str()); - return nullptr; - } - Selected = &Definition; - SelectedBindings = std::move(Bindings); - } - if (Selected) return instantiateFunction(*Selected, SelectedBindings); - } - } - reportError("No matching overload for %s(%s)", Name.c_str(), Key.c_str()); - return nullptr; -} -- cgit v1.3.1-4-g156e