[clang] [clang][CodeGen] Rename isSingleElementStruct to isSingleElementRecord and factor out PPC FP/vector check (NFC) (PR #234054)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 20 19:01:13 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Matt Turner (mattst88)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/234054.diff
9 Files Affected:
- (modified) clang/lib/CodeGen/ABIInfoImpl.cpp (+3-3)
- (modified) clang/lib/CodeGen/ABIInfoImpl.h (+6-5)
- (modified) clang/lib/CodeGen/Targets/AMDGPU.cpp (+3-3)
- (modified) clang/lib/CodeGen/Targets/CSKY.cpp (+1-1)
- (modified) clang/lib/CodeGen/Targets/PPC.cpp (+20-18)
- (modified) clang/lib/CodeGen/Targets/SPIR.cpp (+3-3)
- (modified) clang/lib/CodeGen/Targets/SystemZ.cpp (+4-4)
- (modified) clang/lib/CodeGen/Targets/WebAssembly.cpp (+3-3)
- (modified) clang/lib/CodeGen/Targets/X86.cpp (+4-4)
``````````diff
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..cac2ee86f7d1f 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()))
@@ -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 = isSingleElementStruct(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 = isSingleElementStruct(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.
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);
``````````
</details>
https://github.com/llvm/llvm-project/pull/234054
More information about the cfe-commits
mailing list