[cfe-commits] r143922 - in /cfe/trunk: include/clang/AST/APValue.h lib/AST/APValue.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Daniel Dunbar daniel at zuster.org
Tue Mar 6 15:37:52 PST 2012


Hi Richard,

I've been looking into compile time performance, and I'm worried about
this code.

It looks like it is doing a lot of work for non-C++ code, and I see a
pretty big compile time speedup (2%, which is pretty big for one
thing) from disabling this code.

Below is a report (generated using assorted dtrace and custom scripts)
which compares the calls made by Clang with this code disabled (i.e.,
I put a return false at the head of the function). There is really a
ton of work being done here, which seems absolutely wrong for C code.

Can you investigate?

Report follows. Percentages are of total # of calls made during
execution of clang on 403.gcc / combine.c, although I expect the
particular test case is not that important.
--
$ ./compare-stats.py data/rclang.r152133-full-dtrace-log-0.txt.summary
rclang-2012-03-06_15-08-full-dtrace-log-0.txt.summary | head -20
A:   115525, B:    50444, Abs Delta:   -65081, Change: -0.60%
	clang::Expr::getExprLoc() const
A:   118302, B:    72984, Abs Delta:   -45318, Change: -0.42%
	clang::Stmt::getSourceRange() const
A:    89344, B:    56217, Abs Delta:   -33127, Change: -0.31%
	clang::DeclarationNameInfo::getEndLoc() const
A:    77534, B:    44439, Abs Delta:   -33095, Change: -0.31%
	clang::DeclRefExpr::getSourceRange() const
A:    29797, B:     2218, Abs Delta:   -27579, Change: -0.26%
	(anonymous namespace)::EvalInfo::Diag(clang::SourceLocation, unsigned
int, unsigned int)
A:    39639, B:    12060, Abs Delta:   -27579, Change: -0.26%
	clang::VarDecl::isThisDeclarationADefinition() const
A:    27885, B:      306, Abs Delta:   -27579, Change: -0.26%
	clang::VarDecl::getDefinition()
A:    27579, B:        0, Abs Delta:   -27579, Change: -0.26%
	_ZL30HandleLValueToRValueConversionRN12_GLOBAL__N_18EvalInfoEPKN5clang4ExprENS2_8QualTypeERKNS_6LValueERNS2_7APValueE
A:    64310, B:    37768, Abs Delta:   -26542, Change: -0.25%
	clang::Decl::getASTContext() const
A:    10170, B:        0, Abs Delta:   -10170, Change: -0.09%
	clang::Type::isFloatingType() const
--

 - Daniel

On Mon, Nov 7, 2011 at 1:22 AM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Mon Nov  7 03:22:26 2011
> New Revision: 143922
>
> URL: http://llvm.org/viewvc/llvm-project?rev=143922&view=rev
> Log:
> Constant expression evaluation: support for arrays.
>
> Modified:
>    cfe/trunk/include/clang/AST/APValue.h
>    cfe/trunk/lib/AST/APValue.cpp
>    cfe/trunk/lib/AST/ExprConstant.cpp
>    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
>    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
>
> Modified: cfe/trunk/include/clang/AST/APValue.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=143922&r1=143921&r2=143922&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/APValue.h (original)
> +++ cfe/trunk/include/clang/AST/APValue.h Mon Nov  7 03:22:26 2011
> @@ -25,7 +25,8 @@
>   class Decl;
>
>  /// APValue - This class implements a discriminated union of [uninitialized]
> -/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
> +/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
> +/// [Vector: N * APValue], [Array: N * APValue]
>  class APValue {
>   typedef llvm::APSInt APSInt;
>   typedef llvm::APFloat APFloat;
> @@ -37,13 +38,15 @@
>     ComplexInt,
>     ComplexFloat,
>     LValue,
> -    Vector
> +    Vector,
> +    Array
>   };
>   union LValuePathEntry {
>     const Decl *BaseOrMember;
>     uint64_t ArrayIndex;
>   };
>   struct NoLValuePath {};
> +  struct UninitArray {};
>  private:
>   ValueKind Kind;
>
> @@ -55,15 +58,19 @@
>     APFloat Real, Imag;
>     ComplexAPFloat() : Real(0.0), Imag(0.0) {}
>   };
> -
> +  struct LV;
>   struct Vec {
>     APValue *Elts;
>     unsigned NumElts;
>     Vec() : Elts(0), NumElts(0) {}
>     ~Vec() { delete[] Elts; }
>   };
> -
> -  struct LV;
> +  struct Arr {
> +    APValue *Elts;
> +    unsigned NumElts, ArrSize;
> +    Arr(unsigned NumElts, unsigned ArrSize);
> +    ~Arr();
> +  };
>
>   enum {
>     MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
> @@ -104,6 +111,9 @@
>     MakeLValue(); setLValue(B, O, Path);
>   }
>   APValue(const Expr *B);
> +  APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
> +    MakeArray(InitElts, Size);
> +  }
>
>   ~APValue() {
>     MakeUninit();
> @@ -117,6 +127,7 @@
>   bool isComplexFloat() const { return Kind == ComplexFloat; }
>   bool isLValue() const { return Kind == LValue; }
>   bool isVector() const { return Kind == Vector; }
> +  bool isArray() const { return Kind == Array; }
>
>   void print(raw_ostream &OS) const;
>   void dump() const;
> @@ -137,19 +148,6 @@
>     return const_cast<APValue*>(this)->getFloat();
>   }
>
> -  APValue &getVectorElt(unsigned i) {
> -    assert(isVector() && "Invalid accessor");
> -    return ((Vec*)(char*)Data)->Elts[i];
> -  }
> -  const APValue &getVectorElt(unsigned i) const {
> -    assert(isVector() && "Invalid accessor");
> -    return ((const Vec*)(const char*)Data)->Elts[i];
> -  }
> -  unsigned getVectorLength() const {
> -    assert(isVector() && "Invalid accessor");
> -    return ((const Vec*)(const void *)Data)->NumElts;
> -  }
> -
>   APSInt &getComplexIntReal() {
>     assert(isComplexInt() && "Invalid accessor");
>     return ((ComplexAPSInt*)(char*)Data)->Real;
> @@ -190,6 +188,47 @@
>   bool hasLValuePath() const;
>   ArrayRef<LValuePathEntry> getLValuePath() const;
>
> +  APValue &getVectorElt(unsigned I) {
> +    assert(isVector() && "Invalid accessor");
> +    assert(I < getVectorLength() && "Index out of range");
> +    return ((Vec*)(char*)Data)->Elts[I];
> +  }
> +  const APValue &getVectorElt(unsigned I) const {
> +    return const_cast<APValue*>(this)->getVectorElt(I);
> +  }
> +  unsigned getVectorLength() const {
> +    assert(isVector() && "Invalid accessor");
> +    return ((const Vec*)(const void *)Data)->NumElts;
> +  }
> +
> +  APValue &getArrayInitializedElt(unsigned I) {
> +    assert(isArray() && "Invalid accessor");
> +    assert(I < getArrayInitializedElts() && "Index out of range");
> +    return ((Arr*)(char*)Data)->Elts[I];
> +  }
> +  const APValue &getArrayInitializedElt(unsigned I) const {
> +    return const_cast<APValue*>(this)->getArrayInitializedElt(I);
> +  }
> +  bool hasArrayFiller() const {
> +    return getArrayInitializedElts() != getArraySize();
> +  }
> +  APValue &getArrayFiller() {
> +    assert(isArray() && "Invalid accessor");
> +    assert(hasArrayFiller() && "No array filler");
> +    return ((Arr*)(char*)Data)->Elts[getArrayInitializedElts()];
> +  }
> +  const APValue &getArrayFiller() const {
> +    return const_cast<APValue*>(this)->getArrayFiller();
> +  }
> +  unsigned getArrayInitializedElts() const {
> +    assert(isArray() && "Invalid accessor");
> +    return ((const Arr*)(const void *)Data)->NumElts;
> +  }
> +  unsigned getArraySize() const {
> +    assert(isArray() && "Invalid accessor");
> +    return ((const Arr*)(const void *)Data)->ArrSize;
> +  }
> +
>   void setInt(const APSInt &I) {
>     assert(isInt() && "Invalid accessor");
>     *(APSInt*)(char*)Data = I;
> @@ -253,6 +292,7 @@
>     Kind = ComplexFloat;
>   }
>   void MakeLValue();
> +  void MakeArray(unsigned InitElts, unsigned Size);
>  };
>
>  inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
>
> Modified: cfe/trunk/lib/AST/APValue.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=143922&r1=143921&r2=143922&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/APValue.cpp (original)
> +++ cfe/trunk/lib/AST/APValue.cpp Mon Nov  7 03:22:26 2011
> @@ -55,6 +55,13 @@
>   }
>  };
>
> +// FIXME: Reduce the malloc traffic here.
> +
> +APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
> +  Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
> +  NumElts(NumElts), ArrSize(Size) {}
> +APValue::Arr::~Arr() { delete [] Elts; }
> +
>  APValue::APValue(const Expr* B) : Kind(Uninitialized) {
>   MakeLValue();
>   setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>());
> @@ -75,6 +82,8 @@
>       MakeComplexFloat();
>     else if (RHS.isLValue())
>       MakeLValue();
> +    else if (RHS.isArray())
> +      MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
>   }
>   if (isInt())
>     setInt(RHS.getInt());
> @@ -92,6 +101,11 @@
>       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
>     else
>       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
> +  } else if (isArray()) {
> +    for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
> +      getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
> +    if (RHS.hasArrayFiller())
> +      getArrayFiller() = RHS.getArrayFiller();
>   }
>   return *this;
>  }
> @@ -107,9 +121,10 @@
>     ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt();
>   else if (Kind == ComplexFloat)
>     ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat();
> -  else if (Kind == LValue) {
> +  else if (Kind == LValue)
>     ((LV*)(char*)Data)->~LV();
> -  }
> +  else if (Kind == Array)
> +    ((Arr*)(char*)Data)->~Arr();
>   Kind = Uninitialized;
>  }
>
> @@ -149,9 +164,20 @@
>   case ComplexFloat:
>     OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
>        << ", " << GetApproxValue(getComplexFloatImag());
> +    return;
>   case LValue:
>     OS << "LValue: <todo>";
>     return;
> +  case Array:
> +    OS << "Array: ";
> +    for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) {
> +      OS << getArrayInitializedElt(I);
> +      if (I != getArraySize() - 1) OS << ", ";
> +    }
> +    if (hasArrayFiller())
> +      OS << getArraySize() - getArrayInitializedElts() << " x "
> +         << getArrayFiller();
> +    return;
>   }
>  }
>
> @@ -187,6 +213,15 @@
>   case APValue::LValue:
>     Out << "LValue: <todo>";
>     break;
> +  case APValue::Array:
> +    Out << '{';
> +    if (unsigned N = V.getArrayInitializedElts()) {
> +      Out << V.getArrayInitializedElt(0);
> +      for (unsigned I = 1; I != N; ++I)
> +        Out << ", " << V.getArrayInitializedElt(I);
> +    }
> +    Out << '}';
> +    break;
>   }
>  }
>
> @@ -244,3 +279,9 @@
>   new ((void*)(char*)Data) LV();
>   Kind = LValue;
>  }
> +
> +void APValue::MakeArray(unsigned InitElts, unsigned Size) {
> +  assert(isUninit() && "Bad state change");
> +  new ((void*)(char*)Data) Arr(InitElts, Size);
> +  Kind = Array;
> +}
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143922&r1=143921&r2=143922&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Nov  7 03:22:26 2011
> @@ -132,6 +132,7 @@
>     void adjustIndex(uint64_t N) {
>       if (Invalid) return;
>       if (ArrayElement) {
> +        // FIXME: Make sure the index stays within bounds, or one past the end.
>         Entries.back().ArrayIndex += N;
>         return;
>       }
> @@ -475,6 +476,7 @@
>     return EvalPointerValueAsBool(PointerResult, Result);
>   }
>   case APValue::Vector:
> +  case APValue::Array:
>     return false;
>   }
>
> @@ -569,6 +571,13 @@
>   // expression. If not, we should propagate up a diagnostic.
>   APValue EvalResult;
>   if (!EvaluateConstantExpression(EvalResult, InitInfo, Init)) {
> +    // FIXME: If the evaluation failure was not permanent (for instance, if we
> +    // hit a variable with no declaration yet, or a constexpr function with no
> +    // definition yet), the standard is unclear as to how we should behave.
> +    //
> +    // Either the initializer should be evaluated when the variable is defined,
> +    // or a failed evaluation of the initializer should be reattempted each time
> +    // it is used.
>     VD->setEvaluatedValue(APValue());
>     return false;
>   }
> @@ -583,8 +592,48 @@
>   return Quals.hasConst() && !Quals.hasVolatile();
>  }
>
> -bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
> -                                    const LValue &LVal, CCValue &RVal) {
> +/// Extract the designated sub-object of an rvalue.
> +static bool ExtractSubobject(EvalInfo &Info, CCValue &Obj, QualType ObjType,
> +                             const SubobjectDesignator &Sub, QualType SubType) {
> +  if (Sub.Invalid || Sub.OnePastTheEnd)
> +    return false;
> +  if (Sub.Entries.empty()) {
> +    assert(Info.Ctx.hasSameUnqualifiedType(ObjType, SubType) &&
> +           "Unexpected subobject type");
> +    return true;
> +  }
> +
> +  assert(!Obj.isLValue() && "extracting subobject of lvalue");
> +  const APValue *O = &Obj;
> +  for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
> +    if (O->isUninit())
> +      return false;
> +    if (ObjType->isArrayType()) {
> +      const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
> +      if (!CAT)
> +        return false;
> +      uint64_t Index = Sub.Entries[I].ArrayIndex;
> +      if (CAT->getSize().ule(Index))
> +        return false;
> +      if (O->getArrayInitializedElts() > Index)
> +        O = &O->getArrayInitializedElt(Index);
> +      else
> +        O = &O->getArrayFiller();
> +      ObjType = CAT->getElementType();
> +    } else {
> +      // FIXME: Support handling of subobjects of structs and unions. Also
> +      // for vector elements, if we want to support those?
> +    }
> +  }
> +
> +  assert(Info.Ctx.hasSameUnqualifiedType(ObjType, SubType) &&
> +         "Unexpected subobject type");
> +  Obj = CCValue(*O, CCValue::GlobalValue());
> +  return true;
> +}
> +
> +static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
> +                                           const LValue &LVal, CCValue &RVal) {
>   const Expr *Base = LVal.Base;
>   CallStackFrame *Frame = LVal.Frame;
>
> @@ -620,10 +669,7 @@
>       return false;
>
>     if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
> -      // If the lvalue refers to a subobject or has been cast to some other
> -      // type, don't use it.
> -      return LVal.Offset.isZero() &&
> -             Info.Ctx.hasSameUnqualifiedType(Type, VT);
> +      return ExtractSubobject(Info, RVal, VT, LVal.Designator, Type);
>
>     // The declaration was initialized by an lvalue, with no lvalue-to-rvalue
>     // conversion. This happens when the declaration and the lvalue should be
> @@ -654,31 +700,22 @@
>     return true;
>   }
>
> -  // FIXME: Support accessing subobjects of objects of literal types. A simple
> -  // byte offset is insufficient for C++11 semantics: we need to know how the
> -  // reference was formed (which union member was named, for instance).
> -
> -  // Beyond this point, we don't support accessing subobjects.
> -  if (!LVal.Offset.isZero() ||
> -      !Info.Ctx.hasSameUnqualifiedType(Type, Base->getType()))
> -    return false;
> -
> -  // If this is a temporary expression with a nontrivial initializer, grab the
> -  // value from the relevant stack frame.
>   if (Frame) {
> +    // If this is a temporary expression with a nontrivial initializer, grab the
> +    // value from the relevant stack frame.
>     RVal = Frame->Temporaries[Base];
> -    return true;
> -  }
> -
> -  // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
> -  // initializer until now for such expressions. Such an expression can't be
> -  // an ICE in C, so this only matters for fold.
> -  if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
> +  } else if (const CompoundLiteralExpr *CLE
> +             = dyn_cast<CompoundLiteralExpr>(Base)) {
> +    // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
> +    // initializer until now for such expressions. Such an expression can't be
> +    // an ICE in C, so this only matters for fold.
>     assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
> -    return Evaluate(RVal, Info, CLE->getInitializer());
> -  }
> +    if (!Evaluate(RVal, Info, CLE->getInitializer()))
> +      return false;
> +  } else
> +    return false;
>
> -  return false;
> +  return ExtractSubobject(Info, RVal, Base->getType(), LVal.Designator, Type);
>  }
>
>  namespace {
> @@ -1600,6 +1637,55 @@
>  }
>
>  //===----------------------------------------------------------------------===//
> +// Array Evaluation
> +//===----------------------------------------------------------------------===//
> +
> +namespace {
> +  class ArrayExprEvaluator
> +  : public ExprEvaluatorBase<ArrayExprEvaluator, bool> {
> +    APValue &Result;
> +  public:
> +
> +    ArrayExprEvaluator(EvalInfo &Info, APValue &Result)
> +      : ExprEvaluatorBaseTy(Info), Result(Result) {}
> +
> +    bool Success(const APValue &V, const Expr *E) {
> +      assert(V.isArray() && "Expected array type");
> +      Result = V;
> +      return true;
> +    }
> +    bool Error(const Expr *E) { return false; }
> +
> +    bool VisitInitListExpr(const InitListExpr *E);
> +  };
> +} // end anonymous namespace
> +
> +static bool EvaluateArray(const Expr* E, APValue& Result, EvalInfo &Info) {
> +  assert(E->isRValue() && E->getType()->isArrayType() &&
> +         E->getType()->isLiteralType() && "not a literal array rvalue");
> +  return ArrayExprEvaluator(Info, Result).Visit(E);
> +}
> +
> +bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
> +  const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
> +  if (!CAT)
> +    return false;
> +
> +  Result = APValue(APValue::UninitArray(), E->getNumInits(),
> +                   CAT->getSize().getZExtValue());
> +  for (InitListExpr::const_iterator I = E->begin(), End = E->end();
> +       I != End; ++I)
> +    if (!EvaluateConstantExpression(Result.getArrayInitializedElt(I-E->begin()),
> +                                    Info, cast<Expr>(*I)))
> +      return false;
> +
> +  if (!Result.hasArrayFiller()) return true;
> +  assert(E->hasArrayFiller() && "no array filler for incomplete init list");
> +  return EvaluateConstantExpression(Result.getArrayFiller(), Info,
> +                                    E->getArrayFiller());
> +}
> +
> +//===----------------------------------------------------------------------===//
>  // Integer Evaluation
>  //
>  // As a GNU extension, we support casting pointers to sufficiently-wide integer
> @@ -2173,6 +2259,10 @@
>         return Success(E->getOpcode() == BO_NE, E);
>       }
>
> +      // FIXME: Implement the C++11 restrictions:
> +      //  - Pointer subtractions must be on elements of the same array.
> +      //  - Pointer comparisons must be between members with the same access.
> +
>       if (E->getOpcode() == BO_Sub) {
>         QualType Type = E->getLHS()->getType();
>         QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
> @@ -3258,8 +3348,8 @@
>     // FIXME: Implement evaluation of pointer-to-member types.
>     return false;
>   } else if (E->getType()->isArrayType() && E->getType()->isLiteralType()) {
> -    // FIXME: Implement evaluation of array rvalues.
> -    return false;
> +    if (!EvaluateArray(E, Result, Info))
> +      return false;
>   } else if (E->getType()->isRecordType() && E->getType()->isLiteralType()) {
>     // FIXME: Implement evaluation of record rvalues.
>     return false;
> @@ -3278,10 +3368,10 @@
>   if (E->isRValue() && E->getType()->isLiteralType()) {
>     // Evaluate arrays and record types in-place, so that later initializers can
>     // refer to earlier-initialized members of the object.
> -    if (E->getType()->isArrayType())
> -      // FIXME: Implement evaluation of array rvalues.
> -      return false;
> -    else if (E->getType()->isRecordType())
> +    if (E->getType()->isArrayType()) {
> +      if (!EvaluateArray(E, Result, Info))
> +        return false;
> +    } else if (E->getType()->isRecordType())
>       // FIXME: Implement evaluation of record rvalues.
>       return false;
>   }
> @@ -3312,6 +3402,10 @@
>       return false;
>   }
>
> +  // Don't produce array constants until CodeGen is taught to handle them.
> +  if (Value.isArray())
> +    return false;
> +
>   // Check this core constant expression is a constant expression, and if so,
>   // convert it to one.
>   return CheckConstantExpression(Value, Result.Val);
>
> Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=143922&r1=143921&r2=143922&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Mon Nov  7 03:22:26 2011
> @@ -1070,6 +1070,9 @@
>       }
>       return llvm::ConstantVector::get(Inits);
>     }
> +    case APValue::Array:
> +      assert(0 && "shouldn't see array constants here yet");
> +      break;
>     }
>   }
>
>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143922&r1=143921&r2=143922&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Mon Nov  7 03:22:26 2011
> @@ -280,3 +280,45 @@
>  static_assert_fold(max == str + 38, "");
>
>  }
> +
> +namespace Array {
> +
> +// FIXME: Use templates for these once we support constexpr templates.
> +constexpr int Sum(const int *begin, const int *end) {
> +  return begin == end ? 0 : *begin + Sum(begin+1, end);
> +}
> +constexpr const int *begin(const int (&xs)[5]) { return xs; }
> +constexpr const int *end(const int (&xs)[5]) { return xs + 5; }
> +
> +constexpr int xs[] = { 1, 2, 3, 4, 5 };
> +constexpr int ys[] = { 5, 4, 3, 2, 1 };
> +constexpr int sum_xs = Sum(begin(xs), end(xs));
> +static_assert_fold(sum_xs == 15, "");
> +
> +constexpr int ZipFoldR(int (*F)(int x, int y, int c), int n,
> +                       const int *xs, const int *ys, int c) {
> +  return n ? F(*xs, *ys, ZipFoldR(F, n-1, xs+1, ys+1, c)) : c;
> +}
> +constexpr int MulAdd(int x, int y, int c) { return x * y + c; }
> +constexpr int InnerProduct = ZipFoldR(MulAdd, 5, xs, ys, 0);
> +static_assert_fold(InnerProduct == 35, "");
> +
> +constexpr int SubMul(int x, int y, int c) { return (x - y) * c; }
> +constexpr int DiffProd = ZipFoldR(SubMul, 2, xs+3, ys+3, 1);
> +static_assert_fold(DiffProd == 8, "");
> +static_assert_fold(ZipFoldR(SubMul, 3, xs+3, ys+3, 1), ""); // expected-error {{constant expression}}
> +
> +constexpr const int *p = xs + 3;
> +constexpr int xs4 = p[1]; // ok
> +constexpr int xs5 = p[2]; // expected-error {{constant expression}}
> +constexpr int xs0 = p[-3]; // ok
> +constexpr int xs_1 = p[-4]; // expected-error {{constant expression}}
> +
> +constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
> +static_assert_fold(zs[0][0][0][0] == 1, "");
> +static_assert_fold(zs[1][1][1][1] == 16, "");
> +static_assert_fold(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}}
> +static_assert_fold((&zs[0][0][0][2])[-1] == 2, "");
> +static_assert_fold(**(**(zs + 1) + 1) == 11, "");
> +
> +}
>
>
> _______________________________________________
> 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