[cfe-commits] r147561 - in /cfe/trunk: include/clang/AST/APValue.h lib/AST/APValue.cpp lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/Sema/SemaChecking.cpp test/CodeGenCXX/const-init.cpp

Eli Friedman eli.friedman at gmail.com
Wed Jan 4 15:13:47 PST 2012


Author: efriedma
Date: Wed Jan  4 17:13:47 2012
New Revision: 147561

URL: http://llvm.org/viewvc/llvm-project?rev=147561&view=rev
Log:
Add an APValue representation for the difference between two address-of-label expressions.  Add support to Evaluate and CGExprConstant for generating/handling them.  Remove the special-case for such differences in Expr::isConstantInitializer.

With that done, remove a bunch of buggy code from CGExprConstant for handling scalar expressions which is no longer necessary.

Fixes PR11705.


Modified:
    cfe/trunk/include/clang/AST/APValue.h
    cfe/trunk/lib/AST/APValue.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/CodeGenCXX/const-init.cpp

Modified: cfe/trunk/include/clang/AST/APValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/APValue.h (original)
+++ cfe/trunk/include/clang/AST/APValue.h Wed Jan  4 17:13:47 2012
@@ -21,6 +21,7 @@
 #include "llvm/ADT/PointerUnion.h"
 
 namespace clang {
+  class AddrLabelExpr;
   class ASTContext;
   class CharUnits;
   class DiagnosticBuilder;
@@ -49,7 +50,8 @@
     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 @@
     UnionData();
     ~UnionData();
   };
+  struct AddrLabelDiffData {
+    const AddrLabelExpr* LHSExpr;
+    const AddrLabelExpr* RHSExpr;
+  };
   struct MemberPointerData;
 
   enum {
@@ -155,6 +161,10 @@
           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 @@
   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 @@
   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 @@
     ((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 @@
   }
   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.

Modified: cfe/trunk/lib/AST/APValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/lib/AST/APValue.cpp (original)
+++ cfe/trunk/lib/AST/APValue.cpp Wed Jan  4 17:13:47 2012
@@ -149,6 +149,8 @@
       MakeMemberPointer(RHS.getMemberPointerDecl(),
                         RHS.isMemberPointerToDerivedMember(),
                         RHS.getMemberPointerPath());
+    else if (RHS.isAddrLabelDiff())
+      MakeAddrLabelDiff();
   }
   if (isInt())
     setInt(RHS.getInt());
@@ -177,8 +179,11 @@
       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 @@
     ((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 @@
   case MemberPointer:
     OS << "MemberPointer: <todo>";
     return;
+  case AddrLabelDiff:
+    OS << "AddrLabelDiff: <todo>";
+    return;
   }
   llvm_unreachable("Unknown APValue kind!");
 }
@@ -472,6 +482,11 @@
     }
     Out << "0";
     return;
+  case APValue::AddrLabelDiff:
+    Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName();
+    Out << " - ";
+    Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName();
+    return;
   }
   llvm_unreachable("Unknown APValue kind!");
 }

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Jan  4 17:13:47 2012
@@ -2530,16 +2530,6 @@
       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 @@
         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:

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Jan  4 17:13:47 2012
@@ -210,6 +210,8 @@
     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 @@
   case APValue::Array:
   case APValue::Struct:
   case APValue::Union:
+  case APValue::AddrLabelDiff:
     return false;
   }
 
@@ -3997,6 +4000,23 @@
       // 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 @@
     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 @@
       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);
     }

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Wed Jan  4 17:13:47 2012
@@ -500,27 +500,6 @@
     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 @@
     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 @@
     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 @@
     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 @@
       }
       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:

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jan  4 17:13:47 2012
@@ -3239,7 +3239,7 @@
   // 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());
 }
 

Modified: cfe/trunk/test/CodeGenCXX/const-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init.cpp?rev=147561&r1=147560&r2=147561&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/const-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/const-init.cpp Wed Jan  4 17:13:47 2012
@@ -56,3 +56,16 @@
   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;}





More information about the cfe-commits mailing list