https://github.com/mattst88 created 
https://github.com/llvm/llvm-project/pull/234054

Two NFC refactors split out of #223481 at review request.

- Rename isSingleElementStruct to isSingleElementRecord. It decomposes unions
  as well as structures, both at the top level and in nested fields and bases;
  the new name and comment say so, so that a later isSingleElementStruct can
  refuse unions.
- Factor the single-element floating-point/128-bit vector aggregate test that
  PPC64_SVR4_ABIInfo::computeInfo and getParamTypeAlignment each performed
  into getSingleElementFPOrVectorType.

Assisted-by: Claude Code


>From 06e418f744a2d37ab641f78d826a7500802c4b35 Mon Sep 17 00:00:00 2001
From: Matt Turner <[email protected]>
Date: Thu, 15 Oct 2026 18:29:13 -0400
Subject: [PATCH 1/2] [clang][CodeGen] Rename isSingleElementStruct to
 isSingleElementRecord (NFC)

isSingleElementStruct decomposes unions as well as structures, both at
the top level and in nested fields and bases. Rename it to
isSingleElementRecord and say so in its comment, so that a later
isSingleElementStruct can refuse unions.

Assisted-by: Claude Code
---
 clang/lib/CodeGen/ABIInfoImpl.cpp         |  6 +++---
 clang/lib/CodeGen/ABIInfoImpl.h           | 11 ++++++-----
 clang/lib/CodeGen/Targets/AMDGPU.cpp      |  6 +++---
 clang/lib/CodeGen/Targets/CSKY.cpp        |  2 +-
 clang/lib/CodeGen/Targets/PPC.cpp         |  6 +++---
 clang/lib/CodeGen/Targets/SPIR.cpp        |  6 +++---
 clang/lib/CodeGen/Targets/SystemZ.cpp     |  8 ++++----
 clang/lib/CodeGen/Targets/WebAssembly.cpp |  6 +++---
 clang/lib/CodeGen/Targets/X86.cpp         |  8 ++++----
 9 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp 
b/clang/lib/CodeGen/ABIInfoImpl.cpp
index 23b6b7e8200da..a7f88411d0626 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.cpp
+++ b/clang/lib/CodeGen/ABIInfoImpl.cpp
@@ -302,7 +302,7 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType 
T, bool AllowArrays,
   return true;
 }
 
-const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
+const Type *CodeGen::isSingleElementRecord(QualType T, ASTContext &Context) {
   const auto *RD = T->getAsRecordDecl();
   if (!RD)
     return nullptr;
@@ -325,7 +325,7 @@ const Type *CodeGen::isSingleElementStruct(QualType T, 
ASTContext &Context) {
 
       // If this is non-empty and not a single element struct, the composite
       // cannot be a single element struct.
-      Found = isSingleElementStruct(I.getType(), Context);
+      Found = isSingleElementRecord(I.getType(), Context);
       if (!Found)
         return nullptr;
     }
@@ -354,7 +354,7 @@ const Type *CodeGen::isSingleElementStruct(QualType T, 
ASTContext &Context) {
     if (!isAggregateTypeForABI(FT)) {
       Found = FT.getTypePtr();
     } else {
-      Found = isSingleElementStruct(FT, Context);
+      Found = isSingleElementRecord(FT, Context);
       if (!Found)
         return nullptr;
     }
diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h
index f0276be8cb97f..f9cec462620de 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.h
+++ b/clang/lib/CodeGen/ABIInfoImpl.h
@@ -120,15 +120,16 @@ bool isEmptyField(ASTContext &Context, const FieldDecl 
*FD, bool AllowArrays,
 bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
                    bool AsIfNoUniqueAddr = false);
 
-/// isSingleElementStruct - Determine if a structure is a "single
-/// element struct", i.e. it has exactly one non-empty field or
+/// isSingleElementRecord - Determine if a record is a "single
+/// element record", i.e. it has exactly one non-empty field or
 /// exactly one field which is itself a single element
-/// struct. Structures with flexible array members are never
-/// considered single element structs.
+/// record. Both structures and unions are decomposed, at the top level
+/// and at every level of nesting. Records with flexible array members
+/// are never considered single element records.
 ///
 /// \return The field declaration for the single non-empty field, if
 /// it exists.
-const Type *isSingleElementStruct(QualType T, ASTContext &Context);
+const Type *isSingleElementRecord(QualType T, ASTContext &Context);
 
 Address EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
                        const ABIArgInfo &AI);
diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp 
b/clang/lib/CodeGen/Targets/AMDGPU.cpp
index d54efe81f8cee..fd9182adda47d 100644
--- a/clang/lib/CodeGen/Targets/AMDGPU.cpp
+++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp
@@ -152,7 +152,7 @@ ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType 
RetTy) const {
         return ABIArgInfo::getIgnore();
 
       // Lower single-element structs to just return a regular value.
-      if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+      if (const Type *SeltTy = isSingleElementRecord(RetTy, getContext()))
         return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
 
       if (const auto *RD = RetTy->getAsRecordDecl();
@@ -188,7 +188,7 @@ ABIArgInfo 
AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const {
 
   // TODO: Can we omit empty structs?
 
-  if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+  if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
     Ty = QualType(SeltTy, 0);
 
   llvm::Type *OrigLTy = CGT.ConvertType(Ty);
@@ -243,7 +243,7 @@ ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, 
bool Variadic,
     // Lower single-element structs to just pass a regular value. TODO: We
     // could do reasonable-size multiple-element structs too, using 
getExpand(),
     // though watch out for things like bitfields.
-    if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+    if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
 
     if (const auto *RD = Ty->getAsRecordDecl();
diff --git a/clang/lib/CodeGen/Targets/CSKY.cpp 
b/clang/lib/CodeGen/Targets/CSKY.cpp
index b9254208f912a..a7455f6b39fb4 100644
--- a/clang/lib/CodeGen/Targets/CSKY.cpp
+++ b/clang/lib/CodeGen/Targets/CSKY.cpp
@@ -92,7 +92,7 @@ ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int 
&ArgGPRsLeft,
     return ABIArgInfo::getIgnore();
 
   if (!Ty->isUnionType())
-    if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+    if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
 
   uint64_t Size = getContext().getTypeSize(Ty);
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp 
b/clang/lib/CodeGen/Targets/PPC.cpp
index df14719a8c6a8..5818c3c6ca9ff 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -428,7 +428,7 @@ CharUnits 
PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
   // For single-element float/vector structs, we consider the whole type
   // to have the same alignment requirements as its single element.
   const Type *AlignTy = nullptr;
-  if (const Type *EltType = isSingleElementStruct(Ty, getContext())) {
+  if (const Type *EltType = isSingleElementRecord(Ty, getContext())) {
     const BuiltinType *BT = EltType->getAs<BuiltinType>();
     if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) 
||
         (BT && BT->isFloatingPoint()))
@@ -688,7 +688,7 @@ class PPC64_SVR4_ABIInfo : public ABIInfo {
       // We rely on the default argument classification for the most part.
       // One exception:  An aggregate containing a single floating-point
       // or vector item must be passed in a register if one is available.
-      const Type *T = isSingleElementStruct(I.type, getContext());
+      const Type *T = isSingleElementRecord(I.type, getContext());
       if (T) {
         const BuiltinType *BT = T->getAs<BuiltinType>();
         if ((T->isVectorType() && getContext().getTypeSize(T) == 128) ||
@@ -797,7 +797,7 @@ CharUnits 
PPC64_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
   // For single-element float/vector structs, we consider the whole type
   // to have the same alignment requirements as its single element.
   const Type *AlignAsType = nullptr;
-  const Type *EltType = isSingleElementStruct(Ty, getContext());
+  const Type *EltType = isSingleElementRecord(Ty, getContext());
   if (EltType) {
     const BuiltinType *BT = EltType->getAs<BuiltinType>();
     if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) 
||
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp 
b/clang/lib/CodeGen/Targets/SPIR.cpp
index 19936d44208dd..8088a09ecdced 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -262,7 +262,7 @@ ABIArgInfo AMDGCNSPIRVABIInfo::classifyReturnType(QualType 
RetTy) const {
     return ABIArgInfo::getIgnore();
 
   // Lower single-element structs to just return a regular value.
-  if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+  if (const Type *SeltTy = isSingleElementRecord(RetTy, getContext()))
     return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
 
   if (const auto *RD = RetTy->getAsRecordDecl();
@@ -296,7 +296,7 @@ ABIArgInfo 
AMDGCNSPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const {
 
   // TODO: Can we omit empty structs?
 
-  if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+  if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
     Ty = QualType(SeltTy, 0);
 
   llvm::Type *OrigLTy = CGT.ConvertType(Ty);
@@ -359,7 +359,7 @@ ABIArgInfo 
AMDGCNSPIRVABIInfo::classifyArgumentType(QualType Ty,
   // Lower single-element structs to just pass a regular value. TODO: We
   // could do reasonable-size multiple-element structs too, using getExpand(),
   // though watch out for things like bitfields.
-  if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+  if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
     return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
 
   if (const auto *RD = Ty->getAsRecordDecl();
diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp 
b/clang/lib/CodeGen/Targets/SystemZ.cpp
index a27fee633ead2..6c5c2e65dcaf1 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -229,22 +229,22 @@ QualType SystemZABIInfo::getSingleElementType(QualType 
Ty) const {
 
     // Check the fields.
     for (const auto *FD : RD->fields()) {
-      // Unlike isSingleElementStruct(), empty structure and array fields
+      // Unlike isSingleElementRecord(), empty structure and array fields
       // do count.  So do anonymous bitfields that aren't zero-sized.
 
-      // Like isSingleElementStruct(), ignore C++20 empty data members.
+      // Like isSingleElementRecord(), ignore C++20 empty data members.
       if (FD->hasAttr<NoUniqueAddressAttr>() &&
           isEmptyRecord(getContext(), FD->getType(), true))
         continue;
 
-      // Unlike isSingleElementStruct(), arrays do not count.
+      // Unlike isSingleElementRecord(), arrays do not count.
       // Nested structures still do though.
       if (!Found.isNull())
         return Ty;
       Found = getSingleElementType(FD->getType());
     }
 
-    // Unlike isSingleElementStruct(), trailing padding is allowed.
+    // Unlike isSingleElementRecord(), trailing padding is allowed.
     // An 8-byte aligned struct s { float f; } is passed as a double.
     if (!Found.isNull())
       return Found;
diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp 
b/clang/lib/CodeGen/Targets/WebAssembly.cpp
index 8f6f58bfb807e..b892923eddc51 100644
--- a/clang/lib/CodeGen/Targets/WebAssembly.cpp
+++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp
@@ -150,7 +150,7 @@ ABIArgInfo 
WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
     // Lower single-element structs to just pass a regular value. TODO: We
     // could do reasonable-size multiple-element structs too, using 
getExpand(),
     // though watch out for things like bitfields.
-    if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+    if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
     // For the experimental multivalue ABI, fully expand all other aggregates
     if (Kind == WebAssemblyABIKind::ExperimentalMV) {
@@ -186,7 +186,7 @@ ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType 
RetTy) const {
       // Lower single-element structs to just return a regular value. TODO: We
       // could do reasonable-size multiple-element structs too, using
       // ABIArgInfo::getDirect().
-      if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+      if (const Type *SeltTy = isSingleElementRecord(RetTy, getContext()))
         return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
       // For the experimental multivalue ABI, return all other aggregates
       if (Kind == WebAssemblyABIKind::ExperimentalMV)
@@ -202,7 +202,7 @@ RValue WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, 
Address VAListAddr,
                                      QualType Ty, AggValueSlot Slot) const {
   bool IsIndirect = isAggregateTypeForABI(Ty) &&
                     !isEmptyRecord(getContext(), Ty, true) &&
-                    !isSingleElementStruct(Ty, getContext());
+                    !isSingleElementRecord(Ty, getContext());
   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
                           getContext().getTypeInfoInChars(Ty),
                           CharUnits::fromQuantity(4),
diff --git a/clang/lib/CodeGen/Targets/X86.cpp 
b/clang/lib/CodeGen/Targets/X86.cpp
index c0947c481d2b0..c5c8bd4c0b27d 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -544,7 +544,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
       // floating-point register. (MSVC does not apply this special case.)
       // We apply a similar transformation for pointer types to improve the
       // quality of the generated IR.
-      if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+      if (const Type *SeltTy = isSingleElementRecord(RetTy, getContext()))
         if ((!IsWin32StructABI && SeltTy->isRealFloatingType())
             || SeltTy->hasPointerRepresentation())
           return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
@@ -631,7 +631,7 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, 
bool ByVal,
       Realign);
 }
 
-/// Like isSingleElementStruct, but only looks through one level of records.
+/// Like isSingleElementRecord, but only looks through one level of records.
 /// This mirrors how GCC gives a record the mode of its only field.
 static const Type *getSingleFieldType(QualType T, ASTContext &Context) {
   const auto *RD = T->getAsRecordDecl();
@@ -692,7 +692,7 @@ static const Type *getSingleFieldType(QualType T, 
ASTContext &Context) {
 X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
   if (getContext().getLangOpts().isCompatibleWith(
           LangOptions::ClangABI::Ver23)) {
-    const Type *T = isSingleElementStruct(Ty, getContext());
+    const Type *T = isSingleElementRecord(Ty, getContext());
     if (!T)
       T = Ty.getTypePtr();
 
@@ -2477,7 +2477,7 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
 llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType 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, getContext()))
+  if (const Type *InnerTy = isSingleElementRecord(Ty, getContext()))
     Ty = QualType(InnerTy, 0);
 
   llvm::Type *IRType = CGT.ConvertType(Ty);

>From 2a749612a768f5bcf60bdf366cb2cc37ac04110b Mon Sep 17 00:00:00 2001
From: Matt Turner <[email protected]>
Date: Mon, 14 Sep 2026 07:47:46 -0400
Subject: [PATCH 2/2] [clang][PowerPC] Factor out single-element FP/vector
 aggregate check

PPC64_SVR4_ABIInfo::computeInfo and getParamTypeAlignment each tested
whether an aggregate wraps a single floating-point or 128-bit vector
value. Move the test into getSingleElementFPOrVectorType.

Assisted-by: Claude Code
---
 clang/lib/CodeGen/Targets/PPC.cpp | 36 ++++++++++++++++---------------
 1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/PPC.cpp 
b/clang/lib/CodeGen/Targets/PPC.cpp
index 5818c3c6ca9ff..cac2ee86f7d1f 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -667,6 +667,7 @@ class PPC64_SVR4_ABIInfo : public ABIInfo {
 
   bool isPromotableTypeForABI(QualType Ty) const;
   CharUnits getParamTypeAlignment(QualType Ty) const;
+  const Type *getSingleElementFPOrVectorType(QualType Ty) const;
 
   ABIArgInfo classifyReturnType(QualType RetTy) const;
   ABIArgInfo classifyArgumentType(QualType Ty) const;
@@ -688,15 +689,9 @@ class PPC64_SVR4_ABIInfo : public ABIInfo {
       // We rely on the default argument classification for the most part.
       // One exception:  An aggregate containing a single floating-point
       // or vector item must be passed in a register if one is available.
-      const Type *T = isSingleElementRecord(I.type, getContext());
-      if (T) {
-        const BuiltinType *BT = T->getAs<BuiltinType>();
-        if ((T->isVectorType() && getContext().getTypeSize(T) == 128) ||
-            (BT && BT->isFloatingPoint())) {
-          QualType QT(T, 0);
-          I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
-          continue;
-        }
+      if (const Type *T = getSingleElementFPOrVectorType(I.type)) {
+        I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QualType(T, 0)));
+        continue;
       }
       I.info = classifyArgumentType(I.type);
     }
@@ -796,14 +791,7 @@ CharUnits 
PPC64_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
 
   // For single-element float/vector structs, we consider the whole type
   // to have the same alignment requirements as its single element.
-  const Type *AlignAsType = nullptr;
-  const Type *EltType = isSingleElementRecord(Ty, getContext());
-  if (EltType) {
-    const BuiltinType *BT = EltType->getAs<BuiltinType>();
-    if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) 
||
-        (BT && BT->isFloatingPoint()))
-      AlignAsType = EltType;
-  }
+  const Type *AlignAsType = getSingleElementFPOrVectorType(Ty);
 
   // Likewise for ELFv2 homogeneous aggregates.
   const Type *Base = nullptr;
@@ -828,6 +816,20 @@ CharUnits 
PPC64_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
   return CharUnits::fromQuantity(8);
 }
 
+/// If Ty is a one-member aggregate wrapping a floating-point or 128-bit vector
+/// type, return that type.
+const Type *
+PPC64_SVR4_ABIInfo::getSingleElementFPOrVectorType(QualType Ty) const {
+  const Type *EltType = isSingleElementRecord(Ty, getContext());
+  if (!EltType)
+    return nullptr;
+  const BuiltinType *BT = EltType->getAs<BuiltinType>();
+  if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) ||
+      (BT && BT->isFloatingPoint()))
+    return EltType;
+  return nullptr;
+}
+
 bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
   // Homogeneous aggregates for ELFv2 must have base types of float,
   // double, long double, or 128-bit vectors.

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

Reply via email to