r332847 - [CodeGen] Recognize more cases of zero initialization

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Mon May 21 09:09:55 PDT 2018


Author: sepavloff
Date: Mon May 21 09:09:54 2018
New Revision: 332847

URL: http://llvm.org/viewvc/llvm-project?rev=332847&view=rev
Log:
[CodeGen] Recognize more cases of zero initialization

If a variable has an initializer, codegen tries to build its value. If
the variable is large in size, building its value requires substantial
resources. It causes strange behavior from user viewpoint: compilation
of huge zero initialized arrays like:

    char data_1[2147483648u] = { 0 };

consumes enormous amount of time and memory.

With this change codegen tries to determine if variable initializer is
equivalent to zero initializer. In this case variable value is not
constructed.

This change fixes PR18978.

Differential Revision: https://reviews.llvm.org/D46241

Removed:
    cfe/trunk/test/SemaCXX/large-array-init.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/test/CodeGen/const-init.c
    cfe/trunk/test/CodeGen/designated-initializers.c
    cfe/trunk/test/CodeGen/union-init2.c
    cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp
    cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon May 21 09:09:54 2018
@@ -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,

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon May 21 09:09:54 2018
@@ -10312,12 +10312,6 @@ bool Expr::EvaluateAsBooleanCondition(bo
          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,
 
   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 &Resu
 
   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
 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,

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Mon May 21 09:09:54 2018
@@ -1392,20 +1392,40 @@ static QualType getNonMemoryType(CodeGen
   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();
 

Modified: cfe/trunk/test/CodeGen/const-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/const-init.c?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/const-init.c (original)
+++ cfe/trunk/test/CodeGen/const-init.c Mon May 21 09:09:54 2018
@@ -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()
 }
 

Modified: cfe/trunk/test/CodeGen/designated-initializers.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/designated-initializers.c?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/designated-initializers.c (original)
+++ cfe/trunk/test/CodeGen/designated-initializers.c Mon May 21 09:09:54 2018
@@ -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

Modified: cfe/trunk/test/CodeGen/union-init2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/union-init2.c?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/union-init2.c (original)
+++ cfe/trunk/test/CodeGen/union-init2.c Mon May 21 09:09:54 2018
@@ -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;

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=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx11-initializer-aggregate.cpp Mon May 21 09:09:54 2018
@@ -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
+}

Modified: cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp?rev=332847&r1=332846&r2=332847&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp Mon May 21 09:09:54 2018
@@ -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
 

Removed: cfe/trunk/test/SemaCXX/large-array-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/large-array-init.cpp?rev=332846&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/large-array-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/large-array-init.cpp (removed)
@@ -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; }




More information about the cfe-commits mailing list