diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-02 23:27:11 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-02 23:27:11 +0000 |
commit | a3ca41f0c2bd1c4a752df88b283332f3b757d21e (patch) | |
tree | 8aab234057f7a0c60c5d1bc20ad31ebb07d5977e | |
parent | 067cc40308a9643400fd291fc8678c4a6785e90c (diff) |
Reinstate r151879, r151880, reverted in r151922, along with a bugfix for
scalar emission of DeclRefExprs to const bools: emit scalar bools as i1,
not as i8.
In addition to the extra unit testing, this has successfully bootstrapped.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151955 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 42 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 24 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 10 | ||||
-rw-r--r-- | test/CodeGenCXX/const-init-cxx11.cpp | 72 |
5 files changed, 121 insertions, 30 deletions
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 2803640bda..61c10bbe4f 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -511,7 +511,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, const APValue &FieldValue = RD->isUnion() ? Val.getUnionValue() : Val.getStructField(FieldNo); llvm::Constant *EltInit = - CGM.EmitConstantValue(FieldValue, Field->getType(), CGF); + CGM.EmitConstantValueForMemory(FieldValue, Field->getType(), CGF); assert(EltInit && "EmitConstantValue can't fail"); if (!Field->isBitField()) { @@ -1015,7 +1015,7 @@ public: llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, CodeGenFunction *CGF) { if (const APValue *Value = D.evaluateValue()) - return EmitConstantValue(*Value, D.getType(), CGF); + return EmitConstantValueForMemory(*Value, D.getType(), CGF); // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a // reference is a constant expression, and the reference binds to a temporary, @@ -1049,10 +1049,12 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, else Success = E->EvaluateAsRValue(Result, Context); + llvm::Constant *C = 0; if (Success && !Result.HasSideEffects) - return EmitConstantValue(Result.Val, DestType, CGF); + C = EmitConstantValue(Result.Val, DestType, CGF); + else + C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E)); - llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E)); if (C && C->getType()->isIntegerTy(1)) { llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); C = llvm::ConstantExpr::getZExt(C, BoolTy); @@ -1110,16 +1112,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, return C; } } - case APValue::Int: { - llvm::Constant *C = llvm::ConstantInt::get(VMContext, - Value.getInt()); - - if (C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType); - C = llvm::ConstantExpr::getZExt(C, BoolTy); - } - return C; - } + case APValue::Int: + return llvm::ConstantInt::get(VMContext, Value.getInt()); case APValue::ComplexInt: { llvm::Constant *Complex[2]; @@ -1199,16 +1193,16 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, // Emit array filler, if there is one. llvm::Constant *Filler = 0; if (Value.hasArrayFiller()) - Filler = EmitConstantValue(Value.getArrayFiller(), - CAT->getElementType(), CGF); + Filler = EmitConstantValueForMemory(Value.getArrayFiller(), + CAT->getElementType(), CGF); // Emit initializer elements. llvm::Type *CommonElementType = 0; for (unsigned I = 0; I < NumElements; ++I) { llvm::Constant *C = Filler; if (I < NumInitElts) - C = EmitConstantValue(Value.getArrayInitializedElt(I), - CAT->getElementType(), CGF); + C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I), + CAT->getElementType(), CGF); if (I == 0) CommonElementType = C->getType(); else if (C->getType() != CommonElementType) @@ -1237,6 +1231,18 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, } llvm::Constant * +CodeGenModule::EmitConstantValueForMemory(const APValue &Value, + QualType DestType, + CodeGenFunction *CGF) { + llvm::Constant *C = EmitConstantValue(Value, DestType, CGF); + if (C->getType()->isIntegerTy(1)) { + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType); + C = llvm::ConstantExpr::getZExt(C, BoolTy); + } + return C; +} + +llvm::Constant * CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) { assert(E->isFileScope() && "not a file-scope compound literal expr"); return ConstExprEmitter(*this, 0).EmitLValue(E); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 125e431bff..f7ab880e6c 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -212,18 +212,21 @@ public: // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { Expr::EvalResult Result; - if (!E->EvaluateAsRValue(Result, CGF.getContext())) - return EmitLoadOfLValue(E); + bool IsReferenceConstant = false; + QualType EvalTy = E->getType(); + if (!E->EvaluateAsRValue(Result, CGF.getContext())) { + // If this is a reference, try to determine what it is bound to. + if (!E->getDecl()->getType()->isReferenceType() || + !E->EvaluateAsLValue(Result, CGF.getContext())) + return EmitLoadOfLValue(E); + + IsReferenceConstant = true; + EvalTy = E->getDecl()->getType(); + } assert(!Result.HasSideEffects && "Constant declref with side-effect?!"); - llvm::Constant *C; - if (Result.Val.isInt()) - C = Builder.getInt(Result.Val.getInt()); - else if (Result.Val.isFloat()) - C = llvm::ConstantFP::get(VMContext, Result.Val.getFloat()); - else - return EmitLoadOfLValue(E); + llvm::Constant *C = CGF.CGM.EmitConstantValue(Result.Val, EvalTy, &CGF); // Make sure we emit a debug reference to the global variable. if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) { @@ -233,6 +236,9 @@ public: CGF.EmitDeclRefExprDbgValue(E, C); } + if (IsReferenceConstant) + return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(C, E->getType())); + return C; } Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) { diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a3a71b7e52..922a5df344 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1472,7 +1472,8 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D, } // Emit the constant for the initializer_list. - llvm::Constant *llvmInit = EmitConstantValue(initListValue, D->getType()); + llvm::Constant *llvmInit = + EmitConstantValueForMemory(initListValue, D->getType()); assert(llvmInit && "failed to initialize as constant"); return llvmInit; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 8bbee6a284..ba4887d057 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -706,11 +706,17 @@ public: llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, CodeGenFunction *CGF = 0); - /// EmitConstantValue - Try to emit the given constant value as a - /// constant; returns 0 if the value cannot be emitted as a constant. + /// EmitConstantValue - Emit the given constant value as a constant, in the + /// type's scalar representation. llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType, CodeGenFunction *CGF = 0); + /// EmitConstantValueForMemory - Emit the given constant value as a constant, + /// in the type's memory representation. + llvm::Constant *EmitConstantValueForMemory(const APValue &Value, + QualType DestType, + CodeGenFunction *CGF = 0); + /// EmitNullConstant - Return the result of value-initializing the given /// type, i.e. a null expression of the given type. This is usually, /// but not always, an LLVM null constant. diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 5366d6d485..a1486c1175 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -337,3 +337,75 @@ namespace VirtualBase { X<D> x; // CHECK: call {{.*}}@_ZN11VirtualBase1XINS_1DEEC1Ev } + +// PR12145 +namespace Unreferenced { + int n; + constexpr int *p = &n; + // We must not emit a load of 'p' here, since it's not odr-used. + int q = *p; + // CHECK-NOT: _ZN12Unreferenced1pE + // CHECK: = load i32* @_ZN12Unreferenced1nE + // CHECK-NEXT: store i32 {{.*}}, i32* @_ZN12Unreferenced1qE + // CHECK-NOT: _ZN12Unreferenced1pE + + // Technically, we are not required to substitute variables of reference types + // initialized by constant expressions, because the special case for odr-use + // of variables in [basic.def.odr]p2 only applies to objects. But we do so + // anyway. + + constexpr int &r = n; + // CHECK-NOT: _ZN12Unreferenced1rE + int s = r; + + const int t = 1; + const int &rt = t; + int f(int); + int u = f(rt); + // CHECK: call i32 @_ZN12Unreferenced1fEi(i32 1) +} + +namespace InitFromConst { + template<typename T> void consume(T); + + const bool b = true; + const int n = 5; + const double d = 4.3; + + struct S { int n = 7; S *p = 0; }; + constexpr S s = S(); + const S &r = s; + constexpr const S *p = &r; + constexpr int S::*mp = &S::n; + constexpr int a[3] = { 1, 4, 9 }; + + void test() { + // CHECK: call void @_ZN13InitFromConst7consumeIbEEvT_(i1 zeroext true) + consume(b); + + // CHECK: call void @_ZN13InitFromConst7consumeIiEEvT_(i32 5) + consume(n); + + // CHECK: call void @_ZN13InitFromConst7consumeIdEEvT_(double 4.300000e+00) + consume(d); + + // CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE) + consume<const S&>(s); + + // FIXME CHECK-NOT: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE) + // There's no lvalue-to-rvalue conversion here, so 'r' is odr-used, and + // we're permitted to emit a load of it. This seems likely to be a defect + // in the standard. If we start emitting a direct reference to 's', update + // this test. + consume<const S&>(r); + + // CHECK: call void @_ZN13InitFromConst7consumeIPKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE) + consume(p); + + // CHECK: call void @_ZN13InitFromConst7consumeIMNS_1SEiEEvT_(i64 0) + consume(mp); + + // CHECK: call void @_ZN13InitFromConst7consumeIPKiEEvT_(i32* getelementptr inbounds ([3 x i32]* @_ZN13InitFromConstL1aE, i32 0, i32 0)) + consume(a); + } +} |