simon_tatham updated this revision to Diff 434838.
simon_tatham added a comment.
Added tests with `extern "C"`, at @lenary's (offline) suggestion.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D127197/new/
https://reviews.llvm.org/D127197
Files:
clang/lib/CodeGen/ABIInfo.h
clang/lib/CodeGen/TargetInfo.cpp
clang/test/CodeGen/homogeneous-aggregates.c
Index: clang/test/CodeGen/homogeneous-aggregates.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/homogeneous-aggregates.c
@@ -0,0 +1,95 @@
+// REQUIRES: arm-registered-target,aarch64-registered-target,powerpc-registered-target
+// RUN: %clang_cc1 -triple thumbv7-none-none -mfloat-abi hard -x c -emit-llvm -o - %s | FileCheck %s --check-prefix=AAPCS
+// RUN: %clang_cc1 -triple thumbv7-none-none -mfloat-abi hard -x c++ -emit-llvm -o - %s | FileCheck %s --check-prefix=AAPCS
+// RUN: %clang_cc1 -triple thumbv7-none-none -mfloat-abi hard -x c++ -DEXTERN_C -emit-llvm -o - %s | FileCheck %s --check-prefix=AAPCS
+// RUN: %clang_cc1 -triple aarch64-none-none -mfloat-abi hard -x c -emit-llvm -o - %s | FileCheck %s --check-prefix=AAPCS
+// RUN: %clang_cc1 -triple aarch64-none-none -mfloat-abi hard -x c++ -emit-llvm -o - %s | FileCheck %s --check-prefix=AAPCS
+// RUN: %clang_cc1 -triple aarch64-none-none -mfloat-abi hard -x c++ -DEXTERN_C -emit-llvm -o - %s | FileCheck %s --check-prefix=AAPCS
+// RUN: %clang_cc1 -triple powerpc64le-none-none -mfloat-abi hard -x c -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC --check-prefix=PPC-C
+// RUN: %clang_cc1 -triple powerpc64le-none-none -mfloat-abi hard -x c++ -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC --check-prefix=PPC-CXX
+// RUN: %clang_cc1 -triple powerpc64le-none-none -mfloat-abi hard -x c++ -DEXTERN_C -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC --check-prefix=PPC-CXX
+
+// The aim here is to test whether each of these structure types is
+// regarded as a homogeneous aggregate of a single kind of
+// floating-point item, because in all of these ABIs, that changes the
+// calling convention.
+//
+// We expect that 'Floats' and 'Doubles' are homogeneous, and 'Mixed'
+// is not. But the next two structures, with separating zero-size
+// bitfields, are more interesting.
+//
+// For the Arm architecture, AAPCS says that the homogeneity rule is
+// applied _after_ data layout is completed, so that it's unaffected
+// by anything that was completely discarded during data layout. So we
+// expect that FloatsBF and DoublesBF still count as homogeneous.
+//
+// But on PowerPC, it depends on whether the source language is C or
+// C++, because that's consistent with the decisions gcc makes.
+
+struct Floats {
+ float a;
+ float b;
+};
+
+struct Doubles {
+ double a;
+ double b;
+};
+
+struct Mixed {
+ double a;
+ float b;
+};
+
+struct FloatsBF {
+ float a;
+ int : 0;
+ float b;
+};
+
+struct DoublesBF {
+ double a;
+ int : 0;
+ double b;
+};
+
+// In C++ mode, we test both with and without extern "C", to ensure
+// that doesn't make a difference.
+#ifdef EXTERN_C
+#define LINKAGE extern "C"
+#else
+#define LINKAGE
+#endif
+
+// For Arm backends, the IR emitted for the homogeneous-aggregate
+// return convention uses the actual structure type, so that
+// HandleFloats returns a %struct.Floats, and so on. To check that
+// 'Mixed' is not treated as homogeneous, it's enough to check that
+// its return type is _not_ %struct.Mixed. (The fallback handling
+// varies between AArch32 and AArch64.)
+//
+// For PowerPC, homogeneous structure types are lowered to an IR array
+// types like [2 x float], and the non-homogeneous Mixed is lowered to
+// a pair of i64.
+
+// AAPCS: define{{.*}} %struct.Floats @{{.*HandleFloats.*}}
+// PPC: define{{.*}} [2 x float] @{{.*HandleFloats.*}}
+LINKAGE struct Floats HandleFloats(struct Floats x) { return x; }
+
+// AAPCS: define{{.*}} %struct.Doubles @{{.*HandleDoubles.*}}
+// PPC: define{{.*}} [2 x double] @{{.*HandleDoubles.*}}
+LINKAGE struct Doubles HandleDoubles(struct Doubles x) { return x; }
+
+// AAPCS-NOT: define{{.*}} %struct.Mixed @{{.*HandleMixed.*}}
+// PPC: define{{.*}} { i64, i64 } @{{.*HandleMixed.*}}
+LINKAGE struct Mixed HandleMixed(struct Mixed x) { return x; }
+
+// AAPCS: define{{.*}} %struct.FloatsBF @{{.*HandleFloatsBF.*}}
+// PPC-C-NOT: define{{.*}} [2 x float] @{{.*HandleFloatsBF.*}}
+// PPC-CXX: define{{.*}} [2 x float] @{{.*HandleFloatsBF.*}}
+LINKAGE struct FloatsBF HandleFloatsBF(struct FloatsBF x) { return x; }
+
+// AAPCS: define{{.*}} %struct.DoublesBF @{{.*HandleDoublesBF.*}}
+// PPC-C-NOT: define{{.*}} [2 x double] @{{.*HandleDoublesBF.*}}
+// PPC-CXX: define{{.*}} [2 x double] @{{.*HandleDoublesBF.*}}
+LINKAGE struct DoublesBF HandleDoublesBF(struct DoublesBF x) { return x; }
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -240,6 +240,11 @@
return false;
}
+bool ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() const {
+ // For compatibility with GCC, ignore empty bitfields in C++ mode.
+ return getContext().getLangOpts().CPlusPlus;
+}
+
LLVM_DUMP_METHOD void ABIArgInfo::dump() const {
raw_ostream &OS = llvm::errs();
OS << "(ABIArgInfo Kind=";
@@ -5213,8 +5218,7 @@
if (isEmptyRecord(getContext(), FT, true))
continue;
- // For compatibility with GCC, ignore empty bitfields in C++ mode.
- if (getContext().getLangOpts().CPlusPlus &&
+ if (isZeroLengthBitfieldPermittedInHomogeneousAggregate() &&
FD->isZeroLengthBitField(getContext()))
continue;
@@ -5511,6 +5515,7 @@
bool isHomogeneousAggregateBaseType(QualType Ty) const override;
bool isHomogeneousAggregateSmallEnough(const Type *Ty,
uint64_t Members) const override;
+ bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const override;
bool isIllegalVectorType(QualType Ty) const;
@@ -5970,6 +5975,16 @@
return Members <= 4;
}
+bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate()
+ const {
+ // AAPCS64 says that the rule for whether something is a homogeneous
+ // aggregate is applied to the output of the data layout decision. So
+ // anything that doesn't affect the data layout also does not affect
+ // homogeneity. In particular, zero-length bitfields don't stop a struct
+ // being homogeneous.
+ return true;
+}
+
Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
ABIArgInfo AI = classifyArgumentType(Ty, /*IsVariadic=*/true,
@@ -6339,6 +6354,7 @@
bool isHomogeneousAggregateBaseType(QualType Ty) const override;
bool isHomogeneousAggregateSmallEnough(const Type *Ty,
uint64_t Members) const override;
+ bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const override;
bool isEffectivelyAAPCS_VFP(unsigned callConvention, bool acceptHalf) const;
@@ -7002,6 +7018,15 @@
return Members <= 4;
}
+bool ARMABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() const {
+ // AAPCS32 says that the rule for whether something is a homogeneous
+ // aggregate is applied to the output of the data layout decision. So
+ // anything that doesn't affect the data layout also does not affect
+ // homogeneity. In particular, zero-length bitfields don't stop a struct
+ // being homogeneous.
+ return true;
+}
+
bool ARMABIInfo::isEffectivelyAAPCS_VFP(unsigned callConvention,
bool acceptHalf) const {
// Give precedence to user-specified calling conventions.
Index: clang/lib/CodeGen/ABIInfo.h
===================================================================
--- clang/lib/CodeGen/ABIInfo.h
+++ clang/lib/CodeGen/ABIInfo.h
@@ -100,6 +100,7 @@
virtual bool isHomogeneousAggregateSmallEnough(const Type *Base,
uint64_t Members) const;
+ virtual bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const;
bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
uint64_t &Members) const;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits