[cfe-commits] r152479 - in /cfe/trunk: lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/blocks-cxx11.cpp
John McCall
rjmccall at apple.com
Fri Mar 9 19:05:10 PST 2012
Author: rjmccall
Date: Fri Mar 9 21:05:10 2012
New Revision: 152479
URL: http://llvm.org/viewvc/llvm-project?rev=152479&view=rev
Log:
Unify the BlockDeclRefExpr and DeclRefExpr paths so that
we correctly emit loads of BlockDeclRefExprs even when they
don't qualify as ODR-uses. I think I'm adequately convinced
that BlockDeclRefExpr can die.
Added:
cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp
Modified:
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprAgg.cpp
cfe/trunk/lib/CodeGen/CGExprComplex.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=152479&r1=152478&r2=152479&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Fri Mar 9 21:05:10 2012
@@ -745,6 +745,122 @@
}
}
+/// Given an object of the given canonical type, can we safely copy a
+/// value out of it based on its initializer?
+static bool isConstantEmittableObjectType(QualType type) {
+ assert(type.isCanonical());
+ assert(!type->isReferenceType());
+
+ // Must be const-qualified but non-volatile.
+ Qualifiers qs = type.getLocalQualifiers();
+ if (!qs.hasConst() || qs.hasVolatile()) return false;
+
+ // Otherwise, all object types satisfy this except C++ classes with
+ // mutable subobjects or non-trivial copy/destroy behavior.
+ if (const RecordType *RT = dyn_cast<RecordType>(type))
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (RD->hasMutableFields() || !RD->isTrivial())
+ return false;
+
+ return true;
+}
+
+/// Can we constant-emit a load of a reference to a variable of the
+/// given type? This is different from predicates like
+/// Decl::isUsableInConstantExpressions because we do want it to apply
+/// in situations that don't necessarily satisfy the language's rules
+/// for this (e.g. C++'s ODR-use rules). For example, we want to able
+/// to do this with const float variables even if those variables
+/// aren't marked 'constexpr'.
+enum ConstantEmissionKind {
+ CEK_None,
+ CEK_AsReferenceOnly,
+ CEK_AsValueOrReference,
+ CEK_AsValueOnly
+};
+static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) {
+ type = type.getCanonicalType();
+ if (const ReferenceType *ref = dyn_cast<ReferenceType>(type)) {
+ if (isConstantEmittableObjectType(ref->getPointeeType()))
+ return CEK_AsValueOrReference;
+ return CEK_AsReferenceOnly;
+ }
+ if (isConstantEmittableObjectType(type))
+ return CEK_AsValueOnly;
+ return CEK_None;
+}
+
+/// Try to emit a reference to the given value without producing it as
+/// an l-value. This is actually more than an optimization: we can't
+/// produce an l-value for variables that we never actually captured
+/// in a block or lambda, which means const int variables or constexpr
+/// literals or similar.
+CodeGenFunction::ConstantEmission
+CodeGenFunction::tryEmitAsConstant(ValueDecl *value, Expr *refExpr) {
+ // The value needs to be an enum constant or a constant variable.
+ ConstantEmissionKind CEK;
+ if (isa<ParmVarDecl>(value)) {
+ CEK = CEK_None;
+ } else if (VarDecl *var = dyn_cast<VarDecl>(value)) {
+ CEK = checkVarTypeForConstantEmission(var->getType());
+ } else if (isa<EnumConstantDecl>(value)) {
+ CEK = CEK_AsValueOnly;
+ } else {
+ CEK = CEK_None;
+ }
+ if (CEK == CEK_None) return ConstantEmission();
+
+ // We evaluate use an on-stack DeclRefExpr because the constant
+ // evaluator (quite reasonably) ignores BlockDeclRefExprs.
+ DeclRefExpr stackRef(value, refExpr->getType(), refExpr->getValueKind(),
+ refExpr->getExprLoc());
+
+ // If it's okay to evaluate as a
+ Expr::EvalResult result;
+ bool resultIsReference;
+ QualType resultType;
+
+ // It's best to evaluate all the way as an r-value if that's permitted.
+ if (CEK != CEK_AsReferenceOnly &&
+ stackRef.EvaluateAsRValue(result, getContext())) {
+ resultIsReference = false;
+ resultType = refExpr->getType();
+
+ // Otherwise, try to evaluate as an l-value.
+ } else if (CEK != CEK_AsValueOnly &&
+ stackRef.EvaluateAsLValue(result, getContext())) {
+ resultIsReference = true;
+ resultType = value->getType();
+
+ // Failure.
+ } else {
+ return ConstantEmission();
+ }
+
+ // In any case, if the initializer has side-effects, abandon ship.
+ if (result.HasSideEffects)
+ return ConstantEmission();
+
+ // Emit as a constant.
+ llvm::Constant *C = CGM.EmitConstantValue(result.Val, resultType, this);
+
+ // 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(&stackRef, C);
+ } else {
+ assert(isa<EnumConstantDecl>(value));
+ EmitDeclRefExprDbgValue(&stackRef, C);
+ }
+
+ // If we emitted a reference constant, we need to dereference that.
+ if (resultIsReference)
+ return ConstantEmission::forReference(C);
+
+ return ConstantEmission::forValue(C);
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(),
Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=152479&r1=152478&r2=152479&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Fri Mar 9 21:05:10 2012
@@ -109,7 +109,28 @@
}
// l-values.
- void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); }
+ void emitDeclRef(ValueDecl *VD, Expr *refExpr) {
+ // 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 (VD->getType()->isReferenceType()) {
+ if (CodeGenFunction::ConstantEmission result
+ = CGF.tryEmitAsConstant(VD, refExpr)) {
+ EmitFinalDestCopy(refExpr, result.getReferenceLValue(CGF, refExpr));
+ return;
+ }
+ }
+
+ EmitAggLoadOfLValue(refExpr);
+ }
+ void VisitDeclRefExpr(DeclRefExpr *E) { emitDeclRef(E->getDecl(), E); }
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ emitDeclRef(E->getDecl(), E);
+ }
+
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
@@ -117,9 +138,6 @@
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
- void VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- EmitAggLoadOfLValue(E);
- }
void VisitPredefinedExpr(const PredefinedExpr *E) {
EmitAggLoadOfLValue(E);
}
Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=152479&r1=152478&r2=152479&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Fri Mar 9 21:05:10 2012
@@ -111,8 +111,24 @@
}
// l-values.
- ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitBlockDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy emitDeclRef(ValueDecl *VD, Expr *refExpr) {
+ if (CodeGenFunction::ConstantEmission result
+ = CGF.tryEmitAsConstant(VD, refExpr)) {
+ if (result.isReference())
+ return EmitLoadOfLValue(result.getReferenceLValue(CGF, refExpr));
+
+ llvm::ConstantStruct *pair =
+ cast<llvm::ConstantStruct>(result.getValue());
+ return ComplexPairTy(pair->getOperand(0), pair->getOperand(1));
+ }
+ return EmitLoadOfLValue(refExpr);
+ }
+ ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
+ return emitDeclRef(E->getDecl(), E);
+ }
+ ComplexPairTy VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ return emitDeclRef(E->getDecl(), E);
+ }
ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return EmitLoadOfLValue(E);
}
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=152479&r1=152478&r2=152479&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Fri Mar 9 21:05:10 2012
@@ -211,48 +211,24 @@
// Otherwise, assume the mapping is the scalar directly.
return CGF.getOpaqueRValueMapping(E).getScalarVal();
}
-
- // l-values.
- Value *VisitDeclRefExpr(DeclRefExpr *E) {
- VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
- if (!VD && !isa<EnumConstantDecl>(E->getDecl()))
- return EmitLoadOfLValue(E);
- if (VD && !VD->isUsableInConstantExpressions(CGF.getContext()))
- return EmitLoadOfLValue(E);
- // This is an enumerator or a variable which is usable in constant
- // expressions. Try to emit its value instead.
- Expr::EvalResult Result;
- 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 = CGF.CGM.EmitConstantValue(Result.Val, EvalTy, &CGF);
-
- // Make sure we emit a debug reference to the global variable.
- if (VD) {
- if (!CGF.getContext().DeclMustBeEmitted(VD))
- CGF.EmitDeclRefExprDbgValue(E, C);
- } else {
- assert(isa<EnumConstantDecl>(E->getDecl()));
- CGF.EmitDeclRefExprDbgValue(E, C);
+ // l-values.
+ Value *emitDeclRef(ValueDecl *VD, Expr *refExpr) {
+ if (CodeGenFunction::ConstantEmission result
+ = CGF.tryEmitAsConstant(VD, refExpr)) {
+ if (result.isReference())
+ return EmitLoadOfLValue(result.getReferenceLValue(CGF, refExpr));
+ return result.getValue();
}
-
- if (IsReferenceConstant)
- return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(C, E->getType()));
-
- return C;
+ return EmitLoadOfLValue(refExpr);
+ }
+ Value *VisitDeclRefExpr(DeclRefExpr *E) {
+ return emitDeclRef(E->getDecl(), E);
+ }
+ Value *VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ return emitDeclRef(E->getDecl(), E);
}
+
Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
return CGF.EmitObjCSelectorExpr(E);
}
@@ -304,8 +280,6 @@
Value *VisitStmtExpr(const StmtExpr *E);
- Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E);
-
// Unary Operators.
Value *VisitUnaryPostDec(const UnaryOperator *E) {
LValue LV = EmitLValue(E->getSubExpr());
@@ -1272,11 +1246,6 @@
.getScalarVal();
}
-Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- LValue LV = CGF.EmitBlockDeclRefLValue(E);
- return CGF.EmitLoadOfLValue(LV).getScalarVal();
-}
-
//===----------------------------------------------------------------------===//
// Unary Operators
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=152479&r1=152478&r2=152479&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Mar 9 21:05:10 2012
@@ -2107,6 +2107,36 @@
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
+ class ConstantEmission {
+ llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
+ ConstantEmission(llvm::Constant *C, bool isReference)
+ : ValueAndIsReference(C, isReference) {}
+ public:
+ ConstantEmission() {}
+ static ConstantEmission forReference(llvm::Constant *C) {
+ return ConstantEmission(C, true);
+ }
+ static ConstantEmission forValue(llvm::Constant *C) {
+ return ConstantEmission(C, false);
+ }
+
+ operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; }
+
+ bool isReference() const { return ValueAndIsReference.getInt(); }
+ LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const {
+ assert(isReference());
+ return CGF.MakeNaturalAlignAddrLValue(ValueAndIsReference.getPointer(),
+ refExpr->getType());
+ }
+
+ llvm::Constant *getValue() const {
+ assert(!isReference());
+ return ValueAndIsReference.getPointer();
+ }
+ };
+
+ ConstantEmission tryEmitAsConstant(ValueDecl *VD, Expr *refExpr);
+
RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,
AggValueSlot slot = AggValueSlot::ignored());
LValue EmitPseudoObjectLValue(const PseudoObjectExpr *e);
Added: cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp?rev=152479&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/blocks-cxx11.cpp Fri Mar 9 21:05:10 2012
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - | FileCheck %s
+
+template <class T> void takeItByValue(T);
+void takeABlock(void (^)());
+
+// rdar://problem/11022704
+namespace test_int {
+ void test() {
+ const int x = 100;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: call void @_Z13takeItByValueIiEvT_(i32 100)
+ }
+}
+
+namespace test_int_ref {
+ void test() {
+ const int y = 200;
+ const int &x = y;
+ takeABlock(^{ takeItByValue(x); });
+
+ // TODO: there's no good reason that this isn't foldable.
+ // CHECK: call void @_Z13takeItByValueIiEvT_(i32 {{%.*}})
+ }
+}
+
+namespace test_float {
+ void test() {
+ const float x = 1;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: call void @_Z13takeItByValueIfEvT_(float 1.0
+ }
+}
+
+namespace test_float_ref {
+ void test() {
+ const float y = 100;
+ const float &x = y;
+ takeABlock(^{ takeItByValue(x); });
+
+ // TODO: there's no good reason that this isn't foldable.
+ // CHECK: call void @_Z13takeItByValueIfEvT_(float {{%.*}})
+ }
+}
+
+namespace test_complex_int {
+ void test() {
+ constexpr _Complex int x = 500;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: store i32 500,
+
+ // CHECK: store i32 500,
+ // CHECK-NEXT: store i32 0,
+ // CHECK-NEXT: [[COERCE:%.*]] = bitcast
+ // CHECK-NEXT: [[CVAL:%.*]] = load i64* [[COERCE]]
+ // CHECK-NEXT: call void @_Z13takeItByValueICiEvT_(i64 [[CVAL]])
+ }
+}
+
+namespace test_complex_int_ref {
+ void test() {
+ const _Complex int y = 100;
+ const _Complex int &x = y;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: call void @_Z13takeItByValueICiEvT_(i64
+ }
+}
+
+namespace test_complex_int_ref_mutable {
+ _Complex int y = 100;
+ void test() {
+ const _Complex int &x = y;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: [[R:%.*]] = load i32* getelementptr inbounds ({ i32, i32 }* @_ZN28test_complex_int_ref_mutable1yE, i32 0, i32 0)
+ // CHECK-NEXT: [[I:%.*]] = load i32* getelementptr inbounds ({ i32, i32 }* @_ZN28test_complex_int_ref_mutable1yE, i32 0, i32 1)
+ // CHECK-NEXT: [[RSLOT:%.*]] = getelementptr inbounds { i32, i32 }* [[CSLOT:%.*]], i32 0, i32 0
+ // CHECK-NEXT: [[ISLOT:%.*]] = getelementptr inbounds { i32, i32 }* [[CSLOT]], i32 0, i32 1
+ // CHECK-NEXT: store i32 [[R]], i32* [[RSLOT]]
+ // CHECK-NEXT: store i32 [[I]], i32* [[ISLOT]]
+ // CHECK-NEXT: [[COERCE:%.*]] = bitcast { i32, i32 }* [[CSLOT]] to i64*
+ // CHECK-NEXT: [[CVAL:%.*]] = load i64* [[COERCE]],
+ // CHECK-NEXT: call void @_Z13takeItByValueICiEvT_(i64 [[CVAL]])
+ }
+}
+
More information about the cfe-commits
mailing list