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 /include | |
| 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 'include')
| -rw-r--r-- | include/cps/CABI.h | 76 | ||||
| -rw-r--r-- | include/cps/FunctionGen.h | 6 |
2 files changed, 81 insertions, 1 deletions
diff --git a/include/cps/CABI.h b/include/cps/CABI.h new file mode 100644 index 0000000..ba776e9 --- /dev/null +++ b/include/cps/CABI.h @@ -0,0 +1,76 @@ +#pragma once +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/IRBuilder.h" +#include <cstdint> +#include <memory> +#include <string> +#include <vector> + +namespace cps { + +struct TypeInfo; +class TypeSystem; + +// One EXTERN "C" parameter or result as clang's ABIArgInfo arranges it. Only +// the kinds our targets use exist here; ClangABI reports any other kind as an +// internal error. +struct CABIArg { + enum class Kind { Direct, Extend, Indirect, Ignore }; + Kind K = Kind::Direct; + llvm::Type *ValueType = nullptr; // the pseudocode value; void for VOID + llvm::Type *CoerceType = nullptr; // Direct, Extend: the IR type passed + unsigned Offset = 0; // Direct, Extend: byte offset of the coerced part + bool Flatten = false; // Direct: a struct CoerceType passed element by element + unsigned DirectAlign = 0; // Direct, Extend: stack alignment, if any + llvm::Attribute::AttrKind Extension = llvm::Attribute::None; // Extend: SExt, ZExt or NoExt + bool ByVal = false; // Indirect: byval, otherwise a pointer to a copy + uint64_t Align = 0; // Indirect: alignment of the memory in bytes + bool InReg = false; +}; + +// An arranged EXTERN signature. Args holds the Fixed prototype parameters and, +// for one variadic call, the promoted variadic arguments after them. +struct CABISignature { + CABIArg Ret; + std::vector<CABIArg> Args; + size_t Fixed = 0; + bool Variadic = false; + unsigned CallingConv = 0; +}; + +// Arranges signatures for the host C ABI with clang's CodeGen. The clang +// context is created on the first call; ClangABI.cc is the only file that +// includes clang headers. +class ClangABI { +public: + ClangABI(llvm::LLVMContext &Context, const TypeSystem &Types); + ~ClangABI(); + // Ret is nullptr for VOID; the first Fixed of Args are the prototype's + // parameters. On failure Err holds the reason for an internal error. + bool arrange(const TypeInfo *Ret, const std::vector<const TypeInfo *> &Args, size_t Fixed, + bool Variadic, CABISignature &Sig, std::string &Err); + +private: + struct State; + llvm::LLVMContext &Context; + const TypeSystem &Types; + std::unique_ptr<State> S; +}; + +// Generic lowering of an arranged signature (Lowering.cc), without +// per-architecture code. +// The declared function type, from the fixed parameters. +llvm::FunctionType *getCABIFunctionType(const CABISignature &Sig); +// The call attributes, for every argument in Sig. +llvm::AttributeList getCABIAttributes(llvm::LLVMContext &C, const CABISignature &Sig); +// The IR arguments for one pseudocode value per Sig.Args entry. SRet receives +// the result memory when the result is returned indirectly. +std::vector<llvm::Value *> lowerCABIArguments(llvm::IRBuilder<> &B, const CABISignature &Sig, + llvm::ArrayRef<llvm::Value *> Args, llvm::Value *&SRet); +// The pseudocode result of Call; nullptr for VOID. +llvm::Value *lowerCABIResult(llvm::IRBuilder<> &B, const CABISignature &Sig, llvm::Value *Call, + llvm::Value *SRet); + +} // namespace cps diff --git a/include/cps/FunctionGen.h b/include/cps/FunctionGen.h index 1b4a07a..8b63d67 100644 --- a/include/cps/FunctionGen.h +++ b/include/cps/FunctionGen.h @@ -1,4 +1,5 @@ #pragma once +#include "cps/CABI.h" #include "cps/Identifier.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" @@ -45,9 +46,11 @@ struct FuncSig { std::vector<ParamSig> Params; size_t OwnerUnit = 0; // EXTERN "C": called through its declared C type, which may differ from a - // runtime declaration of the same libc symbol. + // runtime declaration of the same libc symbol. ExternABI is clang's + // arrangement of the fixed parameters; ExternType and ExternAttrs lower it. bool IsExternal = false; bool IsVariadic = false; + CABISignature ExternABI; llvm::FunctionType *ExternType = nullptr; llvm::AttributeList ExternAttrs; }; @@ -83,6 +86,7 @@ private: std::function<void(const FuncSig &)> BeforeCall; ArrayParamBinder BindArrayParam; std::function<void(llvm::Value *, const std::string &, int)> RegisterCopy; + ClangABI ABI{Context, Types}; // clang context created on the first EXTERN void createArgumentAllocas(llvm::Function *F, const std::vector<ParamDecl> &Params, bool IsMethod); llvm::Type *getLLVMType(const std::string &TypeName); |
