[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