arphaman created this revision. C++ allows us to reference static variables through member expressions. Prior to this patch, non-integer static variables that were referenced using a member expression were always emitted using lvalue loads. The old behaviour introduced an inconsistency between regular uses of static variables and member expressions uses, for example, the following program compiled and linked successfully:
struct Foo { constexpr static const char *name = "foo"; }; int main() { return Foo::name[0] == 'f'; } but this program failed to link because "Foo::name" wasn't found: struct Foo { constexpr static const char *name = "foo"; }; int main() { Foo f; return f.name[0] == 'f'; } This patch ensures that static variables referenced through member expressions are emitted in the same way as ordinary static variable references. rdar://33942261 Repository: rL LLVM https://reviews.llvm.org/D36876 Files: lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/member-expr-references-variable.cpp
Index: test/CodeGenCXX/member-expr-references-variable.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/member-expr-references-variable.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +struct Struct { + constexpr static const char *name = "foo"; + + constexpr static __complex float complexValue = 42.0; + + Struct(); + Struct(int x); +}; + +void use(int n, const char *c); + +Struct *getPtr(); + +// CHECK: @[[STR:.*]] = private unnamed_addr constant [4 x i8] c"foo\00", align 1 + +void scalarStaticVariableInMemberExpr(Struct *ptr, Struct &ref) { + use(1, Struct::name); +// CHECK: call void @_Z3useiPKc(i32 1, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) + Struct s; + use(2, s.name); +// CHECK: call void @_Z3useiPKc(i32 2, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) + use(3, ptr->name); +// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 +// CHECK: call void @_Z3useiPKc(i32 3, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) + use(4, ref.name); +// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 +// CHECK: call void @_Z3useiPKc(i32 4, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) + use(5, Struct(2).name); +// CHECK: call void @_ZN6StructC1Ei(%struct.Struct* %{{.*}}, i32 2) +// CHECK: call void @_Z3useiPKc(i32 5, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) + use(6, getPtr()->name); +// CHECK: call %struct.Struct* @_Z6getPtrv() +// CHECK: call void @_Z3useiPKc(i32 6, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) +} + +void use(int n, __complex float v); + +void complexStaticVariableInMemberExpr(Struct *ptr, Struct &ref) { + use(1, Struct::complexValue); +// CHECK: store float 4.200000e+01, float* %[[coerce0:.*]].{{.*}}, align 4 +// CHECK: store float 0.000000e+00, float* %[[coerce0]].{{.*}}, align 4 +// CHECK: %[[cast0:.*]] = bitcast { float, float }* %[[coerce0]] to <2 x float>* +// CHECK: %[[vector0:.*]] = load <2 x float>, <2 x float>* %[[cast0]], align 4 +// CHECK: call void @_Z3useiCf(i32 1, <2 x float> %[[vector0]]) + Struct s; + use(2, s.complexValue); +// CHECK: store float 4.200000e+01, float* %[[coerce1:.*]].{{.*}}, align 4 +// CHECK: store float 0.000000e+00, float* %[[coerce1]].{{.*}}, align 4 +// CHECK: %[[cast1:.*]] = bitcast { float, float }* %[[coerce1]] to <2 x float>* +// CHECK: %[[vector1:.*]] = load <2 x float>, <2 x float>* %[[cast1]], align 4 +// CHECK: call void @_Z3useiCf(i32 2, <2 x float> %[[vector1]]) + use(3, ptr->complexValue); +// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 +// CHECK: store float 4.200000e+01, float* %[[coerce2:.*]].{{.*}}, align 4 +// CHECK: store float 0.000000e+00, float* %[[coerce2]].{{.*}}, align 4 +// CHECK: %[[cast2:.*]] = bitcast { float, float }* %[[coerce2]] to <2 x float>* +// CHECK: %[[vector2:.*]] = load <2 x float>, <2 x float>* %[[cast2]], align 4 +// CHECK: call void @_Z3useiCf(i32 3, <2 x float> %[[vector2]]) + use(4, ref.complexValue); +// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 +// CHECK: store float 4.200000e+01, float* %[[coerce3:.*]].{{.*}}, align 4 +// CHECK: store float 0.000000e+00, float* %[[coerce3]].{{.*}}, align 4 +// CHECK: %[[cast3:.*]] = bitcast { float, float }* %[[coerce3]] to <2 x float>* +// CHECK: %[[vector3:.*]] = load <2 x float>, <2 x float>* %[[cast3]], align 4 +// CHECK: call void @_Z3useiCf(i32 4, <2 x float> %[[vector3]]) + use(5, Struct(2).complexValue); +// CHECK: call void @_ZN6StructC1Ei(%struct.Struct* %{{.*}}, i32 2) +// CHECK: store float 4.200000e+01, float* %[[coerce4:.*]].{{.*}}, align 4 +// CHECK: store float 0.000000e+00, float* %[[coerce4]].{{.*}}, align 4 +// CHECK: %[[cast4:.*]] = bitcast { float, float }* %[[coerce4]] to <2 x float>* +// CHECK: %[[vector4:.*]] = load <2 x float>, <2 x float>* %[[cast4]], align 4 +// CHECK: call void @_Z3useiCf(i32 5, <2 x float> %[[vector4]]) + use(6, getPtr()->complexValue); +// CHECK: call %struct.Struct* @_Z6getPtrv() +// CHECK: store float 4.200000e+01, float* %[[coerce5:.*]].{{.*}}, align 4 +// CHECK: store float 0.000000e+00, float* %[[coerce5]].{{.*}}, align 4 +// CHECK: %[[cast5:.*]] = bitcast { float, float }* %[[coerce5]] to <2 x float>* +// CHECK: %[[vector5:.*]] = load <2 x float>, <2 x float>* %[[cast5]], align 4 +// CHECK: call void @_Z3useiCf(i32 6, <2 x float> %[[vector5]]) +} Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -3158,7 +3158,9 @@ } }; - ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr); + ConstantEmission + tryEmitDeclRefOrMemberExprAsConstant(Expr *E, ValueDecl *Value, + bool AllowSideEffects = false); RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e, AggValueSlot slot = AggValueSlot::ignored()); @@ -3190,7 +3192,7 @@ LValue EmitStmtExprLValue(const StmtExpr *E); LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E); LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E); - void EmitDeclRefExprDbgValue(const DeclRefExpr *E, const APValue &Init); + void EmitDeclRefOrMemberExprDbgValue(const Expr *E, const APValue &Init); //===--------------------------------------------------------------------===// // Scalar Expression Emission Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -2007,12 +2007,17 @@ return EmitLValue(E).getAddress(); } -void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E, - const APValue &Init) { +void CodeGenFunction::EmitDeclRefOrMemberExprDbgValue(const Expr *E, + const APValue &Init) { + const ValueDecl *VD; + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + VD = DRE->getDecl(); + else + VD = cast<MemberExpr>(E)->getMemberDecl(); assert(!Init.isUninit() && "Invalid DeclRefExpr initializer!"); if (CGDebugInfo *Dbg = getDebugInfo()) if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) - Dbg->EmitGlobalVariable(E->getDecl(), Init); + Dbg->EmitGlobalVariable(VD, Init); } CodeGenFunction::PeepholeProtection Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -429,13 +429,21 @@ } // l-values. - Value *VisitDeclRefExpr(DeclRefExpr *E) { - if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) { + Value *tryEmitDeclRefOrMemberExprAsConstant(Expr *E, ValueDecl *VD, + bool AllowSideEffects = false) { + if (CodeGenFunction::ConstantEmission result = + CGF.tryEmitDeclRefOrMemberExprAsConstant(E, VD, AllowSideEffects)) { if (result.isReference()) return EmitLoadOfLValue(result.getReferenceLValue(CGF, E), E->getExprLoc()); return result.getValue(); } + return nullptr; + } + + Value *VisitDeclRefExpr(DeclRefExpr *E) { + if (Value *V = tryEmitDeclRefOrMemberExprAsConstant(E, E->getDecl())) + return V; return EmitLoadOfLValue(E); } @@ -1299,13 +1307,24 @@ } Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { - llvm::APSInt Value; - if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) { + Value *V; + if (isa<VarDecl>(E->getMemberDecl())) { + V = tryEmitDeclRefOrMemberExprAsConstant(E, E->getMemberDecl(), + /*AllowSideEffects=*/true); + } else { + // Fields can evaluate to constants if their base can be evaluated. + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) + V = Builder.getInt(Value); + else + V = nullptr; + } + if (V) { if (E->isArrow()) CGF.EmitScalarExpr(E->getBase()); else EmitLValue(E->getBase()); - return Builder.getInt(Value); + return V; } return EmitLoadOfLValue(E); Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -122,16 +122,26 @@ // l-values. - ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) { - if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) { + Optional<ComplexPairTy> + tryEmitDeclRefOrMemberExprAsConstant(Expr *E, ValueDecl *VD, + bool AllowSideEffects = false) { + if (CodeGenFunction::ConstantEmission result = + CGF.tryEmitDeclRefOrMemberExprAsConstant(E, VD, AllowSideEffects)) { if (result.isReference()) return EmitLoadOfLValue(result.getReferenceLValue(CGF, E), E->getExprLoc()); llvm::Constant *pair = result.getValue(); return ComplexPairTy(pair->getAggregateElement(0U), pair->getAggregateElement(1U)); } + return None; + } + + ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) { + auto Constant = tryEmitDeclRefOrMemberExprAsConstant(E, E->getDecl()); + if (Constant) + return *Constant; return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { @@ -141,7 +151,18 @@ return CGF.EmitObjCMessageExpr(E).getComplexVal(); } ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitMemberExpr(MemberExpr *ME) { + auto Constant = tryEmitDeclRefOrMemberExprAsConstant( + ME, ME->getMemberDecl(), /*AllowSideEffects=*/true); + if (Constant) { + if (ME->isArrow()) + CGF.EmitScalarExpr(ME->getBase()); + else + CGF.EmitLValue(ME->getBase()); + return *Constant; + } + return EmitLoadOfLValue(ME); + } ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) { if (E->isGLValue()) return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getExprLoc()); Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -132,8 +132,8 @@ // actively preventing us from listing variables in the captures // list of a block. if (E->getDecl()->getType()->isReferenceType()) { - if (CodeGenFunction::ConstantEmission result - = CGF.tryEmitAsConstant(E)) { + if (CodeGenFunction::ConstantEmission result = + CGF.tryEmitDeclRefOrMemberExprAsConstant(E, E->getDecl())) { EmitFinalDestCopy(E->getType(), result.getReferenceLValue(CGF, E)); return; } Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -1277,16 +1277,17 @@ /// in a block or lambda, which means const int variables or constexpr /// literals or similar. CodeGenFunction::ConstantEmission -CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { - ValueDecl *value = refExpr->getDecl(); +CodeGenFunction::tryEmitDeclRefOrMemberExprAsConstant(Expr *E, ValueDecl *Value, + bool AllowSideEffects) { + assert((isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) && "invalid expr"); // The value needs to be an enum constant or a constant variable. ConstantEmissionKind CEK; - if (isa<ParmVarDecl>(value)) { + if (isa<ParmVarDecl>(Value)) { CEK = CEK_None; - } else if (auto *var = dyn_cast<VarDecl>(value)) { + } else if (auto *var = dyn_cast<VarDecl>(Value)) { CEK = checkVarTypeForConstantEmission(var->getType()); - } else if (isa<EnumConstantDecl>(value)) { + } else if (isa<EnumConstantDecl>(Value)) { CEK = CEK_AsValueOnly; } else { CEK = CEK_None; @@ -1298,38 +1299,37 @@ QualType resultType; // It's best to evaluate all the way as an r-value if that's permitted. - if (CEK != CEK_AsReferenceOnly && - refExpr->EvaluateAsRValue(result, getContext())) { + if (CEK != CEK_AsReferenceOnly && E->EvaluateAsRValue(result, getContext())) { resultIsReference = false; - resultType = refExpr->getType(); + resultType = E->getType(); - // Otherwise, try to evaluate as an l-value. + // Otherwise, try to evaluate as an l-value. } else if (CEK != CEK_AsValueOnly && - refExpr->EvaluateAsLValue(result, getContext())) { + E->EvaluateAsLValue(result, getContext())) { resultIsReference = true; - resultType = value->getType(); + resultType = Value->getType(); - // Failure. + // Failure. } else { return ConstantEmission(); } // In any case, if the initializer has side-effects, abandon ship. - if (result.HasSideEffects) + if (result.HasSideEffects && !AllowSideEffects) return ConstantEmission(); // Emit as a constant. - auto C = ConstantEmitter(*this).emitAbstract(refExpr->getLocation(), - result.Val, resultType); + auto C = ConstantEmitter(*this).emitAbstract(E->getExprLoc(), result.Val, + resultType); // Make sure we emit a debug reference to the global variable. // This should probably fire even for - if (isa<VarDecl>(value)) { - if (!getContext().DeclMustBeEmitted(cast<VarDecl>(value))) - EmitDeclRefExprDbgValue(refExpr, result.Val); + if (isa<VarDecl>(Value)) { + if (!getContext().DeclMustBeEmitted(cast<VarDecl>(Value))) + EmitDeclRefOrMemberExprDbgValue(E, result.Val); } else { - assert(isa<EnumConstantDecl>(value)); - EmitDeclRefExprDbgValue(refExpr, result.Val); + assert(isa<EnumConstantDecl>(Value)); + EmitDeclRefOrMemberExprDbgValue(E, result.Val); } // If we emitted a reference constant, we need to dereference that.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits