Skip to content

[WIP] Clang ABI Types #133080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft

[WIP] Clang ABI Types #133080

wants to merge 19 commits into from

Conversation

easyonaadit
Copy link
Contributor

@easyonaadit easyonaadit commented Mar 26, 2025

This is a prototype for introducing an ABI lowering library in LLVM.
Initial design is focused around the x86_64 SysV ABI specifications.
The major work currently involves supporting the ABI details
related to calling conventions.

This library will feature its own completely independent type system.
Frontends which want to support a C FFI's will have to map from their
AST types to the library type system, and provide the target triple,
and based on this the library will return ABIArgInfo, an object which
will have the function call coerced according to the ABI specifications.

This prototype currently supports the following:

  1. Independent type system: Builtin Types, Record Types
  2. Mapping code: from Clang AST types -> LLVMABI Types
  3. ABIFunctionInfo: Result to be returned from the library
  4. ABIArgInfo: Will hold the ABI coerced function parameters,
    will be a part of the result returned.
  5. Prototype function for computing the x86_64 SysV ABI specifications
  6. Dump methods for debugging

have annotated the code with some parts of understanding.
Copy link

github-actions bot commented Mar 26, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- llvm/lib/LLVMABI/ABICall.h llvm/lib/LLVMABI/ABIFunctionInfo.cpp llvm/lib/LLVMABI/ABIFunctionInfo.h llvm/lib/LLVMABI/Targets/x86.cpp llvm/lib/LLVMABI/Type.cpp llvm/lib/LLVMABI/Type.h clang/lib/CodeGen/CGCall.cpp
View the diff from clang-format here.
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7c950dc1d..13d9e0e16 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -11,8 +11,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/include/llvm/LLVMABI/Type.h"
-#include "llvm/include/llvm/LLVMABI/ABIFunctionInfo.h"
 #include "CGCall.h"
 #include "ABIInfo.h"
 #include "ABIInfoImpl.h"
@@ -44,6 +42,8 @@
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Type.h"
 #include "llvm/Transforms/Utils/Local.h"
+#include "llvm/include/llvm/LLVMABI/ABIFunctionInfo.h"
+#include "llvm/include/llvm/LLVMABI/Type.h"
 #include <optional>
 using namespace clang;
 using namespace CodeGen;
@@ -52,12 +52,13 @@ using namespace ABI;
 /***/
 ABIFunction::CallingConv ClangCallConvToABICallConv(CallingConv CC) {
   switch (CC) {
-  default: return ABIFunction::CallingConv::CC_C;
-  case CC_X86StdCall: return ABIFunction::CallingConv::CC_X86StdCall;
+  default:
+    return ABIFunction::CallingConv::CC_C;
+  case CC_X86StdCall:
+    return ABIFunction::CallingConv::CC_X86StdCall;
   }
 }
 
-
 unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
   switch (CC) {
   default: return llvm::CallingConv::C;
@@ -825,41 +826,43 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
 }
 }
 
-std::unique_ptr<ABI::Type> getABIType(QualType QT){
+std::unique_ptr<ABI::Type> getABIType(QualType QT) {
   const clang::Type *BaseType = QT.getTypePtr();
 
   switch (BaseType->getTypeClass()) {
-    case clang::Type::Builtin: {
-        // Cast to BuiltinType to access its kind
-        auto *BT = llvm::cast<clang::BuiltinType>(BaseType);
-
-        ABIBuiltinType::Kind ABIKind;
-        switch (BT->getKind()) {
-        case clang::BuiltinType::Void:
-            ABIKind = ABIBuiltinType::Void;
-            break;
-        case clang::BuiltinType::Bool:
-            ABIKind = ABIBuiltinType::Bool;
-            break;
-        case clang::BuiltinType::Int:
-            ABIKind = ABIBuiltinType::Integer;
-            break;
-        case clang::BuiltinType::UInt:
-            ABIKind = ABIBuiltinType::UInt128;
-            break;
-        case clang::BuiltinType::Float:
-            ABIKind = ABIBuiltinType::Float;
-            break;
-        default:
-            // TODO: support additional types
-            return std::make_unique<ABI::Type>(ABI::ABIBuiltinType(ABIBuiltinType::Void), 0);
-        }
-      auto *ABIType = new ABI::ABIBuiltinType(ABIKind);
-      return std::make_unique<ABI::Type>(ABIType, 0);
+  case clang::Type::Builtin: {
+    // Cast to BuiltinType to access its kind
+    auto *BT = llvm::cast<clang::BuiltinType>(BaseType);
+
+    ABIBuiltinType::Kind ABIKind;
+    switch (BT->getKind()) {
+    case clang::BuiltinType::Void:
+      ABIKind = ABIBuiltinType::Void;
+      break;
+    case clang::BuiltinType::Bool:
+      ABIKind = ABIBuiltinType::Bool;
+      break;
+    case clang::BuiltinType::Int:
+      ABIKind = ABIBuiltinType::Integer;
+      break;
+    case clang::BuiltinType::UInt:
+      ABIKind = ABIBuiltinType::UInt128;
+      break;
+    case clang::BuiltinType::Float:
+      ABIKind = ABIBuiltinType::Float;
+      break;
+    default:
+      // TODO: support additional types
+      return std::make_unique<ABI::Type>(
+          ABI::ABIBuiltinType(ABIBuiltinType::Void), 0);
     }
-    default :
-      // TODO: support additonal types
-      return std::make_unique<ABI::Type>(ABI::ABIBuiltinType(ABIBuiltinType::Void), 0);
+    auto *ABIType = new ABI::ABIBuiltinType(ABIKind);
+    return std::make_unique<ABI::Type>(ABIType, 0);
+  }
+  default:
+    // TODO: support additonal types
+    return std::make_unique<ABI::Type>(
+        ABI::ABIBuiltinType(ABIBuiltinType::Void), 0);
   }
 }
 
@@ -897,24 +900,27 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
   std::unique_ptr<ABI::Type> resultTypeABI = getABIType(resultType);
 
   std::vector<ABI::Type> abiTypes;
-  abiTypes.reserve(argTypes.size());  
+  abiTypes.reserve(argTypes.size());
 
   for (CanQualType &element : argTypes) {
-    abiTypes.push_back(*getABIType(element));  // Move unique_ptr into the vector
+    abiTypes.push_back(*getABIType(element)); // Move unique_ptr into the vector
   }
 
   // map the abi::Types -> abi::FunctionInfo type, done by the library
-  ABIFunction::ABIFunctionInfo *ABIFI = ABIFunction::ABIFunctionInfo::create(CC, abiTypes, *(resultTypeABI.get()));
+  ABIFunction::ABIFunctionInfo *ABIFI = ABIFunction::ABIFunctionInfo::create(
+      CC, abiTypes, *(resultTypeABI.get()));
 
   // Compute ABI information.
-  if (ClangCallConvToLLVMCallConv(info.getCC()) == llvm::CallingConv::SPIR_KERNEL) {
+  if (ClangCallConvToLLVMCallConv(info.getCC()) ==
+      llvm::CallingConv::SPIR_KERNEL) {
     // Force target independent argument handling for the host visible
     // kernel functions.
     computeSPIRKernelABIInfo(CGM, *FI);
   } else if (info.getCC() == CC_Swift || info.getCC() == CC_SwiftAsync) {
     swiftcall::computeABIInfo(CGM, *FI);
   } else {
-    // inject the required ABI information into the function. done by the library
+    // inject the required ABI information into the function. done by the
+    // library
     ABI::computeFunctionInfo(CodeGenModule::getTargetCodeGenInfo(), ABIFI);
   }
 
diff --git a/llvm/lib/LLVMABI/ABICall.h b/llvm/lib/LLVMABI/ABICall.h
index 8edb3a4b6..058aa84f6 100644
--- a/llvm/lib/LLVMABI/ABICall.h
+++ b/llvm/lib/LLVMABI/ABICall.h
@@ -1,8 +1,8 @@
 #ifndef ABICALL_H
 #define ABICALL_H
 
-#include "Type.h"
 #include "ABIFunctionInfo.h"
+#include "Type.h"
 
 using namespace ABI;
 using namespace ABIFunction;
@@ -18,7 +18,6 @@ public:
   ABIArgInfo classifyArgumentType(Type RetTy) const;
 
   void computeInfo(ABIFunctionInfo &FI) const override;
-
 };
 
 #endif
diff --git a/llvm/lib/LLVMABI/ABIFunctionInfo.h b/llvm/lib/LLVMABI/ABIFunctionInfo.h
index c04d99210..56bc3e9cc 100644
--- a/llvm/lib/LLVMABI/ABIFunctionInfo.h
+++ b/llvm/lib/LLVMABI/ABIFunctionInfo.h
@@ -6,7 +6,7 @@
 
 using namespace ABI;
 
-namespace ABIFunction{
+namespace ABIFunction {
 
 /// ABIArgInfo - Helper class to encapsulate information about how a
 /// specific C type should be passed to or returned from a function.
@@ -70,10 +70,10 @@ public:
 
 private:
   Kind TheKind;
- 
+
 public:
   ABIArgInfo(Kind K = Direct) : TheKind(K) {}
-        
+
   Kind getKind() const { return TheKind; }
 
   static Kind getDirect() { return Direct; }
@@ -104,38 +104,37 @@ struct ABIFunctionInfoArgInfo {
 class ABIFunctionInfo {
   typedef ABIFunctionInfoArgInfo ArgInfo;
 
-  private:
+private:
   CallingConv CC;
   std::vector<ArgInfo> Parameters;
   ArgInfo RetInfo;
-  
-  public:
-    ABIFunctionInfo(CallingConv cc, std::vector<const Type *> parameters,
-                    Type ReturnInfo);
 
-    static ABIFunctionInfo *create(CallingConv cc,
-                                   std::vector<const Type *> parameters,
-                                   Type ReturnInfo);
+public:
+  ABIFunctionInfo(CallingConv cc, std::vector<const Type *> parameters,
+                  Type ReturnInfo);
+
+  static ABIFunctionInfo *
+  create(CallingConv cc, std::vector<const Type *> parameters, Type ReturnInfo);
 
-    ABIArgInfo &getReturnInfo();
-    const ABIArgInfo &getReturnInfo() const;
+  ABIArgInfo &getReturnInfo();
+  const ABIArgInfo &getReturnInfo() const;
 
-    const Type *getReturnType() const;
+  const Type *getReturnType() const;
 
-    using arg_iterator = std::vector<ArgInfo>::iterator;
-    using const_arg_iterator = std::vector<ArgInfo>::const_iterator;
+  using arg_iterator = std::vector<ArgInfo>::iterator;
+  using const_arg_iterator = std::vector<ArgInfo>::const_iterator;
 
-    arg_iterator arg_begin();
-    arg_iterator arg_end();
+  arg_iterator arg_begin();
+  arg_iterator arg_end();
 
-    const_arg_iterator arg_begin() const;
-    const_arg_iterator arg_end() const;
+  const_arg_iterator arg_begin() const;
+  const_arg_iterator arg_end() const;
 
-    void dump() const;
+  void dump() const;
 
-    unsigned getCallingConvention() const { return CC; }
+  unsigned getCallingConvention() const { return CC; }
 };
 
-}
+} // namespace ABIFunction
 
 #endif
\ No newline at end of file
diff --git a/llvm/lib/LLVMABI/Type.cpp b/llvm/lib/LLVMABI/Type.cpp
index 4811c82dd..ac8950bb6 100644
--- a/llvm/lib/LLVMABI/Type.cpp
+++ b/llvm/lib/LLVMABI/Type.cpp
@@ -5,40 +5,46 @@
 using namespace ABI;
 
 void ABIBuiltinType::dump() const {
-    std::cout << "BuiltinType: ";
-    // Assuming you're sticking with these only:
-    switch (kind) {
-        case Void: std::cout << "Void\n"; break;
-        case Bool: std::cout << "Bool\n"; break;
-        case Integer:
-          std::cout << "Integer\n";
-          break;
-        case Int128: std::cout << "Int128\n"; break;
-        case UInt128:
-          std::cout << "UInt128\n";
-          break;
-        case LongLong:
-          std::cout << "LongLong\n";
-          break;
-        case Float:
-          std::cout << "Float\n";
-          break;
-        case Double:
-          std::cout << "Double\n";
-          break;
-        case Float16:
-          std::cout << "Float16\n";
-          break;
-        case BFloat16:
-          std::cout << "BFloat16\n";
-          break;
-        case Float128:
-          std::cout << "Float128\n";
-          break;
-        case LongDouble:
-          std::cout << "LongDouble\n";
-          break;
-    }
+  std::cout << "BuiltinType: ";
+  // Assuming you're sticking with these only:
+  switch (kind) {
+  case Void:
+    std::cout << "Void\n";
+    break;
+  case Bool:
+    std::cout << "Bool\n";
+    break;
+  case Integer:
+    std::cout << "Integer\n";
+    break;
+  case Int128:
+    std::cout << "Int128\n";
+    break;
+  case UInt128:
+    std::cout << "UInt128\n";
+    break;
+  case LongLong:
+    std::cout << "LongLong\n";
+    break;
+  case Float:
+    std::cout << "Float\n";
+    break;
+  case Double:
+    std::cout << "Double\n";
+    break;
+  case Float16:
+    std::cout << "Float16\n";
+    break;
+  case BFloat16:
+    std::cout << "BFloat16\n";
+    break;
+  case Float128:
+    std::cout << "Float128\n";
+    break;
+  case LongDouble:
+    std::cout << "LongDouble\n";
+    break;
+  }
 }
 
 void ABIRecordType::dump() const {
@@ -48,5 +54,5 @@ void ABIRecordType::dump() const {
     std::cout << "  Field: " << F.Name << ", Offset: " << F.OffsetInBits
               << " bits"
               << ", TypeClass: " << F.FieldType->getTypeClass() << "\n";
-    }
+  }
 }
diff --git a/llvm/lib/LLVMABI/Type.h b/llvm/lib/LLVMABI/Type.h
index d45371aad..d75523f5b 100644
--- a/llvm/lib/LLVMABI/Type.h
+++ b/llvm/lib/LLVMABI/Type.h
@@ -7,106 +7,104 @@
 
 using namespace std;
 
-  
-namespace ABI{
-  class Type {
-    public:
-    enum TypeClass { Builtin, Record };
-    
-    Type(TypeClass TC) : Tc(TC) {}
+namespace ABI {
+class Type {
+public:
+  enum TypeClass { Builtin, Record };
 
-    // getter method
-    TypeClass getTypeClass() const { return Tc; }
+  Type(TypeClass TC) : Tc(TC) {}
 
-    virtual ~Type() = default;
-    bool isBuiltinType() const { return getTypeClass() == Builtin; }
-    bool isAggregateType() const { return getTypeClass() == Record; }
+  // getter method
+  TypeClass getTypeClass() const { return Tc; }
 
-    static bool classof(const Type *T) { return true; }
+  virtual ~Type() = default;
+  bool isBuiltinType() const { return getTypeClass() == Builtin; }
+  bool isAggregateType() const { return getTypeClass() == Record; }
 
-    // debug info
-    virtual void dump() const;
+  static bool classof(const Type *T) { return true; }
 
-  private:
-    //save the type class
-    TypeClass Tc;
+  // debug info
+  virtual void dump() const;
+
+private:
+  // save the type class
+  TypeClass Tc;
 };
 
 class ABIBuiltinType : public Type {
-  public:
-    enum Kind {
-      Void,
-      Bool,
-      Integer,
-      Int128,
-      UInt128,
-      LongLong,
-      Float,
-      Double,
-      Float16,
-      BFloat16,
-      Float128,
-      LongDouble
-    };
-
-  private:
-    Kind kind;
-    uint64_t Size;
-    uint64_t Alignment;
-
-  public:
-    ABIBuiltinType(Kind K) : Type(Builtin), kind(K) {}
-
-    Kind getKind() const { return kind; }
-
-    bool isInteger() const {
-      return getKind() == Kind::Integer || getKind() == Kind::Int128;
-    }
-    bool isFloatingPoint() const { return getKind() == Kind::Float; }
-
-    static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
-
-    void dump() const override;
+public:
+  enum Kind {
+    Void,
+    Bool,
+    Integer,
+    Int128,
+    UInt128,
+    LongLong,
+    Float,
+    Double,
+    Float16,
+    BFloat16,
+    Float128,
+    LongDouble
+  };
+
+private:
+  Kind kind;
+  uint64_t Size;
+  uint64_t Alignment;
+
+public:
+  ABIBuiltinType(Kind K) : Type(Builtin), kind(K) {}
+
+  Kind getKind() const { return kind; }
+
+  bool isInteger() const {
+    return getKind() == Kind::Integer || getKind() == Kind::Int128;
+  }
+  bool isFloatingPoint() const { return getKind() == Kind::Float; }
+
+  static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
+
+  void dump() const override;
 };
 
 class ABIRecordType : public Type {
-  public:
-    struct Field {
-      std::string Name;
-      const Type *FieldType;
-      uint64_t OffsetInBits;
+public:
+  struct Field {
+    std::string Name;
+    const Type *FieldType;
+    uint64_t OffsetInBits;
 
-      Field(const std::string &N, const Type *T, uint64_t Offset = 0)
-          : Name(N), FieldType(T), OffsetInBits(Offset) {}
-    };
+    Field(const std::string &N, const Type *T, uint64_t Offset = 0)
+        : Name(N), FieldType(T), OffsetInBits(Offset) {}
+  };
 
-    using FieldList = std::vector<Field>;
+  using FieldList = std::vector<Field>;
 
-    ABIRecordType(const std::string &Name, uint64_t AlignInBits = 0)
-        : Type(Record), RecordName(Name), Alignment(AlignInBits) {}
+  ABIRecordType(const std::string &Name, uint64_t AlignInBits = 0)
+      : Type(Record), RecordName(Name), Alignment(AlignInBits) {}
 
-    void addField(const std::string &Name, const Type *T, uint64_t Offset = 0) {
-      Fields.emplace_back(Name, T, Offset);
-    }
+  void addField(const std::string &Name, const Type *T, uint64_t Offset = 0) {
+    Fields.emplace_back(Name, T, Offset);
+  }
 
-    const FieldList &getFields() const { return Fields; }
+  const FieldList &getFields() const { return Fields; }
 
-    uint64_t getAlignmentInBits() const { return Alignment; }
-    void setAlignmentInBits(uint64_t Align) { Alignment = Align; }
+  uint64_t getAlignmentInBits() const { return Alignment; }
+  void setAlignmentInBits(uint64_t Align) { Alignment = Align; }
 
-    const std::string &getName() const { return RecordName; }
+  const std::string &getName() const { return RecordName; }
 
-    static bool classof(const Type *T) { return T->getTypeClass() == Record; }
+  static bool classof(const Type *T) { return T->getTypeClass() == Record; }
 
-    void dump() const;
+  void dump() const;
 
-  private:
-    std::string RecordName;
-    FieldList Fields;
-    uint64_t Alignment;
+private:
+  std::string RecordName;
+  FieldList Fields;
+  uint64_t Alignment;
 };
 
 } // namespace ABI
 
 #endif
-

…l have a lot to refactor.

Things to decide yet:
1. The mapping of QualTypes to ABI types is yet not crystal clear.
2. I think I am polluting the namespaces. Need to clean that up.
3. Mapping the ABIFunctionInfo to the CGFunctionInfo is yet to be done.
4. The target Call information has to be passed to the library. how does the library know which target it is lowering for.
invoke the compute info function. I will need to pass some information about the target.
Also mapping from ABIFunctionInfo types back to CGFunctionInfo is still pending.

Is the library going to be shipped seperately? or is it going to be a part of the LLVM repo?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant