[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