[llvm] [ABI][AMDGPU] Add AMDGPU target ABI classifier to the LLVM ABI library (PR #220177)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 23:46:35 PDT 2026


================
@@ -0,0 +1,306 @@
+//===- AMDGPU.cpp - AMDGPU 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ABI/FunctionInfo.h"
+#include "llvm/ABI/TargetInfo.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/Support/AMDGPUAddrSpace.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/TypeSize.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+namespace llvm {
+namespace abi {
+
+class AMDGPUTargetInfo final : public TargetInfo {
+private:
+  static const unsigned MaxNumRegsForArgsRet = 16;
+
+  ABICompatInfo CompatInfo;
+
+  /// HIP coerces a generic scalar-pointer kernel argument to the global
+  /// address space. Gated by the front end, which alone can see LangOpts.HIP.
+  bool CoerceGenericPtrArgToGlobal;
+
+  ArgInfo classifyReturnType(const Type *RetTy) const;
+  ArgInfo classifyKernelArgumentType(const Type *Ty) const;
+  ArgInfo classifyArgumentType(const Type *Ty, bool Variadic,
+                               unsigned &NumRegsLeft) const;
+
+  /// Target-independent fallback classification for arguments and returns.
+  ArgInfo classifyDefaultArgumentType(const Type *Ty) const;
+  ArgInfo classifyDefaultReturnType(const Type *Ty) const;
+
+  /// Estimate number of registers the type will use when passed in registers.
+  uint64_t getNumRegsForType(const Type *Ty) const;
+
+public:
+  AMDGPUTargetInfo(TypeBuilder &TypeBuilder, const ABICompatInfo &Compat,
+                   bool CoerceGenericPtrArgToGlobal)
+      : TargetInfo(TypeBuilder), CompatInfo(Compat),
+        CoerceGenericPtrArgToGlobal(CoerceGenericPtrArgToGlobal) {}
+
+  const ABICompatInfo &getABICompatInfo() const override { return CompatInfo; }
+
+  void computeInfo(FunctionInfo &FI) const override;
+};
+
+uint64_t AMDGPUTargetInfo::getNumRegsForType(const Type *Ty) const {
+  uint64_t NumRegs = 0;
+
+  if (const auto *VT = dyn_cast<VectorType>(Ty)) {
+    // Compute from the number of elements. The reported size is based on the
+    // in-memory size, which includes the padding 4th element for 3-vectors.
+    const Type *EltTy = VT->getElementType();
+    uint64_t EltSize = EltTy->getSizeInBits().getFixedValue();
+    unsigned NumElts = VT->getNumElements().getFixedValue();
+
+    // 16-bit element vectors should be passed as packed.
+    if (EltSize == 16)
+      return (NumElts + 1) / 2;
+
+    uint64_t EltNumRegs = (EltSize + 31) / 32;
+    return EltNumRegs * NumElts;
+  }
+
+  if (const auto *RT = dyn_cast<RecordType>(Ty)) {
+    for (const FieldInfo &Field : RT->getFields())
+      NumRegs += getNumRegsForType(Field.FieldType);
+    return NumRegs;
+  }
+
+  return (Ty->getSizeInBits().getFixedValue() + 31) / 32;
+}
+
+// Natural-alignment indirect in the alloca address space (PRIVATE on AMDGPU),
+// ByVal by default.
+static ArgInfo getNaturalAlignIndirectPrivate(const Type *Ty,
+                                              bool ByVal = true) {
+  return ArgInfo::getIndirect(Ty->getAlignment(), ByVal,
+                              /*AddrSpace=*/AMDGPUAS::PRIVATE_ADDRESS);
+}
+
+// A _BitInt wider than int128 is passed indirectly. AMDGPU has int128, so the
+// threshold is 128 bits.
+static bool isOversizedBitInt(const Type *Ty) {
+  const auto *IT = dyn_cast<IntegerType>(Ty);
+  return IT && IT->isBitInt() && IT->getSizeInBits().getFixedValue() > 128;
+}
+
+// Default argument classification for types not handled by the AMDGPU rules.
+ArgInfo AMDGPUTargetInfo::classifyDefaultArgumentType(const Type *Ty) const {
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
+  if (isAggregateTypeForABI(Ty)) {
+    if (RecordArgABI RAA = getRecordArgABI(Ty); RAA != RAA_Default)
+      return getNaturalAlignIndirectPrivate(Ty,
+                                            /*ByVal=*/RAA ==
+                                                RAA_DirectInMemory);
+    return getNaturalAlignIndirectPrivate(Ty);
+  }
+
+  if (isOversizedBitInt(Ty))
+    return getNaturalAlignIndirectPrivate(Ty);
+
+  const auto *IT = dyn_cast<IntegerType>(Ty);
+  return (IT && isPromotableInteger(IT)) ? ArgInfo::getExtend(Ty)
+                                         : ArgInfo::getDirect();
+}
+
+// Default return classification for types not handled by the AMDGPU rules.
+ArgInfo AMDGPUTargetInfo::classifyDefaultReturnType(const Type *Ty) const {
+  if (Ty->isVoid())
+    return ArgInfo::getIgnore();
+
+  if (isAggregateTypeForABI(Ty))
+    return getNaturalAlignIndirectPrivate(Ty);
+
+  if (isOversizedBitInt(Ty))
+    return getNaturalAlignIndirectPrivate(Ty);
+
+  const auto *IT = dyn_cast<IntegerType>(Ty);
+  return (IT && isPromotableInteger(IT)) ? ArgInfo::getExtend(Ty)
+                                         : ArgInfo::getDirect();
+}
+
+ArgInfo AMDGPUTargetInfo::classifyReturnType(const Type *RetTy) const {
+  if (RetTy->isVoid())
+    return ArgInfo::getIgnore();
+
+  if (isAggregateTypeForABI(RetTy)) {
+    // Records with non-trivial destructors/copy-constructors should not be
+    // returned by value.
+    if (getRecordArgABI(RetTy) == RAA_Default) {
+      const auto *RT = dyn_cast<RecordType>(RetTy);
+
+      // Ignore empty structs/unions.
+      if (RT && RT->isEmpty())
----------------
skc7 wrote:

Updated in latest patch. Thanks.

https://github.com/llvm/llvm-project/pull/220177


More information about the llvm-commits mailing list