Sent from my iPhone
On Mar 9, 2012, at 7:05 PM, John McCall <[email protected]> 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 > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
