r333141 - Use zeroinitializer for (trailing zero portion of) large array initializers
David Blaikie via cfe-commits
cfe-commits at lists.llvm.org
Mon May 28 15:34:21 PDT 2018
Probably nice to mention in the commit message what the fix was (& if/where
there was there a test added for it?) so readers don't have to try to
eyeball diff this commit against the otherone.
On Wed, May 23, 2018 at 4:45 PM Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: rsmith
> Date: Wed May 23 16:41:38 2018
> New Revision: 333141
>
> URL: http://llvm.org/viewvc/llvm-project?rev=333141&view=rev
> Log:
> Use zeroinitializer for (trailing zero portion of) large array initializers
> more reliably.
>
> This re-commits r333044 with a fix for PR37560.
>
> Modified:
> cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> cfe/trunk/lib/Sema/SemaInit.cpp
> cfe/trunk/test/CodeGen/init.c
> cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
> cfe/trunk/test/SemaCXX/aggregate-initialization.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=333141&r1=333140&r2=333141&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Wed May 23 16:41:38 2018
> @@ -635,6 +635,60 @@ static ConstantAddress tryEmitGlobalComp
> return ConstantAddress(GV, Align);
> }
>
> +static llvm::Constant *
> +EmitArrayConstant(CodeGenModule &CGM, const ConstantArrayType *DestType,
> + llvm::Type *CommonElementType, unsigned ArrayBound,
> + SmallVectorImpl<llvm::Constant *> &Elements,
> + llvm::Constant *Filler) {
> + // Figure out how long the initial prefix of non-zero elements is.
> + unsigned NonzeroLength = ArrayBound;
> + if (Elements.size() < NonzeroLength && Filler->isNullValue())
> + NonzeroLength = Elements.size();
> + if (NonzeroLength == Elements.size()) {
> + while (NonzeroLength > 0 && Elements[NonzeroLength -
> 1]->isNullValue())
> + --NonzeroLength;
> + }
> +
> + if (NonzeroLength == 0) {
> + return llvm::ConstantAggregateZero::get(
> + CGM.getTypes().ConvertType(QualType(DestType, 0)));
> + }
> +
> + // Add a zeroinitializer array filler if we have lots of trailing
> zeroes.
> + unsigned TrailingZeroes = ArrayBound - NonzeroLength;
> + if (TrailingZeroes >= 8) {
> + assert(Elements.size() >= NonzeroLength &&
> + "missing initializer for non-zero element");
> + Elements.resize(NonzeroLength + 1);
> + auto *FillerType =
> + CommonElementType
> + ? CommonElementType
> + : CGM.getTypes().ConvertType(DestType->getElementType());
> + FillerType = llvm::ArrayType::get(FillerType, TrailingZeroes);
> + Elements.back() = llvm::ConstantAggregateZero::get(FillerType);
> + CommonElementType = nullptr;
> + } else if (Elements.size() != ArrayBound) {
> + // Otherwise pad to the right size with the filler if necessary.
> + Elements.resize(ArrayBound, Filler);
> + if (Filler->getType() != CommonElementType)
> + CommonElementType = nullptr;
> + }
> +
> + // If all elements have the same type, just emit an array constant.
> + if (CommonElementType)
> + return llvm::ConstantArray::get(
> + llvm::ArrayType::get(CommonElementType, ArrayBound), Elements);
> +
> + // We have mixed types. Use a packed struct.
> + llvm::SmallVector<llvm::Type *, 16> Types;
> + Types.reserve(Elements.size());
> + for (llvm::Constant *Elt : Elements)
> + Types.push_back(Elt->getType());
> + llvm::StructType *SType =
> + llvm::StructType::get(CGM.getLLVMContext(), Types, true);
> + return llvm::ConstantStruct::get(SType, Elements);
> +}
> +
> /// This class only needs to handle two cases:
> /// 1) Literals (this is used by APValue emission to emit literals).
> /// 2) Arrays, structs and unions (outside C++11 mode, we don't currently
> @@ -832,68 +886,47 @@ public:
> }
>
> llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) {
> - llvm::ArrayType *AType =
> - cast<llvm::ArrayType>(ConvertType(ILE->getType()));
> - llvm::Type *ElemTy = AType->getElementType();
> + auto *CAT = CGM.getContext().getAsConstantArrayType(ILE->getType());
> + assert(CAT && "can't emit array init for non-constant-bound array");
> unsigned NumInitElements = ILE->getNumInits();
> - unsigned NumElements = AType->getNumElements();
> + unsigned NumElements = CAT->getSize().getZExtValue();
>
> // Initialising an array requires us to automatically
> // initialise any elements that have not been initialised explicitly
> unsigned NumInitableElts = std::min(NumInitElements, NumElements);
>
> - QualType EltType =
> CGM.getContext().getAsArrayType(T)->getElementType();
> + QualType EltType = CAT->getElementType();
>
> // Initialize remaining array elements.
> - llvm::Constant *fillC;
> - if (Expr *filler = ILE->getArrayFiller())
> + llvm::Constant *fillC = nullptr;
> + if (Expr *filler = ILE->getArrayFiller()) {
> fillC = Emitter.tryEmitAbstractForMemory(filler, EltType);
> - else
> - fillC = Emitter.emitNullForMemory(EltType);
> - if (!fillC)
> - return nullptr;
> -
> - // Try to use a ConstantAggregateZero if we can.
> - if (fillC->isNullValue() && !NumInitableElts)
> - return llvm::ConstantAggregateZero::get(AType);
> + if (!fillC)
> + return nullptr;
> + }
>
> // Copy initializer elements.
> SmallVector<llvm::Constant*, 16> Elts;
> - Elts.reserve(std::max(NumInitableElts, NumElements));
> + if (fillC && fillC->isNullValue())
> + Elts.reserve(NumInitableElts + 1);
> + else
> + Elts.reserve(NumElements);
>
> - bool RewriteType = false;
> - bool AllNullValues = true;
> + llvm::Type *CommonElementType = nullptr;
> for (unsigned i = 0; i < NumInitableElts; ++i) {
> Expr *Init = ILE->getInit(i);
> llvm::Constant *C = Emitter.tryEmitPrivateForMemory(Init, EltType);
> if (!C)
> return nullptr;
> - RewriteType |= (C->getType() != ElemTy);
> + if (i == 0)
> + CommonElementType = C->getType();
> + else if (C->getType() != CommonElementType)
> + CommonElementType = nullptr;
> Elts.push_back(C);
> - if (AllNullValues && !C->isNullValue())
> - AllNullValues = false;
> }
>
> - // If all initializer elements are "zero," then avoid storing
> NumElements
> - // instances of the zero representation.
> - if (AllNullValues)
> - return llvm::ConstantAggregateZero::get(AType);
> -
> - RewriteType |= (fillC->getType() != ElemTy);
> - Elts.resize(NumElements, fillC);
> -
> - if (RewriteType) {
> - // FIXME: Try to avoid packing the array
> - std::vector<llvm::Type*> Types;
> - Types.reserve(Elts.size());
> - for (unsigned i = 0, e = Elts.size(); i < e; ++i)
> - Types.push_back(Elts[i]->getType());
> - llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
> - Types, true);
> - return llvm::ConstantStruct::get(SType, Elts);
> - }
> -
> - return llvm::ConstantArray::get(AType, Elts);
> + return EmitArrayConstant(CGM, CAT, CommonElementType, NumElements,
> Elts,
> + fillC);
> }
>
> llvm::Constant *EmitRecordInitialization(InitListExpr *ILE, QualType T)
> {
> @@ -1889,40 +1922,31 @@ llvm::Constant *ConstantEmitter::tryEmit
> case APValue::Union:
> return ConstStructBuilder::BuildStruct(*this, Value, DestType);
> case APValue::Array: {
> - const ArrayType *CAT = CGM.getContext().getAsArrayType(DestType);
> + const ConstantArrayType *CAT =
> + CGM.getContext().getAsConstantArrayType(DestType);
> unsigned NumElements = Value.getArraySize();
> unsigned NumInitElts = Value.getArrayInitializedElts();
>
> // Emit array filler, if there is one.
> llvm::Constant *Filler = nullptr;
> - if (Value.hasArrayFiller())
> + if (Value.hasArrayFiller()) {
> Filler = tryEmitAbstractForMemory(Value.getArrayFiller(),
> CAT->getElementType());
> -
> - // Emit initializer elements.
> - llvm::Type *CommonElementType =
> - CGM.getTypes().ConvertType(CAT->getElementType());
> -
> - // Try to use a ConstantAggregateZero if we can.
> - if (Filler && Filler->isNullValue() && !NumInitElts) {
> - llvm::ArrayType *AType =
> - llvm::ArrayType::get(CommonElementType, NumElements);
> - return llvm::ConstantAggregateZero::get(AType);
> + if (!Filler)
> + return nullptr;
> }
>
> + // Emit initializer elements.
> SmallVector<llvm::Constant*, 16> Elts;
> - Elts.reserve(NumElements);
> - for (unsigned I = 0; I < NumElements; ++I) {
> - llvm::Constant *C = Filler;
> - if (I < NumInitElts) {
> - C = tryEmitPrivateForMemory(Value.getArrayInitializedElt(I),
> - CAT->getElementType());
> - } else if (!Filler) {
> - assert(Value.hasArrayFiller() &&
> - "Missing filler for implicit elements of initializer");
> - C = tryEmitPrivateForMemory(Value.getArrayFiller(),
> - CAT->getElementType());
> - }
> + if (Filler && Filler->isNullValue())
> + Elts.reserve(NumInitElts + 1);
> + else
> + Elts.reserve(NumElements);
> +
> + llvm::Type *CommonElementType = nullptr;
> + for (unsigned I = 0; I < NumInitElts; ++I) {
> + llvm::Constant *C = tryEmitPrivateForMemory(
> + Value.getArrayInitializedElt(I), CAT->getElementType());
> if (!C) return nullptr;
>
> if (I == 0)
> @@ -1932,20 +1956,8 @@ llvm::Constant *ConstantEmitter::tryEmit
> Elts.push_back(C);
> }
>
> - if (!CommonElementType) {
> - // FIXME: Try to avoid packing the array
> - std::vector<llvm::Type*> Types;
> - Types.reserve(NumElements);
> - for (unsigned i = 0, e = Elts.size(); i < e; ++i)
> - Types.push_back(Elts[i]->getType());
> - llvm::StructType *SType =
> - llvm::StructType::get(CGM.getLLVMContext(), Types, true);
> - return llvm::ConstantStruct::get(SType, Elts);
> - }
> -
> - llvm::ArrayType *AType =
> - llvm::ArrayType::get(CommonElementType, NumElements);
> - return llvm::ConstantArray::get(AType, Elts);
> + return EmitArrayConstant(CGM, CAT, CommonElementType, NumElements,
> Elts,
> + Filler);
> }
> case APValue::MemberPointer:
> return CGM.getCXXABI().EmitMemberPointer(Value, DestType);
>
> Modified: cfe/trunk/lib/Sema/SemaInit.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=333141&r1=333140&r2=333141&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaInit.cpp Wed May 23 16:41:38 2018
> @@ -751,6 +751,9 @@ InitListChecker::FillInEmptyInitializati
> ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
> ElementEntity.setElementIndex(Init);
>
> + if (Init >= NumInits && ILE->hasArrayFiller())
> + return;
> +
> Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
> if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
> ILE->setInit(Init, ILE->getArrayFiller());
>
> Modified: cfe/trunk/test/CodeGen/init.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/init.c?rev=333141&r1=333140&r2=333141&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/init.c (original)
> +++ cfe/trunk/test/CodeGen/init.c Wed May 23 16:41:38 2018
> @@ -72,6 +72,16 @@ struct a7 {
> struct a7 test7 = { .b = 0, .v = "bar" };
>
>
> +// CHECK-DAG: @huge_array = global {{.*}} <{ i32 1, i32 0, i32 2, i32 0,
> i32 3, [999999995 x i32] zeroinitializer }>
> +int huge_array[1000000000] = {1, 0, 2, 0, 3, 0, 0, 0};
> +
> +// CHECK-DAG: @huge_struct = global {{.*}} { i32 1, <{ i32, [999999999 x
> i32] }> <{ i32 2, [999999999 x i32] zeroinitializer }> }
> +struct Huge {
> + int a;
> + int arr[1000 * 1000 * 1000];
> +} huge_struct = {1, {2, 0, 0, 0}};
> +
> +
> // PR279 comment #3
> char test8(int X) {
> char str[100000] = "abc"; // tail should be memset.
>
> Modified: cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp?rev=333141&r1=333140&r2=333141&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp Wed May 23
> 16:41:38 2018
> @@ -11,6 +11,42 @@ namespace NonAggregateCopyInAggregateIni
> struct C { A &&p; } c{{1}};
> }
>
> +namespace NearlyZeroInit {
> + // CHECK-DAG: @_ZN14NearlyZeroInit1aE = global {{.*}} <{ i32 1, i32 2,
> i32 3, [120 x i32] zeroinitializer }>
> + int a[123] = {1, 2, 3};
> + // CHECK-DAG: @_ZN14NearlyZeroInit1bE = global {{.*}} { i32 1, <{ i32,
> [2147483647 <(214)%20748-3647> x i32] }> <{ i32 2, [2147483647 x i32]
> zeroinitializer }> }
> + struct B { int n; int arr[1024 * 1024 * 1024 * 2u]; } b = {1, {2}};
> +}
> +
> +namespace PR37560 {
> + union U {
> + char x;
> + int a;
> + };
> + // FIXME: [dcl.init]p2, the padding bits of the union object should be
> + // initialized to 0, not undef, which would allow us to collapse the
> tail
> + // of these arrays to zeroinitializer.
> + // CHECK-DAG: @_ZN7PR375601cE = global <{ { i8, [3 x i8] } }> <{ { i8,
> [3 x i8] } { i8 0, [3 x i8] undef } }>
> + U c[1] = {};
> + // CHECK-DAG: @_ZN7PR375601dE = global {{.*}} <{ { i8, [3 x i8] } { i8
> 97, [3 x i8] undef }, %"{{[^"]*}}" { i32 123 }, { i8, [3 x i8] } { i8 98,
> [3 x i8] undef }, { i8, [3 x i8] } { i8 0, [3 x i8] undef },
> + U d[16] = {'a', {.a = 123}, 'b'};
> + // CHECK-DAG: @_ZN7PR375601eE = global {{.*}} <{ %"{{[^"]*}}" { i32 123
> }, %"{{[^"]*}}" { i32 456 }, { i8, [3 x i8] } { i8 0, [3 x i8] undef },
> + U e[16] = {{.a = 123}, {.a = 456}};
> +
> + union V {
> + int a;
> + char x;
> + };
> + // CHECK-DAG: @_ZN7PR375601fE = global [1 x %"{{[^"]*}}"]
> zeroinitializer
> + V f[1] = {};
> + // CHECK-DAG: @_ZN7PR375601gE = global {{.*}} <{ { i8, [3 x i8] } { i8
> 97, [3 x i8] undef }, %"{{[^"]*}}" { i32 123 }, { i8, [3 x i8] } { i8 98,
> [3 x i8] undef }, [13 x %"{{[^"]*}}"] zeroinitializer }>
> + V g[16] = {{.x = 'a'}, {.a = 123}, {.x = 'b'}};
> + // CHECK-DAG: @_ZN7PR375601hE = global {{.*}} <{ %"{{[^"]*}}" { i32 123
> }, %"{{[^"]*}}" { i32 456 }, [14 x %"{{[^"]*}}"] zeroinitializer }>
> + V h[16] = {{.a = 123}, {.a = 456}};
> + // CHECK-DAG: @_ZN7PR375601iE = global [4 x %"{{[^"]*}}"] [%"{{[^"]*}}"
> { i32 123 }, %"{{[^"]*}}" { i32 456 }, %"{{[^"]*}}" zeroinitializer,
> %"{{[^"]*}}" zeroinitializer]
> + V i[4] = {{.a = 123}, {.a = 456}};
> +}
> +
> // CHECK-LABEL: define {{.*}}@_Z3fn1i(
> int fn1(int x) {
> // CHECK: %[[INITLIST:.*]] = alloca %struct.A
> @@ -51,3 +87,35 @@ namespace NonTrivialInit {
> // meaningful.
> B b[30] = {};
> }
> +
> +namespace ZeroInit {
> + enum { Zero, One };
> + constexpr int zero() { return 0; }
> + constexpr int *null() { return nullptr; }
> + struct Filler {
> + int x;
> + Filler();
> + };
> + struct S1 {
> + int x;
> + };
> +
> + // These declarations, if implemented elementwise, require huge
> + // amout of memory and compiler time.
> + unsigned char data_1[1024 * 1024 * 1024 * 2u] = { 0 };
> + unsigned char data_2[1024 * 1024 * 1024 * 2u] = { Zero };
> + unsigned char data_3[1024][1024][1024] = {{{0}}};
> + unsigned char data_4[1024 * 1024 * 1024 * 2u] = { zero() };
> + int *data_5[1024 * 1024 * 512] = { nullptr };
> + int *data_6[1024 * 1024 * 512] = { null() };
> + struct S1 data_7[1024 * 1024 * 512] = {{0}};
> + char data_8[1000 * 1000 * 1000] = {};
> + int (&&data_9)[1000 * 1000 * 1000] = {0};
> + unsigned char data_10[1024 * 1024 * 1024 * 2u] = { 1 };
> + unsigned char data_11[1024 * 1024 * 1024 * 2u] = { One };
> + unsigned char data_12[1024][1024][1024] = {{{1}}};
> +
> + // This variable must be initialized elementwise.
> + Filler data_e1[1024] = {};
> + // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
> +}
>
> Modified: cfe/trunk/test/SemaCXX/aggregate-initialization.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/aggregate-initialization.cpp?rev=333141&r1=333140&r2=333141&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/aggregate-initialization.cpp (original)
> +++ cfe/trunk/test/SemaCXX/aggregate-initialization.cpp Wed May 23
> 16:41:38 2018
> @@ -180,3 +180,9 @@ namespace IdiomaticStdArrayInitDoesNotWa
>
> #pragma clang diagnostic pop
> }
> +
> +namespace HugeArraysUseArrayFiller {
> + // All we're checking here is that initialization completes in a
> reasonable
> + // amount of time.
> + struct A { int n; int arr[1000 * 1000 * 1000]; } a = {1, {2}};
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180528/8e7c6590/attachment-0001.html>
More information about the cfe-commits
mailing list