arphaman updated this revision to Diff 112360.
arphaman marked 2 inline comments as done.
arphaman added a comment.
- Create `tryEmitAsConstant` for MemberExprs and `emitConstant` helper for
complex values as suggested by John.
- Remove dead constant emission code from CGExprAggregate.cpp
- Emit static variable member expressions as DREs when emitting Lvalues to
ensure the IR is consistent between DREs and MEs that reference a constant
static variables whose type is a reference to an aggregate
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.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,104 @@
+// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+struct Agg { const char * x; const char * y; constexpr Agg() : x(0), y(0) {} };
+
+struct Struct {
+ constexpr static const char *name = "foo";
+
+ constexpr static __complex float complexValue = 42.0;
+
+ static constexpr const Agg &agg = Agg();
+
+ 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]])
+}
+
+void aggregateRefInMemberExpr(Struct *ptr, Struct &ref) {
+ use(1, Struct::agg.x);
+// CHECK: %[[value0:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 1, i8* %[[value0]])
+ Struct s;
+ use(2, s.agg.x);
+// CHECK: %[[value1:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 2, i8* %[[value1]])
+ use(3, ptr->agg.x);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: %[[value2:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 3, i8* %[[value2]])
+ use(4, ref.agg.x);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: %[[value3:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 4, i8* %[[value3]])
+}
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -3161,6 +3161,7 @@
};
ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);
+ ConstantEmission tryEmitAsConstant(const MemberExpr *ME);
RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,
AggValueSlot slot = AggValueSlot::ignored());
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -428,14 +428,19 @@
return CGF.getOpaqueRValueMapping(E).getScalarVal();
}
+ Value *emitConstant(const CodeGenFunction::ConstantEmission &Constant,
+ Expr *E) {
+ assert(Constant && "not a constant");
+ if (Constant.isReference())
+ return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E),
+ E->getExprLoc());
+ return Constant.getValue();
+ }
+
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {
- if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
- if (result.isReference())
- return EmitLoadOfLValue(result.getReferenceLValue(CGF, E),
- E->getExprLoc());
- return result.getValue();
- }
+ if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E))
+ return emitConstant(Constant, E);
return EmitLoadOfLValue(E);
}
@@ -1299,13 +1304,15 @@
}
Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
- llvm::APSInt Value;
- if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
- if (E->isArrow())
- CGF.EmitScalarExpr(E->getBase());
- else
- EmitLValue(E->getBase());
- return Builder.getInt(Value);
+ if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) {
+ CGF.EmitIgnoredExpr(E->getBase());
+ return emitConstant(Constant, E);
+ } else {
+ llvm::APSInt Value;
+ if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
+ CGF.EmitIgnoredExpr(E->getBase());
+ return Builder.getInt(Value);
+ }
}
return EmitLoadOfLValue(E);
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp
+++ lib/CodeGen/CGExprComplex.cpp
@@ -120,18 +120,22 @@
return Visit(E->getSubExpr());
}
+ ComplexPairTy emitConstant(const CodeGenFunction::ConstantEmission &Constant,
+ Expr *E) {
+ assert(Constant && "not a constant");
+ if (Constant.isReference())
+ return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E),
+ E->getExprLoc());
+
+ llvm::Constant *pair = Constant.getValue();
+ return ComplexPairTy(pair->getAggregateElement(0U),
+ pair->getAggregateElement(1U));
+ }
// l-values.
ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
- if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
- if (result.isReference())
- return EmitLoadOfLValue(result.getReferenceLValue(CGF, E),
- E->getExprLoc());
-
- llvm::Constant *pair = result.getValue();
- return ComplexPairTy(pair->getAggregateElement(0U),
- pair->getAggregateElement(1U));
- }
+ if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E))
+ return emitConstant(Constant, E);
return EmitLoadOfLValue(E);
}
ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
@@ -141,7 +145,14 @@
return CGF.EmitObjCMessageExpr(E).getComplexVal();
}
ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy VisitMemberExpr(MemberExpr *ME) {
+ if (CodeGenFunction::ConstantEmission Constant =
+ CGF.tryEmitAsConstant(ME)) {
+ CGF.EmitIgnoredExpr(ME->getBase());
+ return emitConstant(Constant, ME);
+ }
+ 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
@@ -124,24 +124,7 @@
}
// l-values.
- void VisitDeclRefExpr(DeclRefExpr *E) {
- // For aggregates, we should always be able to emit the variable
- // as an l-value unless it's a reference. This is due to the fact
- // that we can't actually ever see a normal l2r conversion on an
- // aggregate in C++, and in C there's no language standard
- // 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)) {
- EmitFinalDestCopy(E->getType(), result.getReferenceLValue(CGF, E));
- return;
- }
- }
-
- EmitAggLoadOfLValue(E);
- }
-
+ void VisitDeclRefExpr(DeclRefExpr *E) { EmitAggLoadOfLValue(E); }
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -1339,6 +1339,25 @@
return ConstantEmission::forValue(C);
}
+static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
+ const MemberExpr *ME) {
+ if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
+ // Try to emit static variable member expressions as DREs.
+ return DeclRefExpr::Create(
+ CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
+ /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
+ ME->getType(), ME->getValueKind());
+ }
+ return nullptr;
+}
+
+CodeGenFunction::ConstantEmission
+CodeGenFunction::tryEmitAsConstant(const MemberExpr *ME) {
+ if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, ME))
+ return tryEmitAsConstant(DRE);
+ return ConstantEmission();
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue,
SourceLocation Loc) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
@@ -3540,6 +3559,11 @@
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
+ if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, E)) {
+ EmitIgnoredExpr(E->getBase());
+ return EmitDeclRefLValue(DRE);
+ }
+
Expr *BaseExpr = E->getBase();
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
LValue BaseLV;
@@ -3566,9 +3590,6 @@
return LV;
}
- if (auto *VD = dyn_cast<VarDecl>(ND))
- return EmitGlobalVarDeclLValue(*this, E, VD);
-
if (const auto *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits