[clang] [llvm] [WIP] ABI Lowering Library (PR #140112)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 17 20:45:24 PDT 2025
https://github.com/vortex73 updated https://github.com/llvm/llvm-project/pull/140112
>From 385f2e52c334a0a0aeba438db8b1844384a87213 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/17] [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 c86bbafb47b4fc1490c2091aceae129a090e6f07 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/17] [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 f60d02712f6b880b9231f5bfd5fc6a0ab51bda59 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/17] [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 a56183000f085..4d818c83a472d 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 2a9eb437edfb06368c1a9afa76b47494536941ef 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/17] [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 4d818c83a472d..06b4a55678b1d 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 6206f586cc2c14a6a795e96f8b6d1b7df2a1a917 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/17] [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 0f2a352886e7f..53a14ad6a47e3 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 4a977a80de3fd5ce07d213f452891c30159d509d 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/17] [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 53a14ad6a47e3..d83f3df933ef6 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 4b7d09179f5242adf6f591714ddb4f568c640260 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/17] [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 8a78809780abbcd0164f5e4759a6f4422b80af7c 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/17] [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 3ed33c726875e41b5288ea4482bb168f4d098ca1 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/17] [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 1af2559215d8f5de985ca26d89ffa3af57361bfe 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/17] [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 7a66952a990c014e93a671229ae76d7d33b86262 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/17] [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 06b4a55678b1d..4d818c83a472d 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 b94f68940c4ff86fdf7a9d8798cc0540d5868af1 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Sat, 21 Jun 2025 19:07:52 +0530
Subject: [PATCH 12/17] [LLVMABI] clang integration
---
clang/lib/CodeGen/CGCall.cpp | 101 ++++++++++-
clang/lib/CodeGen/CMakeLists.txt | 1 +
clang/lib/CodeGen/CodeGenModule.cpp | 13 ++
clang/lib/CodeGen/CodeGenModule.h | 5 +
clang/lib/CodeGen/CodeGenTypes.cpp | 3 +-
clang/lib/CodeGen/CodeGenTypes.h | 12 ++
clang/lib/CodeGen/QualTypeMapper.cpp | 3 +-
llvm/include/llvm/ABI/ABIFunctionInfo.h | 5 +-
llvm/include/llvm/ABI/ABIInfo.h | 2 +-
llvm/include/llvm/ABI/ABITypeMapper.h | 67 +++++++
llvm/include/llvm/ABI/TargetCodegenInfo.h | 58 ++++++
llvm/include/llvm/ABI/Types.h | 9 +-
llvm/lib/ABI/ABITypeMapper.cpp | 208 ++++++++++++++++++++++
llvm/lib/ABI/CMakeLists.txt | 2 +
llvm/lib/ABI/TargetCodeGenInfo.cpp | 23 +++
llvm/lib/ABI/Targets/BPF.cpp | 13 +-
16 files changed, 511 insertions(+), 14 deletions(-)
create mode 100644 llvm/include/llvm/ABI/ABITypeMapper.h
create mode 100644 llvm/include/llvm/ABI/TargetCodegenInfo.h
create mode 100644 llvm/lib/ABI/ABITypeMapper.cpp
create mode 100644 llvm/lib/ABI/TargetCodeGenInfo.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index b959982809911..336d3e6ce2a3e 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -30,7 +30,11 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/QualTypeMapper.h"
#include "clang/CodeGen/SwiftCallingConv.h"
+#include "llvm/ABI/ABIFunctionInfo.h"
+#include "llvm/ABI/ABITypeMapper.h"
+#include "llvm/ABI/Types.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Assumptions.h"
@@ -42,6 +46,8 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Utils/Local.h"
#include <optional>
using namespace clang;
@@ -825,6 +831,47 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
}
} // namespace clang
+ABIArgInfo CodeGenTypes::convertABIArgInfo(const llvm::abi::ABIArgInfo &abiInfo,
+ QualType type) {
+ ABIArgInfo result;
+
+ if (abiInfo.isDirect()) {
+ llvm::Type *CoercedType = nullptr;
+ if (abiInfo.getCoerceToType()) {
+ CoercedType = ReverseMapper.convertType(abiInfo.getCoerceToType());
+ }
+ if (!CoercedType) {
+ CoercedType = ConvertType(type);
+ }
+ result = ABIArgInfo::getDirect(CoercedType);
+ } else if (abiInfo.isExtend()) {
+ llvm::Type *CoercedType = nullptr;
+ if (abiInfo.getCoerceToType()) {
+ CoercedType = ReverseMapper.convertType(abiInfo.getCoerceToType());
+ }
+ if (!CoercedType) {
+ CoercedType = ConvertType(type);
+ }
+
+ if (abiInfo.isSignExt()) {
+ result = ABIArgInfo::getSignExtend(type, CoercedType);
+ } else {
+ result = ABIArgInfo::getZeroExtend(type, CoercedType);
+ }
+ } else if (abiInfo.isIndirect()) {
+ result = ABIArgInfo::getIndirect(
+ CharUnits::fromQuantity(abiInfo.getIndirectAlign()), 0);
+ } else if (abiInfo.isIgnore()) {
+ result = ABIArgInfo::getIgnore();
+ }
+
+ if (abiInfo.isInReg()) {
+ result.setInReg(true);
+ }
+
+ return result;
+}
+
/// Arrange the argument and result information for an abstract value
/// of a given function type. This is the method which all of the
/// above functions ultimately defer to.
@@ -849,6 +896,7 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
void *insertPos = nullptr;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
+ llvm::abi::ABIFunctionInfo *tempFI;
if (FI)
return *FI;
@@ -857,12 +905,21 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
// Construct the function info. We co-allocate the ArgInfos.
FI = CGFunctionInfo::create(CC, isInstanceMethod, isChainCall, isDelegateCall,
info, paramInfos, resultType, argTypes, required);
+
+ SmallVector<const llvm::abi::Type *, 8> MappedArgTypes;
+ for (CanQualType ArgType : argTypes) {
+ MappedArgTypes.push_back(Mapper.convertType(ArgType));
+ }
+ tempFI = llvm::abi::ABIFunctionInfo::create(
+ CC, Mapper.convertType(resultType), MappedArgTypes);
FunctionInfos.InsertNode(FI, insertPos);
bool inserted = FunctionsBeingProcessed.insert(FI).second;
(void)inserted;
assert(inserted && "Recursively being processed?");
+ bool isBPF = CGM.getTriple().isBPF();
+
// Compute ABI information.
if (CC == llvm::CallingConv::SPIR_KERNEL) {
// Force target independent argument handling for the host visible
@@ -871,20 +928,50 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
} else if (info.getCC() == CC_Swift || info.getCC() == CC_SwiftAsync) {
swiftcall::computeABIInfo(CGM, *FI);
} else {
- CGM.getABIInfo().computeInfo(*FI);
+ if (isBPF)
+ CGM.fetchABIInfo(TB).computeInfo(*tempFI);
+ else
+ CGM.getABIInfo().computeInfo(*FI);
}
// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
- ABIArgInfo &retInfo = FI->getReturnInfo();
- if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
- retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
+ if (isBPF && tempFI) {
+
+ const auto &abiRetInfo = tempFI->getReturnInfo();
+ ABIArgInfo &cgRetInfo = FI->getReturnInfo();
+
+ cgRetInfo = convertABIArgInfo(abiRetInfo, FI->getReturnType());
+
+ unsigned numArgs = std::min(FI->arg_size(), tempFI->getNumArgs());
+ unsigned argIndex = 0;
+
+ for (auto &cgArg : FI->arguments()) {
+ if (argIndex >= numArgs)
+ break;
- for (auto &I : FI->arguments())
- if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr)
- I.info.setCoerceToType(ConvertType(I.type));
+ const auto &abiArgInfo = tempFI->getArgInfo(argIndex);
+ cgArg.info = convertABIArgInfo(abiArgInfo.ArgInfo, cgArg.type);
+ if (abiArgInfo.ArgInfo.isInReg())
+ cgArg.info.setInReg(true);
+
+ argIndex++;
+ }
+ } else {
+ // Non-BPF path: handle coerce types for direct/extend cases
+ ABIArgInfo &retInfo = FI->getReturnInfo();
+ if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr) {
+ retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
+ }
+
+ for (auto &I : FI->arguments()) {
+ if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr) {
+ I.info.setCoerceToType(ConvertType(I.type));
+ }
+ }
+ }
bool erased = FunctionsBeingProcessed.erase(FI);
(void)erased;
assert(erased && "Not in set?");
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index d83f3df933ef6..3f320f037c33f 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
AggressiveInstCombine
+ ABI
Analysis
BitReader
BitWriter
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 2d37e0f13199b..9ff79b1a48060 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -47,6 +47,7 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ABI/TargetCodegenInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -72,6 +73,7 @@
#include "llvm/TargetParser/Triple.h"
#include "llvm/TargetParser/X86TargetParser.h"
#include "llvm/Transforms/Utils/BuildLibCalls.h"
+#include <memory>
#include <optional>
#include <set>
@@ -104,6 +106,17 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
llvm_unreachable("invalid C++ ABI kind");
}
+static std::unique_ptr<llvm::abi::TargetCodeGenInfo>
+makeTargetCodeGenInfo(llvm::abi::TypeBuilder &TB) {
+ return llvm::abi::createBPFTargetCodeGenInfo(TB);
+}
+
+const llvm::abi::ABIInfo &
+CodeGenModule::fetchABIInfo(llvm::abi::TypeBuilder &TB) {
+ newTargetCodeGenInfo = makeTargetCodeGenInfo(TB);
+ return newTargetCodeGenInfo->getABIInfo();
+}
+
static std::unique_ptr<TargetCodeGenInfo>
createTargetCodeGenInfo(CodeGenModule &CGM) {
const TargetInfo &Target = CGM.getTarget();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index cb013feb769fc..3d58ede2b7cc4 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -30,6 +30,9 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/XRayLists.h"
#include "clang/Lex/PreprocessorOptions.h"
+#include "llvm/ABI/ABIInfo.h"
+#include "llvm/ABI/TargetCodegenInfo.h"
+#include "llvm/ABI/Types.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
@@ -361,6 +364,7 @@ class CodeGenModule : public CodeGenTypeCache {
std::unique_ptr<CodeGenTBAA> TBAA;
mutable std::unique_ptr<TargetCodeGenInfo> TheTargetCodeGenInfo;
+ mutable std::unique_ptr<llvm::abi::TargetCodeGenInfo> newTargetCodeGenInfo;
// This should not be moved earlier, since its initialization depends on some
// of the previous reference members being already initialized and also checks
@@ -838,6 +842,7 @@ class CodeGenModule : public CodeGenTypeCache {
void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO);
const ABIInfo &getABIInfo();
+ const llvm::abi::ABIInfo &fetchABIInfo(llvm::abi::TypeBuilder &TB);
CGCXXABI &getCXXABI() const { return *ABI; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index f2a0a649a88fd..1359e65715ce8 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -33,7 +33,8 @@ using namespace CodeGen;
CodeGenTypes::CodeGenTypes(CodeGenModule &cgm)
: CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()),
- Target(cgm.getTarget()) {
+ Target(cgm.getTarget()), TB(Alloc), Mapper(cgm.getContext(), Alloc),
+ ReverseMapper(getLLVMContext()) {
SkippedLayout = false;
LongDoubleReferenced = false;
}
diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index 29f6f1ec80bc3..186dec8aec525 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -16,6 +16,10 @@
#include "CGCall.h"
#include "clang/Basic/ABI.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/QualTypeMapper.h"
+#include "llvm/ABI/ABIFunctionInfo.h"
+#include "llvm/ABI/ABITypeMapper.h"
+#include "llvm/ABI/Types.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/Module.h"
@@ -92,6 +96,11 @@ class CodeGenTypes {
/// Helper for ConvertType.
llvm::Type *ConvertFunctionTypeInternal(QualType FT);
+ mutable llvm::BumpPtrAllocator Alloc;
+ mutable llvm::abi::TypeBuilder TB;
+ mutable QualTypeMapper Mapper;
+ llvm::ABITypeMapper ReverseMapper;
+
public:
CodeGenTypes(CodeGenModule &cgm);
~CodeGenTypes();
@@ -273,6 +282,9 @@ class CodeGenTypes {
const FunctionProtoType *FTP,
const CXXMethodDecl *MD);
+ ABIArgInfo convertABIArgInfo(const llvm::abi::ABIArgInfo &abiInfo,
+ QualType type);
+
/// "Arrange" the LLVM information for a call or type with the given
/// signature. This is largely an internal method; other clients
/// should use one of the above routines, which ultimately defer to
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index 6d2d4618ac2b4..b4c8aa5663a46 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -76,7 +76,8 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(LangAS::Default));
return Builder.getPointerType(PointerSize, PointerAlign);
} else {
- llvm_unreachable("Unsupported type for ABI lowering");
+ QT.dump();
+ llvm::errs() << "[UNHANDLED TYPE]\n";
}
TypeCache[QT] = Result;
return Result;
diff --git a/llvm/include/llvm/ABI/ABIFunctionInfo.h b/llvm/include/llvm/ABI/ABIFunctionInfo.h
index e47015749389b..d6a07b0cc283a 100644
--- a/llvm/include/llvm/ABI/ABIFunctionInfo.h
+++ b/llvm/include/llvm/ABI/ABIFunctionInfo.h
@@ -110,10 +110,12 @@ class ABIArgInfo {
bool isDirect() const { return TheKind == Direct; }
bool isIndirect() const { return TheKind == Indirect; }
bool isIgnore() const { return TheKind == Ignore; }
+ bool isExtend() const { return TheKind == Extend; }
bool isExpand() const { return TheKind == Expand; }
bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
bool isInAlloca() const { return TheKind == InAlloca; }
bool isInReg() const { return InReg; }
+ bool isSignExt() const { return SignExt; }
bool hasPaddingInReg() const { return PaddingInReg; }
unsigned getIndirectAlign() const {
@@ -127,7 +129,8 @@ class ABIArgInfo {
}
const Type *getCoerceToType() const {
- assert((isDirect() || isCoerceAndExpand()) && "Invalid Kind!");
+ assert((isDirect() || isExtend() || isCoerceAndExpand()) &&
+ "Invalid Kind!");
return CoercionType;
}
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
index 48d289331746c..3a18c8cf029f7 100644
--- a/llvm/include/llvm/ABI/ABIInfo.h
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -28,7 +28,7 @@ class ABIInfo {
virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
- void computeInfo(ABIFunctionInfo &FI) const;
+ virtual void computeInfo(ABIFunctionInfo &FI) const = 0;
virtual bool isPassByRef(const Type *Ty) const { return false; }
};
diff --git a/llvm/include/llvm/ABI/ABITypeMapper.h b/llvm/include/llvm/ABI/ABITypeMapper.h
new file mode 100644
index 0000000000000..f326ca00dc392
--- /dev/null
+++ b/llvm/include/llvm/ABI/ABITypeMapper.h
@@ -0,0 +1,67 @@
+//===---- ABITypeMapper.h - Maps LLVM ABI Types to LLVM IR 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 LLVM ABI type representations back to corresponding LLVM IR types.
+/// This reverse mapper translates low-level ABI-specific types back into
+/// LLVM IR types suitable for code generation and optimization passes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_ABITYPEMAPPER_H
+#define LLVM_CODEGEN_ABITYPEMAPPER_H
+
+#include "llvm/ABI/Types.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/TypeSize.h"
+
+namespace llvm {
+
+class ABITypeMapper {
+public:
+ explicit ABITypeMapper(LLVMContext &Ctx) : Context(Ctx) {}
+
+ Type *convertType(const abi::Type *ABIType);
+
+ void clearCache() { TypeCache.clear(); }
+
+private:
+ LLVMContext &Context;
+
+ DenseMap<const abi::Type *, Type *> TypeCache;
+
+ Type *convertIntegerType(const abi::IntegerType *IT);
+
+ Type *convertFloatType(const abi::FloatType *FT);
+
+ Type *convertPointerType(const abi::PointerType *PT);
+
+ Type *convertArrayType(const abi::ArrayType *AT);
+
+ Type *convertVectorType(const abi::VectorType *VT);
+
+ Type *convertStructType(const abi::StructType *ST);
+
+ Type *convertUnionType(const abi::UnionType *UT);
+
+ Type *convertVoidType(const abi::VoidType *VT);
+
+ Type *getFloatTypeForSemantics(const fltSemantics &Semantics);
+
+ StructType *createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
+ uint32_t NumFields, TypeSize Size,
+ Align Alignment, bool IsUnion = false);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_ABITYPEMAPPER_H
diff --git a/llvm/include/llvm/ABI/TargetCodegenInfo.h b/llvm/include/llvm/ABI/TargetCodegenInfo.h
new file mode 100644
index 0000000000000..54110bb3bc1ec
--- /dev/null
+++ b/llvm/include/llvm/ABI/TargetCodegenInfo.h
@@ -0,0 +1,58 @@
+#include "llvm/ABI/ABIInfo.h"
+#include <memory>
+
+#ifndef LLVM_ABI_TARGETCODEGENINFO_H
+#define LLVM_ABI_TARGETCODEGENINFO_H
+
+namespace llvm::abi {
+
+class TargetCodeGenInfo {
+ std::unique_ptr<llvm::abi::ABIInfo> Info;
+
+protected:
+ template <typename T> const T getABIInfo() const {
+ return static_cast<const T &>(*Info);
+ }
+
+public:
+ TargetCodeGenInfo(std::unique_ptr<llvm::abi::ABIInfo> Info);
+ virtual ~TargetCodeGenInfo();
+
+ const ABIInfo &getABIInfo() const { return *Info; }
+
+ virtual void computeInfo(ABIFunctionInfo &FI) const;
+};
+
+std::unique_ptr<TargetCodeGenInfo>
+createDefaultTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo> createBPFTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createX8664TargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createAArch64TargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo> createARMTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createRISCVTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createPPC64TargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createSystemZTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createWebAssemblyTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createNVPTXTargetCodeGenInfo(TypeBuilder &TB);
+
+std::unique_ptr<TargetCodeGenInfo>
+createAMDGPUTargetCodeGenInfo(TypeBuilder &TB);
+} // namespace llvm::abi
+
+#endif
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 9395e377522bc..518c0e6cc2dd4 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -102,14 +102,19 @@ class FloatType : public Type {
TypeSize::getFixed(APFloat::getSizeInBits(FloatSemantics)), Align),
Semantics(&FloatSemantics) {}
+ const fltSemantics *getSemantics() { return Semantics; }
static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
};
class PointerType : public Type {
+ unsigned AddrSpace;
+
public:
- PointerType(uint64_t Size, Align Align)
- : Type(TypeKind::Pointer, TypeSize::getFixed(Size), Align) {}
+ PointerType(uint64_t Size, Align Align, unsigned AddressSpace = 0)
+ : Type(TypeKind::Pointer, TypeSize::getFixed(Size), Align),
+ AddrSpace(AddressSpace) {}
+ unsigned getAddrSpace() const { return AddrSpace; }
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Pointer;
}
diff --git a/llvm/lib/ABI/ABITypeMapper.cpp b/llvm/lib/ABI/ABITypeMapper.cpp
new file mode 100644
index 0000000000000..8aee6e8d4b8b3
--- /dev/null
+++ b/llvm/lib/ABI/ABITypeMapper.cpp
@@ -0,0 +1,208 @@
+//===---- ABITypeMapper.cpp - Maps LLVM ABI Types to LLVM IR 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 LLVM ABI type representations back to corresponding LLVM IR types.
+/// This reverse mapper translates low-level ABI-specific types back into
+/// LLVM IR types suitable for code generation and optimization passes.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ABI/ABITypeMapper.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+Type *ABITypeMapper::convertType(const abi::Type *ABIType) {
+ if (!ABIType)
+ return nullptr;
+
+ auto It = TypeCache.find(ABIType);
+ if (It != TypeCache.end())
+ return It->second;
+
+ Type *Result = nullptr;
+
+ switch (ABIType->getKind()) {
+ case abi::TypeKind::Integer:
+ Result = IntegerType::get(Context,
+ cast<abi::IntegerType>(ABIType)->getSizeInBits());
+ break;
+ case abi::TypeKind::Float:
+ Result = convertFloatType(cast<abi::FloatType>(ABIType));
+ break;
+ case abi::TypeKind::Pointer:
+ Result = PointerType::get(Context,
+ cast<abi::PointerType>(ABIType)->getAddrSpace());
+ break;
+ case abi::TypeKind::Array:
+ Result = convertArrayType(cast<abi::ArrayType>(ABIType));
+ break;
+ case abi::TypeKind::Vector:
+ Result = convertVectorType(cast<abi::VectorType>(ABIType));
+ break;
+ case abi::TypeKind::Struct:
+ Result = convertStructType(cast<abi::StructType>(ABIType));
+ break;
+ case abi::TypeKind::Union:
+ Result = convertUnionType(cast<abi::UnionType>(ABIType));
+ break;
+ case abi::TypeKind::Void:
+ Result = Type::getVoidTy(Context);
+ break;
+ }
+
+ if (Result)
+ TypeCache[ABIType] = Result;
+
+ return Result;
+}
+
+Type *ABITypeMapper::convertFloatType(const abi::FloatType *FT) {
+ const fltSemantics *Semantics =
+ const_cast<abi::FloatType *>(FT)->getSemantics();
+ return Type::getFloatingPointTy(Context, *Semantics);
+}
+
+Type *ABITypeMapper::convertArrayType(const abi::ArrayType *AT) {
+ Type *ElementType = convertType(AT->getElementType());
+ if (!ElementType)
+ return nullptr;
+
+ uint64_t NumElements = AT->getNumElements();
+
+ return ArrayType::get(ElementType, NumElements);
+}
+
+Type *ABITypeMapper::convertVectorType(const abi::VectorType *VT) {
+ Type *ElementType = convertType(VT->getElementType());
+ if (!ElementType)
+ return nullptr;
+
+ ElementCount EC = VT->getNumElements();
+
+ if (EC.isScalable())
+ return ScalableVectorType::get(ElementType, EC.getKnownMinValue());
+ return VectorType::get(ElementType, EC);
+}
+
+Type *ABITypeMapper::convertStructType(const abi::StructType *ST) {
+ return createStructFromFields(*ST->getFields(), ST->getNumFields(),
+ ST->getSizeInBits(), ST->getAlignment(), false);
+}
+
+Type *ABITypeMapper::convertUnionType(const abi::UnionType *UT) {
+ return createStructFromFields(*UT->getFields(), UT->getNumFields(),
+ UT->getSizeInBits(), UT->getAlignment(), true);
+}
+
+StructType *
+ABITypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
+ uint32_t NumFields, TypeSize Size,
+ Align Alignment, bool IsUnion) {
+ SmallVector<Type *, 16> FieldTypes;
+
+ if (IsUnion) {
+ Type *LargestFieldType = nullptr;
+ uint64_t LargestFieldSize = 0;
+
+ for (const auto &Field : Fields) {
+ Type *FieldType = convertType(Field.FieldType);
+ if (!FieldType)
+ continue;
+
+ uint64_t FieldSize = 0;
+ if (auto *IntTy = dyn_cast<IntegerType>(FieldType)) {
+ FieldSize = IntTy->getBitWidth();
+ } else if (FieldType->isFloatingPointTy()) {
+ FieldSize = FieldType->getPrimitiveSizeInBits();
+ } else if (FieldType->isPointerTy()) {
+ FieldSize = 64; // Assume 64-bit pointers
+ }
+
+ if (FieldSize > LargestFieldSize) {
+ LargestFieldSize = FieldSize;
+ LargestFieldType = FieldType;
+ }
+ }
+
+ if (LargestFieldType) {
+ FieldTypes.push_back(LargestFieldType);
+
+ uint64_t UnionSizeBits = Size.getFixedValue();
+ if (LargestFieldSize < UnionSizeBits) {
+ uint64_t PaddingBits = UnionSizeBits - LargestFieldSize;
+ if (PaddingBits % 8 == 0) {
+ Type *ByteType = IntegerType::get(Context, 8);
+ Type *PaddingType = ArrayType::get(ByteType, PaddingBits / 8);
+ FieldTypes.push_back(PaddingType);
+ } else {
+ Type *PaddingType = IntegerType::get(Context, PaddingBits);
+ FieldTypes.push_back(PaddingType);
+ }
+ }
+ }
+ } else {
+ uint64_t CurrentOffset = 0;
+
+ for (const auto &Field : Fields) {
+ if (Field.OffsetInBits > CurrentOffset) {
+ uint64_t PaddingBits = Field.OffsetInBits - CurrentOffset;
+ if (PaddingBits % 8 == 0 && PaddingBits >= 8) {
+ Type *ByteType = IntegerType::get(Context, 8);
+ Type *PaddingType = ArrayType::get(ByteType, PaddingBits / 8);
+ FieldTypes.push_back(PaddingType);
+ } else if (PaddingBits > 0) {
+ Type *PaddingType = IntegerType::get(Context, PaddingBits);
+ FieldTypes.push_back(PaddingType);
+ }
+ CurrentOffset = Field.OffsetInBits;
+ }
+
+ Type *FieldType = convertType(Field.FieldType);
+ if (!FieldType)
+ continue;
+
+ if (Field.IsBitField && Field.BitFieldWidth > 0) {
+ FieldType = IntegerType::get(Context, Field.BitFieldWidth);
+ CurrentOffset += Field.BitFieldWidth;
+ } else {
+ FieldTypes.push_back(FieldType);
+ if (auto *IntTy = dyn_cast<IntegerType>(FieldType)) {
+ CurrentOffset += IntTy->getBitWidth();
+ } else if (FieldType->isFloatingPointTy()) {
+ CurrentOffset += FieldType->getPrimitiveSizeInBits();
+ } else if (FieldType->isPointerTy()) {
+ CurrentOffset += 64; // Assume 64-bit pointers
+ } else {
+ CurrentOffset += 64; // Conservative estimate
+ }
+ }
+ }
+
+ uint64_t TotalSizeBits = Size.getFixedValue();
+ if (CurrentOffset < TotalSizeBits) {
+ uint64_t PaddingBits = TotalSizeBits - CurrentOffset;
+ if (PaddingBits % 8 == 0 && PaddingBits >= 8) {
+ Type *ByteType = IntegerType::get(Context, 8);
+ Type *PaddingType = ArrayType::get(ByteType, PaddingBits / 8);
+ FieldTypes.push_back(PaddingType);
+ } else if (PaddingBits > 0) {
+ Type *PaddingType = IntegerType::get(Context, PaddingBits);
+ FieldTypes.push_back(PaddingType);
+ }
+ }
+ }
+
+ return StructType::get(Context, FieldTypes, /*isPacked=*/false);
+}
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
index f4b74f551c720..33baab6090998 100644
--- a/llvm/lib/ABI/CMakeLists.txt
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -1,5 +1,7 @@
add_llvm_component_library(LLVMABI
ABIFunctionInfo.cpp
+ ABITypeMapper.cpp
+ TargetCodeGenInfo.cpp
Targets/BPF.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/ABI/TargetCodeGenInfo.cpp b/llvm/lib/ABI/TargetCodeGenInfo.cpp
new file mode 100644
index 0000000000000..aa312e1a10138
--- /dev/null
+++ b/llvm/lib/ABI/TargetCodeGenInfo.cpp
@@ -0,0 +1,23 @@
+//===- TargetCodeGenInfo.cpp - Target CodeGen Info Implementation -------===//
+//
+// 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/TargetCodegenInfo.h"
+#include "llvm/ABI/ABIFunctionInfo.h"
+
+namespace llvm::abi {
+
+TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<llvm::abi::ABIInfo> Info)
+ : Info(std::move(Info)) {}
+
+TargetCodeGenInfo::~TargetCodeGenInfo() = default;
+
+void TargetCodeGenInfo::computeInfo(ABIFunctionInfo &FI) const {
+ // Default Impl here
+}
+
+} // namespace llvm::abi
diff --git a/llvm/lib/ABI/Targets/BPF.cpp b/llvm/lib/ABI/Targets/BPF.cpp
index ae2752eb0c50d..4841febae76be 100644
--- a/llvm/lib/ABI/Targets/BPF.cpp
+++ b/llvm/lib/ABI/Targets/BPF.cpp
@@ -8,6 +8,7 @@
#include "llvm/ABI/ABIFunctionInfo.h"
#include "llvm/ABI/ABIInfo.h"
+#include "llvm/ABI/TargetCodegenInfo.h"
#include "llvm/ABI/Types.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Casting.h"
@@ -90,7 +91,7 @@ class BPFABIInfo : public ABIInfo {
return ABIArgInfo::getDirect();
}
- void computeInfo(ABIFunctionInfo &FI) {
+ void computeInfo(ABIFunctionInfo &FI) const override {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments()) {
I.ArgInfo = classifyArgumentType(I.ABIType);
@@ -98,4 +99,14 @@ class BPFABIInfo : public ABIInfo {
}
};
+class BPFTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ BPFTargetCodeGenInfo(TypeBuilder &TB)
+ : TargetCodeGenInfo(std::make_unique<BPFABIInfo>(TB)) {}
+};
+
+std::unique_ptr<TargetCodeGenInfo> createBPFTargetCodeGenInfo(TypeBuilder &TB) {
+ return std::make_unique<BPFTargetCodeGenInfo>(TB);
+}
+
} // namespace llvm::abi
>From 8560eaf50b14c44fa9783e6eec74c3d9eb95b871 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Wed, 2 Jul 2025 01:00:41 +0530
Subject: [PATCH 13/17] [LLVMABI] Scaffolding the SysV ABI
---
llvm/include/llvm/ABI/ABIInfo.h | 31 +++
llvm/include/llvm/ABI/Types.h | 2 +-
llvm/lib/ABI/CMakeLists.txt | 1 +
llvm/lib/ABI/Targets/X86.cpp | 424 ++++++++++++++++++++++++++++++++
4 files changed, 457 insertions(+), 1 deletion(-)
create mode 100644 llvm/lib/ABI/Targets/X86.cpp
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
index 3a18c8cf029f7..3a1717e28c77a 100644
--- a/llvm/include/llvm/ABI/ABIInfo.h
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -17,19 +17,50 @@
#include "llvm/ABI/ABIFunctionInfo.h"
#include "llvm/ABI/Types.h"
#include <cassert>
+#include <climits>
+#include <cstdint>
namespace llvm {
namespace abi {
+struct ABICompatInfo {
+ unsigned Version = UINT_MAX;
+
+ struct ABIFlags {
+ bool PassInt128VectorsInMem : 1;
+ bool ReturnCXXRecordGreaterThan128InMem : 1;
+ bool ClassifyIntegerMMXAsSSE : 1;
+ bool HonorsRevision98 : 1;
+
+ ABIFlags()
+ : PassInt128VectorsInMem(true),
+ ReturnCXXRecordGreaterThan128InMem(true),
+ ClassifyIntegerMMXAsSSE(true), HonorsRevision98(true) {}
+
+ } Flags;
+
+ ABICompatInfo() : Version(UINT_MAX) {}
+ ABICompatInfo(unsigned Ver) : Version(Ver) {}
+};
+
/// Abstract base class for target-specific ABI information.
class ABIInfo {
+private:
+ ABICompatInfo CompatInfo;
+
public:
+ ABIInfo() : CompatInfo() {}
+ explicit ABIInfo(const ABICompatInfo &Info) : CompatInfo(Info) {}
+
virtual ~ABIInfo() = default;
virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
virtual void computeInfo(ABIFunctionInfo &FI) const = 0;
virtual bool isPassByRef(const Type *Ty) const { return false; }
+ const ABICompatInfo &getABICompatInfo() const { return CompatInfo; }
+
+ void setABICompatInfo(const struct ABICompatInfo &Info) { CompatInfo = Info; }
};
} // namespace abi
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 518c0e6cc2dd4..5228a1590377f 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -102,7 +102,7 @@ class FloatType : public Type {
TypeSize::getFixed(APFloat::getSizeInBits(FloatSemantics)), Align),
Semantics(&FloatSemantics) {}
- const fltSemantics *getSemantics() { return Semantics; }
+ const fltSemantics *getSemantics() const { return Semantics; }
static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
};
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
index 33baab6090998..e6efe1ec933c8 100644
--- a/llvm/lib/ABI/CMakeLists.txt
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMABI
ABITypeMapper.cpp
TargetCodeGenInfo.cpp
Targets/BPF.cpp
+ Targets/X86.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
new file mode 100644
index 0000000000000..9010fa9dd4d57
--- /dev/null
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -0,0 +1,424 @@
+//===- X86.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/ABIFunctionInfo.h"
+#include "llvm/ABI/ABIInfo.h"
+#include "llvm/ABI/TargetCodegenInfo.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/TargetParser/Triple.h"
+#include <cstdint>
+
+namespace llvm {
+namespace abi {
+
+enum class AVXABILevel { None, AVX, AVX512 };
+
+static unsigned getNativeVectorSizeForAVXABI(AVXABILevel AVXLevel) {
+ switch (AVXLevel) {
+ case AVXABILevel::AVX512:
+ return 512;
+ case AVXABILevel::AVX:
+ return 256;
+ case AVXABILevel::None:
+ return 128;
+ }
+ llvm_unreachable("Unknown AVXLevel");
+}
+
+class X86_64ABIInfo : public ABIInfo {
+public:
+ enum Class {
+ Integer = 0,
+ SSE,
+ SSEUp,
+ X87,
+ X87UP,
+ Complex_X87,
+ NoClass,
+ Memory
+ };
+
+private:
+ AVXABILevel AVXLevel;
+ bool Has64BitPointers;
+ const llvm::Triple &TargetTriple;
+
+ static Class merge(Class Accum, Class Field);
+
+ void postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const;
+
+ void classify(const Type *T, uint64_t OffsetBase, Class &Lo, Class &Hi,
+ bool IsNamedArg, bool IsRegCall = false) const;
+
+ llvm::Type *getByteVectorType(const Type *Ty) const;
+ llvm::Type *getSseTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
+ const Type *SourceTy,
+ unsigned SourceOffset) const;
+
+ llvm::Type *getIntegerTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
+ const Type *SourceTy,
+ unsigned SourceOffset) const;
+
+ ABIArgInfo getIndirectReturnResult(const Type *Ty) const;
+
+ ABIArgInfo getIndirectResult(const Type *Ty, unsigned FreeIntRegs) const;
+
+ ABIArgInfo classifyReturnType(const Type *RetTy) const override;
+
+ ABIArgInfo classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
+ unsigned &NeededInt, unsigned &NeededSse,
+ bool IsNamedArg,
+ bool IsRegCall = false) const;
+
+ ABIArgInfo classifyRegCallStructType(const Type *Ty, unsigned &NeededInt,
+ unsigned &NeededSSE,
+ unsigned &MaxVectorWidth) const;
+
+ ABIArgInfo classifyRegCallStructTypeImpl(const Type *Ty, unsigned &NeededInt,
+ unsigned &NeededSSE,
+ unsigned &MaxVectorWidth) const;
+
+ bool isIllegalVectorType(const Type *Ty) const;
+
+ // The Functionality of these methods will be moved to
+ // llvm::abi::ABICompatInfo
+
+ bool honorsRevision98() const { return !TargetTriple.isOSDarwin(); }
+
+ bool classifyIntegerMMXAsSSE() const {
+ if (TargetTriple.isOSDarwin() || TargetTriple.isPS() ||
+ TargetTriple.isOSFreeBSD())
+ return false;
+ return true;
+ }
+
+ bool passInt128VectorsInMem() const {
+ // TODO: accept ABICompat info from the frontends
+ return TargetTriple.isOSLinux() || TargetTriple.isOSNetBSD();
+ }
+
+ bool returnCXXRecordGreaterThan128InMem() const {
+ // TODO: accept ABICompat info from the frontends
+ return true;
+ }
+
+public:
+ X86_64ABIInfo(const Triple &Triple, AVXABILevel AVXABILevel,
+ bool Has64BitPtrs, const ABICompatInfo &Compat)
+ : ABIInfo(Compat), AVXLevel(AVXABILevel), Has64BitPointers(Has64BitPtrs),
+ TargetTriple(Triple) {}
+
+ bool isPassedUsingAVXType(const Type *Type) const {
+ unsigned NeededInt, NeededSse;
+ ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse, true);
+
+ if (Info.isDirect()) {
+ auto *Ty = Info.getCoerceToType();
+ if (auto *VectorTy = dyn_cast_or_null<VectorType>(Ty))
+ return VectorTy->getSizeInBits().getFixedValue();
+ }
+ return false;
+ }
+
+ void computeInfo(ABIFunctionInfo &FI) const override;
+
+ bool has64BitPointers() const { return Has64BitPointers; }
+};
+
+void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo,
+ Class &Hi) const {
+ // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
+ //
+ // (a) If one of the classes is Memory, the whole argument is passed in
+ // memory.
+ //
+ // (b) If X87UP is not preceded by X87, the whole argument is passed in
+ // memory.
+ //
+ // (c) If the size of the aggregate exceeds two eightbytes and the first
+ // eightbyte isn't SSE or any other eightbyte isn't SSEUP, the whole
+ // argument is passed in memory. NOTE: This is necessary to keep the
+ // ABI working for processors that don't support the __m256 type.
+ //
+ // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
+ //
+ // Some of these are enforced by the merging logic. Others can arise
+ // only with unions; for example:
+ // union { _Complex double; unsigned; }
+ //
+ // Note that clauses (b) and (c) were added in 0.98.
+
+ if (Hi == Memory)
+ Lo = Memory;
+ if (Hi == X87UP && Lo != X87 && getABICompatInfo().Flags.HonorsRevision98)
+ Lo = Memory;
+ if (AggregateSize > 128 && (Lo != SSE && Hi != SSEUp))
+ Lo = Memory;
+ if (Hi == SSEUp && Lo != SSE)
+ Hi = SSE;
+}
+X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
+ // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
+ // classified recursively so that always two fields are
+ // considered. The resulting class is calculated according to
+ // the classes of the fields in the eightbyte:
+ //
+ // (a) If both classes are equal, this is the resulting class.
+ //
+ // (b) If one of the classes is NO_CLASS, the resulting class is
+ // the other class.
+ //
+ // (c) If one of the classes is MEMORY, the result is the MEMORY
+ // class.
+ //
+ // (d) If one of the classes is INTEGER, the result is the
+ // INTEGER.
+ //
+ // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ // MEMORY is used as class.
+ //
+ // (f) Otherwise class SSE is used.
+
+ // Accum should never be memory (we should have returned) or
+ // ComplexX87 (because this cannot be passed in a structure).
+ assert((Accum != Memory && Accum != Complex_X87) &&
+ "Invalid accumulated classification during merge.");
+
+ if (Accum == Field || Field == NoClass)
+ return Accum;
+ if (Accum == NoClass)
+ return Field;
+ if (Field == Memory)
+ return Memory;
+ if (Accum == Integer || Field == Integer)
+ return Integer;
+ if (Field == X87 || Field == X87UP || Field == Complex_X87 || Accum == X87 ||
+ Accum == X87UP)
+ return Memory;
+
+ return SSE;
+}
+void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
+ Class &Hi, bool IsNamedArg, bool IsRegCall) const {
+ Lo = Hi = NoClass;
+ Class &Current = OffsetBase < 64 ? Lo : Hi;
+ Current = Memory;
+
+ if (T->isVoid()) {
+ Current = NoClass;
+ return;
+ }
+
+ if (const auto *IT = dyn_cast<IntegerType>(T)) {
+ auto BitWidth = IT->getSizeInBits().getFixedValue();
+
+ if (BitWidth == 128) {
+ Lo = Integer;
+ Hi = Integer;
+ } else if (BitWidth <= 64)
+ Current = Integer;
+
+ return;
+ }
+
+ if (const auto *FT = dyn_cast<FloatType>(T)) {
+ const auto *FltSem = FT->getSemantics();
+
+ if (FltSem == &llvm::APFloat::IEEEsingle() ||
+ FltSem == &llvm::APFloat::IEEEdouble() ||
+ FltSem == &llvm::APFloat::IEEEhalf() ||
+ FltSem == &llvm::APFloat::BFloat()) {
+ Current = SSE;
+ } else if (FltSem == &llvm::APFloat::IEEEquad()) {
+ Lo = SSE;
+ Hi = SSEUp;
+ } else if (FltSem == &llvm::APFloat::x87DoubleExtended()) {
+ Lo = X87;
+ Hi = X87UP;
+ } else {
+ Current = SSE;
+ }
+ return;
+ }
+
+ if (T->isPointer()) {
+ Current = Integer;
+ return;
+ }
+
+ if (const auto *VT = dyn_cast<VectorType>(T)) {
+ auto Size = VT->getSizeInBits().getFixedValue();
+ const Type *ElementType = VT->getElementType();
+
+ if (Size == 1 || Size == 8 || Size == 16 || Size == 32) {
+ Current = Integer;
+ uint64_t EB_Lo = (OffsetBase) / 64;
+ uint64_t EB_Hi = (OffsetBase + Size - 1) / 64;
+ if (EB_Lo != EB_Hi)
+ Hi = Lo;
+ } else if (Size == 64) {
+ if (const auto *FT = dyn_cast<FloatType>(ElementType)) {
+ if (FT->getSemantics() == &llvm::APFloat::IEEEdouble())
+ return;
+ }
+
+ if (const auto *IT = dyn_cast<IntegerType>(ElementType)) {
+ uint64_t ElemBits = IT->getSizeInBits().getFixedValue();
+ if (!getABICompatInfo().Flags.ClassifyIntegerMMXAsSSE &&
+ (ElemBits == 64 || ElemBits == 32)) {
+ Current = Integer;
+ } else {
+ Current = SSE;
+ }
+ } else {
+ Current = SSE;
+ }
+ if (OffsetBase && OffsetBase != 64)
+ Hi = Lo;
+ } else if (Size == 128 ||
+ (IsNamedArg && Size <= getNativeVectorSizeForAVXABI(AVXLevel))) {
+ if (const auto *IT = dyn_cast<IntegerType>(ElementType)) {
+ uint64_t ElemBits = IT->getSizeInBits().getFixedValue();
+ if (getABICompatInfo().Flags.PassInt128VectorsInMem && Size != 128 &&
+ ElemBits == 128)
+ return;
+ }
+
+ Lo = SSE;
+ Hi = SSEUp;
+ }
+ return;
+ }
+
+ if (const auto *AT = dyn_cast<ArrayType>(T)) {
+ uint64_t Size = AT->getSizeInBits().getFixedValue();
+
+ if (!IsRegCall && Size > 512)
+ return;
+
+ const Type *ElementType = AT->getElementType();
+ uint64_t ElemAlign = ElementType->getAlignment().value() * 8;
+ if (OffsetBase % ElemAlign)
+ return;
+
+ Current = NoClass;
+ uint64_t EltSize = ElementType->getSizeInBits().getFixedValue();
+ uint64_t ArraySize = AT->getNumElements();
+
+ if (Size > 128 &&
+ (Size != EltSize || Size > getNativeVectorSizeForAVXABI(AVXLevel)))
+ return;
+
+ for (uint64_t I = 0, Offset = OffsetBase; I < ArraySize;
+ ++I, Offset += EltSize) {
+ Class FieldLo, FieldHi;
+ classify(ElementType, Offset, FieldLo, FieldHi, IsNamedArg);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+ postMerge(Size, Lo, Hi);
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
+ return;
+ }
+ if (const auto *ST = dyn_cast<StructType>(T)) {
+ uint64_t Size = ST->getSizeInBits().getFixedValue();
+
+ if (Size > 512)
+ return;
+
+ Current = NoClass;
+
+ const FieldInfo *Fields = ST->getFields();
+ uint32_t NumFields = ST->getNumFields();
+
+ for (uint32_t I = 0; I < NumFields; ++I) {
+ const FieldInfo &Field = Fields[I];
+ uint64_t Offset = OffsetBase + Field.OffsetInBits;
+ bool BitField = Field.IsBitField;
+
+ if (Size > 128 &&
+ Size != Field.FieldType->getSizeInBits().getFixedValue() &&
+ Size > getNativeVectorSizeForAVXABI(AVXLevel)) {
+ Lo = Memory;
+ postMerge(Size, Lo, Hi);
+ return;
+ }
+ if (!BitField) {
+ uint64_t FieldAlign = Field.FieldType->getAlignment().value() * 8;
+ if (Offset % FieldAlign) {
+ Lo = Memory;
+ postMerge(Size, Lo, Hi);
+ return;
+ }
+ }
+
+ Class FieldLo, FieldHi;
+
+ if (BitField) {
+ uint64_t BitFieldSize = Field.BitFieldWidth;
+ uint64_t EB_Lo = Offset / 64;
+ uint64_t EB_Hi = (Offset + BitFieldSize - 1) / 64;
+
+ if (EB_Lo) {
+ assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
+ FieldLo = NoClass;
+ FieldHi = Integer;
+ } else {
+ FieldLo = Integer;
+ FieldHi = EB_Hi ? Integer : NoClass;
+ }
+ } else {
+ classify(Field.FieldType, Offset, FieldLo, FieldHi, IsNamedArg);
+ }
+
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+ postMerge(Size, Lo, Hi);
+ return;
+ }
+ if (const auto *UT = dyn_cast<UnionType>(T)) {
+ uint64_t Size = UT->getSizeInBits().getFixedValue();
+
+ if (Size > 512)
+ return;
+
+ Current = NoClass;
+
+ const FieldInfo *Fields = UT->getFields();
+ uint32_t NumFields = UT->getNumFields();
+
+ for (uint32_t I = 0; I < NumFields; ++I) {
+ const FieldInfo &Field = Fields[I];
+ uint64_t Offset = OffsetBase + Field.OffsetInBits;
+
+ Class FieldLo, FieldHi;
+ classify(Field.FieldType, Offset, FieldLo, FieldHi, IsNamedArg);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ postMerge(Size, Lo, Hi);
+ return;
+ }
+
+ Lo = Memory;
+ Hi = NoClass;
+}
+
+} // namespace abi
+} // namespace llvm
>From 8eeefbe1c7b045f0aa56cfcaf4254e703aa008b7 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Tue, 8 Jul 2025 18:33:51 +0530
Subject: [PATCH 14/17] [LLVMABI] Classifier
---
clang/lib/CodeGen/CGCall.cpp | 37 ++++----
clang/lib/CodeGen/QualTypeMapper.cpp | 25 +++++-
llvm/include/llvm/ABI/Types.h | 121 ++++++++++++++++++++++++---
llvm/lib/ABI/Targets/X86.cpp | 103 ++++++++++++++++++++++-
4 files changed, 251 insertions(+), 35 deletions(-)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 336d3e6ce2a3e..428d07aebe0c0 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -831,43 +831,37 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
}
} // namespace clang
-ABIArgInfo CodeGenTypes::convertABIArgInfo(const llvm::abi::ABIArgInfo &abiInfo,
+ABIArgInfo CodeGenTypes::convertABIArgInfo(const llvm::abi::ABIArgInfo &AbiInfo,
QualType type) {
ABIArgInfo result;
- if (abiInfo.isDirect()) {
+ if (AbiInfo.isDirect()) {
llvm::Type *CoercedType = nullptr;
- if (abiInfo.getCoerceToType()) {
- CoercedType = ReverseMapper.convertType(abiInfo.getCoerceToType());
- }
- if (!CoercedType) {
+ if (AbiInfo.getCoerceToType())
+ CoercedType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
+ if (!CoercedType)
CoercedType = ConvertType(type);
- }
result = ABIArgInfo::getDirect(CoercedType);
- } else if (abiInfo.isExtend()) {
+ } else if (AbiInfo.isExtend()) {
llvm::Type *CoercedType = nullptr;
- if (abiInfo.getCoerceToType()) {
- CoercedType = ReverseMapper.convertType(abiInfo.getCoerceToType());
- }
- if (!CoercedType) {
+ if (AbiInfo.getCoerceToType())
+ CoercedType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
+ if (!CoercedType)
CoercedType = ConvertType(type);
- }
-
- if (abiInfo.isSignExt()) {
+ if (AbiInfo.isSignExt()) {
result = ABIArgInfo::getSignExtend(type, CoercedType);
} else {
result = ABIArgInfo::getZeroExtend(type, CoercedType);
}
- } else if (abiInfo.isIndirect()) {
+ } else if (AbiInfo.isIndirect()) {
result = ABIArgInfo::getIndirect(
- CharUnits::fromQuantity(abiInfo.getIndirectAlign()), 0);
- } else if (abiInfo.isIgnore()) {
+ CharUnits::fromQuantity(AbiInfo.getIndirectAlign()), 0);
+ } else if (AbiInfo.isIgnore()) {
result = ABIArgInfo::getIgnore();
}
- if (abiInfo.isInReg()) {
+ if (AbiInfo.isInReg())
result.setInReg(true);
- }
return result;
}
@@ -896,7 +890,6 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
void *insertPos = nullptr;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
- llvm::abi::ABIFunctionInfo *tempFI;
if (FI)
return *FI;
@@ -910,7 +903,7 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
for (CanQualType ArgType : argTypes) {
MappedArgTypes.push_back(Mapper.convertType(ArgType));
}
- tempFI = llvm::abi::ABIFunctionInfo::create(
+ llvm::abi::ABIFunctionInfo *tempFI = llvm::abi::ABIFunctionInfo::create(
CC, Mapper.convertType(resultType), MappedArgTypes);
FunctionInfos.InsertNode(FI, insertPos);
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index b4c8aa5663a46..90ba526e74a74 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -210,6 +210,8 @@ const llvm::abi::StructType *
QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
SmallVector<llvm::abi::FieldInfo, 16> Fields;
+ SmallVector<llvm::abi::FieldInfo, 8> BaseClasses;
+ SmallVector<llvm::abi::FieldInfo, 8> VirtualBaseClasses;
if (RD->isPolymorphic()) {
const llvm::abi::Type *VtablePointer =
@@ -229,6 +231,7 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
8;
Fields.emplace_back(BaseType, BaseOffset);
+ BaseClasses.emplace_back(BaseType, BaseOffset);
}
for (const auto &VBase : RD->vbases()) {
@@ -243,6 +246,7 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
8;
Fields.emplace_back(VBaseType, VBaseOffset);
+ VirtualBaseClasses.emplace_back(VBaseType, VBaseOffset);
}
computeFieldInfo(RD, Fields, Layout);
@@ -255,7 +259,26 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
llvm::TypeSize::getFixed(Layout.getSize().getQuantity() * 8);
llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
- return Builder.getStructType(Fields, Size, Alignment);
+ bool HasNonTrivialCopy = !RD->hasSimpleCopyConstructor();
+ bool HasNonTrivialDtor = !RD->hasSimpleDestructor();
+ bool HasFlexibleArrayMember = false;
+ bool HasUnalignedFields = false;
+
+ unsigned FieldIndex = 0;
+ for (const auto *FD : RD->fields()) {
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldIndex);
+ uint64_t ExpectedAlignment = ASTCtx.getTypeAlign(FD->getType());
+ if (FieldOffset % ExpectedAlignment != 0) {
+ HasUnalignedFields = true;
+ break;
+ }
+ ++FieldIndex;
+ }
+
+ return Builder.getStructType(
+ Fields, Size, Alignment, llvm::abi::StructPacking::Default, BaseClasses,
+ VirtualBaseClasses, true, RD->isPolymorphic(), HasNonTrivialCopy,
+ HasNonTrivialDtor, HasFlexibleArrayMember, HasUnalignedFields);
}
/// Converts reference types to pointer representations in the ABI.
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 5228a1590377f..33fec61f4b151 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -28,6 +28,8 @@ namespace abi {
enum class TypeKind {
Void,
+ MemberPointer,
+ Complex,
Integer,
Float,
Pointer,
@@ -67,6 +69,8 @@ class Type {
bool isVector() const { return Kind == TypeKind::Vector; }
bool isStruct() const { return Kind == TypeKind::Struct; }
bool isUnion() const { return Kind == TypeKind::Union; }
+ bool isMemberPointer() const { return Kind == TypeKind::MemberPointer; }
+ bool isComplex() const { return Kind == TypeKind::Union; }
};
class VoidType : public Type {
@@ -76,6 +80,43 @@ class VoidType : public Type {
static bool classof(const Type *T) { return T->getKind() == TypeKind::Void; }
};
+class ComplexType : public Type {
+public:
+ ComplexType(const Type *ElementType, uint64_t SizeInBits, Align Alignment)
+ : Type(TypeKind::Complex, TypeSize::getFixed(SizeInBits), Alignment),
+ ElementType(ElementType) {}
+
+ const Type *getElementType() const { return ElementType; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Complex;
+ }
+
+private:
+ const Type *ElementType;
+};
+
+class MemberPointerType : public Type {
+public:
+ MemberPointerType(bool IsFunctionPointer, bool Has64BitPointers,
+ uint64_t SizeInBits, Align Alignment)
+ : Type(TypeKind::MemberPointer, TypeSize::getFixed(SizeInBits),
+ Alignment),
+ IsFunctionPointer(IsFunctionPointer),
+ Has64BitPointers(Has64BitPointers) {}
+
+ bool isFunctionPointer() const { return IsFunctionPointer; }
+ bool has64BitPointers() const { return Has64BitPointers; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::MemberPointer;
+ }
+
+private:
+ bool IsFunctionPointer;
+ bool Has64BitPointers;
+};
+
class IntegerType : public Type {
private:
bool IsSigned;
@@ -179,16 +220,53 @@ class StructType : public Type {
uint32_t NumFields;
StructPacking Packing;
+ bool IsCXXRecord;
+ bool IsPolymorphic;
+ bool HasNonTrivialCopyConstructor;
+ bool HasNonTrivialDestructor;
+ bool HasFlexibleArrayMember;
+ bool HasUnalignedFields;
+ const FieldInfo *BaseClasses;
+ uint32_t NumBaseClasses;
+ const FieldInfo *VirtualBaseClasses;
+ uint32_t NumVirtualBaseClasses;
+
public:
- StructType(const FieldInfo *StructFields, uint32_t FieldCount, TypeSize Size,
- Align Align, StructPacking Pack = StructPacking::Default)
+ StructType(const FieldInfo *StructFields, uint32_t FieldCount,
+ const FieldInfo *Bases, uint32_t BaseCount,
+ const FieldInfo *VBases, uint32_t VBaseCount, TypeSize Size,
+ Align Align, StructPacking Pack = StructPacking::Default,
+ bool CXXRecord = false, bool Polymorphic = false,
+ bool NonTrivialCopy = false, bool NonTrivialDtor = false,
+ bool FlexibleArray = false, bool UnalignedFields = false)
: Type(TypeKind::Struct, Size, Align), Fields(StructFields),
- NumFields(FieldCount), Packing(Pack) {}
+ NumFields(FieldCount), Packing(Pack), IsCXXRecord(CXXRecord),
+ IsPolymorphic(Polymorphic),
+ HasNonTrivialCopyConstructor(NonTrivialCopy),
+ HasNonTrivialDestructor(NonTrivialDtor),
+ HasFlexibleArrayMember(FlexibleArray),
+ HasUnalignedFields(UnalignedFields), BaseClasses(Bases),
+ NumBaseClasses(BaseCount), VirtualBaseClasses(VBases),
+ NumVirtualBaseClasses(VBaseCount) {}
const FieldInfo *getFields() const { return Fields; }
uint32_t getNumFields() const { return NumFields; }
StructPacking getPacking() const { return Packing; }
+ bool isCXXRecord() const { return IsCXXRecord; }
+ bool isPolymorphic() const { return IsPolymorphic; }
+ bool hasNonTrivialCopyConstructor() const {
+ return HasNonTrivialCopyConstructor;
+ }
+ bool hasNonTrivialDestructor() const { return HasNonTrivialDestructor; }
+ bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
+ bool hasUnalignedFields() const { return HasUnalignedFields; }
+
+ const FieldInfo *getBaseClasses() const { return BaseClasses; }
+ uint32_t getNumBaseClasses() const { return NumBaseClasses; }
+ const FieldInfo *getVirtualBaseClasses() const { return VirtualBaseClasses; }
+ uint32_t getNumVirtualBaseClasses() const { return NumVirtualBaseClasses; }
+
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Struct;
}
@@ -250,19 +328,42 @@ class TypeBuilder {
VectorType(ElementType, NumElements, Align);
}
- const StructType *getStructType(ArrayRef<FieldInfo> Fields, TypeSize Size,
- Align Align,
- StructPacking Pack = StructPacking::Default) {
+ const StructType *
+ getStructType(ArrayRef<FieldInfo> Fields, TypeSize Size, Align Align,
+ StructPacking Pack = StructPacking::Default,
+ ArrayRef<FieldInfo> BaseClasses = {},
+ ArrayRef<FieldInfo> VirtualBaseClasses = {},
+ bool CXXRecord = false, bool Polymorphic = false,
+ bool NonTrivialCopy = false, bool NonTrivialDtor = false,
+ bool FlexibleArray = false, bool UnalignedFields = false) {
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);
- }
+ FieldInfo *BaseArray = nullptr;
+ if (!BaseClasses.empty()) {
+ BaseArray = Allocator.Allocate<FieldInfo>(BaseClasses.size());
+ for (size_t I = 0; I < BaseClasses.size(); ++I) {
+ new (&BaseArray[I]) FieldInfo(BaseClasses[I]);
+ }
+ }
+
+ FieldInfo *VBaseArray = nullptr;
+ if (!VirtualBaseClasses.empty()) {
+ VBaseArray = Allocator.Allocate<FieldInfo>(VirtualBaseClasses.size());
+ for (size_t I = 0; I < VirtualBaseClasses.size(); ++I) {
+ new (&VBaseArray[I]) FieldInfo(VirtualBaseClasses[I]);
+ }
+ }
+ return new (Allocator.Allocate<StructType>())
+ StructType(FieldArray, static_cast<uint32_t>(Fields.size()), BaseArray,
+ static_cast<uint32_t>(BaseClasses.size()), VBaseArray,
+ static_cast<uint32_t>(VirtualBaseClasses.size()), Size,
+ Align, Pack, CXXRecord, Polymorphic, NonTrivialCopy,
+ NonTrivialDtor, FlexibleArray, UnalignedFields);
+ }
const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, TypeSize Size,
Align Align,
StructPacking Pack = StructPacking::Default) {
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index 9010fa9dd4d57..8782b82a86afd 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -254,6 +254,58 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
return;
}
+ if (const auto *MPT = dyn_cast<MemberPointerType>(T)) {
+ if (MPT->isFunctionPointer()) {
+ if (MPT->has64BitPointers()) {
+ Lo = Hi = Integer;
+ } else {
+ uint64_t EB_FuncPtr = OffsetBase / 64;
+ uint64_t EB_ThisAdj = (OffsetBase + 64 - 1) / 64;
+ if (EB_FuncPtr != EB_ThisAdj) {
+ Lo = Hi = Integer;
+ } else {
+ Current = Integer;
+ }
+ }
+ } else {
+ Current = Integer;
+ }
+ return;
+ }
+
+ if (const auto *CT = dyn_cast<ComplexType>(T)) {
+ const Type *ElementType = CT->getElementType();
+ uint64_t Size = T->getSizeInBits().getFixedValue();
+
+ if (const auto *EIT = dyn_cast<IntegerType>(ElementType)) {
+ if (Size <= 64)
+ Current = Integer;
+ else if (Size <= 128)
+ Lo = Hi = Integer;
+ } else if (const auto *EFT = dyn_cast<FloatType>(ElementType)) {
+ const auto *FltSem = EFT->getSemantics();
+ if (FltSem == &llvm::APFloat::IEEEhalf() ||
+ FltSem == &llvm::APFloat::IEEEsingle() ||
+ FltSem == &llvm::APFloat::BFloat()) {
+ Current = SSE;
+ } else if (FltSem == &llvm::APFloat::IEEEdouble()) {
+ Lo = Hi = SSE;
+ } else if (FltSem == &llvm::APFloat::x87DoubleExtended()) {
+ Current = Complex_X87;
+ } else if (FltSem == &llvm::APFloat::IEEEquad()) {
+ Current = Memory;
+ }
+ }
+
+ uint64_t ElementSize = ElementType->getSizeInBits().getFixedValue();
+ uint64_t EB_Real = OffsetBase / 64;
+ uint64_t EB_Imag = (OffsetBase + ElementSize) / 64;
+ if (Hi == NoClass && EB_Real != EB_Imag)
+ Hi = Lo;
+
+ return;
+ }
+
if (const auto *VT = dyn_cast<VectorType>(T)) {
auto Size = VT->getSizeInBits().getFixedValue();
const Type *ElementType = VT->getElementType();
@@ -278,8 +330,6 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
} else {
Current = SSE;
}
- } else {
- Current = SSE;
}
if (OffsetBase && OffsetBase != 64)
Hi = Lo;
@@ -333,11 +383,60 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
if (const auto *ST = dyn_cast<StructType>(T)) {
uint64_t Size = ST->getSizeInBits().getFixedValue();
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than eight eightbytes, ..., it has class MEMORY.
if (Size > 512)
return;
+ // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
+ // copy constructor or a non-trivial destructor, it is passed by invisible
+ // reference.
+ if (ST->isCXXRecord() &&
+ (ST->hasNonTrivialCopyConstructor() || ST->hasNonTrivialDestructor())) {
+ return;
+ }
+
+ // Assume variable sized types are passed in memory.
+ if (ST->hasFlexibleArrayMember()) {
+ return;
+ }
+ // Reset Lo class, this will be recomputed.
Current = NoClass;
+ // If this is a C++ record, classify the bases first.
+ if (ST->isCXXRecord()) {
+ const FieldInfo *BaseClasses = ST->getBaseClasses();
+ for (uint32_t I = 0; I < ST->getNumBaseClasses(); ++I) {
+ const FieldInfo &Base = BaseClasses[I];
+
+ // Classify this field.
+ //
+ // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a
+ // single eightbyte, each is classified separately. Each eightbyte gets
+ // initialized to class NO_CLASS.
+ Class FieldLo, FieldHi;
+ uint64_t Offset = OffsetBase + Base.OffsetInBits;
+ classify(Base.FieldType, Offset, FieldLo, FieldHi, IsNamedArg);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+
+ if (getABICompatInfo().Flags.ReturnCXXRecordGreaterThan128InMem &&
+ (Size > 128 &&
+ (Size != Base.FieldType->getSizeInBits().getFixedValue() ||
+ Size > getNativeVectorSizeForAVXABI(AVXLevel)))) {
+ Lo = Memory;
+ postMerge(Size, Lo, Hi);
+ return;
+ }
+
+ if (Lo == Memory || Hi == Memory) {
+ postMerge(Size, Lo, Hi);
+ return;
+ }
+ }
+ }
+
+ // Classify the fields one at a time, merging the results.
const FieldInfo *Fields = ST->getFields();
uint32_t NumFields = ST->getNumFields();
>From 13edf65134d8a2cc14f6bf3bcc338c3358857009 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Thu, 24 Jul 2025 03:51:18 +0530
Subject: [PATCH 15/17] [LLVMABI] Return Type Classifier
---
clang/lib/CodeGen/CGCall.cpp | 3 +-
llvm/include/llvm/ABI/ABIFunctionInfo.h | 71 ++-
llvm/include/llvm/ABI/ABIInfo.h | 5 +-
llvm/include/llvm/ABI/Types.h | 9 +-
llvm/lib/ABI/ABIInfo.cpp | 26 +
llvm/lib/ABI/CMakeLists.txt | 1 +
llvm/lib/ABI/Targets/X86.cpp | 617 ++++++++++++++++++++++--
7 files changed, 678 insertions(+), 54 deletions(-)
create mode 100644 llvm/lib/ABI/ABIInfo.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 428d07aebe0c0..a39a41391eb20 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -900,9 +900,8 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
info, paramInfos, resultType, argTypes, required);
SmallVector<const llvm::abi::Type *, 8> MappedArgTypes;
- for (CanQualType ArgType : argTypes) {
+ for (CanQualType ArgType : argTypes)
MappedArgTypes.push_back(Mapper.convertType(ArgType));
- }
llvm::abi::ABIFunctionInfo *tempFI = llvm::abi::ABIFunctionInfo::create(
CC, Mapper.convertType(resultType), MappedArgTypes);
FunctionInfos.InsertNode(FI, insertPos);
diff --git a/llvm/include/llvm/ABI/ABIFunctionInfo.h b/llvm/include/llvm/ABI/ABIFunctionInfo.h
index d6a07b0cc283a..c008d910928fe 100644
--- a/llvm/include/llvm/ABI/ABIFunctionInfo.h
+++ b/llvm/include/llvm/ABI/ABIFunctionInfo.h
@@ -17,6 +17,7 @@
#include "llvm/ABI/Types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/CallingConv.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/TrailingObjects.h"
namespace llvm {
@@ -30,6 +31,7 @@ class ABIArgInfo {
Direct,
Extend,
Indirect,
+ IndirectAliased,
Ignore,
Expand,
CoerceAndExpand,
@@ -39,12 +41,29 @@ class ABIArgInfo {
private:
Kind TheKind;
const Type *CoercionType;
+ const Type *PaddingType;
+ struct DirectAttrInfo {
+ unsigned Offset;
+ unsigned Align;
+ };
+
+ struct IndirectAttrInfo {
+ unsigned Align;
+ unsigned AddrSpace;
+ };
+
+ union {
+ DirectAttrInfo DirectAttr;
+ IndirectAttrInfo IndirectAttr;
+ };
bool InReg : 1;
bool PaddingInReg : 1;
bool SignExt : 1;
bool ZeroExt : 1;
unsigned IndirectAlign : 16;
bool IndirectByVal : 1;
+ bool IndirectRealign : 1;
+ bool CanBeFlattened : 1;
ABIArgInfo(Kind K = Direct)
: TheKind(K), CoercionType(nullptr), InReg(false), PaddingInReg(false),
@@ -52,21 +71,50 @@ class ABIArgInfo {
}
public:
- static ABIArgInfo getDirect(const Type *T = nullptr) {
+ static ABIArgInfo getDirect(const Type *T = nullptr, unsigned Offset = 0,
+ const Type *Padding = nullptr,
+ bool CanBeFlattened = true, unsigned Align = 0) {
ABIArgInfo AI(Direct);
AI.CoercionType = T;
+ AI.PaddingType = Padding;
+ AI.DirectAttr.Offset = Offset;
+ AI.DirectAttr.Align = Align;
+ AI.CanBeFlattened = CanBeFlattened;
return AI;
}
+ static ABIArgInfo getIndirectAliased(unsigned Align, unsigned AddrSpace = 0,
+ bool Realign = false,
+ const Type *Padding = nullptr) {
+ ABIArgInfo AI(IndirectAliased);
+ AI.IndirectAttr.Align = Align;
+ AI.IndirectAttr.AddrSpace = AddrSpace;
+ AI.IndirectRealign = Realign;
+ AI.PaddingType = Padding;
+ return AI;
+ }
static ABIArgInfo getDirectInReg(const Type *T = nullptr) {
ABIArgInfo AI = getDirect(T);
AI.InReg = true;
return AI;
}
+ static ABIArgInfo getExtend(const Type *T) {
+ assert(T && "Type cannot be null");
+ assert(T->isInteger() && "Unexpected type - only integers can be extended");
- static ABIArgInfo getExtend(const Type *T = nullptr) {
ABIArgInfo AI(Extend);
AI.CoercionType = T;
+ AI.DirectAttr.Offset = 0;
+ AI.DirectAttr.Align = 0;
+ AI.PaddingType = nullptr;
+
+ const IntegerType *IntTy = dyn_cast<IntegerType>(T);
+ if (IntTy->isSigned()) {
+ AI.setSignExt();
+ } else {
+ AI.setZeroExt();
+ }
+
return AI;
}
@@ -76,6 +124,21 @@ class ABIArgInfo {
this->ZeroExt = false;
return *this;
}
+ // static ABIArgInfo getSignExtend(ABIArgInfo AI) {
+ // AI.DirectAttr.Offset = 0;
+ // AI.DirectAttr.Align = 0;
+ // AI.ZeroExt = false;
+ // AI.PaddingType = nullptr;
+ // return AI;
+ // }
+ //
+ // static ABIArgInfo getZeroExtend(ABIArgInfo AI) {
+ // AI.DirectAttr.Offset = 0;
+ // AI.DirectAttr.Align = 0;
+ // AI.ZeroExt = true;
+ // AI.PaddingType = nullptr;
+ // return AI;
+ // }
ABIArgInfo &setZeroExt(bool ZeroExtend = true) {
this->ZeroExt = ZeroExtend;
@@ -248,11 +311,11 @@ class ABIFunctionInfo final
bool isVariadic() const { return Required.isVariadic(); }
ArrayRef<ArgInfo> arguments() const {
- return {getTrailingObjects<ArgInfo>(), NumArgs};
+ return {getTrailingObjects(), NumArgs};
}
MutableArrayRef<ArgInfo> arguments() {
- return {getTrailingObjects<ArgInfo>(), NumArgs};
+ return {getTrailingObjects(), NumArgs};
}
ArgInfo &getArgInfo(unsigned Index) {
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
index 3a1717e28c77a..6a14b9187854c 100644
--- a/llvm/include/llvm/ABI/ABIInfo.h
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -59,8 +59,11 @@ class ABIInfo {
virtual void computeInfo(ABIFunctionInfo &FI) const = 0;
virtual bool isPassByRef(const Type *Ty) const { return false; }
const ABICompatInfo &getABICompatInfo() const { return CompatInfo; }
+ ABIArgInfo getNaturalAlignIndirect(const Type *Ty) const;
+ bool isAggregateTypeForABI(const Type *Ty) const;
+ bool isPromotableIntegerType(const IntegerType *Ty) const;
- void setABICompatInfo(const struct ABICompatInfo &Info) { CompatInfo = Info; }
+ void setABICompatInfo(const ABICompatInfo &Info) { CompatInfo = Info; }
};
} // namespace abi
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 33fec61f4b151..781ccf031c41c 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -337,24 +337,21 @@ class TypeBuilder {
bool NonTrivialCopy = false, bool NonTrivialDtor = false,
bool FlexibleArray = false, bool UnalignedFields = false) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
- for (size_t I = 0; I < Fields.size(); ++I) {
+ for (size_t I = 0; I < Fields.size(); ++I)
new (&FieldArray[I]) FieldInfo(Fields[I]);
- }
FieldInfo *BaseArray = nullptr;
if (!BaseClasses.empty()) {
BaseArray = Allocator.Allocate<FieldInfo>(BaseClasses.size());
- for (size_t I = 0; I < BaseClasses.size(); ++I) {
+ for (size_t I = 0; I < BaseClasses.size(); ++I)
new (&BaseArray[I]) FieldInfo(BaseClasses[I]);
- }
}
FieldInfo *VBaseArray = nullptr;
if (!VirtualBaseClasses.empty()) {
VBaseArray = Allocator.Allocate<FieldInfo>(VirtualBaseClasses.size());
- for (size_t I = 0; I < VirtualBaseClasses.size(); ++I) {
+ for (size_t I = 0; I < VirtualBaseClasses.size(); ++I)
new (&VBaseArray[I]) FieldInfo(VirtualBaseClasses[I]);
- }
}
return new (Allocator.Allocate<StructType>())
diff --git a/llvm/lib/ABI/ABIInfo.cpp b/llvm/lib/ABI/ABIInfo.cpp
new file mode 100644
index 0000000000000..d94bca2d3aed1
--- /dev/null
+++ b/llvm/lib/ABI/ABIInfo.cpp
@@ -0,0 +1,26 @@
+#include "llvm/ABI/ABIInfo.h"
+
+using namespace llvm::abi;
+bool ABIInfo::isAggregateTypeForABI(const Type *Ty) const {
+ // Member pointers are always aggregates
+ if (Ty->isMemberPointer())
+ return true;
+
+ // Check for fundamental scalar types
+ if (Ty->isInteger() || Ty->isFloat() || Ty->isPointer())
+ return false;
+
+ // Everything else is treated as aggregate
+ return true;
+}
+
+// Check if an integer type should be promoted
+bool ABIInfo::isPromotableIntegerType(const IntegerType *Ty) const {
+ unsigned BitWidth = Ty->getSizeInBits().getFixedValue();
+ return BitWidth < 32;
+}
+
+// Create indirect return with natural alignment
+ABIArgInfo ABIInfo::getNaturalAlignIndirect(const Type *Ty) const {
+ return ABIArgInfo::getIndirect(Ty->getAlignment().value(), /*ByVal=*/true);
+}
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
index e6efe1ec933c8..5f5ddd81bdd9d 100644
--- a/llvm/lib/ABI/CMakeLists.txt
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -1,6 +1,7 @@
add_llvm_component_library(LLVMABI
ABIFunctionInfo.cpp
ABITypeMapper.cpp
+ ABIInfo.cpp
TargetCodeGenInfo.cpp
Targets/BPF.cpp
Targets/X86.cpp
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index 8782b82a86afd..091666d8b9f90 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -8,6 +8,7 @@
#include "llvm/ABI/ABIFunctionInfo.h"
#include "llvm/ABI/ABIInfo.h"
+#include "llvm/ABI/ABITypeMapper.h"
#include "llvm/ABI/TargetCodegenInfo.h"
#include "llvm/ABI/Types.h"
#include "llvm/IR/DerivedTypes.h"
@@ -47,6 +48,7 @@ class X86_64ABIInfo : public ABIInfo {
};
private:
+ TypeBuilder &TB;
AVXABILevel AVXLevel;
bool Has64BitPointers;
const llvm::Triple &TargetTriple;
@@ -58,17 +60,30 @@ class X86_64ABIInfo : public ABIInfo {
void classify(const Type *T, uint64_t OffsetBase, Class &Lo, Class &Hi,
bool IsNamedArg, bool IsRegCall = false) const;
- llvm::Type *getByteVectorType(const Type *Ty) const;
llvm::Type *getSseTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
const Type *SourceTy,
unsigned SourceOffset) const;
- llvm::Type *getIntegerTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
+ const Type *getIntegerTypeAtOffset(const Type *IRType, unsigned IROffset,
const Type *SourceTy,
unsigned SourceOffset) const;
+ // llvm::Type *getIntegerTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
+ // const Type *SourceTy,
+ // unsigned SourceOffset) const;
+ // Type *getIntegerTypeForClass(const Type *OriginalType,
+ // uint64_t OffsetInBytes) const;
+
+ const Type *getSSETypeAtOffset(const Type *IRType, unsigned IROffset,
+ const Type *SourceTy,
+ unsigned SourceOffset) const;
ABIArgInfo getIndirectReturnResult(const Type *Ty) const;
+ const Type *getFPTypeAtOffset(const Type *Ty, unsigned Offset) const;
+ const Type *isSingleElementStruct(const Type *Ty) const;
+ const Type *getByteVectorType(const Type *Ty) const;
+
+ const Type *createPairType(const Type *Lo, const Type *Hi) const;
ABIArgInfo getIndirectResult(const Type *Ty, unsigned FreeIntRegs) const;
ABIArgInfo classifyReturnType(const Type *RetTy) const override;
@@ -111,19 +126,21 @@ class X86_64ABIInfo : public ABIInfo {
}
public:
- X86_64ABIInfo(const Triple &Triple, AVXABILevel AVXABILevel,
- bool Has64BitPtrs, const ABICompatInfo &Compat)
- : ABIInfo(Compat), AVXLevel(AVXABILevel), Has64BitPointers(Has64BitPtrs),
- TargetTriple(Triple) {}
+ X86_64ABIInfo(TypeBuilder &TypeBuilder, const Triple &Triple,
+ AVXABILevel AVXABILevel, bool Has64BitPtrs,
+ const ABICompatInfo &Compat)
+ : ABIInfo(Compat), TB(TypeBuilder), AVXLevel(AVXABILevel),
+ Has64BitPointers(Has64BitPtrs), TargetTriple(Triple) {}
bool isPassedUsingAVXType(const Type *Type) const {
unsigned NeededInt, NeededSse;
- ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse, true);
+ ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse,
+ /*IsNamedArg=*/true);
if (Info.isDirect()) {
auto *Ty = Info.getCoerceToType();
if (auto *VectorTy = dyn_cast_or_null<VectorType>(Ty))
- return VectorTy->getSizeInBits().getFixedValue();
+ return VectorTy->getSizeInBits().getFixedValue() > 128;
}
return false;
}
@@ -273,55 +290,32 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
return;
}
- if (const auto *CT = dyn_cast<ComplexType>(T)) {
- const Type *ElementType = CT->getElementType();
- uint64_t Size = T->getSizeInBits().getFixedValue();
-
- if (const auto *EIT = dyn_cast<IntegerType>(ElementType)) {
- if (Size <= 64)
- Current = Integer;
- else if (Size <= 128)
- Lo = Hi = Integer;
- } else if (const auto *EFT = dyn_cast<FloatType>(ElementType)) {
- const auto *FltSem = EFT->getSemantics();
- if (FltSem == &llvm::APFloat::IEEEhalf() ||
- FltSem == &llvm::APFloat::IEEEsingle() ||
- FltSem == &llvm::APFloat::BFloat()) {
- Current = SSE;
- } else if (FltSem == &llvm::APFloat::IEEEdouble()) {
- Lo = Hi = SSE;
- } else if (FltSem == &llvm::APFloat::x87DoubleExtended()) {
- Current = Complex_X87;
- } else if (FltSem == &llvm::APFloat::IEEEquad()) {
- Current = Memory;
- }
- }
-
- uint64_t ElementSize = ElementType->getSizeInBits().getFixedValue();
- uint64_t EB_Real = OffsetBase / 64;
- uint64_t EB_Imag = (OffsetBase + ElementSize) / 64;
- if (Hi == NoClass && EB_Real != EB_Imag)
- Hi = Lo;
-
- return;
- }
-
if (const auto *VT = dyn_cast<VectorType>(T)) {
auto Size = VT->getSizeInBits().getFixedValue();
const Type *ElementType = VT->getElementType();
if (Size == 1 || Size == 8 || Size == 16 || Size == 32) {
+ // gcc passes the following as integer:
+ // 4 bytes - <4 x char>, <2 x short>, <1 x int>, <1 x float>
+ // 2 bytes - <2 x char>, <1 x short>
+ // 1 byte - <1 x char>
Current = Integer;
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
uint64_t EB_Lo = (OffsetBase) / 64;
uint64_t EB_Hi = (OffsetBase + Size - 1) / 64;
if (EB_Lo != EB_Hi)
Hi = Lo;
} else if (Size == 64) {
if (const auto *FT = dyn_cast<FloatType>(ElementType)) {
+ // gcc passes <1 x double> in memory. :(
if (FT->getSemantics() == &llvm::APFloat::IEEEdouble())
return;
}
+ // gcc passes <1 x long long> as SSE but clang used to unconditionally
+ // pass them as integer. For platforms where clang is the de facto
+ // platform compiler, we must continue to use integer.
if (const auto *IT = dyn_cast<IntegerType>(ElementType)) {
uint64_t ElemBits = IT->getSizeInBits().getFixedValue();
if (!getABICompatInfo().Flags.ClassifyIntegerMMXAsSSE &&
@@ -331,23 +325,75 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
Current = SSE;
}
}
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
if (OffsetBase && OffsetBase != 64)
Hi = Lo;
} else if (Size == 128 ||
(IsNamedArg && Size <= getNativeVectorSizeForAVXABI(AVXLevel))) {
if (const auto *IT = dyn_cast<IntegerType>(ElementType)) {
uint64_t ElemBits = IT->getSizeInBits().getFixedValue();
+ // gcc passes 256 and 512 bit <X x __int128> vectors in memory. :(
if (getABICompatInfo().Flags.PassInt128VectorsInMem && Size != 128 &&
ElemBits == 128)
return;
}
+ // Arguments of 256-bits are split into four eightbyte chunks. The
+ // least significant one belongs to class SSE and all the others to class
+ // SSEUP. The original Lo and Hi design considers that types can't be
+ // greater than 128-bits, so a 64-bit split in Hi and Lo makes sense.
+ // This design isn't correct for 256-bits, but since there're no cases
+ // where the upper parts would need to be inspected, avoid adding
+ // complexity and just consider Hi to match the 64-256 part.
+ //
+ // Note that per 3.5.7 of AMD64-ABI, 256-bit args are only passed in
+ // registers if they are "named", i.e. not part of the "..." of a
+ // variadic function.
+ //
+ // Similarly, per 3.2.3. of the AVX512 draft, 512-bits ("named") args are
+ // split into eight eightbyte chunks, one SSE and seven SSEUP.
Lo = SSE;
Hi = SSEUp;
}
return;
}
+ if (const auto *CT = dyn_cast<ComplexType>(T)) {
+ const Type *ElementType = CT->getElementType();
+ uint64_t Size = T->getSizeInBits().getFixedValue();
+
+ if (const auto *EIT = dyn_cast<IntegerType>(ElementType)) {
+ if (Size <= 64)
+ Current = Integer;
+ else if (Size <= 128)
+ Lo = Hi = Integer;
+ } else if (const auto *EFT = dyn_cast<FloatType>(ElementType)) {
+ const auto *FltSem = EFT->getSemantics();
+ if (FltSem == &llvm::APFloat::IEEEhalf() ||
+ FltSem == &llvm::APFloat::IEEEsingle() ||
+ FltSem == &llvm::APFloat::BFloat()) {
+ Current = SSE;
+ } else if (FltSem == &llvm::APFloat::IEEEdouble()) {
+ Lo = Hi = SSE;
+ } else if (FltSem == &llvm::APFloat::x87DoubleExtended()) {
+ Current = Complex_X87;
+ } else if (FltSem == &llvm::APFloat::IEEEquad()) {
+ Current = Memory;
+ }
+ }
+
+ uint64_t ElementSize = ElementType->getSizeInBits().getFixedValue();
+ // If this complex type crosses an eightbyte boundary then it
+ // should be split.
+ uint64_t EB_Real = OffsetBase / 64;
+ uint64_t EB_Imag = (OffsetBase + ElementSize) / 64;
+ if (Hi == NoClass && EB_Real != EB_Imag)
+ Hi = Lo;
+
+ return;
+ }
+
if (const auto *AT = dyn_cast<ArrayType>(T)) {
uint64_t Size = AT->getSizeInBits().getFixedValue();
@@ -519,5 +565,494 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
Hi = NoClass;
}
+ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
+ // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
+ // classification algorithm.
+
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(RetTy, 0, Lo, Hi, /*isNamedArg*/ true);
+
+ // Check some invariants
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ const Type *ResType = nullptr;
+ switch (Lo) {
+ case NoClass:
+ if (Hi == NoClass)
+ return ABIArgInfo::getIgnore();
+ // If the low part is just padding, it takes no register, leave ResType
+ // null.
+ assert((Hi == SSE || Hi == Integer || Hi == X87UP) &&
+ "Unknown missing lo part");
+ break;
+ case SSEUp:
+ case X87UP:
+ llvm_unreachable("Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
+ // hidden argument.
+ case Memory:
+ return getIndirectReturnResult(RetTy);
+
+ // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
+ // available register of the sequence %rax, %rdx is used.
+ case Integer:
+ ResType = getIntegerTypeAtOffset(RetTy, 0, RetTy, 0);
+
+ // If we have a sign or zero extended integer, make sure to return Extend
+ // so that the parameter gets the right LLVM IR attributes.
+ if (Hi == NoClass && ResType->isInteger()) {
+ const IntegerType *IntTy = cast<IntegerType>(RetTy);
+ if (IntTy && isPromotableIntegerType(IntTy)) {
+ ABIArgInfo Info = ABIArgInfo::getExtend(ResType);
+ return Info;
+ }
+ }
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
+ // available SSE register of the sequence %xmm0, %xmm1 is used.
+ case SSE:
+ ResType = getSSETypeAtOffset(RetTy, 0, RetTy, 0);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
+ // returned on the X87 stack in %st0 as 80-bit x87 number.
+ case X87:
+ ResType = TB.getFloatType(APFloat::x87DoubleExtended(), Align(16));
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real
+ // part of the value is returned in %st0 and the imaginary part in
+ // %st1.
+ case Complex_X87:
+ assert(Hi == Complex_X87 && "Unexpected ComplexX87 classification.");
+ {
+ const Type *X87Type =
+ TB.getFloatType(APFloat::x87DoubleExtended(), Align(16));
+ FieldInfo Fields[] = {
+ FieldInfo(X87Type, 0), FieldInfo(X87Type, 128) // 128 bits offset
+ };
+ ResType = TB.getStructType(Fields, TypeSize::getFixed(256), Align(16));
+ }
+ break;
+ }
+
+ const Type *HighPart = nullptr;
+ switch (Hi) {
+ // Memory was handled previously and X87 should
+ // never occur as a hi class.
+ case Memory:
+ case X87:
+ llvm_unreachable("Invalid classification for hi word.");
+
+ case Complex_X87:
+ case NoClass:
+ break;
+
+ case Integer:
+ HighPart = getIntegerTypeAtOffset(RetTy, 8, RetTy, 8);
+ if (Lo == NoClass)
+ return ABIArgInfo::getDirect(HighPart);
+ break;
+
+ case SSE:
+ HighPart = getSSETypeAtOffset(RetTy, 8, RetTy, 8);
+ if (Lo == NoClass)
+ return ABIArgInfo::getDirect(HighPart);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
+ // is passed in the next available eightbyte chunk if the last used
+ // vector register.
+ //
+ // SSEUP should always be preceded by SSE, just widen.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = getByteVectorType(RetTy);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
+ // returned together with the previous X87 value in %st0.
+ case X87UP:
+ // If X87Up is preceded by X87, we don't need to do
+ // anything. However, in some cases with unions it may not be
+ // preceded by X87. In such situations we follow gcc and pass the
+ // extra bits in an SSE reg.
+ if (Lo != X87) {
+ HighPart = getSSETypeAtOffset(RetTy, 8, RetTy, 8);
+ if (Lo == NoClass) // Return HighPart at offset 8 in memory.
+ return ABIArgInfo::getDirect(HighPart);
+ }
+ break;
+ }
+
+ // If a high part was specified, merge it together with the low part. It is
+ // known to pass in the high eightbyte of the result. We do this by forming a
+ // first class struct aggregate with the high and low part: {low, high}
+ if (HighPart)
+ ResType = createPairType(ResType, HighPart);
+
+ return ABIArgInfo::getDirect(ResType);
+}
+
+/// GetX86_64ByValArgumentPair - Given a high and low type that can ideally
+/// be used as elements of a two register pair to pass or return, return a
+/// first class aggregate to represent them. For example, if the low part of
+/// a by-value argument should be passed as i32* and the high part as float,
+/// return {i32*, float}.
+const Type *X86_64ABIInfo::createPairType(const Type *Lo,
+ const Type *Hi) const {
+ // In order to correctly satisfy the ABI, we need to the high part to start
+ // at offset 8. If the high and low parts we inferred are both 4-byte types
+ // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have
+ // the second element at offset 8. Check for this:
+ unsigned LoSize = Lo->getSizeInBits().getFixedValue() / 8;
+ Align HiAlign = Hi->getAlignment();
+ unsigned HiStart = alignTo(LoSize, HiAlign);
+
+ assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
+
+ // To handle this, we have to increase the size of the low part so that the
+ // second element will start at an 8 byte offset. We can't increase the size
+ // of the second element because it might make us access off the end of the
+ // struct.
+ const Type *AdjustedLo = Lo;
+ if (HiStart != 8) {
+ // There are usually two sorts of types the ABI generation code can produce
+ // for the low part of a pair that aren't 8 bytes in size: half, float or
+ // i8/i16/i32. This can also include pointers when they are 32-bit (X32 and
+ // NaCl).
+ // Promote these to a larger type.
+ if (Lo->isFloat()) {
+ const FloatType *FT = cast<FloatType>(Lo);
+ if (FT->getSemantics() == &APFloat::IEEEhalf() ||
+ FT->getSemantics() == &APFloat::IEEEsingle()) {
+ AdjustedLo = TB.getFloatType(APFloat::IEEEdouble(), Align(8));
+ }
+ }
+ // Promote integers and pointers to i64
+ else if (Lo->isInteger() || Lo->isPointer()) {
+ AdjustedLo = TB.getIntegerType(64, Align(8), /*Signed=*/false);
+ } else {
+ assert(false && "Invalid/unknown low type in pair");
+ }
+ }
+
+ // Create the pair struct
+ FieldInfo Fields[] = {
+ FieldInfo(AdjustedLo, 0), // Low part at offset 0
+ FieldInfo(Hi, 8 * 8) // High part at offset 8 bytes (64 bits)
+ };
+
+ // Verify the high part is at offset 8
+ assert((8 * 8) == Fields[1].OffsetInBits &&
+ "High part must be at offset 8 bytes");
+
+ return TB.getStructType(Fields,
+ TypeSize::getFixed(128), // Total size 16 bytes
+ Align(8), // Natural alignment
+ StructPacking::Default);
+}
+
+static bool bitsContainNoUserData(const Type *Ty, unsigned StartBit,
+ unsigned EndBit) {
+ // If range is completely beyond type size, it's definitely padding
+ unsigned TySize = Ty->getSizeInBits().getFixedValue();
+ if (TySize <= StartBit)
+ return true;
+
+ // Handle arrays - check each element
+ if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+ const Type *EltTy = AT->getElementType();
+ unsigned EltSize = EltTy->getSizeInBits().getFixedValue();
+
+ for (unsigned I = 0; I < AT->getNumElements(); ++I) {
+ unsigned EltOffset = I * EltSize;
+ if (EltOffset >= EndBit)
+ break; // Elements are sorted by offset
+
+ unsigned EltStart = (EltOffset < StartBit) ? StartBit - EltOffset : 0;
+ if (!bitsContainNoUserData(EltTy, EltStart, EndBit - EltOffset))
+ return false;
+ }
+ return true;
+ }
+
+ // Handle structs - check all fields and base classes
+ if (const StructType *ST = dyn_cast<StructType>(Ty)) {
+ // Check base classes first (for C++ records)
+ if (ST->isCXXRecord()) {
+ for (unsigned I = 0; I < ST->getNumBaseClasses(); ++I) {
+ const FieldInfo &Base = ST->getBaseClasses()[I];
+ if (Base.OffsetInBits >= EndBit)
+ continue;
+
+ unsigned BaseStart =
+ (Base.OffsetInBits < StartBit) ? StartBit - Base.OffsetInBits : 0;
+ if (!bitsContainNoUserData(Base.FieldType, BaseStart,
+ EndBit - Base.OffsetInBits))
+ return false;
+ }
+ }
+
+ // Check all fields
+ for (unsigned I = 0; I < ST->getNumFields(); ++I) {
+ const FieldInfo &Field = ST->getFields()[I];
+ if (Field.OffsetInBits >= EndBit)
+ break; // Fields are sorted by offset
+
+ unsigned FieldStart =
+ (Field.OffsetInBits < StartBit) ? StartBit - Field.OffsetInBits : 0;
+ if (!bitsContainNoUserData(Field.FieldType, FieldStart,
+ EndBit - Field.OffsetInBits))
+ return false;
+ }
+ return true;
+ }
+
+ // For unions, vectors, and primitives - assume all bits are user data
+ return false;
+}
+
+const Type *X86_64ABIInfo::getIntegerTypeAtOffset(const Type *ABIType,
+ unsigned ABIOffset,
+ const Type *SourceTy,
+ unsigned SourceOffset) const {
+ // If we're dealing with an un-offset ABI type, then it means that we're
+ // returning an 8-byte unit starting with it. See if we can safely use it.
+ if (ABIOffset == 0) {
+ // Pointers and 64-bit integers fill the 8-byte unit
+ if ((ABIType->isPointer() && Has64BitPointers) ||
+ (ABIType->isInteger() &&
+ cast<IntegerType>(ABIType)->getSizeInBits() == 64))
+ return ABIType;
+
+ // If we have a 1/2/4-byte integer, we can use it only if the rest of the
+ // goodness in the source type is just tail padding. This is allowed to
+ // kick in for struct {double,int} on the int, but not on
+ // struct{double,int,int} because we wouldn't return the second int. We
+ // have to do this analysis on the source type because we can't depend on
+ // unions being lowered a specific way etc.
+ if (ABIType->isInteger()) {
+ unsigned BitWidth = cast<IntegerType>(ABIType)->getSizeInBits();
+ if (BitWidth == 8 || BitWidth == 16 || BitWidth == 32) {
+ // Check if the rest is just padding
+ if (bitsContainNoUserData(SourceTy, SourceOffset * 8 + BitWidth,
+ SourceOffset * 8 + 64))
+ return ABIType;
+ }
+ } else if (ABIType->isPointer() && !Has64BitPointers) {
+ // Check if the rest is just padding
+ if (bitsContainNoUserData(SourceTy, SourceOffset * 8 + 32,
+ SourceOffset * 8 + 64))
+ return ABIType;
+ }
+ }
+
+ // Handle structs by recursing into fields
+ if (auto *STy = dyn_cast<StructType>(ABIType)) {
+ const FieldInfo *Fields = STy->getFields();
+
+ // Find field containing the IROffset
+ for (unsigned I = 0; I < STy->getNumFields(); ++I) {
+ const FieldInfo &Field = Fields[I];
+ unsigned FieldOffsetBytes = Field.OffsetInBits / 8;
+ unsigned FieldSizeBytes = Field.FieldType->getSizeInBits() / 8;
+
+ // Check if IROffset falls within this field
+ if (ABIOffset >= FieldOffsetBytes &&
+ ABIOffset < FieldOffsetBytes + FieldSizeBytes) {
+ return getIntegerTypeAtOffset(Field.FieldType,
+ ABIOffset - FieldOffsetBytes, SourceTy,
+ SourceOffset);
+ }
+ }
+ }
+
+ // Handle arrays
+ if (auto *ATy = dyn_cast<ArrayType>(ABIType)) {
+ const Type *EltTy = ATy->getElementType();
+ unsigned EltSize = EltTy->getSizeInBits() / 8;
+ if (EltSize > 0) { // Avoid division by zero
+ unsigned EltOffset = (ABIOffset / EltSize) * EltSize;
+ return getIntegerTypeAtOffset(EltTy, ABIOffset - EltOffset, SourceTy,
+ SourceOffset);
+ }
+ }
+
+ // Default case - use integer type that fits
+ unsigned TySizeInBytes = SourceTy->getSizeInBits() / 8;
+ assert(TySizeInBytes != SourceOffset && "Empty field?");
+ unsigned AvailableSize = TySizeInBytes - SourceOffset;
+ return TB.getIntegerType(std::min(AvailableSize, 8U) * 8, Align(1),
+ /*Signed=*/false);
+}
+/// Returns the floating point type at the specified offset within a type, or
+/// nullptr if no floating point type is found at that offset.
+const Type *X86_64ABIInfo::getFPTypeAtOffset(const Type *Ty,
+ unsigned Offset) const {
+ // Check for direct match at offset 0
+ if (Offset == 0 && Ty->isFloat())
+ return Ty;
+
+ // Handle struct types by checking each field
+ if (const StructType *ST = dyn_cast<StructType>(Ty)) {
+ const FieldInfo *Fields = ST->getFields();
+
+ // Find the field containing the requested offset
+ for (unsigned i = 0; i < ST->getNumFields(); ++i) {
+ unsigned FieldOffset = Fields[i].OffsetInBits / 8; // Convert to bytes
+ unsigned FieldSize = Fields[i].FieldType->getSizeInBits() / 8;
+
+ // Check if offset falls within this field
+ if (Offset >= FieldOffset && Offset < FieldOffset + FieldSize) {
+ return getFPTypeAtOffset(Fields[i].FieldType, Offset - FieldOffset);
+ }
+ }
+ return nullptr;
+ }
+
+ // Handle array types
+ if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+ const Type *EltTy = AT->getElementType();
+ unsigned EltSize = EltTy->getSizeInBits() / 8;
+ unsigned EltIndex = Offset / EltSize;
+
+ return getFPTypeAtOffset(EltTy, Offset - (EltIndex * EltSize));
+ }
+
+ // No floating point type found at this offset
+ return nullptr;
+}
+
+/// Helper to check if a floating point type matches specific semantics
+static bool isFloatTypeWithSemantics(const Type *Ty,
+ const fltSemantics &Semantics) {
+ if (!Ty->isFloat())
+ return false;
+ const FloatType *FT = cast<FloatType>(Ty);
+ return FT->getSemantics() == &Semantics;
+}
+
+/// GetSSETypeAtOffset - Return a type that will be passed by the backend in the
+/// low 8 bytes of an XMM register, corresponding to the SSE class.
+const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
+ unsigned ABIOffset,
+ const Type *SourceTy,
+ unsigned SourceOffset) const {
+ // Get the floating point type at the requested offset
+ const Type *T0 = getFPTypeAtOffset(ABIType, ABIOffset);
+ if (!T0 || isFloatTypeWithSemantics(T0, APFloat::IEEEdouble()))
+ return TB.getFloatType(APFloat::IEEEdouble(), Align(8));
+
+ // Calculate remaining source size in bytes
+ unsigned SourceSize =
+ (SourceTy->getSizeInBits().getFixedValue() / 8) - SourceOffset;
+
+ // Try to get adjacent FP type
+ const Type *T1 = nullptr;
+ unsigned T0Size = T0->getSizeInBits().getFixedValue() / 8;
+ if (SourceSize > T0Size)
+ T1 = getFPTypeAtOffset(ABIType, ABIOffset + T0Size);
+
+ // Special case for half/bfloat + float combinations
+ if (!T1 && isFloatTypeWithSemantics(T0, APFloat::IEEEhalf()) &&
+ SourceSize > 4)
+ T1 = getFPTypeAtOffset(ABIType, ABIOffset + 4);
+
+ // If no adjacent type found, return the single type
+ if (!T1)
+ return T0;
+
+ // Handle vector cases
+ if (isFloatTypeWithSemantics(T0, APFloat::IEEEsingle()) &&
+ isFloatTypeWithSemantics(T1, APFloat::IEEEsingle())) {
+ return TB.getVectorType(T0, ElementCount::getFixed(2), Align(8));
+ }
+
+ if (isFloatTypeWithSemantics(T0, APFloat::IEEEhalf()) &&
+ isFloatTypeWithSemantics(T1, APFloat::IEEEhalf())) {
+ const Type *T2 = nullptr;
+ if (SourceSize > 4)
+ T2 = getFPTypeAtOffset(ABIType, ABIOffset + 4);
+ if (!T2)
+ return TB.getVectorType(T0, ElementCount::getFixed(2), Align(8));
+ return TB.getVectorType(T0, ElementCount::getFixed(4), Align(8));
+ }
+
+ // Mixed half-float cases
+ if (isFloatTypeWithSemantics(T0, APFloat::IEEEhalf()) ||
+ isFloatTypeWithSemantics(T1, APFloat::IEEEhalf())) {
+ return TB.getVectorType(TB.getFloatType(APFloat::IEEEhalf(), Align(2)),
+ ElementCount::getFixed(4), Align(8));
+ }
+
+ // Default to double
+ return TB.getFloatType(APFloat::IEEEdouble(), Align(8));
+}
+
+/// The ABI specifies that a value should be passed in a full vector XMM/YMM
+/// register. Pick an LLVM IR type that will be passed as a vector register.
+const Type *X86_64ABIInfo::getByteVectorType(const Type *Ty) const {
+ // Wrapper structs/arrays that only contain vectors are passed just like
+ // vectors; strip them off if present.
+ if (const Type *InnerTy = isSingleElementStruct(Ty))
+ Ty = InnerTy;
+
+ // Handle vector types
+ if (const VectorType *VT = dyn_cast<VectorType>(Ty)) {
+ // Don't pass vXi128 vectors in their native type, the backend can't
+ // legalize them.
+ if (passInt128VectorsInMem() && VT->getElementType()->isInteger() &&
+ cast<IntegerType>(VT->getElementType())->getSizeInBits() == 128) {
+ unsigned Size = VT->getSizeInBits().getFixedValue();
+ return TB.getVectorType(TB.getIntegerType(64, Align(8), /*Signed=*/false),
+ ElementCount::getFixed(Size / 64),
+ Align(Size / 8));
+ }
+ return VT;
+ }
+
+ // Handle fp128
+ if (isFloatTypeWithSemantics(Ty, APFloat::IEEEquad()))
+ return Ty;
+
+ // We couldn't find the preferred IR vector type for 'Ty'.
+ unsigned Size = Ty->getSizeInBits().getFixedValue();
+ assert((Size == 128 || Size == 256 || Size == 512) && "Invalid vector size");
+
+ return TB.getVectorType(TB.getFloatType(APFloat::IEEEdouble(), Align(8)),
+ ElementCount::getFixed(Size / 64), Align(Size / 8));
+}
+
+// Returns the single element if this is a single-element struct wrapper
+const Type *X86_64ABIInfo::isSingleElementStruct(const Type *Ty) const {
+ if (const StructType *ST = dyn_cast<StructType>(Ty)) {
+ if (ST->getNumFields() == 1 && ST->getNumBaseClasses() == 0)
+ return ST->getFields()[0].FieldType;
+ }
+ return nullptr;
+}
+
+ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
+ // If this is a scalar value, handle it specially
+ if (!isAggregateTypeForABI(Ty)) {
+ // Handle integer types that need extension
+ if (Ty->isInteger()) {
+ const IntegerType *IntTy = cast<IntegerType>(Ty);
+ if (isPromotableIntegerType(IntTy)) {
+ ABIArgInfo Info = ABIArgInfo::getExtend(Ty);
+ return Info;
+ }
+ }
+ return ABIArgInfo::getDirect();
+ }
+
+ // For aggregate types or other cases, return as indirect
+ return getNaturalAlignIndirect(Ty);
+}
+
} // namespace abi
} // namespace llvm
>From f948b105edfd1a1981c93a58f31dbad5605eea3a Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Fri, 1 Aug 2025 19:19:43 +0530
Subject: [PATCH 16/17] [LLVMABI] ReturnType Classifier Integration
---
clang/include/clang/CodeGen/QualTypeMapper.h | 8 +-
clang/lib/CodeGen/CodeGenTypes.h | 2 +
clang/lib/CodeGen/QualTypeMapper.cpp | 131 ++++++-
clang/lib/CodeGen/Targets/X86.cpp | 29 +-
clang/test/CodeGen/sysv_abi.c | 4 -
llvm/include/llvm/ABI/ABIInfo.h | 21 +-
llvm/include/llvm/ABI/ABITypeMapper.h | 8 +-
llvm/include/llvm/ABI/TargetCodegenInfo.h | 13 +-
llvm/include/llvm/ABI/Types.h | 132 +++++--
llvm/include/llvm/IR/DataLayout.h | 1 +
llvm/lib/ABI/ABIInfo.cpp | 58 ++-
llvm/lib/ABI/ABITypeMapper.cpp | 86 ++++-
llvm/lib/ABI/Targets/BPF.cpp | 2 +-
llvm/lib/ABI/Targets/X86.cpp | 364 +++++++++++++------
14 files changed, 671 insertions(+), 188 deletions(-)
diff --git a/clang/include/clang/CodeGen/QualTypeMapper.h b/clang/include/clang/CodeGen/QualTypeMapper.h
index 1c748bc633447..8cf365864a724 100644
--- a/clang/include/clang/CodeGen/QualTypeMapper.h
+++ b/clang/include/clang/CodeGen/QualTypeMapper.h
@@ -42,11 +42,16 @@ class QualTypeMapper {
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::Type *convertComplexType(const ComplexType *CT);
+ const llvm::abi::Type *
+ convertMemberPointerType(const clang::MemberPointerType *MPT);
+ const llvm::abi::Type *convertMatrixType(const ConstantMatrixType *MT);
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);
+ const llvm::abi::StructType *convertCXXRecordType(const CXXRecordDecl *RD,
+ bool canPassInRegs);
void computeFieldInfo(const clang::RecordDecl *RD,
SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
@@ -54,6 +59,7 @@ class QualTypeMapper {
llvm::TypeSize getTypeSize(clang::QualType QT) const;
llvm::Align getTypeAlign(clang::QualType QT) const;
+ llvm::Align getPreferredTypeAlign(QualType QT) const;
uint64_t getPointerSize() const;
uint64_t getPointerAlign() const;
diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index 186dec8aec525..5fba09bdc29e8 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -108,6 +108,8 @@ class CodeGenTypes {
const llvm::DataLayout &getDataLayout() const {
return TheModule.getDataLayout();
}
+ llvm::abi::TypeBuilder &getTypeBuilder() { return TB; }
+ clang::CodeGen::QualTypeMapper &getMapper() { return Mapper; }
CodeGenModule &getCGM() const { return CGM; }
ASTContext &getContext() const { return Context; }
const TargetInfo &getTarget() const { return Target; }
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index 90ba526e74a74..cda2928f1c206 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -15,6 +15,7 @@
///
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/QualTypeMapper.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -61,23 +62,38 @@ 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 *CT = dyn_cast<ComplexType>(QT.getTypePtr())) {
+ Result = convertComplexType(CT);
+ } else if (const auto *AT = dyn_cast<AtomicType>(QT.getTypePtr())) {
+ return convertType(AT->getValueType());
+ } else if (const auto *BPT = dyn_cast<BlockPointerType>(QT.getTypePtr())) {
+ return createPointerTypeForPointee(ASTCtx.VoidPtrTy);
+
+ } else if (const auto *MT = dyn_cast<ConstantMatrixType>(QT.getTypePtr())) {
+ const llvm::abi::Type *ElementType = convertType(MT->getElementType());
+ uint64_t NumElements = MT->getNumRows() * MT->getNumColumns();
+ llvm::Align MatrixAlign = getTypeAlign(QT);
+ return Builder.getVectorType(ElementType,
+ llvm::ElementCount::getFixed(NumElements),
+ MatrixAlign);
+ } else if (const auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
+ Result = convertMemberPointerType(MPT);
} 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();
llvm::Align TypeAlign = getTypeAlign(QT);
- return Builder.getIntegerType(NumBits, TypeAlign, IsSigned);
+ return Builder.getIntegerType(NumBits, TypeAlign, IsSigned, false, true);
} 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));
- return Builder.getPointerType(PointerSize, PointerAlign);
+ return Builder.getPointerType(PointerSize, llvm::Align(PointerAlign.value()/8),ASTCtx.getTargetInfo().getTargetAddressSpace(QT.getAddressSpace()));
} else {
QT.dump();
- llvm::errs() << "[UNHANDLED TYPE]\n";
}
TypeCache[QT] = Result;
return Result;
@@ -97,7 +113,12 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
case BuiltinType::Void:
return Builder.getVoidType();
+ case BuiltinType::NullPtr:
+ return createPointerTypeForPointee(QT);
+
case BuiltinType::Bool:
+ return Builder.getIntegerType(ASTCtx.getTypeSize(QT), getTypeAlign(QT),
+ false, true);
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::SChar:
@@ -165,12 +186,68 @@ 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());
+
+ if (auto *IT = llvm::dyn_cast<llvm::abi::IntegerType>(ElementType)) {
+ unsigned BW = IT->getSizeInBits().getFixedValue();
+
+ if (BW != 1 && (BW & 7)) {
+ BW = llvm::bit_ceil(BW);
+ BW = std::clamp(BW, 8u, 64u);
+ bool Signed = IT->isSigned();
+ ElementType = Builder.getIntegerType(BW, llvm::Align(BW / 8), Signed);
+ } else if (BW < 8 && BW != 1) {
+ bool Signed = IT->isSigned();
+ ElementType = Builder.getIntegerType(8, llvm::Align(1), Signed);
+ }
+ }
+
+ unsigned NElems = VT->getNumElements();
+ if (!llvm::isPowerOf2_32(NElems))
+ NElems = llvm::bit_ceil(NElems);
llvm::ElementCount NumElements =
- llvm::ElementCount::getFixed(VT->getNumElements());
+ llvm::ElementCount::getFixed(NElems);
llvm::Align VectorAlign = getTypeAlign(QualType(VT, 0));
- return Builder.getVectorType(ElementType, NumElements, VectorAlign);
+ return
+ Builder.getVectorType(ElementType, NumElements, VectorAlign);
+}
+
+/// Converts complex types to LLVM ABI complex representations.
+/// Complex types consist of two components of the element type
+/// (real and imaginary parts).
+///
+/// \param CT The ComplexType to convert
+/// \return LLVM ABI ComplexType with element type and alignment
+const llvm::abi::Type *
+QualTypeMapper::convertComplexType(const ComplexType *CT) {
+ const llvm::abi::Type *ElementType = convertType(CT->getElementType());
+ llvm::Align ComplexAlign = getTypeAlign(QualType(CT, 0));
+
+ auto *Result = Builder.getComplexType(ElementType, ComplexAlign);
+
+ return Result;
+ // return Builder.getComplexType(ElementType, ComplexAlign);
+}
+
+/// Converts member pointer types to LLVM ABI representations.
+/// Member pointers have different layouts depending on whether they
+/// point to functions or data members.
+///
+/// \param MPT The MemberPointerType to convert
+/// \return LLVM ABI MemberPointerType
+const llvm::abi::Type *
+QualTypeMapper::convertMemberPointerType(const clang::MemberPointerType *MPT) {
+ QualType QT(MPT, 0);
+ uint64_t Size = ASTCtx.getTypeSize(QT);
+ llvm::Align Align = getTypeAlign(QT);
+
+ bool IsFunctionPointer = MPT->isFunctionType();
+ bool Has64BitPointers =
+ ASTCtx.getTargetInfo().getPointerWidth(LangAS::Default) == 64;
+
+ return Builder.getMemberPointerType(IsFunctionPointer, Has64BitPointers, Size,
+ Align);
}
/// Converts record types (struct/class/union) to LLVM ABI representations.
@@ -181,10 +258,18 @@ const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
/// \return LLVM ABI StructType or UnionType
const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
+ bool canPassInRegs = false;
+ bool hasFlexibleArrMember = false;
+ if (RD) {
+ canPassInRegs = RT->getDecl()->canPassInRegisters();
+ hasFlexibleArrMember = RD->hasFlexibleArrayMember();
+ }
if (!RD) {
SmallVector<llvm::abi::FieldInfo, 0> Fields;
- return Builder.getStructType(Fields, llvm::TypeSize::getFixed(0),
- llvm::Align(1));
+ return Builder.getStructType(
+ Fields, llvm::TypeSize::getFixed(0), llvm::Align(1),
+ llvm::abi::StructPacking::Default, {}, {}, false, false, false, false,
+ hasFlexibleArrMember, false, canPassInRegs);
}
if (RD->isUnion())
@@ -193,7 +278,7 @@ const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
// 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 convertCXXRecordType(CXXRd, canPassInRegs);
}
return convertStructType(RD);
}
@@ -207,7 +292,8 @@ const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
/// \param RD The C++ record declaration
/// \return LLVM ABI StructType representing the complete object layout
const llvm::abi::StructType *
-QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
+QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD,
+ bool canPassInRegs) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
SmallVector<llvm::abi::FieldInfo, 16> Fields;
SmallVector<llvm::abi::FieldInfo, 8> BaseClasses;
@@ -261,7 +347,7 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
bool HasNonTrivialCopy = !RD->hasSimpleCopyConstructor();
bool HasNonTrivialDtor = !RD->hasSimpleDestructor();
- bool HasFlexibleArrayMember = false;
+ bool HasFlexibleArrayMember = RD->hasFlexibleArrayMember();
bool HasUnalignedFields = false;
unsigned FieldIndex = 0;
@@ -278,7 +364,8 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
return Builder.getStructType(
Fields, Size, Alignment, llvm::abi::StructPacking::Default, BaseClasses,
VirtualBaseClasses, true, RD->isPolymorphic(), HasNonTrivialCopy,
- HasNonTrivialDtor, HasFlexibleArrayMember, HasUnalignedFields);
+ HasNonTrivialDtor, HasFlexibleArrayMember, HasUnalignedFields,
+ canPassInRegs);
}
/// Converts reference types to pointer representations in the ABI.
@@ -329,6 +416,7 @@ const llvm::abi::StructType *
QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
+ bool IsCXXRecord = isa<CXXRecordDecl>(RD);
SmallVector<llvm::abi::FieldInfo, 16> Fields;
computeFieldInfo(RD, Fields, Layout);
@@ -336,7 +424,10 @@ QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
llvm::TypeSize::getFixed(Layout.getSize().getQuantity() * 8);
llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
- return Builder.getStructType(Fields, Size, Alignment);
+ return Builder.getStructType(
+ Fields, Size, Alignment, llvm::abi::StructPacking::Default, {}, {}, IsCXXRecord,
+ false, false, false, RD->hasFlexibleArrayMember(), false,
+ RD->canPassInRegisters());
}
/// Converts C union types where all fields occupy the same memory location.
@@ -359,8 +450,13 @@ QualTypeMapper::convertUnionType(const clang::RecordDecl *RD) {
return Builder.getUnionType(Fields, Size, Alignment);
}
+llvm::Align QualTypeMapper::getPreferredTypeAlign(QualType QT) const {
+ return llvm::Align(ASTCtx.getPreferredTypeAlignInChars(QT).getQuantity());
+}
+
llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const {
- return llvm::Align(ASTCtx.getTypeAlign(QT));
+
+ return llvm::Align(ASTCtx.getTypeAlignInChars(QT).getQuantity());
}
const llvm::abi::Type *
@@ -369,7 +465,7 @@ QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
llvm::Align Alignment =
llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(AddrSpace));
- return Builder.getPointerType(PointerSize, Alignment);
+ return Builder.getPointerType(PointerSize, llvm::Align(Alignment.value()/8),ASTCtx.getTargetInfo().getTargetAddressSpace(AddrSpace));
}
/// Processes the fields of a record (struct/class/union) and populates
@@ -390,11 +486,14 @@ void QualTypeMapper::computeFieldInfo(
bool IsBitField = FD->isBitField();
uint64_t BitFieldWidth = 0;
+ bool IsUnnamed = false;
- if (IsBitField)
+ if (IsBitField) {
BitFieldWidth = FD->getBitWidthValue();
+ IsUnnamed = FD->isUnnamedBitField();
+ }
- Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth);
+ Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth,IsUnnamed);
++FieldIndex;
}
}
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index d3431aae0431c..7bcb48394bd9f 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -7,9 +7,13 @@
//===----------------------------------------------------------------------===//
#include "ABIInfoImpl.h"
+#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/Basic/DiagnosticFrontend.h"
+#include "llvm/ABI/ABIInfo.h"
+#include "llvm/ABI/Types.h"
#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -2104,6 +2108,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
}
}
+
// Classify the fields one at a time, merging the results.
unsigned idx = 0;
bool UseClang11Compat = getContext().getLangOpts().getClangABICompat() <=
@@ -2179,6 +2184,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
Hi = merge(Hi, FieldHi);
if (Lo == Memory || Hi == Memory)
break;
+
+
}
postMerge(Size, Lo, Hi);
@@ -2962,6 +2969,17 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
unsigned FreeSSERegs = IsRegCall ? 16 : 8;
unsigned NeededInt = 0, NeededSSE = 0, MaxVectorWidth = 0;
+ llvm::abi::ABICompatInfo CompatInfo;
+ CompatInfo.Flags.ClassifyIntegerMMXAsSSE = classifyIntegerMMXAsSSE();
+ CompatInfo.Flags.HonorsRevision98 = honorsRevision0_98();
+ CompatInfo.Flags.PassInt128VectorsInMem = passInt128VectorsInMem();
+ CompatInfo.Flags.ReturnCXXRecordGreaterThan128InMem =
+ returnCXXRecordGreaterThan128InMem();
+ auto avxABILvl = static_cast<llvm::abi::X86AVXABILevel>(AVXLevel);
+ auto newTargetInfo = llvm::abi::createX8664TargetCodeGenInfo(
+ CGT.getTypeBuilder(), CGT.getTarget().getTriple(), avxABILvl,
+ Has64BitPointers, CompatInfo);
+
if (!::classifyReturnType(getCXXABI(), FI, *this)) {
if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() &&
!FI.getReturnType()->getTypePtr()->isUnionType()) {
@@ -2981,8 +2999,15 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Complex Long Double Type is passed in Memory when Regcall
// calling convention is used.
FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
- else
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ else {
+ // FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ const llvm::abi::Type *mappedTy =
+ CGT.getMapper().convertType(FI.getReturnType());
+ llvm::abi::ABIArgInfo newRetInfo =
+ newTargetInfo->getABIInfo().classifyReturnType(mappedTy);
+ FI.getReturnInfo() =
+ CGT.convertABIArgInfo(newRetInfo, FI.getReturnType());
+ }
}
// If the return value is indirect, then the hidden argument is consuming one
diff --git a/clang/test/CodeGen/sysv_abi.c b/clang/test/CodeGen/sysv_abi.c
index 29ea819c2aa26..36c0872a9253f 100644
--- a/clang/test/CodeGen/sysv_abi.c
+++ b/clang/test/CodeGen/sysv_abi.c
@@ -30,14 +30,10 @@ typedef __attribute__((vector_size(64))) float my_m512;
my_m256 SYSV_CC get_m256(void);
void SYSV_CC take_m256(my_m256);
-my_m512 SYSV_CC get_m512(void);
-void SYSV_CC take_m512(my_m512);
void use_vectors(void) {
my_m256 v1 = get_m256();
take_m256(v1);
- my_m512 v2 = get_m512();
- take_m512(v2);
}
// CHECK: define {{(dso_local )?}}void @use_vectors()
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
index 6a14b9187854c..624bac2a5d2ea 100644
--- a/llvm/include/llvm/ABI/ABIInfo.h
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -23,6 +23,20 @@
namespace llvm {
namespace abi {
+enum RecordArgABI {
+ /// Pass it using the normal C aggregate rules for the ABI, potentially
+ /// introducing extra copies and passing some or all of it in registers.
+ RAA_Default = 0,
+
+ /// Pass it on the stack using its defined layout. The argument must be
+ /// evaluated directly into the correct stack position in the arguments area,
+ /// and the call machinery must not move it or introduce extra copies.
+ RAA_DirectInMemory,
+
+ /// Pass it as a pointer to temporary memory.
+ RAA_Indirect
+};
+
struct ABICompatInfo {
unsigned Version = UINT_MAX;
@@ -54,14 +68,19 @@ class ABIInfo {
virtual ~ABIInfo() = default;
+ RecordArgABI getRecordArgABI(const StructType *ST) const;
virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
- virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
+ // virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
virtual void computeInfo(ABIFunctionInfo &FI) const = 0;
virtual bool isPassByRef(const Type *Ty) const { return false; }
const ABICompatInfo &getABICompatInfo() const { return CompatInfo; }
ABIArgInfo getNaturalAlignIndirect(const Type *Ty) const;
bool isAggregateTypeForABI(const Type *Ty) const;
bool isPromotableIntegerType(const IntegerType *Ty) const;
+bool isZeroSizedType(const Type *Ty) const;
+bool isEmptyRecord(const StructType *ST)const;
+bool isEmptyField(const FieldInfo &FI)const;
+
void setABICompatInfo(const ABICompatInfo &Info) { CompatInfo = Info; }
};
diff --git a/llvm/include/llvm/ABI/ABITypeMapper.h b/llvm/include/llvm/ABI/ABITypeMapper.h
index f326ca00dc392..774df108c6d50 100644
--- a/llvm/include/llvm/ABI/ABITypeMapper.h
+++ b/llvm/include/llvm/ABI/ABITypeMapper.h
@@ -47,6 +47,8 @@ class ABITypeMapper {
Type *convertArrayType(const abi::ArrayType *AT);
+ Type *convertMatrixType(const abi::ArrayType *MT);
+
Type *convertVectorType(const abi::VectorType *VT);
Type *convertStructType(const abi::StructType *ST);
@@ -59,7 +61,11 @@ class ABITypeMapper {
StructType *createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
uint32_t NumFields, TypeSize Size,
- Align Alignment, bool IsUnion = false);
+ Align Alignment, bool IsUnion = false,
+ bool IsCoercedStr = false);
+ Type *convertComplexType(const abi::ComplexType *CT);
+
+ Type *convertMemberPointerType(const abi::MemberPointerType *MPT);
};
} // namespace llvm
diff --git a/llvm/include/llvm/ABI/TargetCodegenInfo.h b/llvm/include/llvm/ABI/TargetCodegenInfo.h
index 54110bb3bc1ec..80ecd58593742 100644
--- a/llvm/include/llvm/ABI/TargetCodegenInfo.h
+++ b/llvm/include/llvm/ABI/TargetCodegenInfo.h
@@ -1,4 +1,5 @@
#include "llvm/ABI/ABIInfo.h"
+#include "llvm/TargetParser/Triple.h"
#include <memory>
#ifndef LLVM_ABI_TARGETCODEGENINFO_H
@@ -28,9 +29,17 @@ createDefaultTargetCodeGenInfo(TypeBuilder &TB);
std::unique_ptr<TargetCodeGenInfo> createBPFTargetCodeGenInfo(TypeBuilder &TB);
-std::unique_ptr<TargetCodeGenInfo>
-createX8664TargetCodeGenInfo(TypeBuilder &TB);
+/// The AVX ABI level for X86 targets.
+enum class X86AVXABILevel {
+ None,
+ AVX,
+ AVX512,
+};
+std::unique_ptr<TargetCodeGenInfo>
+createX8664TargetCodeGenInfo(TypeBuilder &TB, const Triple &Triple,
+ X86AVXABILevel AVXLevel, bool Has64BitPointers,
+ const ABICompatInfo &Compat);
std::unique_ptr<TargetCodeGenInfo>
createAArch64TargetCodeGenInfo(TypeBuilder &TB);
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 781ccf031c41c..01373f999baea 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -21,6 +21,7 @@
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/TypeSize.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdint>
namespace llvm {
@@ -40,26 +41,44 @@ enum class TypeKind {
};
class Type {
+private:
+ TypeSize getTypeStoreSize() const {
+ TypeSize StoreSizeInBits = getTypeStoreSizeInBits();
+ return {StoreSizeInBits.getKnownMinValue() / 8,
+ StoreSizeInBits.isScalable()};
+ }
+ TypeSize getTypeStoreSizeInBits() const {
+ TypeSize BaseSize = getSizeInBits();
+ uint64_t AlignedSizeInBits =
+ alignToPowerOf2(BaseSize.getKnownMinValue(), 8);
+ return {AlignedSizeInBits, BaseSize.isScalable()};
+ }
+
protected:
TypeKind Kind;
TypeSize SizeInBits;
- Align Alignment;
+ Align ABIAlignment;
+ Align PreferredAlignment;
bool IsExplicitlyAligned;
Type(TypeKind K, TypeSize Size, Align Align, bool ExplicitAlign = false)
- : Kind(K), SizeInBits(Size), Alignment(Align),
+ : Kind(K), SizeInBits(Size), ABIAlignment(Align),
IsExplicitlyAligned(ExplicitAlign) {}
public:
TypeKind getKind() const { return Kind; }
TypeSize getSizeInBits() const { return SizeInBits; }
- Align getAlignment() const { return Alignment; }
+ Align getAlignment() const { return ABIAlignment; }
+ Align getPrefferedAlign() const { return PreferredAlignment; }
bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
void setExplicitAlignment(Align Align) {
- Alignment = Align;
+ ABIAlignment = Align;
IsExplicitlyAligned = true;
}
+ TypeSize getTypeAllocSize() const {
+ return alignTo(getTypeStoreSize(), getAlignment().value());
+ }
bool isVoid() const { return Kind == TypeKind::Void; }
bool isInteger() const { return Kind == TypeKind::Integer; }
@@ -70,7 +89,7 @@ class Type {
bool isStruct() const { return Kind == TypeKind::Struct; }
bool isUnion() const { return Kind == TypeKind::Union; }
bool isMemberPointer() const { return Kind == TypeKind::MemberPointer; }
- bool isComplex() const { return Kind == TypeKind::Union; }
+ bool isComplex() const { return Kind == TypeKind::Complex; }
};
class VoidType : public Type {
@@ -120,13 +139,18 @@ class MemberPointerType : public Type {
class IntegerType : public Type {
private:
bool IsSigned;
+ bool IsBoolean;
+ bool IsBitInt;
public:
- IntegerType(uint64_t BitWidth, Align Align, bool Signed)
+ IntegerType(uint64_t BitWidth, Align Align, bool Signed, bool IsBool = false,
+ bool BitInt = false)
: Type(TypeKind::Integer, TypeSize::getFixed(BitWidth), Align),
- IsSigned(Signed) {}
+ IsSigned(Signed), IsBoolean(IsBool), IsBitInt(BitInt) {}
bool isSigned() const { return IsSigned; }
+ bool isBool() const { return IsBoolean; }
+ bool isBitInt() const { return IsBitInt; }
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Integer;
@@ -204,12 +228,13 @@ struct FieldInfo {
const Type *FieldType;
uint64_t OffsetInBits;
bool IsBitField;
+ bool IsUnnamedBitfield;
uint64_t BitFieldWidth;
FieldInfo(const Type *Type, uint64_t Offset = 0, bool BitField = false,
- uint64_t BFWidth = 0)
+ uint64_t BFWidth = 0,bool IsUnnamedBF = false)
: FieldType(Type), OffsetInBits(Offset), IsBitField(BitField),
- BitFieldWidth(BFWidth) {}
+ IsUnnamedBitfield(IsUnnamedBF), BitFieldWidth(BFWidth) {}
};
enum class StructPacking { Default, Packed, ExplicitPacking };
@@ -219,6 +244,8 @@ class StructType : public Type {
const FieldInfo *Fields;
uint32_t NumFields;
StructPacking Packing;
+ bool CanPassInRegisters;
+ bool IsCoercedStruct;
bool IsCXXRecord;
bool IsPolymorphic;
@@ -238,9 +265,11 @@ class StructType : public Type {
Align Align, StructPacking Pack = StructPacking::Default,
bool CXXRecord = false, bool Polymorphic = false,
bool NonTrivialCopy = false, bool NonTrivialDtor = false,
- bool FlexibleArray = false, bool UnalignedFields = false)
+ bool FlexibleArray = false, bool UnalignedFields = false,
+ bool CanPassInRegs = false, bool IsCoercedStr = false)
: Type(TypeKind::Struct, Size, Align), Fields(StructFields),
- NumFields(FieldCount), Packing(Pack), IsCXXRecord(CXXRecord),
+ NumFields(FieldCount), Packing(Pack), CanPassInRegisters(CanPassInRegs),
+ IsCoercedStruct(IsCoercedStr), IsCXXRecord(CXXRecord),
IsPolymorphic(Polymorphic),
HasNonTrivialCopyConstructor(NonTrivialCopy),
HasNonTrivialDestructor(NonTrivialDtor),
@@ -258,6 +287,8 @@ class StructType : public Type {
bool hasNonTrivialCopyConstructor() const {
return HasNonTrivialCopyConstructor;
}
+ bool isCoercedStruct() const { return IsCoercedStruct; }
+ bool canPassInRegisters() const { return CanPassInRegisters; }
bool hasNonTrivialDestructor() const { return HasNonTrivialDestructor; }
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
bool hasUnalignedFields() const { return HasUnalignedFields; }
@@ -303,18 +334,19 @@ class TypeBuilder {
return new (Allocator.Allocate<VoidType>()) VoidType();
}
- const IntegerType *getIntegerType(uint64_t BitWidth, Align Align,
- bool Signed) {
+ const IntegerType *getIntegerType(uint64_t BitWidth, Align Align, bool Signed,
+ bool IsBoolean = false,
+ bool IsBitInt = false) {
return new (Allocator.Allocate<IntegerType>())
- IntegerType(BitWidth, Align, Signed);
+ IntegerType(BitWidth, Align, Signed, IsBoolean, IsBitInt);
}
const FloatType *getFloatType(const fltSemantics &Semantics, Align Align) {
return new (Allocator.Allocate<FloatType>()) FloatType(Semantics, Align);
}
- const PointerType *getPointerType(uint64_t Size, Align Align) {
- return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align);
+ const PointerType *getPointerType(uint64_t Size, Align Align,unsigned Addrspace = 0) {
+ return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align,Addrspace);
}
const ArrayType *getArrayType(const Type *ElementType, uint64_t NumElements) {
@@ -328,6 +360,7 @@ class TypeBuilder {
VectorType(ElementType, NumElements, Align);
}
+ // TODO: clean up this function
const StructType *
getStructType(ArrayRef<FieldInfo> Fields, TypeSize Size, Align Align,
StructPacking Pack = StructPacking::Default,
@@ -335,7 +368,8 @@ class TypeBuilder {
ArrayRef<FieldInfo> VirtualBaseClasses = {},
bool CXXRecord = false, bool Polymorphic = false,
bool NonTrivialCopy = false, bool NonTrivialDtor = false,
- bool FlexibleArray = false, bool UnalignedFields = false) {
+ bool FlexibleArray = false, bool UnalignedFields = false,
+ bool CanPassInRegister = false) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
for (size_t I = 0; I < Fields.size(); ++I)
new (&FieldArray[I]) FieldInfo(Fields[I]);
@@ -354,13 +388,48 @@ class TypeBuilder {
new (&VBaseArray[I]) FieldInfo(VirtualBaseClasses[I]);
}
- return new (Allocator.Allocate<StructType>())
- StructType(FieldArray, static_cast<uint32_t>(Fields.size()), BaseArray,
- static_cast<uint32_t>(BaseClasses.size()), VBaseArray,
- static_cast<uint32_t>(VirtualBaseClasses.size()), Size,
- Align, Pack, CXXRecord, Polymorphic, NonTrivialCopy,
- NonTrivialDtor, FlexibleArray, UnalignedFields);
+ return new (Allocator.Allocate<StructType>()) StructType(
+ FieldArray, static_cast<uint32_t>(Fields.size()), BaseArray,
+ static_cast<uint32_t>(BaseClasses.size()), VBaseArray,
+ static_cast<uint32_t>(VirtualBaseClasses.size()), Size, Align, Pack,
+ CXXRecord, Polymorphic, NonTrivialCopy, NonTrivialDtor, FlexibleArray,
+ UnalignedFields, CanPassInRegister);
}
+ const StructType *
+ getCoercedStructType(ArrayRef<FieldInfo> Fields, TypeSize Size, Align Align,
+ StructPacking Pack = StructPacking::Default,
+ ArrayRef<FieldInfo> BaseClasses = {},
+ ArrayRef<FieldInfo> VirtualBaseClasses = {},
+ bool CXXRecord = false, bool Polymorphic = false,
+ bool NonTrivialCopy = false, bool NonTrivialDtor = false,
+ bool FlexibleArray = false, bool UnalignedFields = false,
+ bool CanPassInRegister = false) {
+ FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
+ for (size_t I = 0; I < Fields.size(); ++I)
+ new (&FieldArray[I]) FieldInfo(Fields[I]);
+
+ FieldInfo *BaseArray = nullptr;
+ if (!BaseClasses.empty()) {
+ BaseArray = Allocator.Allocate<FieldInfo>(BaseClasses.size());
+ for (size_t I = 0; I < BaseClasses.size(); ++I)
+ new (&BaseArray[I]) FieldInfo(BaseClasses[I]);
+ }
+
+ FieldInfo *VBaseArray = nullptr;
+ if (!VirtualBaseClasses.empty()) {
+ VBaseArray = Allocator.Allocate<FieldInfo>(VirtualBaseClasses.size());
+ for (size_t I = 0; I < VirtualBaseClasses.size(); ++I)
+ new (&VBaseArray[I]) FieldInfo(VirtualBaseClasses[I]);
+ }
+
+ return new (Allocator.Allocate<StructType>()) StructType(
+ FieldArray, static_cast<uint32_t>(Fields.size()), BaseArray,
+ static_cast<uint32_t>(BaseClasses.size()), VBaseArray,
+ static_cast<uint32_t>(VirtualBaseClasses.size()), Size, Align, Pack,
+ CXXRecord, Polymorphic, NonTrivialCopy, NonTrivialDtor, FlexibleArray,
+ UnalignedFields, CanPassInRegister, true);
+ }
+
const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, TypeSize Size,
Align Align,
StructPacking Pack = StructPacking::Default) {
@@ -373,6 +442,23 @@ class TypeBuilder {
return new (Allocator.Allocate<UnionType>()) UnionType(
FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
}
+
+ const ComplexType *getComplexType(const Type *ElementType, Align Align) {
+ // Complex types have two elements (real and imaginary parts)
+ uint64_t ElementSize = ElementType->getSizeInBits().getFixedValue();
+ uint64_t ComplexSize = ElementSize * 2;
+
+ return new (Allocator.Allocate<ComplexType>())
+ ComplexType(ElementType, ComplexSize, Align);
+ }
+
+ const MemberPointerType *getMemberPointerType(bool IsFunctionPointer,
+ bool Has64BitPointers,
+ uint64_t SizeInBits,
+ Align Align) {
+ return new (Allocator.Allocate<MemberPointerType>()) MemberPointerType(
+ IsFunctionPointer, Has64BitPointers, SizeInBits, Align);
+ }
};
} // namespace abi
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index 2992484c47d06..ce68a6783832d 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -33,6 +33,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TrailingObjects.h"
#include "llvm/Support/TypeSize.h"
+#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <string>
diff --git a/llvm/lib/ABI/ABIInfo.cpp b/llvm/lib/ABI/ABIInfo.cpp
index d94bca2d3aed1..2666f0f51f82d 100644
--- a/llvm/lib/ABI/ABIInfo.cpp
+++ b/llvm/lib/ABI/ABIInfo.cpp
@@ -7,7 +7,7 @@ bool ABIInfo::isAggregateTypeForABI(const Type *Ty) const {
return true;
// Check for fundamental scalar types
- if (Ty->isInteger() || Ty->isFloat() || Ty->isPointer())
+ if (Ty->isInteger() || Ty->isFloat() || Ty->isPointer() || Ty->isVector())
return false;
// Everything else is treated as aggregate
@@ -24,3 +24,59 @@ bool ABIInfo::isPromotableIntegerType(const IntegerType *Ty) const {
ABIArgInfo ABIInfo::getNaturalAlignIndirect(const Type *Ty) const {
return ABIArgInfo::getIndirect(Ty->getAlignment().value(), /*ByVal=*/true);
}
+RecordArgABI ABIInfo::getRecordArgABI(const StructType *ST) const {
+ if (!ST->canPassInRegisters())
+ return RAA_Indirect;
+ return RAA_Default;
+}
+
+bool ABIInfo::isZeroSizedType(const Type *Ty) const {
+ return Ty->getSizeInBits().getFixedValue() == 0;
+}
+
+bool ABIInfo::isEmptyRecord(const StructType *ST) const {
+ if (ST->hasFlexibleArrayMember() ||
+ ST->isPolymorphic() ||
+ ST->getNumVirtualBaseClasses() != 0)
+ return false;
+
+ for (unsigned I = 0; I < ST->getNumBaseClasses(); ++I) {
+ const Type *BaseTy = ST->getBaseClasses()[I].FieldType;
+ auto *BaseST = dyn_cast<StructType>(BaseTy);
+ if (!BaseST || !isEmptyRecord(BaseST))
+ return false;
+ }
+
+ for (unsigned I = 0; I < ST->getNumFields(); ++I) {
+ const FieldInfo &FI = ST->getFields()[I];
+
+ if (FI.IsBitField && FI.BitFieldWidth == 0)
+ continue;
+ if (FI.IsUnnamedBitfield)
+ continue;
+
+ if (!isZeroSizedType(FI.FieldType))
+ return false;
+ }
+ return true;
+}
+
+
+bool ABIInfo::isEmptyField(const FieldInfo &FI) const {
+ if (FI.IsUnnamedBitfield)
+ return true;
+ if (FI.IsBitField && FI.BitFieldWidth == 0)
+ return true;
+
+ const Type *Ty = FI.FieldType;
+ while (auto *AT = dyn_cast<ArrayType>(Ty)) {
+ if (AT->getNumElements() != 1)
+ break;
+ Ty = AT->getElementType();
+ }
+
+ if (auto *ST = dyn_cast<StructType>(Ty))
+ return isEmptyRecord(ST);
+
+ return isZeroSizedType(Ty);
+}
diff --git a/llvm/lib/ABI/ABITypeMapper.cpp b/llvm/lib/ABI/ABITypeMapper.cpp
index 8aee6e8d4b8b3..3e0da55fc6d79 100644
--- a/llvm/lib/ABI/ABITypeMapper.cpp
+++ b/llvm/lib/ABI/ABITypeMapper.cpp
@@ -20,6 +20,7 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -60,6 +61,12 @@ Type *ABITypeMapper::convertType(const abi::Type *ABIType) {
case abi::TypeKind::Void:
Result = Type::getVoidTy(Context);
break;
+ case abi::TypeKind::Complex:
+ Result = convertComplexType(cast<abi::ComplexType>(ABIType));
+ break;
+ case abi::TypeKind::MemberPointer:
+ Result = convertMemberPointerType(cast<abi::MemberPointerType>(ABIType));
+ break;
}
if (Result)
@@ -97,8 +104,10 @@ Type *ABITypeMapper::convertVectorType(const abi::VectorType *VT) {
}
Type *ABITypeMapper::convertStructType(const abi::StructType *ST) {
- return createStructFromFields(*ST->getFields(), ST->getNumFields(),
- ST->getSizeInBits(), ST->getAlignment(), false);
+ ArrayRef<abi::FieldInfo> FieldsArray(ST->getFields(), ST->getNumFields());
+ return createStructFromFields(FieldsArray, ST->getNumFields(),
+ ST->getSizeInBits(), ST->getAlignment(), false,
+ ST->isCoercedStruct());
}
Type *ABITypeMapper::convertUnionType(const abi::UnionType *UT) {
@@ -106,10 +115,51 @@ Type *ABITypeMapper::convertUnionType(const abi::UnionType *UT) {
UT->getSizeInBits(), UT->getAlignment(), true);
}
-StructType *
-ABITypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
- uint32_t NumFields, TypeSize Size,
- Align Alignment, bool IsUnion) {
+Type *ABITypeMapper::convertComplexType(const abi::ComplexType *CT) {
+ // Complex types are represented as structs with two elements: {real, imag}
+ Type *ElementType = convertType(CT->getElementType());
+ if (!ElementType)
+ return nullptr;
+ // // Check if the element type is a float type and is 16 bits (half
+ // precision)
+ // if (ElementType->isFloatingPointTy() &&
+ // ElementType->getPrimitiveSizeInBits() == 2 /* bytes */ * 8) {
+ // // Return <2 x half> vector type for complex half
+ // return VectorType::get(ElementType, ElementCount::getFixed(2));
+ // }
+
+ SmallVector<Type *, 2> Fields = {ElementType, ElementType};
+ return StructType::get(Context, Fields, /*isPacked=*/false);
+}
+
+Type *
+ABITypeMapper::convertMemberPointerType(const abi::MemberPointerType *MPT) {
+
+ if (MPT->isFunctionPointer()) {
+ if (MPT->has64BitPointers()) {
+ // {i64, i64} for function pointer + adjustment
+ Type *I64 = IntegerType::get(Context, 64);
+ SmallVector<Type *, 2> Fields = {I64, I64};
+ return StructType::get(Context, Fields, /*isPacked=*/false);
+ } else {
+ // {i32, i32} for 32-bit systems
+ Type *I32 = IntegerType::get(Context, 32);
+ SmallVector<Type *, 2> Fields = {I32, I32};
+ return StructType::get(Context, Fields, /*isPacked=*/false);
+ }
+ } else {
+ // Data member pointer - single offset value
+ if (MPT->has64BitPointers()) {
+ return IntegerType::get(Context, 64);
+ } else {
+ return IntegerType::get(Context, 32);
+ }
+ }
+}
+
+StructType *ABITypeMapper::createStructFromFields(
+ ArrayRef<abi::FieldInfo> Fields, uint32_t NumFields, TypeSize Size,
+ Align Alignment, bool IsUnion, bool IsCoercedStr) {
SmallVector<Type *, 16> FieldTypes;
if (IsUnion) {
@@ -156,7 +206,7 @@ ABITypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
uint64_t CurrentOffset = 0;
for (const auto &Field : Fields) {
- if (Field.OffsetInBits > CurrentOffset) {
+ if (!IsCoercedStr && Field.OffsetInBits > CurrentOffset) {
uint64_t PaddingBits = Field.OffsetInBits - CurrentOffset;
if (PaddingBits % 8 == 0 && PaddingBits >= 8) {
Type *ByteType = IntegerType::get(Context, 8);
@@ -190,16 +240,18 @@ ABITypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
}
}
- uint64_t TotalSizeBits = Size.getFixedValue();
- if (CurrentOffset < TotalSizeBits) {
- uint64_t PaddingBits = TotalSizeBits - CurrentOffset;
- if (PaddingBits % 8 == 0 && PaddingBits >= 8) {
- Type *ByteType = IntegerType::get(Context, 8);
- Type *PaddingType = ArrayType::get(ByteType, PaddingBits / 8);
- FieldTypes.push_back(PaddingType);
- } else if (PaddingBits > 0) {
- Type *PaddingType = IntegerType::get(Context, PaddingBits);
- FieldTypes.push_back(PaddingType);
+ if (!IsCoercedStr) {
+ uint64_t TotalSizeBits = Size.getFixedValue();
+ if (CurrentOffset < TotalSizeBits) {
+ uint64_t PaddingBits = TotalSizeBits - CurrentOffset;
+ if (PaddingBits % 8 == 0 && PaddingBits >= 8) {
+ Type *ByteType = IntegerType::get(Context, 8);
+ Type *PaddingType = ArrayType::get(ByteType, PaddingBits / 8);
+ FieldTypes.push_back(PaddingType);
+ } else if (PaddingBits > 0) {
+ Type *PaddingType = IntegerType::get(Context, PaddingBits);
+ FieldTypes.push_back(PaddingType);
+ }
}
}
}
diff --git a/llvm/lib/ABI/Targets/BPF.cpp b/llvm/lib/ABI/Targets/BPF.cpp
index 4841febae76be..bac18b04e0833 100644
--- a/llvm/lib/ABI/Targets/BPF.cpp
+++ b/llvm/lib/ABI/Targets/BPF.cpp
@@ -51,7 +51,7 @@ class BPFABIInfo : public ABIInfo {
return ABIArgInfo::getDirect();
}
- ABIArgInfo classifyArgumentType(const Type *ArgTy) const override {
+ ABIArgInfo classifyArgumentType(const Type *ArgTy) const {
if (isAggregateType(ArgTy)) {
auto SizeInBits = ArgTy->getSizeInBits().getFixedValue();
if (SizeInBits == 0)
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index 091666d8b9f90..949a2338e2293 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -13,22 +13,26 @@
#include "llvm/ABI/Types.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TypeSize.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
+#include <cassert>
#include <cstdint>
namespace llvm {
namespace abi {
-enum class AVXABILevel { None, AVX, AVX512 };
-
-static unsigned getNativeVectorSizeForAVXABI(AVXABILevel AVXLevel) {
+static unsigned getNativeVectorSizeForAVXABI(X86AVXABILevel AVXLevel) {
switch (AVXLevel) {
- case AVXABILevel::AVX512:
+ case X86AVXABILevel::AVX512:
return 512;
- case AVXABILevel::AVX:
+ case X86AVXABILevel::AVX:
return 256;
- case AVXABILevel::None:
+ case X86AVXABILevel::None:
return 128;
}
llvm_unreachable("Unknown AVXLevel");
@@ -49,7 +53,7 @@ class X86_64ABIInfo : public ABIInfo {
private:
TypeBuilder &TB;
- AVXABILevel AVXLevel;
+ X86AVXABILevel AVXLevel;
bool Has64BitPointers;
const llvm::Triple &TargetTriple;
@@ -60,9 +64,9 @@ class X86_64ABIInfo : public ABIInfo {
void classify(const Type *T, uint64_t OffsetBase, Class &Lo, Class &Hi,
bool IsNamedArg, bool IsRegCall = false) const;
- llvm::Type *getSseTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
- const Type *SourceTy,
- unsigned SourceOffset) const;
+ // llvm::Type *getSseTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
+ // const Type *SourceTy,
+ // unsigned SourceOffset) const;
const Type *getIntegerTypeAtOffset(const Type *IRType, unsigned IROffset,
const Type *SourceTy,
@@ -73,10 +77,11 @@ class X86_64ABIInfo : public ABIInfo {
// Type *getIntegerTypeForClass(const Type *OriginalType,
// uint64_t OffsetInBytes) const;
- const Type *getSSETypeAtOffset(const Type *IRType, unsigned IROffset,
+ const Type *getSSETypeAtOffset(const Type *ABIType, unsigned ABIOffset,
const Type *SourceTy,
unsigned SourceOffset) const;
+ void computeInfo(ABIFunctionInfo &FI) const override;
ABIArgInfo getIndirectReturnResult(const Type *Ty) const;
const Type *getFPTypeAtOffset(const Type *Ty, unsigned Offset) const;
@@ -87,65 +92,67 @@ class X86_64ABIInfo : public ABIInfo {
ABIArgInfo getIndirectResult(const Type *Ty, unsigned FreeIntRegs) const;
ABIArgInfo classifyReturnType(const Type *RetTy) const override;
+ const char *getClassName(Class C) const;
- ABIArgInfo classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
- unsigned &NeededInt, unsigned &NeededSse,
- bool IsNamedArg,
- bool IsRegCall = false) const;
-
- ABIArgInfo classifyRegCallStructType(const Type *Ty, unsigned &NeededInt,
- unsigned &NeededSSE,
- unsigned &MaxVectorWidth) const;
-
- ABIArgInfo classifyRegCallStructTypeImpl(const Type *Ty, unsigned &NeededInt,
- unsigned &NeededSSE,
- unsigned &MaxVectorWidth) const;
+ // ABIArgInfo classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
+ // unsigned &NeededInt, unsigned &NeededSse,
+ // bool IsNamedArg,
+ // bool IsRegCall = false) const;
- bool isIllegalVectorType(const Type *Ty) const;
+ // ABIArgInfo classifyRegCallStructType(const Type *Ty, unsigned &NeededInt,
+ // unsigned &NeededSSE,
+ // unsigned &MaxVectorWidth) const;
+ //
+ // ABIArgInfo classifyRegCallStructTypeImpl(const Type *Ty, unsigned
+ // &NeededInt,
+ // unsigned &NeededSSE,
+ // unsigned &MaxVectorWidth) const;
+ //
+ // bool isIllegalVectorType(const Type *Ty) const;
// The Functionality of these methods will be moved to
// llvm::abi::ABICompatInfo
- bool honorsRevision98() const { return !TargetTriple.isOSDarwin(); }
-
- bool classifyIntegerMMXAsSSE() const {
- if (TargetTriple.isOSDarwin() || TargetTriple.isPS() ||
- TargetTriple.isOSFreeBSD())
- return false;
- return true;
- }
-
- bool passInt128VectorsInMem() const {
- // TODO: accept ABICompat info from the frontends
- return TargetTriple.isOSLinux() || TargetTriple.isOSNetBSD();
- }
-
- bool returnCXXRecordGreaterThan128InMem() const {
- // TODO: accept ABICompat info from the frontends
- return true;
- }
+ // bool honorsRevision98() const { return !TargetTriple.isOSDarwin(); }
+ //
+ // bool classifyIntegerMMXAsSSE() const {
+ // if (TargetTriple.isOSDarwin() || TargetTriple.isPS() ||
+ // TargetTriple.isOSFreeBSD())
+ // return false;
+ // return true;
+ // }
+ //
+ // bool passInt128VectorsInMem() const {
+ // // TODO: accept ABICompat info from the frontends
+ // return TargetTriple.isOSLinux() || TargetTriple.isOSNetBSD();
+ // }
+ //
+ // bool returnCXXRecordGreaterThan128InMem() const {
+ // // TODO: accept ABICompat info from the frontends
+ // return true;
+ // }
public:
X86_64ABIInfo(TypeBuilder &TypeBuilder, const Triple &Triple,
- AVXABILevel AVXABILevel, bool Has64BitPtrs,
+ X86AVXABILevel AVXABILevel, bool Has64BitPtrs,
const ABICompatInfo &Compat)
: ABIInfo(Compat), TB(TypeBuilder), AVXLevel(AVXABILevel),
Has64BitPointers(Has64BitPtrs), TargetTriple(Triple) {}
- bool isPassedUsingAVXType(const Type *Type) const {
- unsigned NeededInt, NeededSse;
- ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse,
- /*IsNamedArg=*/true);
-
- if (Info.isDirect()) {
- auto *Ty = Info.getCoerceToType();
- if (auto *VectorTy = dyn_cast_or_null<VectorType>(Ty))
- return VectorTy->getSizeInBits().getFixedValue() > 128;
- }
- return false;
- }
+ // bool isPassedUsingAVXType(const Type *Type) const {
+ // unsigned NeededInt, NeededSse;
+ // ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse,
+ // /*IsNamedArg=*/true);
+ //
+ // if (Info.isDirect()) {
+ // auto *Ty = Info.getCoerceToType();
+ // if (auto *VectorTy = dyn_cast_or_null<VectorType>(Ty))
+ // return VectorTy->getSizeInBits().getFixedValue() > 128;
+ // }
+ // return false;
+ // }
- void computeInfo(ABIFunctionInfo &FI) const override;
+ // void computeInfo(ABIFunctionInfo &FI) const override;
bool has64BitPointers() const { return Has64BitPointers; }
};
@@ -237,7 +244,8 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
if (const auto *IT = dyn_cast<IntegerType>(T)) {
auto BitWidth = IT->getSizeInBits().getFixedValue();
- if (BitWidth == 128) {
+ if (BitWidth == 128 ||
+ (IT->isBitInt() && BitWidth > 64 && BitWidth <= 128)) {
Lo = Integer;
Hi = Integer;
} else if (BitWidth <= 64)
@@ -265,7 +273,6 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
}
return;
}
-
if (T->isPointer()) {
Current = Integer;
return;
@@ -372,15 +379,16 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
const auto *FltSem = EFT->getSemantics();
if (FltSem == &llvm::APFloat::IEEEhalf() ||
FltSem == &llvm::APFloat::IEEEsingle() ||
- FltSem == &llvm::APFloat::BFloat()) {
+ FltSem == &llvm::APFloat::BFloat())
Current = SSE;
- } else if (FltSem == &llvm::APFloat::IEEEdouble()) {
- Lo = Hi = SSE;
- } else if (FltSem == &llvm::APFloat::x87DoubleExtended()) {
- Current = Complex_X87;
- } else if (FltSem == &llvm::APFloat::IEEEquad()) {
+ else if (FltSem == &llvm::APFloat::IEEEquad())
Current = Memory;
- }
+ else if (FltSem == &llvm::APFloat::x87DoubleExtended())
+ Current = Complex_X87;
+ else if (FltSem == &llvm::APFloat::IEEEdouble())
+ Lo = Hi = SSE;
+ else
+ llvm_unreachable("Unexpected long double representation!");
}
uint64_t ElementSize = ElementType->getSizeInBits().getFixedValue();
@@ -429,6 +437,7 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
if (const auto *ST = dyn_cast<StructType>(T)) {
uint64_t Size = ST->getSizeInBits().getFixedValue();
+
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
// than eight eightbytes, ..., it has class MEMORY.
if (Size > 512)
@@ -437,8 +446,7 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
// AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
// copy constructor or a non-trivial destructor, it is passed by invisible
// reference.
- if (ST->isCXXRecord() &&
- (ST->hasNonTrivialCopyConstructor() || ST->hasNonTrivialDestructor())) {
+ if (ST->isCXXRecord() && (getRecordArgABI(ST))) {
return;
}
@@ -491,21 +499,21 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
uint64_t Offset = OffsetBase + Field.OffsetInBits;
bool BitField = Field.IsBitField;
- if (Size > 128 &&
- Size != Field.FieldType->getSizeInBits().getFixedValue() &&
- Size > getNativeVectorSizeForAVXABI(AVXLevel)) {
+ if (BitField && Field.IsUnnamedBitfield)
+ continue;
+
+ if (Size > 128 && (Size > getNativeVectorSizeForAVXABI(AVXLevel))) {
Lo = Memory;
postMerge(Size, Lo, Hi);
return;
}
- if (!BitField) {
- uint64_t FieldAlign = Field.FieldType->getAlignment().value() * 8;
- if (Offset % FieldAlign) {
+
+ bool IsInMemory = Offset % (Field.FieldType->getAlignment().value() * 8);
+ if (!BitField && IsInMemory) {
Lo = Memory;
postMerge(Size, Lo, Hi);
return;
}
- }
Class FieldLo, FieldHi;
@@ -547,7 +555,7 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
for (uint32_t I = 0; I < NumFields; ++I) {
const FieldInfo &Field = Fields[I];
- uint64_t Offset = OffsetBase + Field.OffsetInBits;
+ uint64_t Offset = OffsetBase;
Class FieldLo, FieldHi;
classify(Field.FieldType, Offset, FieldLo, FieldHi, IsNamedArg);
@@ -599,16 +607,28 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
// available register of the sequence %rax, %rdx is used.
case Integer:
ResType = getIntegerTypeAtOffset(RetTy, 0, RetTy, 0);
-
+ if (const auto *IT = dyn_cast<IntegerType>(ResType)) {
+ if (IT->isBool() && RetTy->isInteger() &&
+ cast<IntegerType>(RetTy)->isBool()) {
+ // Convert boolean to i1 for LLVM IR
+ ResType = TB.getIntegerType(1, IT->getAlignment(), false, true);
+ return ABIArgInfo::getExtend(ResType);
+ }
+ }
// If we have a sign or zero extended integer, make sure to return Extend
// so that the parameter gets the right LLVM IR attributes.
if (Hi == NoClass && ResType->isInteger()) {
- const IntegerType *IntTy = cast<IntegerType>(RetTy);
- if (IntTy && isPromotableIntegerType(IntTy)) {
- ABIArgInfo Info = ABIArgInfo::getExtend(ResType);
- return Info;
+ if (const IntegerType *IntTy = dyn_cast<IntegerType>(RetTy)) {
+ if (IntTy && isPromotableIntegerType(IntTy)) {
+ ABIArgInfo Info = ABIArgInfo::getExtend(RetTy);
+ return Info;
+ }
}
}
+ if (ResType->isInteger() && ResType->getSizeInBits() == 128) {
+ assert(Hi == Integer);
+ return ABIArgInfo::getDirect(ResType);
+ }
break;
// AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
@@ -634,7 +654,8 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
FieldInfo Fields[] = {
FieldInfo(X87Type, 0), FieldInfo(X87Type, 128) // 128 bits offset
};
- ResType = TB.getStructType(Fields, TypeSize::getFixed(256), Align(16));
+ ResType =
+ TB.getCoercedStructType(Fields, TypeSize::getFixed(256), Align(16));
}
break;
}
@@ -654,13 +675,13 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
case Integer:
HighPart = getIntegerTypeAtOffset(RetTy, 8, RetTy, 8);
if (Lo == NoClass)
- return ABIArgInfo::getDirect(HighPart);
+ return ABIArgInfo::getDirect(HighPart, 8);
break;
case SSE:
HighPart = getSSETypeAtOffset(RetTy, 8, RetTy, 8);
if (Lo == NoClass)
- return ABIArgInfo::getDirect(HighPart);
+ return ABIArgInfo::getDirect(HighPart, 8);
break;
// AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
@@ -683,7 +704,7 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
if (Lo != X87) {
HighPart = getSSETypeAtOffset(RetTy, 8, RetTy, 8);
if (Lo == NoClass) // Return HighPart at offset 8 in memory.
- return ABIArgInfo::getDirect(HighPart);
+ return ABIArgInfo::getDirect(HighPart, 8);
}
break;
}
@@ -708,7 +729,7 @@ const Type *X86_64ABIInfo::createPairType(const Type *Lo,
// at offset 8. If the high and low parts we inferred are both 4-byte types
// (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have
// the second element at offset 8. Check for this:
- unsigned LoSize = Lo->getSizeInBits().getFixedValue() / 8;
+ unsigned LoSize = (unsigned)Lo->getTypeAllocSize();
Align HiAlign = Hi->getAlignment();
unsigned HiStart = alignTo(LoSize, HiAlign);
@@ -728,7 +749,8 @@ const Type *X86_64ABIInfo::createPairType(const Type *Lo,
if (Lo->isFloat()) {
const FloatType *FT = cast<FloatType>(Lo);
if (FT->getSemantics() == &APFloat::IEEEhalf() ||
- FT->getSemantics() == &APFloat::IEEEsingle()) {
+ FT->getSemantics() == &APFloat::IEEEsingle() ||
+ FT->getSemantics() == &APFloat::BFloat()) {
AdjustedLo = TB.getFloatType(APFloat::IEEEdouble(), Align(8));
}
}
@@ -736,24 +758,27 @@ const Type *X86_64ABIInfo::createPairType(const Type *Lo,
else if (Lo->isInteger() || Lo->isPointer()) {
AdjustedLo = TB.getIntegerType(64, Align(8), /*Signed=*/false);
} else {
- assert(false && "Invalid/unknown low type in pair");
+ assert((Lo->isInteger() || Lo->isPointer()) &&
+ "Invalid/unknown low type in pair");
}
+ unsigned AdjustedLoSize = AdjustedLo->getSizeInBits().getFixedValue() / 8;
+ HiStart = alignTo(AdjustedLoSize, HiAlign);
}
// Create the pair struct
FieldInfo Fields[] = {
- FieldInfo(AdjustedLo, 0), // Low part at offset 0
- FieldInfo(Hi, 8 * 8) // High part at offset 8 bytes (64 bits)
+ FieldInfo(AdjustedLo, 0), // Low part at offset 0
+ FieldInfo(Hi, HiStart * 8) // High part at offset 8 bytes (64 bits)
};
// Verify the high part is at offset 8
assert((8 * 8) == Fields[1].OffsetInBits &&
"High part must be at offset 8 bytes");
- return TB.getStructType(Fields,
- TypeSize::getFixed(128), // Total size 16 bytes
- Align(8), // Natural alignment
- StructPacking::Default);
+ return TB.getCoercedStructType(Fields,
+ TypeSize::getFixed(128), // Total size 16 bytes
+ Align(8), // Natural alignment
+ StructPacking::Default);
}
static bool bitsContainNoUserData(const Type *Ty, unsigned StartBit,
@@ -826,8 +851,9 @@ const Type *X86_64ABIInfo::getIntegerTypeAtOffset(const Type *ABIType,
// Pointers and 64-bit integers fill the 8-byte unit
if ((ABIType->isPointer() && Has64BitPointers) ||
(ABIType->isInteger() &&
- cast<IntegerType>(ABIType)->getSizeInBits() == 64))
+ cast<IntegerType>(ABIType)->getSizeInBits() == 64)){
return ABIType;
+ }
// If we have a 1/2/4-byte integer, we can use it only if the rest of the
// goodness in the source type is just tail padding. This is allowed to
@@ -882,8 +908,18 @@ const Type *X86_64ABIInfo::getIntegerTypeAtOffset(const Type *ABIType,
}
}
+ if (ABIType->isInteger() && ABIType->getSizeInBits().getFixedValue() == 128) {
+ assert(ABIOffset == 0);
+ return ABIType;
+ }
+
// Default case - use integer type that fits
- unsigned TySizeInBytes = SourceTy->getSizeInBits() / 8;
+ unsigned TySizeInBytes =
+ SourceTy->getSizeInBits().getFixedValue() / 8;
+ if (auto *IT = dyn_cast<IntegerType>(SourceTy)){
+ if (IT->isBitInt())
+ TySizeInBytes = alignTo(SourceTy->getSizeInBits().getFixedValue(),64)/8;
+ }
assert(TySizeInBytes != SourceOffset && "Empty field?");
unsigned AvailableSize = TySizeInBytes - SourceOffset;
return TB.getIntegerType(std::min(AvailableSize, 8U) * 8, Align(1),
@@ -894,24 +930,37 @@ const Type *X86_64ABIInfo::getIntegerTypeAtOffset(const Type *ABIType,
const Type *X86_64ABIInfo::getFPTypeAtOffset(const Type *Ty,
unsigned Offset) const {
// Check for direct match at offset 0
- if (Offset == 0 && Ty->isFloat())
+ if (Offset == 0 && Ty->isFloat()) {
return Ty;
+ }
+
+ if (const ComplexType *CT = dyn_cast<ComplexType>(Ty)) {
+ const Type *ElementType = CT->getElementType();
+ unsigned ElementSize = ElementType->getSizeInBits().getFixedValue() / 8;
+
+ if (Offset == 0 || Offset == ElementSize) {
+ return ElementType;
+ }
+ return nullptr;
+ }
// Handle struct types by checking each field
if (const StructType *ST = dyn_cast<StructType>(Ty)) {
+ if (!ST->getNumFields())
+ return nullptr;
const FieldInfo *Fields = ST->getFields();
// Find the field containing the requested offset
for (unsigned i = 0; i < ST->getNumFields(); ++i) {
- unsigned FieldOffset = Fields[i].OffsetInBits / 8; // Convert to bytes
- unsigned FieldSize = Fields[i].FieldType->getSizeInBits() / 8;
+ unsigned FieldOffset = Fields[i].OffsetInBits / 8;
+ unsigned FieldSize =
+ Fields[i].FieldType->getSizeInBits().getFixedValue() / 8;
// Check if offset falls within this field
if (Offset >= FieldOffset && Offset < FieldOffset + FieldSize) {
return getFPTypeAtOffset(Fields[i].FieldType, Offset - FieldOffset);
}
}
- return nullptr;
}
// Handle array types
@@ -942,6 +991,12 @@ const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
unsigned ABIOffset,
const Type *SourceTy,
unsigned SourceOffset) const {
+
+ auto Is16bitFpTy = [](const Type *T) {
+ return isFloatTypeWithSemantics(T, APFloat::IEEEhalf()) ||
+ isFloatTypeWithSemantics(T, APFloat::BFloat());
+ };
+
// Get the floating point type at the requested offset
const Type *T0 = getFPTypeAtOffset(ABIType, ABIOffset);
if (!T0 || isFloatTypeWithSemantics(T0, APFloat::IEEEdouble()))
@@ -953,27 +1008,26 @@ const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
// Try to get adjacent FP type
const Type *T1 = nullptr;
- unsigned T0Size = T0->getSizeInBits().getFixedValue() / 8;
- if (SourceSize > T0Size)
+ unsigned T0Size =
+ alignTo(T0->getSizeInBits().getFixedValue(), T0->getAlignment().value()) /
+ 8;
+ if (SourceSize > T0Size) {
T1 = getFPTypeAtOffset(ABIType, ABIOffset + T0Size);
+ }
- // Special case for half/bfloat + float combinations
- if (!T1 && isFloatTypeWithSemantics(T0, APFloat::IEEEhalf()) &&
- SourceSize > 4)
- T1 = getFPTypeAtOffset(ABIType, ABIOffset + 4);
-
- // If no adjacent type found, return the single type
- if (!T1)
- return T0;
+ if (T1 == nullptr) {
+ if (Is16bitFpTy(T0) && SourceSize > 4)
+ T1 = getFPTypeAtOffset(ABIType, ABIOffset + 4);
+ if (T1 == nullptr)
+ return T0;
+ }
// Handle vector cases
if (isFloatTypeWithSemantics(T0, APFloat::IEEEsingle()) &&
isFloatTypeWithSemantics(T1, APFloat::IEEEsingle())) {
return TB.getVectorType(T0, ElementCount::getFixed(2), Align(8));
}
-
- if (isFloatTypeWithSemantics(T0, APFloat::IEEEhalf()) &&
- isFloatTypeWithSemantics(T1, APFloat::IEEEhalf())) {
+ if (Is16bitFpTy(T0) && Is16bitFpTy(T1)) {
const Type *T2 = nullptr;
if (SourceSize > 4)
T2 = getFPTypeAtOffset(ABIType, ABIOffset + 4);
@@ -983,8 +1037,7 @@ const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
}
// Mixed half-float cases
- if (isFloatTypeWithSemantics(T0, APFloat::IEEEhalf()) ||
- isFloatTypeWithSemantics(T1, APFloat::IEEEhalf())) {
+ if (Is16bitFpTy(T0) || Is16bitFpTy(T1)) {
return TB.getVectorType(TB.getFloatType(APFloat::IEEEhalf(), Align(2)),
ElementCount::getFixed(4), Align(8));
}
@@ -1005,7 +1058,8 @@ const Type *X86_64ABIInfo::getByteVectorType(const Type *Ty) const {
if (const VectorType *VT = dyn_cast<VectorType>(Ty)) {
// Don't pass vXi128 vectors in their native type, the backend can't
// legalize them.
- if (passInt128VectorsInMem() && VT->getElementType()->isInteger() &&
+ if (getABICompatInfo().Flags.PassInt128VectorsInMem &&
+ VT->getElementType()->isInteger() &&
cast<IntegerType>(VT->getElementType())->getSizeInBits() == 128) {
unsigned Size = VT->getSizeInBits().getFixedValue();
return TB.getVectorType(TB.getIntegerType(64, Align(8), /*Signed=*/false),
@@ -1029,13 +1083,64 @@ const Type *X86_64ABIInfo::getByteVectorType(const Type *Ty) const {
// Returns the single element if this is a single-element struct wrapper
const Type *X86_64ABIInfo::isSingleElementStruct(const Type *Ty) const {
- if (const StructType *ST = dyn_cast<StructType>(Ty)) {
- if (ST->getNumFields() == 1 && ST->getNumBaseClasses() == 0)
- return ST->getFields()[0].FieldType;
+ const auto *ST = dyn_cast<StructType>(Ty);
+ if (!ST)
+ return nullptr;
+
+ if (ST->isPolymorphic() ||
+ ST->hasNonTrivialCopyConstructor() ||
+ ST->hasNonTrivialDestructor() ||
+ ST->hasFlexibleArrayMember() ||
+ ST->getNumVirtualBaseClasses() != 0)
+ return nullptr;
+
+ const Type *Found = nullptr;
+
+ for (unsigned I = 0; I < ST->getNumBaseClasses(); ++I) {
+ const Type *BaseTy = ST->getBaseClasses()[I].FieldType;
+ auto *BaseST = dyn_cast<StructType>(BaseTy);
+
+ if (!BaseST || isEmptyRecord(BaseST))
+ continue; // ignore empty bases
+
+ const Type *Elem = isSingleElementStruct(BaseTy);
+ if (!Elem || Found)
+ return nullptr;
+ Found = Elem;
}
- return nullptr;
+
+ for (unsigned I = 0; I < ST->getNumFields(); ++I) {
+ const FieldInfo &FI = ST->getFields()[I];
+ if (isEmptyField(FI))
+ continue;
+
+ const Type *FTy = FI.FieldType;
+
+ while (auto *AT = dyn_cast<ArrayType>(FTy)) {
+ if (AT->getNumElements() != 1)
+ break;
+ FTy = AT->getElementType();
+ }
+
+ const Type *Elem;
+ if (auto *InnerST = dyn_cast<StructType>(FTy))
+ Elem = isSingleElementStruct(InnerST);
+ else
+ Elem = FTy;
+ if (!Elem || Found)
+ return nullptr;
+ Found = Elem;
+ }
+
+ if (!Found)
+ return nullptr;
+ if (Found->getSizeInBits() != Ty->getSizeInBits())
+ return nullptr;
+
+ return Found;
}
+
ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
// If this is a scalar value, handle it specially
if (!isAggregateTypeForABI(Ty)) {
@@ -1046,6 +1151,8 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
ABIArgInfo Info = ABIArgInfo::getExtend(Ty);
return Info;
}
+ if (IntTy->isBitInt())
+ return getNaturalAlignIndirect(IntTy);
}
return ABIArgInfo::getDirect();
}
@@ -1054,5 +1161,24 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
return getNaturalAlignIndirect(Ty);
}
+void X86_64ABIInfo::computeInfo(ABIFunctionInfo &FI) const {
+ // TODO: Implement proper function info computation
+}
+class X8664TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ X8664TargetCodeGenInfo(TypeBuilder &TB, const Triple &Triple,
+ X86AVXABILevel AVXLevel, bool Has64BitPointers,
+ const ABICompatInfo &Compat)
+ : TargetCodeGenInfo(std::make_unique<X86_64ABIInfo>(
+ TB, Triple, AVXLevel, Has64BitPointers, Compat)) {}
+};
+
+std::unique_ptr<TargetCodeGenInfo>
+createX8664TargetCodeGenInfo(TypeBuilder &TB, const Triple &Triple,
+ X86AVXABILevel AVXLevel, bool Has64BitPointers,
+ const ABICompatInfo &Compat) {
+ return std::make_unique<X8664TargetCodeGenInfo>(TB, Triple, AVXLevel,
+ Has64BitPointers, Compat);
+}
} // namespace abi
} // namespace llvm
>From 37cd4b6e206c299af56a56120444c83cc2f55f03 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Sun, 10 Aug 2025 22:28:05 +0530
Subject: [PATCH 17/17] [LLVMABI] Argument+ReturnType classifiers
---
clang/include/clang/CodeGen/QualTypeMapper.h | 56 +-
clang/lib/CodeGen/CGCall.cpp | 206 +++++-
clang/lib/CodeGen/CodeGenModule.cpp | 60 +-
clang/lib/CodeGen/CodeGenTypes.cpp | 3 +-
clang/lib/CodeGen/QualTypeMapper.cpp | 261 +++++---
clang/lib/CodeGen/Targets/X86.cpp | 29 +-
clang/test/CodeGen/sysv_abi.c | 4 +
llvm/include/llvm/ABI/ABIFunctionInfo.h | 128 +++-
llvm/include/llvm/ABI/ABIInfo.h | 17 +-
llvm/include/llvm/ABI/ABITypeMapper.h | 9 +-
llvm/include/llvm/ABI/Types.h | 315 +++++----
llvm/include/llvm/IR/DataLayout.h | 1 -
llvm/lib/ABI/ABIInfo.cpp | 32 +-
llvm/lib/ABI/ABITypeMapper.cpp | 66 +-
llvm/lib/ABI/Targets/BPF.cpp | 26 +-
llvm/lib/ABI/Targets/X86.cpp | 656 +++++++++++++------
16 files changed, 1296 insertions(+), 573 deletions(-)
diff --git a/clang/include/clang/CodeGen/QualTypeMapper.h b/clang/include/clang/CodeGen/QualTypeMapper.h
index 8cf365864a724..6bc90f3995a07 100644
--- a/clang/include/clang/CodeGen/QualTypeMapper.h
+++ b/clang/include/clang/CodeGen/QualTypeMapper.h
@@ -28,14 +28,31 @@
namespace clang {
namespace CodeGen {
+struct ABICacheKey {
+ QualType Type;
+ bool InMemory;
+
+ ABICacheKey() = default;
+
+ ABICacheKey(QualType QT, bool InMem = false)
+ : Type(QT.getCanonicalType().getUnqualifiedType()), InMemory(InMem) {}
+
+ bool operator==(const ABICacheKey &Other) const {
+ return Type == Other.Type && InMemory == Other.InMemory;
+ }
+
+ bool operator!=(const ABICacheKey &Other) const { return !(*this == Other); }
+};
+
class QualTypeMapper {
private:
clang::ASTContext &ASTCtx;
llvm::abi::TypeBuilder Builder;
- llvm::DenseMap<clang::QualType, const llvm::abi::Type *> TypeCache;
+ llvm::DenseMap<ABICacheKey, const llvm::abi::Type *> TypeCache;
- const llvm::abi::Type *convertBuiltinType(const clang::BuiltinType *BT);
+ const llvm::abi::Type *convertBuiltinType(const clang::BuiltinType *BT,
+ bool InMemory = false);
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);
@@ -48,7 +65,8 @@ class QualTypeMapper {
const llvm::abi::Type *convertMatrixType(const ConstantMatrixType *MT);
const llvm::abi::StructType *convertStructType(const clang::RecordDecl *RD);
- const llvm::abi::UnionType *convertUnionType(const clang::RecordDecl *RD);
+ const llvm::abi::StructType *convertUnionType(const clang::RecordDecl *RD,
+ bool isTransparent = false);
const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
const llvm::abi::StructType *convertCXXRecordType(const CXXRecordDecl *RD,
bool canPassInRegs);
@@ -67,7 +85,7 @@ class QualTypeMapper {
explicit QualTypeMapper(clang::ASTContext &Ctx, llvm::BumpPtrAllocator &Alloc)
: ASTCtx(Ctx), Builder(Alloc) {}
- const llvm::abi::Type *convertType(clang::QualType QT);
+ const llvm::abi::Type *convertType(clang::QualType QT, bool InMemory = false);
void clearCache() { TypeCache.clear(); }
@@ -76,5 +94,33 @@ class QualTypeMapper {
} // namespace CodeGen
} // namespace clang
+namespace llvm {
+template <> struct DenseMapInfo<clang::CodeGen::ABICacheKey> {
+ static clang::CodeGen::ABICacheKey getEmptyKey() {
+ clang::CodeGen::ABICacheKey k;
+ k.Type = DenseMapInfo<clang::QualType>::getEmptyKey();
+ k.InMemory = false;
+ return k;
+ }
+
+ static clang::CodeGen::ABICacheKey getTombstoneKey() {
+ clang::CodeGen::ABICacheKey k;
+ k.Type = DenseMapInfo<clang::QualType>::getTombstoneKey();
+ k.InMemory = true;
+ return k;
+ }
+
+ static unsigned getHashValue(const clang::CodeGen::ABICacheKey &Key) {
+ unsigned TypeHash = (unsigned)((uintptr_t)Key.Type.getAsOpaquePtr()) ^
+ ((unsigned)((uintptr_t)Key.Type.getAsOpaquePtr() >> 9));
+ return hash_combine(TypeHash, hash_value(Key.InMemory));
+ }
+
+ static bool isEqual(const clang::CodeGen::ABICacheKey &LHS,
+ const clang::CodeGen::ABICacheKey &RHS) {
+ return LHS.Type == RHS.Type && LHS.InMemory == RHS.InMemory;
+ }
+};
+} // namespace llvm
-#endif // !CLANG_CODEGEN_QUALTYPE_MAPPER_H
+#endif // CLANG_CODEGEN_QUALTYPE_MAPPER_H
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index a39a41391eb20..01df913f0695a 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -47,6 +47,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Utils/Local.h"
#include <optional>
@@ -831,37 +832,192 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
}
} // namespace clang
+static QualType getIntegerTypeForExtension(ASTContext &Ctx, llvm::Type *LLVMTy,
+ bool IsSigned) {
+ if (auto *IntTy = dyn_cast<llvm::IntegerType>(LLVMTy)) {
+ unsigned BitWidth = IntTy->getBitWidth();
+ return Ctx.getIntTypeForBitwidth(BitWidth, IsSigned);
+ }
+ return QualType();
+}
+
+static bool shouldSignExtend(QualType Ty) {
+ if (Ty->isSignedIntegerType() || Ty->isEnumeralType()) {
+ if (const EnumType *ET = Ty->getAs<EnumType>()) {
+ return ET->getOriginalDecl()->getIntegerType()->isSignedIntegerType();
+ }
+ return true;
+ }
+ return false;
+}
+
ABIArgInfo CodeGenTypes::convertABIArgInfo(const llvm::abi::ABIArgInfo &AbiInfo,
QualType type) {
ABIArgInfo result;
- if (AbiInfo.isDirect()) {
+ // To maintain coherence with clang's current impl.
+ if (type->isConstantMatrixType()) {
+ const auto *MT = type->getAs<ConstantMatrixType>();
+ unsigned NumElements = MT->getNumRows() * MT->getNumColumns();
+ llvm::Type *ElementType = ConvertType(MT->getElementType());
+ llvm::Type *VectorType = llvm::VectorType::get(
+ ElementType, llvm::ElementCount::getFixed(NumElements));
+
+ result = ABIArgInfo::getDirect(VectorType);
+ return result;
+ }
+ switch (AbiInfo.getKind()) {
+ case llvm::abi::ABIArgInfo::Direct: {
llvm::Type *CoercedType = nullptr;
if (AbiInfo.getCoerceToType())
CoercedType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
if (!CoercedType)
CoercedType = ConvertType(type);
- result = ABIArgInfo::getDirect(CoercedType);
- } else if (AbiInfo.isExtend()) {
+
+ llvm::Type *PaddingType = nullptr;
+ if (AbiInfo.getPaddingType())
+ PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());
+
+ result = ABIArgInfo::getDirect(CoercedType, AbiInfo.getDirectOffset(),
+ PaddingType, AbiInfo.getCanBeFlattened(),
+ AbiInfo.getDirectAlign());
+
+ if (AbiInfo.isInReg())
+ result.setInReg(true);
+ if (AbiInfo.hasPaddingInReg())
+ result.setPaddingInReg(true);
+ break;
+ }
+ case llvm::abi::ABIArgInfo::Extend: {
llvm::Type *CoercedType = nullptr;
- if (AbiInfo.getCoerceToType())
+ QualType ExtendType = type;
+
+ if (AbiInfo.getCoerceToType()) {
CoercedType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
+
+ if (CoercedType && CoercedType->isIntegerTy()) {
+ bool IsSigned = AbiInfo.isSignExt() ||
+ (AbiInfo.isNoExt() && shouldSignExtend(type));
+ ExtendType =
+ getIntegerTypeForExtension(getContext(), CoercedType, IsSigned);
+
+ if (ExtendType.isNull()) {
+ ExtendType = type;
+ if (type->isUnionType() || !type->isIntegralOrEnumerationType()) {
+ unsigned BitWidth =
+ cast<llvm::IntegerType>(CoercedType)->getBitWidth();
+ ExtendType = getContext().getIntTypeForBitwidth(BitWidth, IsSigned);
+ }
+ }
+ }
+ }
+
if (!CoercedType)
CoercedType = ConvertType(type);
+
+ if (!ExtendType->isIntegralOrEnumerationType()) {
+ if (CoercedType && CoercedType->isIntegerTy()) {
+ unsigned BitWidth = cast<llvm::IntegerType>(CoercedType)->getBitWidth();
+ bool IsSigned = AbiInfo.isSignExt() || shouldSignExtend(type);
+ ExtendType = getContext().getIntTypeForBitwidth(BitWidth, IsSigned);
+ } else {
+ ExtendType = getContext().IntTy;
+ }
+ }
+
if (AbiInfo.isSignExt()) {
- result = ABIArgInfo::getSignExtend(type, CoercedType);
+ result = ABIArgInfo::getSignExtend(ExtendType, CoercedType);
+ } else if (AbiInfo.isZeroExt()) {
+ result = ABIArgInfo::getZeroExtend(ExtendType, CoercedType);
} else {
- result = ABIArgInfo::getZeroExtend(type, CoercedType);
+ result = ABIArgInfo::getExtend(ExtendType, CoercedType);
}
- } else if (AbiInfo.isIndirect()) {
- result = ABIArgInfo::getIndirect(
- CharUnits::fromQuantity(AbiInfo.getIndirectAlign()), 0);
- } else if (AbiInfo.isIgnore()) {
+
+ if (AbiInfo.isInReg())
+ result.setInReg(true);
+ break;
+ }
+ case llvm::abi::ABIArgInfo::Indirect: {
+ CharUnits Alignment = CharUnits::fromQuantity(AbiInfo.getIndirectAlign());
+
+ llvm::Type *PaddingType = nullptr;
+ if (AbiInfo.getPaddingType())
+ PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());
+
+ result = ABIArgInfo::getIndirect(Alignment, AbiInfo.getIndirectAddrSpace(),
+ AbiInfo.getIndirectByVal(),
+ AbiInfo.getIndirectRealign(), PaddingType);
+
+ if (AbiInfo.isInReg())
+ result.setInReg(true);
+ if (AbiInfo.isSRetAfterThis())
+ result.setSRetAfterThis(true);
+ break;
+ }
+ case llvm::abi::ABIArgInfo::IndirectAliased: {
+ CharUnits Alignment = CharUnits::fromQuantity(AbiInfo.getIndirectAlign());
+
+ llvm::Type *PaddingType = nullptr;
+ if (AbiInfo.getPaddingType())
+ PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());
+
+ result = ABIArgInfo::getIndirectAliased(
+ Alignment, AbiInfo.getIndirectAddrSpace(), AbiInfo.getIndirectRealign(),
+ PaddingType);
+ break;
+ }
+
+ case llvm::abi::ABIArgInfo::Ignore: {
result = ABIArgInfo::getIgnore();
+ break;
}
- if (AbiInfo.isInReg())
- result.setInReg(true);
+ case llvm::abi::ABIArgInfo::Expand: {
+ llvm::Type *PaddingType = nullptr;
+ if (AbiInfo.getPaddingType())
+ PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());
+
+ if (PaddingType) {
+ result = ABIArgInfo::getExpandWithPadding(AbiInfo.hasPaddingInReg(),
+ PaddingType);
+ } else {
+ result = ABIArgInfo::getExpand();
+ }
+ break;
+ }
+
+ case llvm::abi::ABIArgInfo::CoerceAndExpand: {
+ llvm::Type *CoerceType = nullptr;
+ llvm::Type *UnpaddedType = nullptr;
+
+ if (AbiInfo.getCoerceToType())
+ CoerceType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
+ if (AbiInfo.getUnpaddedCoerceAndExpandType())
+ UnpaddedType =
+ ReverseMapper.convertType(AbiInfo.getUnpaddedCoerceAndExpandType());
+
+ if (!CoerceType)
+ CoerceType = ConvertType(type);
+ if (!UnpaddedType)
+ UnpaddedType = CoerceType;
+
+ llvm::StructType *CoerceStructType = dyn_cast<llvm::StructType>(CoerceType);
+ if (!CoerceStructType) {
+ CoerceStructType = llvm::StructType::get(CoerceType->getContext());
+ }
+
+ result = ABIArgInfo::getCoerceAndExpand(CoerceStructType, UnpaddedType);
+ break;
+ }
+
+ case llvm::abi::ABIArgInfo::InAlloca: {
+ result = ABIArgInfo::getInAlloca(AbiInfo.getInAllocaFieldIndex(),
+ AbiInfo.getInAllocaIndirect());
+ if (AbiInfo.getInAllocaSRet())
+ result.setInAllocaSRet(true);
+ break;
+ }
+ }
return result;
}
@@ -911,6 +1067,11 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
assert(inserted && "Recursively being processed?");
bool isBPF = CGM.getTriple().isBPF();
+ const llvm::Triple &Triple = getTarget().getTriple();
+ bool isSysV =
+ Triple.getArch() == llvm::Triple::x86_64 &&
+ (CC == llvm::CallingConv::X86_64_SysV || CC == llvm::CallingConv::C) &&
+ (Triple.isOSLinux() || Triple.isOSGlibc());
// Compute ABI information.
if (CC == llvm::CallingConv::SPIR_KERNEL) {
@@ -920,16 +1081,29 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
} else if (info.getCC() == CC_Swift || info.getCC() == CC_SwiftAsync) {
swiftcall::computeABIInfo(CGM, *FI);
} else {
- if (isBPF)
+ if (isBPF || isSysV) {
CGM.fetchABIInfo(TB).computeInfo(*tempFI);
- else
+ } else {
CGM.getABIInfo().computeInfo(*FI);
+ }
+ }
+
+ // Non-BPF/SysV path: handle coerce types for direct/extend cases
+ ABIArgInfo &retInfo = FI->getReturnInfo();
+ if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr) {
+ retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
+ }
+
+ for (auto &I : FI->arguments()) {
+ if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr) {
+ I.info.setCoerceToType(ConvertType(I.type));
+ }
}
// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
- if (isBPF && tempFI) {
+ if ((isBPF || isSysV) && tempFI) {
const auto &abiRetInfo = tempFI->getReturnInfo();
ABIArgInfo &cgRetInfo = FI->getReturnInfo();
@@ -952,7 +1126,7 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
argIndex++;
}
} else {
- // Non-BPF path: handle coerce types for direct/extend cases
+ // Non-BPF/SysV path: handle coerce types for direct/extend cases
ABIArgInfo &retInfo = FI->getReturnInfo();
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr) {
retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 9ff79b1a48060..6055aed82aca4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -37,6 +37,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Diagnostic.h"
@@ -106,14 +107,61 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
llvm_unreachable("invalid C++ ABI kind");
}
-static std::unique_ptr<llvm::abi::TargetCodeGenInfo>
-makeTargetCodeGenInfo(llvm::abi::TypeBuilder &TB) {
- return llvm::abi::createBPFTargetCodeGenInfo(TB);
-}
-
const llvm::abi::ABIInfo &
CodeGenModule::fetchABIInfo(llvm::abi::TypeBuilder &TB) {
- newTargetCodeGenInfo = makeTargetCodeGenInfo(TB);
+ if (getTriple().getArch() == llvm::Triple::x86_64) {
+ StringRef ABI = Target.getABI();
+ llvm::abi::X86AVXABILevel AVXLevel =
+ (ABI == "avx512" ? llvm::abi::X86AVXABILevel::AVX512
+ : ABI == "avx" ? llvm::abi::X86AVXABILevel::AVX
+ : llvm::abi::X86AVXABILevel::None);
+ llvm::abi::ABICompatInfo CompatInfo;
+ bool classifyIntegerMMXAsSSE = [&]() {
+ if (getContext().getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver3_8)
+ return false;
+
+ const llvm::Triple &Triple = getTarget().getTriple();
+ if (Triple.isOSDarwin() || Triple.isPS() || Triple.isOSFreeBSD())
+ return false;
+ return true;
+ }();
+ bool honorsRevision0_98 = !getTarget().getTriple().isOSDarwin();
+
+ bool passInt128VectorsInMem = [&]() {
+ if (getContext().getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver9)
+ return false;
+
+ const llvm::Triple &T = getTarget().getTriple();
+ return T.isOSLinux() || T.isOSNetBSD();
+ }();
+
+ bool returnCXXRecordGreaterThan128InMem = [&]() {
+ if (getContext().getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver20)
+ return false;
+
+ return true;
+ }();
+
+ CompatInfo.Flags.ClassifyIntegerMMXAsSSE = classifyIntegerMMXAsSSE;
+ CompatInfo.Flags.HonorsRevision98 = honorsRevision0_98;
+ CompatInfo.Flags.PassInt128VectorsInMem = passInt128VectorsInMem;
+ CompatInfo.Flags.ReturnCXXRecordGreaterThan128InMem =
+ returnCXXRecordGreaterThan128InMem;
+ CompatInfo.Flags.Clang11Compat =
+ getContext().getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver11 ||
+ getContext().getTargetInfo().getTriple().isPS();
+
+ newTargetCodeGenInfo = llvm::abi::createX8664TargetCodeGenInfo(
+ TB, getTriple(), AVXLevel,
+ getContext().getTargetInfo().getPointerWidth(LangAS::Default) == 64,
+ CompatInfo);
+
+ } else
+ newTargetCodeGenInfo = llvm::abi::createBPFTargetCodeGenInfo(TB);
return newTargetCodeGenInfo->getABIInfo();
}
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 1359e65715ce8..a925667e43b71 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -27,6 +27,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
using namespace clang;
using namespace CodeGen;
@@ -34,7 +35,7 @@ using namespace CodeGen;
CodeGenTypes::CodeGenTypes(CodeGenModule &cgm)
: CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()),
Target(cgm.getTarget()), TB(Alloc), Mapper(cgm.getContext(), Alloc),
- ReverseMapper(getLLVMContext()) {
+ ReverseMapper(getLLVMContext(), getDataLayout()) {
SkippedLayout = false;
LongDoubleReferenced = false;
}
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp b/clang/lib/CodeGen/QualTypeMapper.cpp
index cda2928f1c206..303dfd070795f 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -16,6 +16,8 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/QualTypeMapper.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTFwd.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -25,6 +27,7 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ABI/Types.h"
#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/TypeSize.h"
#include "llvm/Support/raw_ostream.h"
@@ -37,65 +40,68 @@ namespace CodeGen {
///
/// \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) {
+const llvm::abi::Type *QualTypeMapper::convertType(QualType QT, bool InMemory) {
// Canonicalize type and strip qualifiers
// This ensures consistent type representation across different contexts
QT = QT.getCanonicalType().getUnqualifiedType();
+ ABICacheKey CacheKey(QT, InMemory);
// Results are cached since type conversion may be expensive
- auto It = TypeCache.find(QT);
+ auto It = TypeCache.find(CacheKey);
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())) {
+ if (const auto *BT = dyn_cast<BuiltinType>(QT.getTypePtr()))
+ Result = convertBuiltinType(BT, InMemory);
+ else if (const auto *PT = dyn_cast<PointerType>(QT.getTypePtr()))
Result = convertPointerType(PT);
- } else if (const auto *RT = dyn_cast<ReferenceType>(QT.getTypePtr())) {
+ else if (const auto *RT = dyn_cast<ReferenceType>(QT.getTypePtr()))
Result = convertReferenceType(RT);
- } else if (const auto *AT = dyn_cast<ArrayType>(QT.getTypePtr())) {
+ else if (const auto *AT = dyn_cast<ArrayType>(QT.getTypePtr()))
Result = convertArrayType(AT);
- } else if (const auto *VT = dyn_cast<VectorType>(QT.getTypePtr())) {
+ else if (const auto *VT = dyn_cast<VectorType>(QT.getTypePtr()))
Result = convertVectorType(VT);
- } else if (const auto *RT = dyn_cast<RecordType>(QT.getTypePtr())) {
+ else if (const auto *RT = dyn_cast<RecordType>(QT.getTypePtr()))
Result = convertRecordType(RT);
- } else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
+ else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr()))
Result = convertEnumType(ET);
- } else if (const auto *CT = dyn_cast<ComplexType>(QT.getTypePtr())) {
+ else if (const auto *CT = dyn_cast<ComplexType>(QT.getTypePtr()))
Result = convertComplexType(CT);
- } else if (const auto *AT = dyn_cast<AtomicType>(QT.getTypePtr())) {
+ else if (const auto *AT = dyn_cast<AtomicType>(QT.getTypePtr()))
return convertType(AT->getValueType());
- } else if (const auto *BPT = dyn_cast<BlockPointerType>(QT.getTypePtr())) {
+ else if (const auto *BPT = dyn_cast<BlockPointerType>(QT.getTypePtr()))
return createPointerTypeForPointee(ASTCtx.VoidPtrTy);
-
- } else if (const auto *MT = dyn_cast<ConstantMatrixType>(QT.getTypePtr())) {
+ else if (const auto *PipeT = dyn_cast<PipeType>(QT.getTypePtr()))
+ Result = createPointerTypeForPointee(ASTCtx.VoidPtrTy);
+ else if (const auto *MT = dyn_cast<ConstantMatrixType>(QT.getTypePtr())) {
const llvm::abi::Type *ElementType = convertType(MT->getElementType());
uint64_t NumElements = MT->getNumRows() * MT->getNumColumns();
- llvm::Align MatrixAlign = getTypeAlign(QT);
- return Builder.getVectorType(ElementType,
- llvm::ElementCount::getFixed(NumElements),
- MatrixAlign);
+ return Builder.getArrayType(ElementType, NumElements, true);
} else if (const auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
Result = convertMemberPointerType(MPT);
} 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();
+ unsigned RawNumBits = BIT->getNumBits();
+ bool IsPromotableInt = BIT->getNumBits() < ASTCtx.getTypeSize(ASTCtx.IntTy);
bool IsSigned = BIT->isSigned();
llvm::Align TypeAlign = getTypeAlign(QT);
- return Builder.getIntegerType(NumBits, TypeAlign, IsSigned, false, true);
+ return Builder.getIntegerType(RawNumBits, TypeAlign, IsSigned, false, true,
+ IsPromotableInt, InMemory);
} 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);
+ auto PointerSize =
+ ASTCtx.getTargetInfo().getPointerWidth(QT.getAddressSpace());
llvm::Align PointerAlign =
llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(LangAS::Default));
- return Builder.getPointerType(PointerSize, llvm::Align(PointerAlign.value()/8),ASTCtx.getTargetInfo().getTargetAddressSpace(QT.getAddressSpace()));
- } else {
+ return Builder.getPointerType(
+ PointerSize, llvm::Align(PointerAlign.value() / 8),
+ ASTCtx.getTargetInfo().getTargetAddressSpace(QT.getAddressSpace()));
+ } else
QT.dump();
- }
- TypeCache[QT] = Result;
+
+ if (Result)
+ TypeCache[CacheKey] = Result;
return Result;
}
@@ -105,8 +111,8 @@ const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
///
/// \param BT The BuiltinType to convert
/// \return Corresponding LLVM ABI integer, float, or void type
-const llvm::abi::Type *
-QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
+const llvm::abi::Type *QualTypeMapper::convertBuiltinType(const BuiltinType *BT,
+ bool InMemory) {
QualType QT(BT, 0);
switch (BT->getKind()) {
@@ -114,11 +120,11 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
return Builder.getVoidType();
case BuiltinType::NullPtr:
- return createPointerTypeForPointee(QT);
+ return createPointerTypeForPointee(QT);
case BuiltinType::Bool:
- return Builder.getIntegerType(ASTCtx.getTypeSize(QT), getTypeAlign(QT),
- false, true);
+ return Builder.getIntegerType(1, getTypeAlign(QT), false, true, false,
+ ASTCtx.isPromotableIntegerType(QT), InMemory);
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::SChar:
@@ -139,7 +145,8 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
case BuiltinType::Int128:
case BuiltinType::UInt128:
return Builder.getIntegerType(ASTCtx.getTypeSize(QT), getTypeAlign(QT),
- BT->isSignedInteger());
+ BT->isSignedInteger(), false, false,
+ ASTCtx.isPromotableIntegerType(QT));
case BuiltinType::Half:
case BuiltinType::Float16:
@@ -151,6 +158,49 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
return Builder.getFloatType(ASTCtx.getFloatTypeSemantics(QT),
getTypeAlign(QT));
+ case BuiltinType::OCLImage1dRO:
+ case BuiltinType::OCLImage1dWO:
+ case BuiltinType::OCLImage1dRW:
+ case BuiltinType::OCLImage1dArrayRO:
+ case BuiltinType::OCLImage1dArrayWO:
+ case BuiltinType::OCLImage1dArrayRW:
+ case BuiltinType::OCLImage1dBufferRO:
+ case BuiltinType::OCLImage1dBufferWO:
+ case BuiltinType::OCLImage1dBufferRW:
+ case BuiltinType::OCLImage2dRO:
+ case BuiltinType::OCLImage2dWO:
+ case BuiltinType::OCLImage2dRW:
+ case BuiltinType::OCLImage2dArrayRO:
+ case BuiltinType::OCLImage2dArrayWO:
+ case BuiltinType::OCLImage2dArrayRW:
+ case BuiltinType::OCLImage2dDepthRO:
+ case BuiltinType::OCLImage2dDepthWO:
+ case BuiltinType::OCLImage2dDepthRW:
+ case BuiltinType::OCLImage2dArrayDepthRO:
+ case BuiltinType::OCLImage2dArrayDepthWO:
+ case BuiltinType::OCLImage2dArrayDepthRW:
+ case BuiltinType::OCLImage2dMSAARO:
+ case BuiltinType::OCLImage2dMSAAWO:
+ case BuiltinType::OCLImage2dMSAARW:
+ case BuiltinType::OCLImage2dArrayMSAARO:
+ case BuiltinType::OCLImage2dArrayMSAAWO:
+ case BuiltinType::OCLImage2dArrayMSAARW:
+ case BuiltinType::OCLImage2dMSAADepthRO:
+ case BuiltinType::OCLImage2dMSAADepthWO:
+ case BuiltinType::OCLImage2dMSAADepthRW:
+ case BuiltinType::OCLImage2dArrayMSAADepthRO:
+ case BuiltinType::OCLImage2dArrayMSAADepthWO:
+ case BuiltinType::OCLImage2dArrayMSAADepthRW:
+ case BuiltinType::OCLImage3dRO:
+ case BuiltinType::OCLImage3dWO:
+ case BuiltinType::OCLImage3dRW:
+ return createPointerTypeForPointee(QT);
+
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLQueue:
+ return createPointerTypeForPointee(QT);
+
default:
// Unhandled BuiltinTypes are treated as unsigned integers.
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
@@ -180,37 +230,42 @@ QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
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());
+ QualType VectorQualType(VT, 0);
+ // Handle element size adjustments for sub-byte types
if (auto *IT = llvm::dyn_cast<llvm::abi::IntegerType>(ElementType)) {
unsigned BW = IT->getSizeInBits().getFixedValue();
-
- if (BW != 1 && (BW & 7)) {
- BW = llvm::bit_ceil(BW);
- BW = std::clamp(BW, 8u, 64u);
+ if (BW != 1 && (BW & 7)) {
+ BW = llvm::bit_ceil(BW);
+ BW = std::clamp(BW, 8u, 64u);
bool Signed = IT->isSigned();
ElementType = Builder.getIntegerType(BW, llvm::Align(BW / 8), Signed);
- } else if (BW < 8 && BW != 1) {
+ } else if (BW < 8 && BW != 1) {
bool Signed = IT->isSigned();
ElementType = Builder.getIntegerType(8, llvm::Align(1), Signed);
}
}
- unsigned NElems = VT->getNumElements();
- if (!llvm::isPowerOf2_32(NElems))
- NElems = llvm::bit_ceil(NElems);
- llvm::ElementCount NumElements =
- llvm::ElementCount::getFixed(NElems);
+ unsigned NElems = VT->getNumElements();
+ uint64_t LogicalSizeInBits =
+ NElems * ElementType->getSizeInBits().getFixedValue();
+
+ // Only round up for small vectors (≤ 64 bits)
+ if (LogicalSizeInBits <= 64) {
+ uint64_t ABISizeInBits = ASTCtx.getTypeSize(VectorQualType);
+ if (ABISizeInBits > LogicalSizeInBits) {
+ uint64_t ElementSizeInBits = ElementType->getSizeInBits().getFixedValue();
+ NElems = ABISizeInBits / ElementSizeInBits;
+ }
+ }
+ // For larger vectors, keep exact element count
- llvm::Align VectorAlign = getTypeAlign(QualType(VT, 0));
+ llvm::ElementCount NumElements = llvm::ElementCount::getFixed(NElems);
+ llvm::Align VectorAlign = getTypeAlign(VectorQualType);
- return
- Builder.getVectorType(ElementType, NumElements, VectorAlign);
+ return Builder.getVectorType(ElementType, NumElements, VectorAlign);
}
/// Converts complex types to LLVM ABI complex representations.
@@ -224,10 +279,7 @@ QualTypeMapper::convertComplexType(const ComplexType *CT) {
const llvm::abi::Type *ElementType = convertType(CT->getElementType());
llvm::Align ComplexAlign = getTypeAlign(QualType(CT, 0));
- auto *Result = Builder.getComplexType(ElementType, ComplexAlign);
-
- return Result;
- // return Builder.getComplexType(ElementType, ComplexAlign);
+ return Builder.getComplexType(ElementType, ComplexAlign);
}
/// Converts member pointer types to LLVM ABI representations.
@@ -242,12 +294,9 @@ QualTypeMapper::convertMemberPointerType(const clang::MemberPointerType *MPT) {
uint64_t Size = ASTCtx.getTypeSize(QT);
llvm::Align Align = getTypeAlign(QT);
- bool IsFunctionPointer = MPT->isFunctionType();
- bool Has64BitPointers =
- ASTCtx.getTargetInfo().getPointerWidth(LangAS::Default) == 64;
+ bool IsFunctionPointer = MPT->isMemberFunctionPointerType();
- return Builder.getMemberPointerType(IsFunctionPointer, Has64BitPointers, Size,
- Align);
+ return Builder.getMemberPointerType(IsFunctionPointer, Size, Align);
}
/// Converts record types (struct/class/union) to LLVM ABI representations.
@@ -257,11 +306,11 @@ QualTypeMapper::convertMemberPointerType(const clang::MemberPointerType *MPT) {
/// \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();
+ const RecordDecl *RD = RT->getOriginalDecl()->getDefinition();
bool canPassInRegs = false;
bool hasFlexibleArrMember = false;
if (RD) {
- canPassInRegs = RT->getDecl()->canPassInRegisters();
+ canPassInRegs = RT->getOriginalDecl()->canPassInRegisters();
hasFlexibleArrMember = RD->hasFlexibleArrayMember();
}
if (!RD) {
@@ -272,8 +321,12 @@ const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
hasFlexibleArrMember, false, canPassInRegs);
}
- if (RD->isUnion())
+ if (RD->isUnion()) {
+ const RecordDecl *UD = RT->getOriginalDecl();
+ if (UD->hasAttr<TransparentUnionAttr>())
+ return convertUnionType(RD, true);
return convertUnionType(RD);
+ }
// Handle C++ classes with base classes
auto *const CXXRd = dyn_cast<CXXRecordDecl>(RD);
@@ -299,6 +352,7 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD,
SmallVector<llvm::abi::FieldInfo, 8> BaseClasses;
SmallVector<llvm::abi::FieldInfo, 8> VirtualBaseClasses;
+ // Add vtable pointer for polymorphic classes
if (RD->isPolymorphic()) {
const llvm::abi::Type *VtablePointer =
createPointerTypeForPointee(ASTCtx.VoidPtrTy);
@@ -310,13 +364,11 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD,
continue;
const RecordType *BaseRT = Base.getType()->castAs<RecordType>();
-
const llvm::abi::Type *BaseType = convertType(Base.getType());
uint64_t BaseOffset =
Layout.getBaseClassOffset(BaseRT->getAsCXXRecordDecl()).getQuantity() *
8;
- Fields.emplace_back(BaseType, BaseOffset);
BaseClasses.emplace_back(BaseType, BaseOffset);
}
@@ -331,9 +383,9 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD,
.getQuantity() *
8;
- Fields.emplace_back(VBaseType, VBaseOffset);
VirtualBaseClasses.emplace_back(VBaseType, VBaseOffset);
}
+
computeFieldInfo(RD, Fields, Layout);
llvm::sort(Fields,
@@ -397,7 +449,7 @@ 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) {
- const EnumDecl *ED = ET->getDecl();
+ const EnumDecl *ED = ET->getOriginalDecl();
QualType UnderlyingType = ED->getIntegerType();
if (UnderlyingType.isNull())
@@ -425,8 +477,8 @@ QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
return Builder.getStructType(
- Fields, Size, Alignment, llvm::abi::StructPacking::Default, {}, {}, IsCXXRecord,
- false, false, false, RD->hasFlexibleArrayMember(), false,
+ Fields, Size, Alignment, llvm::abi::StructPacking::Default, {}, {},
+ IsCXXRecord, false, false, false, RD->hasFlexibleArrayMember(), false,
RD->canPassInRegisters());
}
@@ -436,18 +488,64 @@ QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
///
/// \param RD The RecordDecl representing the union
/// \return LLVM ABI UnionType
-const llvm::abi::UnionType *
-QualTypeMapper::convertUnionType(const clang::RecordDecl *RD) {
+const llvm::abi::StructType *
+QualTypeMapper::convertUnionType(const clang::RecordDecl *RD,
+ bool isTransparent) {
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
- SmallVector<llvm::abi::FieldInfo, 16> Fields;
- computeFieldInfo(RD, Fields, Layout);
+ SmallVector<llvm::abi::FieldInfo, 16> AllFields;
+ computeFieldInfo(RD, AllFields, 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);
+ auto *UnionMeta = new llvm::abi::UnionMetadata(AllFields, Size, Alignment);
+
+ const llvm::abi::Type *StorageType = nullptr;
+ bool SeenNamedMember = false;
+
+ for (const auto *Field : RD->fields()) {
+ if (Field->isBitField() && Field->isZeroLengthBitField())
+ continue;
+
+ const llvm::abi::Type *FieldType = convertType(Field->getType(), true);
+
+ if (!SeenNamedMember) {
+ SeenNamedMember = Field->getIdentifier() != nullptr;
+ if (!SeenNamedMember) {
+ if (const auto *FieldRD = Field->getType()->getAsRecordDecl())
+ SeenNamedMember = FieldRD->findFirstNamedDataMember() != nullptr;
+ }
+
+ if (SeenNamedMember) {
+ StorageType = FieldType;
+ }
+ }
+
+ if (!StorageType ||
+ FieldType->getAlignment().value() >
+ StorageType->getAlignment().value() ||
+ (FieldType->getAlignment().value() ==
+ StorageType->getAlignment().value() &&
+ FieldType->getSizeInBits().getFixedValue() >
+ StorageType->getSizeInBits().getFixedValue())) {
+ StorageType = FieldType;
+ }
+ }
+
+ SmallVector<llvm::abi::FieldInfo, 1> UnionFields;
+ if (StorageType) {
+ UnionFields.emplace_back(StorageType, 0, false, 0, false);
+ }
+
+ const llvm::abi::StructType *LoweredUnion = Builder.getUnionType(
+ UnionFields, Size, Alignment, llvm::abi::StructPacking::Default,
+ isTransparent, RD->canPassInRegisters());
+
+ LoweredUnion->setMetadata(UnionMeta);
+
+ return LoweredUnion;
}
llvm::Align QualTypeMapper::getPreferredTypeAlign(QualType QT) const {
@@ -465,7 +563,9 @@ QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
llvm::Align Alignment =
llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(AddrSpace));
- return Builder.getPointerType(PointerSize, llvm::Align(Alignment.value()/8),ASTCtx.getTargetInfo().getTargetAddressSpace(AddrSpace));
+ return Builder.getPointerType(
+ PointerSize, llvm::Align(Alignment.value() / 8),
+ ASTCtx.getTargetInfo().getTargetAddressSpace(AddrSpace));
}
/// Processes the fields of a record (struct/class/union) and populates
@@ -481,19 +581,20 @@ void QualTypeMapper::computeFieldInfo(
unsigned FieldIndex = 0;
for (const auto *FD : RD->fields()) {
- const llvm::abi::Type *FieldType = convertType(FD->getType());
+ const llvm::abi::Type *FieldType = convertType(FD->getType(), true);
uint64_t OffsetInBits = Layout.getFieldOffset(FieldIndex);
bool IsBitField = FD->isBitField();
uint64_t BitFieldWidth = 0;
- bool IsUnnamed = false;
+ bool IsUnnamed = false;
if (IsBitField) {
BitFieldWidth = FD->getBitWidthValue();
- IsUnnamed = FD->isUnnamedBitField();
- }
+ IsUnnamed = FD->isUnnamedBitField();
+ }
- Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth,IsUnnamed);
+ Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth,
+ IsUnnamed);
++FieldIndex;
}
}
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 7bcb48394bd9f..d3431aae0431c 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -7,13 +7,9 @@
//===----------------------------------------------------------------------===//
#include "ABIInfoImpl.h"
-#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/Basic/DiagnosticFrontend.h"
-#include "llvm/ABI/ABIInfo.h"
-#include "llvm/ABI/Types.h"
#include "llvm/ADT/SmallBitVector.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -2108,7 +2104,6 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
}
}
-
// Classify the fields one at a time, merging the results.
unsigned idx = 0;
bool UseClang11Compat = getContext().getLangOpts().getClangABICompat() <=
@@ -2184,8 +2179,6 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
Hi = merge(Hi, FieldHi);
if (Lo == Memory || Hi == Memory)
break;
-
-
}
postMerge(Size, Lo, Hi);
@@ -2969,17 +2962,6 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
unsigned FreeSSERegs = IsRegCall ? 16 : 8;
unsigned NeededInt = 0, NeededSSE = 0, MaxVectorWidth = 0;
- llvm::abi::ABICompatInfo CompatInfo;
- CompatInfo.Flags.ClassifyIntegerMMXAsSSE = classifyIntegerMMXAsSSE();
- CompatInfo.Flags.HonorsRevision98 = honorsRevision0_98();
- CompatInfo.Flags.PassInt128VectorsInMem = passInt128VectorsInMem();
- CompatInfo.Flags.ReturnCXXRecordGreaterThan128InMem =
- returnCXXRecordGreaterThan128InMem();
- auto avxABILvl = static_cast<llvm::abi::X86AVXABILevel>(AVXLevel);
- auto newTargetInfo = llvm::abi::createX8664TargetCodeGenInfo(
- CGT.getTypeBuilder(), CGT.getTarget().getTriple(), avxABILvl,
- Has64BitPointers, CompatInfo);
-
if (!::classifyReturnType(getCXXABI(), FI, *this)) {
if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() &&
!FI.getReturnType()->getTypePtr()->isUnionType()) {
@@ -2999,15 +2981,8 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Complex Long Double Type is passed in Memory when Regcall
// calling convention is used.
FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
- else {
- // FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- const llvm::abi::Type *mappedTy =
- CGT.getMapper().convertType(FI.getReturnType());
- llvm::abi::ABIArgInfo newRetInfo =
- newTargetInfo->getABIInfo().classifyReturnType(mappedTy);
- FI.getReturnInfo() =
- CGT.convertABIArgInfo(newRetInfo, FI.getReturnType());
- }
+ else
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
}
// If the return value is indirect, then the hidden argument is consuming one
diff --git a/clang/test/CodeGen/sysv_abi.c b/clang/test/CodeGen/sysv_abi.c
index 36c0872a9253f..29ea819c2aa26 100644
--- a/clang/test/CodeGen/sysv_abi.c
+++ b/clang/test/CodeGen/sysv_abi.c
@@ -30,10 +30,14 @@ typedef __attribute__((vector_size(64))) float my_m512;
my_m256 SYSV_CC get_m256(void);
void SYSV_CC take_m256(my_m256);
+my_m512 SYSV_CC get_m512(void);
+void SYSV_CC take_m512(my_m512);
void use_vectors(void) {
my_m256 v1 = get_m256();
take_m256(v1);
+ my_m512 v2 = get_m512();
+ take_m512(v2);
}
// CHECK: define {{(dso_local )?}}void @use_vectors()
diff --git a/llvm/include/llvm/ABI/ABIFunctionInfo.h b/llvm/include/llvm/ABI/ABIFunctionInfo.h
index c008d910928fe..b6b4ee21cf055 100644
--- a/llvm/include/llvm/ABI/ABIFunctionInfo.h
+++ b/llvm/include/llvm/ABI/ABIFunctionInfo.h
@@ -39,9 +39,7 @@ class ABIArgInfo {
};
private:
- Kind TheKind;
const Type *CoercionType;
- const Type *PaddingType;
struct DirectAttrInfo {
unsigned Offset;
unsigned Align;
@@ -55,20 +53,27 @@ class ABIArgInfo {
union {
DirectAttrInfo DirectAttr;
IndirectAttrInfo IndirectAttr;
+ unsigned AllocaFieldIndex;
+ };
+ union {
+ const Type *PaddingType;
+ const Type *UnpaddedCoerceAndExpandType;
};
+ Kind TheKind;
bool InReg : 1;
bool PaddingInReg : 1;
bool SignExt : 1;
bool ZeroExt : 1;
- unsigned IndirectAlign : 16;
bool IndirectByVal : 1;
bool IndirectRealign : 1;
+ bool SRetAfterThis : 1;
bool CanBeFlattened : 1;
+ bool InAllocaSRet : 1;
+ bool InAllocaIndirect : 1;
ABIArgInfo(Kind K = Direct)
- : TheKind(K), CoercionType(nullptr), InReg(false), PaddingInReg(false),
- SignExt(false), ZeroExt(false), IndirectAlign(0), IndirectByVal(false) {
- }
+ : CoercionType(nullptr), TheKind(K), InReg(false), PaddingInReg(false),
+ SignExt(false), ZeroExt(false), IndirectByVal(false) {}
public:
static ABIArgInfo getDirect(const Type *T = nullptr, unsigned Offset = 0,
@@ -124,21 +129,6 @@ class ABIArgInfo {
this->ZeroExt = false;
return *this;
}
- // static ABIArgInfo getSignExtend(ABIArgInfo AI) {
- // AI.DirectAttr.Offset = 0;
- // AI.DirectAttr.Align = 0;
- // AI.ZeroExt = false;
- // AI.PaddingType = nullptr;
- // return AI;
- // }
- //
- // static ABIArgInfo getZeroExtend(ABIArgInfo AI) {
- // AI.DirectAttr.Offset = 0;
- // AI.DirectAttr.Align = 0;
- // AI.ZeroExt = true;
- // AI.PaddingType = nullptr;
- // return AI;
- // }
ABIArgInfo &setZeroExt(bool ZeroExtend = true) {
this->ZeroExt = ZeroExtend;
@@ -147,10 +137,16 @@ class ABIArgInfo {
return *this;
}
- static ABIArgInfo getIndirect(unsigned Align = 0, bool ByVal = true) {
+ static ABIArgInfo getIndirect(unsigned Align = 0, bool ByVal = true,
+ unsigned AddrSpace = 0, bool Realign = false,
+ const Type *Padding = nullptr) {
ABIArgInfo AI(Indirect);
- AI.IndirectAlign = Align;
+ AI.IndirectAttr.Align = Align;
+ AI.IndirectAttr.AddrSpace = AddrSpace;
AI.IndirectByVal = ByVal;
+ AI.IndirectRealign = Realign;
+ AI.SRetAfterThis = false;
+ AI.PaddingType = Padding;
return AI;
}
@@ -176,20 +172,85 @@ class ABIArgInfo {
bool isExtend() const { return TheKind == Extend; }
bool isExpand() const { return TheKind == Expand; }
bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
+ bool isIndirectAliased() const { return TheKind == IndirectAliased; }
bool isInAlloca() const { return TheKind == InAlloca; }
bool isInReg() const { return InReg; }
bool isSignExt() const { return SignExt; }
bool hasPaddingInReg() const { return PaddingInReg; }
+ const Type *getPaddingType() const {
+ return canHavePaddingType() ? PaddingType : nullptr;
+ }
+
+ bool canHavePaddingType() const {
+ return isDirect() || isExtend() || isIndirect() || isIndirectAliased() ||
+ isExpand();
+ }
+
+ unsigned getDirectOffset() const {
+ assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ return DirectAttr.Offset;
+ }
unsigned getIndirectAlign() const {
- assert(isIndirect() && "Invalid Kind!");
- return IndirectAlign;
+ assert((isIndirect() || isIndirectAliased()) && "Invalid Kind!");
+ return IndirectAttr.Align;
+ }
+
+ unsigned getIndirectAddrSpace() const {
+ assert((isIndirect() || isIndirectAliased()) && "Invalid Kind!");
+ return IndirectAttr.AddrSpace;
}
bool getIndirectByVal() const {
assert(isIndirect() && "Invalid Kind!");
return IndirectByVal;
}
+ bool getIndirectRealign() const {
+ assert((isIndirect() || isIndirectAliased()) && "Invalid Kind!");
+ return IndirectRealign;
+ }
+
+ bool isSRetAfterThis() const {
+ assert(isIndirect() && "Invalid Kind!");
+ return SRetAfterThis;
+ }
+
+ unsigned getInAllocaFieldIndex() const {
+ assert(isInAlloca() && "Invalid kind!");
+ return AllocaFieldIndex;
+ }
+
+ bool getInAllocaIndirect() const {
+ assert(isInAlloca() && "Invalid kind!");
+ return InAllocaIndirect;
+ }
+
+ bool getInAllocaSRet() const {
+ assert(isInAlloca() && "Invalid kind!");
+ return InAllocaSRet;
+ }
+ const Type *getUnpaddedCoerceAndExpandType() const {
+ assert(isCoerceAndExpand());
+ return UnpaddedCoerceAndExpandType;
+ }
+ bool isZeroExt() const {
+ assert(isExtend() && "Invalid Kind!");
+ return ZeroExt;
+ }
+ bool isNoExt() const {
+ assert(isExtend() && "Invalid Kind!");
+ return !SignExt && !ZeroExt;
+ }
+
+ unsigned getDirectAlign() const {
+ assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ return DirectAttr.Align;
+ }
+
+ bool getCanBeFlattened() const {
+ assert(isDirect() && "Invalid kind!");
+ return CanBeFlattened;
+ }
const Type *getCoerceToType() const {
assert((isDirect() || isExtend() || isCoerceAndExpand()) &&
@@ -257,7 +318,8 @@ struct RequiredArgs {
bool isVariadic() const { return allowsOptionalArgs(); }
unsigned getNumRequiredArgs() const {
- return allowsOptionalArgs() ? NumRequired : 0;
+ assert(allowsOptionalArgs());
+ return NumRequired;
}
bool operator==(const RequiredArgs &Other) const {
@@ -295,6 +357,16 @@ class ABIFunctionInfo final
friend class TrailingObjects;
public:
+ typedef const ArgInfo *const_arg_iterator;
+ typedef ArgInfo *arg_iterator;
+
+ const_arg_iterator arg_begin() const { return getTrailingObjects(); }
+ const_arg_iterator arg_end() const { return getTrailingObjects() + NumArgs; }
+ arg_iterator arg_begin() { return getTrailingObjects(); }
+ arg_iterator arg_end() { return getTrailingObjects() + NumArgs; }
+
+ unsigned arg_size() const { return NumArgs; }
+
static ABIFunctionInfo *
create(CallingConv::ID CC, const Type *ReturnType,
ArrayRef<const Type *> ArgTypes,
@@ -310,6 +382,10 @@ class ABIFunctionInfo final
RequiredArgs getRequiredArgs() const { return Required; }
bool isVariadic() const { return Required.isVariadic(); }
+ unsigned getNumRequiredArgs() const {
+ return isVariadic() ? Required.getNumRequiredArgs() : arg_size();
+ }
+
ArrayRef<ArgInfo> arguments() const {
return {getTrailingObjects(), NumArgs};
}
diff --git a/llvm/include/llvm/ABI/ABIInfo.h b/llvm/include/llvm/ABI/ABIInfo.h
index 624bac2a5d2ea..04b06d7ab436c 100644
--- a/llvm/include/llvm/ABI/ABIInfo.h
+++ b/llvm/include/llvm/ABI/ABIInfo.h
@@ -45,11 +45,13 @@ struct ABICompatInfo {
bool ReturnCXXRecordGreaterThan128InMem : 1;
bool ClassifyIntegerMMXAsSSE : 1;
bool HonorsRevision98 : 1;
+ bool Clang11Compat : 1;
ABIFlags()
: PassInt128VectorsInMem(true),
ReturnCXXRecordGreaterThan128InMem(true),
- ClassifyIntegerMMXAsSSE(true), HonorsRevision98(true) {}
+ ClassifyIntegerMMXAsSSE(true), HonorsRevision98(true),
+ Clang11Compat(true) {}
} Flags;
@@ -69,18 +71,17 @@ class ABIInfo {
virtual ~ABIInfo() = default;
RecordArgABI getRecordArgABI(const StructType *ST) const;
- virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
- // virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
+ RecordArgABI getRecordArgABI(const Type *Ty) const;
+ RecordArgABI getRecordArgABI(const StructType *ST, bool IsCxxRecord) const;
virtual void computeInfo(ABIFunctionInfo &FI) const = 0;
virtual bool isPassByRef(const Type *Ty) const { return false; }
const ABICompatInfo &getABICompatInfo() const { return CompatInfo; }
- ABIArgInfo getNaturalAlignIndirect(const Type *Ty) const;
+ ABIArgInfo getNaturalAlignIndirect(const Type *Ty, bool ByVal = true) const;
bool isAggregateTypeForABI(const Type *Ty) const;
bool isPromotableIntegerType(const IntegerType *Ty) const;
-bool isZeroSizedType(const Type *Ty) const;
-bool isEmptyRecord(const StructType *ST)const;
-bool isEmptyField(const FieldInfo &FI)const;
-
+ bool isZeroSizedType(const Type *Ty) const;
+ bool isEmptyRecord(const StructType *ST) const;
+ bool isEmptyField(const FieldInfo &FI) const;
void setABICompatInfo(const ABICompatInfo &Info) { CompatInfo = Info; }
};
diff --git a/llvm/include/llvm/ABI/ABITypeMapper.h b/llvm/include/llvm/ABI/ABITypeMapper.h
index 774df108c6d50..133df6185ccb5 100644
--- a/llvm/include/llvm/ABI/ABITypeMapper.h
+++ b/llvm/include/llvm/ABI/ABITypeMapper.h
@@ -19,6 +19,7 @@
#include "llvm/ABI/Types.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Type.h"
@@ -28,7 +29,8 @@ namespace llvm {
class ABITypeMapper {
public:
- explicit ABITypeMapper(LLVMContext &Ctx) : Context(Ctx) {}
+ explicit ABITypeMapper(LLVMContext &Ctx, const DataLayout &DataLayout)
+ : Context(Ctx), DL(DataLayout) {}
Type *convertType(const abi::Type *ABIType);
@@ -36,11 +38,14 @@ class ABITypeMapper {
private:
LLVMContext &Context;
+ const DataLayout &DL;
DenseMap<const abi::Type *, Type *> TypeCache;
Type *convertIntegerType(const abi::IntegerType *IT);
+ Type *convertFieldType(const abi::Type *FieldType);
+
Type *convertFloatType(const abi::FloatType *FT);
Type *convertPointerType(const abi::PointerType *PT);
@@ -53,8 +58,6 @@ class ABITypeMapper {
Type *convertStructType(const abi::StructType *ST);
- Type *convertUnionType(const abi::UnionType *UT);
-
Type *convertVoidType(const abi::VoidType *VT);
Type *getFloatTypeForSemantics(const fltSemantics &Semantics);
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 01373f999baea..e1c40d3202322 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -18,10 +18,11 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/TypeSize.h"
-#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
#include <cstdint>
namespace llvm {
@@ -37,7 +38,6 @@ enum class TypeKind {
Array,
Vector,
Struct,
- Union,
};
class Type {
@@ -58,24 +58,25 @@ class Type {
TypeKind Kind;
TypeSize SizeInBits;
Align ABIAlignment;
- Align PreferredAlignment;
- bool IsExplicitlyAligned;
+ mutable const void *Metadata;
- Type(TypeKind K, TypeSize Size, Align Align, bool ExplicitAlign = false)
- : Kind(K), SizeInBits(Size), ABIAlignment(Align),
- IsExplicitlyAligned(ExplicitAlign) {}
+ Type(TypeKind K, TypeSize Size, Align Align)
+ : Kind(K), SizeInBits(Size), ABIAlignment(Align) {}
public:
TypeKind getKind() const { return Kind; }
TypeSize getSizeInBits() const { return SizeInBits; }
Align getAlignment() const { return ABIAlignment; }
- Align getPrefferedAlign() const { return PreferredAlignment; }
- bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
- void setExplicitAlignment(Align Align) {
- ABIAlignment = Align;
- IsExplicitlyAligned = true;
+ template <typename T> void setMetadata(const T *Meta) const {
+ Metadata = Meta;
}
+
+ template <typename T> const T *getMetadata() const {
+ return static_cast<const T *>(Metadata);
+ }
+ bool hasMetadata() const { return Metadata != nullptr; }
+
TypeSize getTypeAllocSize() const {
return alignTo(getTypeStoreSize(), getAlignment().value());
}
@@ -87,7 +88,6 @@ class Type {
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 isMemberPointer() const { return Kind == TypeKind::MemberPointer; }
bool isComplex() const { return Kind == TypeKind::Complex; }
};
@@ -115,42 +115,27 @@ class ComplexType : public Type {
const Type *ElementType;
};
-class MemberPointerType : public Type {
-public:
- MemberPointerType(bool IsFunctionPointer, bool Has64BitPointers,
- uint64_t SizeInBits, Align Alignment)
- : Type(TypeKind::MemberPointer, TypeSize::getFixed(SizeInBits),
- Alignment),
- IsFunctionPointer(IsFunctionPointer),
- Has64BitPointers(Has64BitPointers) {}
-
- bool isFunctionPointer() const { return IsFunctionPointer; }
- bool has64BitPointers() const { return Has64BitPointers; }
-
- static bool classof(const Type *T) {
- return T->getKind() == TypeKind::MemberPointer;
- }
-
-private:
- bool IsFunctionPointer;
- bool Has64BitPointers;
-};
-
class IntegerType : public Type {
private:
bool IsSigned;
bool IsBoolean;
bool IsBitInt;
+ bool IsPromotable;
+ bool InMemory;
public:
IntegerType(uint64_t BitWidth, Align Align, bool Signed, bool IsBool = false,
- bool BitInt = false)
+ bool BitInt = false, bool IsPromotableInt = false,
+ bool InMem = false)
: Type(TypeKind::Integer, TypeSize::getFixed(BitWidth), Align),
- IsSigned(Signed), IsBoolean(IsBool), IsBitInt(BitInt) {}
+ IsSigned(Signed), IsBoolean(IsBool), IsBitInt(BitInt),
+ IsPromotable(IsPromotableInt), InMemory(InMem) {}
bool isSigned() const { return IsSigned; }
bool isBool() const { return IsBoolean; }
bool isBitInt() const { return IsBitInt; }
+ bool needsMemoryRep() const { return InMemory; }
+ bool isPromotableIntegerType() const { return IsPromotable; }
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Integer;
@@ -171,33 +156,70 @@ class FloatType : public Type {
static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
};
-class PointerType : public Type {
+class PointerLikeType : public Type {
+protected:
unsigned AddrSpace;
+ PointerLikeType(TypeKind K, TypeSize Size, Align Align, unsigned AS = 0)
+ : Type(K, Size, Align), AddrSpace(AS) {}
+
+public:
+ virtual ~PointerLikeType() = default;
+ unsigned getAddrSpace() const { return AddrSpace; }
+ virtual bool isMemberPointer() const = 0;
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::Pointer ||
+ T->getKind() == TypeKind::MemberPointer;
+ }
+};
+class PointerType : public PointerLikeType {
public:
PointerType(uint64_t Size, Align Align, unsigned AddressSpace = 0)
- : Type(TypeKind::Pointer, TypeSize::getFixed(Size), Align),
- AddrSpace(AddressSpace) {}
+ : PointerLikeType(TypeKind::Pointer, TypeSize::getFixed(Size), Align,
+ AddressSpace) {}
+
+ bool isMemberPointer() const override { return false; }
- unsigned getAddrSpace() const { return AddrSpace; }
static bool classof(const Type *T) {
return T->getKind() == TypeKind::Pointer;
}
};
+class MemberPointerType : public PointerLikeType {
+private:
+ bool IsFunctionPointer;
+
+public:
+ MemberPointerType(bool IsFunctionPointer, uint64_t SizeInBits,
+ Align Alignment, unsigned AddressSpace = 0)
+ : PointerLikeType(TypeKind::MemberPointer, TypeSize::getFixed(SizeInBits),
+ Alignment, AddressSpace),
+ IsFunctionPointer(IsFunctionPointer) {}
+
+ bool isMemberPointer() const override { return true; }
+ bool isFunctionPointer() const { return IsFunctionPointer; }
+
+ static bool classof(const Type *T) {
+ return T->getKind() == TypeKind::MemberPointer;
+ }
+};
+
class ArrayType : public Type {
private:
const Type *ElementType;
uint64_t NumElements;
+ bool IsMatrix;
public:
- ArrayType(const Type *ElemType, uint64_t NumElems)
+ ArrayType(const Type *ElemType, uint64_t NumElems, bool IsMatrixType = false)
: Type(TypeKind::Array, ElemType->getSizeInBits() * NumElems,
ElemType->getAlignment()),
- ElementType(ElemType), NumElements(NumElems) {}
+ ElementType(ElemType), NumElements(NumElems), IsMatrix(IsMatrixType) {}
const Type *getElementType() const { return ElementType; }
uint64_t getNumElements() const { return NumElements; }
+ bool isMatrixType() const { return IsMatrix; }
static bool classof(const Type *T) { return T->getKind() == TypeKind::Array; }
};
@@ -232,7 +254,7 @@ struct FieldInfo {
uint64_t BitFieldWidth;
FieldInfo(const Type *Type, uint64_t Offset = 0, bool BitField = false,
- uint64_t BFWidth = 0,bool IsUnnamedBF = false)
+ uint64_t BFWidth = 0, bool IsUnnamedBF = false)
: FieldType(Type), OffsetInBits(Offset), IsBitField(BitField),
IsUnnamedBitfield(IsUnnamedBF), BitFieldWidth(BFWidth) {}
};
@@ -241,11 +263,14 @@ enum class StructPacking { Default, Packed, ExplicitPacking };
class StructType : public Type {
private:
- const FieldInfo *Fields;
- uint32_t NumFields;
+ ArrayRef<FieldInfo> Fields;
+ ArrayRef<FieldInfo> BaseClasses;
+ ArrayRef<FieldInfo> VirtualBaseClasses;
StructPacking Packing;
bool CanPassInRegisters;
bool IsCoercedStruct;
+ bool IsUnion;
+ bool IsTransparent;
bool IsCXXRecord;
bool IsPolymorphic;
@@ -253,35 +278,30 @@ class StructType : public Type {
bool HasNonTrivialDestructor;
bool HasFlexibleArrayMember;
bool HasUnalignedFields;
- const FieldInfo *BaseClasses;
- uint32_t NumBaseClasses;
- const FieldInfo *VirtualBaseClasses;
- uint32_t NumVirtualBaseClasses;
public:
- StructType(const FieldInfo *StructFields, uint32_t FieldCount,
- const FieldInfo *Bases, uint32_t BaseCount,
- const FieldInfo *VBases, uint32_t VBaseCount, TypeSize Size,
- Align Align, StructPacking Pack = StructPacking::Default,
+ StructType(ArrayRef<FieldInfo> StructFields, ArrayRef<FieldInfo> Bases,
+ ArrayRef<FieldInfo> VBases, TypeSize Size, Align Align,
+ StructPacking Pack = StructPacking::Default, bool Union = false,
bool CXXRecord = false, bool Polymorphic = false,
bool NonTrivialCopy = false, bool NonTrivialDtor = false,
bool FlexibleArray = false, bool UnalignedFields = false,
- bool CanPassInRegs = false, bool IsCoercedStr = false)
+ bool CanPassInRegs = false, bool IsCoercedStr = false,
+ bool Transparent = false)
: Type(TypeKind::Struct, Size, Align), Fields(StructFields),
- NumFields(FieldCount), Packing(Pack), CanPassInRegisters(CanPassInRegs),
- IsCoercedStruct(IsCoercedStr), IsCXXRecord(CXXRecord),
+ BaseClasses(Bases), VirtualBaseClasses(VBases), Packing(Pack),
+ CanPassInRegisters(CanPassInRegs), IsCoercedStruct(IsCoercedStr),
+ IsUnion(Union), IsTransparent(Transparent), IsCXXRecord(CXXRecord),
IsPolymorphic(Polymorphic),
HasNonTrivialCopyConstructor(NonTrivialCopy),
HasNonTrivialDestructor(NonTrivialDtor),
HasFlexibleArrayMember(FlexibleArray),
- HasUnalignedFields(UnalignedFields), BaseClasses(Bases),
- NumBaseClasses(BaseCount), VirtualBaseClasses(VBases),
- NumVirtualBaseClasses(VBaseCount) {}
+ HasUnalignedFields(UnalignedFields) {}
- const FieldInfo *getFields() const { return Fields; }
- uint32_t getNumFields() const { return NumFields; }
+ uint32_t getNumFields() const { return Fields.size(); }
StructPacking getPacking() const { return Packing; }
+ bool isUnion() const { return IsUnion; }
bool isCXXRecord() const { return IsCXXRecord; }
bool isPolymorphic() const { return IsPolymorphic; }
bool hasNonTrivialCopyConstructor() const {
@@ -293,33 +313,75 @@ class StructType : public Type {
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
bool hasUnalignedFields() const { return HasUnalignedFields; }
- const FieldInfo *getBaseClasses() const { return BaseClasses; }
- uint32_t getNumBaseClasses() const { return NumBaseClasses; }
- const FieldInfo *getVirtualBaseClasses() const { return VirtualBaseClasses; }
- uint32_t getNumVirtualBaseClasses() const { return NumVirtualBaseClasses; }
+ uint32_t getNumBaseClasses() const { return BaseClasses.size(); }
+ uint32_t getNumVirtualBaseClasses() const {
+ return VirtualBaseClasses.size();
+ }
+ bool isTransparentUnion() const { return IsTransparent; }
+ ArrayRef<FieldInfo> getFields() const { return Fields; }
+ ArrayRef<FieldInfo> getBaseClasses() const { return BaseClasses; }
+ ArrayRef<FieldInfo> getVirtualBaseClasses() const {
+ return VirtualBaseClasses;
+ }
+
+ const FieldInfo *getElementContainingOffset(unsigned OffsetInBits) const {
+ std::vector<std::pair<unsigned, const FieldInfo *>> AllElements;
+
+ for (const auto &Field : Fields) {
+ if (Field.IsUnnamedBitfield)
+ continue;
+ AllElements.emplace_back(Field.OffsetInBits, &Field);
+ }
+
+ for (const auto &Base : BaseClasses)
+ AllElements.emplace_back(Base.OffsetInBits, &Base);
+
+ for (const auto &VBase : VirtualBaseClasses)
+ AllElements.emplace_back(VBase.OffsetInBits, &VBase);
+ std::sort(AllElements.begin(), AllElements.end(),
+ [](const auto &a, const auto &b) { return a.first < b.first; });
+
+ auto it =
+ std::upper_bound(AllElements.begin(), AllElements.end(), OffsetInBits,
+ [](unsigned offset, const auto &element) {
+ return offset < element.first;
+ });
+
+ if (it == AllElements.begin())
+ return nullptr;
+
+ --it;
+
+ const FieldInfo *candidate = it->second;
+ unsigned elementStart = it->first;
+ unsigned elementSize =
+ candidate->FieldType->getSizeInBits().getFixedValue();
+
+ if (OffsetInBits >= elementStart &&
+ OffsetInBits < elementStart + elementSize)
+ return candidate;
+
+ return nullptr;
+ }
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, TypeSize Size,
- Align Align, StructPacking Pack = StructPacking::Default)
- : Type(TypeKind::Union, Size, Align), Fields(UnionFields),
- NumFields(FieldCount), Packing(Pack) {}
+// Union metadata to preserve original field information
+struct UnionMetadata {
+ SmallVector<FieldInfo, 16> OriginalFields;
+ TypeSize OriginalSize;
+ Align OriginalAlignment;
- const FieldInfo *getFields() const { return Fields; }
- uint32_t getNumFields() const { return NumFields; }
- StructPacking getPacking() const { return Packing; }
+ UnionMetadata(ArrayRef<FieldInfo> Fields, TypeSize Size, Align Align)
+ : OriginalFields(Fields.begin(), Fields.end()), OriginalSize(Size),
+ OriginalAlignment(Align) {}
- static bool classof(const Type *T) { return T->getKind() == TypeKind::Union; }
+ ArrayRef<FieldInfo> getFields() const { return OriginalFields; }
+ TypeSize getSize() const { return OriginalSize; }
+ Align getAlignment() const { return OriginalAlignment; }
};
// API for creating ABI Types
@@ -336,22 +398,27 @@ class TypeBuilder {
const IntegerType *getIntegerType(uint64_t BitWidth, Align Align, bool Signed,
bool IsBoolean = false,
- bool IsBitInt = false) {
- return new (Allocator.Allocate<IntegerType>())
- IntegerType(BitWidth, Align, Signed, IsBoolean, IsBitInt);
+ bool IsBitInt = false,
+ bool IsPromotable = false,
+ bool InMemory = false) {
+ return new (Allocator.Allocate<IntegerType>()) IntegerType(
+ BitWidth, Align, Signed, IsBoolean, IsBitInt, IsPromotable, InMemory);
}
const FloatType *getFloatType(const fltSemantics &Semantics, Align Align) {
return new (Allocator.Allocate<FloatType>()) FloatType(Semantics, Align);
}
- const PointerType *getPointerType(uint64_t Size, Align Align,unsigned Addrspace = 0) {
- return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align,Addrspace);
+ const PointerType *getPointerType(uint64_t Size, Align Align,
+ unsigned Addrspace = 0) {
+ return new (Allocator.Allocate<PointerType>())
+ PointerType(Size, Align, Addrspace);
}
- const ArrayType *getArrayType(const Type *ElementType, uint64_t NumElements) {
+ const ArrayType *getArrayType(const Type *ElementType, uint64_t NumElements,
+ bool IsMatrixType = false) {
return new (Allocator.Allocate<ArrayType>())
- ArrayType(ElementType, NumElements);
+ ArrayType(ElementType, NumElements, IsMatrixType);
}
const VectorType *getVectorType(const Type *ElementType,
@@ -371,29 +438,29 @@ class TypeBuilder {
bool FlexibleArray = false, bool UnalignedFields = false,
bool CanPassInRegister = false) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
- for (size_t I = 0; I < Fields.size(); ++I)
- new (&FieldArray[I]) FieldInfo(Fields[I]);
+ std::copy(Fields.begin(), Fields.end(), FieldArray);
FieldInfo *BaseArray = nullptr;
if (!BaseClasses.empty()) {
BaseArray = Allocator.Allocate<FieldInfo>(BaseClasses.size());
- for (size_t I = 0; I < BaseClasses.size(); ++I)
- new (&BaseArray[I]) FieldInfo(BaseClasses[I]);
+ std::copy(BaseClasses.begin(), BaseClasses.end(), BaseArray);
}
FieldInfo *VBaseArray = nullptr;
if (!VirtualBaseClasses.empty()) {
VBaseArray = Allocator.Allocate<FieldInfo>(VirtualBaseClasses.size());
- for (size_t I = 0; I < VirtualBaseClasses.size(); ++I)
- new (&VBaseArray[I]) FieldInfo(VirtualBaseClasses[I]);
+ std::copy(VirtualBaseClasses.begin(), VirtualBaseClasses.end(),
+ VBaseArray);
}
- return new (Allocator.Allocate<StructType>()) StructType(
- FieldArray, static_cast<uint32_t>(Fields.size()), BaseArray,
- static_cast<uint32_t>(BaseClasses.size()), VBaseArray,
- static_cast<uint32_t>(VirtualBaseClasses.size()), Size, Align, Pack,
- CXXRecord, Polymorphic, NonTrivialCopy, NonTrivialDtor, FlexibleArray,
- UnalignedFields, CanPassInRegister);
+ ArrayRef<FieldInfo> FieldsRef(FieldArray, Fields.size());
+ ArrayRef<FieldInfo> BasesRef(BaseArray, BaseClasses.size());
+ ArrayRef<FieldInfo> VBasesRef(VBaseArray, VirtualBaseClasses.size());
+
+ return new (Allocator.Allocate<StructType>())
+ StructType(FieldsRef, BasesRef, VBasesRef, Size, Align, Pack, false,
+ CXXRecord, Polymorphic, NonTrivialCopy, NonTrivialDtor,
+ FlexibleArray, UnalignedFields, CanPassInRegister);
}
const StructType *
getCoercedStructType(ArrayRef<FieldInfo> Fields, TypeSize Size, Align Align,
@@ -405,42 +472,49 @@ class TypeBuilder {
bool FlexibleArray = false, bool UnalignedFields = false,
bool CanPassInRegister = false) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
- for (size_t I = 0; I < Fields.size(); ++I)
- new (&FieldArray[I]) FieldInfo(Fields[I]);
+ std::copy(Fields.begin(), Fields.end(), FieldArray);
FieldInfo *BaseArray = nullptr;
if (!BaseClasses.empty()) {
BaseArray = Allocator.Allocate<FieldInfo>(BaseClasses.size());
- for (size_t I = 0; I < BaseClasses.size(); ++I)
- new (&BaseArray[I]) FieldInfo(BaseClasses[I]);
+ std::copy(BaseClasses.begin(), BaseClasses.end(), BaseArray);
}
FieldInfo *VBaseArray = nullptr;
if (!VirtualBaseClasses.empty()) {
VBaseArray = Allocator.Allocate<FieldInfo>(VirtualBaseClasses.size());
- for (size_t I = 0; I < VirtualBaseClasses.size(); ++I)
- new (&VBaseArray[I]) FieldInfo(VirtualBaseClasses[I]);
+ std::copy(VirtualBaseClasses.begin(), VirtualBaseClasses.end(),
+ VBaseArray);
}
- return new (Allocator.Allocate<StructType>()) StructType(
- FieldArray, static_cast<uint32_t>(Fields.size()), BaseArray,
- static_cast<uint32_t>(BaseClasses.size()), VBaseArray,
- static_cast<uint32_t>(VirtualBaseClasses.size()), Size, Align, Pack,
- CXXRecord, Polymorphic, NonTrivialCopy, NonTrivialDtor, FlexibleArray,
- UnalignedFields, CanPassInRegister, true);
+ ArrayRef<FieldInfo> FieldsRef(FieldArray, Fields.size());
+ ArrayRef<FieldInfo> BasesRef(BaseArray, BaseClasses.size());
+ ArrayRef<FieldInfo> VBasesRef(VBaseArray, VirtualBaseClasses.size());
+ return new (Allocator.Allocate<StructType>())
+ StructType(FieldsRef, BasesRef, VBasesRef, Size, Align, Pack, false,
+ CXXRecord, Polymorphic, NonTrivialCopy, NonTrivialDtor,
+ FlexibleArray, UnalignedFields, CanPassInRegister, true);
}
-
- const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, TypeSize Size,
- Align Align,
- StructPacking Pack = StructPacking::Default) {
+ const StructType *getUnionType(ArrayRef<FieldInfo> Fields, TypeSize Size,
+ Align Align,
+ StructPacking Pack = StructPacking::Default,
+ bool IsTransparent = false,
+ bool CanPassInRegs = false) {
FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
for (size_t I = 0; I < Fields.size(); ++I) {
- new (&FieldArray[I]) FieldInfo(Fields[I]);
+ const FieldInfo &field = Fields[I];
+ new (&FieldArray[I])
+ FieldInfo(field.FieldType, 0, field.IsBitField, field.BitFieldWidth,
+ field.IsUnnamedBitfield);
}
- return new (Allocator.Allocate<UnionType>()) UnionType(
- FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
+ ArrayRef<FieldInfo> FieldsRef(FieldArray, Fields.size());
+
+ return new (Allocator.Allocate<StructType>())
+ StructType(FieldsRef, ArrayRef<FieldInfo>(), ArrayRef<FieldInfo>(),
+ Size, Align, Pack, true, false, false, false, false, false,
+ false, CanPassInRegs, false, IsTransparent);
}
const ComplexType *getComplexType(const Type *ElementType, Align Align) {
@@ -453,11 +527,10 @@ class TypeBuilder {
}
const MemberPointerType *getMemberPointerType(bool IsFunctionPointer,
- bool Has64BitPointers,
uint64_t SizeInBits,
Align Align) {
- return new (Allocator.Allocate<MemberPointerType>()) MemberPointerType(
- IsFunctionPointer, Has64BitPointers, SizeInBits, Align);
+ return new (Allocator.Allocate<MemberPointerType>())
+ MemberPointerType(IsFunctionPointer, SizeInBits, Align);
}
};
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index ce68a6783832d..2992484c47d06 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -33,7 +33,6 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TrailingObjects.h"
#include "llvm/Support/TypeSize.h"
-#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <string>
diff --git a/llvm/lib/ABI/ABIInfo.cpp b/llvm/lib/ABI/ABIInfo.cpp
index 2666f0f51f82d..85607c6cfe583 100644
--- a/llvm/lib/ABI/ABIInfo.cpp
+++ b/llvm/lib/ABI/ABIInfo.cpp
@@ -1,4 +1,5 @@
#include "llvm/ABI/ABIInfo.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm::abi;
bool ABIInfo::isAggregateTypeForABI(const Type *Ty) const {
@@ -21,23 +22,39 @@ bool ABIInfo::isPromotableIntegerType(const IntegerType *Ty) const {
}
// Create indirect return with natural alignment
-ABIArgInfo ABIInfo::getNaturalAlignIndirect(const Type *Ty) const {
- return ABIArgInfo::getIndirect(Ty->getAlignment().value(), /*ByVal=*/true);
+ABIArgInfo ABIInfo::getNaturalAlignIndirect(const Type *Ty, bool ByVal) const {
+ return ABIArgInfo::getIndirect(Ty->getAlignment().value(), ByVal);
}
RecordArgABI ABIInfo::getRecordArgABI(const StructType *ST) const {
- if (!ST->canPassInRegisters())
+ if (ST && !ST->canPassInRegisters())
return RAA_Indirect;
return RAA_Default;
}
+RecordArgABI ABIInfo::getRecordArgABI(const StructType *ST,
+ bool IsCxxRecord) const {
+ if (!IsCxxRecord) {
+ if (!ST->canPassInRegisters())
+ return RAA_Indirect;
+ return RAA_Default;
+ }
+ return getRecordArgABI(ST);
+}
+
+RecordArgABI ABIInfo::getRecordArgABI(const Type *Ty) const {
+ const StructType *ST = dyn_cast<StructType>(Ty);
+ if (!ST)
+ return RAA_Default;
+ return getRecordArgABI(ST, ST->isCXXRecord());
+}
+
bool ABIInfo::isZeroSizedType(const Type *Ty) const {
return Ty->getSizeInBits().getFixedValue() == 0;
}
bool ABIInfo::isEmptyRecord(const StructType *ST) const {
- if (ST->hasFlexibleArrayMember() ||
- ST->isPolymorphic() ||
- ST->getNumVirtualBaseClasses() != 0)
+ if (ST->hasFlexibleArrayMember() || ST->isPolymorphic() ||
+ ST->getNumVirtualBaseClasses() != 0)
return false;
for (unsigned I = 0; I < ST->getNumBaseClasses(); ++I) {
@@ -61,8 +78,7 @@ bool ABIInfo::isEmptyRecord(const StructType *ST) const {
return true;
}
-
-bool ABIInfo::isEmptyField(const FieldInfo &FI) const {
+bool ABIInfo::isEmptyField(const FieldInfo &FI) const {
if (FI.IsUnnamedBitfield)
return true;
if (FI.IsBitField && FI.BitFieldWidth == 0)
diff --git a/llvm/lib/ABI/ABITypeMapper.cpp b/llvm/lib/ABI/ABITypeMapper.cpp
index 3e0da55fc6d79..d88823bb47ea0 100644
--- a/llvm/lib/ABI/ABITypeMapper.cpp
+++ b/llvm/lib/ABI/ABITypeMapper.cpp
@@ -16,6 +16,7 @@
#include "llvm/ABI/ABITypeMapper.h"
#include "llvm/ABI/Types.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/bit.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
@@ -35,10 +36,21 @@ Type *ABITypeMapper::convertType(const abi::Type *ABIType) {
Type *Result = nullptr;
switch (ABIType->getKind()) {
- case abi::TypeKind::Integer:
- Result = IntegerType::get(Context,
- cast<abi::IntegerType>(ABIType)->getSizeInBits());
+ case abi::TypeKind::Integer: {
+ const auto *IT = cast<abi::IntegerType>(ABIType);
+ unsigned Bitwidth = IT->getSizeInBits().getFixedValue();
+
+ if (IT->needsMemoryRep()) {
+ if (Bitwidth <= 8) {
+ Bitwidth = 8;
+ } else {
+ Bitwidth = bit_ceil(Bitwidth);
+ }
+ }
+
+ Result = IntegerType::get(Context, Bitwidth);
break;
+ }
case abi::TypeKind::Float:
Result = convertFloatType(cast<abi::FloatType>(ABIType));
break;
@@ -55,9 +67,6 @@ Type *ABITypeMapper::convertType(const abi::Type *ABIType) {
case abi::TypeKind::Struct:
Result = convertStructType(cast<abi::StructType>(ABIType));
break;
- case abi::TypeKind::Union:
- Result = convertUnionType(cast<abi::UnionType>(ABIType));
- break;
case abi::TypeKind::Void:
Result = Type::getVoidTy(Context);
break;
@@ -87,6 +96,8 @@ Type *ABITypeMapper::convertArrayType(const abi::ArrayType *AT) {
return nullptr;
uint64_t NumElements = AT->getNumElements();
+ if (AT->isMatrixType())
+ return VectorType::get(ElementType, ElementCount::getFixed(NumElements));
return ArrayType::get(ElementType, NumElements);
}
@@ -104,15 +115,10 @@ Type *ABITypeMapper::convertVectorType(const abi::VectorType *VT) {
}
Type *ABITypeMapper::convertStructType(const abi::StructType *ST) {
- ArrayRef<abi::FieldInfo> FieldsArray(ST->getFields(), ST->getNumFields());
+ ArrayRef<abi::FieldInfo> FieldsArray = ST->getFields();
return createStructFromFields(FieldsArray, ST->getNumFields(),
- ST->getSizeInBits(), ST->getAlignment(), false,
- ST->isCoercedStruct());
-}
-
-Type *ABITypeMapper::convertUnionType(const abi::UnionType *UT) {
- return createStructFromFields(*UT->getFields(), UT->getNumFields(),
- UT->getSizeInBits(), UT->getAlignment(), true);
+ ST->getSizeInBits(), ST->getAlignment(),
+ ST->isUnion(), ST->isCoercedStruct());
}
Type *ABITypeMapper::convertComplexType(const abi::ComplexType *CT) {
@@ -120,13 +126,6 @@ Type *ABITypeMapper::convertComplexType(const abi::ComplexType *CT) {
Type *ElementType = convertType(CT->getElementType());
if (!ElementType)
return nullptr;
- // // Check if the element type is a float type and is 16 bits (half
- // precision)
- // if (ElementType->isFloatingPointTy() &&
- // ElementType->getPrimitiveSizeInBits() == 2 /* bytes */ * 8) {
- // // Return <2 x half> vector type for complex half
- // return VectorType::get(ElementType, ElementCount::getFixed(2));
- // }
SmallVector<Type *, 2> Fields = {ElementType, ElementType};
return StructType::get(Context, Fields, /*isPacked=*/false);
@@ -135,26 +134,23 @@ Type *ABITypeMapper::convertComplexType(const abi::ComplexType *CT) {
Type *
ABITypeMapper::convertMemberPointerType(const abi::MemberPointerType *MPT) {
+ bool Has64BitPointers = DL.getPointerSizeInBits() == 64;
if (MPT->isFunctionPointer()) {
- if (MPT->has64BitPointers()) {
+
+ if (Has64BitPointers) {
// {i64, i64} for function pointer + adjustment
Type *I64 = IntegerType::get(Context, 64);
SmallVector<Type *, 2> Fields = {I64, I64};
return StructType::get(Context, Fields, /*isPacked=*/false);
- } else {
- // {i32, i32} for 32-bit systems
+ } // {i32, i32} for 32-bit systems
Type *I32 = IntegerType::get(Context, 32);
SmallVector<Type *, 2> Fields = {I32, I32};
return StructType::get(Context, Fields, /*isPacked=*/false);
- }
- } else {
- // Data member pointer - single offset value
- if (MPT->has64BitPointers()) {
- return IntegerType::get(Context, 64);
- } else {
- return IntegerType::get(Context, 32);
- }
- }
+
+ } // Data member pointer - single offset value
+ if (Has64BitPointers)
+ return IntegerType::get(Context, 64);
+ return IntegerType::get(Context, 32);
}
StructType *ABITypeMapper::createStructFromFields(
@@ -177,7 +173,7 @@ StructType *ABITypeMapper::createStructFromFields(
} else if (FieldType->isFloatingPointTy()) {
FieldSize = FieldType->getPrimitiveSizeInBits();
} else if (FieldType->isPointerTy()) {
- FieldSize = 64; // Assume 64-bit pointers
+ FieldSize = Field.FieldType->getSizeInBits();
}
if (FieldSize > LargestFieldSize) {
@@ -233,7 +229,7 @@ StructType *ABITypeMapper::createStructFromFields(
} else if (FieldType->isFloatingPointTy()) {
CurrentOffset += FieldType->getPrimitiveSizeInBits();
} else if (FieldType->isPointerTy()) {
- CurrentOffset += 64; // Assume 64-bit pointers
+ CurrentOffset += Field.FieldType->getSizeInBits();
} else {
CurrentOffset += 64; // Conservative estimate
}
diff --git a/llvm/lib/ABI/Targets/BPF.cpp b/llvm/lib/ABI/Targets/BPF.cpp
index bac18b04e0833..d7554d0187cc0 100644
--- a/llvm/lib/ABI/Targets/BPF.cpp
+++ b/llvm/lib/ABI/Targets/BPF.cpp
@@ -20,18 +20,13 @@ class BPFABIInfo : public ABIInfo {
TypeBuilder &TB;
bool isAggregateType(const Type *Ty) const {
- return Ty->isStruct() || Ty->isUnion() || Ty->isArray();
- }
-
- bool isPromotableIntegerType(const IntegerType *IntTy) const {
- auto BitWidth = IntTy->getSizeInBits().getFixedValue();
- return BitWidth > 0 && BitWidth < 32;
+ return Ty->isStruct() || Ty->isVector() || Ty->isArray();
}
public:
BPFABIInfo(TypeBuilder &TypeBuilder) : TB(TypeBuilder) {}
- ABIArgInfo classifyReturnType(const Type *RetTy) const override {
+ ABIArgInfo classifyReturnType(const Type *RetTy) const {
if (RetTy->isVoid())
return ABIArgInfo::getIgnore();
@@ -43,9 +38,8 @@ class BPFABIInfo : public ABIInfo {
}
if (const auto *IntTy = dyn_cast<IntegerType>(RetTy)) {
- if (IntTy->getSizeInBits().getFixedValue() > 128) {
+ if (IntTy->isBitInt() && IntTy->getSizeInBits().getFixedValue() > 128)
return ABIArgInfo::getIndirect(RetTy->getAlignment().value());
- }
}
return ABIArgInfo::getDirect();
@@ -74,20 +68,12 @@ class BPFABIInfo : public ABIInfo {
if (const auto *IntTy = dyn_cast<IntegerType>(ArgTy)) {
auto BitWidth = IntTy->getSizeInBits().getFixedValue();
- if (BitWidth > 128)
+ if (IntTy->isBitInt() && BitWidth > 128)
return ABIArgInfo::getIndirect(ArgTy->getAlignment().value());
- if (isPromotableIntegerType(IntTy)) {
- const Type *PromotedTy =
- TB.getIntegerType(32, Align(4), IntTy->isSigned());
- auto AI = ABIArgInfo::getExtend(PromotedTy);
-
- IntTy->isSigned() ? AI.setSignExt() : AI.setZeroExt();
-
- return AI;
- }
+ if (IntTy->isPromotableIntegerType())
+ return ABIArgInfo::getExtend(ArgTy);
}
-
return ABIArgInfo::getDirect();
}
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index 949a2338e2293..4c6848018bb02 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -20,7 +20,9 @@
#include "llvm/Support/TypeSize.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
+#include <algorithm>
#include <cassert>
+#include <cmath>
#include <cstdint>
namespace llvm {
@@ -64,22 +66,15 @@ class X86_64ABIInfo : public ABIInfo {
void classify(const Type *T, uint64_t OffsetBase, Class &Lo, Class &Hi,
bool IsNamedArg, bool IsRegCall = false) const;
- // llvm::Type *getSseTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
- // const Type *SourceTy,
- // unsigned SourceOffset) const;
-
const Type *getIntegerTypeAtOffset(const Type *IRType, unsigned IROffset,
const Type *SourceTy,
unsigned SourceOffset) const;
- // llvm::Type *getIntegerTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
- // const Type *SourceTy,
- // unsigned SourceOffset) const;
- // Type *getIntegerTypeForClass(const Type *OriginalType,
- // uint64_t OffsetInBytes) const;
const Type *getSSETypeAtOffset(const Type *ABIType, unsigned ABIOffset,
const Type *SourceTy,
unsigned SourceOffset) const;
+ bool isIllegalVectorType(const Type *Ty) const;
+ bool containsMatrixField(const StructType *ST) const;
void computeInfo(ABIFunctionInfo &FI) const override;
ABIArgInfo getIndirectReturnResult(const Type *Ty) const;
@@ -91,46 +86,14 @@ class X86_64ABIInfo : public ABIInfo {
const Type *createPairType(const Type *Lo, const Type *Hi) const;
ABIArgInfo getIndirectResult(const Type *Ty, unsigned FreeIntRegs) const;
- ABIArgInfo classifyReturnType(const Type *RetTy) const override;
+ ABIArgInfo classifyReturnType(const Type *RetTy) const;
const char *getClassName(Class C) const;
- // ABIArgInfo classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
- // unsigned &NeededInt, unsigned &NeededSse,
- // bool IsNamedArg,
- // bool IsRegCall = false) const;
-
- // ABIArgInfo classifyRegCallStructType(const Type *Ty, unsigned &NeededInt,
- // unsigned &NeededSSE,
- // unsigned &MaxVectorWidth) const;
- //
- // ABIArgInfo classifyRegCallStructTypeImpl(const Type *Ty, unsigned
- // &NeededInt,
- // unsigned &NeededSSE,
- // unsigned &MaxVectorWidth) const;
- //
- // bool isIllegalVectorType(const Type *Ty) const;
-
- // The Functionality of these methods will be moved to
- // llvm::abi::ABICompatInfo
-
- // bool honorsRevision98() const { return !TargetTriple.isOSDarwin(); }
- //
- // bool classifyIntegerMMXAsSSE() const {
- // if (TargetTriple.isOSDarwin() || TargetTriple.isPS() ||
- // TargetTriple.isOSFreeBSD())
- // return false;
- // return true;
- // }
- //
- // bool passInt128VectorsInMem() const {
- // // TODO: accept ABICompat info from the frontends
- // return TargetTriple.isOSLinux() || TargetTriple.isOSNetBSD();
- // }
- //
- // bool returnCXXRecordGreaterThan128InMem() const {
- // // TODO: accept ABICompat info from the frontends
- // return true;
- // }
+ ABIArgInfo classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
+ unsigned &NeededInt, unsigned &NeededSse,
+ bool IsNamedArg,
+ bool IsRegCall = false) const;
+ const Type *useFirstFieldIfTransparentUnion(const Type *Ty) const;
public:
X86_64ABIInfo(TypeBuilder &TypeBuilder, const Triple &Triple,
@@ -139,21 +102,6 @@ class X86_64ABIInfo : public ABIInfo {
: ABIInfo(Compat), TB(TypeBuilder), AVXLevel(AVXABILevel),
Has64BitPointers(Has64BitPtrs), TargetTriple(Triple) {}
- // bool isPassedUsingAVXType(const Type *Type) const {
- // unsigned NeededInt, NeededSse;
- // ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse,
- // /*IsNamedArg=*/true);
- //
- // if (Info.isDirect()) {
- // auto *Ty = Info.getCoerceToType();
- // if (auto *VectorTy = dyn_cast_or_null<VectorType>(Ty))
- // return VectorTy->getSizeInBits().getFixedValue() > 128;
- // }
- // return false;
- // }
-
- // void computeInfo(ABIFunctionInfo &FI) const override;
-
bool has64BitPointers() const { return Has64BitPointers; }
};
@@ -184,7 +132,7 @@ void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo,
Lo = Memory;
if (Hi == X87UP && Lo != X87 && getABICompatInfo().Flags.HonorsRevision98)
Lo = Memory;
- if (AggregateSize > 128 && (Lo != SSE && Hi != SSEUp))
+ if (AggregateSize > 128 && (Lo != SSE || Hi != SSEUp))
Lo = Memory;
if (Hi == SSEUp && Lo != SSE)
Hi = SSE;
@@ -230,6 +178,20 @@ X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
return SSE;
}
+
+bool X86_64ABIInfo::containsMatrixField(const StructType *ST) const {
+ for (const auto &Field : ST->getFields()) {
+ const Type *FieldType = Field.FieldType;
+
+ if (const auto *AT = dyn_cast<ArrayType>(FieldType))
+ return AT->isMatrixType();
+
+ if (const auto *NestedST = dyn_cast<StructType>(FieldType))
+ return containsMatrixField(NestedST);
+ }
+ return false;
+}
+
void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
Class &Hi, bool IsNamedArg, bool IsRegCall) const {
Lo = Hi = NoClass;
@@ -268,9 +230,8 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
} else if (FltSem == &llvm::APFloat::x87DoubleExtended()) {
Lo = X87;
Hi = X87UP;
- } else {
+ } else
Current = SSE;
- }
return;
}
if (T->isPointer()) {
@@ -280,20 +241,18 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
if (const auto *MPT = dyn_cast<MemberPointerType>(T)) {
if (MPT->isFunctionPointer()) {
- if (MPT->has64BitPointers()) {
+ if (Has64BitPointers) {
Lo = Hi = Integer;
} else {
uint64_t EB_FuncPtr = OffsetBase / 64;
uint64_t EB_ThisAdj = (OffsetBase + 64 - 1) / 64;
if (EB_FuncPtr != EB_ThisAdj) {
Lo = Hi = Integer;
- } else {
+ } else
Current = Integer;
- }
}
- } else {
+ } else
Current = Integer;
- }
return;
}
@@ -328,10 +287,10 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
if (!getABICompatInfo().Flags.ClassifyIntegerMMXAsSSE &&
(ElemBits == 64 || ElemBits == 32)) {
Current = Integer;
- } else {
+ } else
Current = SSE;
- }
- }
+ } else
+ Current = SSE;
// If this type crosses an eightbyte boundary, it should be
// split.
if (OffsetBase && OffsetBase != 64)
@@ -437,6 +396,10 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
if (const auto *ST = dyn_cast<StructType>(T)) {
uint64_t Size = ST->getSizeInBits().getFixedValue();
+ if (containsMatrixField(ST)) {
+ Lo = Memory;
+ return;
+ }
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
// than eight eightbytes, ..., it has class MEMORY.
@@ -446,22 +409,19 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
// AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
// copy constructor or a non-trivial destructor, it is passed by invisible
// reference.
- if (ST->isCXXRecord() && (getRecordArgABI(ST))) {
+ if (getRecordArgABI(ST, ST->isCXXRecord()))
return;
- }
// Assume variable sized types are passed in memory.
- if (ST->hasFlexibleArrayMember()) {
+ if (ST->hasFlexibleArrayMember())
return;
- }
+
// Reset Lo class, this will be recomputed.
Current = NoClass;
// If this is a C++ record, classify the bases first.
if (ST->isCXXRecord()) {
- const FieldInfo *BaseClasses = ST->getBaseClasses();
- for (uint32_t I = 0; I < ST->getNumBaseClasses(); ++I) {
- const FieldInfo &Base = BaseClasses[I];
+ for (const auto &Base : ST->getBaseClasses()) {
// Classify this field.
//
@@ -491,29 +451,33 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
}
// Classify the fields one at a time, merging the results.
- const FieldInfo *Fields = ST->getFields();
- uint32_t NumFields = ST->getNumFields();
- for (uint32_t I = 0; I < NumFields; ++I) {
- const FieldInfo &Field = Fields[I];
+ bool IsUnion = ST->isUnion() && !getABICompatInfo().Flags.Clang11Compat;
+ auto Fields = ST->isUnion() && ST->hasMetadata()
+ ? ST->getMetadata<UnionMetadata>()->getFields()
+ : ST->getFields();
+ for (const auto &Field : Fields) {
uint64_t Offset = OffsetBase + Field.OffsetInBits;
bool BitField = Field.IsBitField;
- if (BitField && Field.IsUnnamedBitfield)
- continue;
+ if (BitField && Field.IsUnnamedBitfield)
+ continue;
- if (Size > 128 && (Size > getNativeVectorSizeForAVXABI(AVXLevel))) {
+ if (Size > 128 &&
+ ((!IsUnion &&
+ Size != Field.FieldType->getSizeInBits().getFixedValue()) ||
+ Size > getNativeVectorSizeForAVXABI(AVXLevel))) {
Lo = Memory;
postMerge(Size, Lo, Hi);
return;
}
- bool IsInMemory = Offset % (Field.FieldType->getAlignment().value() * 8);
+ bool IsInMemory = Offset % (Field.FieldType->getAlignment().value() * 8);
if (!BitField && IsInMemory) {
- Lo = Memory;
- postMerge(Size, Lo, Hi);
- return;
- }
+ Lo = Memory;
+ postMerge(Size, Lo, Hi);
+ return;
+ }
Class FieldLo, FieldHi;
@@ -530,9 +494,8 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
FieldLo = Integer;
FieldHi = EB_Hi ? Integer : NoClass;
}
- } else {
+ } else
classify(Field.FieldType, Offset, FieldLo, FieldHi, IsNamedArg);
- }
Lo = merge(Lo, FieldLo);
Hi = merge(Hi, FieldHi);
@@ -542,35 +505,149 @@ void X86_64ABIInfo::classify(const Type *T, uint64_t OffsetBase, Class &Lo,
postMerge(Size, Lo, Hi);
return;
}
- if (const auto *UT = dyn_cast<UnionType>(T)) {
- uint64_t Size = UT->getSizeInBits().getFixedValue();
- if (Size > 512)
- return;
+ Lo = Memory;
+ Hi = NoClass;
+}
- Current = NoClass;
+const Type *
+X86_64ABIInfo::useFirstFieldIfTransparentUnion(const Type *Ty) const {
+ if (const auto *ST = dyn_cast<StructType>(Ty)) {
+ if (ST->isUnion() && ST->isTransparentUnion()) {
+ auto Fields = ST->getFields();
+ if (ST->hasMetadata())
+ Fields = ST->getMetadata<UnionMetadata>()->getFields();
+ assert(!Fields.empty() && "sema created an empty transparent union");
+ return Fields.front().FieldType;
+ }
+ }
+ return Ty;
+}
- const FieldInfo *Fields = UT->getFields();
- uint32_t NumFields = UT->getNumFields();
+ABIArgInfo
+X86_64ABIInfo::classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
+ unsigned &NeededInt, unsigned &NeededSSE,
+ bool IsNamedArg, bool IsRegCall) const {
- for (uint32_t I = 0; I < NumFields; ++I) {
- const FieldInfo &Field = Fields[I];
- uint64_t Offset = OffsetBase;
+ Ty = useFirstFieldIfTransparentUnion(Ty);
- Class FieldLo, FieldHi;
- classify(Field.FieldType, Offset, FieldLo, FieldHi, IsNamedArg);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory)
- break;
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(Ty, 0, Lo, Hi, IsNamedArg, IsRegCall);
+
+ // Check some invariants
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ NeededInt = 0;
+ NeededSSE = 0;
+ const Type *ResType = nullptr;
+
+ switch (Lo) {
+ case NoClass:
+ if (Hi == NoClass)
+ return ABIArgInfo::getIgnore();
+ // If the low part is just padding, it takes no register, leave ResType
+ // null.
+ assert((Hi == SSE || Hi == Integer || Hi == X87UP) &&
+ "Unknown missing lo part");
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument
+ // on the stack.
+ case Memory:
+ // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or
+ // COMPLEX_X87, it is passed in memory.
+ case X87:
+ case Complex_X87:
+ if (getRecordArgABI(dyn_cast<StructType>(Ty)) == RAA_Indirect)
+ ++NeededInt;
+ return getIndirectResult(Ty, FreeIntRegs);
+
+ case SSEUp:
+ case X87UP:
+ llvm_unreachable("Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next
+ // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
+ // and %r9 is used.
+ case Integer:
+ ++NeededInt;
+
+ // Pick an 8-byte type based on the preferred type.
+ ResType = getIntegerTypeAtOffset(Ty, 0, Ty, 0);
+
+ // If we have a sign or zero extended integer, make sure to return Extend
+ // so that the parameter gets the right LLVM IR attributes.
+ if (Hi == NoClass && ResType->isInteger()) {
+ if (Ty->isInteger() && cast<IntegerType>(Ty)->isPromotableIntegerType())
+ return ABIArgInfo::getExtend(Ty);
}
- postMerge(Size, Lo, Hi);
- return;
+ if (ResType->isInteger() && ResType->getSizeInBits() == 128) {
+ assert(Hi == Integer);
+ ++NeededInt;
+ return ABIArgInfo::getDirect(ResType);
+ }
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
+ // available SSE register is used, the registers are taken in the
+ // order from %xmm0 to %xmm7.
+ case SSE:
+ ResType = getSSETypeAtOffset(Ty, 0, Ty, 0);
+ ++NeededSSE;
+ break;
}
- Lo = Memory;
- Hi = NoClass;
+ const Type *HighPart = nullptr;
+ switch (Hi) {
+ // Memory was handled previously, Complex_X87 and X87 should
+ // never occur as hi classes, and X87UP must be preceded by X87,
+ // which is passed in memory.
+ case Memory:
+ case X87:
+ case Complex_X87:
+ llvm_unreachable("Invalid classification for hi word.");
+
+ case NoClass:
+ break;
+
+ case Integer:
+ ++NeededInt;
+ // Pick an 8-byte type based on the preferred type.
+ HighPart = getIntegerTypeAtOffset(Ty, 8, Ty, 8);
+
+ if (Lo == NoClass) // Pass HighPart at offset 8 in memory.
+ return ABIArgInfo::getDirect(HighPart, 8);
+ break;
+
+ // X87UP generally doesn't occur here (long double is passed in
+ // memory), except in situations involving unions.
+ case X87UP:
+ case SSE:
+ ++NeededSSE;
+ HighPart = getSSETypeAtOffset(Ty, 8, Ty, 8);
+
+ if (Lo == NoClass) // Pass HighPart at offset 8 in memory.
+ return ABIArgInfo::getDirect(HighPart, 8);
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the
+ // eightbyte is passed in the upper half of the last used SSE
+ // register. This only happens when 128-bit vectors are passed.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification");
+ ResType = getByteVectorType(Ty);
+ break;
+ }
+
+ // If a high part was specified, merge it together with the low part. It is
+ // known to pass in the high eightbyte of the result. We do this by forming a
+ // first class struct aggregate with the high and low part: {low, high}
+ if (HighPart)
+ ResType = createPairType(ResType, HighPart);
+
+ return ABIArgInfo::getDirect(ResType);
}
ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
@@ -607,19 +684,11 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(const Type *RetTy) const {
// available register of the sequence %rax, %rdx is used.
case Integer:
ResType = getIntegerTypeAtOffset(RetTy, 0, RetTy, 0);
- if (const auto *IT = dyn_cast<IntegerType>(ResType)) {
- if (IT->isBool() && RetTy->isInteger() &&
- cast<IntegerType>(RetTy)->isBool()) {
- // Convert boolean to i1 for LLVM IR
- ResType = TB.getIntegerType(1, IT->getAlignment(), false, true);
- return ABIArgInfo::getExtend(ResType);
- }
- }
// If we have a sign or zero extended integer, make sure to return Extend
// so that the parameter gets the right LLVM IR attributes.
if (Hi == NoClass && ResType->isInteger()) {
if (const IntegerType *IntTy = dyn_cast<IntegerType>(RetTy)) {
- if (IntTy && isPromotableIntegerType(IntTy)) {
+ if (IntTy->isPromotableIntegerType()) {
ABIArgInfo Info = ABIArgInfo::getExtend(RetTy);
return Info;
}
@@ -750,17 +819,15 @@ const Type *X86_64ABIInfo::createPairType(const Type *Lo,
const FloatType *FT = cast<FloatType>(Lo);
if (FT->getSemantics() == &APFloat::IEEEhalf() ||
FT->getSemantics() == &APFloat::IEEEsingle() ||
- FT->getSemantics() == &APFloat::BFloat()) {
+ FT->getSemantics() == &APFloat::BFloat())
AdjustedLo = TB.getFloatType(APFloat::IEEEdouble(), Align(8));
- }
}
// Promote integers and pointers to i64
- else if (Lo->isInteger() || Lo->isPointer()) {
+ else if (Lo->isInteger() || Lo->isPointer())
AdjustedLo = TB.getIntegerType(64, Align(8), /*Signed=*/false);
- } else {
+ else
assert((Lo->isInteger() || Lo->isPointer()) &&
"Invalid/unknown low type in pair");
- }
unsigned AdjustedLoSize = AdjustedLo->getSizeInBits().getFixedValue() / 8;
HiStart = alignTo(AdjustedLoSize, HiAlign);
}
@@ -796,7 +863,7 @@ static bool bitsContainNoUserData(const Type *Ty, unsigned StartBit,
for (unsigned I = 0; I < AT->getNumElements(); ++I) {
unsigned EltOffset = I * EltSize;
if (EltOffset >= EndBit)
- break; // Elements are sorted by offset
+ break;
unsigned EltStart = (EltOffset < StartBit) ? StartBit - EltOffset : 0;
if (!bitsContainNoUserData(EltTy, EltStart, EndBit - EltOffset))
@@ -807,6 +874,38 @@ static bool bitsContainNoUserData(const Type *Ty, unsigned StartBit,
// Handle structs - check all fields and base classes
if (const StructType *ST = dyn_cast<StructType>(Ty)) {
+ if (ST->isUnion() && ST->hasMetadata()) {
+ if (const auto *UnionMeta = ST->getMetadata<UnionMetadata>()) {
+ // Handle union using original fields from metadata
+ for (const auto &Field : UnionMeta->getFields()) {
+ if (Field.IsUnnamedBitfield)
+ continue;
+
+ unsigned FieldStart = (Field.OffsetInBits < StartBit)
+ ? StartBit - Field.OffsetInBits
+ : 0;
+ unsigned FieldEnd =
+ FieldStart + Field.FieldType->getSizeInBits().getFixedValue();
+
+ // Check if field overlaps with the queried range
+ if (FieldStart < EndBit && FieldEnd > StartBit) {
+ // There's an overlap, so there is user data
+ unsigned RelativeStart =
+ (StartBit > FieldStart) ? StartBit - FieldStart : 0;
+ unsigned RelativeEnd =
+ (EndBit < FieldEnd)
+ ? EndBit - FieldStart
+ : Field.FieldType->getSizeInBits().getFixedValue();
+
+ if (!bitsContainNoUserData(Field.FieldType, RelativeStart,
+ RelativeEnd)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
// Check base classes first (for C++ records)
if (ST->isCXXRecord()) {
for (unsigned I = 0; I < ST->getNumBaseClasses(); ++I) {
@@ -822,11 +921,10 @@ static bool bitsContainNoUserData(const Type *Ty, unsigned StartBit,
}
}
- // Check all fields
for (unsigned I = 0; I < ST->getNumFields(); ++I) {
const FieldInfo &Field = ST->getFields()[I];
if (Field.OffsetInBits >= EndBit)
- break; // Fields are sorted by offset
+ break;
unsigned FieldStart =
(Field.OffsetInBits < StartBit) ? StartBit - Field.OffsetInBits : 0;
@@ -846,120 +944,98 @@ const Type *X86_64ABIInfo::getIntegerTypeAtOffset(const Type *ABIType,
const Type *SourceTy,
unsigned SourceOffset) const {
// If we're dealing with an un-offset ABI type, then it means that we're
- // returning an 8-byte unit starting with it. See if we can safely use it.
+ // returning an 8-byte unit starting with it. See if we can safely use it.
if (ABIOffset == 0) {
- // Pointers and 64-bit integers fill the 8-byte unit
+ // Pointers and int64's always fill the 8-byte unit.
if ((ABIType->isPointer() && Has64BitPointers) ||
(ABIType->isInteger() &&
- cast<IntegerType>(ABIType)->getSizeInBits() == 64)){
+ cast<IntegerType>(ABIType)->getSizeInBits() == 64))
return ABIType;
- }
// If we have a 1/2/4-byte integer, we can use it only if the rest of the
- // goodness in the source type is just tail padding. This is allowed to
+ // goodness in the source type is just tail padding. This is allowed to
// kick in for struct {double,int} on the int, but not on
- // struct{double,int,int} because we wouldn't return the second int. We
+ // struct{double,int,int} because we wouldn't return the second int. We
// have to do this analysis on the source type because we can't depend on
// unions being lowered a specific way etc.
- if (ABIType->isInteger()) {
- unsigned BitWidth = cast<IntegerType>(ABIType)->getSizeInBits();
- if (BitWidth == 8 || BitWidth == 16 || BitWidth == 32) {
- // Check if the rest is just padding
- if (bitsContainNoUserData(SourceTy, SourceOffset * 8 + BitWidth,
- SourceOffset * 8 + 64))
- return ABIType;
- }
- } else if (ABIType->isPointer() && !Has64BitPointers) {
- // Check if the rest is just padding
- if (bitsContainNoUserData(SourceTy, SourceOffset * 8 + 32,
+ if ((ABIType->isInteger() &&
+ (cast<IntegerType>(ABIType)->getSizeInBits() == 1 ||
+ cast<IntegerType>(ABIType)->getSizeInBits() == 8 ||
+ cast<IntegerType>(ABIType)->getSizeInBits() == 16 ||
+ cast<IntegerType>(ABIType)->getSizeInBits() == 32)) ||
+ (ABIType->isPointer() && !Has64BitPointers)) {
+
+ unsigned BitWidth = ABIType->isPointer()
+ ? 32
+ : cast<IntegerType>(ABIType)->getSizeInBits();
+
+ if (bitsContainNoUserData(SourceTy, SourceOffset * 8 + BitWidth,
SourceOffset * 8 + 64))
return ABIType;
}
}
- // Handle structs by recursing into fields
- if (auto *STy = dyn_cast<StructType>(ABIType)) {
- const FieldInfo *Fields = STy->getFields();
-
- // Find field containing the IROffset
- for (unsigned I = 0; I < STy->getNumFields(); ++I) {
- const FieldInfo &Field = Fields[I];
- unsigned FieldOffsetBytes = Field.OffsetInBits / 8;
- unsigned FieldSizeBytes = Field.FieldType->getSizeInBits() / 8;
-
- // Check if IROffset falls within this field
- if (ABIOffset >= FieldOffsetBytes &&
- ABIOffset < FieldOffsetBytes + FieldSizeBytes) {
- return getIntegerTypeAtOffset(Field.FieldType,
- ABIOffset - FieldOffsetBytes, SourceTy,
- SourceOffset);
- }
+ if (const auto *STy = dyn_cast<StructType>(ABIType)) {
+ if (const FieldInfo *Element =
+ STy->getElementContainingOffset(ABIOffset * 8)) {
+
+ unsigned ElementOffsetBytes = Element->OffsetInBits / 8;
+ return getIntegerTypeAtOffset(Element->FieldType,
+ ABIOffset - ElementOffsetBytes, SourceTy,
+ SourceOffset);
}
}
- // Handle arrays
- if (auto *ATy = dyn_cast<ArrayType>(ABIType)) {
+ if (const auto *ATy = dyn_cast<ArrayType>(ABIType)) {
const Type *EltTy = ATy->getElementType();
unsigned EltSize = EltTy->getSizeInBits() / 8;
- if (EltSize > 0) { // Avoid division by zero
+ if (EltSize > 0) {
unsigned EltOffset = (ABIOffset / EltSize) * EltSize;
return getIntegerTypeAtOffset(EltTy, ABIOffset - EltOffset, SourceTy,
SourceOffset);
}
}
- if (ABIType->isInteger() && ABIType->getSizeInBits().getFixedValue() == 128) {
+ // If we have a 128-bit integer, we can pass it safely using an i128
+ // so we return that
+ if (ABIType->isInteger() && ABIType->getSizeInBits() == 128) {
assert(ABIOffset == 0);
return ABIType;
}
- // Default case - use integer type that fits
unsigned TySizeInBytes =
- SourceTy->getSizeInBits().getFixedValue() / 8;
- if (auto *IT = dyn_cast<IntegerType>(SourceTy)){
- if (IT->isBitInt())
- TySizeInBytes = alignTo(SourceTy->getSizeInBits().getFixedValue(),64)/8;
+ llvm::divideCeil(SourceTy->getSizeInBits().getFixedValue(), 8);
+ if (auto *IT = dyn_cast<IntegerType>(SourceTy)) {
+ if (IT->isBitInt())
+ TySizeInBytes =
+ alignTo(SourceTy->getSizeInBits().getFixedValue(), 64) / 8;
}
assert(TySizeInBytes != SourceOffset && "Empty field?");
unsigned AvailableSize = TySizeInBytes - SourceOffset;
- return TB.getIntegerType(std::min(AvailableSize, 8U) * 8, Align(1),
- /*Signed=*/false);
+ return TB.getIntegerType(std::min(AvailableSize, 8U) * 8, Align(1), false);
}
/// Returns the floating point type at the specified offset within a type, or
/// nullptr if no floating point type is found at that offset.
const Type *X86_64ABIInfo::getFPTypeAtOffset(const Type *Ty,
unsigned Offset) const {
// Check for direct match at offset 0
- if (Offset == 0 && Ty->isFloat()) {
+ if (Offset == 0 && Ty->isFloat())
return Ty;
- }
if (const ComplexType *CT = dyn_cast<ComplexType>(Ty)) {
const Type *ElementType = CT->getElementType();
unsigned ElementSize = ElementType->getSizeInBits().getFixedValue() / 8;
- if (Offset == 0 || Offset == ElementSize) {
+ if (Offset == 0 || Offset == ElementSize)
return ElementType;
- }
return nullptr;
}
// Handle struct types by checking each field
if (const StructType *ST = dyn_cast<StructType>(Ty)) {
- if (!ST->getNumFields())
- return nullptr;
- const FieldInfo *Fields = ST->getFields();
-
- // Find the field containing the requested offset
- for (unsigned i = 0; i < ST->getNumFields(); ++i) {
- unsigned FieldOffset = Fields[i].OffsetInBits / 8;
- unsigned FieldSize =
- Fields[i].FieldType->getSizeInBits().getFixedValue() / 8;
-
- // Check if offset falls within this field
- if (Offset >= FieldOffset && Offset < FieldOffset + FieldSize) {
- return getFPTypeAtOffset(Fields[i].FieldType, Offset - FieldOffset);
- }
+ if (const FieldInfo *Element = ST->getElementContainingOffset(Offset * 8)) {
+ unsigned ElementOffsetBytes = Element->OffsetInBits / 8;
+ return getFPTypeAtOffset(Element->FieldType, Offset - ElementOffsetBytes);
}
}
@@ -1011,9 +1087,8 @@ const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
unsigned T0Size =
alignTo(T0->getSizeInBits().getFixedValue(), T0->getAlignment().value()) /
8;
- if (SourceSize > T0Size) {
+ if (SourceSize > T0Size)
T1 = getFPTypeAtOffset(ABIType, ABIOffset + T0Size);
- }
if (T1 == nullptr) {
if (Is16bitFpTy(T0) && SourceSize > 4)
@@ -1024,9 +1099,9 @@ const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
}
// Handle vector cases
if (isFloatTypeWithSemantics(T0, APFloat::IEEEsingle()) &&
- isFloatTypeWithSemantics(T1, APFloat::IEEEsingle())) {
+ isFloatTypeWithSemantics(T1, APFloat::IEEEsingle()))
return TB.getVectorType(T0, ElementCount::getFixed(2), Align(8));
- }
+
if (Is16bitFpTy(T0) && Is16bitFpTy(T1)) {
const Type *T2 = nullptr;
if (SourceSize > 4)
@@ -1037,10 +1112,9 @@ const Type *X86_64ABIInfo::getSSETypeAtOffset(const Type *ABIType,
}
// Mixed half-float cases
- if (Is16bitFpTy(T0) || Is16bitFpTy(T1)) {
+ if (Is16bitFpTy(T0) || Is16bitFpTy(T1))
return TB.getVectorType(TB.getFloatType(APFloat::IEEEhalf(), Align(2)),
ElementCount::getFixed(4), Align(8));
- }
// Default to double
return TB.getFloatType(APFloat::IEEEdouble(), Align(8));
@@ -1087,21 +1161,19 @@ const Type *X86_64ABIInfo::isSingleElementStruct(const Type *Ty) const {
if (!ST)
return nullptr;
- if (ST->isPolymorphic() ||
- ST->hasNonTrivialCopyConstructor() ||
- ST->hasNonTrivialDestructor() ||
- ST->hasFlexibleArrayMember() ||
- ST->getNumVirtualBaseClasses() != 0)
+ if (ST->isPolymorphic() || ST->hasNonTrivialCopyConstructor() ||
+ ST->hasNonTrivialDestructor() || ST->hasFlexibleArrayMember() ||
+ ST->getNumVirtualBaseClasses() != 0)
return nullptr;
const Type *Found = nullptr;
- for (unsigned I = 0; I < ST->getNumBaseClasses(); ++I) {
- const Type *BaseTy = ST->getBaseClasses()[I].FieldType;
+ for (const auto &Base : ST->getBaseClasses()) {
+ const Type *BaseTy = Base.FieldType;
auto *BaseST = dyn_cast<StructType>(BaseTy);
if (!BaseST || isEmptyRecord(BaseST))
- continue; // ignore empty bases
+ continue;
const Type *Elem = isSingleElementStruct(BaseTy);
if (!Elem || Found)
@@ -1109,8 +1181,10 @@ const Type *X86_64ABIInfo::isSingleElementStruct(const Type *Ty) const {
Found = Elem;
}
- for (unsigned I = 0; I < ST->getNumFields(); ++I) {
- const FieldInfo &FI = ST->getFields()[I];
+ auto Fields = ST->isUnion() && ST->hasMetadata()
+ ? ST->getMetadata<UnionMetadata>()->getFields()
+ : ST->getFields();
+ for (const auto &FI : Fields) {
if (isEmptyField(FI))
continue;
@@ -1126,20 +1200,102 @@ const Type *X86_64ABIInfo::isSingleElementStruct(const Type *Ty) const {
if (auto *InnerST = dyn_cast<StructType>(FTy))
Elem = isSingleElementStruct(InnerST);
else
- Elem = FTy;
+ Elem = FTy;
if (!Elem || Found)
return nullptr;
Found = Elem;
}
if (!Found)
- return nullptr;
+ return nullptr;
if (Found->getSizeInBits() != Ty->getSizeInBits())
return nullptr;
return Found;
}
+bool X86_64ABIInfo::isIllegalVectorType(const Type *Ty) const {
+ if (const auto *VecTy = dyn_cast<VectorType>(Ty)) {
+ uint64_t Size = VecTy->getSizeInBits().getFixedValue();
+ unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel);
+
+ // Vectors <= 64 bits or > largest supported vector size are illegal
+ if (Size <= 64 || Size > LargestVector)
+ return true;
+
+ // Check for 128-bit integer element vectors that should be passed in memory
+ const Type *EltTy = VecTy->getElementType();
+ if (getABICompatInfo().Flags.PassInt128VectorsInMem && EltTy->isInteger()) {
+ const auto *IntTy = cast<IntegerType>(EltTy);
+ if (IntTy->getSizeInBits().getFixedValue() == 128)
+ return true;
+ }
+ }
+ return false;
+}
+
+ABIArgInfo X86_64ABIInfo::getIndirectResult(const Type *Ty,
+ unsigned FreeIntRegs) const {
+ // If this is a scalar LLVM value then assume LLVM will pass it in the right
+ // place naturally.
+ //
+ // This assumption is optimistic, as there could be free registers available
+ // when we need to pass this argument in memory, and LLVM could try to pass
+ // the argument in the free register. This does not seem to happen currently,
+ // but this code would be much safer if we could mark the argument with
+ // 'onstack'. See PR12193.
+ if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty) &&
+ !(Ty->isInteger() && cast<IntegerType>(Ty)->isBitInt())) {
+ return (Ty->isInteger() && cast<IntegerType>(Ty)->isPromotableIntegerType()
+ ? ABIArgInfo::getExtend(Ty)
+ : ABIArgInfo::getDirect());
+ }
+
+ // Check if this is a record type that needs special handling
+ if (auto RecordRAA = getRecordArgABI(Ty))
+ return getNaturalAlignIndirect(Ty, RecordRAA ==
+ RecordArgABI::RAA_DirectInMemory);
+
+ // Compute the byval alignment. We specify the alignment of the byval in all
+ // cases so that the mid-level optimizer knows the alignment of the byval.
+ unsigned Align =
+ std::max(static_cast<unsigned>(Ty->getAlignment().value()), 8U);
+
+ // Attempt to avoid passing indirect results using byval when possible. This
+ // is important for good codegen.
+ //
+ // We do this by coercing the value into a scalar type which the backend can
+ // handle naturally (i.e., without using byval).
+ //
+ // For simplicity, we currently only do this when we have exhausted all of the
+ // free integer registers. Doing this when there are free integer registers
+ // would require more care, as we would have to ensure that the coerced value
+ // did not claim the unused register. That would require either reording the
+ // arguments to the function (so that any subsequent inreg values came first),
+ // or only doing this optimization when there were no following arguments that
+ // might be inreg.
+ //
+ // We currently expect it to be rare (particularly in well written code) for
+ // arguments to be passed on the stack when there are still free integer
+ // registers available (this would typically imply large structs being passed
+ // by value), so this seems like a fair tradeoff for now.
+ //
+ // We can revisit this if the backend grows support for 'onstack' parameter
+ // attributes. See PR12193.
+ if (FreeIntRegs == 0) {
+ uint64_t Size = Ty->getSizeInBits().getFixedValue();
+
+ // If this type fits in an eightbyte, coerce it into the matching integral
+ // type, which will end up on the stack (with alignment 8).
+ if (Align == 8 && Size <= 64) {
+ const Type *IntTy =
+ TB.getIntegerType(Size, llvm::Align(8), /*Signed=*/false);
+ return ABIArgInfo::getDirect(IntTy);
+ }
+ }
+
+ return ABIArgInfo::getIndirect(Align);
+}
ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
// If this is a scalar value, handle it specially
@@ -1147,12 +1303,12 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
// Handle integer types that need extension
if (Ty->isInteger()) {
const IntegerType *IntTy = cast<IntegerType>(Ty);
- if (isPromotableIntegerType(IntTy)) {
+ if (IntTy->isPromotableIntegerType()) {
ABIArgInfo Info = ABIArgInfo::getExtend(Ty);
return Info;
}
- if (IntTy->isBitInt())
- return getNaturalAlignIndirect(IntTy);
+ if (IntTy->isBitInt())
+ return getNaturalAlignIndirect(IntTy);
}
return ABIArgInfo::getDirect();
}
@@ -1161,9 +1317,77 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(const Type *Ty) const {
return getNaturalAlignIndirect(Ty);
}
+static bool classifyCXXReturnType(ABIFunctionInfo &FI, const ABIInfo &Info) {
+ const abi::Type *Ty = FI.getReturnType();
+
+ if (const auto *ST = llvm::dyn_cast<abi::StructType>(Ty)) {
+ if (!ST->isCXXRecord() && !ST->canPassInRegisters()) {
+ ABIArgInfo IndirectInfo =
+ ABIArgInfo::getIndirect(ST->getAlignment().value());
+ FI.getReturnInfo() = IndirectInfo;
+ return true;
+ }
+ if (!ST->canPassInRegisters()) {
+ ABIArgInfo IndirectInfo =
+ ABIArgInfo::getIndirect(Ty->getAlignment().value(), false, 0, false);
+ FI.getReturnInfo() = IndirectInfo;
+ return true;
+ }
+ }
+
+ return false;
+}
+
void X86_64ABIInfo::computeInfo(ABIFunctionInfo &FI) const {
- // TODO: Implement proper function info computation
+ CallingConv::ID CallingConv = FI.getCallingConvention();
+
+ if (CallingConv == CallingConv::Win64 ||
+ CallingConv == CallingConv::X86_RegCall)
+ return;
+
+ bool IsRegCall = false;
+
+ unsigned FreeIntRegs = 6;
+ unsigned FreeSSERegs = 8;
+ unsigned NeededInt = 0, NeededSSE = 0;
+
+ if (!classifyCXXReturnType(FI, *this)) {
+ const Type *RetTy = FI.getReturnType();
+ ABIArgInfo RetInfo = classifyReturnType(RetTy);
+ FI.getReturnInfo() = RetInfo;
+ }
+
+ if (FI.getReturnInfo().isIndirect())
+ --FreeIntRegs;
+
+ unsigned NumRequiredArgs = FI.getNumRequiredArgs();
+
+ unsigned ArgNo = 0;
+ for (auto IT = FI.arg_begin(), IE = FI.arg_end(); IT != IE; ++IT, ++ArgNo) {
+ bool IsNamedArg = ArgNo < NumRequiredArgs;
+ const Type *ArgTy = IT->ABIType;
+ NeededInt = 0;
+ NeededSSE = 0;
+
+ ABIArgInfo ArgInfo = classifyArgumentType(ArgTy, FreeIntRegs, NeededInt,
+ NeededSSE, IsNamedArg, IsRegCall);
+
+ // AMD64-ABI 3.2.3p3: If there are no registers available for any
+ // eightbyte of an argument, the whole argument is passed on the
+ // stack. If registers have already been assigned for some
+ // eightbytes of such an argument, the assignments get reverted.
+ if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) {
+ FreeIntRegs -= NeededInt;
+ FreeSSERegs -= NeededSSE;
+ IT->ArgInfo = ArgInfo;
+ } else {
+ // Not enough registers, pass on stack
+ ABIArgInfo IndirectInfo = getIndirectResult(ArgTy, FreeIntRegs);
+ IT->ArgInfo = IndirectInfo;
+ }
+ }
}
+
class X8664TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X8664TargetCodeGenInfo(TypeBuilder &TB, const Triple &Triple,
More information about the cfe-commits
mailing list