r332847 - [CodeGen] Recognize more cases of zero initialization
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon May 21 13:22:12 PDT 2018
On 21 May 2018 at 09:09, Serge Pavlov via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> 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))
>
As I mentioned on the review thread, this is wrong, and you need to call
D->evaluateValue() here instead.
> + 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; }
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180521/198fdf87/attachment-0001.html>
More information about the cfe-commits
mailing list