diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-22 13:43:50 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-22 13:43:50 +0000 |
| commit | 06538905915b15bde6364459929fe89cf0b8de5c (patch) | |
| tree | 1ec58f49ee4d990484001c13395aae2a8e5cd328 /lib/CodeGen/FunctionGen.cc | |
| parent | 90bf56f456e22dcd98458eca14e0b152a5efb179 (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/FunctionGen.cc')
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 50 |
1 files changed, 26 insertions, 24 deletions
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<Type *> ArgTypes; - AttrBuilder RetAttrs(Context); - std::vector<AttributeSet> ParamAttrs; + std::vector<const TypeInfo *> 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<Function>(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<llvm::V 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; + Value *SRet = nullptr; + std::vector<Value *> IRArgs = lowerCABIArguments( + Builder, Sig.ExternABI, ArrayRef<Value *>(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<CallBase>(Call)->setAttributes(Sig.ExternAttrs); - return Call; + cast<CallBase>(Call)->setCallingConv(Sig.ExternABI.CallingConv); + Value *Result = lowerCABIResult(Builder, Sig.ExternABI, Call, SRet); + return Result ? Result : Call; } void FunctionGen::emitReturn(llvm::Value *RetVal) { |
