forked from OSchip/llvm-project
Emit initializers for static-storage-duration temporaries as constants where
possible. llvm-svn: 183967
This commit is contained in:
parent
18db1f2f1a
commit
a509f2fdfa
|
@ -4093,6 +4093,7 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
|
|||
APValue *Value;
|
||||
if (E->getStorageDuration() == SD_Static) {
|
||||
Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
|
||||
*Value = APValue();
|
||||
Result.set(E);
|
||||
} else {
|
||||
Value = &Info.CurrentCall->Temporaries[E];
|
||||
|
|
|
@ -321,6 +321,13 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
|
|||
llvm::Value *Object = createReferenceTemporary(*this, M, E);
|
||||
LValue RefTempDst = MakeAddrLValue(Object, M->getType());
|
||||
|
||||
if (llvm::GlobalVariable *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
|
||||
// We should not have emitted the initializer for this temporary as a
|
||||
// constant.
|
||||
assert(!Var->hasInitializer());
|
||||
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
|
||||
}
|
||||
|
||||
EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false);
|
||||
|
||||
pushTemporaryCleanup(*this, M, E, Object);
|
||||
|
@ -343,7 +350,16 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
|
|||
|
||||
// Create and initialize the reference temporary.
|
||||
llvm::Value *Object = createReferenceTemporary(*this, M, E);
|
||||
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
|
||||
if (llvm::GlobalVariable *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
|
||||
// If the temporary is a global and has a constant initializer, we may
|
||||
// have already initialized it.
|
||||
if (!Var->hasInitializer()) {
|
||||
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
|
||||
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
|
||||
}
|
||||
} else {
|
||||
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
|
||||
}
|
||||
pushTemporaryCleanup(*this, M, E, Object);
|
||||
|
||||
// Perform derived-to-base casts and/or field accesses, to get from the
|
||||
|
|
|
@ -2615,15 +2615,16 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str,
|
|||
}
|
||||
|
||||
llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
|
||||
const MaterializeTemporaryExpr *E, const Expr *Inner) {
|
||||
const MaterializeTemporaryExpr *E, const Expr *Init) {
|
||||
assert((E->getStorageDuration() == SD_Static ||
|
||||
E->getStorageDuration() == SD_Thread) && "not a global temporary");
|
||||
const VarDecl *VD = cast<VarDecl>(E->getExtendingDecl());
|
||||
|
||||
// If we're not materializing a subobject of the temporary, keep the
|
||||
// cv-qualifiers from the type of the MaterializeTemporaryExpr.
|
||||
if (Inner == E->GetTemporaryExpr())
|
||||
Inner = E;
|
||||
QualType MaterializedType = Init->getType();
|
||||
if (Init == E->GetTemporaryExpr())
|
||||
MaterializedType = E->getType();
|
||||
|
||||
llvm::Constant *&Slot = MaterializedGlobalTemporaryMap[E];
|
||||
if (Slot)
|
||||
|
@ -2637,34 +2638,44 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
|
|||
getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
|
||||
Out.flush();
|
||||
|
||||
llvm::Constant *InitialValue = 0;
|
||||
APValue *Value = 0;
|
||||
if (E->getStorageDuration() == SD_Static) {
|
||||
// We might have a constant initializer for this temporary.
|
||||
// We might have a cached constant initializer for this temporary. Note
|
||||
// that this might have a different value from the value computed by
|
||||
// evaluating the initializer if the surrounding constant expression
|
||||
// modifies the temporary.
|
||||
Value = getContext().getMaterializedTemporaryValue(E, false);
|
||||
if (Value && Value->isUninit())
|
||||
Value = 0;
|
||||
}
|
||||
|
||||
bool Constant;
|
||||
// Try evaluating it now, it might have a constant initializer.
|
||||
Expr::EvalResult EvalResult;
|
||||
if (!Value && Init->EvaluateAsRValue(EvalResult, getContext()) &&
|
||||
!EvalResult.hasSideEffects())
|
||||
Value = &EvalResult.Val;
|
||||
|
||||
llvm::Constant *InitialValue = 0;
|
||||
bool Constant = false;
|
||||
llvm::Type *Type;
|
||||
if (Value) {
|
||||
// The temporary has a constant initializer, use it.
|
||||
InitialValue = EmitConstantValue(*Value, Inner->getType(), 0);
|
||||
Constant = isTypeConstant(Inner->getType(), /*ExcludeCtor*/Value);
|
||||
InitialValue = EmitConstantValue(*Value, MaterializedType, 0);
|
||||
Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value);
|
||||
Type = InitialValue->getType();
|
||||
} else {
|
||||
// No constant initializer, the initialization will be provided when we
|
||||
// No initializer, the initialization will be provided when we
|
||||
// initialize the declaration which performed lifetime extension.
|
||||
InitialValue = EmitNullConstant(Inner->getType());
|
||||
Constant = false;
|
||||
Type = getTypes().ConvertTypeForMem(MaterializedType);
|
||||
}
|
||||
|
||||
// Create a global variable for this lifetime-extended temporary.
|
||||
llvm::GlobalVariable *GV =
|
||||
new llvm::GlobalVariable(getModule(), InitialValue->getType(), Constant,
|
||||
llvm::GlobalValue::PrivateLinkage, InitialValue,
|
||||
Name.c_str());
|
||||
new llvm::GlobalVariable(getModule(), Type, Constant,
|
||||
llvm::GlobalValue::PrivateLinkage,
|
||||
InitialValue, Name.c_str());
|
||||
GV->setAlignment(
|
||||
getContext().getTypeAlignInChars(Inner->getType()).getQuantity());
|
||||
getContext().getTypeAlignInChars(MaterializedType).getQuantity());
|
||||
if (VD->getTLSKind())
|
||||
setTLSMode(GV, *VD);
|
||||
Slot = GV;
|
||||
|
|
|
@ -24,6 +24,25 @@ namespace ModifyStaticTemporary {
|
|||
A a = { 6, f(a.temporary) };
|
||||
// CHECK: @_ZGRN21ModifyStaticTemporary1aE = private global i32 54
|
||||
// CHECK: @_ZN21ModifyStaticTemporary1aE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1aE, i32 42
|
||||
|
||||
A b = { 7, ++b.temporary };
|
||||
// CHECK: @_ZGRN21ModifyStaticTemporary1bE = private global i32 8
|
||||
// CHECK: @_ZN21ModifyStaticTemporary1bE = global {{.*}} i32* @_ZGRN21ModifyStaticTemporary1bE, i32 8
|
||||
|
||||
// Can't emit all of 'c' as a constant here, so emit the initial value of
|
||||
// 'c.temporary', not the value as modified by the partial evaluation within
|
||||
// the initialization of 'c.x'.
|
||||
A c = { 10, (++c.temporary, b.x) };
|
||||
// CHECK: @_ZGRN21ModifyStaticTemporary1cE = private global i32 10
|
||||
// CHECK: @_ZN21ModifyStaticTemporary1cE = global {{.*}} zeroinitializer
|
||||
}
|
||||
|
||||
// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b
|
||||
|
||||
// CHECK: define
|
||||
// CHECK-NOT: @_ZGRN21ModifyStaticTemporary1cE
|
||||
// CHECK: store {{.*}} @_ZGRN21ModifyStaticTemporary1cE, {{.*}} @_ZN21ModifyStaticTemporary1cE
|
||||
// CHECK: add
|
||||
// CHECK: store
|
||||
// CHECK: load {{.*}} @_ZN21ModifyStaticTemporary1bE
|
||||
// CHECK: store {{.*}} @_ZN21ModifyStaticTemporary1cE
|
||||
|
|
|
@ -50,8 +50,9 @@ namespace std {
|
|||
};
|
||||
}
|
||||
|
||||
constexpr int a = 2, b = 4, c = 6;
|
||||
std::initializer_list<std::initializer_list<int>> nested = {
|
||||
{1, 2}, {3, 4}, {5, 6}
|
||||
{1, a}, {3, b}, {5, c}
|
||||
};
|
||||
|
||||
// CHECK-STATIC-BL: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4
|
||||
|
@ -70,17 +71,17 @@ std::initializer_list<std::initializer_list<int>> nested = {
|
|||
// CHECK-DYNAMIC-BL: @_ZGR6nested2 = private global [2 x i32] zeroinitializer
|
||||
// CHECK-DYNAMIC-BL: @_ZGR6nested3 = private global [2 x i32] zeroinitializer
|
||||
// CHECK-DYNAMIC-BL: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
|
||||
// CHECK-DYNAMIC-BL: store i32 2, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
|
||||
// CHECK-DYMAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
|
||||
// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
|
||||
// CHECK-DYNAMIC-BL: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
|
||||
// CHECK-DYNAMIC-BL: store i32 4, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
|
||||
// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
|
||||
// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
|
||||
// CHECK-DYNAMIC-BL: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0)
|
||||
// CHECK-DYNAMIC-BL: store i32 6, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0),
|
||||
// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8
|
||||
// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8
|
||||
|
@ -108,19 +109,19 @@ std::initializer_list<std::initializer_list<int>> nested = {
|
|||
// CHECK-DYNAMIC-BE: @_ZGR6nested2 = private global [2 x i32] zeroinitializer
|
||||
// CHECK-DYNAMIC-BE: @_ZGR6nested3 = private global [2 x i32] zeroinitializer
|
||||
// CHECK-DYNAMIC-BE: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
|
||||
// CHECK-DYNAMIC-BE: store i32 2, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
|
||||
// CHECK-DYMAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
|
||||
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 1, i64 0),
|
||||
// CHECK-DYMAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
|
||||
// CHECK-DYNAMIC-BE: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
|
||||
// CHECK-DYNAMIC-BE: store i32 4, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
|
||||
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
|
||||
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 1, i64 0),
|
||||
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
|
||||
// CHECK-DYNAMIC-BE: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0)
|
||||
// CHECK-DYNAMIC-BE: store i32 6, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
|
||||
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0),
|
||||
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8
|
||||
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 1, i64 0),
|
||||
|
|
|
@ -57,21 +57,26 @@ namespace thread_local_global_array {
|
|||
// objects aren't really a problem).
|
||||
//
|
||||
// CHECK: @_ZN25thread_local_global_array1xE = thread_local global
|
||||
// CHECK: @_ZGRN25thread_local_global_array1xE = private thread_local global [4 x i32]
|
||||
// CHECK: @_ZGRN25thread_local_global_array1xE = private thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
|
||||
std::initializer_list<int> thread_local x = { 1, 2, 3, 4 };
|
||||
}
|
||||
|
||||
// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
|
||||
// CHECK: @_ZGR15globalInitList2 = private global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
|
||||
|
||||
// CHECK: @_ZN15partly_constant1kE = global i32 0, align 4
|
||||
// CHECK: @_ZN15partly_constant2ilE = global {{.*}} null, align 8
|
||||
// CHECK: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = private global {{.*}} zeroinitializer, align 8
|
||||
// CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = private global [3 x {{.*}}] zeroinitializer, align 8
|
||||
// CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = private constant [3 x i32] [i32 1, i32 2, i32 3], align 4
|
||||
// CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = private global [2 x i32] zeroinitializer, align 4
|
||||
// CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = private constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
|
||||
|
||||
// CHECK: appending global
|
||||
|
||||
|
||||
// thread_local initializer:
|
||||
// CHECK: define internal void
|
||||
// CHECK: store i32 1, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 0)
|
||||
// CHECK: store i32 2, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 1)
|
||||
// CHECK: store i32 3, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 2)
|
||||
// CHECK: store i32 4, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 3)
|
||||
// CHECK: store i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8
|
||||
// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8
|
||||
|
@ -354,3 +359,39 @@ namespace dtors {
|
|||
// CHECK: br i1
|
||||
}
|
||||
}
|
||||
|
||||
namespace partly_constant {
|
||||
int k;
|
||||
std::initializer_list<std::initializer_list<int>> &&il = { { 1, 2, 3 }, { 4, k }, { 5, 6, 7, 8 } };
|
||||
// First init list.
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]],
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_FIRST]], i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 0)
|
||||
// CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 1)
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]],
|
||||
//
|
||||
// Second init list array (non-constant).
|
||||
// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0)
|
||||
// CHECK: load i32* @_ZN15partly_constant1kE
|
||||
// CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 1)
|
||||
//
|
||||
// Second init list.
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 0)
|
||||
// CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 1)
|
||||
//
|
||||
// Third init list.
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_THIRD]], i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 2, i32 0)
|
||||
// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}* @_ZGRN15partly_constant2ilE4, i64 0, i64 2, i32 1)
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],
|
||||
//
|
||||
// Outer init list.
|
||||
// CHECK: store {{.*}}* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0),
|
||||
// CHECK: {{.*}}** getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 0)
|
||||
// CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 1)
|
||||
//
|
||||
// 'il' reference.
|
||||
// CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue