From 5eccd90b47b327917ad0e5858c79ca8fab27cd74 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 13:51:44 +0000 Subject: feat(codegen): pass C-struct records by value as variadic arguments A variadic EXTERN call is now arranged by clang per call, from the fixed parameter count and the promoted argument types. C-struct records pass unchanged in variadic positions, as C11 6.5.2.2p6-7 and 7.16.1.1p2 allow; a record that is not a C struct names the offending field. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/FunctionGen.cc | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'lib/CodeGen/FunctionGen.cc') diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index b79698e..6895945 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -470,21 +470,40 @@ llvm::Value *FunctionGen::emitCall(const std::string &Callee, const std::vector< return Exceptions.emitCall(CalleeF, Args, "calltmp"); } -llvm::Value *FunctionGen::emitCall(const FuncSig &Sig, const std::vector &Args) { +llvm::Value *FunctionGen::emitCall(const FuncSig &Sig, const std::vector &Args, + const std::vector &Variadic) { if (BeforeCall) BeforeCall(Sig); if (!Sig.IsExternal) return emitCall(Sig.LinkName, Args); FunctionCallee Callee(Sig.ExternType, Module.getNamedValue(Sig.LinkName)); - // Variadic arguments arrive promoted and pass as they are. - size_t Fixed = Sig.ExternABI.Fixed; + // A call with variadic arguments is arranged with their promoted types. + const CABISignature *ABISig = &Sig.ExternABI; + CABISignature CallABI; + if (!Variadic.empty()) { + std::vector ArgTypes; + for (const ParamSig &P : Sig.Params) ArgTypes.push_back(Types.resolve(P.TypeName)); + ArgTypes.insert(ArgTypes.end(), Variadic.begin(), Variadic.end()); + const TypeInfo *Ret = sameIdentifier(Sig.ReturnTypeName, "VOID") + ? nullptr : Types.resolve(Sig.ReturnTypeName); + std::string Err; + if (!ABI.arrange(Ret, ArgTypes, Sig.Params.size(), true, CallABI, Err)) { + reportError("Internal: cannot arrange the call to %s: %s", Sig.Name.c_str(), Err.c_str()); + return nullptr; + } + ABISig = &CallABI; + } + if (Args.size() != ABISig->Args.size()) { + reportError("Internal: the call to %s has %zu arguments but %zu are arranged", Sig.Name.c_str(), + Args.size(), ABISig->Args.size()); + return nullptr; + } Value *SRet = nullptr; - std::vector IRArgs = lowerCABIArguments( - Builder, Sig.ExternABI, ArrayRef(Args).take_front(Fixed), SRet); - IRArgs.insert(IRArgs.end(), Args.begin() + Fixed, Args.end()); + std::vector IRArgs = lowerCABIArguments(Builder, *ABISig, Args, SRet); Value *Call = Sig.ExternType->getReturnType()->isVoidTy() ? Exceptions.emitCall(Callee, IRArgs) : Exceptions.emitCall(Callee, IRArgs, "calltmp"); - cast(Call)->setAttributes(Sig.ExternAttrs); - cast(Call)->setCallingConv(Sig.ExternABI.CallingConv); - Value *Result = lowerCABIResult(Builder, Sig.ExternABI, Call, SRet); + cast(Call)->setAttributes(ABISig == &Sig.ExternABI + ? Sig.ExternAttrs : getCABIAttributes(Context, CallABI)); + cast(Call)->setCallingConv(ABISig->CallingConv); + Value *Result = lowerCABIResult(Builder, *ABISig, Call, SRet); return Result ? Result : Call; } -- cgit v1.3.1-4-g156e