forked from OSchip/llvm-project
CodeGen: Use the initing member's type for a union's storage type more often
Unions are initialized with the default initialization of their first named member. If that member is not zero initialized, then we should prefer that member's type. Otherwise, we might try to make an otherwise unsuitable type (like an array) which we cannot easily initialize with a pointer to member. llvm-svn: 219781
This commit is contained in:
parent
2e29b40d5e
commit
b00ddf31b2
clang
|
@ -279,6 +279,8 @@ void CGRecordLowering::lower(bool NVBaseType) {
|
||||||
void CGRecordLowering::lowerUnion() {
|
void CGRecordLowering::lowerUnion() {
|
||||||
CharUnits LayoutSize = Layout.getSize();
|
CharUnits LayoutSize = Layout.getSize();
|
||||||
llvm::Type *StorageType = nullptr;
|
llvm::Type *StorageType = nullptr;
|
||||||
|
bool SeenNamedMember = false;
|
||||||
|
bool InitializingMemberIsNonZero = false;
|
||||||
// Compute zero-initializable status.
|
// Compute zero-initializable status.
|
||||||
if (!D->field_empty() && !isZeroInitializable(*D->field_begin()))
|
if (!D->field_empty() && !isZeroInitializable(*D->field_begin()))
|
||||||
IsZeroInitializable = IsZeroInitializableAsBase = false;
|
IsZeroInitializable = IsZeroInitializableAsBase = false;
|
||||||
|
@ -299,11 +301,24 @@ void CGRecordLowering::lowerUnion() {
|
||||||
}
|
}
|
||||||
Fields[Field->getCanonicalDecl()] = 0;
|
Fields[Field->getCanonicalDecl()] = 0;
|
||||||
llvm::Type *FieldType = getStorageType(Field);
|
llvm::Type *FieldType = getStorageType(Field);
|
||||||
|
// This union might not be zero initialized: it may contain a pointer to
|
||||||
|
// data member which might have some exotic initialization sequence.
|
||||||
|
// If this is the case, then we aught not to try and come up with a "better"
|
||||||
|
// type, it might not be very easy to come up with a Constant which
|
||||||
|
// correctly initializes it.
|
||||||
|
if (!SeenNamedMember && Field->getDeclName()) {
|
||||||
|
SeenNamedMember = true;
|
||||||
|
if (!isZeroInitializable(Field)) {
|
||||||
|
InitializingMemberIsNonZero = true;
|
||||||
|
StorageType = FieldType;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Conditionally update our storage type if we've got a new "better" one.
|
// Conditionally update our storage type if we've got a new "better" one.
|
||||||
if (!StorageType ||
|
if (!StorageType ||
|
||||||
getAlignment(FieldType) > getAlignment(StorageType) ||
|
getAlignment(FieldType) > getAlignment(StorageType) ||
|
||||||
(getAlignment(FieldType) == getAlignment(StorageType) &&
|
(getAlignment(FieldType) == getAlignment(StorageType) &&
|
||||||
getSize(FieldType) > getSize(StorageType)))
|
getSize(FieldType) > getSize(StorageType)))
|
||||||
|
if (!InitializingMemberIsNonZero)
|
||||||
StorageType = FieldType;
|
StorageType = FieldType;
|
||||||
}
|
}
|
||||||
// If we have no storage type just pad to the appropriate size and return.
|
// If we have no storage type just pad to the appropriate size and return.
|
||||||
|
|
|
@ -268,4 +268,13 @@ B b;
|
||||||
// CHECK-GLOBAL: @_ZN7PR210891bE = global %"struct.PR21089::B" { %"struct.PR21089::A.base" <{ i8 0, [7 x i8] zeroinitializer, i64 -1, i8 0 }>, [7 x i8] zeroinitializer }, align 8
|
// CHECK-GLOBAL: @_ZN7PR210891bE = global %"struct.PR21089::B" { %"struct.PR21089::A.base" <{ i8 0, [7 x i8] zeroinitializer, i64 -1, i8 0 }>, [7 x i8] zeroinitializer }, align 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PR21282 {
|
||||||
|
union U {
|
||||||
|
int U::*x;
|
||||||
|
long y[2];
|
||||||
|
};
|
||||||
|
U u;
|
||||||
|
// CHECK-GLOBAL: @_ZN7PR212821uE = global %"union.PR21282::U" { i64 -1, [8 x i8] zeroinitializer }, align 8
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }
|
// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }
|
||||||
|
|
Loading…
Reference in New Issue