[clang] [llvm] [WIP] ABI Lowering Library (PR #140112)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 17 12:19:40 PDT 2025
https://github.com/vortex73 updated https://github.com/llvm/llvm-project/pull/140112
>From 322c1cfb925f3073f3d3b30abe1b2e35ae7745f3 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Thu, 15 May 2025 23:13:50 +0530
Subject: [PATCH 01/11] [LLVM ABI] The Typesystem
---
llvm/include/llvm/ABI/Types.h | 121 ++++++++++++++++++++++++++++++++++
1 file changed, 121 insertions(+)
create mode 100644 llvm/include/llvm/ABI/Types.h
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
new file mode 100644
index 0000000000000..443a6c1eab4e7
--- /dev/null
+++ b/llvm/include/llvm/ABI/Types.h
@@ -0,0 +1,121 @@
+#ifndef LLVM_ABI_TYPES_H
+#define LLVM_ABI_TYPES_H
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+namespace llvm {
+namespace abi {
+
+enum class TypeKind {
+ Void,
+ Integer,
+ Float,
+ Pointer,
+ Array,
+ Vector,
+ Struct,
+ Union,
+ Function
+};
+class Type {
+protected:
+ TypeKind Kind;
+ uint64_t SizeInBits;
+ uint64_t AlignInBits;
+ bool IsExplicitlyAligned;
+
+ Type(TypeKind K, uint64_t Size, uint64_t Align, bool ExplicitAlign = false)
+ : Kind(K), SizeInBits(Size), AlignInBits(Align),
+ IsExplicitlyAligned(ExplicitAlign) {}
+
+public:
+ virtual ~Type() = default;
+
+ TypeKind getKind() const { return Kind; }
+ uint64_t getSizeInBits() const { return SizeInBits; }
+ uint64_t getAlignInBits() const { return AlignInBits; }
+ bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
+
+ void setExplicitAlignment(uint64_t Align) {
+ AlignInBits = Align;
+ IsExplicitlyAligned = true;
+ }
+
+ bool isVoid() const { return Kind == TypeKind::Void; }
+ bool isInteger() const { return Kind == TypeKind::Integer; }
+ bool isFloat() const { return Kind == TypeKind::Float; }
+ bool isPointer() const { return Kind == TypeKind::Pointer; }
+ bool isArray() const { return Kind == TypeKind::Array; }
+ bool isVector() const { return Kind == TypeKind::Vector; }
+ bool isStruct() const { return Kind == TypeKind::Struct; }
+ bool isUnion() const { return Kind == TypeKind::Union; }
+ bool isFunction() const { return Kind == TypeKind::Function; }
+
+ static bool classof(const Type *) { return true; }
+};
+class VoidType : public Type {
+public:
+ VoidType() : Type(TypeKind::Void, 0, 0) {}
+
+ static bool classof(const Type *T) { return T->getKind() == TypeKind::Void; }
+};
+
+class IntegerType : public Type {
+private:
+ bool IsSigned;
+ bool IsAltRepresentation;
+ std::string TypeName;
+
+public:
+ IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed,
+ bool AltRep = false, const std::string &Name = "")
+ : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed),
+ IsAltRepresentation(AltRep), TypeName(Name) {}
+
+ bool isSigned() const { return IsSigned; }
+ bool isAltRepresentation() const { return IsAltRepresentation; }
+ const std::string &getTypeName() const { return TypeName; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Integer;
+ }
+};
+class FloatType : public Type {
+private:
+ std::string TypeName;
+
+public:
+ FloatType(uint64_t BitWidth, uint64_t Align, const std::string &Name)
+ : Type(TypeKind::Float, BitWidth, Align), TypeName(Name) {}
+
+ const std::string &getTypeName() const { return TypeName; }
+
+ static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
+};
+class PointerType : public Type {
+private:
+ std::unique_ptr<Type> PointeeType;
+ bool IsConst;
+ bool IsVolatile;
+
+public:
+ PointerType(std::unique_ptr<Type> Pointee, uint64_t Size, uint64_t Align,
+ bool Const = false, bool Volatile = false)
+ : Type(TypeKind::Pointer, Size, Align), PointeeType(std::move(Pointee)),
+ IsConst(Const), IsVolatile(Volatile) {}
+
+ const Type *getPointeeType() const { return PointeeType.get(); }
+ bool isConst() const { return IsConst; }
+ bool isVolatile() const { return IsVolatile; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Pointer;
+ }
+};
+
+} // namespace abi
+} // namespace llvm
+
+#endif
>From 0858b1f327c7a49c2e2825124a8d5cabbd8654fd Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Fri, 23 May 2025 17:53:53 +0530
Subject: [PATCH 02/11] [LLVMABI] API for Creating types
---
llvm/include/llvm/ABI/Types.h | 244 +++++++++++++++++++++++++++++-----
1 file changed, 213 insertions(+), 31 deletions(-)
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 443a6c1eab4e7..84cb586832dbd 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -1,9 +1,9 @@
#ifndef LLVM_ABI_TYPES_H
#define LLVM_ABI_TYPES_H
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Allocator.h"
#include <cstdint>
-#include <memory>
-#include <string>
namespace llvm {
namespace abi {
@@ -19,6 +19,7 @@ enum class TypeKind {
Union,
Function
};
+
class Type {
protected:
TypeKind Kind;
@@ -31,8 +32,6 @@ class Type {
IsExplicitlyAligned(ExplicitAlign) {}
public:
- virtual ~Type() = default;
-
TypeKind getKind() const { return Kind; }
uint64_t getSizeInBits() const { return SizeInBits; }
uint64_t getAlignInBits() const { return AlignInBits; }
@@ -52,9 +51,8 @@ class Type {
bool isStruct() const { return Kind == TypeKind::Struct; }
bool isUnion() const { return Kind == TypeKind::Union; }
bool isFunction() const { return Kind == TypeKind::Function; }
-
- static bool classof(const Type *) { return true; }
};
+
class VoidType : public Type {
public:
VoidType() : Type(TypeKind::Void, 0, 0) {}
@@ -65,53 +63,237 @@ class VoidType : public Type {
class IntegerType : public Type {
private:
bool IsSigned;
- bool IsAltRepresentation;
- std::string TypeName;
public:
- IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed,
- bool AltRep = false, const std::string &Name = "")
- : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed),
- IsAltRepresentation(AltRep), TypeName(Name) {}
+ IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed)
+ : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed) {}
bool isSigned() const { return IsSigned; }
- bool isAltRepresentation() const { return IsAltRepresentation; }
- const std::string &getTypeName() const { return TypeName; }
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Integer;
}
};
+
class FloatType : public Type {
+public:
+ FloatType(uint64_t BitWidth, uint64_t Align)
+ : Type(TypeKind::Float, BitWidth, Align) {}
+
+ static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
+};
+
+class PointerType : public Type {
+public:
+ PointerType(uint64_t Size, uint64_t Align)
+ : Type(TypeKind::Pointer, Size, Align) {}
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Pointer;
+ }
+};
+
+class ArrayType : public Type {
private:
- std::string TypeName;
+ const Type *ElementType;
+ uint64_t NumElements;
public:
- FloatType(uint64_t BitWidth, uint64_t Align, const std::string &Name)
- : Type(TypeKind::Float, BitWidth, Align), TypeName(Name) {}
+ ArrayType(const Type *ElemType, uint64_t NumElems)
+ : Type(TypeKind::Array, ElemType->getSizeInBits() * NumElems,
+ ElemType->getAlignInBits()),
+ ElementType(ElemType), NumElements(NumElems) {}
- const std::string &getTypeName() const { return TypeName; }
+ const Type *getElementType() const { return ElementType; }
+ uint64_t getNumElements() const { return NumElements; }
- static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
+ static bool classof(const Type *T) { return T->getKind() == TypeKind::Array; }
};
-class PointerType : public Type {
+
+class VectorType : public Type {
private:
- std::unique_ptr<Type> PointeeType;
- bool IsConst;
- bool IsVolatile;
+ const Type *ElementType;
+ uint64_t NumElements;
public:
- PointerType(std::unique_ptr<Type> Pointee, uint64_t Size, uint64_t Align,
- bool Const = false, bool Volatile = false)
- : Type(TypeKind::Pointer, Size, Align), PointeeType(std::move(Pointee)),
- IsConst(Const), IsVolatile(Volatile) {}
+ VectorType(const Type *ElemType, uint64_t NumElems, uint64_t Align)
+ : Type(TypeKind::Vector, ElemType->getSizeInBits() * NumElems, Align),
+ ElementType(ElemType), NumElements(NumElems) {}
- const Type *getPointeeType() const { return PointeeType.get(); }
- bool isConst() const { return IsConst; }
- bool isVolatile() const { return IsVolatile; }
+ const Type *getElementType() const { return ElementType; }
+ uint64_t getNumElements() const { return NumElements; }
static bool classof(const Type *T) {
- return T->getKind() == TypeKind::Pointer;
+ return T->getKind() == TypeKind::Vector;
+ }
+};
+
+struct FieldInfo {
+ const Type *FieldType;
+ uint64_t OffsetInBits;
+ bool IsBitField;
+ uint64_t BitFieldWidth;
+
+ FieldInfo(const Type *Type, uint64_t Offset = 0, bool BitField = false,
+ uint64_t BFWidth = 0)
+ : FieldType(Type), OffsetInBits(Offset), IsBitField(BitField),
+ BitFieldWidth(BFWidth) {}
+};
+
+enum class StructPacking { Default, Packed, ExplicitPacking };
+
+class StructType : public Type {
+private:
+ const FieldInfo *Fields;
+ uint32_t NumFields;
+ StructPacking Packing;
+
+public:
+ StructType(const FieldInfo *StructFields, uint32_t FieldCount, uint64_t Size,
+ uint64_t Align, StructPacking Pack = StructPacking::Default)
+ : Type(TypeKind::Struct, Size, Align), Fields(StructFields),
+ NumFields(FieldCount), Packing(Pack) {}
+
+ const FieldInfo *getFields() const { return Fields; }
+ uint32_t getNumFields() const { return NumFields; }
+ StructPacking getPacking() const { return Packing; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Struct;
+ }
+};
+
+class UnionType : public Type {
+private:
+ const FieldInfo *Fields;
+ uint32_t NumFields;
+ StructPacking Packing;
+
+public:
+ UnionType(const FieldInfo *UnionFields, uint32_t FieldCount, uint64_t Size,
+ uint64_t Align, StructPacking Pack = StructPacking::Default)
+ : Type(TypeKind::Union, Size, Align), Fields(UnionFields),
+ NumFields(FieldCount), Packing(Pack) {}
+
+ const FieldInfo *getFields() const { return Fields; }
+ uint32_t getNumFields() const { return NumFields; }
+ StructPacking getPacking() const { return Packing; }
+
+ static bool classof(const Type *T) { return T->getKind() == TypeKind::Union; }
+};
+
+enum class CallConv {
+ C,
+ // TODO: extend for more CallConvs
+};
+
+class FunctionType : public Type {
+private:
+ const Type *ReturnType;
+ const Type *const *ParameterTypes;
+ uint32_t NumParams;
+ bool IsVarArg;
+ CallConv CC;
+
+public:
+ FunctionType(const Type *RetType, const Type *const *ParamTypes,
+ uint32_t ParamCount, bool VarArgs, CallConv CallConv)
+ : Type(TypeKind::Function, 0, 0), ReturnType(RetType),
+ ParameterTypes(ParamTypes), NumParams(ParamCount), IsVarArg(VarArgs),
+ CC(CallConv) {}
+
+ const Type *getReturnType() const { return ReturnType; }
+ const Type *const *getParameterTypes() const { return ParameterTypes; }
+ uint32_t getNumParameters() const { return NumParams; }
+ const Type *getParameterType(uint32_t Index) const {
+ assert(Index < NumParams && "Parameter index out of bounds");
+ return ParameterTypes[Index];
+ }
+ bool isVarArg() const { return IsVarArg; }
+ CallConv getCallingConv() const { return CC; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Function;
+ }
+};
+
+// API for creating ABI Types
+class TypeBuilder {
+private:
+ BumpPtrAllocator &Allocator;
+
+public:
+ explicit TypeBuilder(BumpPtrAllocator &Alloc) : Allocator(Alloc) {}
+
+ const VoidType *getVoidType() {
+ return new (Allocator.Allocate<VoidType>()) VoidType();
+ }
+
+ const IntegerType *getIntegerType(uint64_t BitWidth, uint64_t Align,
+ bool Signed) {
+ return new (Allocator.Allocate<IntegerType>())
+ IntegerType(BitWidth, Align, Signed);
+ }
+
+ const FloatType *getFloatType(uint64_t BitWidth, uint64_t Align) {
+ return new (Allocator.Allocate<FloatType>()) FloatType(BitWidth, Align);
+ }
+
+ const PointerType *getPointerType(uint64_t Size, uint64_t Align) {
+ return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align);
+ }
+
+ const ArrayType *getArrayType(const Type *ElementType, uint64_t NumElements) {
+ return new (Allocator.Allocate<ArrayType>())
+ ArrayType(ElementType, NumElements);
+ }
+
+ const VectorType *getVectorType(const Type *ElementType, uint64_t NumElements,
+ uint64_t Align) {
+ return new (Allocator.Allocate<VectorType>())
+ VectorType(ElementType, NumElements, Align);
+ }
+
+ const StructType *getStructType(ArrayRef<FieldInfo> Fields, uint64_t Size,
+ uint64_t Align,
+ StructPacking Pack = StructPacking::Default) {
+ FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
+
+ for (size_t I = 0; I < Fields.size(); ++I) {
+ new (&FieldArray[I]) FieldInfo(Fields[I]);
+ }
+
+ return new (Allocator.Allocate<StructType>()) StructType(
+ FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
+ }
+
+ const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, uint64_t Size,
+ uint64_t Align,
+ StructPacking Pack = StructPacking::Default) {
+ FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
+
+ for (size_t I = 0; I < Fields.size(); ++I) {
+ new (&FieldArray[I]) FieldInfo(Fields[I]);
+ }
+
+ return new (Allocator.Allocate<UnionType>()) UnionType(
+ FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
+ }
+
+ const FunctionType *getFunctionType(const Type *ReturnType,
+ ArrayRef<const Type *> ParamTypes,
+ bool IsVarArg,
+ CallConv CC = CallConv::C) {
+ const Type **ParamArray =
+ Allocator.Allocate<const Type *>(ParamTypes.size());
+
+ for (size_t I = 0; I < ParamTypes.size(); ++I) {
+ ParamArray[I] = ParamTypes[I];
+ }
+
+ return new (Allocator.Allocate<FunctionType>())
+ FunctionType(ReturnType, ParamArray,
+ static_cast<uint32_t>(ParamTypes.size()), IsVarArg, CC);
}
};
>From 114cab7c06c080bf9661c31f405b39b2a8575d6d Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Tue, 27 May 2025 03:07:20 +0530
Subject: [PATCH 03/11] [LLVMABI] Mapper Interface
---
llvm/include/llvm/ABI/QualTypeMapper.h | 52 +++++++++++
llvm/include/llvm/ABI/Types.h | 117 ++++++++-----------------
llvm/lib/ABI/CMakeLists.txt | 17 ++++
llvm/lib/ABI/QualTypeMapper.cpp | 16 ++++
llvm/lib/CMakeLists.txt | 1 +
5 files changed, 123 insertions(+), 80 deletions(-)
create mode 100644 llvm/include/llvm/ABI/QualTypeMapper.h
create mode 100644 llvm/lib/ABI/CMakeLists.txt
create mode 100644 llvm/lib/ABI/QualTypeMapper.cpp
diff --git a/llvm/include/llvm/ABI/QualTypeMapper.h b/llvm/include/llvm/ABI/QualTypeMapper.h
new file mode 100644
index 0000000000000..f408325dad007
--- /dev/null
+++ b/llvm/include/llvm/ABI/QualTypeMapper.h
@@ -0,0 +1,52 @@
+#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
+#define LLVM_ABI_QUALTYPE_MAPPER_H
+
+#include "llvm/Support/Allocator.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Type.h>
+#include <llvm/ABI/Types.h>
+#include <llvm/ADT/DenseMap.h>
+
+namespace llvm {
+namespace abi {
+
+class QualTypeMapper {
+private:
+ clang::ASTContext &ASTCtx;
+ TypeBuilder Builder;
+
+ // llvm::DenseMap<clang::QualType , const Type*> TypeCache;
+
+ const Type *convertBuiltinType(const clang::BuiltinType *BT);
+ const Type *convertPointerType(const clang::PointerType *PT);
+ const Type *convertArrayType(const clang::ArrayType *AT);
+ const Type *convertVectorType(const clang::VectorType *VT);
+ const Type *convertRecordType(const clang::RecordType *RT);
+ const Type *convertFunctionType(const clang::FunctionProtoType *FT);
+ const Type *convertEnumType(const clang::EnumType *ET);
+
+ void computeRecordLayout(const clang::RecordDecl *RD,
+ llvm::SmallVectorImpl<FieldInfo> &Fields,
+ uint64_t &TotalSize, uint64_t &Alignment,
+ StructPacking &Packing);
+
+ uint64_t getTypeSize(clang::QualType QT) const;
+ uint64_t getTypeAlign(clang::QualType QT) const;
+ uint64_t getPointerSize() const;
+ uint64_t getPointerAlign() const;
+
+public:
+ explicit QualTypeMapper(clang::ASTContext &Ctx, BumpPtrAllocator &Alloc)
+ : ASTCtx(Ctx), Builder(Alloc) {}
+
+ const Type *convertType(clang::QualType QT);
+
+ // void clearCache() {TypeCache.clear();}
+
+ TypeBuilder getTypeBuilder() { return Builder; }
+};
+
+} // namespace abi
+} // namespace llvm
+
+#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 84cb586832dbd..e99bee35acf77 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -1,9 +1,13 @@
#ifndef LLVM_ABI_TYPES_H
#define LLVM_ABI_TYPES_H
+#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/TypeSize.h"
#include <cstdint>
+#include <llvm/IR/CallingConv.h>
namespace llvm {
namespace abi {
@@ -17,27 +21,26 @@ enum class TypeKind {
Vector,
Struct,
Union,
- Function
};
class Type {
protected:
TypeKind Kind;
- uint64_t SizeInBits;
- uint64_t AlignInBits;
+ TypeSize SizeInBits;
+ Align AlignInBits;
bool IsExplicitlyAligned;
- Type(TypeKind K, uint64_t Size, uint64_t Align, bool ExplicitAlign = false)
+ Type(TypeKind K, TypeSize Size, Align Align, bool ExplicitAlign = false)
: Kind(K), SizeInBits(Size), AlignInBits(Align),
IsExplicitlyAligned(ExplicitAlign) {}
public:
TypeKind getKind() const { return Kind; }
- uint64_t getSizeInBits() const { return SizeInBits; }
- uint64_t getAlignInBits() const { return AlignInBits; }
+ TypeSize getSizeInBits() const { return SizeInBits; }
+ Align getAlignInBits() const { return AlignInBits; }
bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
- void setExplicitAlignment(uint64_t Align) {
+ void setExplicitAlignment(Align Align) {
AlignInBits = Align;
IsExplicitlyAligned = true;
}
@@ -50,12 +53,11 @@ class Type {
bool isVector() const { return Kind == TypeKind::Vector; }
bool isStruct() const { return Kind == TypeKind::Struct; }
bool isUnion() const { return Kind == TypeKind::Union; }
- bool isFunction() const { return Kind == TypeKind::Function; }
};
class VoidType : public Type {
public:
- VoidType() : Type(TypeKind::Void, 0, 0) {}
+ VoidType() : Type(TypeKind::Void, TypeSize::getFixed(0), Align(1)) {}
static bool classof(const Type *T) { return T->getKind() == TypeKind::Void; }
};
@@ -65,8 +67,9 @@ class IntegerType : public Type {
bool IsSigned;
public:
- IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed)
- : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed) {}
+ IntegerType(uint64_t BitWidth, Align Align, bool Signed)
+ : Type(TypeKind::Integer, TypeSize::getFixed(BitWidth), Align),
+ IsSigned(Signed) {}
bool isSigned() const { return IsSigned; }
@@ -76,17 +79,22 @@ class IntegerType : public Type {
};
class FloatType : public Type {
+private:
+ const fltSemantics *Semantics;
+
public:
- FloatType(uint64_t BitWidth, uint64_t Align)
- : Type(TypeKind::Float, BitWidth, Align) {}
+ FloatType(const fltSemantics &FloatSemantics, Align Align)
+ : Type(TypeKind::Float,
+ TypeSize::getFixed(APFloat::getSizeInBits(FloatSemantics)), Align),
+ Semantics(&FloatSemantics) {}
static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
};
class PointerType : public Type {
public:
- PointerType(uint64_t Size, uint64_t Align)
- : Type(TypeKind::Pointer, Size, Align) {}
+ PointerType(uint64_t Size, Align Align)
+ : Type(TypeKind::Pointer, TypeSize::getFixed(Size), Align) {}
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Pointer;
@@ -116,7 +124,7 @@ class VectorType : public Type {
uint64_t NumElements;
public:
- VectorType(const Type *ElemType, uint64_t NumElems, uint64_t Align)
+ VectorType(const Type *ElemType, uint64_t NumElems, Align Align)
: Type(TypeKind::Vector, ElemType->getSizeInBits() * NumElems, Align),
ElementType(ElemType), NumElements(NumElems) {}
@@ -149,8 +157,8 @@ class StructType : public Type {
StructPacking Packing;
public:
- StructType(const FieldInfo *StructFields, uint32_t FieldCount, uint64_t Size,
- uint64_t Align, StructPacking Pack = StructPacking::Default)
+ StructType(const FieldInfo *StructFields, uint32_t FieldCount, TypeSize Size,
+ Align Align, StructPacking Pack = StructPacking::Default)
: Type(TypeKind::Struct, Size, Align), Fields(StructFields),
NumFields(FieldCount), Packing(Pack) {}
@@ -170,8 +178,8 @@ class UnionType : public Type {
StructPacking Packing;
public:
- UnionType(const FieldInfo *UnionFields, uint32_t FieldCount, uint64_t Size,
- uint64_t Align, StructPacking Pack = StructPacking::Default)
+ UnionType(const FieldInfo *UnionFields, uint32_t FieldCount, TypeSize Size,
+ Align Align, StructPacking Pack = StructPacking::Default)
: Type(TypeKind::Union, Size, Align), Fields(UnionFields),
NumFields(FieldCount), Packing(Pack) {}
@@ -182,41 +190,6 @@ class UnionType : public Type {
static bool classof(const Type *T) { return T->getKind() == TypeKind::Union; }
};
-enum class CallConv {
- C,
- // TODO: extend for more CallConvs
-};
-
-class FunctionType : public Type {
-private:
- const Type *ReturnType;
- const Type *const *ParameterTypes;
- uint32_t NumParams;
- bool IsVarArg;
- CallConv CC;
-
-public:
- FunctionType(const Type *RetType, const Type *const *ParamTypes,
- uint32_t ParamCount, bool VarArgs, CallConv CallConv)
- : Type(TypeKind::Function, 0, 0), ReturnType(RetType),
- ParameterTypes(ParamTypes), NumParams(ParamCount), IsVarArg(VarArgs),
- CC(CallConv) {}
-
- const Type *getReturnType() const { return ReturnType; }
- const Type *const *getParameterTypes() const { return ParameterTypes; }
- uint32_t getNumParameters() const { return NumParams; }
- const Type *getParameterType(uint32_t Index) const {
- assert(Index < NumParams && "Parameter index out of bounds");
- return ParameterTypes[Index];
- }
- bool isVarArg() const { return IsVarArg; }
- CallConv getCallingConv() const { return CC; }
-
- static bool classof(const Type *T) {
- return T->getKind() == TypeKind::Function;
- }
-};
-
// API for creating ABI Types
class TypeBuilder {
private:
@@ -229,17 +202,17 @@ class TypeBuilder {
return new (Allocator.Allocate<VoidType>()) VoidType();
}
- const IntegerType *getIntegerType(uint64_t BitWidth, uint64_t Align,
+ const IntegerType *getIntegerType(uint64_t BitWidth, Align Align,
bool Signed) {
return new (Allocator.Allocate<IntegerType>())
IntegerType(BitWidth, Align, Signed);
}
- const FloatType *getFloatType(uint64_t BitWidth, uint64_t Align) {
- return new (Allocator.Allocate<FloatType>()) FloatType(BitWidth, Align);
+ const FloatType *getFloatType(const fltSemantics &Semantics, Align Align) {
+ return new (Allocator.Allocate<FloatType>()) FloatType(Semantics, Align);
}
- const PointerType *getPointerType(uint64_t Size, uint64_t Align) {
+ const PointerType *getPointerType(uint64_t Size, Align Align) {
return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align);
}
@@ -249,13 +222,13 @@ class TypeBuilder {
}
const VectorType *getVectorType(const Type *ElementType, uint64_t NumElements,
- uint64_t Align) {
+ Align Align) {
return new (Allocator.Allocate<VectorType>())
VectorType(ElementType, NumElements, Align);
}
- const StructType *getStructType(ArrayRef<FieldInfo> Fields, uint64_t Size,
- uint64_t Align,
+ const StructType *getStructType(ArrayRef<FieldInfo> Fields, TypeSize Size,
+ Align Align,
StructPacking Pack = StructPacking::Default) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
@@ -267,8 +240,8 @@ class TypeBuilder {
FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
}
- const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, uint64_t Size,
- uint64_t Align,
+ const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, TypeSize Size,
+ Align Align,
StructPacking Pack = StructPacking::Default) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
@@ -279,22 +252,6 @@ class TypeBuilder {
return new (Allocator.Allocate<UnionType>()) UnionType(
FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
}
-
- const FunctionType *getFunctionType(const Type *ReturnType,
- ArrayRef<const Type *> ParamTypes,
- bool IsVarArg,
- CallConv CC = CallConv::C) {
- const Type **ParamArray =
- Allocator.Allocate<const Type *>(ParamTypes.size());
-
- for (size_t I = 0; I < ParamTypes.size(); ++I) {
- ParamArray[I] = ParamTypes[I];
- }
-
- return new (Allocator.Allocate<FunctionType>())
- FunctionType(ReturnType, ParamArray,
- static_cast<uint32_t>(ParamTypes.size()), IsVarArg, CC);
- }
};
} // namespace abi
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
new file mode 100644
index 0000000000000..d6aa9b542cc05
--- /dev/null
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_llvm_component_library(LLVMABI
+ QualTypeMapper.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
+
+ DEPENDS
+ intrinsics_gen
+
+ LINK_COMPONENTS
+ Core
+ Support
+)
+
+target_include_directories(LLVMABI PRIVATE
+ ${LLVM_MAIN_INCLUDE_DIR}
+)
diff --git a/llvm/lib/ABI/QualTypeMapper.cpp b/llvm/lib/ABI/QualTypeMapper.cpp
new file mode 100644
index 0000000000000..fcf3555aaf369
--- /dev/null
+++ b/llvm/lib/ABI/QualTypeMapper.cpp
@@ -0,0 +1,16 @@
+//===-- llvm/ABI/QualTypeMapper.cpp - QualType to ABI Mapping -------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This File contains the logic for converting clang::Qualtype to
+// llvm::abi::Type for ABI Lowering
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ABI/QualTypeMapper.h>
+
+// TODO: Implementation of Qualtype -> abi::Type Mapping
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index f6465612d30c0..b888f6637a925 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -3,6 +3,7 @@ include(LLVM-Build)
# `Demangle', `Support' and `TableGen' libraries are added on the top-level
# CMakeLists.txt
+add_subdirectory(ABI)
add_subdirectory(IR)
add_subdirectory(FuzzMutate)
add_subdirectory(FileCheck)
>From 3a5827125418875f6976b40751b7628d5faf6d4f Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Fri, 30 May 2025 03:00:01 +0530
Subject: [PATCH 04/11] [LLVMABI] QualType Mapper Implementation
---
clang/include/clang/ABI/QualTypeMapper.h | 78 +++++++++
clang/lib/ABI/CMakeLists.txt | 9 +
clang/lib/ABI/QualTypeMapper.cpp | 209 +++++++++++++++++++++++
clang/lib/CMakeLists.txt | 1 +
llvm/include/llvm/ABI/QualTypeMapper.h | 52 ------
llvm/lib/ABI/CMakeLists.txt | 17 --
llvm/lib/ABI/QualTypeMapper.cpp | 16 --
llvm/lib/CMakeLists.txt | 2 +-
8 files changed, 298 insertions(+), 86 deletions(-)
create mode 100644 clang/include/clang/ABI/QualTypeMapper.h
create mode 100644 clang/lib/ABI/CMakeLists.txt
create mode 100644 clang/lib/ABI/QualTypeMapper.cpp
delete mode 100644 llvm/include/llvm/ABI/QualTypeMapper.h
delete mode 100644 llvm/lib/ABI/CMakeLists.txt
delete mode 100644 llvm/lib/ABI/QualTypeMapper.cpp
diff --git a/clang/include/clang/ABI/QualTypeMapper.h b/clang/include/clang/ABI/QualTypeMapper.h
new file mode 100644
index 0000000000000..70ae9e0f83130
--- /dev/null
+++ b/clang/include/clang/ABI/QualTypeMapper.h
@@ -0,0 +1,78 @@
+#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
+#define LLVM_ABI_QUALTYPE_MAPPER_H
+
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/Support/Allocator.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Decl.h>
+#include <clang/AST/Type.h>
+#include <llvm/ABI/Types.h>
+#include <llvm/ADT/DenseMap.h>
+
+// Specialization for QualType
+template <> struct llvm::DenseMapInfo<clang::QualType> {
+ static inline clang::QualType getEmptyKey() {
+ return clang::QualType::getFromOpaquePtr(
+ reinterpret_cast<clang::Type *>(-1));
+ }
+
+ static inline clang::QualType getTombstoneKey() {
+ return clang::QualType::getFromOpaquePtr(
+ reinterpret_cast<clang::Type *>(-2));
+ }
+
+ static unsigned getHashValue(const clang::QualType &Val) {
+ return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
+ ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
+ }
+
+ static bool isEqual(const clang::QualType &LHS, const clang::QualType &RHS) {
+ return LHS == RHS;
+ }
+};
+
+namespace clang {
+namespace mapper {
+
+class QualTypeMapper {
+private:
+ clang::ASTContext &ASTCtx;
+ llvm::abi::TypeBuilder Builder;
+
+ llvm::DenseMap<clang::QualType, const llvm::abi::Type *> TypeCache;
+
+ const llvm::abi::Type *convertBuiltinType(const clang::BuiltinType *BT);
+ const llvm::abi::Type *convertPointerType(const clang::PointerType *PT);
+ const llvm::abi::Type *convertArrayType(const clang::ArrayType *AT);
+ const llvm::abi::Type *convertVectorType(const clang::VectorType *VT);
+ const llvm::abi::Type *convertRecordType(const clang::RecordType *RT);
+ const llvm::abi::Type *convertEnumType(const clang::EnumType *ET);
+
+ const llvm::abi::StructType *convertStructType(const clang::RecordDecl *RD);
+ const llvm::abi::UnionType *convertUnionType(const clang::RecordDecl *RD);
+ const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
+
+ void computeFieldInfo(const clang::RecordDecl *RD,
+ SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
+ const clang::ASTRecordLayout &Layout);
+
+ llvm::TypeSize getTypeSize(clang::QualType QT) const;
+ llvm::Align getTypeAlign(clang::QualType QT) const;
+ uint64_t getPointerSize() const;
+ uint64_t getPointerAlign() const;
+
+public:
+ explicit QualTypeMapper(clang::ASTContext &Ctx, llvm::BumpPtrAllocator &Alloc)
+ : ASTCtx(Ctx), Builder(Alloc) {}
+
+ const llvm::abi::Type *convertType(clang::QualType QT);
+
+ void clearCache() { TypeCache.clear(); }
+
+ llvm::abi::TypeBuilder getTypeBuilder() { return Builder; }
+};
+
+} // namespace mapper
+} // namespace clang
+
+#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
diff --git a/clang/lib/ABI/CMakeLists.txt b/clang/lib/ABI/CMakeLists.txt
new file mode 100644
index 0000000000000..86a8324b5716a
--- /dev/null
+++ b/clang/lib/ABI/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_clang_library(clangABI
+ QualTypeMapper.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ LLVMABI
+ LLVMSupport
+)
diff --git a/clang/lib/ABI/QualTypeMapper.cpp b/clang/lib/ABI/QualTypeMapper.cpp
new file mode 100644
index 0000000000000..22070f250026e
--- /dev/null
+++ b/clang/lib/ABI/QualTypeMapper.cpp
@@ -0,0 +1,209 @@
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+#include <clang/ABI/QualTypeMapper.h>
+
+namespace clang {
+namespace mapper {
+
+const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
+ QT = QT.getCanonicalType().getUnqualifiedType();
+
+ auto It = TypeCache.find(QT);
+ if (It != TypeCache.end())
+ return It->second;
+
+ const llvm::abi::Type *Result = nullptr;
+ if (const auto *BT = dyn_cast<BuiltinType>(QT.getTypePtr())) {
+ Result = convertBuiltinType(BT);
+ } else if (const auto *PT = dyn_cast<PointerType>(QT.getTypePtr())) {
+ Result = convertPointerType(PT);
+ } else if (const auto *AT = dyn_cast<ArrayType>(QT.getTypePtr())) {
+ Result = convertArrayType(AT);
+ } else if (const auto *VT = dyn_cast<VectorType>(QT.getTypePtr())) {
+ Result = convertVectorType(VT);
+ } else if (const auto *RT = dyn_cast<RecordType>(QT.getTypePtr())) {
+ Result = convertRecordType(RT);
+ } else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
+ Result = convertEnumType(ET);
+ } else {
+ // TODO: Write Fallback logic for unsupported types.
+ }
+ TypeCache[QT] = Result;
+ return Result;
+}
+
+const llvm::abi::Type *
+QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ return Builder.getVoidType();
+
+ case BuiltinType::Bool:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_U:
+ case BuiltinType::UShort:
+ return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+ getTypeAlign(QualType(BT, 0)), false);
+
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ return Builder.getIntegerType(ASTCtx.getCharWidth(),
+ getTypeAlign(QualType(BT, 0)), true);
+
+ case BuiltinType::WChar_U:
+ return Builder.getIntegerType(ASTCtx.getCharWidth(),
+ getTypeAlign(QualType(BT, 0)), false);
+
+ case BuiltinType::WChar_S:
+ return Builder.getIntegerType(ASTCtx.getCharWidth(),
+ getTypeAlign(QualType(BT, 0)), true);
+
+ case BuiltinType::Char8:
+ return Builder.getIntegerType(8, getTypeAlign(QualType(BT, 0)), false);
+
+ case BuiltinType::Char16:
+ return Builder.getIntegerType(16, getTypeAlign(QualType(BT, 0)), false);
+
+ case BuiltinType::Char32:
+ return Builder.getIntegerType(32, getTypeAlign(QualType(BT, 0)), false);
+
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return Builder.getIntegerType(ASTCtx.getIntWidth(QualType(BT, 0)),
+ getTypeAlign(QualType(BT, 0)),
+ BT->getKind() == BuiltinType::Int);
+
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+ getTypeAlign(QualType(BT, 0)),
+ BT->getKind() == BuiltinType::Long);
+
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+ getTypeAlign(QualType(BT, 0)),
+ BT->getKind() == BuiltinType::LongLong);
+
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ return Builder.getIntegerType(128, getTypeAlign(QualType(BT, 0)),
+ BT->getKind() == BuiltinType::Int128);
+
+ case BuiltinType::Half:
+ case BuiltinType::Float16:
+ return Builder.getFloatType(llvm::APFloat::IEEEhalf(),
+ getTypeAlign(QualType(BT, 0)));
+
+ case BuiltinType::Float:
+ return Builder.getFloatType(llvm::APFloat::IEEEsingle(),
+ getTypeAlign(QualType(BT, 0)));
+
+ case BuiltinType::Double:
+ return Builder.getFloatType(llvm::APFloat::IEEEdouble(),
+ getTypeAlign(QualType(BT, 0)));
+
+ case BuiltinType::LongDouble:
+ return Builder.getFloatType(ASTCtx.getFloatTypeSemantics(QualType(BT, 0)),
+ getTypeAlign(QualType(BT, 0)));
+
+ case BuiltinType::BFloat16:
+ return Builder.getFloatType(llvm::APFloat::BFloat(),
+ getTypeAlign(QualType(BT, 0)));
+
+ case BuiltinType::Float128:
+ return Builder.getFloatType(llvm::APFloat::IEEEquad(),
+ getTypeAlign(QualType(BT, 0)));
+
+ default:
+ return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+ getTypeAlign(QualType(BT, 0)), false);
+ }
+}
+
+const llvm::abi::Type *
+QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
+ const llvm::abi::Type *ElementType = convertType(AT->getElementType());
+
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ auto NumElements = CAT->getZExtSize();
+ return Builder.getArrayType(ElementType, NumElements);
+ }
+ if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT))
+ return Builder.getArrayType(ElementType, 0);
+ if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
+ return createPointerTypeForPointee(VAT->getPointeeType());
+ // TODO: This of a better fallback.
+ return Builder.getArrayType(ElementType, 1);
+}
+
+const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
+ const llvm::abi::Type *ElementType = convertType(VT->getElementType());
+ uint64_t NumElements = VT->getNumElements();
+
+ llvm::Align VectorAlign = getTypeAlign(QualType(VT, 0));
+
+ return Builder.getVectorType(ElementType, NumElements, VectorAlign);
+}
+
+const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ if (!RD) {
+ SmallVector<llvm::abi::FieldInfo, 0> Fields;
+ return Builder.getStructType(Fields, llvm::TypeSize::getFixed(0),
+ llvm::Align(1));
+ }
+
+ if (RD->isUnion())
+ return convertUnionType(RD);
+ return convertStructType(RD);
+}
+
+const llvm::abi::Type *
+QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
+ return createPointerTypeForPointee(PT->getPointeeType());
+}
+
+llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const {
+ return llvm::Align(ASTCtx.getTypeAlign(QT));
+}
+
+const llvm::abi::Type *
+QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
+ auto AddrSpace = PointeeType.getAddressSpace();
+ auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
+ llvm::Align Alignment =
+ llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(AddrSpace));
+ return Builder.getPointerType(PointerSize, Alignment);
+}
+
+void QualTypeMapper::computeFieldInfo(
+ const RecordDecl *RD, SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
+ const ASTRecordLayout &Layout) {
+ unsigned FieldIndex = 0;
+
+ for (const auto *FD : RD->fields()) {
+ const llvm::abi::Type *FieldType = convertType(FD->getType());
+ uint64_t OffsetInBits = Layout.getFieldOffset(FieldIndex);
+
+ bool IsBitField = FD->isBitField();
+ uint64_t BitFieldWidth = 0;
+
+ if (IsBitField) {
+ BitFieldWidth = FD->getBitWidthValue();
+ }
+
+ Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth);
+ ++FieldIndex;
+ }
+}
+
+} // namespace mapper
+} // namespace clang
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index 4f2218b583e41..f034622c06c2f 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(ABI)
add_subdirectory(Headers)
add_subdirectory(Basic)
add_subdirectory(APINotes)
diff --git a/llvm/include/llvm/ABI/QualTypeMapper.h b/llvm/include/llvm/ABI/QualTypeMapper.h
deleted file mode 100644
index f408325dad007..0000000000000
--- a/llvm/include/llvm/ABI/QualTypeMapper.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
-#define LLVM_ABI_QUALTYPE_MAPPER_H
-
-#include "llvm/Support/Allocator.h"
-#include <clang/AST/ASTContext.h>
-#include <clang/AST/Type.h>
-#include <llvm/ABI/Types.h>
-#include <llvm/ADT/DenseMap.h>
-
-namespace llvm {
-namespace abi {
-
-class QualTypeMapper {
-private:
- clang::ASTContext &ASTCtx;
- TypeBuilder Builder;
-
- // llvm::DenseMap<clang::QualType , const Type*> TypeCache;
-
- const Type *convertBuiltinType(const clang::BuiltinType *BT);
- const Type *convertPointerType(const clang::PointerType *PT);
- const Type *convertArrayType(const clang::ArrayType *AT);
- const Type *convertVectorType(const clang::VectorType *VT);
- const Type *convertRecordType(const clang::RecordType *RT);
- const Type *convertFunctionType(const clang::FunctionProtoType *FT);
- const Type *convertEnumType(const clang::EnumType *ET);
-
- void computeRecordLayout(const clang::RecordDecl *RD,
- llvm::SmallVectorImpl<FieldInfo> &Fields,
- uint64_t &TotalSize, uint64_t &Alignment,
- StructPacking &Packing);
-
- uint64_t getTypeSize(clang::QualType QT) const;
- uint64_t getTypeAlign(clang::QualType QT) const;
- uint64_t getPointerSize() const;
- uint64_t getPointerAlign() const;
-
-public:
- explicit QualTypeMapper(clang::ASTContext &Ctx, BumpPtrAllocator &Alloc)
- : ASTCtx(Ctx), Builder(Alloc) {}
-
- const Type *convertType(clang::QualType QT);
-
- // void clearCache() {TypeCache.clear();}
-
- TypeBuilder getTypeBuilder() { return Builder; }
-};
-
-} // namespace abi
-} // namespace llvm
-
-#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
deleted file mode 100644
index d6aa9b542cc05..0000000000000
--- a/llvm/lib/ABI/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-add_llvm_component_library(LLVMABI
- QualTypeMapper.cpp
-
- ADDITIONAL_HEADER_DIRS
- ${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
-
- DEPENDS
- intrinsics_gen
-
- LINK_COMPONENTS
- Core
- Support
-)
-
-target_include_directories(LLVMABI PRIVATE
- ${LLVM_MAIN_INCLUDE_DIR}
-)
diff --git a/llvm/lib/ABI/QualTypeMapper.cpp b/llvm/lib/ABI/QualTypeMapper.cpp
deleted file mode 100644
index fcf3555aaf369..0000000000000
--- a/llvm/lib/ABI/QualTypeMapper.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-//===-- llvm/ABI/QualTypeMapper.cpp - QualType to ABI Mapping -------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This File contains the logic for converting clang::Qualtype to
-// llvm::abi::Type for ABI Lowering
-//
-//===----------------------------------------------------------------------===//
-
-#include <llvm/ABI/QualTypeMapper.h>
-
-// TODO: Implementation of Qualtype -> abi::Type Mapping
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index b888f6637a925..c84690abda028 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -3,7 +3,7 @@ include(LLVM-Build)
# `Demangle', `Support' and `TableGen' libraries are added on the top-level
# CMakeLists.txt
-add_subdirectory(ABI)
+# add_subdirectory(ABI)
add_subdirectory(IR)
add_subdirectory(FuzzMutate)
add_subdirectory(FileCheck)
>From 283264277936dfc5f8b86cc30af4fa468910c887 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Sun, 1 Jun 2025 22:05:23 +0530
Subject: [PATCH 05/11] [LLVMABI] Added mappings for record types
---
.../QualtypeMapper.h} | 58 ++++----
clang/lib/ABI/CMakeLists.txt | 9 --
clang/lib/CMakeLists.txt | 1 -
clang/lib/CodeGen/CMakeLists.txt | 1 +
.../QualtypeMapper.cpp} | 128 ++++++++++--------
llvm/include/llvm/ABI/Types.h | 26 +++-
6 files changed, 117 insertions(+), 106 deletions(-)
rename clang/include/clang/{ABI/QualTypeMapper.h => CodeGen/QualtypeMapper.h} (59%)
delete mode 100644 clang/lib/ABI/CMakeLists.txt
rename clang/lib/{ABI/QualTypeMapper.cpp => CodeGen/QualtypeMapper.cpp} (67%)
diff --git a/clang/include/clang/ABI/QualTypeMapper.h b/clang/include/clang/CodeGen/QualtypeMapper.h
similarity index 59%
rename from clang/include/clang/ABI/QualTypeMapper.h
rename to clang/include/clang/CodeGen/QualtypeMapper.h
index 70ae9e0f83130..e99c6847a67b0 100644
--- a/clang/include/clang/ABI/QualTypeMapper.h
+++ b/clang/include/clang/CodeGen/QualtypeMapper.h
@@ -1,35 +1,29 @@
-#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
-#define LLVM_ABI_QUALTYPE_MAPPER_H
-
-#include "llvm/IR/DerivedTypes.h"
+//==---- QualtypeMapper.h - Maps Clang Qualtype to LLVMABI Types -----------==//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Maps Clang QualType instances to corresponding LLVM ABI type
+/// representations. This mapper translates high-level type information from the
+/// AST into low-level ABI-specific types that encode size, alignment, and
+/// layout details required for code generation and cross-language
+/// interoperability.
+///
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_CODEGEN_QUALTYPE_MAPPER_H
+#define CLANG_CODEGEN_QUALTYPE_MAPPER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
-#include <clang/AST/ASTContext.h>
-#include <clang/AST/Decl.h>
-#include <clang/AST/Type.h>
-#include <llvm/ABI/Types.h>
-#include <llvm/ADT/DenseMap.h>
-
-// Specialization for QualType
-template <> struct llvm::DenseMapInfo<clang::QualType> {
- static inline clang::QualType getEmptyKey() {
- return clang::QualType::getFromOpaquePtr(
- reinterpret_cast<clang::Type *>(-1));
- }
-
- static inline clang::QualType getTombstoneKey() {
- return clang::QualType::getFromOpaquePtr(
- reinterpret_cast<clang::Type *>(-2));
- }
-
- static unsigned getHashValue(const clang::QualType &Val) {
- return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
- ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
- }
-
- static bool isEqual(const clang::QualType &LHS, const clang::QualType &RHS) {
- return LHS == RHS;
- }
-};
namespace clang {
namespace mapper {
@@ -75,4 +69,4 @@ class QualTypeMapper {
} // namespace mapper
} // namespace clang
-#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
+#endif // !CLANG_CODEGEN_QUALTYPE_MAPPER_H
diff --git a/clang/lib/ABI/CMakeLists.txt b/clang/lib/ABI/CMakeLists.txt
deleted file mode 100644
index 86a8324b5716a..0000000000000
--- a/clang/lib/ABI/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-add_clang_library(clangABI
- QualTypeMapper.cpp
-
- LINK_LIBS
- clangAST
- clangBasic
- LLVMABI
- LLVMSupport
-)
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index f034622c06c2f..4f2218b583e41 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -1,4 +1,3 @@
-add_subdirectory(ABI)
add_subdirectory(Headers)
add_subdirectory(Basic)
add_subdirectory(APINotes)
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index a05b31f971e18..c70862a05d35d 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -115,6 +115,7 @@ add_clang_library(clangCodeGen
ModuleBuilder.cpp
ObjectFilePCHContainerWriter.cpp
PatternInit.cpp
+ QualtypeMapper.cpp
SanitizerMetadata.cpp
SwiftCallingConv.cpp
TargetBuiltins/ARM.cpp
diff --git a/clang/lib/ABI/QualTypeMapper.cpp b/clang/lib/CodeGen/QualtypeMapper.cpp
similarity index 67%
rename from clang/lib/ABI/QualTypeMapper.cpp
rename to clang/lib/CodeGen/QualtypeMapper.cpp
index 22070f250026e..f1577383af4dc 100644
--- a/clang/lib/ABI/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualtypeMapper.cpp
@@ -1,12 +1,28 @@
+//==---- QualtypeMapper.cpp - Maps Clang Qualtype to LLVMABI Types ---------==//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Maps Clang QualType instances to corresponding LLVM ABI type
+/// representations. This mapper translates high-level type information from the
+/// AST into low-level ABI-specific types that encode size, alignment, and
+/// layout details required for code generation and cross-language
+/// interoperability.
+///
+//===----------------------------------------------------------------------===//
+#include "clang/CodeGen/QualtypeMapper.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
-#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ABI/Types.h"
#include "llvm/Support/Alignment.h"
-#include "llvm/Support/Casting.h"
-#include <clang/ABI/QualTypeMapper.h>
+#include "llvm/Support/TypeSize.h"
namespace clang {
namespace mapper {
@@ -40,87 +56,44 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
const llvm::abi::Type *
QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
+ QualType QT(BT, 0);
+
switch (BT->getKind()) {
case BuiltinType::Void:
return Builder.getVoidType();
case BuiltinType::Bool:
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- case BuiltinType::UShort:
- return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
- getTypeAlign(QualType(BT, 0)), false);
-
case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
case BuiltinType::SChar:
- case BuiltinType::Short:
- return Builder.getIntegerType(ASTCtx.getCharWidth(),
- getTypeAlign(QualType(BT, 0)), true);
-
- case BuiltinType::WChar_U:
- return Builder.getIntegerType(ASTCtx.getCharWidth(),
- getTypeAlign(QualType(BT, 0)), false);
-
+ case BuiltinType::UChar:
case BuiltinType::WChar_S:
- return Builder.getIntegerType(ASTCtx.getCharWidth(),
- getTypeAlign(QualType(BT, 0)), true);
-
+ case BuiltinType::WChar_U:
case BuiltinType::Char8:
- return Builder.getIntegerType(8, getTypeAlign(QualType(BT, 0)), false);
-
case BuiltinType::Char16:
- return Builder.getIntegerType(16, getTypeAlign(QualType(BT, 0)), false);
-
case BuiltinType::Char32:
- return Builder.getIntegerType(32, getTypeAlign(QualType(BT, 0)), false);
-
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
case BuiltinType::Int:
case BuiltinType::UInt:
- return Builder.getIntegerType(ASTCtx.getIntWidth(QualType(BT, 0)),
- getTypeAlign(QualType(BT, 0)),
- BT->getKind() == BuiltinType::Int);
-
case BuiltinType::Long:
case BuiltinType::ULong:
- return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
- getTypeAlign(QualType(BT, 0)),
- BT->getKind() == BuiltinType::Long);
-
case BuiltinType::LongLong:
case BuiltinType::ULongLong:
- return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
- getTypeAlign(QualType(BT, 0)),
- BT->getKind() == BuiltinType::LongLong);
-
case BuiltinType::Int128:
case BuiltinType::UInt128:
- return Builder.getIntegerType(128, getTypeAlign(QualType(BT, 0)),
- BT->getKind() == BuiltinType::Int128);
+ return Builder.getIntegerType(ASTCtx.getTypeSize(QT), getTypeAlign(QT),
+ BT->isSignedInteger());
case BuiltinType::Half:
case BuiltinType::Float16:
- return Builder.getFloatType(llvm::APFloat::IEEEhalf(),
- getTypeAlign(QualType(BT, 0)));
-
+ case BuiltinType::BFloat16:
case BuiltinType::Float:
- return Builder.getFloatType(llvm::APFloat::IEEEsingle(),
- getTypeAlign(QualType(BT, 0)));
-
case BuiltinType::Double:
- return Builder.getFloatType(llvm::APFloat::IEEEdouble(),
- getTypeAlign(QualType(BT, 0)));
-
case BuiltinType::LongDouble:
- return Builder.getFloatType(ASTCtx.getFloatTypeSemantics(QualType(BT, 0)),
- getTypeAlign(QualType(BT, 0)));
-
- case BuiltinType::BFloat16:
- return Builder.getFloatType(llvm::APFloat::BFloat(),
- getTypeAlign(QualType(BT, 0)));
-
case BuiltinType::Float128:
- return Builder.getFloatType(llvm::APFloat::IEEEquad(),
- getTypeAlign(QualType(BT, 0)));
+ return Builder.getFloatType(ASTCtx.getFloatTypeSemantics(QT),
+ getTypeAlign(QT));
default:
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
@@ -171,6 +144,45 @@ QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
return createPointerTypeForPointee(PT->getPointeeType());
}
+const llvm::abi::Type *
+QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
+ const EnumDecl *ED = ET->getDecl();
+ QualType UnderlyingType = ED->getIntegerType();
+
+ if (UnderlyingType.isNull())
+ UnderlyingType = ASTCtx.IntTy;
+
+ return convertType(UnderlyingType);
+}
+
+const llvm::abi::StructType *
+QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
+ const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
+
+ SmallVector<llvm::abi::FieldInfo, 16> Fields;
+ computeFieldInfo(RD, Fields, Layout);
+
+ llvm::TypeSize Size =
+ llvm::TypeSize::getFixed(Layout.getSize().getQuantity() * 8);
+ llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
+
+ return Builder.getStructType(Fields, Size, Alignment);
+}
+
+const llvm::abi::UnionType *
+QualTypeMapper::convertUnionType(const clang::RecordDecl *RD) {
+ const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
+
+ SmallVector<llvm::abi::FieldInfo, 16> Fields;
+ computeFieldInfo(RD, Fields, Layout);
+
+ llvm::TypeSize Size =
+ llvm::TypeSize::getFixed(Layout.getSize().getQuantity() * 8);
+ llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
+
+ return Builder.getUnionType(Fields, Size, Alignment);
+}
+
llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const {
return llvm::Align(ASTCtx.getTypeAlign(QT));
}
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index e99bee35acf77..2b91b72e9daf1 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -1,13 +1,27 @@
+//===- ABI/Types.h ----------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the Types and related helper methods concerned to the
+/// LLVMABI library which mirrors ABI related type information from
+/// the LLVM frontend.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_ABI_TYPES_H
#define LLVM_ABI_TYPES_H
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/CallingConv.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/TypeSize.h"
#include <cstdint>
-#include <llvm/IR/CallingConv.h>
namespace llvm {
namespace abi {
@@ -27,21 +41,21 @@ class Type {
protected:
TypeKind Kind;
TypeSize SizeInBits;
- Align AlignInBits;
+ Align Alignment;
bool IsExplicitlyAligned;
Type(TypeKind K, TypeSize Size, Align Align, bool ExplicitAlign = false)
- : Kind(K), SizeInBits(Size), AlignInBits(Align),
+ : Kind(K), SizeInBits(Size), Alignment(Align),
IsExplicitlyAligned(ExplicitAlign) {}
public:
TypeKind getKind() const { return Kind; }
TypeSize getSizeInBits() const { return SizeInBits; }
- Align getAlignInBits() const { return AlignInBits; }
+ Align getAlignment() const { return Alignment; }
bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
void setExplicitAlignment(Align Align) {
- AlignInBits = Align;
+ Alignment = Align;
IsExplicitlyAligned = true;
}
@@ -109,7 +123,7 @@ class ArrayType : public Type {
public:
ArrayType(const Type *ElemType, uint64_t NumElems)
: Type(TypeKind::Array, ElemType->getSizeInBits() * NumElems,
- ElemType->getAlignInBits()),
+ ElemType->getAlignment()),
ElementType(ElemType), NumElements(NumElems) {}
const Type *getElementType() const { return ElementType; }
>From 74cbee261d6a4292f8a484e0c791598ab5f515ec Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Wed, 4 Jun 2025 17:22:21 +0530
Subject: [PATCH 06/11] [LLVMABI] Support CXX classes with base classes
---
.../{QualtypeMapper.h => QualTypeMapper.h} | 3 +-
clang/lib/CodeGen/CMakeLists.txt | 2 +-
...{QualtypeMapper.cpp => QualTypeMapper.cpp} | 68 +++++++++++++++++--
3 files changed, 67 insertions(+), 6 deletions(-)
rename clang/include/clang/CodeGen/{QualtypeMapper.h => QualTypeMapper.h} (94%)
rename clang/lib/CodeGen/{QualtypeMapper.cpp => QualTypeMapper.cpp} (77%)
diff --git a/clang/include/clang/CodeGen/QualtypeMapper.h b/clang/include/clang/CodeGen/QualTypeMapper.h
similarity index 94%
rename from clang/include/clang/CodeGen/QualtypeMapper.h
rename to clang/include/clang/CodeGen/QualTypeMapper.h
index e99c6847a67b0..d0a2d29093d15 100644
--- a/clang/include/clang/CodeGen/QualtypeMapper.h
+++ b/clang/include/clang/CodeGen/QualTypeMapper.h
@@ -1,4 +1,4 @@
-//==---- QualtypeMapper.h - Maps Clang Qualtype to LLVMABI Types -----------==//
+//==---- QualTypeMapper.h - Maps Clang QualType to LLVMABI Types -----------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -45,6 +45,7 @@ class QualTypeMapper {
const llvm::abi::StructType *convertStructType(const clang::RecordDecl *RD);
const llvm::abi::UnionType *convertUnionType(const clang::RecordDecl *RD);
const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
+ const llvm::abi::StructType *convertCXXRecordType(const CXXRecordDecl *RD);
void computeFieldInfo(const clang::RecordDecl *RD,
SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index c70862a05d35d..f805819de300f 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -115,7 +115,7 @@ add_clang_library(clangCodeGen
ModuleBuilder.cpp
ObjectFilePCHContainerWriter.cpp
PatternInit.cpp
- QualtypeMapper.cpp
+ QualTypeMapper.cpp
SanitizerMetadata.cpp
SwiftCallingConv.cpp
TargetBuiltins/ARM.cpp
diff --git a/clang/lib/CodeGen/QualtypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
similarity index 77%
rename from clang/lib/CodeGen/QualtypeMapper.cpp
rename to clang/lib/CodeGen/QualTypeMapper.cpp
index f1577383af4dc..41fd70c9b1855 100644
--- a/clang/lib/CodeGen/QualtypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -1,4 +1,4 @@
-//==---- QualtypeMapper.cpp - Maps Clang Qualtype to LLVMABI Types ---------==//
+//==---- QualTypeMapper.cpp - Maps Clang QualType to LLVMABI Types ---------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -14,8 +14,9 @@
/// interoperability.
///
//===----------------------------------------------------------------------===//
-#include "clang/CodeGen/QualtypeMapper.h"
+#include "clang/CodeGen/QualTypeMapper.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
@@ -48,7 +49,7 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
} else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
Result = convertEnumType(ET);
} else {
- // TODO: Write Fallback logic for unsupported types.
+ llvm_unreachable("Unsupported type for ABI lowering");
}
TypeCache[QT] = Result;
return Result;
@@ -113,7 +114,6 @@ QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
return Builder.getArrayType(ElementType, 0);
if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
return createPointerTypeForPointee(VAT->getPointeeType());
- // TODO: This of a better fallback.
return Builder.getArrayType(ElementType, 1);
}
@@ -136,9 +136,69 @@ const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
if (RD->isUnion())
return convertUnionType(RD);
+
+ // Handle C++ classes with base classes
+ auto *const CXXRd = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXRd && (CXXRd->getNumBases() > 0 || CXXRd->getNumVBases() > 0)) {
+ return convertCXXRecordType(CXXRd);
+ }
return convertStructType(RD);
}
+const llvm::abi::StructType *
+QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
+ const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
+ SmallVector<llvm::abi::FieldInfo, 16> Fields;
+
+ if (RD->isPolymorphic()) {
+ const llvm::abi::Type *VtablePointer =
+ createPointerTypeForPointee(ASTCtx.VoidPtrTy);
+ Fields.emplace_back(VtablePointer, 0);
+ }
+
+ for (const auto &Base : RD->bases()) {
+ if (Base.isVirtual())
+ continue;
+
+ const RecordType *BaseRT = Base.getType()->getAs<RecordType>();
+ if (!BaseRT)
+ continue;
+
+ const llvm::abi::Type *BaseType = convertType(Base.getType());
+ uint64_t BaseOffset =
+ Layout.getBaseClassOffset(BaseRT->getAsCXXRecordDecl()).getQuantity() *
+ 8;
+
+ Fields.emplace_back(BaseType, BaseOffset);
+ }
+
+ for (const auto &VBase : RD->vbases()) {
+ const RecordType *VBaseRT = VBase.getType()->getAs<RecordType>();
+ if (!VBaseRT)
+ continue;
+
+ const llvm::abi::Type *VBaseType = convertType(VBase.getType());
+ uint64_t VBaseOffset =
+ Layout.getVBaseClassOffset(VBaseRT->getAsCXXRecordDecl())
+ .getQuantity() *
+ 8;
+
+ Fields.emplace_back(VBaseType, VBaseOffset);
+ }
+ computeFieldInfo(RD, Fields, Layout);
+
+ llvm::sort(Fields,
+ [](const llvm::abi::FieldInfo &A, const llvm::abi::FieldInfo &B) {
+ return A.OffsetInBits < B.OffsetInBits;
+ });
+
+ llvm::TypeSize Size =
+ llvm::TypeSize::getFixed(Layout.getSize().getQuantity() * 8);
+ llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
+
+ return Builder.getStructType(Fields, Size, Alignment);
+}
+
const llvm::abi::Type *
QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
return createPointerTypeForPointee(PT->getPointeeType());
>From da1bef05de4e9ec2abfb63fcf19acefd9cbc736f Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Thu, 5 Jun 2025 01:00:47 +0530
Subject: [PATCH 07/11] [LLVMABI] Mapper Benchmark 1
---
clang/include/clang/CodeGen/QualTypeMapper.h | 1 +
clang/lib/CodeGen/QualTypeMapper.cpp | 55 +++++++++++++++++++-
2 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/CodeGen/QualTypeMapper.h b/clang/include/clang/CodeGen/QualTypeMapper.h
index d0a2d29093d15..94fc74763a8ee 100644
--- a/clang/include/clang/CodeGen/QualTypeMapper.h
+++ b/clang/include/clang/CodeGen/QualTypeMapper.h
@@ -41,6 +41,7 @@ class QualTypeMapper {
const llvm::abi::Type *convertVectorType(const clang::VectorType *VT);
const llvm::abi::Type *convertRecordType(const clang::RecordType *RT);
const llvm::abi::Type *convertEnumType(const clang::EnumType *ET);
+ const llvm::abi::Type *convertReferenceType(const ReferenceType *RT);
const llvm::abi::StructType *convertStructType(const clang::RecordDecl *RD);
const llvm::abi::UnionType *convertUnionType(const clang::RecordDecl *RD);
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index 41fd70c9b1855..b78b815b85880 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -19,11 +19,13 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ABI/Types.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/TypeSize.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace mapper {
@@ -40,6 +42,8 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
Result = convertBuiltinType(BT);
} else if (const auto *PT = dyn_cast<PointerType>(QT.getTypePtr())) {
Result = convertPointerType(PT);
+ } else if (const auto *RT = dyn_cast<ReferenceType>(QT.getTypePtr())) {
+ Result = convertReferenceType(RT);
} else if (const auto *AT = dyn_cast<ArrayType>(QT.getTypePtr())) {
Result = convertArrayType(AT);
} else if (const auto *VT = dyn_cast<VectorType>(QT.getTypePtr())) {
@@ -48,6 +52,18 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
Result = convertRecordType(RT);
} else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
Result = convertEnumType(ET);
+ } else if (const auto *BIT = dyn_cast<BitIntType>(QT.getTypePtr())) {
+ QualType QT(BIT, 0);
+ uint64_t NumBits = BIT->getNumBits();
+ bool IsSigned = BIT->isSigned();
+ llvm::Align TypeAlign = getTypeAlign(QT);
+ return Builder.getIntegerType(NumBits, TypeAlign, IsSigned);
+ } else if (isa<ObjCObjectType>(QT.getTypePtr()) ||
+ isa<ObjCObjectPointerType>(QT.getTypePtr())) {
+ auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(LangAS::Default);
+ llvm::Align PointerAlign =
+ llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(LangAS::Default));
+ return Builder.getPointerType(PointerSize, PointerAlign);
} else {
llvm_unreachable("Unsupported type for ABI lowering");
}
@@ -199,6 +215,11 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
return Builder.getStructType(Fields, Size, Alignment);
}
+const llvm::abi::Type *
+QualTypeMapper::convertReferenceType(const ReferenceType *RT) {
+ return createPointerTypeForPointee(RT->getPointeeType());
+}
+
const llvm::abi::Type *
QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
return createPointerTypeForPointee(PT->getPointeeType());
@@ -206,13 +227,43 @@ QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
const llvm::abi::Type *
QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
+ if (!ET)
+ return Builder.getIntegerType(32, llvm::Align(4), true);
const EnumDecl *ED = ET->getDecl();
+ if (!ED)
+ return Builder.getIntegerType(32, llvm::Align(4), true);
+ if (ED->isInvalidDecl())
+ return Builder.getIntegerType(32, llvm::Align(4), true);
+
+ if (!ED->isComplete()) {
+ if (ED->isFixed()) {
+ QualType UnderlyingType = ED->getIntegerType();
+ if (!UnderlyingType.isNull()) {
+ return convertType(UnderlyingType);
+ }
+ }
+ return Builder.getIntegerType(32, llvm::Align(4), true);
+ }
QualType UnderlyingType = ED->getIntegerType();
- if (UnderlyingType.isNull())
+ if (UnderlyingType.isNull()) {
+ UnderlyingType = ED->getPromotionType();
+ }
+
+ if (UnderlyingType.isNull()) {
UnderlyingType = ASTCtx.IntTy;
+ }
+
+ if (const auto *BT = dyn_cast<BuiltinType>(UnderlyingType.getTypePtr())) {
+ return convertBuiltinType(BT);
+ }
+
+ // For non-builtin underlying types, extract type information safely
+ uint64_t TypeSize = ASTCtx.getTypeSize(UnderlyingType);
+ llvm::Align TypeAlign = getTypeAlign(UnderlyingType);
+ bool IsSigned = UnderlyingType->isSignedIntegerType();
- return convertType(UnderlyingType);
+ return Builder.getIntegerType(TypeSize, TypeAlign, IsSigned);
}
const llvm::abi::StructType *
>From 3ac524826fb8855b82c65956502c7e5d4ae6b5d6 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Sun, 8 Jun 2025 18:39:14 +0530
Subject: [PATCH 08/11] [LLVMABI] Refactor and Docs
---
clang/lib/CodeGen/QualTypeMapper.cpp | 96 ++++++++++++++++++++++++----
llvm/include/llvm/ABI/Types.h | 16 +++--
2 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index b78b815b85880..420c25975a844 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -30,9 +30,18 @@
namespace clang {
namespace mapper {
+/// Main entry point for converting Clang QualType to LLVM ABI Type.
+/// This method performs type canonicalization, caching, and dispatches
+/// to specialized conversion methods based on the type kind.
+///
+/// \param QT The Clang QualType to convert
+/// \return Corresponding LLVM ABI Type representation, or nullptr on error
const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
+ // Canonicalize type and strip qualifiers
+ // This ensures consistent type representation across different contexts
QT = QT.getCanonicalType().getUnqualifiedType();
+ // Results are cached since type conversion may be expensive
auto It = TypeCache.find(QT);
if (It != TypeCache.end())
return It->second;
@@ -53,6 +62,7 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
} else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
Result = convertEnumType(ET);
} else if (const auto *BIT = dyn_cast<BitIntType>(QT.getTypePtr())) {
+ // Handle C23 _BitInt(N) types - arbitrary precision integers
QualType QT(BIT, 0);
uint64_t NumBits = BIT->getNumBits();
bool IsSigned = BIT->isSigned();
@@ -60,6 +70,7 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
return Builder.getIntegerType(NumBits, TypeAlign, IsSigned);
} else if (isa<ObjCObjectType>(QT.getTypePtr()) ||
isa<ObjCObjectPointerType>(QT.getTypePtr())) {
+ // Objective-C objects are represented as pointers in the ABI
auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(LangAS::Default);
llvm::Align PointerAlign =
llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(LangAS::Default));
@@ -71,6 +82,12 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
return Result;
}
+/// Converts C/C++ builtin types to LLVM ABI types.
+/// This handles all fundamental scalar types including integers, floats,
+/// and special types like void and bool.
+///
+/// \param BT The BuiltinType to convert
+/// \return Corresponding LLVM ABI integer, float, or void type
const llvm::abi::Type *
QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
QualType QT(BT, 0);
@@ -113,11 +130,18 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
getTypeAlign(QT));
default:
+ // Unhandled BuiltinTypes are treated as unsigned integers.
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
getTypeAlign(QualType(BT, 0)), false);
}
}
+/// Converts array types to LLVM ABI array representations.
+/// Handles different array kinds: constant arrays, incomplete arrays,
+/// and variable-length arrays.
+///
+/// \param AT The ArrayType to convert
+/// \return LLVM ABI ArrayType or PointerType
const llvm::abi::Type *
QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
const llvm::abi::Type *ElementType = convertType(AT->getElementType());
@@ -130,9 +154,14 @@ QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
return Builder.getArrayType(ElementType, 0);
if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
return createPointerTypeForPointee(VAT->getPointeeType());
+ // Fallback for other array types
return Builder.getArrayType(ElementType, 1);
}
+/// Converts vector types to LLVM ABI vector representations.
+///
+/// \param VT The VectorType to convert
+/// \return LLVM ABI VectorType with element type, count, and alignment
const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
const llvm::abi::Type *ElementType = convertType(VT->getElementType());
uint64_t NumElements = VT->getNumElements();
@@ -142,6 +171,12 @@ const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
return Builder.getVectorType(ElementType, NumElements, VectorAlign);
}
+/// Converts record types (struct/class/union) to LLVM ABI representations.
+/// This is the main dispatch method that handles different record kinds
+/// and delegates to specialized converters.
+///
+/// \param RT The RecordType to convert
+/// \return LLVM ABI StructType or UnionType
const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
if (!RD) {
@@ -161,6 +196,14 @@ const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
return convertStructType(RD);
}
+/// Converts C++ classes with inheritance to LLVM ABI struct representations.
+/// This method handles the complex layout of C++ objects including:
+/// - Virtual table pointers for polymorphic classes
+/// - Base class subobjects (both direct and virtual bases)
+/// - Member field layout with proper offsets
+///
+/// \param RD The C++ record declaration
+/// \return LLVM ABI StructType representing the complete object layout
const llvm::abi::StructType *
QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
@@ -176,9 +219,7 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
if (Base.isVirtual())
continue;
- const RecordType *BaseRT = Base.getType()->getAs<RecordType>();
- if (!BaseRT)
- continue;
+ const RecordType *BaseRT = Base.getType()->castAs<RecordType>();
const llvm::abi::Type *BaseType = convertType(Base.getType());
uint64_t BaseOffset =
@@ -215,16 +256,33 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
return Builder.getStructType(Fields, Size, Alignment);
}
+/// Converts reference types to pointer representations in the ABI.
+/// Both lvalue references (T&) and rvalue references (T&&) are represented
+/// as pointers at the ABI level.
+///
+/// \param RT The ReferenceType to convert
+/// \return LLVM ABI PointerType
const llvm::abi::Type *
QualTypeMapper::convertReferenceType(const ReferenceType *RT) {
return createPointerTypeForPointee(RT->getPointeeType());
}
+/// Converts pointer types to LLVM ABI pointer representations.
+/// Takes into account address space information for the pointed-to type.
+///
+/// \param PT The PointerType to convert
+/// \return LLVM ABI PointerType with appropriate size and alignment
const llvm::abi::Type *
QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
return createPointerTypeForPointee(PT->getPointeeType());
}
+/// Converts enumeration types to their underlying integer representations.
+/// This method handles various enum states and falls back to safe defaults
+/// when enum information is incomplete or invalid.
+///
+/// \param ET The EnumType to convert
+/// \return LLVM ABI IntegerType representing the enum's underlying type
const llvm::abi::Type *
QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
if (!ET)
@@ -246,19 +304,15 @@ QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
}
QualType UnderlyingType = ED->getIntegerType();
- if (UnderlyingType.isNull()) {
+ if (UnderlyingType.isNull())
UnderlyingType = ED->getPromotionType();
- }
- if (UnderlyingType.isNull()) {
+ if (UnderlyingType.isNull())
UnderlyingType = ASTCtx.IntTy;
- }
- if (const auto *BT = dyn_cast<BuiltinType>(UnderlyingType.getTypePtr())) {
+ if (const auto *BT = dyn_cast<BuiltinType>(UnderlyingType.getTypePtr()))
return convertBuiltinType(BT);
- }
- // For non-builtin underlying types, extract type information safely
uint64_t TypeSize = ASTCtx.getTypeSize(UnderlyingType);
llvm::Align TypeAlign = getTypeAlign(UnderlyingType);
bool IsSigned = UnderlyingType->isSignedIntegerType();
@@ -266,6 +320,12 @@ QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
return Builder.getIntegerType(TypeSize, TypeAlign, IsSigned);
}
+/// Converts plain C structs and C++ classes without inheritance.
+/// This handles the simpler case where we only need to layout member fields
+/// without considering base classes or virtual functions.
+///
+/// \param RD The RecordDecl to convert
+/// \return LLVM ABI StructType
const llvm::abi::StructType *
QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
@@ -280,6 +340,12 @@ QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
return Builder.getStructType(Fields, Size, Alignment);
}
+/// Converts C union types where all fields occupy the same memory location.
+/// The union size is determined by its largest member, and all fields
+/// start at offset 0.
+///
+/// \param RD The RecordDecl representing the union
+/// \return LLVM ABI UnionType
const llvm::abi::UnionType *
QualTypeMapper::convertUnionType(const clang::RecordDecl *RD) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
@@ -307,6 +373,13 @@ QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
return Builder.getPointerType(PointerSize, Alignment);
}
+/// Processes the fields of a record (struct/class/union) and populates
+/// the Fields vector with FieldInfo objects containing type, offset,
+/// and bitfield information.
+///
+/// \param RD The RecordDecl whose fields to process
+/// \param Fields Output vector to populate with field information
+/// \param Layout The AST record layout containing field offset information
void QualTypeMapper::computeFieldInfo(
const RecordDecl *RD, SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
const ASTRecordLayout &Layout) {
@@ -319,9 +392,8 @@ void QualTypeMapper::computeFieldInfo(
bool IsBitField = FD->isBitField();
uint64_t BitFieldWidth = 0;
- if (IsBitField) {
+ if (IsBitField)
BitFieldWidth = FD->getBitWidthValue();
- }
Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth);
++FieldIndex;
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 2b91b72e9daf1..e4642142662d3 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -135,15 +135,23 @@ class ArrayType : public Type {
class VectorType : public Type {
private:
const Type *ElementType;
- uint64_t NumElements;
+ ElementCount NumElements;
public:
- VectorType(const Type *ElemType, uint64_t NumElems, Align Align)
- : Type(TypeKind::Vector, ElemType->getSizeInBits() * NumElems, Align),
+ VectorType(const Type *ElemType, ElementCount NumElems, Align Align)
+ : Type(
+ TypeKind::Vector,
+ NumElems.isScalable()
+ ? TypeSize(ElemType->getSizeInBits().getFixedValue() *
+ NumElems.getKnownMinValue(),
+ true)
+ : TypeSize::getFixed(ElemType->getSizeInBits().getFixedValue() *
+ NumElems.getFixedValue()),
+ Align),
ElementType(ElemType), NumElements(NumElems) {}
const Type *getElementType() const { return ElementType; }
- uint64_t getNumElements() const { return NumElements; }
+ ElementCount getNumElements() const { return NumElements; }
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Vector;
>From 0f045dabf0fe045c2812d8062ade8dad66eeb64a Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Thu, 12 Jun 2025 23:18:12 +0530
Subject: [PATCH 09/11] [LLVMABI] Init ABIInfo
---
llvm/include/llvm/ABI/ABIFunctionInfo.h | 172 ++++++++++++++++++++++++
llvm/include/llvm/ABI/ABIInfo.h | 136 +++++++++++++++++++
llvm/lib/ABI/ABIFunctionInfo.cpp | 40 ++++++
3 files changed, 348 insertions(+)
create mode 100644 llvm/include/llvm/ABI/ABIFunctionInfo.h
create mode 100644 llvm/include/llvm/ABI/ABIInfo.h
create mode 100644 llvm/lib/ABI/ABIFunctionInfo.cpp
diff --git a/llvm/include/llvm/ABI/ABIFunctionInfo.h b/llvm/include/llvm/ABI/ABIFunctionInfo.h
new file mode 100644
index 0000000000000..b0a590373b586
--- /dev/null
+++ b/llvm/include/llvm/ABI/ABIFunctionInfo.h
@@ -0,0 +1,172 @@
+//===----- ABIFunctionInfo.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 ABIFunctionInfo and associated types used in representing the
+// ABI-coerced types for function arguments and return values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ABI_ABIFUNCTIONINFO_H
+#define LLVM_ABI_ABIFUNCTIONINFO_H
+
+#include "ABIInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/Support/TrailingObjects.h"
+
+namespace llvm {
+namespace abi {
+
+struct FunctionABIInfo {
+ llvm::CallingConv::ID CC = llvm::CallingConv::C;
+ llvm::CallingConv::ID EffectiveCC = llvm::CallingConv::C;
+
+ // Core ABI attributes
+ bool NoReturn = false;
+ bool NoUnwind = false;
+ bool HasSRet = false;
+ bool IsVariadic = false;
+ bool IsInstanceMethod = false;
+ // Are these ABI Relavent(?)
+ bool IsChainCall = false;
+ bool IsDelegateCall = false;
+
+ // Register usage controls
+ bool HasRegParm = false;
+ unsigned RegParm = 0;
+ bool NoCallerSavedRegs = false;
+ // Security/extensions(are they ABI related?)
+ bool NoCfCheck = false;
+ bool CmseNSCall = false;
+
+ // Optimization hints
+ bool ReturnsRetained = false;
+ unsigned MaxVectorWidth = 0;
+
+ FunctionABIInfo() = default;
+ FunctionABIInfo(llvm::CallingConv::ID CC) : CC(CC), EffectiveCC(CC) {}
+};
+
+// Not an Immediate requirement for BPF
+struct RequiredArgs {
+private:
+ unsigned NumRequired;
+ static constexpr unsigned All = ~0U;
+
+public:
+ RequiredArgs() : NumRequired(All) {}
+ explicit RequiredArgs(unsigned N) : NumRequired(N) {}
+
+ static RequiredArgs forPrototypedFunction(unsigned NumArgs) {
+ return RequiredArgs(NumArgs);
+ }
+
+ static RequiredArgs forVariadicFunction(unsigned NumRequired) {
+ return RequiredArgs(NumRequired);
+ }
+
+ bool allowsOptionalArgs() const { return NumRequired != All; }
+
+ unsigned getNumRequiredArgs() const {
+ return allowsOptionalArgs() ? NumRequired : 0;
+ }
+
+ bool operator==(const RequiredArgs &Other) const {
+ return NumRequired == Other.NumRequired;
+ }
+};
+
+// Implementation detail of ABIFunctionInfo, factored out so it can be named
+// in the TrailingObjects base class of ABIFunctionInfo.
+struct ABIFunctionInfoArgInfo {
+ const Type *ABIType;
+ ABIArgInfo ArgInfo;
+
+ ABIFunctionInfoArgInfo()
+ : ABIType(nullptr), ArgInfo(ABIArgInfo::getDirect()) {}
+ ABIFunctionInfoArgInfo(Type *T)
+ : ABIType(T), ArgInfo(ABIArgInfo::getDirect()) {}
+ ABIFunctionInfoArgInfo(Type *T, ABIArgInfo A) : ABIType(T), ArgInfo(A) {}
+};
+
+class ABIFunctionInfo final
+ : public llvm::FoldingSetNode,
+ private TrailingObjects<ABIFunctionInfo, ABIFunctionInfoArgInfo> {
+ typedef ABIFunctionInfoArgInfo ArgInfo;
+
+private:
+ const Type *ReturnType;
+ ABIArgInfo ReturnInfo;
+ unsigned NumArgs;
+ FunctionABIInfo ABIInfo;
+ RequiredArgs
+ Required; // For Variadic Functions but we can focus on this later
+
+ ABIFunctionInfo(const Type *RetTy, unsigned NumArguments)
+ : ReturnType(RetTy), ReturnInfo(ABIArgInfo::getDirect()),
+ NumArgs(NumArguments) {}
+
+ friend class TrailingObjects;
+
+public:
+ static ABIFunctionInfo *
+ create(llvm::CallingConv::ID CC, const Type *ReturnType,
+ llvm::ArrayRef<const Type *> ArgTypes,
+ const FunctionABIInfo &ABIInfo = FunctionABIInfo(),
+ RequiredArgs Required = RequiredArgs());
+
+ const Type *getReturnType() const { return ReturnType; }
+ ABIArgInfo &getReturnInfo() { return ReturnInfo; }
+ const ABIArgInfo &getReturnInfo() const { return ReturnInfo; }
+
+ llvm::CallingConv::ID getCallingConvention() const { return ABIInfo.CC; }
+
+ const FunctionABIInfo &getExtInfo() const { return ABIInfo; }
+ RequiredArgs getRequiredArgs() const { return Required; }
+ llvm::ArrayRef<ArgInfo> arguments() const {
+ return {getTrailingObjects<ArgInfo>(), NumArgs};
+ }
+
+ llvm::MutableArrayRef<ArgInfo> arguments() {
+ return {getTrailingObjects<ArgInfo>(), NumArgs};
+ }
+
+ ArgInfo &getArgInfo(unsigned Index) {
+ assert(Index < NumArgs && "Invalid argument index");
+ return arguments()[Index];
+ }
+
+ const ArgInfo &getArgInfo(unsigned Index) const {
+ assert(Index < NumArgs && "Invalid argument index");
+ return arguments()[Index];
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(static_cast<unsigned>(ABIInfo.CC));
+ ID.AddPointer(ReturnType);
+ ID.AddInteger(static_cast<unsigned>(ReturnInfo.getKind()));
+ if (ReturnInfo.getCoerceToType())
+ ID.AddPointer(ReturnInfo.getCoerceToType());
+ ID.AddInteger(NumArgs);
+ for (const auto &ArgInfo : arguments()) {
+ ID.AddPointer(ArgInfo.ABIType);
+ ID.AddInteger(static_cast<unsigned>(ArgInfo.ArgInfo.getKind()));
+ if (ArgInfo.ArgInfo.getCoerceToType())
+ ID.AddPointer(ArgInfo.ArgInfo.getCoerceToType());
+ }
+ ID.AddInteger(Required.getNumRequiredArgs());
+ ID.AddBoolean(Required.allowsOptionalArgs());
+ ID.AddBoolean(ABIInfo.NoReturn);
+ ID.AddBoolean(ABIInfo.IsVariadic);
+ // TODO: Add more flags
+ }
+};
+} // namespace abi
+} // namespace llvm
+
+#endif // !LLVM_ABI_ABIFUNCTIONINFO_H
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
new file mode 100644
index 0000000000000..aa56dd5e96f2c
--- /dev/null
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -0,0 +1,136 @@
+//===----- ABIInfo.h - ABI information access & encapsulation ----- 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// ABI information access & encapsulation
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ABI_ABIINFO_H
+#define LLVM_ABI_ABIINFO_H
+
+#include "llvm/ABI/Types.h"
+#include <cassert>
+
+namespace llvm {
+namespace abi {
+
+/// ABIArgInfo - Helper class to encapsulate information about how a
+/// specific C type should be passed to or returned from a function.
+class ABIArgInfo {
+public:
+ enum Kind { Direct, Indirect, Ignore, Expand, CoerceAndExpand, InAlloca };
+
+private:
+ Kind TheKind;
+ const Type *CoercionType;
+
+ bool InReg : 1;
+ bool PaddingInReg : 1;
+
+ unsigned IndirectAlign : 16;
+ bool IndirectByVal : 1;
+
+ ABIArgInfo(Kind K = Direct)
+ : TheKind(K), CoercionType(nullptr), InReg(false), PaddingInReg(false),
+ IndirectAlign(0), IndirectByVal(false) {}
+
+public:
+ static ABIArgInfo getDirect(const Type *T = nullptr) {
+ ABIArgInfo AI(Direct);
+ AI.CoercionType = T;
+ return AI;
+ }
+
+ static ABIArgInfo getDirectInReg(const Type *T = nullptr) {
+ ABIArgInfo AI = getDirect(T);
+ AI.InReg = true;
+ return AI;
+ }
+
+ static ABIArgInfo getIndirect(unsigned Align = 0, bool ByVal = true) {
+ ABIArgInfo AI(Indirect);
+ AI.IndirectAlign = Align;
+ AI.IndirectByVal = ByVal;
+ return AI;
+ }
+
+ static ABIArgInfo getIndirectInReg(unsigned Align = 0, bool ByVal = true) {
+ ABIArgInfo AI = getIndirect(Align, ByVal);
+ AI.InReg = true;
+ return AI;
+ }
+
+ static ABIArgInfo getIgnore() { return ABIArgInfo(Ignore); }
+
+ static ABIArgInfo getExpand() { return ABIArgInfo(Expand); }
+
+ static ABIArgInfo getCoerceAndExpand(const Type *CoercionType) {
+ ABIArgInfo AI(CoerceAndExpand);
+ AI.CoercionType = CoercionType;
+ return AI;
+ }
+
+ Kind getKind() const { return TheKind; }
+
+ bool isDirect() const { return TheKind == Direct; }
+ bool isIndirect() const { return TheKind == Indirect; }
+ bool isIgnore() const { return TheKind == Ignore; }
+ bool isExpand() const { return TheKind == Expand; }
+ bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
+ bool isInAlloca() const { return TheKind == InAlloca; }
+
+ bool isInReg() const { return InReg; }
+ bool hasPaddingInReg() const { return PaddingInReg; }
+
+ unsigned getIndirectAlign() const {
+ assert(isIndirect() && "Only indirect arguments have alignment");
+ return IndirectAlign;
+ }
+
+ bool getIndirectByVal() const {
+ assert(isIndirect() && "Only indirect arguments can be ByVal");
+ return IndirectByVal;
+ }
+
+ const Type *getCoerceToType() const {
+ assert((isDirect() || isCoerceAndExpand()) &&
+ "Only Direct and CoerceAndExpand arguments can have coercion types");
+ return CoercionType;
+ }
+
+ ABIArgInfo &setInReg(bool InReg = true) {
+ this->InReg = InReg;
+ return *this;
+ }
+
+ ABIArgInfo &setPaddingInReg(bool HasPadding = true) {
+ this->PaddingInReg = HasPadding;
+ return *this;
+ }
+};
+
+/// Abstract base class for target-specific ABI information.
+class ABIInfo {
+public:
+ virtual ~ABIInfo() = default;
+
+ virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
+ virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
+
+ virtual bool isPassByRef(const Type *Ty) const { return false; }
+
+ virtual unsigned getTypeAlignment(const Type *Ty) const = 0;
+
+ virtual unsigned getTypeSize(const Type *Ty) const = 0;
+};
+
+} // namespace abi
+} // namespace llvm
+
+#endif // LLVM_ABI_ABIINFO_H
diff --git a/llvm/lib/ABI/ABIFunctionInfo.cpp b/llvm/lib/ABI/ABIFunctionInfo.cpp
new file mode 100644
index 0000000000000..f0a75fa7f8151
--- /dev/null
+++ b/llvm/lib/ABI/ABIFunctionInfo.cpp
@@ -0,0 +1,40 @@
+//===----- ABIFunctionInfo.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/ABIFunctionInfo.h"
+
+using namespace llvm;
+using namespace llvm::abi;
+
+ABIFunctionInfo *ABIFunctionInfo::create(llvm::CallingConv::ID CC,
+ const Type *ReturnType,
+ llvm::ArrayRef<const Type *> ArgTypes,
+ const FunctionABIInfo &ABIInfo,
+ RequiredArgs Required) {
+
+ assert(!Required.allowsOptionalArgs() ||
+ Required.getNumRequiredArgs() <= ArgTypes.size());
+
+ void *Buffer = operator new(
+ totalSizeToAlloc<ABIFunctionInfoArgInfo>(ArgTypes.size()));
+
+ ABIFunctionInfo *FI =
+ new (Buffer) ABIFunctionInfo(ReturnType, ArgTypes.size());
+
+ FI->ABIInfo = ABIInfo;
+ FI->ABIInfo.CC = CC;
+ FI->Required = Required;
+
+ auto Args = FI->arguments();
+ for (unsigned I = 0; I < ArgTypes.size(); ++I) {
+ Args[I].ABIType = ArgTypes[I];
+ Args[I].ArgInfo = ABIArgInfo::getDirect();
+ }
+
+ return FI;
+}
>From b458dab65c9de603926955e2b0b6ae7d820bc06d Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Sat, 14 Jun 2025 01:55:46 +0530
Subject: [PATCH 10/11] [LLVMABI] Added BPF Target
---
llvm/lib/ABI/Targets/BPF.cpp | 102 +++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 llvm/lib/ABI/Targets/BPF.cpp
diff --git a/llvm/lib/ABI/Targets/BPF.cpp b/llvm/lib/ABI/Targets/BPF.cpp
new file mode 100644
index 0000000000000..52aff3ca368bd
--- /dev/null
+++ b/llvm/lib/ABI/Targets/BPF.cpp
@@ -0,0 +1,102 @@
+//===- BPF.cpp ------------------------------------------------------------===//
+//
+// 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/ABIInfo.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+
+namespace llvm::abi {
+
+class BPFABIInfo : public ABIInfo {
+private:
+ TypeBuilder &TB;
+
+ bool isAggregateType(const Type *Ty) const {
+ return Ty->isStruct() || Ty->isUnion() || Ty->isArray() ||
+ (Ty->isVector() && !isSimpleVector(dyn_cast<VectorType>(Ty)));
+ }
+
+ bool isSimpleVector(const VectorType *VecTy) const {
+ const Type *ElemTy = VecTy->getElementType();
+
+ if (!ElemTy->isInteger() && !ElemTy->isFloat())
+ return false;
+
+ auto VecSizeInBits = VecTy->getSizeInBits().getFixedValue();
+ return VecSizeInBits <= 128;
+ }
+
+ bool isPromotableIntegerType(const IntegerType *IntTy) const {
+ auto BitWidth = IntTy->getSizeInBits().getFixedValue();
+ return BitWidth > 0 && BitWidth < 32;
+ }
+
+public:
+ BPFABIInfo(TypeBuilder &TypeBuilder) : TB(TypeBuilder) {}
+
+ ABIArgInfo classifyReturnType(const Type *RetTy) const override {
+ if (RetTy->isVoid())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateType(RetTy)) {
+ auto SizeInBits = RetTy->getSizeInBits().getFixedValue();
+
+ if (SizeInBits == 0)
+ return ABIArgInfo::getIgnore();
+
+ return ABIArgInfo::getIndirect(RetTy->getAlignment().value());
+ }
+
+ if (const auto *IntTy = dyn_cast<IntegerType>(RetTy)) {
+ if (IntTy->getSizeInBits().getFixedValue() > 128) {
+ return ABIArgInfo::getIndirect(RetTy->getAlignment().value());
+ }
+ }
+
+ return ABIArgInfo::getDirect();
+ }
+
+ ABIArgInfo classifyArgumentType(const Type *ArgTy) const override {
+ if (isAggregateType(ArgTy)) {
+ auto SizeInBits = ArgTy->getSizeInBits().getFixedValue();
+
+ if (SizeInBits == 0)
+ return ABIArgInfo::getIgnore();
+
+ if (SizeInBits <= 128) {
+ const Type *CoerceTy;
+ if (SizeInBits <= 64) {
+ auto AlignedBits = alignTo(SizeInBits, 8);
+ CoerceTy = TB.getIntegerType(AlignedBits, Align(8), false);
+ } else {
+ const Type *RegTy = TB.getIntegerType(64, Align(8), false);
+ CoerceTy = TB.getArrayType(RegTy, 2);
+ }
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+ return ABIArgInfo::getIndirect(ArgTy->getAlignment().value());
+ }
+
+ if (const auto *IntTy = dyn_cast<IntegerType>(ArgTy)) {
+ auto BitWidth = IntTy->getSizeInBits().getFixedValue();
+ if (BitWidth > 128)
+ return ABIArgInfo::getIndirect(ArgTy->getAlignment().value());
+ if (isPromotableIntegerType(IntTy)) {
+ const Type *PromotedTy =
+ TB.getIntegerType(32, Align(4), IntTy->isSigned());
+ return ABIArgInfo::getDirect(
+ PromotedTy); // change to getExtend when implemented
+ }
+ }
+
+ return ABIArgInfo::getDirect();
+ }
+};
+
+} // namespace llvm::abi
>From 9bfcba959c3bccfae7763f01cea2ed6f99be4cd5 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Sun, 15 Jun 2025 16:01:47 +0530
Subject: [PATCH 11/11] [LLVMABI] Refactored the BPF Impl
---
clang/include/clang/CodeGen/QualTypeMapper.h | 4 +-
clang/lib/CodeGen/QualTypeMapper.cpp | 35 +---
llvm/include/llvm/ABI/ABIFunctionInfo.h | 199 ++++++++++++++-----
llvm/include/llvm/ABI/ABIInfo.h | 102 +---------
llvm/include/llvm/ABI/Types.h | 18 +-
llvm/lib/ABI/ABIFunctionInfo.cpp | 10 +-
llvm/lib/ABI/CMakeLists.txt | 14 ++
llvm/lib/ABI/Targets/BPF.cpp | 35 ++--
llvm/lib/CMakeLists.txt | 2 +-
9 files changed, 202 insertions(+), 217 deletions(-)
create mode 100644 llvm/lib/ABI/CMakeLists.txt
diff --git a/clang/include/clang/CodeGen/QualTypeMapper.h b/clang/include/clang/CodeGen/QualTypeMapper.h
index 94fc74763a8ee..1c748bc633447 100644
--- a/clang/include/clang/CodeGen/QualTypeMapper.h
+++ b/clang/include/clang/CodeGen/QualTypeMapper.h
@@ -26,7 +26,7 @@
#include "llvm/Support/Allocator.h"
namespace clang {
-namespace mapper {
+namespace CodeGen {
class QualTypeMapper {
private:
@@ -68,7 +68,7 @@ class QualTypeMapper {
llvm::abi::TypeBuilder getTypeBuilder() { return Builder; }
};
-} // namespace mapper
+} // namespace CodeGen
} // namespace clang
#endif // !CLANG_CODEGEN_QUALTYPE_MAPPER_H
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index 420c25975a844..6d2d4618ac2b4 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -28,7 +28,7 @@
#include "llvm/Support/raw_ostream.h"
namespace clang {
-namespace mapper {
+namespace CodeGen {
/// Main entry point for converting Clang QualType to LLVM ABI Type.
/// This method performs type canonicalization, caching, and dispatches
@@ -164,7 +164,8 @@ QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
/// \return LLVM ABI VectorType with element type, count, and alignment
const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
const llvm::abi::Type *ElementType = convertType(VT->getElementType());
- uint64_t NumElements = VT->getNumElements();
+ llvm::ElementCount NumElements =
+ llvm::ElementCount::getFixed(VT->getNumElements());
llvm::Align VectorAlign = getTypeAlign(QualType(VT, 0));
@@ -285,39 +286,13 @@ QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
/// \return LLVM ABI IntegerType representing the enum's underlying type
const llvm::abi::Type *
QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
- if (!ET)
- return Builder.getIntegerType(32, llvm::Align(4), true);
const EnumDecl *ED = ET->getDecl();
- if (!ED)
- return Builder.getIntegerType(32, llvm::Align(4), true);
- if (ED->isInvalidDecl())
- return Builder.getIntegerType(32, llvm::Align(4), true);
-
- if (!ED->isComplete()) {
- if (ED->isFixed()) {
- QualType UnderlyingType = ED->getIntegerType();
- if (!UnderlyingType.isNull()) {
- return convertType(UnderlyingType);
- }
- }
- return Builder.getIntegerType(32, llvm::Align(4), true);
- }
QualType UnderlyingType = ED->getIntegerType();
- if (UnderlyingType.isNull())
- UnderlyingType = ED->getPromotionType();
-
if (UnderlyingType.isNull())
UnderlyingType = ASTCtx.IntTy;
- if (const auto *BT = dyn_cast<BuiltinType>(UnderlyingType.getTypePtr()))
- return convertBuiltinType(BT);
-
- uint64_t TypeSize = ASTCtx.getTypeSize(UnderlyingType);
- llvm::Align TypeAlign = getTypeAlign(UnderlyingType);
- bool IsSigned = UnderlyingType->isSignedIntegerType();
-
- return Builder.getIntegerType(TypeSize, TypeAlign, IsSigned);
+ return convertType(UnderlyingType);
}
/// Converts plain C structs and C++ classes without inheritance.
@@ -400,5 +375,5 @@ void QualTypeMapper::computeFieldInfo(
}
}
-} // namespace mapper
+} // namespace CodeGen
} // namespace clang
diff --git a/llvm/include/llvm/ABI/ABIFunctionInfo.h b/llvm/include/llvm/ABI/ABIFunctionInfo.h
index b0a590373b586..e47015749389b 100644
--- a/llvm/include/llvm/ABI/ABIFunctionInfo.h
+++ b/llvm/include/llvm/ABI/ABIFunctionInfo.h
@@ -14,26 +14,141 @@
#ifndef LLVM_ABI_ABIFUNCTIONINFO_H
#define LLVM_ABI_ABIFUNCTIONINFO_H
-#include "ABIInfo.h"
+#include "llvm/ABI/Types.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/FoldingSet.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/Support/TrailingObjects.h"
namespace llvm {
namespace abi {
-struct FunctionABIInfo {
- llvm::CallingConv::ID CC = llvm::CallingConv::C;
- llvm::CallingConv::ID EffectiveCC = llvm::CallingConv::C;
+/// ABIArgInfo - Helper class to encapsulate information about how a
+/// specific type should be passed to or returned from a function.
+class ABIArgInfo {
+public:
+ enum Kind {
+ Direct,
+ Extend,
+ Indirect,
+ Ignore,
+ Expand,
+ CoerceAndExpand,
+ InAlloca
+ };
+
+private:
+ Kind TheKind;
+ const Type *CoercionType;
+ bool InReg : 1;
+ bool PaddingInReg : 1;
+ bool SignExt : 1;
+ bool ZeroExt : 1;
+ unsigned IndirectAlign : 16;
+ bool IndirectByVal : 1;
+
+ ABIArgInfo(Kind K = Direct)
+ : TheKind(K), CoercionType(nullptr), InReg(false), PaddingInReg(false),
+ SignExt(false), ZeroExt(false), IndirectAlign(0), IndirectByVal(false) {
+ }
+
+public:
+ static ABIArgInfo getDirect(const Type *T = nullptr) {
+ ABIArgInfo AI(Direct);
+ AI.CoercionType = T;
+ return AI;
+ }
+
+ static ABIArgInfo getDirectInReg(const Type *T = nullptr) {
+ ABIArgInfo AI = getDirect(T);
+ AI.InReg = true;
+ return AI;
+ }
+
+ static ABIArgInfo getExtend(const Type *T = nullptr) {
+ ABIArgInfo AI(Extend);
+ AI.CoercionType = T;
+ return AI;
+ }
+
+ ABIArgInfo &setSignExt(bool SignExtend = true) {
+ this->SignExt = SignExtend;
+ if (SignExtend)
+ this->ZeroExt = false;
+ return *this;
+ }
+
+ ABIArgInfo &setZeroExt(bool ZeroExtend = true) {
+ this->ZeroExt = ZeroExtend;
+ if (ZeroExtend)
+ this->SignExt = false;
+ return *this;
+ }
+
+ static ABIArgInfo getIndirect(unsigned Align = 0, bool ByVal = true) {
+ ABIArgInfo AI(Indirect);
+ AI.IndirectAlign = Align;
+ AI.IndirectByVal = ByVal;
+ return AI;
+ }
+
+ static ABIArgInfo getIndirectInReg(unsigned Align = 0, bool ByVal = true) {
+ ABIArgInfo AI = getIndirect(Align, ByVal);
+ AI.InReg = true;
+ return AI;
+ }
+
+ static ABIArgInfo getIgnore() { return ABIArgInfo(Ignore); }
+ static ABIArgInfo getExpand() { return ABIArgInfo(Expand); }
+
+ static ABIArgInfo getCoerceAndExpand(const Type *CoercionType) {
+ ABIArgInfo AI(CoerceAndExpand);
+ AI.CoercionType = CoercionType;
+ return AI;
+ }
+
+ Kind getKind() const { return TheKind; }
+ bool isDirect() const { return TheKind == Direct; }
+ bool isIndirect() const { return TheKind == Indirect; }
+ bool isIgnore() const { return TheKind == Ignore; }
+ bool isExpand() const { return TheKind == Expand; }
+ bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
+ bool isInAlloca() const { return TheKind == InAlloca; }
+ bool isInReg() const { return InReg; }
+ bool hasPaddingInReg() const { return PaddingInReg; }
+
+ unsigned getIndirectAlign() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return IndirectAlign;
+ }
+
+ bool getIndirectByVal() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return IndirectByVal;
+ }
+
+ const Type *getCoerceToType() const {
+ assert((isDirect() || isCoerceAndExpand()) && "Invalid Kind!");
+ return CoercionType;
+ }
+
+ ABIArgInfo &setInReg(bool InReg = true) {
+ this->InReg = InReg;
+ return *this;
+ }
+
+ ABIArgInfo &setPaddingInReg(bool HasPadding = true) {
+ this->PaddingInReg = HasPadding;
+ return *this;
+ }
+};
+
+/// Function-level ABI attributes that affect argument/return passing
+struct ABICallAttributes {
+ CallingConv::ID CC = CallingConv::C;
+ CallingConv::ID EffectiveCC = CallingConv::C;
- // Core ABI attributes
- bool NoReturn = false;
- bool NoUnwind = false;
bool HasSRet = false;
- bool IsVariadic = false;
bool IsInstanceMethod = false;
- // Are these ABI Relavent(?)
bool IsChainCall = false;
bool IsDelegateCall = false;
@@ -41,19 +156,20 @@ struct FunctionABIInfo {
bool HasRegParm = false;
unsigned RegParm = 0;
bool NoCallerSavedRegs = false;
- // Security/extensions(are they ABI related?)
+
+ // Security extensions
bool NoCfCheck = false;
bool CmseNSCall = false;
- // Optimization hints
+ // Memory management
bool ReturnsRetained = false;
unsigned MaxVectorWidth = 0;
- FunctionABIInfo() = default;
- FunctionABIInfo(llvm::CallingConv::ID CC) : CC(CC), EffectiveCC(CC) {}
+ ABICallAttributes() = default;
+ ABICallAttributes(CallingConv::ID CC) : CC(CC), EffectiveCC(CC) {}
};
-// Not an Immediate requirement for BPF
+/// Information about required vs optional arguments for variadic functions
struct RequiredArgs {
private:
unsigned NumRequired;
@@ -72,6 +188,7 @@ struct RequiredArgs {
}
bool allowsOptionalArgs() const { return NumRequired != All; }
+ bool isVariadic() const { return allowsOptionalArgs(); }
unsigned getNumRequiredArgs() const {
return allowsOptionalArgs() ? NumRequired : 0;
@@ -82,8 +199,7 @@ struct RequiredArgs {
}
};
-// Implementation detail of ABIFunctionInfo, factored out so it can be named
-// in the TrailingObjects base class of ABIFunctionInfo.
+/// Argument information for ABIFunctionInfo
struct ABIFunctionInfoArgInfo {
const Type *ABIType;
ABIArgInfo ArgInfo;
@@ -96,17 +212,15 @@ struct ABIFunctionInfoArgInfo {
};
class ABIFunctionInfo final
- : public llvm::FoldingSetNode,
- private TrailingObjects<ABIFunctionInfo, ABIFunctionInfoArgInfo> {
+ : private TrailingObjects<ABIFunctionInfo, ABIFunctionInfoArgInfo> {
typedef ABIFunctionInfoArgInfo ArgInfo;
private:
const Type *ReturnType;
ABIArgInfo ReturnInfo;
unsigned NumArgs;
- FunctionABIInfo ABIInfo;
- RequiredArgs
- Required; // For Variadic Functions but we can focus on this later
+ ABICallAttributes CallAttrs;
+ RequiredArgs Required;
ABIFunctionInfo(const Type *RetTy, unsigned NumArguments)
: ReturnType(RetTy), ReturnInfo(ABIArgInfo::getDirect()),
@@ -116,24 +230,25 @@ class ABIFunctionInfo final
public:
static ABIFunctionInfo *
- create(llvm::CallingConv::ID CC, const Type *ReturnType,
- llvm::ArrayRef<const Type *> ArgTypes,
- const FunctionABIInfo &ABIInfo = FunctionABIInfo(),
+ create(CallingConv::ID CC, const Type *ReturnType,
+ ArrayRef<const Type *> ArgTypes,
+ const ABICallAttributes &CallAttrs = ABICallAttributes(),
RequiredArgs Required = RequiredArgs());
const Type *getReturnType() const { return ReturnType; }
ABIArgInfo &getReturnInfo() { return ReturnInfo; }
const ABIArgInfo &getReturnInfo() const { return ReturnInfo; }
- llvm::CallingConv::ID getCallingConvention() const { return ABIInfo.CC; }
-
- const FunctionABIInfo &getExtInfo() const { return ABIInfo; }
+ CallingConv::ID getCallingConvention() const { return CallAttrs.CC; }
+ const ABICallAttributes &getCallAttributes() const { return CallAttrs; }
RequiredArgs getRequiredArgs() const { return Required; }
- llvm::ArrayRef<ArgInfo> arguments() const {
+ bool isVariadic() const { return Required.isVariadic(); }
+
+ ArrayRef<ArgInfo> arguments() const {
return {getTrailingObjects<ArgInfo>(), NumArgs};
}
- llvm::MutableArrayRef<ArgInfo> arguments() {
+ MutableArrayRef<ArgInfo> arguments() {
return {getTrailingObjects<ArgInfo>(), NumArgs};
}
@@ -146,27 +261,11 @@ class ABIFunctionInfo final
assert(Index < NumArgs && "Invalid argument index");
return arguments()[Index];
}
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(static_cast<unsigned>(ABIInfo.CC));
- ID.AddPointer(ReturnType);
- ID.AddInteger(static_cast<unsigned>(ReturnInfo.getKind()));
- if (ReturnInfo.getCoerceToType())
- ID.AddPointer(ReturnInfo.getCoerceToType());
- ID.AddInteger(NumArgs);
- for (const auto &ArgInfo : arguments()) {
- ID.AddPointer(ArgInfo.ABIType);
- ID.AddInteger(static_cast<unsigned>(ArgInfo.ArgInfo.getKind()));
- if (ArgInfo.ArgInfo.getCoerceToType())
- ID.AddPointer(ArgInfo.ArgInfo.getCoerceToType());
- }
- ID.AddInteger(Required.getNumRequiredArgs());
- ID.AddBoolean(Required.allowsOptionalArgs());
- ID.AddBoolean(ABIInfo.NoReturn);
- ID.AddBoolean(ABIInfo.IsVariadic);
- // TODO: Add more flags
- }
+
+ unsigned getNumArgs() const { return NumArgs; }
};
+
} // namespace abi
} // namespace llvm
-#endif // !LLVM_ABI_ABIFUNCTIONINFO_H
+#endif // LLVM_ABI_ABIFUNCTIONINFO_H
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
index aa56dd5e96f2c..48d289331746c 100644
--- a/llvm/include/llvm/ABI/ABIInfo.h
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -14,107 +14,13 @@
#ifndef LLVM_ABI_ABIINFO_H
#define LLVM_ABI_ABIINFO_H
+#include "llvm/ABI/ABIFunctionInfo.h"
#include "llvm/ABI/Types.h"
#include <cassert>
namespace llvm {
namespace abi {
-/// ABIArgInfo - Helper class to encapsulate information about how a
-/// specific C type should be passed to or returned from a function.
-class ABIArgInfo {
-public:
- enum Kind { Direct, Indirect, Ignore, Expand, CoerceAndExpand, InAlloca };
-
-private:
- Kind TheKind;
- const Type *CoercionType;
-
- bool InReg : 1;
- bool PaddingInReg : 1;
-
- unsigned IndirectAlign : 16;
- bool IndirectByVal : 1;
-
- ABIArgInfo(Kind K = Direct)
- : TheKind(K), CoercionType(nullptr), InReg(false), PaddingInReg(false),
- IndirectAlign(0), IndirectByVal(false) {}
-
-public:
- static ABIArgInfo getDirect(const Type *T = nullptr) {
- ABIArgInfo AI(Direct);
- AI.CoercionType = T;
- return AI;
- }
-
- static ABIArgInfo getDirectInReg(const Type *T = nullptr) {
- ABIArgInfo AI = getDirect(T);
- AI.InReg = true;
- return AI;
- }
-
- static ABIArgInfo getIndirect(unsigned Align = 0, bool ByVal = true) {
- ABIArgInfo AI(Indirect);
- AI.IndirectAlign = Align;
- AI.IndirectByVal = ByVal;
- return AI;
- }
-
- static ABIArgInfo getIndirectInReg(unsigned Align = 0, bool ByVal = true) {
- ABIArgInfo AI = getIndirect(Align, ByVal);
- AI.InReg = true;
- return AI;
- }
-
- static ABIArgInfo getIgnore() { return ABIArgInfo(Ignore); }
-
- static ABIArgInfo getExpand() { return ABIArgInfo(Expand); }
-
- static ABIArgInfo getCoerceAndExpand(const Type *CoercionType) {
- ABIArgInfo AI(CoerceAndExpand);
- AI.CoercionType = CoercionType;
- return AI;
- }
-
- Kind getKind() const { return TheKind; }
-
- bool isDirect() const { return TheKind == Direct; }
- bool isIndirect() const { return TheKind == Indirect; }
- bool isIgnore() const { return TheKind == Ignore; }
- bool isExpand() const { return TheKind == Expand; }
- bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
- bool isInAlloca() const { return TheKind == InAlloca; }
-
- bool isInReg() const { return InReg; }
- bool hasPaddingInReg() const { return PaddingInReg; }
-
- unsigned getIndirectAlign() const {
- assert(isIndirect() && "Only indirect arguments have alignment");
- return IndirectAlign;
- }
-
- bool getIndirectByVal() const {
- assert(isIndirect() && "Only indirect arguments can be ByVal");
- return IndirectByVal;
- }
-
- const Type *getCoerceToType() const {
- assert((isDirect() || isCoerceAndExpand()) &&
- "Only Direct and CoerceAndExpand arguments can have coercion types");
- return CoercionType;
- }
-
- ABIArgInfo &setInReg(bool InReg = true) {
- this->InReg = InReg;
- return *this;
- }
-
- ABIArgInfo &setPaddingInReg(bool HasPadding = true) {
- this->PaddingInReg = HasPadding;
- return *this;
- }
-};
-
/// Abstract base class for target-specific ABI information.
class ABIInfo {
public:
@@ -122,12 +28,8 @@ class ABIInfo {
virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
-
+ void computeInfo(ABIFunctionInfo &FI) const;
virtual bool isPassByRef(const Type *Ty) const { return false; }
-
- virtual unsigned getTypeAlignment(const Type *Ty) const = 0;
-
- virtual unsigned getTypeSize(const Type *Ty) const = 0;
};
} // namespace abi
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index e4642142662d3..9395e377522bc 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -139,15 +139,11 @@ class VectorType : public Type {
public:
VectorType(const Type *ElemType, ElementCount NumElems, Align Align)
- : Type(
- TypeKind::Vector,
- NumElems.isScalable()
- ? TypeSize(ElemType->getSizeInBits().getFixedValue() *
- NumElems.getKnownMinValue(),
- true)
- : TypeSize::getFixed(ElemType->getSizeInBits().getFixedValue() *
- NumElems.getFixedValue()),
- Align),
+ : Type(TypeKind::Vector,
+ TypeSize(ElemType->getSizeInBits().getFixedValue() *
+ NumElems.getKnownMinValue(),
+ NumElems.isScalable()),
+ Align),
ElementType(ElemType), NumElements(NumElems) {}
const Type *getElementType() const { return ElementType; }
@@ -243,8 +239,8 @@ class TypeBuilder {
ArrayType(ElementType, NumElements);
}
- const VectorType *getVectorType(const Type *ElementType, uint64_t NumElements,
- Align Align) {
+ const VectorType *getVectorType(const Type *ElementType,
+ ElementCount NumElements, Align Align) {
return new (Allocator.Allocate<VectorType>())
VectorType(ElementType, NumElements, Align);
}
diff --git a/llvm/lib/ABI/ABIFunctionInfo.cpp b/llvm/lib/ABI/ABIFunctionInfo.cpp
index f0a75fa7f8151..eed444e9837b3 100644
--- a/llvm/lib/ABI/ABIFunctionInfo.cpp
+++ b/llvm/lib/ABI/ABIFunctionInfo.cpp
@@ -11,10 +11,10 @@
using namespace llvm;
using namespace llvm::abi;
-ABIFunctionInfo *ABIFunctionInfo::create(llvm::CallingConv::ID CC,
+ABIFunctionInfo *ABIFunctionInfo::create(CallingConv::ID CC,
const Type *ReturnType,
- llvm::ArrayRef<const Type *> ArgTypes,
- const FunctionABIInfo &ABIInfo,
+ ArrayRef<const Type *> ArgTypes,
+ const ABICallAttributes &CallAttrs,
RequiredArgs Required) {
assert(!Required.allowsOptionalArgs() ||
@@ -26,8 +26,8 @@ ABIFunctionInfo *ABIFunctionInfo::create(llvm::CallingConv::ID CC,
ABIFunctionInfo *FI =
new (Buffer) ABIFunctionInfo(ReturnType, ArgTypes.size());
- FI->ABIInfo = ABIInfo;
- FI->ABIInfo.CC = CC;
+ FI->CallAttrs = CallAttrs;
+ FI->CallAttrs.CC = CC;
FI->Required = Required;
auto Args = FI->arguments();
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
new file mode 100644
index 0000000000000..f4b74f551c720
--- /dev/null
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_llvm_component_library(LLVMABI
+ ABIFunctionInfo.cpp
+ Targets/BPF.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
+
+ DEPENDS
+ intrinsics_gen
+
+ LINK_COMPONENTS
+ Core
+ Support
+)
diff --git a/llvm/lib/ABI/Targets/BPF.cpp b/llvm/lib/ABI/Targets/BPF.cpp
index 52aff3ca368bd..ae2752eb0c50d 100644
--- a/llvm/lib/ABI/Targets/BPF.cpp
+++ b/llvm/lib/ABI/Targets/BPF.cpp
@@ -1,4 +1,4 @@
-//===- BPF.cpp ------------------------------------------------------------===//
+//===- BPF.cpp - BPF ABI Implementation ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ABI/ABIFunctionInfo.h"
#include "llvm/ABI/ABIInfo.h"
#include "llvm/ABI/Types.h"
#include "llvm/Support/Alignment.h"
@@ -18,18 +19,7 @@ class BPFABIInfo : public ABIInfo {
TypeBuilder &TB;
bool isAggregateType(const Type *Ty) const {
- return Ty->isStruct() || Ty->isUnion() || Ty->isArray() ||
- (Ty->isVector() && !isSimpleVector(dyn_cast<VectorType>(Ty)));
- }
-
- bool isSimpleVector(const VectorType *VecTy) const {
- const Type *ElemTy = VecTy->getElementType();
-
- if (!ElemTy->isInteger() && !ElemTy->isFloat())
- return false;
-
- auto VecSizeInBits = VecTy->getSizeInBits().getFixedValue();
- return VecSizeInBits <= 128;
+ return Ty->isStruct() || Ty->isUnion() || Ty->isArray();
}
bool isPromotableIntegerType(const IntegerType *IntTy) const {
@@ -46,10 +36,8 @@ class BPFABIInfo : public ABIInfo {
if (isAggregateType(RetTy)) {
auto SizeInBits = RetTy->getSizeInBits().getFixedValue();
-
if (SizeInBits == 0)
return ABIArgInfo::getIgnore();
-
return ABIArgInfo::getIndirect(RetTy->getAlignment().value());
}
@@ -65,7 +53,6 @@ class BPFABIInfo : public ABIInfo {
ABIArgInfo classifyArgumentType(const Type *ArgTy) const override {
if (isAggregateType(ArgTy)) {
auto SizeInBits = ArgTy->getSizeInBits().getFixedValue();
-
if (SizeInBits == 0)
return ABIArgInfo::getIgnore();
@@ -80,6 +67,7 @@ class BPFABIInfo : public ABIInfo {
}
return ABIArgInfo::getDirect(CoerceTy);
}
+
return ABIArgInfo::getIndirect(ArgTy->getAlignment().value());
}
@@ -87,16 +75,27 @@ class BPFABIInfo : public ABIInfo {
auto BitWidth = IntTy->getSizeInBits().getFixedValue();
if (BitWidth > 128)
return ABIArgInfo::getIndirect(ArgTy->getAlignment().value());
+
if (isPromotableIntegerType(IntTy)) {
const Type *PromotedTy =
TB.getIntegerType(32, Align(4), IntTy->isSigned());
- return ABIArgInfo::getDirect(
- PromotedTy); // change to getExtend when implemented
+ auto AI = ABIArgInfo::getExtend(PromotedTy);
+
+ IntTy->isSigned() ? AI.setSignExt() : AI.setZeroExt();
+
+ return AI;
}
}
return ABIArgInfo::getDirect();
}
+
+ void computeInfo(ABIFunctionInfo &FI) {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments()) {
+ I.ArgInfo = classifyArgumentType(I.ABIType);
+ }
+ }
};
} // namespace llvm::abi
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index c84690abda028..b888f6637a925 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -3,7 +3,7 @@ include(LLVM-Build)
# `Demangle', `Support' and `TableGen' libraries are added on the top-level
# CMakeLists.txt
-# add_subdirectory(ABI)
+add_subdirectory(ABI)
add_subdirectory(IR)
add_subdirectory(FuzzMutate)
add_subdirectory(FileCheck)
More information about the llvm-commits
mailing list