aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-22 13:43:50 +0000
committer_ov4 <ov4@ov4.org>2026-10-22 13:43:50 +0000
commit06538905915b15bde6364459929fe89cf0b8de5c (patch)
tree1ec58f49ee4d990484001c13395aae2a8e5cd328 /include
parent90bf56f456e22dcd98458eca14e0b152a5efb179 (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.h76
-rw-r--r--include/cps/FunctionGen.h6
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);