[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-21 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

I've done some more investigation, and I now think this patch is merely working 
around deficiencies elsewhere. See https://reviews.llvm.org/D47166, which aims 
to fix those deficiencies more directly.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-21 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1414-1415
+Expr::EvalResult Result;
+if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) &&
+!Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects))
+  return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) ||

sepavloff wrote:
> rsmith wrote:
> > Please call `D.evaluateValue()` here rather than inventing your own 
> > evaluation scheme. That way, we'll cache the evaluated initializer on the 
> > variable for other uses or reuse the value if we've already evaluated it, 
> > and you don't need to worry about the corner cases involved in getting the 
> > evaluation right. (As it happens, you're getting some minor details wrong 
> > because evaluating an initializer is not quite the same as evaluating an 
> > rvalue, but in practice it's not a big deal here.)
> 
> Call of `D.evaluateValue()` may result in substantial memory and time 
> consumption if the variable value is huge, like in:
> ```
> int char data_1[2147483648u] = { 0 };
> ```
> The idea of this patch is to recognize some cases of zero initialization 
> prior to the evaluation of variable initializer. In the example above, value 
> would be evaluated only for part of the initializer, namely `0`, which does 
> not have an associated variable, so call of `D.evaluateValue()` is not 
> possible.
> 
As noted, `EvaluateAsRValue` gets some of the details here wrong. I reverted 
this in r332886 because of a miscompile due to this fact.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-21 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC332847: [CodeGen] Recognize more cases of zero 
initialization (authored by sepavloff, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D46241?vs=146091=147798#toc

Repository:
  rC Clang

https://reviews.llvm.org/D46241

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

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 , 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 ) {
   // 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: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -10312,20 +10312,14 @@
  HandleConversionToBool(Scratch.Val, Result);
 }
 
-static bool hasUnacceptableSideEffect(Expr::EvalStatus ,
-  Expr::SideEffectsKind SEK) {
-  return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) ||
- (SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior);
-}
-
 bool Expr::EvaluateAsInt(APSInt , const ASTContext ,
  SideEffectsKind AllowSideEffects) const {
   if (!getType()->isIntegralOrEnumerationType())
 return false;
 
   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 , SideEffectsKind SEK) const {
   EvalResult Result;
   return EvaluateAsRValue(Result, Ctx) &&
- !hasUnacceptableSideEffect(Result, SEK);
+ !Result.hasUnacceptableSideEffect(SEK);
 }
 
 APSInt Expr::EvaluateKnownConstInt(const ASTContext ,
Index: include/clang/AST/Expr.h
===
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -537,6 +537,13 @@
   bool isConstantInitializer(ASTContext , 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.
+  };
+
   /// 

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-15 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

@rsmith Do yo think this patch is OK to apply?


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-10 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1414-1415
+Expr::EvalResult Result;
+if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) &&
+!Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects))
+  return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) ||

rsmith wrote:
> Please call `D.evaluateValue()` here rather than inventing your own 
> evaluation scheme. That way, we'll cache the evaluated initializer on the 
> variable for other uses or reuse the value if we've already evaluated it, and 
> you don't need to worry about the corner cases involved in getting the 
> evaluation right. (As it happens, you're getting some minor details wrong 
> because evaluating an initializer is not quite the same as evaluating an 
> rvalue, but in practice it's not a big deal here.)

Call of `D.evaluateValue()` may result in substantial memory and time 
consumption if the variable value is huge, like in:
```
int char data_1[2147483648u] = { 0 };
```
The idea of this patch is to recognize some cases of zero initialization prior 
to the evaluation of variable initializer. In the example above, value would be 
evaluated only for part of the initializer, namely `0`, which does not have an 
associated variable, so call of `D.evaluateValue()` is not possible.



Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-10 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1414-1415
+Expr::EvalResult Result;
+if (Init->EvaluateAsRValue(Result, CE.CGM.getContext()) &&
+!Result.hasUnacceptableSideEffect(Expr::SE_NoSideEffects))
+  return (Result.Val.isInt() && Result.Val.getInt().isNullValue()) ||

Please call `D.evaluateValue()` here rather than inventing your own evaluation 
scheme. That way, we'll cache the evaluated initializer on the variable for 
other uses or reuse the value if we've already evaluated it, and you don't need 
to worry about the corner cases involved in getting the evaluation right. (As 
it happens, you're getting some minor details wrong because evaluating an 
initializer is not quite the same as evaluating an rvalue, but in practice it's 
not a big deal here.)


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-10 Thread John McCall via Phabricator via cfe-commits
rjmccall accepted this revision.
rjmccall added a comment.
This revision is now accepted and ready to land.

Thanks, LGTM.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-10 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 146091.
sepavloff added a comment.

Updated patch

Try evaluating initializer value only if the initializer type is
integral or pointer. It avoids calculation of large value, which
then is discarded.


Repository:
  rC Clang

https://reviews.llvm.org/D46241

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

Index: test/SemaCXX/large-array-init.cpp
===
--- 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[1] = {{ 0 }};
-// CHECK: The number of elements to initialize: 1.
-
-struct S *foo() { return arr; }
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/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/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 = };
 
 
-// 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/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/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: 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 , const Expr *Init) {
+  if (auto *E = dyn_cast_or_null(Init)) {
+CXXConstructorDecl *CD = E->getConstructor();
+return 

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-09 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1413
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (InitTy->hasPointerRepresentation()) {

sepavloff wrote:
> rsmith wrote:
> > sepavloff wrote:
> > > rjmccall wrote:
> > > > Aren't the null-pointer and integer-constant-expression checks below 
> > > > already checking this?  Also, `isEvaluatable` actually computes the 
> > > > full value internally (as an `APValue`), so if you're worried about the 
> > > > memory and compile-time effects of producing such a value, you really 
> > > > shouldn't call it.
> > > > 
> > > > You could reasonably move this entire function to be a method on `Expr` 
> > > > that takes an `ASTContext`.
> > > Comment for `EvaluateAsRValue` says that it tries calculate expression 
> > > agressively. Indeed, for the code:
> > > ```
> > >   decltype(nullptr) null();
> > >   int *p = null();
> > > ```
> > > compiler ignores potential side effect of `null()` and removes the call, 
> > > leaving only zero initialization. `isNullPointerConstant` behaves 
> > > similarly.
> > Nonetheless, it looks like this function could evaluate `Init` up to three 
> > times, which seems unreasonable. Instead of the checks based on trying to 
> > evaluate the initializer (`isNullPointerConstant` + 
> > `isIntegerConstantExpr`), how about calling `VarDecl::evaluateValue()` 
> > (which will return a potentially pre-computed and cached initializer value) 
> > and checking if the result is a zero constant?
> > 
> > In fact, `tryEmitPrivateForVarInit` already does most of that for you, and 
> > the right place to make this change is probably in 
> > `tryEmitPrivateForMemory`, where you can test to see if the `APValue` is 
> > zero-initialized and produce a `zeroinitializer` if so. As a side-benefit, 
> > putting the change there will mean we'll also start using `zeroinitializer` 
> > for zero-initialized subobjects of objects that have non-zero pieces.
> An important point in this patch is that CodeGen tries to find out, if the 
> initializer can be replaced with zeroinitializer, *prior* to the evaluation 
> of it. For huge arrays the evaluation consumes huge amount of memory and time 
> and it must be avoided.
> 
> With this patch CodeGen may evaluate parts of the initializer, if it is 
> represented by `InitListExpr`. It may cause redundant calculation, for 
> instance if the check for zero initialization failed but the initializer is 
> constant. To avoid this redundancy we could cache result of evaluation in 
> instances of `Expr` and then use the partial values in the evaluation of the 
> initializer. The simple use case solved by this patch probably is not a 
> sufficient justification for such redesign.
I really think you should have some sort of type restriction in front of this 
so that you don't end up creating a huge APValue only to throw it away because 
it's not an int or a pointer.  It's quite possible to have something like an 
array initializer in a nested position that's not within an InitListExpr , e.g. 
due to compound literals or std::initializer_list.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

> Hmm. In C++, a static object which isn't constant-initialized is 
> zero-initialized, which is required to set any padding bits to zero (N4640 
> [dcl.init]p6) in both structs and unions. In C, a static object which doesn't 
> have an initializer also has all any padding bits set to zero (N1548 
> 6.7.9p10). Now, this object has an initializer (that acts as a 
> constant-initializer in C++), so those rules don't directly apply; but I 
> would argue that the intent of the standards is not that padding bits become 
> undefined when you happen to have an initializer. So I actually think the 
> zeroinitializer emission is more correct.

Using undefined values instead of zero initialization was implemented in 
https://reviews.llvm.org/rL101535. There is no much info about the reason of 
the implementation. Clang uses undefined values for padding bits, in particular 
in unions, when the first member is not widest. The code:

  union C1 {
  char sel;
  double dval;
};
union C1 val_1 = { 0 };

produces:

  @val_1 = dso_local global { i8, [7 x i8] } { i8 0, [7 x i8] undef }, align 8  

Another case is unnamed bit fields.

struct C2 {
  int : 4;
  int x;
};
struct C2 val_2 = { 0 };

produces:

  @val_2 = dso_local global { [4 x i8], i32 } { [4 x i8] undef, i32 0 }, align 4

Strictly speaking, this IR does not mean violation of the standard, but it can 
modify code generation in some cases. If we decided to use zeroinitializer in 
this case, we probably would need to revise using undefined values in 
initializers, otherwise similar declarations like:

union C1 val_1a = { 0 };
union C1 val_1b = { 1 };

would produce different IR representations, with and without undefined values.

The test `SemaCXX/large-array-init.cpp` is removed in this change. This test 
was added in https://reviews.llvm.org/rL325120 to solve 
https://bugs.llvm.org/show_bug.cgi?id=18978, which describes the same problem, 
as solved by this patch. This patch presents more efficient solution, with it 
the tests compiles 50 time faster. If r325120 does not solve additional 
problems, it can be reverted.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-08 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 145735.
sepavloff added a comment.

Added treatment of structures/unions


Repository:
  rC Clang

https://reviews.llvm.org/D46241

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

Index: test/SemaCXX/large-array-init.cpp
===
--- 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[1] = {{ 0 }};
-// CHECK: The number of elements to initialize: 1.
-
-struct S *foo() { return arr; }
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/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/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 = };
 
 
-// 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/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/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: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,37 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter , 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 

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-07 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1403
+  if (auto *IL = dyn_cast_or_null(Init)) {
+if (InitTy->isConstantArrayType()) {
+  for (auto I : IL->inits())

sepavloff wrote:
> rjmccall wrote:
> > Do you actually care if it's an array initialization instead of a 
> > struct/enum initialization?
> If this code is enabled for for records too, some tests start to fail. For 
> instance, the code:
> ```
> union { int i; double f; } u2 = { };
> ```
> produces output:
> ```
> %union.anon = type { double }
> @u2 = global %union.anon zeroinitializer, align 4
> ```
> while previously it produced:
> ```
> @u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef }, align 4
> ```
> The latter looks more correct.
Hmm.  In C++, a static object which isn't constant-initialized is 
zero-initialized, which is required to set any padding bits to zero (N4640 
[dcl.init]p6) in both structs and unions.  In C, a static object which doesn't 
have an initializer also has all any padding bits set to zero (N1548 6.7.9p10). 
 Now, this object has an initializer (that acts as a constant-initializer in 
C++), so those rules don't directly apply; but I would argue that the intent of 
the standards is not that padding bits become undefined when you happen to have 
an initializer.  So I actually think the `zeroinitializer` emission is more 
correct.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-07 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1413
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (InitTy->hasPointerRepresentation()) {

rsmith wrote:
> sepavloff wrote:
> > rjmccall wrote:
> > > Aren't the null-pointer and integer-constant-expression checks below 
> > > already checking this?  Also, `isEvaluatable` actually computes the full 
> > > value internally (as an `APValue`), so if you're worried about the memory 
> > > and compile-time effects of producing such a value, you really shouldn't 
> > > call it.
> > > 
> > > You could reasonably move this entire function to be a method on `Expr` 
> > > that takes an `ASTContext`.
> > Comment for `EvaluateAsRValue` says that it tries calculate expression 
> > agressively. Indeed, for the code:
> > ```
> >   decltype(nullptr) null();
> >   int *p = null();
> > ```
> > compiler ignores potential side effect of `null()` and removes the call, 
> > leaving only zero initialization. `isNullPointerConstant` behaves similarly.
> Nonetheless, it looks like this function could evaluate `Init` up to three 
> times, which seems unreasonable. Instead of the checks based on trying to 
> evaluate the initializer (`isNullPointerConstant` + `isIntegerConstantExpr`), 
> how about calling `VarDecl::evaluateValue()` (which will return a potentially 
> pre-computed and cached initializer value) and checking if the result is a 
> zero constant?
> 
> In fact, `tryEmitPrivateForVarInit` already does most of that for you, and 
> the right place to make this change is probably in `tryEmitPrivateForMemory`, 
> where you can test to see if the `APValue` is zero-initialized and produce a 
> `zeroinitializer` if so. As a side-benefit, putting the change there will 
> mean we'll also start using `zeroinitializer` for zero-initialized subobjects 
> of objects that have non-zero pieces.
An important point in this patch is that CodeGen tries to find out, if the 
initializer can be replaced with zeroinitializer, *prior* to the evaluation of 
it. For huge arrays the evaluation consumes huge amount of memory and time and 
it must be avoided.

With this patch CodeGen may evaluate parts of the initializer, if it is 
represented by `InitListExpr`. It may cause redundant calculation, for instance 
if the check for zero initialization failed but the initializer is constant. To 
avoid this redundancy we could cache result of evaluation in instances of 
`Expr` and then use the partial values in the evaluation of the initializer. 
The simple use case solved by this patch probably is not a sufficient 
justification for such redesign.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-07 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 145445.
sepavloff marked an inline comment as done.
sepavloff added a comment.

Avoid redundant initializer calculation


Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  include/clang/AST/Expr.h
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp

Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,27 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+
+  // 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() };
+
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
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 , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  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)) {
+if (InitTy->isConstantArrayType()) {
+  for (auto I : IL->inits())
+if (!isZeroInitializer(CE, I))
+  return false;
+  if (const Expr *Filler = IL->getArrayFiller()) {
+return isZeroInitializer(CE, Filler);
+  }
+  return true;
+}
+  } else {
+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 ) {
   // 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: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -10224,20 +10224,14 @@
  HandleConversionToBool(Scratch.Val, Result);
 }
 
-static bool hasUnacceptableSideEffect(Expr::EvalStatus ,
-  Expr::SideEffectsKind SEK) {
-  return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) ||
- (SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior);
-}
-
 bool Expr::EvaluateAsInt(APSInt , const ASTContext ,
  SideEffectsKind AllowSideEffects) const {
   if (!getType()->isIntegralOrEnumerationType())
 return false;
 
   EvalResult ExprResult;
   if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() ||
-  hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
+  ExprResult.hasUnacceptableSideEffect(AllowSideEffects))
 return false;
 
   Result = ExprResult.Val.getInt();
@@ -10251,7 +10245,7 @@
 
   EvalResult ExprResult;
   if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
-  hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
+  ExprResult.hasUnacceptableSideEffect(AllowSideEffects))
 return false;
 
   Result = ExprResult.Val.getFloat();
@@ -10317,7 +10311,7 @@
 bool Expr::isEvaluatable(const ASTContext , SideEffectsKind SEK) const {
   EvalResult Result;
   return EvaluateAsRValue(Result, Ctx) &&
- 

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-03 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1413
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (InitTy->hasPointerRepresentation()) {

sepavloff wrote:
> rjmccall wrote:
> > Aren't the null-pointer and integer-constant-expression checks below 
> > already checking this?  Also, `isEvaluatable` actually computes the full 
> > value internally (as an `APValue`), so if you're worried about the memory 
> > and compile-time effects of producing such a value, you really shouldn't 
> > call it.
> > 
> > You could reasonably move this entire function to be a method on `Expr` 
> > that takes an `ASTContext`.
> Comment for `EvaluateAsRValue` says that it tries calculate expression 
> agressively. Indeed, for the code:
> ```
>   decltype(nullptr) null();
>   int *p = null();
> ```
> compiler ignores potential side effect of `null()` and removes the call, 
> leaving only zero initialization. `isNullPointerConstant` behaves similarly.
Nonetheless, it looks like this function could evaluate `Init` up to three 
times, which seems unreasonable. Instead of the checks based on trying to 
evaluate the initializer (`isNullPointerConstant` + `isIntegerConstantExpr`), 
how about calling `VarDecl::evaluateValue()` (which will return a potentially 
pre-computed and cached initializer value) and checking if the result is a zero 
constant?

In fact, `tryEmitPrivateForVarInit` already does most of that for you, and the 
right place to make this change is probably in `tryEmitPrivateForMemory`, where 
you can test to see if the `APValue` is zero-initialized and produce a 
`zeroinitializer` if so. As a side-benefit, putting the change there will mean 
we'll also start using `zeroinitializer` for zero-initialized subobjects of 
objects that have non-zero pieces.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-03 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked an inline comment as done.
sepavloff added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1403
+  if (auto *IL = dyn_cast_or_null(Init)) {
+if (InitTy->isConstantArrayType()) {
+  for (auto I : IL->inits())

rjmccall wrote:
> Do you actually care if it's an array initialization instead of a struct/enum 
> initialization?
If this code is enabled for for records too, some tests start to fail. For 
instance, the code:
```
union { int i; double f; } u2 = { };
```
produces output:
```
%union.anon = type { double }
@u2 = global %union.anon zeroinitializer, align 4
```
while previously it produced:
```
@u2 = global { i32, [4 x i8] } { i32 0, [4 x i8] undef }, align 4
```
The latter looks more correct.



Comment at: lib/CodeGen/CGExprConstant.cpp:1413
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (InitTy->hasPointerRepresentation()) {

rjmccall wrote:
> Aren't the null-pointer and integer-constant-expression checks below already 
> checking this?  Also, `isEvaluatable` actually computes the full value 
> internally (as an `APValue`), so if you're worried about the memory and 
> compile-time effects of producing such a value, you really shouldn't call it.
> 
> You could reasonably move this entire function to be a method on `Expr` that 
> takes an `ASTContext`.
Comment for `EvaluateAsRValue` says that it tries calculate expression 
agressively. Indeed, for the code:
```
  decltype(nullptr) null();
  int *p = null();
```
compiler ignores potential side effect of `null()` and removes the call, 
leaving only zero initialization. `isNullPointerConstant` behaves similarly.



Comment at: lib/CodeGen/CGExprConstant.cpp:1417
+if (Init->EvaluateAsRValue(ResVal, CE.CGM.getContext()))
+  return ResVal.Val.isLValue() && ResVal.Val.isNullPointer();
+  } else {

rjmccall wrote:
> There's a `isNullPointerConstant` method (you should use 
> `NPC_NeverValueDependent`).
It make code more readable. Thank you!


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-03 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 145049.
sepavloff marked an inline comment as done.
sepavloff added a comment.

Small simplification


Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp


Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,27 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+
+  // 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() };
+
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,43 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  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)) {
+if (InitTy->isConstantArrayType()) {
+  for (auto I : IL->inits())
+if (!isZeroInitializer(CE, I))
+  return false;
+  if (const Expr *Filler = IL->getArrayFiller()) {
+return isZeroInitializer(CE, Filler);
+  }
+  return true;
+}
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (Init->isNullPointerConstant(CE.CGM.getContext(),
+ Expr::NPC_NeverValueDependent)) {
+return true;
+  } else {
+llvm::APSInt Value;
+if (Init->isIntegerConstantExpr(Value, CE.CGM.getContext()))
+  return Value.isNullValue();
+  }
+
+  return false;
+}
+
 llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl ) {
   // 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/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,27 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+
+  // 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() };
+
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,43 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  if (auto *E = 

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-02 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1403
+  if (auto *IL = dyn_cast_or_null(Init)) {
+if (InitTy->isConstantArrayType()) {
+  for (auto I : IL->inits())

Do you actually care if it's an array initialization instead of a struct/enum 
initialization?



Comment at: lib/CodeGen/CGExprConstant.cpp:1413
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (InitTy->hasPointerRepresentation()) {

Aren't the null-pointer and integer-constant-expression checks below already 
checking this?  Also, `isEvaluatable` actually computes the full value 
internally (as an `APValue`), so if you're worried about the memory and 
compile-time effects of producing such a value, you really shouldn't call it.

You could reasonably move this entire function to be a method on `Expr` that 
takes an `ASTContext`.



Comment at: lib/CodeGen/CGExprConstant.cpp:1417
+if (Init->EvaluateAsRValue(ResVal, CE.CGM.getContext()))
+  return ResVal.Val.isLValue() && ResVal.Val.isNullPointer();
+  } else {

There's a `isNullPointerConstant` method (you should use 
`NPC_NeverValueDependent`).


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff marked 3 inline comments as done.
sepavloff added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1414
+  return true;
+}
+  }

rjmccall wrote:
> You should check the array fill expression here; for now, the test case would 
> be something like `StructWithNonTrivialDefaultInit sArr[10] = {};`.
Indeed, this is the missing case. Thank you!


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-05-02 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 144898.
sepavloff added a comment.

Addressed review notes.


Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp


Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,27 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+
+  // 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() };
+
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,44 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  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)) {
+if (InitTy->isConstantArrayType()) {
+  for (auto I : IL->inits())
+if (!isZeroInitializer(CE, I))
+  return false;
+  if (const Expr *Filler = IL->getArrayFiller()) {
+return isZeroInitializer(CE, Filler);
+  }
+  return true;
+}
+  } else if (!Init->isEvaluatable(CE.CGM.getContext())) {
+return false;
+  } else if (InitTy->hasPointerRepresentation()) {
+Expr::EvalResult ResVal;
+if (Init->EvaluateAsRValue(ResVal, CE.CGM.getContext()))
+  return ResVal.Val.isLValue() && ResVal.Val.isNullPointer();
+  } else {
+llvm::APSInt Value;
+if (Init->isIntegerConstantExpr(Value, CE.CGM.getContext()))
+  return Value.isNullValue();
+  }
+
+  return false;
+}
+
 llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl ) {
   // 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/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,27 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+  constexpr int *null() { return nullptr; }
+  struct Filler {
+int x;
+Filler();
+  };
+
+  // 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() };
+
+
+  // This variable must be initialized elementwise.
+  Filler data_e1[1024] = {};
+  // CHECK: getelementptr inbounds {{.*}} @_ZN8ZeroInit7data_e1E
+}
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,44 @@
   return type;
 }
 
+/// Checks if the specified initializer is equivalent to zero initialization.
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  if (auto 

[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-04-30 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: lib/CodeGen/CGExprConstant.cpp:1395
 
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();

You should have a comment here clarifying that this is checking whether the 
initializer is equivalent to a C++ zero initialization, not checking whether 
the initializer produces a zero bit-pattern.



Comment at: lib/CodeGen/CGExprConstant.cpp:1414
+  return true;
+}
+  }

You should check the array fill expression here; for now, the test case would 
be something like `StructWithNonTrivialDefaultInit sArr[10] = {};`.



Comment at: lib/CodeGen/CGExprConstant.cpp:1415
+}
+  }
+  return false;

I would suggest doing your primary switch over the form of Init instead of its 
type, and you can just have an isIntegerConstantExpr check at the end.

You should also check for a null pointer expression.


Repository:
  rC Clang

https://reviews.llvm.org/D46241



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46241: [CodeGen] Recognize more cases of zero initialization

2018-04-29 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff created this revision.
sepavloff added reviewers: rjmccall, rsmith.

If a variable has initializer, codegen tries to build its value. It
causes strange behavior from user viewpoint: compilation of huge zero
initialized arrays like:

  int char data_1[2147483648u] = { 0 };

consumes enormous amount of time and memory.

With this change compiler recognizes more patterns when variable is
initialized with zeros and elementwise treatment can be avoided.


Repository:
  rC Clang

https://reviews.llvm.org/D46241

Files:
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGenCXX/cxx11-initializer-aggregate.cpp


Index: test/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,15 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+
+  // 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() };
+}
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,36 @@
   return type;
 }
 
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  QualType BaseTy = CE.CGM.getContext().getBaseElementType(InitTy);
+  if (BaseTy->isRecordType()) {
+if (auto *E = dyn_cast_or_null(Init)) {
+CXXConstructorDecl *CD = E->getConstructor();
+if (CD->isDefaultConstructor() && CD->isTrivial())
+return true;
+}
+  } else if (InitTy->isIntegerType()) {
+llvm::APSInt Value;
+if (Init->isIntegerConstantExpr(Value, CE.CGM.getContext()))
+  return Value.isNullValue();
+  } else if (InitTy->isConstantArrayType()) {
+if (auto *IL = dyn_cast_or_null(Init)) {
+  for (auto I : IL->inits())
+if (!isZeroInitializer(CE, I))
+  return false;
+  return true;
+}
+  }
+  return false;
+}
+
 llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl ) {
   // 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/CodeGenCXX/cxx11-initializer-aggregate.cpp
===
--- test/CodeGenCXX/cxx11-initializer-aggregate.cpp
+++ test/CodeGenCXX/cxx11-initializer-aggregate.cpp
@@ -51,3 +51,15 @@
   // meaningful.
   B b[30] = {};
 }
+
+namespace ZeroInit {
+  enum { Zero, One };
+  constexpr int zero() { return 0; }
+
+  // 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() };
+}
Index: lib/CodeGen/CGExprConstant.cpp
===
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1392,20 +1392,36 @@
   return type;
 }
 
+static bool isZeroInitializer(ConstantEmitter , const Expr *Init) {
+  QualType InitTy = Init->getType().getCanonicalType();
+  QualType BaseTy = CE.CGM.getContext().getBaseElementType(InitTy);
+  if (BaseTy->isRecordType()) {
+if (auto *E = dyn_cast_or_null(Init)) {
+CXXConstructorDecl *CD = E->getConstructor();
+if (CD->isDefaultConstructor() && CD->isTrivial())
+return true;
+}
+  } else if (InitTy->isIntegerType()) {
+llvm::APSInt Value;
+if (Init->isIntegerConstantExpr(Value, CE.CGM.getContext()))
+  return Value.isNullValue();
+  } else if (InitTy->isConstantArrayType()) {
+if (auto *IL = dyn_cast_or_null(Init)) {
+  for (auto I : IL->inits())
+if (!isZeroInitializer(CE, I))
+  return false;
+  return true;
+}
+  }
+  return false;
+}
+
 llvm::Constant