r332847 - [CodeGen] Recognize more cases of zero initialization
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon May 21 13:28:32 PDT 2018
On 21 May 2018 at 13:22, Richard Smith <richard at metafoo.co.uk> wrote:
> 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/ExprCo
>> nstant.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/CG
>> ExprConstant.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.
>
Actually, evaluateValue() isn't quite right here either, because we may
have drilled into the initializer already. Here's a simple example of code
you miscompile:
int f() { static const int &&r = {0}; return r; }
Prior to your patch this would be properly initialized; after your patch,
due to the incorrect call to EvaluateAsRValue, we "zero-initialize" the
reference.
Your patch will also result in our re-evaluating the initializers of
variables that we've already evaluated.
> + 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/CodeGenCX
>> X/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/CodeGenCX
>> X/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/37517f8c/attachment-0001.html>
More information about the cfe-commits
mailing list