llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Michael Buch (Michael137) <details> <summary>Changes</summary> 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 example 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 from affecting 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`. **Details** The main strategy here was to change the `isZeroSize` check in `CGRecordLowering::accumulateFields` and `CGRecordLowering::accumulateBases` to use the `isEmptyXXX` APIs instead, preventing empty fields from being added to the `Members` and `Bases` structures. The rest of the changes fall out from here, to prevent lookups into these structures (for field numbers or base indices) from failing. Added `isEmptyRecordForLayout` and `isEmptyFieldForLayout` (open to better naming suggestions), which mostly just dispatch to the `isEmptyRecord`/`isEmptyField` respectively. The main difference is that `isEmptyFieldForLayout` doesn't treat `unnamed bitfields` as unconditionally empty (unlike `isEmptyField`). --- Patch is 46.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96422.diff 26 Files Affected: - (modified) clang/lib/CodeGen/ABIInfoImpl.cpp (+20-3) - (modified) clang/lib/CodeGen/ABIInfoImpl.h (+12-3) - (modified) clang/lib/CodeGen/CGExpr.cpp (+2-1) - (modified) clang/lib/CodeGen/CGExprConstant.cpp (+6-3) - (modified) clang/lib/CodeGen/CGRecordLayoutBuilder.cpp (+8-7) - (modified) clang/test/CodeGen/X86/x86_64-vaarg.c (+2-1) - (modified) clang/test/CodeGen/debug-info-packed-struct.c (+1-1) - (modified) clang/test/CodeGen/paren-list-agg-init.cpp (+6-9) - (modified) clang/test/CodeGen/voidptr-vaarg.c (+2-1) - (modified) clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp (+3-3) - (modified) clang/test/CodeGenCXX/auto-var-init.cpp (+9-6) - (modified) clang/test/CodeGenCXX/bitfield-access-empty.cpp (+8-8) - (modified) clang/test/CodeGenCXX/class-layout.cpp (+1-1) - (modified) clang/test/CodeGenCXX/compound-literals.cpp (+1-1) - (modified) clang/test/CodeGenCXX/exceptions.cpp (+3-4) - (modified) clang/test/CodeGenCXX/lambda-deterministic-captures.cpp (+1-3) - (modified) clang/test/CodeGenCXX/ms_struct.cpp (+1-3) - (modified) clang/test/CodeGenCXX/partial-destruction.cpp (+4-7) - (modified) clang/test/CodeGenCXX/pr18962.cpp (+2-3) - (modified) clang/test/CodeGenCXX/references.cpp (+1-3) - (modified) clang/test/CodeGenCXX/temporaries.cpp (+6-6) - (modified) clang/test/CodeGenObjCXX/lambda-to-block.mm (+4-5) - (modified) clang/test/OpenMP/irbuilder_for_iterator.cpp (+4-6) - (modified) clang/test/OpenMP/irbuilder_for_rangefor.cpp (+6-8) - (modified) clang/test/OpenMP/task_member_call_codegen.cpp (+9-13) - (modified) clang/test/Sema/ms_class_layout.cpp (+2-12) ``````````diff diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index e9a26abb77837..703e69e889967 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,20 @@ 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::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>(); if (!RT) return false; @@ -310,6 +322,11 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, 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 92986fb431646..ec5a5872462c7 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.h +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -126,17 +126,26 @@ 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); + +/// 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 /// 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); +/// 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 534f46da74862..60a78e77f78c6 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" @@ -4756,7 +4757,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 (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 dffb8ce83b643..1c6f842081ada 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" @@ -2437,8 +2438,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 (isEmptyRecordForLayout(CGM.getContext(), I.getType()) || + CGM.getContext() + .getASTRecordLayout(base) + .getNonVirtualSize() .isZero()) continue; @@ -2474,7 +2477,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); // Ignore empty bases. - if (base->isEmpty()) + 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 5169be204c14d..c0f2e4e52f117 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "CGRecordLayout.h" +#include "ABIInfoImpl.h" #include "CGCXXABI.h" +#include "CGRecordLayout.h" #include "CodeGenTypes.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" @@ -384,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 (Field->isZeroSize(Context)) { + } else if (isEmptyFieldForLayout(Context, *Field)) { // Empty fields have no storage. ++Field; } else { @@ -634,7 +635,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, // non-reusable tail padding. CharUnits LimitOffset; for (auto Probe = Field; Probe != FieldEnd; ++Probe) - if (!Probe->isZeroSize(Context)) { + if (!isEmptyFieldForLayout(Context, *Probe)) { // A member with storage sets the limit. assert((getFieldBitOffset(*Probe) % CharBits) == 0 && "Next storage is not byte-aligned"); @@ -732,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 (!BaseDecl->isEmpty() && + if (!isEmptyRecordForLayout(Context, Base.getType()) && !Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl), MemberInfo::Base, getStorageType(BaseDecl), BaseDecl)); @@ -880,7 +881,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 (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. @@ -896,7 +897,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 (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 @@ -1162,7 +1163,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { const FieldDecl *FD = *it; // Ignore zero-sized fields. - if (FD->isZeroSize(getContext())) + if (isEmptyFieldForLayout(getContext(), FD)) 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 d6b885d9fb18c..7d5102f93ca6f 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 676cdb38b396f..33b8b4c7e13fb 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 88b1834d42d87..16cfe772a4ae5 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/CodeGen/voidptr-vaarg.c b/clang/test/CodeGen/voidptr-vaarg.c index d023ddf0fb5d2..4f008fd85115a 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/2011-12-19-init-list-ctor.cpp b/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp index 14557829268ef..3efb8c449c8fa 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 e1568bee136e5..b0fc4946040b7 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" @@ -174,14 +174,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 { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } }, align +// 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 { %struct.base { ptr inttoptr ([[IPTRT]] [[IPTR]] to ptr) } }, align +// 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 {}; -// 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 unnam... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/96422 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits