From 80d4b55db94db2172a04617d1a80feca6bbcea5c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Dec 2011 19:48:30 +0000 Subject: [PATCH] Small refactoring and simplification of constant evaluation and some of its clients. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147318 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 8 +- lib/AST/ExprConstant.cpp | 123 +++++++++++++----------- lib/CodeGen/CGBuiltin.cpp | 1 - lib/CodeGen/CGDebugInfo.cpp | 16 +-- lib/CodeGen/CGExprScalar.cpp | 16 ++- lib/CodeGen/CodeGenFunction.cpp | 12 +-- lib/CodeGen/CodeGenFunction.h | 1 - lib/Sema/SemaChecking.cpp | 6 +- lib/Sema/SemaStmt.cpp | 18 ++-- lib/Sema/SemaType.cpp | 10 +- lib/StaticAnalyzer/Core/ExprEngineC.cpp | 10 +- 11 files changed, 106 insertions(+), 115 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 9c189e2d06..9eff18b714 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -471,10 +471,12 @@ public: /// side-effects. bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const; + enum SideEffectsKind { SE_NoSideEffects, SE_AllowSideEffects }; + /// EvaluateAsInt - Return true if this is a constant which we can fold and - /// convert to an integer without side-effects, using any crazy technique that - /// we want to. - bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx) const; + /// convert to an integer, using any crazy technique that we want to. + bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded without side-effects, but discard the result. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 46580697de..3579e75d94 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -3658,6 +3658,61 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return -1; } +/// EvaluateBuiltinConstantPForLValue - Determine the result of +/// __builtin_constant_p when applied to the given lvalue. +/// +/// An lvalue is only "constant" if it is a pointer or reference to the first +/// character of a string literal. +template +static bool EvaluateBuiltinConstantPForLValue(const LValue &LV) { + const Expr *E = LV.getLValueBase().dyn_cast(); + return E && isa(E) && LV.getLValueOffset().isZero(); +} + +/// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to +/// GCC as we can manage. +static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { + QualType ArgType = Arg->getType(); + + // __builtin_constant_p always has one operand. The rules which gcc follows + // are not precisely documented, but are as follows: + // + // - If the operand is of integral, floating, complex or enumeration type, + // and can be folded to a known value of that type, it returns 1. + // - If the operand and can be folded to a pointer to the first character + // of a string literal (or such a pointer cast to an integral type), it + // returns 1. + // + // Otherwise, it returns 0. + // + // FIXME: GCC also intends to return 1 for literals of aggregate types, but + // its support for this does not currently work. + if (ArgType->isIntegralOrEnumerationType()) { + Expr::EvalResult Result; + if (!Arg->EvaluateAsRValue(Result, Ctx) || Result.HasSideEffects) + return false; + + APValue &V = Result.Val; + if (V.getKind() == APValue::Int) + return true; + + return EvaluateBuiltinConstantPForLValue(V); + } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) { + return Arg->isEvaluatable(Ctx); + } else if (ArgType->isPointerType() || Arg->isGLValue()) { + LValue LV; + Expr::EvalStatus Status; + EvalInfo Info(Ctx, Status); + if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info) + : EvaluatePointer(Arg, LV, Info)) && + !Status.HasSideEffects) + return EvaluateBuiltinConstantPForLValue(LV); + } + + // Anything else isn't considered to be sufficiently constant. + return false; +} + /// Retrieves the "underlying object type" of the given expression, /// as used by __builtin_object_size. QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) { @@ -3722,53 +3777,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); - case Builtin::BI__builtin_constant_p: { - const Expr *Arg = E->getArg(0); - QualType ArgType = Arg->getType(); - // __builtin_constant_p always has one operand. The rules which gcc follows - // are not precisely documented, but are as follows: - // - // - If the operand is of integral, floating, complex or enumeration type, - // and can be folded to a known value of that type, it returns 1. - // - If the operand and can be folded to a pointer to the first character - // of a string literal (or such a pointer cast to an integral type), it - // returns 1. - // - // Otherwise, it returns 0. - // - // FIXME: GCC also intends to return 1 for literals of aggregate types, but - // its support for this does not currently work. - int IsConstant = 0; - if (ArgType->isIntegralOrEnumerationType()) { - // Note, a pointer cast to an integral type is only a constant if it is - // a pointer to the first character of a string literal. - Expr::EvalResult Result; - if (Arg->EvaluateAsRValue(Result, Info.Ctx) && !Result.HasSideEffects) { - APValue &V = Result.Val; - if (V.getKind() == APValue::LValue) { - if (const Expr *E = V.getLValueBase().dyn_cast()) - IsConstant = isa(E) && V.getLValueOffset().isZero(); - } else { - IsConstant = 1; - } - } - } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) { - IsConstant = Arg->isEvaluatable(Info.Ctx); - } else if (ArgType->isPointerType() || Arg->isGLValue()) { - LValue LV; - // Use a separate EvalInfo: ignore constexpr parameter and 'this' bindings - // during the check. - Expr::EvalStatus Status; - EvalInfo SubInfo(Info.Ctx, Status); - if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, SubInfo) - : EvaluatePointer(Arg, LV, SubInfo)) && - !Status.HasSideEffects) - if (const Expr *E = LV.getLValueBase().dyn_cast()) - IsConstant = isa(E) && LV.getLValueOffset().isZero(); - } + case Builtin::BI__builtin_constant_p: + return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E); - return Success(IsConstant, E); - } case Builtin::BI__builtin_eh_return_data_regno: { int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue(); Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand); @@ -5240,10 +5251,14 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, Result); } -bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const { +bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects) const { + if (!getType()->isIntegralOrEnumerationType()) + return false; + EvalResult ExprResult; - if (!EvaluateAsRValue(ExprResult, Ctx) || ExprResult.HasSideEffects || - !ExprResult.Val.isInt()) + if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() || + (!AllowSideEffects && ExprResult.HasSideEffects)) return false; Result = ExprResult.Val.getInt(); @@ -5680,14 +5695,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // extension. See GCC PR38377 for discussion. if (const CallExpr *CallCE = dyn_cast(Exp->getCond()->IgnoreParenCasts())) - if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p) { - Expr::EvalResult EVResult; - if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects || - !EVResult.Val.isInt()) { - return ICEDiag(2, E->getLocStart()); - } - return NoDiag(); - } + if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p) + return CheckEvalInICE(E, Ctx); ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); if (CondResult.Val == 2) return CondResult; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 2a467b59bc..3e5a6772eb 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -16,7 +16,6 @@ #include "CodeGenModule.h" #include "CGObjCRuntime.h" #include "clang/Basic/TargetInfo.h" -#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/TargetBuiltins.h" diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index af6d25d363..f48157f48c 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1107,18 +1107,18 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl); CollectVTableInfo(CXXDecl, Unit, EltTys); } - + // Collect static variables with initializers. for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); I != E; ++I) if (const VarDecl *V = dyn_cast(*I)) { - if (const Expr *Init = V->getInit()) { - Expr::EvalResult Result; - if (Init->EvaluateAsRValue(Result, CGM.getContext()) && - Result.Val.isInt()) { - llvm::ConstantInt *CI - = llvm::ConstantInt::get(CGM.getLLVMContext(), Result.Val.getInt()); - + llvm::SmallVector Notes; + if (V->getInit() && V->evaluateValue(Notes)) { + APValue *Value = V->getEvaluatedValue(); + if (Value && Value->isInt()) { + llvm::ConstantInt *CI + = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); + // Create the descriptor for static variable. llvm::DIFile VUnit = getOrCreateFile(V->getLocation()); StringRef VName = V->getName(); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index e7620af24d..c2aec36ee8 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -801,13 +801,13 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { return Builder.CreateShuffleVector(V1, V2, SV, "shuffle"); } Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { - Expr::EvalResult Result; - if (E->EvaluateAsRValue(Result, CGF.getContext()) && Result.Val.isInt()) { + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) { if (E->isArrow()) CGF.EmitScalarExpr(E->getBase()); else EmitLValue(E->getBase()); - return Builder.getInt(Result.Val.getInt()); + return Builder.getInt(Value); } // Emit debug info for aggregate now, if it was delayed to reduce @@ -1466,9 +1466,9 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { // Try folding the offsetof to a constant. - Expr::EvalResult EvalResult; - if (E->EvaluateAsRValue(EvalResult, CGF.getContext())) - return Builder.getInt(EvalResult.Val.getInt()); + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, CGF.getContext())) + return Builder.getInt(Value); // Loop over the components of the offsetof to compute the value. unsigned n = E->getNumComponents(); @@ -1589,9 +1589,7 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( // If this isn't sizeof(vla), the result must be constant; use the constant // folding logic so we don't have to duplicate it here. - Expr::EvalResult Result; - E->EvaluateAsRValue(Result, CGF.getContext()); - return Builder.getInt(Result.Val.getInt()); + return Builder.getInt(E->EvaluateKnownConstInt(CGF.getContext())); } Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) { diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 0a5efe03be..62d18ea8ee 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -18,7 +18,6 @@ #include "CGDebugInfo.h" #include "CGException.h" #include "clang/Basic/TargetInfo.h" -#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -520,15 +519,14 @@ bool CodeGenFunction:: ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &ResultInt) { // FIXME: Rename and handle conversion of other evaluatable things // to bool. - Expr::EvalResult Result; - if (!Cond->EvaluateAsRValue(Result, getContext()) || !Result.Val.isInt() || - Result.HasSideEffects) + llvm::APSInt Int; + if (!Cond->EvaluateAsInt(Int, getContext())) return false; // Not foldable, not integer or not fully evaluatable. - + if (CodeGenFunction::ContainsLabel(Cond)) return false; // Contains a label. - - ResultInt = Result.Val.getInt(); + + ResultInt = Int; return true; } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f6b05c8c0f..105cfbec82 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -43,7 +43,6 @@ namespace llvm { } namespace clang { - class APValue; class ASTContext; class BlockDecl; class CXXDestructorDecl; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 9bb532b532..44513020bb 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -3662,12 +3662,10 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, Expr *OriginalInit = Init->IgnoreParenImpCasts(); - Expr::EvalResult InitValue; - if (!OriginalInit->EvaluateAsRValue(InitValue, S.Context) || - !InitValue.Val.isInt()) + llvm::APSInt Value; + if (!OriginalInit->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) return false; - const llvm::APSInt &Value = InitValue.Val.getInt(); unsigned OriginalWidth = Value.getBitWidth(); unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 2325711b29..d79218d849 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -16,7 +16,6 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" -#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" @@ -664,20 +663,15 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // condition is constant. llvm::APSInt ConstantCondValue; bool HasConstantCond = false; - bool ShouldCheckConstantCond = false; if (!HasDependentValue && !TheDefaultStmt) { - Expr::EvalResult Result; HasConstantCond - = CondExprBeforePromotion->EvaluateAsRValue(Result, Context); - if (HasConstantCond) { - assert(Result.Val.isInt() && "switch condition evaluated to non-int"); - ConstantCondValue = Result.Val.getInt(); - ShouldCheckConstantCond = true; - - assert(ConstantCondValue.getBitWidth() == CondWidth && - ConstantCondValue.isSigned() == CondIsSigned); - } + = CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context, + Expr::SE_AllowSideEffects); + assert(!HasConstantCond || + (ConstantCondValue.getBitWidth() == CondWidth && + ConstantCondValue.isSigned() == CondIsSigned)); } + bool ShouldCheckConstantCond = HasConstantCond; // Sort all the scalar case values so we can easily detect duplicates. std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 53a541ab46..34f6a93528 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1180,13 +1180,9 @@ static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) { // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable // value as an extension. - Expr::EvalResult Result; - if (S.LangOpts.GNUMode && ArraySize->EvaluateAsRValue(Result, S.Context)) { - if (!Result.hasSideEffects() && Result.Val.isInt()) { - SizeVal = Result.Val.getInt(); - S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant); - return false; - } + if (S.LangOpts.GNUMode && ArraySize->EvaluateAsInt(SizeVal, S.Context)) { + S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant); + return false; } return true; diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index fadfdc40d7..83bc39e1fd 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -482,9 +482,8 @@ void ExprEngine:: VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder B(Pred, Dst, *currentBuilderContext); - Expr::EvalResult Res; - if (OOE->EvaluateAsRValue(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); + APSInt IV; + if (OOE->EvaluateAsInt(IV, getContext())) { assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); assert(OOE->getType()->isIntegerType()); assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType()); @@ -519,9 +518,8 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, } } - Expr::EvalResult Result; - Ex->EvaluateAsRValue(Result, getContext()); - CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue()); + APSInt Value = Ex->EvaluateKnownConstInt(getContext()); + CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); const ProgramState *state = Pred->getState(); state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(), -- 2.40.0