https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/96422
>From 7fb44b1cd3ffac0a0f509cefa3a141dac50da142 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 21 Jun 2024 12:15:07 +0100 Subject: [PATCH 1/8] [clang][CGRecordLayout] Remove dependency on isZeroSize This is a follow-up from the conversation starting at https://github.com/llvm/llvm-project/pull/93809#issuecomment-2173729801 The root problem that motivated the change are external AST sources that compute `ASTRecordLayout`s themselves instead of letting Clang compute them from the AST. One such examples is LLDB using DWARF to get the definitive offsets and sizes of C++ structures. Such layouts should be considered correct (modulo buggy DWARF), but various assertions and lowering logic around the `CGRecordLayoutBuilder` relies on the AST having `[[no_unique_address]]` attached to them. This is a layout-altering attribute which is not encoded in DWARF. This causes us LLDB to trip over the various LLVM<->Clang layout consistency checks. There has been precedent for avoiding such layout-altering attributes to affect lowering with externally-provided layouts (e.g., packed structs). This patch proposes to replace the `isZeroSize` checks in `CGRecordLayoutBuilder` (which roughly means "empty field with [[no_unique_address]]") with checks for `CodeGen::isEmptyField`/`CodeGen::isEmptyRecord`. --- clang/lib/CodeGen/ABIInfoImpl.cpp | 6 ++--- clang/lib/CodeGen/ABIInfoImpl.h | 6 ++--- clang/lib/CodeGen/CGExpr.cpp | 3 ++- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 14 ++++++------ clang/test/CodeGen/X86/x86_64-vaarg.c | 3 ++- clang/test/CodeGen/debug-info-packed-struct.c | 2 +- clang/test/CodeGen/paren-list-agg-init.cpp | 15 +++++-------- .../CodeGenCXX/2011-12-19-init-list-ctor.cpp | 6 ++--- clang/test/CodeGenCXX/auto-var-init.cpp | 10 ++++----- .../test/CodeGenCXX/bitfield-access-empty.cpp | 16 +++++++------- clang/test/CodeGenCXX/class-layout.cpp | 2 +- clang/test/CodeGenCXX/compound-literals.cpp | 2 +- clang/test/CodeGenCXX/exceptions.cpp | 7 +++--- .../lambda-deterministic-captures.cpp | 4 +--- clang/test/CodeGenCXX/ms_struct.cpp | 4 +--- clang/test/CodeGenCXX/partial-destruction.cpp | 11 ++++------ clang/test/CodeGenCXX/pr18962.cpp | 5 ++--- clang/test/CodeGenCXX/references.cpp | 4 +--- clang/test/CodeGenCXX/temporaries.cpp | 12 +++++----- clang/test/CodeGenObjCXX/lambda-to-block.mm | 9 ++++---- clang/test/OpenMP/irbuilder_for_iterator.cpp | 10 ++++----- clang/test/OpenMP/irbuilder_for_rangefor.cpp | 14 +++++------- .../test/OpenMP/task_member_call_codegen.cpp | 22 ++++++++----------- clang/test/Sema/ms_class_layout.cpp | 14 ++---------- 24 files changed, 85 insertions(+), 116 deletions(-) diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index e9a26abb778375..92fcc3bc2c5f4c 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -248,7 +248,7 @@ Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1, return Address(PHI, Addr1.getElementType(), Align); } -bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, +bool CodeGen::isEmptyField(const ASTContext &Context, const FieldDecl *FD, bool AllowArrays, bool AsIfNoUniqueAddr) { if (FD->isUnnamedBitField()) return true; @@ -289,8 +289,8 @@ bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr); } -bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, - bool AsIfNoUniqueAddr) { +bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T, + bool AllowArrays, bool AsIfNoUniqueAddr) { const RecordType *RT = T->getAs<RecordType>(); if (!RT) return false; diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h index 92986fb4316465..e3f373e39c35a5 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.h +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -126,15 +126,15 @@ Address emitMergePHI(CodeGenFunction &CGF, Address Addr1, /// is an unnamed bit-field or an (array of) empty record(s). If /// AsIfNoUniqueAddr is true, then C++ record fields are considered empty if /// the [[no_unique_address]] attribute would have made them empty. -bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays, - bool AsIfNoUniqueAddr = false); +bool isEmptyField(const ASTContext &Context, const FieldDecl *FD, + bool AllowArrays, bool AsIfNoUniqueAddr = false); /// isEmptyRecord - Return true iff a structure contains only empty /// fields. Note that a structure with a flexible array member is not /// considered empty. If AsIfNoUniqueAddr is true, then C++ record fields are /// considered empty if the [[no_unique_address]] attribute would have made /// them empty. -bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, +bool isEmptyRecord(const ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr = false); /// isSingleElementStruct - Determine if a structure is a "single diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 23e5deee325813..f7e417443cc585 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "ABIInfoImpl.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGCall.h" @@ -4762,7 +4763,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base, /// The resulting address doesn't necessarily have the right type. static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base, const FieldDecl *field) { - if (field->isZeroSize(CGF.getContext())) + if (isEmptyField(CGF.getContext(), field, false, true)) return emitAddrOfZeroSizeField(CGF, base, field); const RecordDecl *rec = field->getParent(); diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 5169be204c14d0..8f3e0f16f93a6d 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "CGRecordLayout.h" +#include "ABIInfoImpl.h" #include "CGCXXABI.h" #include "CodeGenTypes.h" #include "clang/AST/ASTContext.h" @@ -384,7 +384,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) { Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd); assert((Field == FieldEnd || !Field->isBitField()) && "Failed to accumulate all the bitfields"); - } else if (Field->isZeroSize(Context)) { + } else if (isEmptyField(Context, *Field, false, true)) { // Empty fields have no storage. ++Field; } else { @@ -634,7 +634,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, // non-reusable tail padding. CharUnits LimitOffset; for (auto Probe = Field; Probe != FieldEnd; ++Probe) - if (!Probe->isZeroSize(Context)) { + if (!isEmptyField(Context, *Probe, false, true)) { // A member with storage sets the limit. assert((getFieldBitOffset(*Probe) % CharBits) == 0 && "Next storage is not byte-aligned"); @@ -732,7 +732,7 @@ void CGRecordLowering::accumulateBases() { // Bases can be zero-sized even if not technically empty if they // contain only a trailing array member. const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (!BaseDecl->isEmpty() && + if (!isEmptyRecord(Context, Base.getType(), false, true) && !Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl), MemberInfo::Base, getStorageType(BaseDecl), BaseDecl)); @@ -880,7 +880,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { if (!isNonVirtualBaseType && isOverlappingVBaseABI()) for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (BaseDecl->isEmpty()) + if (isEmptyRecord(Context, Base.getType(), false, true)) continue; // If the vbase is a primary virtual base of some base, then it doesn't // get its own storage location but instead lives inside of that base. @@ -896,7 +896,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { void CGRecordLowering::accumulateVBases() { for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (BaseDecl->isEmpty()) + if (isEmptyRecord(Context, Base.getType(), false, true)) continue; CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl); // If the vbase is a primary virtual base of some base, then it doesn't @@ -1162,7 +1162,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { const FieldDecl *FD = *it; // Ignore zero-sized fields. - if (FD->isZeroSize(getContext())) + if (isEmptyField(Context, FD, false, true)) continue; // For non-bit-fields, just check that the LLVM struct offset matches the diff --git a/clang/test/CodeGen/X86/x86_64-vaarg.c b/clang/test/CodeGen/X86/x86_64-vaarg.c index d6b885d9fb18c3..7d5102f93ca6f0 100644 --- a/clang/test/CodeGen/X86/x86_64-vaarg.c +++ b/clang/test/CodeGen/X86/x86_64-vaarg.c @@ -56,7 +56,8 @@ typedef struct { // CHECK: vaarg.end: // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP1]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 8, i1 false) -// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[RETVAL]], align 8 +// CHECK-NEXT: [[COERCE:%.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[RETVAL]], i32 0, i32 0 +// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[COERCE]], align 8 // CHECK-NEXT: ret double [[TMP3]] // s1 f(int z, ...) { diff --git a/clang/test/CodeGen/debug-info-packed-struct.c b/clang/test/CodeGen/debug-info-packed-struct.c index 676cdb38b396f2..33b8b4c7e13fb6 100644 --- a/clang/test/CodeGen/debug-info-packed-struct.c +++ b/clang/test/CodeGen/debug-info-packed-struct.c @@ -2,7 +2,7 @@ // CHECK: %struct.layout3 = type <{ i8, [3 x i8], %struct.size8_pack4, i8, [3 x i8] }> // CHECK: %struct.layout0 = type { i8, %struct.size8, i8 } -// CHECK: %struct.layout1 = type <{ i8, %struct.size8_anon, i8, [2 x i8] }> +// CHECK: %struct.layout1 = type { i8, [8 x i8], i8, [2 x i8] } // CHECK: %struct.layout2 = type <{ i8, %struct.size8_pack1, i8 }> // --------------------------------------------------------------------- diff --git a/clang/test/CodeGen/paren-list-agg-init.cpp b/clang/test/CodeGen/paren-list-agg-init.cpp index 88b1834d42d879..16cfe772a4ae59 100644 --- a/clang/test/CodeGen/paren-list-agg-init.cpp +++ b/clang/test/CodeGen/paren-list-agg-init.cpp @@ -48,14 +48,13 @@ struct E { ~E() {}; }; -// CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 } struct F { F (int i = 1); F (const F &f) = delete; F (F &&f) = default; }; -// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [[STRUCT_F]], [3 x i8] }> +// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [4 x i8] }> struct G { int a; F f; @@ -78,12 +77,12 @@ namespace gh61145 { ~Vec(); }; - // CHECK-DAG: [[STRUCT_S1:%.*]] = type { [[STRUCT_VEC]] } + // CHECK-DAG: [[STRUCT_S1:%.*]] = type { i8 } struct S1 { Vec v; }; - // CHECK-DAG: [[STRUCT_S2:%.*]] = type { [[STRUCT_VEC]], i8 } + // CHECK-DAG: [[STRUCT_S2:%.*]] = type { i8, i8 } struct S2 { Vec v; char c; @@ -377,7 +376,7 @@ void foo18() { // CHECK-NEXT: [[G:%.*g.*]] = alloca [[STRUCT_G]], align 4 // CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 0 // CHECK-NEXT: store i32 2, ptr [[A]], align 4 -// CHECK-NEXT: [[F:%.*f.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 1 +// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds i8, ptr [[G]], i64 4 // CHECk-NEXT: call void @{{.*F.*}}(ptr noundef nonnull align 1 dereferenceable(1)) [[F]], ie32 noundef 1) // CHECK: ret void void foo19() { @@ -392,9 +391,8 @@ namespace gh61145 { // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S1]], align 1 // a.k.a. Vec::Vec() // CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]]) - // CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0 // a.k.a. Vec::Vec(Vec&&) - // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]]) + // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]]) // a.k.a. S1::~S1() // CHECK-NEXT: call void @_ZN7gh611452S1D1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]) // a.k.a.Vec::~Vec() @@ -413,9 +411,8 @@ namespace gh61145 { // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S2]], align 1 // a.k.a. Vec::Vec() // CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]]) - // CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0 // a.k.a. Vec::Vec(Vec&&) - // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]]) + // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]]) // CHECK-NEXT: [[C:%.*c.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 // CHECK-NEXT: store i8 0, ptr [[C]], align 1 // a.k.a. S2::~S2() diff --git a/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp b/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp index 14557829268efd..3efb8c449c8fa9 100644 --- a/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp +++ b/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp @@ -19,8 +19,8 @@ struct S { }; // CHECK: store i32 0, ptr @arr -// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (%struct.S, ptr @arr, i32 0, i32 1), ptr noundef @.str) +// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (i8, ptr @arr, i64 4), ptr noundef @.str) // CHECK: store i32 1, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 1) -// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (%struct.S, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 1), i32 0, i32 1), ptr noundef @.str.1) +// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (i8, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 1), i64 4), ptr noundef @.str.1) // CHECK: store i32 2, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 2) -// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (%struct.S, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 2), i32 0, i32 1), ptr noundef @.str.2) +// CHECK: call void @_ZN1AC1EPKc(ptr {{[^,]*}} getelementptr inbounds (i8, ptr getelementptr inbounds (%struct.S, ptr @arr, i64 2), i64 4), ptr noundef @.str.2) diff --git a/clang/test/CodeGenCXX/auto-var-init.cpp b/clang/test/CodeGenCXX/auto-var-init.cpp index e697731b0cdf1e..d3328771cb0948 100644 --- a/clang/test/CodeGenCXX/auto-var-init.cpp +++ b/clang/test/CodeGenCXX/auto-var-init.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=PATTERN,PATTERN-O1 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,ZERO,ZERO-O0 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=ZERO,ZERO-O1 -// RUN: %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0 +// TODO %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0 #pragma clang diagnostic ignored "-Winaccessible-base" @@ -166,14 +166,14 @@ struct semivolatileinit { int i = 0x11111111; volatile int vi = 0x11111111; }; // PATTERN-O0: @__const.test_base_braces.braces = private unnamed_addr constant %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, align // PATTERN-O1-NOT: @__const.test_base_braces.braces struct base { virtual ~base(); }; -// PATTERN-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } }, align +// PATTERN-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_derived_uninit.uninit -// PATTERN-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } }, align +// PATTERN-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_derived_braces.braces struct derived : public base {}; -// PATTERN-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } } }, align +// PATERN-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_virtualderived_uninit.uninit -// PATTERN-O0: @__const.test_virtualderived_braces.braces = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, %struct.derived { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } } }, align +// PATTERN-O0: @__const.test_virtualderived_braces.braces = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_virtualderived_braces.braces struct virtualderived : public virtual base, public virtual derived {}; // PATTERN-O0: @__const.test_matching_uninit.uninit = private unnamed_addr constant %union.matching { i32 [[I32]] }, align 4 diff --git a/clang/test/CodeGenCXX/bitfield-access-empty.cpp b/clang/test/CodeGenCXX/bitfield-access-empty.cpp index c5e6f55ffa6964..4922ed1e7f3de8 100644 --- a/clang/test/CodeGenCXX/bitfield-access-empty.cpp +++ b/clang/test/CodeGenCXX/bitfield-access-empty.cpp @@ -84,8 +84,8 @@ struct P3 { unsigned b : 16; } p3; // CHECK-LABEL: LLVMType:%struct.P3 = -// LAYOUT-SAME: type { i16, %struct.Empty, i16, [2 x i8] } -// LAYOUT-DWN32-SAME: type <{ i16, %struct.Empty, i16 }> +// LAYOUT-SAME: type { i16, [2 x i8], i16, [2 x i8] } +// LAYOUT-DWN32-SAME: type <{ i16, i8, i16 }> // CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P3 = // CHECK: BitFields:[ // LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:16 IsSigned:0 StorageSize:16 StorageOffset:0 @@ -138,13 +138,13 @@ struct P7 { unsigned c; } p7; // CHECK-LABEL: LLVMType:%struct.P7 = -// LAYOUT-SAME: type { i16, i8, %struct.Empty, i32 } -// LAYOUT-DWN32-SAME: type { i16, i8, %struct.Empty, i32 } +// LAYOUT-SAME: type { i32, i32 } +// LAYOUT-DWN32-SAME: type { i32, i32 } // CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P7 = // CHECK: BitFields:[ -// LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:16 IsSigned:0 StorageSize:16 StorageOffset:0 -// LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:8 IsSigned:0 StorageSize:8 StorageOffset:2 +// LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:16 IsSigned:0 StorageSize:32 StorageOffset:0 +// LAYOUT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:8 IsSigned:0 StorageSize:32 StorageOffset:0 -// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:16 IsSigned:0 StorageSize:16 StorageOffset:0 -// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:8 IsSigned:0 StorageSize:8 StorageOffset:2 +// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:16 IsSigned:0 StorageSize:32 StorageOffset:0 +// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:8 IsSigned:0 StorageSize:32 StorageOffset:0 // CHECK-NEXT: ]> diff --git a/clang/test/CodeGenCXX/class-layout.cpp b/clang/test/CodeGenCXX/class-layout.cpp index 84b0f887876ac5..90617d25b254ee 100644 --- a/clang/test/CodeGenCXX/class-layout.cpp +++ b/clang/test/CodeGenCXX/class-layout.cpp @@ -83,7 +83,7 @@ namespace Test6 { namespace Test7 { #pragma pack (1) class A {}; - // CHECK: %"class.Test7::B" = type <{ ptr, %"class.Test7::A" }> + // CHECK: %"class.Test7::B" = type <{ ptr, i8 }> class B { virtual ~B(); A a; diff --git a/clang/test/CodeGenCXX/compound-literals.cpp b/clang/test/CodeGenCXX/compound-literals.cpp index fcec2d19e2def0..1b4a1d4445123e 100644 --- a/clang/test/CodeGenCXX/compound-literals.cpp +++ b/clang/test/CodeGenCXX/compound-literals.cpp @@ -20,7 +20,7 @@ int f() { // CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}, ptr [[LVALUE]], i32 0, i32 0 // CHECK-NEXT: store i32 17, ptr [[I]] - // CHECK-NEXT: [[X:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 1 + // CHECK-NEXT: [[X:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 4 // CHECK-NEXT: call noundef ptr @_ZN1XC1EPKc({{.*}}[[X]] // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 0 // CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = load i32, ptr diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp index e8179f9828fb6b..1f4d2f061a43d4 100644 --- a/clang/test/CodeGenCXX/exceptions.cpp +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -513,8 +513,7 @@ namespace test11 { // CHECK-LABEL: define{{.*}} void @_ZN6test111CC2Ev( // CHECK: [[THIS:%.*]] = load ptr, ptr {{%.*}} // Construct single. - // CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[C:%.*]], ptr [[THIS]], i32 0, i32 0 - // CHECK-NEXT: call void @_ZN6test111AC1Ev(ptr {{[^,]*}} [[SINGLE]]) + // CHECK-NEXT: call void @_ZN6test111AC1Ev(ptr {{[^,]*}} [[THIS]]) // Construct array. // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[C:%.*]], ptr [[THIS]], i32 0, i32 1 // CHECK-NEXT: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x [[A:%.*]]]], ptr [[ARRAY]], i32 0, i32 0, i32 0 @@ -560,8 +559,8 @@ namespace test11 { // CHECK: br label // Finally, the cleanup for single. - // CHECK98: invoke void @_ZN6test111AD1Ev(ptr {{[^,]*}} [[SINGLE]]) - // CHECK11: call void @_ZN6test111AD1Ev(ptr {{[^,]*}} [[SINGLE]]) + // CHECK98: invoke void @_ZN6test111AD1Ev(ptr {{[^,]*}} [[THIS]]) + // CHECK11: call void @_ZN6test111AD1Ev(ptr {{[^,]*}} [[THIS]]) // CHECK: br label // CHECK: resume diff --git a/clang/test/CodeGenCXX/lambda-deterministic-captures.cpp b/clang/test/CodeGenCXX/lambda-deterministic-captures.cpp index 6236ff2ca66cb7..5f14e3977db00c 100644 --- a/clang/test/CodeGenCXX/lambda-deterministic-captures.cpp +++ b/clang/test/CodeGenCXX/lambda-deterministic-captures.cpp @@ -16,8 +16,7 @@ void foo() { } // CHECK: define{{.*}} void @_Z3foov -// CHECK: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 0 -// CHECK-NEXT: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 1 +// CHECK: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 1 // CHECK-NEXT: store float 0.000 // CHECK-NEXT: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 2 // CHECK-NEXT: store float 1.000 @@ -27,7 +26,6 @@ void foo() { // The lambda body. Reverse iteration when the captures aren't deterministic // causes these to be laid out differently in the lambda. // CHECK: define internal void -// CHECK: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 0 // CHECK: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 1 // CHECK: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 2 // CHECK: getelementptr inbounds %{{.+}}, ptr %{{.+}}, i32 0, i32 3 diff --git a/clang/test/CodeGenCXX/ms_struct.cpp b/clang/test/CodeGenCXX/ms_struct.cpp index 1995e3155bd55e..325715e550c580 100644 --- a/clang/test/CodeGenCXX/ms_struct.cpp +++ b/clang/test/CodeGenCXX/ms_struct.cpp @@ -18,9 +18,7 @@ struct ATTR Derived : Base { int value; }; -// CHECK: [[DERIVED:%.*]] = type <{ [[BASE:%.*]], i32, [4 x i8] }> -// CHECK: [[BASE]] = type { [[VBASE:%.*]] } -// CHECK: [[VBASE]] = type { ptr } +// CHECK: [[DERIVED:%.*]] = type { [8 x i8], i32, [4 x i8] } // CHECK: define{{.*}} void @_ZN7DerivedC2Ev // CHECK: [[SELF:%.*]] = load ptr diff --git a/clang/test/CodeGenCXX/partial-destruction.cpp b/clang/test/CodeGenCXX/partial-destruction.cpp index 8ceb4b9bbedeaa..edb3734cc1a2a1 100644 --- a/clang/test/CodeGenCXX/partial-destruction.cpp +++ b/clang/test/CodeGenCXX/partial-destruction.cpp @@ -107,13 +107,12 @@ namespace test1 { // CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4 // CHECK-NEXT: alloca ptr // CHECK-NEXT: alloca i32 - // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[B]], ptr [[V]], i32 0, i32 0 - // CHECK-NEXT: call void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[X]], i32 noundef 5) - // CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds [[B]], ptr [[V]], i32 0, i32 1 + // CHECK-NEXT: call void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[V]], i32 noundef 5) + // CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds i8, ptr [[V]], i64 1 // CHECK-NEXT: invoke void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[Y]], i32 noundef 6) - // CHECK: [[Z:%.*]] = getelementptr inbounds [[B]], ptr [[V]], i32 0, i32 2 + // CHECK: [[Z:%.*]] = getelementptr inbounds i8, ptr [[V]], i64 2 // CHECK-NEXT: invoke void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[Z]], i32 noundef 7) - // CHECK: [[W:%.*]] = getelementptr inbounds [[B]], ptr [[V]], i32 0, i32 3 + // CHECK: [[W:%.*]] = getelementptr inbounds [[B]], ptr [[V]], i32 0, i32 1 // CHECK-NEXT: store i32 8, ptr [[W]], align 4 // CHECK-NEXT: call void @_ZN5test11BD1Ev(ptr {{[^,]*}} [[V]]) // CHECK-NEXT: ret void @@ -124,9 +123,7 @@ namespace test1 { // CHECK: landingpad { ptr, i32 } // CHECK-NEXT: cleanup // CHECKv03: invoke void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[Y]]) - // CHECKv03: invoke void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[X]]) // CHECKv11: call void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[Y]]) - // CHECKv11: call void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[X]]) } namespace test2 { diff --git a/clang/test/CodeGenCXX/pr18962.cpp b/clang/test/CodeGenCXX/pr18962.cpp index b564a7b9a73afd..9ac87003c94c57 100644 --- a/clang/test/CodeGenCXX/pr18962.cpp +++ b/clang/test/CodeGenCXX/pr18962.cpp @@ -23,7 +23,6 @@ D p3; // We end up using an opaque type for 'append' to avoid circular references. // CHECK: %class.A = type { ptr } -// CHECK: %class.C = type <{ ptr, %class.B, [3 x i8] }> -// CHECK: %class.B = type { i8 } +// CHECK: %class.C = type <{ ptr, [4 x i8] }> // CHECK: %class.D = type { %class.C.base, [3 x i8] } -// CHECK: %class.C.base = type <{ ptr, %class.B }> +// CHECK: %class.C.base = type <{ ptr, i8 }> diff --git a/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp index 0fca5e76659c2f..b84cb788d161c3 100644 --- a/clang/test/CodeGenCXX/references.cpp +++ b/clang/test/CodeGenCXX/references.cpp @@ -191,7 +191,6 @@ namespace N2 { // CHECK-LABEL: define{{.*}} void @_ZN2N21fEi // CHECK: call void @_ZN2N24getPEv - // CHECK: getelementptr inbounds // CHECK: store i32 17 // CHECK: call void @_ZN2N21PD1Ev void f(int i) { @@ -220,8 +219,7 @@ namespace N2 { // CHECK-LABEL: define{{.*}} void @_ZN2N21gEi // CHECK: call void @_ZN2N24getZEv - // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} - // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: {{getelementptr inbounds.*i64 16}} // CHECK: store i32 19 // CHECK: call void @_ZN2N21ZD1Ev // CHECK: ret void diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp index f992ce206c5815..9f697bd9bf3efc 100644 --- a/clang/test/CodeGenCXX/temporaries.cpp +++ b/clang/test/CodeGenCXX/temporaries.cpp @@ -715,7 +715,7 @@ namespace MultipleExtension { // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev, {{.*}} @[[TEMPA]] // CHECK: store {{.*}} @[[TEMPA]], {{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], - // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1)) + // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i64 8)) // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]]) // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev, {{.*}} @[[TEMPD]] @@ -729,7 +729,7 @@ namespace MultipleExtension { // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev, {{.*}} @[[TEMPA]] // CHECK: store {{.*}} @[[TEMPA]], {{.*}} @[[E:_ZN17MultipleExtension2e2E]] - // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1)) + // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i64 8)) // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]]) // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev, {{.*}} @[[TEMPD]] @@ -744,11 +744,11 @@ namespace MultipleExtension { // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0 // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]]) // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]] - // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1 + // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i64 8 // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]]) // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2 // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]]) - // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1 + // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i64 4 // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]] // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]] @@ -759,11 +759,11 @@ namespace MultipleExtension { // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0 // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]]) // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]] - // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1 + // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i64 8 // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]]) // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2 // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]]) - // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1 + // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i64 4 // CHECK: store {{.*}} %[[TEMPD2_C]], ptr %[[TEMPE2_C]] g(); diff --git a/clang/test/CodeGenObjCXX/lambda-to-block.mm b/clang/test/CodeGenObjCXX/lambda-to-block.mm index e3ce7104d97bf0..86b540ed52e9ea 100644 --- a/clang/test/CodeGenObjCXX/lambda-to-block.mm +++ b/clang/test/CodeGenObjCXX/lambda-to-block.mm @@ -2,11 +2,10 @@ // Shouldn't crash! -// CHECK: %[[CLASS_ANON:.*]] = type { %[[STRUCT_COPYABLE:.*]] } -// CHECK: %[[STRUCT_COPYABLE]] = type { i8 } -// CHECK: %[[CLASS_ANON_0:.*]] = type { %[[STRUCT_COPYABLE]] } -// CHECK: %[[CLASS_ANON_1:.*]] = type { %[[STRUCT_COPYABLE]] } -// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[STRUCT_COPYABLE]] } +// CHECK: %[[CLASS_ANON:.*]] = type { i8 } +// CHECK: %[[CLASS_ANON_0:.*]] = type { i8 } +// CHECK: %[[CLASS_ANON_1:.*]] = type { i8 } +// CHECK: %[[CLASS_ANON_2:.*]] = type { i8 } // CHECK: @[[BLOCK_DESC0:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 33, ptr @[[COPY_HELPER0:.*__copy_helper_block_.*]], ptr @__destroy_helper_block{{.*}}, {{.*}}}, align 8 // CHECK: @[[BLOCK_DESC1:.*]] = internal constant { i64, i64, ptr, ptr, ptr, ptr } { i64 0, i64 33, ptr @[[COPY_HELPER1:.*__copy_helper_block_.*]], ptr @__destroy_helper_block{{.*}}, {{.*}}}, align 8 diff --git a/clang/test/OpenMP/irbuilder_for_iterator.cpp b/clang/test/OpenMP/irbuilder_for_iterator.cpp index b88416b36c4fa6..99469d62a9fc13 100644 --- a/clang/test/OpenMP/irbuilder_for_iterator.cpp +++ b/clang/test/OpenMP/irbuilder_for_iterator.cpp @@ -48,8 +48,7 @@ extern "C" void workshareloop_iterator(float *a, float *b, float *c) { // CHECK-NEXT: call void @_ZN10MyIteratorC1Ej(ptr noundef nonnull align 1 dereferenceable(1) [[IT]], i32 noundef 7) // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANON]], ptr [[AGG_CAPTURED]], i32 0, i32 0 // CHECK-NEXT: store ptr [[IT]], ptr [[TMP0]], align 8 -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0]], ptr [[AGG_CAPTURED1]], i32 0, i32 0 -// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[TMP1]], ptr noundef nonnull align 1 dereferenceable(1) [[IT]]) +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_CAPTURED1]], ptr noundef nonnull align 1 dereferenceable(1) [[IT]]) // CHECK-NEXT: call void @__captured_stmt(ptr [[DOTCOUNT_ADDR]], ptr [[AGG_CAPTURED]]) // CHECK-NEXT: [[DOTCOUNT:%.*]] = load i64, ptr [[DOTCOUNT_ADDR]], align 8 // CHECK-NEXT: br label [[OMP_LOOP_PREHEADER:%.*]] @@ -155,11 +154,10 @@ extern "C" void workshareloop_iterator(float *a, float *b, float *c) { // CHECK-NEXT: store i64 [[LOGICAL]], ptr [[LOGICAL_ADDR]], align 8 // CHECK-NEXT: store ptr [[__CONTEXT]], ptr [[__CONTEXT_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__CONTEXT_ADDR]], align 8 -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], ptr [[TMP0]], i32 0, i32 0 -// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[LOGICAL_ADDR]], align 8 -// CHECK-NEXT: [[MUL:%.*]] = mul i64 1, [[TMP2]] +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[LOGICAL_ADDR]], align 8 +// CHECK-NEXT: [[MUL:%.*]] = mul i64 1, [[TMP1]] // CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[MUL]] to i32 -// CHECK-NEXT: call void @_ZNK10MyIteratorplEj(ptr dead_on_unwind writable sret([[STRUCT_MYITERATOR]]) align 1 [[REF_TMP]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP1]], i32 noundef [[CONV]]) +// CHECK-NEXT: call void @_ZNK10MyIteratorplEj(ptr dead_on_unwind writable sret([[STRUCT_MYITERATOR]]) align 1 [[REF_TMP]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]], i32 noundef [[CONV]]) // CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[LOOPVAR_ADDR]], align 8 // CHECK-NEXT: [[CALL:%.*]] = call noundef nonnull align 1 dereferenceable(1) ptr @_ZN10MyIteratoraSERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[TMP3]], ptr noundef nonnull align 1 dereferenceable(1) [[REF_TMP]]) // CHECK-NEXT: ret void diff --git a/clang/test/OpenMP/irbuilder_for_rangefor.cpp b/clang/test/OpenMP/irbuilder_for_rangefor.cpp index 6bf91bfda138af..6bf44e2ee41536 100644 --- a/clang/test/OpenMP/irbuilder_for_rangefor.cpp +++ b/clang/test/OpenMP/irbuilder_for_rangefor.cpp @@ -66,8 +66,7 @@ extern "C" void workshareloop_rangefor(float *a, float *b, float *c) { // CHECK-NEXT: store ptr [[__BEGIN2]], ptr [[TMP2]], align 8 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT_ANON]], ptr [[AGG_CAPTURED]], i32 0, i32 1 // CHECK-NEXT: store ptr [[__END2]], ptr [[TMP3]], align 8 -// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_ANON_0]], ptr [[AGG_CAPTURED1]], i32 0, i32 0 -// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[TMP4]], ptr noundef nonnull align 1 dereferenceable(1) [[__BEGIN2]]) +// CHECK-NEXT: call void @_ZN10MyIteratorC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_CAPTURED1]], ptr noundef nonnull align 1 dereferenceable(1) [[__BEGIN2]]) // CHECK-NEXT: call void @__captured_stmt(ptr [[DOTCOUNT_ADDR]], ptr [[AGG_CAPTURED]]) // CHECK-NEXT: [[DOTCOUNT:%.*]] = load i64, ptr [[DOTCOUNT_ADDR]], align 8 // CHECK-NEXT: br label [[OMP_LOOP_PREHEADER:%.*]] @@ -173,13 +172,12 @@ extern "C" void workshareloop_rangefor(float *a, float *b, float *c) { // CHECK-NEXT: store i64 [[LOGICAL]], ptr [[LOGICAL_ADDR]], align 8 // CHECK-NEXT: store ptr [[__CONTEXT]], ptr [[__CONTEXT_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__CONTEXT_ADDR]], align 8 -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ANON_0:%.*]], ptr [[TMP0]], i32 0, i32 0 -// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[LOGICAL_ADDR]], align 8 -// CHECK-NEXT: [[MUL:%.*]] = mul i64 1, [[TMP2]] +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[LOGICAL_ADDR]], align 8 +// CHECK-NEXT: [[MUL:%.*]] = mul i64 1, [[TMP1]] // CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[MUL]] to i32 -// CHECK-NEXT: call void @_ZNK10MyIteratorplEj(ptr dead_on_unwind writable sret([[STRUCT_MYITERATOR]]) align 1 [[REF_TMP]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP1]], i32 noundef [[CONV]]) +// CHECK-NEXT: call void @_ZNK10MyIteratorplEj(ptr dead_on_unwind writable sret([[STRUCT_MYITERATOR]]) align 1 [[REF_TMP]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]], i32 noundef [[CONV]]) // CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK10MyIteratordeEv(ptr noundef nonnull align 1 dereferenceable(1) [[REF_TMP]]) -// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[LOOPVAR_ADDR]], align 8 -// CHECK-NEXT: store i32 [[CALL]], ptr [[TMP3]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[LOOPVAR_ADDR]], align 8 +// CHECK-NEXT: store i32 [[CALL]], ptr [[TMP2]], align 4 // CHECK-NEXT: ret void // diff --git a/clang/test/OpenMP/task_member_call_codegen.cpp b/clang/test/OpenMP/task_member_call_codegen.cpp index b7e0b41b291ec2..c2ab3317ea9bd6 100644 --- a/clang/test/OpenMP/task_member_call_codegen.cpp +++ b/clang/test/OpenMP/task_member_call_codegen.cpp @@ -32,9 +32,8 @@ void c() { // CHECK1-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1:[0-9]+]]) // CHECK1-NEXT: [[TMP1:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @[[GLOB1]], i32 [[TMP0]], i32 1, i64 48, i64 1, ptr @.omp_task_entry.) // CHECK1-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES:%.*]], ptr [[TMP1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], ptr [[TMP1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[STRUCT__KMP_PRIVATES_T:%.*]], ptr [[TMP3]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_omp_task(ptr @[[GLOB1]], i32 [[TMP0]], ptr [[TMP1]]) +// CHECK1-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 40 +// CHECK1-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_omp_task(ptr @[[GLOB1]], i32 [[TMP0]], ptr [[TMP1]]) // CHECK1-NEXT: ret void // // @@ -46,9 +45,8 @@ void c() { // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT__KMP_PRIVATES_T:%.*]], ptr [[TMP2]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 -// CHECK1-NEXT: store ptr [[TMP3]], ptr [[TMP4]], align 8 +// CHECK1-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK1-NEXT: store ptr [[TMP2]], ptr [[TMP3]], align 8 // CHECK1-NEXT: ret void // // @@ -72,7 +70,7 @@ void c() { // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T:%.*]], ptr [[TMP4]], i32 0, i32 2 // CHECK1-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T]], ptr [[TMP4]], i32 0, i32 0 // CHECK1-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8 -// CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], ptr [[TMP3]], i32 0, i32 1 +// CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 40 // CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]]) // CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META6:![0-9]+]]) // CHECK1-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META8:![0-9]+]]) @@ -100,8 +98,7 @@ void c() { // CHECK3-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3:[0-9]+]]) // CHECK3-NEXT: [[TMP0:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @[[GLOB1:[0-9]+]], i32 [[OMP_GLOBAL_THREAD_NUM]], i32 1, i64 48, i64 1, ptr @.omp_task_entry.) // CHECK3-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES:%.*]], ptr [[TMP0]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], ptr [[TMP0]], i32 0, i32 1 -// CHECK3-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT__KMP_PRIVATES_T:%.*]], ptr [[TMP2]], i32 0, i32 0 +// CHECK3-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 40 // CHECK3-NEXT: [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]]) // CHECK3-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_omp_task(ptr @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM1]], ptr [[TMP0]]) // CHECK3-NEXT: ret void @@ -115,9 +112,8 @@ void c() { // CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK3-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 // CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK3-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[STRUCT__KMP_PRIVATES_T:%.*]], ptr [[TMP2]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 -// CHECK3-NEXT: store ptr [[TMP3]], ptr [[TMP4]], align 8 +// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 +// CHECK3-NEXT: store ptr [[TMP2]], ptr [[TMP3]], align 8 // CHECK3-NEXT: ret void // // @@ -141,7 +137,7 @@ void c() { // CHECK3-NEXT: [[TMP5:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T:%.*]], ptr [[TMP4]], i32 0, i32 2 // CHECK3-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T]], ptr [[TMP4]], i32 0, i32 0 // CHECK3-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8 -// CHECK3-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_T_WITH_PRIVATES]], ptr [[TMP3]], i32 0, i32 1 +// CHECK3-NEXT: [[TMP8:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 40 // CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]]) // CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META6:![0-9]+]]) // CHECK3-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META8:![0-9]+]]) diff --git a/clang/test/Sema/ms_class_layout.cpp b/clang/test/Sema/ms_class_layout.cpp index 73382a480f50e4..90b52b5a28532c 100644 --- a/clang/test/Sema/ms_class_layout.cpp +++ b/clang/test/Sema/ms_class_layout.cpp @@ -447,18 +447,8 @@ int main() { // CHECK: %struct.O.base = type { ptr, [4 x i8], %struct.H.base, %struct.G, [4 x i8] } // CHECK: %struct.P = type { %struct.M.base, i32, %struct.K, %struct.L } // CHECK: %struct.R = type { i8 } -// CHECK: %struct.f = type { ptr } -// CHECK: %struct.s = type { ptr, ptr, i32, i32, %struct.f } -// CHECK: %class.IA = type { ptr } -// CHECK: %class.ICh = type { ptr, ptr, i32, %class.IA } -// CHECK: %struct.sd = type { ptr, i32, i8, i32, %struct.f, %struct.s.base, i32, %class.IA, %class.ICh.base } -// CHECK: %struct.AV = type { ptr } -// CHECK: %struct.BV = type { %struct.AV } -// CHECK: %struct.CV = type { ptr, i32, %struct.BV } -// CHECK: %struct.CV.base = type { ptr } -// CHECK: %struct.DV = type { %struct.BV } -// CHECK: %struct.EV = type { %struct.DV, %struct.CV.base, i32, %struct.BV } -// CHECK: %struct.EV.base = type { %struct.DV, %struct.CV.base } +// CHECK: %struct.sd = type { ptr, i32, i8, [11 x i8], %struct.s.base, [16 x i8] } +// CHECK: %struct.EV = type { [16 x i8] } // Overriding a method means that all the vbases containing that // method need a vtordisp. Note: this code will cause an error in cl.exe. >From 4aa16f370798e6fb39b1269e0628e604658a8104 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Sun, 23 Jun 2024 10:01:49 +0100 Subject: [PATCH 2/8] fixup! add missing header --- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 8f3e0f16f93a6d..fa691c124c45e4 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -12,6 +12,7 @@ #include "ABIInfoImpl.h" #include "CGCXXABI.h" +#include "CGRecordLayout.h" #include "CodeGenTypes.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" >From 3706dccf1be7b16901efdf4484f4e6db2053ab08 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Sun, 23 Jun 2024 23:26:36 +0100 Subject: [PATCH 3/8] fixup! remove debug leftovers --- clang/test/CodeGenCXX/auto-var-init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CodeGenCXX/auto-var-init.cpp b/clang/test/CodeGenCXX/auto-var-init.cpp index d3328771cb0948..a72594a9307197 100644 --- a/clang/test/CodeGenCXX/auto-var-init.cpp +++ b/clang/test/CodeGenCXX/auto-var-init.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=PATTERN,PATTERN-O1 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,ZERO,ZERO-O0 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=ZERO,ZERO-O1 -// TODO %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0 +// RUN: %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0 #pragma clang diagnostic ignored "-Winaccessible-base" >From ae309221dfd3d050d4f54cf5a4a5422e9c781359 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 24 Jun 2024 12:18:00 +0100 Subject: [PATCH 4/8] fixup! fix remaining test failures --- clang/lib/CodeGen/CGExprConstant.cpp | 9 ++++++--- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 7 +++++-- clang/test/CodeGen/voidptr-vaarg.c | 3 ++- clang/test/CodeGenCXX/auto-var-init.cpp | 13 ++++++++----- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 1fec587b5c4c7c..03d57aabc0a4e3 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "ABIInfoImpl.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGRecordLayout.h" @@ -2481,8 +2482,10 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); // Ignore empty bases. - if (base->isEmpty() || - CGM.getContext().getASTRecordLayout(base).getNonVirtualSize() + if (isEmptyRecord(CGM.getContext(), I.getType(), false, true) || + CGM.getContext() + .getASTRecordLayout(base) + .getNonVirtualSize() .isZero()) continue; @@ -2518,7 +2521,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); // Ignore empty bases. - if (base->isEmpty()) + if (isEmptyRecord(CGM.getContext(), I.getType(), false, true)) continue; unsigned fieldIndex = layout.getVirtualBaseIndex(base); diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index fa691c124c45e4..dc781e3f7f701b 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -635,7 +635,9 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, // non-reusable tail padding. CharUnits LimitOffset; for (auto Probe = Field; Probe != FieldEnd; ++Probe) - if (!isEmptyField(Context, *Probe, false, true)) { + if (!Probe->isZeroLengthBitField(Context) && + !(isEmptyField(Context, *Probe, false, true) && + !Probe->isBitField())) { // A member with storage sets the limit. assert((getFieldBitOffset(*Probe) % CharBits) == 0 && "Next storage is not byte-aligned"); @@ -1163,7 +1165,8 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { const FieldDecl *FD = *it; // Ignore zero-sized fields. - if (isEmptyField(Context, FD, false, true)) + if (FD->isZeroLengthBitField(Context) || + (isEmptyField(Context, FD, false, true) && !FD->isBitField())) continue; // For non-bit-fields, just check that the LLVM struct offset matches the diff --git a/clang/test/CodeGen/voidptr-vaarg.c b/clang/test/CodeGen/voidptr-vaarg.c index d023ddf0fb5d2d..4f008fd85115a9 100644 --- a/clang/test/CodeGen/voidptr-vaarg.c +++ b/clang/test/CodeGen/voidptr-vaarg.c @@ -245,7 +245,8 @@ typedef struct { // CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4 // CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 4, i1 false) -// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4 +// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_EMPTY_INT_T]], ptr [[RETVAL]], i32 0, i32 0 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[COERCE_DIVE]], align 4 // CHECK-NEXT: ret i32 [[TMP0]] // empty_int_t empty_int(__builtin_va_list list) { diff --git a/clang/test/CodeGenCXX/auto-var-init.cpp b/clang/test/CodeGenCXX/auto-var-init.cpp index a72594a9307197..72bcc1c931cf5a 100644 --- a/clang/test/CodeGenCXX/auto-var-init.cpp +++ b/clang/test/CodeGenCXX/auto-var-init.cpp @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,CHECK-O0 -// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0 +// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0,PATTERN-64-O0 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=PATTERN,PATTERN-O1 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,ZERO,ZERO-O0 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -O1 -emit-llvm -o - | FileCheck %s -check-prefixes=ZERO,ZERO-O1 -// RUN: %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0 +// RUN: %clang_cc1 -std=c++14 -triple i386-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK-O0,PATTERN,PATTERN-O0,PATTERN-32-O0 #pragma clang diagnostic ignored "-Winaccessible-base" @@ -166,14 +166,17 @@ struct semivolatileinit { int i = 0x11111111; volatile int vi = 0x11111111; }; // PATTERN-O0: @__const.test_base_braces.braces = private unnamed_addr constant %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) }, align // PATTERN-O1-NOT: @__const.test_base_braces.braces struct base { virtual ~base(); }; -// PATTERN-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 +// PATTERN-32-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { [4 x i8] c"\FF\FF\FF\FF" }, align 4 +// PATTERN-64-O0: @__const.test_derived_uninit.uninit = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_derived_uninit.uninit -// PATTERN-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 +// PATTERN-32-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { [4 x i8] c"\FF\FF\FF\FF" }, align 4 +// PATTERN-64-O0: @__const.test_derived_braces.braces = private unnamed_addr constant %struct.derived { [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_derived_braces.braces struct derived : public base {}; // PATERN-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_virtualderived_uninit.uninit -// PATTERN-O0: @__const.test_virtualderived_braces.braces = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 +// PATTERN-32-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i32 -1 to ptr) }, [4 x i8] c"\FF\FF\FF\FF" }, align 4 +// PATTERN-64-O0: @__const.test_virtualderived_uninit.uninit = private unnamed_addr constant %struct.virtualderived { %struct.base { ptr inttoptr (i64 -6148914691236517206 to ptr) }, [8 x i8] c"\AA\AA\AA\AA\AA\AA\AA\AA" }, align 8 // PATTERN-O1-NOT: @__const.test_virtualderived_braces.braces struct virtualderived : public virtual base, public virtual derived {}; // PATTERN-O0: @__const.test_matching_uninit.uninit = private unnamed_addr constant %union.matching { i32 [[I32]] }, align 4 >From df799d1206a44af06f7d6e27c4ff281bfba69dc4 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 24 Jun 2024 18:40:30 +0100 Subject: [PATCH 5/8] fixup! add helper wrappers for isEmptyField/isEmptyRecord --- clang/lib/CodeGen/ABIInfoImpl.cpp | 14 ++++++++++++++ clang/lib/CodeGen/ABIInfoImpl.h | 9 +++++++++ clang/lib/CodeGen/CGExpr.cpp | 2 +- clang/lib/CodeGen/CGExprConstant.cpp | 4 ++-- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 15 ++++++--------- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index 92fcc3bc2c5f4c..73311327499508 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -289,6 +289,16 @@ bool CodeGen::isEmptyField(const ASTContext &Context, const FieldDecl *FD, return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr); } +bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD) { + if (FD->isZeroLengthBitField(Context)) + return true; + + if (FD->isUnnamedBitField()) + return false; + + return isEmptyField(Context, FD, /*AllowArrays=*/false, /*AsIfNoUniqueAddr=*/true); +} + bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr) { const RecordType *RT = T->getAs<RecordType>(); @@ -310,6 +320,10 @@ bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T, return true; } +bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { + return isEmptyRecord(Context, T, /*AllowArrays=*/false, /*AsIfNoUniqueAddr=*/true); +} + const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { const RecordType *RT = T->getAs<RecordType>(); if (!RT) diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h index e3f373e39c35a5..ec5a5872462c7d 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.h +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -129,6 +129,10 @@ Address emitMergePHI(CodeGenFunction &CGF, Address Addr1, bool isEmptyField(const ASTContext &Context, const FieldDecl *FD, bool AllowArrays, bool AsIfNoUniqueAddr = false); +/// isEmptyFieldForLayout - Return true iff the field is "empty", that is, +/// either a zero-width bit-field or an empty record. +bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD); + /// isEmptyRecord - Return true iff a structure contains only empty /// fields. Note that a structure with a flexible array member is not /// considered empty. If AsIfNoUniqueAddr is true, then C++ record fields are @@ -137,6 +141,11 @@ bool isEmptyField(const ASTContext &Context, const FieldDecl *FD, bool isEmptyRecord(const ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr = false); +/// isEmptyRecordForLayout - Return true iff a structure contains only empty +/// fields. Note, C++ record fields are considered empty if the +/// [[no_unique_address]] attribute would have made them empty. +bool isEmptyRecordForLayout(const ASTContext &Context, QualType T); + /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or /// exactly one field which is itself a single element diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f7e417443cc585..51f11c071aba00 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4763,7 +4763,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base, /// The resulting address doesn't necessarily have the right type. static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base, const FieldDecl *field) { - if (isEmptyField(CGF.getContext(), field, false, true)) + if (isEmptyFieldForLayout(CGF.getContext(), field)) return emitAddrOfZeroSizeField(CGF, base, field); const RecordDecl *rec = field->getParent(); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 03d57aabc0a4e3..3180f5a3d99ce4 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2482,7 +2482,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); // Ignore empty bases. - if (isEmptyRecord(CGM.getContext(), I.getType(), false, true) || + if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) || CGM.getContext() .getASTRecordLayout(base) .getNonVirtualSize() @@ -2521,7 +2521,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); // Ignore empty bases. - if (isEmptyRecord(CGM.getContext(), I.getType(), false, true)) + if (isEmptyRecordForLayout(CGM.getContext(), I.getType())) continue; unsigned fieldIndex = layout.getVirtualBaseIndex(base); diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index dc781e3f7f701b..c0f2e4e52f117c 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -385,7 +385,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) { Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd); assert((Field == FieldEnd || !Field->isBitField()) && "Failed to accumulate all the bitfields"); - } else if (isEmptyField(Context, *Field, false, true)) { + } else if (isEmptyFieldForLayout(Context, *Field)) { // Empty fields have no storage. ++Field; } else { @@ -635,9 +635,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, // non-reusable tail padding. CharUnits LimitOffset; for (auto Probe = Field; Probe != FieldEnd; ++Probe) - if (!Probe->isZeroLengthBitField(Context) && - !(isEmptyField(Context, *Probe, false, true) && - !Probe->isBitField())) { + if (!isEmptyFieldForLayout(Context, *Probe)) { // A member with storage sets the limit. assert((getFieldBitOffset(*Probe) % CharBits) == 0 && "Next storage is not byte-aligned"); @@ -735,7 +733,7 @@ void CGRecordLowering::accumulateBases() { // Bases can be zero-sized even if not technically empty if they // contain only a trailing array member. const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (!isEmptyRecord(Context, Base.getType(), false, true) && + if (!isEmptyRecordForLayout(Context, Base.getType()) && !Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl), MemberInfo::Base, getStorageType(BaseDecl), BaseDecl)); @@ -883,7 +881,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { if (!isNonVirtualBaseType && isOverlappingVBaseABI()) for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (isEmptyRecord(Context, Base.getType(), false, true)) + if (isEmptyRecordForLayout(Context, Base.getType())) continue; // If the vbase is a primary virtual base of some base, then it doesn't // get its own storage location but instead lives inside of that base. @@ -899,7 +897,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { void CGRecordLowering::accumulateVBases() { for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (isEmptyRecord(Context, Base.getType(), false, true)) + if (isEmptyRecordForLayout(Context, Base.getType())) continue; CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl); // If the vbase is a primary virtual base of some base, then it doesn't @@ -1165,8 +1163,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { const FieldDecl *FD = *it; // Ignore zero-sized fields. - if (FD->isZeroLengthBitField(Context) || - (isEmptyField(Context, FD, false, true) && !FD->isBitField())) + if (isEmptyFieldForLayout(getContext(), FD)) continue; // For non-bit-fields, just check that the LLVM struct offset matches the >From 4e8a84612b9b08bb9d97090eaf758ca50beb0049 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 24 Jun 2024 18:40:46 +0100 Subject: [PATCH 6/8] fixup! clang-format --- clang/lib/CodeGen/ABIInfoImpl.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index 73311327499508..703e69e8899673 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -289,14 +289,16 @@ bool CodeGen::isEmptyField(const ASTContext &Context, const FieldDecl *FD, return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr); } -bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD) { +bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, + const FieldDecl *FD) { if (FD->isZeroLengthBitField(Context)) return true; - + if (FD->isUnnamedBitField()) return false; - return isEmptyField(Context, FD, /*AllowArrays=*/false, /*AsIfNoUniqueAddr=*/true); + return isEmptyField(Context, FD, /*AllowArrays=*/false, + /*AsIfNoUniqueAddr=*/true); } bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T, @@ -321,7 +323,8 @@ bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T, } bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { - return isEmptyRecord(Context, T, /*AllowArrays=*/false, /*AsIfNoUniqueAddr=*/true); + return isEmptyRecord(Context, T, /*AllowArrays=*/false, + /*AsIfNoUniqueAddr=*/true); } const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { >From 18d373c3b6f72b44f84f8f75e69f01f28a6ea37b Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 1 Jul 2024 15:24:25 +0200 Subject: [PATCH 7/8] fixup! adjust other parts of CodeGen to use isEmptyFieldForLayout/isEmptyRecordForLayout --- clang/lib/CodeGen/CGExprConstant.cpp | 3 ++- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 23 +++++++++++++++-------- clang/lib/CodeGen/CodeGenTBAA.cpp | 3 ++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 3180f5a3d99ce4..694d83f03d288b 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2499,7 +2499,8 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, for (const auto *Field : record->fields()) { // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) - if (!Field->isBitField() && !Field->isZeroSize(CGM.getContext())) { + if (!Field->isBitField() && + !isEmptyFieldForLayout(CGM.getContext(), Field)) { unsigned fieldIndex = layout.getLLVMFieldNo(Field); elements[fieldIndex] = CGM.EmitNullConstant(Field->getType()); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index b47b521edd32c3..528ef2f9634c2b 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "CGOpenMPRuntime.h" +#include "ABIInfoImpl.h" #include "CGCXXABI.h" #include "CGCleanup.h" #include "CGRecordLayout.h" @@ -7728,12 +7729,15 @@ class MappableExprsHandler { for (const auto &I : RD->bases()) { if (I.isVirtual()) continue; - const auto *Base = I.getType()->getAsCXXRecordDecl(); + + QualType BaseTy = I.getType(); + const auto *Base = BaseTy->getAsCXXRecordDecl(); // Ignore empty bases. - if (Base->isEmpty() || CGF.getContext() - .getASTRecordLayout(Base) - .getNonVirtualSize() - .isZero()) + if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) || + CGF.getContext() + .getASTRecordLayout(Base) + .getNonVirtualSize() + .isZero()) continue; unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base); @@ -7741,10 +7745,12 @@ class MappableExprsHandler { } // Fill in virtual bases. for (const auto &I : RD->vbases()) { - const auto *Base = I.getType()->getAsCXXRecordDecl(); + QualType BaseTy = I.getType(); // Ignore empty bases. - if (Base->isEmpty()) + if (isEmptyRecordForLayout(CGF.getContext(), BaseTy)) continue; + + const auto *Base = BaseTy->getAsCXXRecordDecl(); unsigned FieldIndex = RL.getVirtualBaseIndex(Base); if (RecordLayout[FieldIndex]) continue; @@ -7755,7 +7761,8 @@ class MappableExprsHandler { for (const auto *Field : RD->fields()) { // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) - if (!Field->isBitField() && !Field->isZeroSize(CGF.getContext())) { + if (!Field->isBitField() && + !isEmptyFieldForLayout(CGF.getContext(), Field)) { unsigned FieldIndex = RL.getLLVMFieldNo(Field); RecordLayout[FieldIndex] = Field; } diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 284421f494711e..b889d1bfe003f3 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenTBAA.h" +#include "ABIInfoImpl.h" #include "CGRecordLayout.h" #include "CodeGenTypes.h" #include "clang/AST/ASTContext.h" @@ -309,7 +310,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { - if ((*i)->isZeroSize(Context)) + if (isEmptyFieldForLayout(Context, *i)) continue; uint64_t Offset = >From 67caf752057e61a0a0c0ef24bb126dbbba2ef8c6 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 5 Jul 2024 12:42:13 +0100 Subject: [PATCH 8/8] fixup! decouple isEmptyXXXForLayout from isEmptyXXX --- clang/lib/CodeGen/ABIInfoImpl.cpp | 42 ++++++++++++------- clang/lib/CodeGen/ABIInfoImpl.h | 19 +++++---- clang/test/CodeGen/debug-info-packed-struct.c | 2 +- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index 703e69e8899673..212ce05ede6ec1 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -248,7 +248,7 @@ Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1, return Address(PHI, Addr1.getElementType(), Align); } -bool CodeGen::isEmptyField(const ASTContext &Context, const FieldDecl *FD, +bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays, bool AsIfNoUniqueAddr) { if (FD->isUnnamedBitField()) return true; @@ -289,6 +289,27 @@ bool CodeGen::isEmptyField(const ASTContext &Context, const FieldDecl *FD, return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr); } +bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, + bool AsIfNoUniqueAddr) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return false; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + for (const auto &I : CXXRD->bases()) + if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr)) + return false; + + for (const auto *I : RD->fields()) + if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr)) + return false; + return true; +} + bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD) { if (FD->isZeroLengthBitField(Context)) @@ -297,34 +318,27 @@ bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, if (FD->isUnnamedBitField()) return false; - return isEmptyField(Context, FD, /*AllowArrays=*/false, - /*AsIfNoUniqueAddr=*/true); + return isEmptyRecordForLayout(Context, FD->getType()); } -bool CodeGen::isEmptyRecord(const ASTContext &Context, QualType T, - bool AllowArrays, bool AsIfNoUniqueAddr) { +bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { const RecordType *RT = T->getAs<RecordType>(); if (!RT) return false; + const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return false; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) for (const auto &I : CXXRD->bases()) - if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr)) + if (!isEmptyRecordForLayout(Context, I.getType())) return false; for (const auto *I : RD->fields()) - if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr)) + if (!isEmptyFieldForLayout(Context, I)) return false; - return true; -} -bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { - return isEmptyRecord(Context, T, /*AllowArrays=*/false, - /*AsIfNoUniqueAddr=*/true); + return true; } const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h index ec5a5872462c7d..5140f28b8f335f 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.h +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -126,24 +126,25 @@ Address emitMergePHI(CodeGenFunction &CGF, Address Addr1, /// is an unnamed bit-field or an (array of) empty record(s). If /// AsIfNoUniqueAddr is true, then C++ record fields are considered empty if /// the [[no_unique_address]] attribute would have made them empty. -bool isEmptyField(const ASTContext &Context, const FieldDecl *FD, - bool AllowArrays, bool AsIfNoUniqueAddr = false); - -/// isEmptyFieldForLayout - Return true iff the field is "empty", that is, -/// either a zero-width bit-field or an empty record. -bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD); +bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays, + bool AsIfNoUniqueAddr = false); /// isEmptyRecord - Return true iff a structure contains only empty /// fields. Note that a structure with a flexible array member is not /// considered empty. If AsIfNoUniqueAddr is true, then C++ record fields are /// considered empty if the [[no_unique_address]] attribute would have made /// them empty. -bool isEmptyRecord(const ASTContext &Context, QualType T, bool AllowArrays, +bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr = false); +/// isEmptyFieldForLayout - Return true iff the field is "empty", that is, +/// either a zero-width bit-field or an \ref isEmptyRecordForLayout. +bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD); + /// isEmptyRecordForLayout - Return true iff a structure contains only empty -/// fields. Note, C++ record fields are considered empty if the -/// [[no_unique_address]] attribute would have made them empty. +/// fields (per \ref isEmptyFieldForLayout). Note, C++ record fields are +/// considered empty if the [[no_unique_address]] attribute would have made +/// them empty. bool isEmptyRecordForLayout(const ASTContext &Context, QualType T); /// isSingleElementStruct - Determine if a structure is a "single diff --git a/clang/test/CodeGen/debug-info-packed-struct.c b/clang/test/CodeGen/debug-info-packed-struct.c index 33b8b4c7e13fb6..676cdb38b396f2 100644 --- a/clang/test/CodeGen/debug-info-packed-struct.c +++ b/clang/test/CodeGen/debug-info-packed-struct.c @@ -2,7 +2,7 @@ // CHECK: %struct.layout3 = type <{ i8, [3 x i8], %struct.size8_pack4, i8, [3 x i8] }> // CHECK: %struct.layout0 = type { i8, %struct.size8, i8 } -// CHECK: %struct.layout1 = type { i8, [8 x i8], i8, [2 x i8] } +// CHECK: %struct.layout1 = type <{ i8, %struct.size8_anon, i8, [2 x i8] }> // CHECK: %struct.layout2 = type <{ i8, %struct.size8_pack1, i8 }> // --------------------------------------------------------------------- _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits