[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
Douglas Gregor
dgregor at apple.com
Fri Mar 9 20:44:11 PST 2012
Sent from my iPhone
On Mar 9, 2012, at 7:05 PM, John McCall <rjmccall at apple.com> wrote:
> 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.
Awesome!
> 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]])
> + }
> +}
> +
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list