Author: Akshay K
Date: 2026-09-15T16:06:51-04:00
New Revision: a84250b63d2a731da76a25e091bb9c5374651625

URL: 
https://github.com/llvm/llvm-project/commit/a84250b63d2a731da76a25e091bb9c5374651625
DIFF: 
https://github.com/llvm/llvm-project/commit/a84250b63d2a731da76a25e091bb9c5374651625.diff

LOG: [LLVMABI] Add CanBeFlattened to abi::ArgInfo (#220558)

Mirror `clang::CodeGen::ABIArgInfo::CanBeFlattened` on `abi::ArgInfo` so
a classifier can keep a Direct record coercion in one piece, as
AAPCS-VFP homogeneous aggregates, AMDGPU direct aggregates and x86
vectorcall HVAs require. The bit defaults to true, so existing
classifiers are unchanged. It is exposed through `getCanBeFlattened()`
and a chainable `setCanBeFlattened()`, both Direct-only like the classic
accessor.

The MLIR `ArgClassification::canFlatten` and the CIR rewriter already
honour the flag; the CIR bridge will read the new bit with the first
classifier that clears it.

Added: 
    llvm/unittests/ABI/FunctionInfoTest.cpp

Modified: 
    clang/lib/CodeGen/CGCall.cpp
    llvm/include/llvm/ABI/FunctionInfo.h
    llvm/unittests/ABI/CMakeLists.txt
    llvm/utils/gn/secondary/llvm/unittests/ABI/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 1221829871b9f..13036b4cdd58c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -976,6 +976,10 @@ void CodeGenModule::computeABIInfoUsingLib(CGFunctionInfo 
&FI) {
       CheckSimple(Target.getDirectAlign(), Res.getDirectAlign(), 
"DirectAlign");
       CheckSimple(Target.getDirectOffset(), Res.getDirectOffset(),
                   "DirectOffset");
+      // Extend falls through to here, and only Direct carries the flag.
+      if (Res.isDirect())
+        CheckSimple(Target.getCanBeFlattened(), Res.getCanBeFlattened(),
+                    "CanBeFlattened");
       break;
     case ABIArgInfo::Indirect:
       CheckSimple(Target.getIndirectByVal(), Res.getIndirectByVal(),
@@ -1023,7 +1027,9 @@ ABIArgInfo CodeGenModule::convertABIArgInfo(const 
llvm::abi::ArgInfo &AbiInfo,
       CoercedType = AbiReverseMapper->convertType(AbiInfo.getCoerceToType());
     if (!CoercedType)
       CoercedType = getTypes().ConvertType(Type);
-    return ABIArgInfo::getDirect(CoercedType, AbiInfo.getDirectOffset());
+    return ABIArgInfo::getDirect(CoercedType, AbiInfo.getDirectOffset(),
+                                 /*Padding=*/nullptr,
+                                 AbiInfo.getCanBeFlattened());
   }
   case llvm::abi::ArgInfo::Extend: {
     llvm::Type *CoercedType = nullptr;

diff  --git a/llvm/include/llvm/ABI/FunctionInfo.h 
b/llvm/include/llvm/ABI/FunctionInfo.h
index caedafcbe9d22..d2e6c619a0434 100644
--- a/llvm/include/llvm/ABI/FunctionInfo.h
+++ b/llvm/include/llvm/ABI/FunctionInfo.h
@@ -71,10 +71,11 @@ class ArgInfo {
   bool ZeroExt : 1;
   bool IndirectByVal : 1;
   bool IndirectRealign : 1;
+  bool CanBeFlattened : 1;
 
   ArgInfo(Kind K = Direct)
       : TheKind(K), SignExt(false), ZeroExt(false), IndirectByVal(false),
-        IndirectRealign(false) {}
+        IndirectRealign(false), CanBeFlattened(false) {}
 
 public:
   /// \param T The type to coerce to. If null, the argument's original type is
@@ -85,12 +86,16 @@ class ArgInfo {
   ///               return value on x86-64).
   /// \param Align  Override for the argument's alignment. If absent, the
   ///               default alignment for \p T is used.
+  /// \param CanBeFlattened Whether a record coercion may be split into one
+  ///               wire argument per field. See getCanBeFlattened.
   static ArgInfo getDirect(const Type *T = nullptr, unsigned Offset = 0,
-                           MaybeAlign Align = std::nullopt) {
+                           MaybeAlign Align = std::nullopt,
+                           bool CanBeFlattened = true) {
     ArgInfo AI(Direct);
     AI.CoercionType = T;
     AI.Alignment = Align;
     AI.DirectAttr.Offset = Offset;
+    AI.CanBeFlattened = CanBeFlattened;
     return AI;
   }
 
@@ -140,6 +145,13 @@ class ArgInfo {
     return *this;
   }
 
+  /// See getCanBeFlattened.
+  ArgInfo &setCanBeFlattened(bool Flatten) {
+    assert(isDirect() && "Invalid Kind!");
+    CanBeFlattened = Flatten;
+    return *this;
+  }
+
   Kind getKind() const { return TheKind; }
   bool isDirect() const { return TheKind == Direct; }
   bool isIndirect() const { return TheKind == Indirect; }
@@ -178,6 +190,13 @@ class ArgInfo {
     return IndirectRealign;
   }
 
+  /// Whether a Direct record coercion may be split into one wire argument
+  /// per field. Mirrors clang::CodeGen::ABIArgInfo::CanBeFlattened.
+  bool getCanBeFlattened() const {
+    assert(isDirect() && "Invalid Kind!");
+    return CanBeFlattened;
+  }
+
   bool isSignExt() const {
     assert(isExtend() && "Invalid Kind!");
     return SignExt;

diff  --git a/llvm/unittests/ABI/CMakeLists.txt 
b/llvm/unittests/ABI/CMakeLists.txt
index 40cdd42ea6c61..4a1910ab8809b 100644
--- a/llvm/unittests/ABI/CMakeLists.txt
+++ b/llvm/unittests/ABI/CMakeLists.txt
@@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
 add_llvm_unittest(ABITests
   AArch64TargetInfoTest.cpp
   IRTypeMapperTest.cpp
+  FunctionInfoTest.cpp
   X86TargetInfoTest.cpp
   TypesTest.cpp
   )

diff  --git a/llvm/unittests/ABI/FunctionInfoTest.cpp 
b/llvm/unittests/ABI/FunctionInfoTest.cpp
new file mode 100644
index 0000000000000..04fafc1108f83
--- /dev/null
+++ b/llvm/unittests/ABI/FunctionInfoTest.cpp
@@ -0,0 +1,110 @@
+//===- FunctionInfoTest.cpp - ArgInfo and FunctionInfo unit tests 
---------===//
+//
+// 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/Types.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Allocator.h"
+#include "gtest/gtest.h"
+#include <optional>
+
+namespace {
+
+using ABIType = llvm::abi::Type;
+using llvm::abi::ArgEntry;
+using llvm::abi::ArgInfo;
+using llvm::abi::FieldInfo;
+using llvm::abi::FunctionInfo;
+using llvm::abi::StructPacking;
+using llvm::abi::TypeBuilder;
+
+class FunctionInfoTest : public ::testing::Test {
+protected:
+  llvm::BumpPtrAllocator Alloc;
+  TypeBuilder TB;
+  const ABIType *I32;
+  const ABIType *I64;
+  /// A two-i64 record: the shape a classifier coerces a 16-byte struct to when
+  /// it lands in two registers, and so the shape a rewriter may flatten.
+  const ABIType *TwoI64;
+
+  FunctionInfoTest()
+      : TB(Alloc), I32(TB.getIntegerType(32, llvm::Align(4), /*Signed=*/true)),
+        I64(TB.getIntegerType(64, llvm::Align(8), /*Signed=*/true)),
+        TwoI64(TB.getRecordType({FieldInfo(I64, 0), FieldInfo(I64, 64)},
+                                llvm::TypeSize::getFixed(128), llvm::Align(8),
+                                StructPacking::Default)) {}
+};
+
+TEST_F(FunctionInfoTest, DirectCanBeFlattenedByDefault) {
+  EXPECT_TRUE(ArgInfo::getDirect().getCanBeFlattened());
+  EXPECT_TRUE(ArgInfo::getDirect(TwoI64).getCanBeFlattened());
+  EXPECT_TRUE(ArgInfo::getDirect(I64, /*Offset=*/8).getCanBeFlattened());
+}
+
+TEST_F(FunctionInfoTest, SetCanBeFlattenedRoundTrips) {
+  ArgInfo Info = ArgInfo::getDirect(TwoI64);
+  EXPECT_EQ(&Info.setCanBeFlattened(false), &Info);
+  EXPECT_FALSE(Info.getCanBeFlattened());
+  // Clearing the flag leaves the rest of the classification alone.
+  EXPECT_TRUE(Info.isDirect());
+  EXPECT_EQ(Info.getCoerceToType(), TwoI64);
+  EXPECT_EQ(Info.getDirectOffset(), 0u);
+
+  Info.setCanBeFlattened(true);
+  EXPECT_TRUE(Info.getCanBeFlattened());
+}
+
+TEST_F(FunctionInfoTest, GetDirectTakesCanBeFlattened) {
+  // The spelling a classifier uses to keep an aggregate in one piece.
+  ArgInfo Info = ArgInfo::getDirect(TwoI64, /*Offset=*/0, std::nullopt,
+                                    /*CanBeFlattened=*/false);
+  EXPECT_TRUE(Info.isDirect());
+  EXPECT_EQ(Info.getCoerceToType(), TwoI64);
+  EXPECT_EQ(Info.getDirectOffset(), 0u);
+  EXPECT_FALSE(Info.getCanBeFlattened());
+
+  EXPECT_TRUE(ArgInfo::getDirect(TwoI64, /*Offset=*/0, std::nullopt,
+                                 /*CanBeFlattened=*/true)
+                  .getCanBeFlattened());
+}
+
+TEST_F(FunctionInfoTest, CanBeFlattenedSurvivesFunctionInfo) {
+  std::unique_ptr<FunctionInfo> FI =
+      FunctionInfo::create(llvm::CallingConv::C, TwoI64, {TwoI64, I32});
+  // Both spellings that clear the flag land in the same place.
+  FI->getReturnInfo() = ArgInfo::getDirect(TwoI64, /*Offset=*/0, std::nullopt,
+                                           /*CanBeFlattened=*/false);
+  FI->getArgInfo(0).Info = ArgInfo::getDirect(TwoI64).setCanBeFlattened(false);
+  FI->getArgInfo(1).Info = ArgInfo::getDirect(I32);
+
+  const FunctionInfo &ConstFI = *FI;
+  EXPECT_FALSE(ConstFI.getReturnInfo().getCanBeFlattened());
+  EXPECT_FALSE(ConstFI.arguments()[0].Info.getCanBeFlattened());
+  EXPECT_TRUE(ConstFI.arguments()[1].Info.getCanBeFlattened());
+
+  // The flag rides along with the rest of the classification on copy.
+  ArgEntry Copy = ConstFI.getArgInfo(0);
+  EXPECT_FALSE(Copy.Info.getCanBeFlattened());
+}
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+TEST_F(FunctionInfoTest, CanBeFlattenedIsDirectOnly) {
+  EXPECT_DEATH((void)ArgInfo::getIgnore().getCanBeFlattened(), "Invalid Kind");
+  EXPECT_DEATH((void)ArgInfo::getExtend(I32).getCanBeFlattened(),
+               "Invalid Kind");
+  EXPECT_DEATH((void)ArgInfo::getIndirect(llvm::Align(8), /*ByVal=*/true)
+                   .getCanBeFlattened(),
+               "Invalid Kind");
+  EXPECT_DEATH((void)ArgInfo::getIgnore().setCanBeFlattened(false),
+               "Invalid Kind");
+}
+#endif
+
+} // namespace

diff  --git a/llvm/utils/gn/secondary/llvm/unittests/ABI/BUILD.gn 
b/llvm/utils/gn/secondary/llvm/unittests/ABI/BUILD.gn
index 43b98bccc447e..4c34fdf7647bd 100644
--- a/llvm/utils/gn/secondary/llvm/unittests/ABI/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/unittests/ABI/BUILD.gn
@@ -9,6 +9,7 @@ unittest("ABITests") {
   sources = [
     "AArch64TargetInfoTest.cpp",
     "IRTypeMapperTest.cpp",
+    "FunctionInfoTest.cpp",
     "X86TargetInfoTest.cpp",
     "TypesTest.cpp",
   ]


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to