summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/Expr.h19
-rw-r--r--clang/lib/AST/ExprConstant.cpp12
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp40
-rw-r--r--clang/test/CodeGen/const-init.c2
-rw-r--r--clang/test/CodeGen/designated-initializers.c2
-rw-r--r--clang/test/CodeGen/union-init2.c2
-rw-r--r--clang/test/CodeGenCXX/cxx11-initializer-aggregate.cpp27
-rw-r--r--clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp4
-rw-r--r--clang/test/SemaCXX/large-array-init.cpp10
9 files changed, 77 insertions, 41 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 47e8261abf1..a44e98b1d1e 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -537,6 +537,13 @@ public:
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 @@ public:
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 @@ public:
/// 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,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0e1fb98bf77..3efd8dc6a60 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10312,12 +10312,6 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result,
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 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
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 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
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::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
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,
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 7b076ea3e65..ae05df1be58 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,40 @@ static QualType getNonMemoryType(CodeGenModule &CGM, QualType type) {
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<CXXConstructExpr>(Init)) {
+ CXXConstructorDecl *CD = E->getConstructor();
+ return CD->isDefaultConstructor() && CD->isTrivial();
+ }
+
+ if (auto *IL = dyn_cast_or_null<InitListExpr>(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<CXXConstructExpr>(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();
diff --git a/clang/test/CodeGen/const-init.c b/clang/test/CodeGen/const-init.c
index 3fd231b630e..2d699954031 100644
--- a/clang/test/CodeGen/const-init.c
+++ b/clang/test/CodeGen/const-init.c
@@ -167,7 +167,7 @@ void g30() {
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()
}
diff --git a/clang/test/CodeGen/designated-initializers.c b/clang/test/CodeGen/designated-initializers.c
index 74532c8fa5b..21077b4c147 100644
--- a/clang/test/CodeGen/designated-initializers.c
+++ b/clang/test/CodeGen/designated-initializers.c
@@ -8,7 +8,7 @@ struct foo {
// 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
diff --git a/clang/test/CodeGen/union-init2.c b/clang/test/CodeGen/union-init2.c
index bf20696a22c..0b68c211122 100644
--- a/clang/test/CodeGen/union-init2.c
+++ b/clang/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;
diff --git a/clang/test/CodeGenCXX/cxx11-initializer-aggregate.cpp b/clang/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
index 8bf35966f5b..0fb247a31c7 100644
--- a/clang/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ b/clang/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,30 @@ 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}};
+
+ // This variable must be initialized elementwise.
+ Filler data_e1[1024] = {};
+ // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
diff --git a/clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp b/clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
index f59ec51136f..ab1c6383bd3 100644
--- a/clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
+++ b/clang/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
@@ -17,14 +17,14 @@ namespace Constant {
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
diff --git a/clang/test/SemaCXX/large-array-init.cpp b/clang/test/SemaCXX/large-array-init.cpp
deleted file mode 100644
index ba734280597..00000000000
--- a/clang/test/SemaCXX/large-array-init.cpp
+++ /dev/null
@@ -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; }
OpenPOWER on IntegriCloud