diff options
-rw-r--r-- | include/clang/AST/APValue.h | 32 | ||||
-rw-r--r-- | lib/AST/APValue.cpp | 17 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 27 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 46 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 94 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/const-init.cpp | 13 |
7 files changed, 133 insertions, 98 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h index 151956903c..bc7138565b 100644 --- a/include/clang/AST/APValue.h +++ b/include/clang/AST/APValue.h @@ -21,6 +21,7 @@ #include "llvm/ADT/PointerUnion.h" namespace clang { + class AddrLabelExpr; class ASTContext; class CharUnits; class DiagnosticBuilder; @@ -49,7 +50,8 @@ public: Array, Struct, Union, - MemberPointer + MemberPointer, + AddrLabelDiff }; typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase; typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType; @@ -100,6 +102,10 @@ private: UnionData(); ~UnionData(); }; + struct AddrLabelDiffData { + const AddrLabelExpr* LHSExpr; + const AddrLabelExpr* RHSExpr; + }; struct MemberPointerData; enum { @@ -155,6 +161,10 @@ public: ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) { MakeMemberPointer(Member, IsDerivedMember, Path); } + APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) + : Kind(Uninitialized) { + MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr); + } ~APValue() { MakeUninit(); @@ -172,6 +182,7 @@ public: bool isStruct() const { return Kind == Struct; } bool isUnion() const { return Kind == Union; } bool isMemberPointer() const { return Kind == MemberPointer; } + bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; } void dump() const; void dump(raw_ostream &OS) const; @@ -316,6 +327,15 @@ public: bool isMemberPointerToDerivedMember() const; ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const; + const AddrLabelExpr* getAddrLabelDiffLHS() const { + assert(isAddrLabelDiff() && "Invalid accessor"); + return ((AddrLabelDiffData*)(char*)Data)->LHSExpr; + } + const AddrLabelExpr* getAddrLabelDiffRHS() const { + assert(isAddrLabelDiff() && "Invalid accessor"); + return ((AddrLabelDiffData*)(char*)Data)->RHSExpr; + } + void setInt(const APSInt &I) { assert(isInt() && "Invalid accessor"); *(APSInt*)(char*)Data = I; @@ -353,6 +373,11 @@ public: ((UnionData*)(char*)Data)->Field = Field; *((UnionData*)(char*)Data)->Value = Value; } + void setAddrLabelDiff(const AddrLabelExpr* LHSExpr, + const AddrLabelExpr* RHSExpr) { + ((AddrLabelDiffData*)(char*)Data)->LHSExpr = LHSExpr; + ((AddrLabelDiffData*)(char*)Data)->RHSExpr = RHSExpr; + } const APValue &operator=(const APValue &RHS); @@ -397,6 +422,11 @@ private: } void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path); + void MakeAddrLabelDiff() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) AddrLabelDiffData(); + Kind = AddrLabelDiff; + } }; } // end namespace clang. diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 2a68341e5a..b8942c3310 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -149,6 +149,8 @@ const APValue &APValue::operator=(const APValue &RHS) { MakeMemberPointer(RHS.getMemberPointerDecl(), RHS.isMemberPointerToDerivedMember(), RHS.getMemberPointerPath()); + else if (RHS.isAddrLabelDiff()) + MakeAddrLabelDiff(); } if (isInt()) setInt(RHS.getInt()); @@ -177,8 +179,11 @@ const APValue &APValue::operator=(const APValue &RHS) { getStructBase(I) = RHS.getStructBase(I); for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I) getStructField(I) = RHS.getStructField(I); - } else if (isUnion()) + } else if (isUnion()) { setUnion(RHS.getUnionField(), RHS.getUnionValue()); + } else if (isAddrLabelDiff()) { + setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS()); + } return *this; } @@ -203,6 +208,8 @@ void APValue::MakeUninit() { ((UnionData*)(char*)Data)->~UnionData(); else if (Kind == MemberPointer) ((MemberPointerData*)(char*)Data)->~MemberPointerData(); + else if (Kind == AddrLabelDiff) + ((AddrLabelDiffData*)(char*)Data)->~AddrLabelDiffData(); Kind = Uninitialized; } @@ -285,6 +292,9 @@ void APValue::dump(raw_ostream &OS) const { case MemberPointer: OS << "MemberPointer: <todo>"; return; + case AddrLabelDiff: + OS << "AddrLabelDiff: <todo>"; + return; } llvm_unreachable("Unknown APValue kind!"); } @@ -472,6 +482,11 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ } Out << "0"; return; + case APValue::AddrLabelDiff: + Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName(); + Out << " - "; + Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName(); + return; } llvm_unreachable("Unknown APValue kind!"); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 9f87161290..bbf54112c8 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2530,16 +2530,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return Exp->getSubExpr()->isConstantInitializer(Ctx, false); break; } - case BinaryOperatorClass: { - // Special case &&foo - &&bar. It would be nice to generalize this somehow - // but this handles the common case. - const BinaryOperator *Exp = cast<BinaryOperator>(this); - if (Exp->getOpcode() == BO_Sub && - isa<AddrLabelExpr>(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && - isa<AddrLabelExpr>(Exp->getRHS()->IgnoreParenNoopCasts(Ctx))) - return true; - break; - } case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: @@ -2558,23 +2548,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { CE->getCastKind() == CK_ConstructorConversion) return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Handle things like (int)(&&x-&&y). It's a bit nasty, but we support it. - if (CE->getCastKind() == CK_IntegralCast) { - const Expr *E = CE->getSubExpr()->IgnoreParenNoopCasts(Ctx); - while (const CastExpr *InnerCE = dyn_cast<CastExpr>(E)) { - if (InnerCE->getCastKind() != CK_IntegralCast) - break; - E = InnerCE->getSubExpr()->IgnoreParenNoopCasts(Ctx); - } - - if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->getOpcode() == BO_Sub && - isa<AddrLabelExpr>(BO->getLHS()->IgnoreParenNoopCasts(Ctx)) && - isa<AddrLabelExpr>(BO->getRHS()->IgnoreParenNoopCasts(Ctx))) - return true; - } - } - break; } case MaterializeTemporaryExprClass: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 4aed81215c..fc214bfa80 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -210,6 +210,8 @@ namespace { CCValue(const ValueDecl *D, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path) : APValue(D, IsDerivedMember, Path) {} + CCValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) : + APValue(LHSExpr, RHSExpr) {} CallStackFrame *getLValueFrame() const { assert(getKind() == LValue); @@ -856,6 +858,7 @@ static bool HandleConversionToBool(const CCValue &Val, bool &Result) { case APValue::Array: case APValue::Struct: case APValue::Union: + case APValue::AddrLabelDiff: return false; } @@ -3997,6 +4000,23 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { + if (E->getOpcode() == BO_Sub) { + // Handle &&A - &&B. + // FIXME: We're missing a check that both labels have the same + // associated function; I'm not sure how to write this check. + if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) + return false; + const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); + const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); + if (!LHSExpr || !RHSExpr) + return false; + const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); + const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); + if (!LHSAddrExpr || !RHSAddrExpr) + return false; + Result = CCValue(LHSAddrExpr, RHSAddrExpr); + return true; + } // Inequalities and subtractions between unrelated pointers have // unspecified or undefined behavior. if (!E->isEqualityOp()) @@ -4091,6 +4111,25 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return true; } + if (E->getOpcode() == BO_Sub && LHSVal.isLValue() && RHSVal.isLValue()) { + // Handle (intptr_t)&&A - (intptr_t)&&B. + // FIXME: We're missing a check that both labels have the same + // associated function; I'm not sure how to write this check. + if (!LHSVal.getLValueOffset().isZero() || + !RHSVal.getLValueOffset().isZero()) + return false; + const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr*>(); + const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr*>(); + if (!LHSExpr || !RHSExpr) + return false; + const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); + const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); + if (!LHSAddrExpr || !RHSAddrExpr) + return false; + Result = CCValue(LHSAddrExpr, RHSAddrExpr); + return true; + } + // All the following cases expect both operands to be an integer if (!LHSVal.isInt() || !RHSVal.isInt()) return Error(E); @@ -4398,6 +4437,13 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return false; if (!Result.isInt()) { + // Allow casts of address-of-label differences if they are no-ops + // or narrowing. (The narrowing case isn't actually guaranteed to + // be constant-evaluatable except in some narrow cases which are hard + // to detect here. We let it through on the assumption the user knows + // what they are doing.) + if (Result.isAddrLabelDiff()) + return Info.Ctx.getTypeSize(DestType) <= Info.Ctx.getTypeSize(SrcType); // Only allow casts of lvalues if they are lossless. return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 1bd94295d3..2c151328c7 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -500,27 +500,6 @@ public: return 0; } - llvm::Constant *VisitBinSub(BinaryOperator *E) { - // This must be a pointer/pointer subtraction. This only happens for - // address of label. - if (!isa<AddrLabelExpr>(E->getLHS()->IgnoreParenNoopCasts(CGM.getContext())) || - !isa<AddrLabelExpr>(E->getRHS()->IgnoreParenNoopCasts(CGM.getContext()))) - return 0; - - llvm::Constant *LHS = CGM.EmitConstantExpr(E->getLHS(), - E->getLHS()->getType(), CGF); - llvm::Constant *RHS = CGM.EmitConstantExpr(E->getRHS(), - E->getRHS()->getType(), CGF); - - llvm::Type *ResultType = ConvertType(E->getType()); - LHS = llvm::ConstantExpr::getPtrToInt(LHS, ResultType); - RHS = llvm::ConstantExpr::getPtrToInt(RHS, ResultType); - - // No need to divide by element size, since addr of label is always void*, - // which has size 1 in GNUish. - return llvm::ConstantExpr::getSub(LHS, RHS); - } - llvm::Constant *VisitCastExpr(CastExpr* E) { Expr *subExpr = E->getSubExpr(); llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF); @@ -570,13 +549,6 @@ public: case CK_NoOp: return C; - case CK_CPointerToObjCPointerCast: - case CK_BlockPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - case CK_BitCast: - if (C->getType() == destType) return C; - return llvm::ConstantExpr::getBitCast(C, destType); - case CK_Dependent: llvm_unreachable("saw dependent cast!"); // These will never be supported. @@ -595,7 +567,12 @@ public: case CK_ConstructorConversion: return 0; - // These should eventually be supported. + // These don't need to be handled here because Evaluate knows how to + // evaluate all scalar expressions which can be constant-evaluated. + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_BitCast: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_BaseToDerived: @@ -613,53 +590,17 @@ public: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: - return 0; - case CK_PointerToIntegral: - if (!E->getType()->isBooleanType()) - return llvm::ConstantExpr::getPtrToInt(C, destType); - // fallthrough - case CK_PointerToBoolean: - return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C, - llvm::ConstantPointerNull::get(cast<llvm::PointerType>(C->getType()))); - case CK_NullToPointer: - return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType)); - - case CK_IntegralCast: { - bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType(); - return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned); - } - - case CK_IntegralToPointer: { - bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType(); - C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned); - return llvm::ConstantExpr::getIntToPtr(C, destType); - } - + case CK_IntegralCast: + case CK_IntegralToPointer: case CK_IntegralToBoolean: - return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C, - llvm::Constant::getNullValue(C->getType())); - case CK_IntegralToFloating: - if (subExpr->getType()->isSignedIntegerOrEnumerationType()) - return llvm::ConstantExpr::getSIToFP(C, destType); - else - return llvm::ConstantExpr::getUIToFP(C, destType); - case CK_FloatingToIntegral: - if (E->getType()->isSignedIntegerOrEnumerationType()) - return llvm::ConstantExpr::getFPToSI(C, destType); - else - return llvm::ConstantExpr::getFPToUI(C, destType); - case CK_FloatingToBoolean: - return llvm::ConstantExpr::getFCmp(llvm::CmpInst::FCMP_UNE, C, - llvm::Constant::getNullValue(C->getType())); - case CK_FloatingCast: - return llvm::ConstantExpr::getFPCast(C, destType); + return 0; } llvm_unreachable("Invalid CastKind"); } @@ -1081,6 +1022,23 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, } return llvm::ConstantVector::get(Inits); } + case APValue::AddrLabelDiff: { + const AddrLabelExpr *LHSExpr = Result.Val.getAddrLabelDiffLHS(); + const AddrLabelExpr *RHSExpr = Result.Val.getAddrLabelDiffRHS(); + llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF); + llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF); + + // Compute difference + llvm::Type *ResultType = getTypes().ConvertType(E->getType()); + LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy); + RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy); + llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS); + + // LLVM os a bit sensitive about the exact format of the + // address-of-label difference; make sure to truncate after + // the subtraction. + return llvm::ConstantExpr::getTruncOrBitCast(AddrLabelDiff, ResultType); + } case APValue::Array: case APValue::Struct: case APValue::Union: diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 44513020bb..248998ed0b 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -3239,7 +3239,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, // FIXME: The only reason we need to pass the type in here is to get // the sign right on this one case. It would be nice if APValue // preserved this. - assert(result.isLValue()); + assert(result.isLValue() || result.isAddrLabelDiff()); return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp index aa77d5c6c0..6fabfc762e 100644 --- a/test/CodeGenCXX/const-init.cpp +++ b/test/CodeGenCXX/const-init.cpp @@ -56,3 +56,16 @@ int writeToMutable() { const MutableMember MM = { 0 }; return ++MM.n; } + +// Make sure we don't try to fold this in the frontend; the backend can't +// handle it. +// CHECK: @PR11705 = global i128 0 +__int128_t PR11705 = (__int128_t)&PR11705; + +// Make sure we don't try to fold this either. +// CHECK: @_ZZ23UnfoldableAddrLabelDiffvE1x = internal global i128 0 +void UnfoldableAddrLabelDiff() { static __int128_t x = (long)&&a-(long)&&b; a:b:return;} + +// But make sure we do fold this. +// CHECK: @_ZZ21FoldableAddrLabelDiffvE1x = internal global i64 sub (i64 ptrtoint (i8* blockaddress(@_Z21FoldableAddrLabelDiffv, %a) +void FoldableAddrLabelDiff() { static long x = (long)&&a-(long)&&b; a:b:return;} |