Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -537,6 +537,13 @@ bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit = nullptr) const; + enum SideEffectsKind { + SE_NoSideEffects, ///< Strictly evaluate the expression. + SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not + ///< arbitrary unmodeled side effects. + SE_AllowSideEffects ///< Allow any unmodeled side effect. + }; + /// EvalStatus is a struct with detailed info about an evaluation in progress. struct EvalStatus { /// Whether the evaluated expression has side effects. @@ -565,6 +572,11 @@ bool hasSideEffects() const { return HasSideEffects; } + + bool hasUnacceptableSideEffect(SideEffectsKind SEK) { + return (SEK < SE_AllowSideEffects && HasSideEffects) || + (SEK < SE_AllowUndefinedBehavior && HasUndefinedBehavior); + } }; /// EvalResult is a struct with detailed info about an evaluated expression. @@ -591,13 +603,6 @@ /// side-effects. bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const; - enum SideEffectsKind { - SE_NoSideEffects, ///< Strictly evaluate the expression. - SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not - ///< arbitrary unmodeled side effects. - SE_AllowSideEffects ///< Allow any unmodeled side effect. - }; - /// EvaluateAsInt - Return true if this is a constant which we can fold and /// convert to an integer, using any crazy technique that we want to. bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -10312,12 +10312,6 @@ HandleConversionToBool(Scratch.Val, Result); } -static bool hasUnacceptableSideEffect(Expr::EvalStatus &Result, - Expr::SideEffectsKind SEK) { - return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) || - (SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior); -} - bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects) const { if (!getType()->isIntegralOrEnumerationType()) @@ -10325,7 +10319,7 @@ EvalResult ExprResult; if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() || - hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) + ExprResult.hasUnacceptableSideEffect(AllowSideEffects)) return false; Result = ExprResult.Val.getInt(); @@ -10339,7 +10333,7 @@ EvalResult ExprResult; if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() || - hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) + ExprResult.hasUnacceptableSideEffect(AllowSideEffects)) return false; Result = ExprResult.Val.getFloat(); @@ -10417,7 +10411,7 @@ bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const { EvalResult Result; return EvaluateAsRValue(Result, Ctx) && - !hasUnacceptableSideEffect(Result, SEK); + !Result.hasUnacceptableSideEffect(SEK); } APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, Index: lib/CodeGen/CGExprConstant.cpp =================================================================== --- lib/CodeGen/CGExprConstant.cpp +++ lib/CodeGen/CGExprConstant.cpp @@ -1392,20 +1392,40 @@ return type; } +/// Checks if the specified initializer is equivalent to zero initialization. +static bool isZeroInitializer(ConstantEmitter &CE, const Expr *Init) { + if (auto *E = dyn_cast_or_null(Init)) { + CXXConstructorDecl *CD = E->getConstructor(); + return CD->isDefaultConstructor() && CD->isTrivial(); + } + + if (auto *IL = dyn_cast_or_null(Init)) { + for (auto I : IL->inits()) + if (!isZeroInitializer(CE, I)) + return false; + if (const Expr *Filler = IL->getArrayFiller()) + return isZeroInitializer(CE, Filler); + return true; + } + + QualType InitTy = Init->getType(); + if (InitTy->isIntegralOrEnumerationType() || InitTy->isPointerType()) { + Expr::EvalResult Result; + if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) && + !Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects)) + return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) || + (Result.Val.isLValue() && Result.Val.isNullPointer()); + } + + return false; +} + llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) { // Make a quick check if variable can be default NULL initialized // and avoid going through rest of code which may do, for c++11, // initialization of memory to all NULLs. - if (!D.hasLocalStorage()) { - QualType Ty = CGM.getContext().getBaseElementType(D.getType()); - if (Ty->isRecordType()) - if (const CXXConstructExpr *E = - dyn_cast_or_null(D.getInit())) { - const CXXConstructorDecl *CD = E->getConstructor(); - if (CD->isTrivial() && CD->isDefaultConstructor()) - return CGM.EmitNullConstant(D.getType()); - } - } + if (!D.hasLocalStorage() && isZeroInitializer(*this, D.getInit())) + return CGM.EmitNullConstant(D.getType()); QualType destType = D.getType(); Index: test/CodeGen/const-init.c =================================================================== --- test/CodeGen/const-init.c +++ test/CodeGen/const-init.c @@ -167,7 +167,7 @@ int : 1; int x; } a = {}; - // CHECK: @g30.a = internal global %struct.anon.1 <{ i8 undef, i32 0 }>, align 1 + // CHECK: @g30.a = internal global %struct.anon.1 zeroinitializer, align 1 #pragma pack() } Index: test/CodeGen/designated-initializers.c =================================================================== --- test/CodeGen/designated-initializers.c +++ test/CodeGen/designated-initializers.c @@ -8,7 +8,7 @@ // CHECK: @u = global %union.anon zeroinitializer union { int i; float f; } u = { }; -// CHECK: @u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef } +// CHECK: @u2 = global %union.anon.0 zeroinitializer union { int i; double f; } u2 = { }; // CHECK: @u3 = global %union.anon.1 zeroinitializer Index: test/CodeGen/union-init2.c =================================================================== --- test/CodeGen/union-init2.c +++ test/CodeGen/union-init2.c @@ -5,7 +5,7 @@ union x {long long b;union x* a;} r = {.a = &r}; -// CHECK: global { [3 x i8], [5 x i8] } { [3 x i8] zeroinitializer, [5 x i8] undef } +// CHECK: global %union.z zeroinitializer union z { char a[3]; long long b; Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp =================================================================== --- test/CodeGenCXX/cxx11-initializer-aggregate.cpp +++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp @@ -51,3 +51,30 @@ // 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}}; + + // This variable must be initialized elementwise. + Filler data_e1[1024] = {}; + // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E +} Index: test/CodeGenCXX/cxx1z-initializer-aggregate.cpp =================================================================== --- test/CodeGenCXX/cxx1z-initializer-aggregate.cpp +++ test/CodeGenCXX/cxx1z-initializer-aggregate.cpp @@ -17,14 +17,14 @@ C c1 = {}; C c2 = {1}; - // CHECK: @_ZN8Constant2c1E = global { i8 } zeroinitializer, align 1 + // CHECK: @_ZN8Constant2c1E = global %"struct.Constant::C" zeroinitializer, align 1 // CHECK: @_ZN8Constant2c2E = global { i8 } { i8 1 }, align 1 // Test packing bases into tail padding. D d1 = {}; D d2 = {1, 2, 3}; D d3 = {1}; - // CHECK: @_ZN8Constant2d1E = global { i32, i8, i8 } zeroinitializer, align 4 + // CHECK: @_ZN8Constant2d1E = global %"struct.Constant::D" zeroinitializer, align 4 // CHECK: @_ZN8Constant2d2E = global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4 // CHECK: @_ZN8Constant2d3E = global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4 Index: test/SemaCXX/large-array-init.cpp =================================================================== --- test/SemaCXX/large-array-init.cpp +++ test/SemaCXX/large-array-init.cpp @@ -1,10 +0,0 @@ -// RUN: %clang_cc1 -S -o %t.ll -mllvm -debug-only=exprconstant %s 2>&1 | \ -// RUN: FileCheck %s -// REQUIRES: asserts - -struct S { int i; }; - -static struct S arr[100000000] = {{ 0 }}; -// CHECK: The number of elements to initialize: 1. - -struct S *foo() { return arr; }