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@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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits