[cfe-commits] r59125 - in /cfe/trunk: lib/AST/ExprConstant.cpp test/Sema/const-eval.c

Eli Friedman eli.friedman at gmail.com
Wed Nov 12 01:44:49 PST 2008


Author: efriedma
Date: Wed Nov 12 03:44:48 2008
New Revision: 59125

URL: http://llvm.org/viewvc/llvm-project?rev=59125&view=rev
Log:
Some additions to tryEvaluate I've had sitting around for a while.
This pushes it a lot closer to being able to deal with most of the stuff 
CodeGen's constant expression evaluator knows how to deal with.  This 
also fixes PR3003.

The test could possibly use some improvement, but this'll work for now.  
Test 6 is inspired by PR3003; the other tests are mostly just designed
to exercise the new code.  The reason for the funny structure of the 
tests is that type fixing for arrays inside of structs is the only place 
in Sema that calls tryEvaluate, at least for the moment.


Added:
    cfe/trunk/test/Sema/const-eval.c
Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=59125&r1=59124&r2=59125&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Nov 12 03:44:48 2008
@@ -13,6 +13,7 @@
 
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/TargetInfo.h"
@@ -62,11 +63,112 @@
 };
 
 
+static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info);
 static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info);
 static bool EvaluateInteger(const Expr *E, APSInt  &Result, EvalInfo &Info);
 static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
 
 //===----------------------------------------------------------------------===//
+// Misc utilities
+//===----------------------------------------------------------------------===//
+
+static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
+  if (E->getType()->isIntegralType()) {
+    APSInt IntResult;
+    if (!EvaluateInteger(E, IntResult, Info))
+      return false;
+    Result = IntResult != 0;
+    return true;
+  } else if (E->getType()->isRealFloatingType()) {
+    APFloat FloatResult(0.0);
+    if (!EvaluateFloat(E, FloatResult, Info))
+      return false;
+    Result = !FloatResult.isZero();
+    return true;
+  } else if (E->getType()->isPointerType()) {
+    APValue PointerResult;
+    if (!EvaluatePointer(E, PointerResult, Info))
+      return false;
+    // FIXME: Is this accurate for all kinds of bases?  If not, what would
+    // the check look like?
+    Result = PointerResult.getLValueBase() || PointerResult.getLValueOffset();
+    return true;
+  }
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// LValue Evaluation
+//===----------------------------------------------------------------------===//
+namespace {
+class VISIBILITY_HIDDEN LValueExprEvaluator
+  : public StmtVisitor<LValueExprEvaluator, APValue> {
+  EvalInfo &Info;
+public:
+    
+  LValueExprEvaluator(EvalInfo &info) : Info(info) {}
+
+  APValue VisitStmt(Stmt *S) {
+    // FIXME: Remove this when we support more expressions.
+    printf("Unhandled pointer statement\n");
+    S->dump();  
+    return APValue();
+  }
+
+  APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+  APValue VisitDeclRefExpr(DeclRefExpr *E) { return APValue(E, 0); }
+  APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
+  APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+  APValue VisitMemberExpr(MemberExpr *E);
+  APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); }
+};
+} // end anonymous namespace
+
+static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
+  Result = LValueExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+  return Result.isLValue();
+}
+
+APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+  if (E->isFileScope())
+    return APValue(E, 0);
+  return APValue();
+}
+
+APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
+  APValue result;
+  QualType Ty;
+  if (E->isArrow()) {
+    if (!EvaluatePointer(E->getBase(), result, Info))
+      return APValue();
+    Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType();
+  } else {
+    result = Visit(E->getBase());
+    if (result.isUninit())
+      return APValue();
+    Ty = E->getBase()->getType();
+  }
+
+  RecordDecl *RD = Ty->getAsRecordType()->getDecl();
+  const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+  FieldDecl *FD = E->getMemberDecl();
+    
+  // FIXME: This is linear time.
+  unsigned i = 0, e = 0;
+  for (i = 0, e = RD->getNumMembers(); i != e; i++) {
+    if (RD->getMember(i) == FD)
+      break;
+  }
+
+  result.setLValue(result.getLValueBase(),
+                   result.getLValueOffset() + RL.getFieldOffset(i) / 8);
+
+  return result;
+}
+
+
+//===----------------------------------------------------------------------===//
 // Pointer Evaluation
 //===----------------------------------------------------------------------===//
 
@@ -86,6 +188,10 @@
 
   APValue VisitBinaryOperator(const BinaryOperator *E);
   APValue VisitCastExpr(const CastExpr* E);
+  APValue VisitUnaryOperator(const UnaryOperator *E);
+  APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
+      { return APValue(E, 0); }
+  APValue VisitConditionalOperator(ConditionalOperator *E);
 };
 } // end anonymous namespace
 
@@ -114,14 +220,33 @@
   if (!EvaluateInteger(IExp, AdditionalOffset, Info))
     return APValue();
 
+  QualType PointeeType = PExp->getType()->getAsPointerType()->getPointeeType();
+  uint64_t SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8;
+
   uint64_t Offset = ResultLValue.getLValueOffset();
+
   if (E->getOpcode() == BinaryOperator::Add)
-    Offset += AdditionalOffset.getZExtValue();
+    Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
   else
-    Offset -= AdditionalOffset.getZExtValue();
-    
+    Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee;
+
   return APValue(ResultLValue.getLValueBase(), Offset);
 }
+
+APValue PointerExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+  if (E->getOpcode() == UnaryOperator::Extension) {
+    // FIXME: Deal with warnings?
+    return Visit(E->getSubExpr());
+  }
+
+  if (E->getOpcode() == UnaryOperator::AddrOf) {
+    APValue result;
+    if (EvaluateLValue(E->getSubExpr(), result, Info))
+      return result;
+  }
+
+  return APValue();
+}
   
 
 APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
@@ -142,11 +267,31 @@
       return APValue(0, Result.getZExtValue());
     }
   }
-  
-  assert(0 && "Unhandled cast");
+
+  if (SubExpr->getType()->isFunctionType() ||
+      SubExpr->getType()->isArrayType()) {
+    APValue Result;
+    if (EvaluateLValue(SubExpr, Result, Info))
+      return Result;
+    return APValue();
+  }
+
+  //assert(0 && "Unhandled cast");
   return APValue();
 }  
 
+APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
+  bool BoolResult;
+  if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+    return APValue();
+
+  Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+
+  APValue Result;
+  if (EvaluatePointer(EvalExpr, Result, Info))
+    return Result;
+  return APValue();
+}
 
 //===----------------------------------------------------------------------===//
 // Integer Evaluation
@@ -349,8 +494,8 @@
       return false;
     
     // X && 0 -> 0, X || 1 -> 1.
-    if (E->getOpcode() == BinaryOperator::LAnd && RHS == 0 ||
-        E->getOpcode() == BinaryOperator::LOr  && RHS != 0) {
+    if ((E->getOpcode() == BinaryOperator::LAnd && RHS == 0) ||
+        (E->getOpcode() == BinaryOperator::LOr  && RHS != 0)) {
       Result = RHS != 0;
       Result.zextOrTrunc(getIntTypeSizeInBits(E->getType()));
       Result.setIsUnsigned(E->getType()->isUnsignedIntegerType());
@@ -470,10 +615,13 @@
   QualType SrcTy = E->getTypeOfArgument();
 
   // sizeof(void) and __alignof__(void) = 1 as a gcc extension.
-  if (SrcTy->isVoidType())
+  if (SrcTy->isVoidType()) {
     Result = 1;
+    return true;
+  }
   
   // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+  // FIXME: But alignof(vla) is!
   if (!SrcTy->isConstantSizeType()) {
     // FIXME: Should we attempt to evaluate this?
     return false;
@@ -491,7 +639,7 @@
   // Get information about the size or align.
   unsigned CharSize = Info.Ctx.Target.getCharWidth();
   if (isSizeOf)
-    Result = getIntTypeSizeInBits(SrcTy) / CharSize;
+    Result = Info.Ctx.getTypeSize(SrcTy) / CharSize;
   else
     Result = Info.Ctx.getTypeAlign(SrcTy) / CharSize;
   return true;
@@ -547,6 +695,16 @@
                                   Expr *SubExpr, QualType DestType) {
   unsigned DestWidth = getIntTypeSizeInBits(DestType);
 
+  if (DestType->isBooleanType()) {
+    bool BoolResult;
+    if (!HandleConversionToBool(SubExpr, BoolResult, Info))
+      return false;
+    Result.zextOrTrunc(DestWidth);
+    Result.setIsUnsigned(DestType->isUnsignedIntegerType());
+    Result = BoolResult;
+    return true;
+  }
+
   // Handle simple integer->integer casts.
   if (SubExpr->getType()->isIntegerType()) {
     if (!Visit(SubExpr))
@@ -554,12 +712,7 @@
     
     // Figure out if this is a truncate, extend or noop cast.
     // If the input is signed, do a sign extend, noop, or truncate.
-    if (DestType->isBooleanType()) {
-      // Conversion to bool compares against zero.
-      Result = Result != 0;
-      Result.zextOrTrunc(DestWidth);
-    } else
-      Result.extOrTrunc(DestWidth);
+    Result.extOrTrunc(DestWidth);
     Result.setIsUnsigned(DestType->isUnsignedIntegerType());
     return true;
   }
@@ -569,29 +722,22 @@
     APValue LV;
     if (!EvaluatePointer(SubExpr, LV, Info))
       return false;
+
     if (LV.getLValueBase())
       return false;
-    
+
     Result.extOrTrunc(DestWidth);
     Result = LV.getLValueOffset();
     Result.setIsUnsigned(DestType->isUnsignedIntegerType());
     return true;
   }
-  
+
   if (!SubExpr->getType()->isRealFloatingType())
     return Error(CastLoc, diag::err_expr_not_constant, DestType);
 
   APFloat F(0.0);
   if (!EvaluateFloat(SubExpr, F, Info))
     return Error(CastLoc, diag::err_expr_not_constant, DestType);
-
-  // If the destination is boolean, compare against zero.
-  if (DestType->isBooleanType()) {
-    Result = !F.isZero();
-    Result.zextOrTrunc(DestWidth);
-    Result.setIsUnsigned(DestType->isUnsignedIntegerType());
-    return true;
-  }     
   
   // Determine whether we are converting to unsigned or signed.
   bool DestSigned = DestType->isSignedIntegerType();
@@ -629,6 +775,8 @@
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitBinaryOperator(const BinaryOperator *E);
   bool VisitFloatingLiteral(const FloatingLiteral *E);
+  bool VisitCastExpr(CastExpr *E);
+  bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
 };
 } // end anonymous namespace
 
@@ -738,6 +886,35 @@
   return true;
 }
 
+bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
+  Expr* SubExpr = E->getSubExpr();
+  const llvm::fltSemantics& destSemantics =
+      Info.Ctx.getFloatTypeSemantics(E->getType());
+  if (SubExpr->getType()->isIntegralType()) {
+    APSInt IntResult;
+    if (!EvaluateInteger(E, IntResult, Info))
+      return false;
+    Result = APFloat(destSemantics, 1);
+    Result.convertFromAPInt(IntResult, IntResult.isSigned(),
+                            APFloat::rmNearestTiesToEven);
+    return true;
+  }
+  if (SubExpr->getType()->isRealFloatingType()) {
+    if (!Visit(SubExpr))
+      return false;
+    bool ignored;
+    Result.convert(destSemantics, APFloat::rmNearestTiesToEven, &ignored);
+    return true;
+  }
+
+  return false;
+}
+
+bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+  Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // Top level TryEvaluate.
 //===----------------------------------------------------------------------===//

Added: cfe/trunk/test/Sema/const-eval.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/const-eval.c?rev=59125&view=auto

==============================================================================
--- cfe/trunk/test/Sema/const-eval.c (added)
+++ cfe/trunk/test/Sema/const-eval.c Wed Nov 12 03:44:48 2008
@@ -0,0 +1,13 @@
+// RUN: clang -fsyntax-only -verify %s
+
+#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
+int x;
+EVAL_EXPR(1, (_Bool)&x)
+EVAL_EXPR(2, (int)(1.0+(double)4))
+EVAL_EXPR(3, (int)(1.0+(float)4.0))
+EVAL_EXPR(4, (_Bool)(1 ? (void*)&x : 0))
+EVAL_EXPR(5, (_Bool)(int[]){0})
+struct y {int x,y;};
+EVAL_EXPR(6, (int)(1+(struct y*)0))
+EVAL_EXPR(7, (int)&((struct y*)0)->y)
+EVAL_EXPR(8, (_Bool)"asdf")





More information about the cfe-commits mailing list