[llvm] 04785ad - [LLVMABI] Create ABI Utils (#185105)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 30 12:04:55 PDT 2026
Author: Narayan
Date: 2026-03-31T00:34:50+05:30
New Revision: 04785adec34ddf9a6ec47f10da5b2b7fe8c9f9c8
URL: https://github.com/llvm/llvm-project/commit/04785adec34ddf9a6ec47f10da5b2b7fe8c9f9c8
DIFF: https://github.com/llvm/llvm-project/commit/04785adec34ddf9a6ec47f10da5b2b7fe8c9f9c8.diff
LOG: [LLVMABI] Create ABI Utils (#185105)
This PR introduces `ABIFunctionInfo` and surrounding utility helpers,
and is part of the set of breakout PRs to upstream the LLVM ABI lowering
library prototyped in https://github.com/llvm/llvm-project/pull/140112.
`ABIFunctionInfo` is directly analogous to `CGFunctionInfo` from Clang's
existing CodeGen pipeline, and represents an ABI lowered view of the
function signature, decoupled from both the Clang AST and LLVM IR.
`ABIArgInfo` encodes lowering decisions and currently supports
Direct,Extend,Indirect and Ignore which are required for our initial
goal of implementing x86-64 SysV and BPF, but this will change as the
library grows to represent more targets that need them.
This PR is a direct precursor to the implementation of `ABIInfo` in the
library as demonstrated in the PR linked above..
Added:
llvm/include/llvm/ABI/FunctionInfo.h
llvm/lib/ABI/FunctionInfo.cpp
Modified:
llvm/lib/ABI/CMakeLists.txt
Removed:
################################################################################
diff --git a/llvm/include/llvm/ABI/FunctionInfo.h b/llvm/include/llvm/ABI/FunctionInfo.h
new file mode 100644
index 0000000000000..228961ea69747
--- /dev/null
+++ b/llvm/include/llvm/ABI/FunctionInfo.h
@@ -0,0 +1,269 @@
+//===----- FunctionInfo.h - ABI Function Information --------- C++ --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines FunctionInfo and associated types used in representing the
+// ABI-coerced types for function arguments and return values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ABI_FUNCTIONINFO_H
+#define LLVM_ABI_FUNCTIONINFO_H
+
+#include "llvm/ABI/Types.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/TrailingObjects.h"
+#include <optional>
+
+namespace llvm {
+namespace abi {
+
+/// Helper class to encapsulate information about how a specific type should be
+/// passed to or returned from a function.
+class ArgInfo {
+public:
+ enum Kind {
+ /// Pass the argument directly using the normal converted LLVM type, or by
+ /// coercing to another specified type stored in 'CoerceToType'.
+ Direct,
+ /// Valid only for integer argument types. Same as 'direct' but also emit a
+ /// zero/sign extension attribute.
+ Extend,
+ /// Pass the argument indirectly via a hidden pointer with the specified
+ /// alignment and address space.
+ Indirect,
+ /// Ignore the argument (treat as void). Useful for void and empty structs.
+ Ignore,
+ };
+
+private:
+ const Type *CoercionType = nullptr;
+
+ struct DirectAttrInfo {
+ unsigned Offset;
+ MaybeAlign Align;
+ };
+
+ struct IndirectAttrInfo {
+ Align Align;
+ unsigned AddrSpace;
+ };
+
+ union {
+ DirectAttrInfo DirectAttr;
+ IndirectAttrInfo IndirectAttr;
+ };
+
+ Kind TheKind;
+ bool SignExt : 1;
+ bool ZeroExt : 1;
+ bool IndirectByVal : 1;
+ bool IndirectRealign : 1;
+
+ ArgInfo(Kind K = Direct)
+ : TheKind(K), SignExt(false), ZeroExt(false), IndirectByVal(false),
+ IndirectRealign(false) {}
+
+public:
+ /// \param T The type to coerce to. If null, the argument's original type is
+ /// used directly.
+ /// \param Offset Byte offset into the memory representation at which the
+ /// coerced type begins. Used when only part of a larger value
+ /// is passed directly (e.g. the high word of a multi-eightbyte
+ /// return value on x86-64).
+ /// \param Align Override for the argument's alignment. If absent, the
+ /// default alignment for \p T is used.
+ static ArgInfo getDirect(const Type *T = nullptr, unsigned Offset = 0,
+ MaybeAlign Align = std::nullopt) {
+ ArgInfo AI(Direct);
+ AI.CoercionType = T;
+ AI.DirectAttr.Offset = Offset;
+ AI.DirectAttr.Align = Align;
+ return AI;
+ }
+
+ static ArgInfo getExtend(const Type *T) {
+ assert(T && "Type cannot be null");
+ assert(T->isInteger() && "Unexpected type - only integers can be extended");
+
+ ArgInfo AI(Extend);
+ AI.CoercionType = T;
+ AI.DirectAttr.Offset = 0;
+ AI.DirectAttr.Align = std::nullopt;
+
+ const IntegerType *IntTy = cast<IntegerType>(T);
+ if (IntTy->isSigned())
+ AI.setSignExt();
+ else
+ AI.setZeroExt();
+
+ return AI;
+ }
+
+ /// Realign: the caller couldn't guarantee sufficient alignment - the callee
+ /// must copy the argument to a properly aligned temporary before use.
+ static ArgInfo getIndirect(Align Align, bool ByVal, unsigned AddrSpace = 0,
+ bool Realign = false) {
+ ArgInfo AI(Indirect);
+ AI.IndirectAttr.Align = Align;
+ AI.IndirectAttr.AddrSpace = AddrSpace;
+ AI.IndirectByVal = ByVal;
+ AI.IndirectRealign = Realign;
+ return AI;
+ }
+
+ static ArgInfo getIgnore() { return ArgInfo(Ignore); }
+
+ ArgInfo &setSignExt(bool SignExtend = true) {
+ this->SignExt = SignExtend;
+ if (SignExtend)
+ this->ZeroExt = false;
+ return *this;
+ }
+
+ ArgInfo &setZeroExt(bool ZeroExtend = true) {
+ this->ZeroExt = ZeroExtend;
+ if (ZeroExtend)
+ this->SignExt = false;
+ return *this;
+ }
+
+ Kind getKind() const { return TheKind; }
+ bool isDirect() const { return TheKind == Direct; }
+ bool isIndirect() const { return TheKind == Indirect; }
+ bool isIgnore() const { return TheKind == Ignore; }
+ bool isExtend() const { return TheKind == Extend; }
+
+ unsigned getDirectOffset() const {
+ assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ return DirectAttr.Offset;
+ }
+
+ MaybeAlign getDirectAlign() const {
+ assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ return DirectAttr.Align;
+ }
+
+ Align getIndirectAlign() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return IndirectAttr.Align;
+ }
+
+ unsigned getIndirectAddrSpace() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return IndirectAttr.AddrSpace;
+ }
+
+ bool getIndirectByVal() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return IndirectByVal;
+ }
+
+ bool getIndirectRealign() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return IndirectRealign;
+ }
+
+ bool isSignExt() const {
+ assert(isExtend() && "Invalid Kind!");
+ return SignExt;
+ }
+
+ bool isZeroExt() const {
+ assert(isExtend() && "Invalid Kind!");
+ return ZeroExt;
+ }
+
+ bool isNoExt() const {
+ assert(isExtend() && "Invalid Kind!");
+ return !SignExt && !ZeroExt;
+ }
+
+ const Type *getCoerceToType() const {
+ assert((isDirect() || isExtend()) && "Invalid Kind!");
+ return CoercionType;
+ }
+};
+
+struct ArgEntry {
+ const Type *ABIType;
+ ArgInfo Info;
+
+ ArgEntry(const Type *T) : ABIType(T), Info(ArgInfo::getDirect()) {}
+ ArgEntry(const Type *T, ArgInfo A) : ABIType(T), Info(A) {}
+};
+
+class FunctionInfo final : private TrailingObjects<FunctionInfo, ArgEntry> {
+private:
+ const Type *ReturnType;
+ ArgInfo ReturnInfo;
+ unsigned NumArgs;
+ CallingConv::ID CC = CallingConv::C;
+ std::optional<unsigned> NumRequired;
+
+ FunctionInfo(CallingConv::ID CC, const Type *RetTy, unsigned NumArguments,
+ std::optional<unsigned> NumRequired)
+ : ReturnType(RetTy), ReturnInfo(ArgInfo::getDirect()),
+ NumArgs(NumArguments), CC(CC), NumRequired(NumRequired) {}
+
+ friend class TrailingObjects;
+
+public:
+ using const_arg_iterator = const ArgEntry *;
+ using arg_iterator = ArgEntry *;
+
+ void operator delete(void *p) { ::operator delete(p); }
+ const_arg_iterator arg_begin() const { return getTrailingObjects(); }
+ const_arg_iterator arg_end() const { return getTrailingObjects() + NumArgs; }
+ arg_iterator arg_begin() { return getTrailingObjects(); }
+ arg_iterator arg_end() { return getTrailingObjects() + NumArgs; }
+
+ unsigned arg_size() const { return NumArgs; }
+
+ static FunctionInfo *
+ create(CallingConv::ID CC, const Type *ReturnType,
+ ArrayRef<const Type *> ArgTypes,
+ std::optional<unsigned> NumRequired = std::nullopt);
+
+ const Type *getReturnType() const { return ReturnType; }
+ ArgInfo &getReturnInfo() { return ReturnInfo; }
+ const ArgInfo &getReturnInfo() const { return ReturnInfo; }
+
+ CallingConv::ID getCallingConvention() const { return CC; }
+
+ bool isVariadic() const { return NumRequired.has_value(); }
+
+ unsigned getNumRequiredArgs() const {
+ return isVariadic() ? *NumRequired : arg_size();
+ }
+
+ ArrayRef<ArgEntry> arguments() const {
+ return {getTrailingObjects(), NumArgs};
+ }
+
+ MutableArrayRef<ArgEntry> arguments() {
+ return {getTrailingObjects(), NumArgs};
+ }
+
+ ArgEntry &getArgInfo(unsigned Index) {
+ assert(Index < NumArgs && "Invalid argument index");
+ return arguments()[Index];
+ }
+
+ const ArgEntry &getArgInfo(unsigned Index) const {
+ assert(Index < NumArgs && "Invalid argument index");
+ return arguments()[Index];
+ }
+};
+
+} // namespace abi
+} // namespace llvm
+
+#endif // LLVM_ABI_FUNCTIONINFO_H
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
index 985d90c9e8df9..8ece1803b8aa1 100644
--- a/llvm/lib/ABI/CMakeLists.txt
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -1,5 +1,6 @@
add_llvm_component_library(LLVMABI
Types.cpp
+ FunctionInfo.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
diff --git a/llvm/lib/ABI/FunctionInfo.cpp b/llvm/lib/ABI/FunctionInfo.cpp
new file mode 100644
index 0000000000000..f89d90c74ea03
--- /dev/null
+++ b/llvm/lib/ABI/FunctionInfo.cpp
@@ -0,0 +1,31 @@
+//===----- FunctionInfo.cpp - ABI Function Information ----------- C++ ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ABI/FunctionInfo.h"
+#include <optional>
+
+using namespace llvm;
+using namespace llvm::abi;
+
+FunctionInfo *FunctionInfo::create(CallingConv::ID CC, const Type *ReturnType,
+ ArrayRef<const Type *> ArgTypes,
+ std::optional<unsigned> NumRequired) {
+
+ assert(!NumRequired || *NumRequired <= ArgTypes.size());
+
+ void *Buffer = operator new(totalSizeToAlloc<ArgEntry>(ArgTypes.size()));
+
+ FunctionInfo *FI =
+ new (Buffer) FunctionInfo(CC, ReturnType, ArgTypes.size(), NumRequired);
+
+ ArgEntry *Args = FI->getTrailingObjects();
+ for (unsigned I = 0; I < ArgTypes.size(); ++I)
+ new (&Args[I]) ArgEntry(ArgTypes[I]);
+
+ return FI;
+}
More information about the llvm-commits
mailing list