From 06538905915b15bde6364459929fe89cf0b8de5c Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 13:43:50 +0000 Subject: feat(codegen): arrange EXTERN signatures with clang's C ABI Every EXTERN "C" signature is now arranged by clang's CodeGen (arrangeFreeFunctionCall) for the host triple and applied by one generic lowering routine, replacing the hand-written signext/zeroext rule. clangCodeGen is linked statically into CPSCodeGen. Records still cross only through pointer types, so generated code is unchanged. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/FunctionGen.cc | 50 ++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'lib/CodeGen/FunctionGen.cc') diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index 1cbf19f..2cf6da3 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -274,7 +274,7 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { } // The prototype names the exact C symbol; parameters and the result must be C -// types. Narrow integers carry the C ABI's sign/zero extension attributes. +// types. clang arranges the signature for the host C ABI. bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { if (PrototypeLinks.count(Proto)) return true; const std::string &Name = Proto->getName(); @@ -291,13 +291,6 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { return false; } - auto Extension = [](const TypeInfo *Info) { - if (Info->Kind != TypeKind::CScalar || !Info->LLVMType->isIntegerTy() || - Info->LLVMType->getIntegerBitWidth() >= 32) - return Attribute::None; - return Info->CSigned ? Attribute::SExt : Attribute::ZExt; - }; - // Records cross the C boundary only as C structs, for now through a // pointer type. What names the parameter or return type in diagnostics. auto CheckRecord = [&](const TypeInfo *Info, const std::string &What) { @@ -327,9 +320,7 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { Sig.IsExternal = true; Sig.IsVariadic = Proto->isVariadic(); - std::vector ArgTypes; - AttrBuilder RetAttrs(Context); - std::vector ParamAttrs; + std::vector ArgTypes; for (size_t I = 0; I < Proto->getParams().size(); ++I) { const ParamDecl &P = Proto->getParams()[I]; const TypeInfo *Info = Types.resolve(P.TypeName); @@ -344,15 +335,12 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { I + 1, Name.c_str(), P.TypeName.c_str()); return false; } - ArgTypes.push_back(Info->LLVMType); - AttrBuilder B(Context); - if (Attribute::AttrKind K = Extension(Info); K != Attribute::None) B.addAttribute(K); - ParamAttrs.push_back(AttributeSet::get(Context, B)); + ArgTypes.push_back(Info); ParamSig PS; PS.TypeName = P.TypeName; Sig.Params.push_back(std::move(PS)); } - Type *RetType = Type::getVoidTy(Context); + const TypeInfo *RetType = nullptr; if (!sameIdentifier(Proto->getReturnType(), "VOID")) { const TypeInfo *Info = Types.resolve(Proto->getReturnType()); if (!Info) { @@ -365,8 +353,7 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { Name.c_str(), Proto->getReturnType().c_str()); return false; } - RetType = Info->LLVMType; - if (Attribute::AttrKind K = Extension(Info); K != Attribute::None) RetAttrs.addAttribute(K); + RetType = Info; } // Repeated identical EXTERN declarations, as in C, share one symbol; each @@ -388,6 +375,7 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { reportError("Conflicting EXTERN declarations of %s", Name.c_str()); return false; } + Sig.ExternABI = First.ExternABI; Sig.ExternType = First.ExternType; Sig.ExternAttrs = First.ExternAttrs; PrototypeLinks.emplace(Proto, Name); @@ -401,10 +389,16 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { else reportError("EXTERN %s conflicts with FUNCTION/PROCEDURE %s", Name.c_str(), Name.c_str()); return false; } - Sig.ExternType = FunctionType::get(RetType, ArgTypes, Proto->isVariadic()); - Sig.ExternAttrs = AttributeList::get(Context, AttributeSet(), - AttributeSet::get(Context, RetAttrs), ParamAttrs); - Module.getOrInsertFunction(Name, Sig.ExternType); + std::string Err; + if (!ABI.arrange(RetType, ArgTypes, ArgTypes.size(), Sig.IsVariadic, Sig.ExternABI, Err)) { + reportError("Internal: cannot arrange EXTERN %s: %s", Name.c_str(), Err.c_str()); + return false; + } + Sig.ExternType = getCABIFunctionType(Sig.ExternABI); + Sig.ExternAttrs = getCABIAttributes(Context, Sig.ExternABI); + FunctionCallee Declared = Module.getOrInsertFunction(Name, Sig.ExternType); + if (auto *F = dyn_cast(Declared.getCallee())) + F->setCallingConv(Sig.ExternABI.CallingConv); PrototypeLinks.emplace(Proto, Name); Overloads.push_back(std::move(Sig)); return true; @@ -485,10 +479,18 @@ llvm::Value *FunctionGen::emitCall(const FuncSig &Sig, const std::vector IRArgs = lowerCABIArguments( + Builder, Sig.ExternABI, ArrayRef(Args).take_front(Fixed), SRet); + IRArgs.insert(IRArgs.end(), Args.begin() + Fixed, Args.end()); Value *Call = Sig.ExternType->getReturnType()->isVoidTy() - ? Exceptions.emitCall(Callee, Args) : Exceptions.emitCall(Callee, Args, "calltmp"); + ? Exceptions.emitCall(Callee, IRArgs) : Exceptions.emitCall(Callee, IRArgs, "calltmp"); cast(Call)->setAttributes(Sig.ExternAttrs); - return Call; + cast(Call)->setCallingConv(Sig.ExternABI.CallingConv); + Value *Result = lowerCABIResult(Builder, Sig.ExternABI, Call, SRet); + return Result ? Result : Call; } void FunctionGen::emitReturn(llvm::Value *RetVal) { -- cgit v1.3.1-4-g156e