Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -1788,18 +1788,25 @@ private: unsigned Opc : 5; unsigned CanOverflow : 1; + // This is only meaningful for operations on floating point types and 0 + // otherwise. + unsigned FPFeatures : 3; + SourceLocation Loc; Stmt *Val; public: UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK, - ExprObjectKind OK, SourceLocation l, bool CanOverflow) + ExprObjectKind OK, SourceLocation l, bool CanOverflow, + FPOptions FPFeatures) : Expr(UnaryOperatorClass, type, VK, OK, input->isTypeDependent() || type->isDependentType(), input->isValueDependent(), (input->isInstantiationDependent() || type->isInstantiationDependentType()), input->containsUnexpandedParameterPack()), - Opc(opc), CanOverflow(CanOverflow), Loc(l), Val(input) {} + Opc(opc), CanOverflow(CanOverflow), + FPFeatures(FPFeatures.getInt()), + Loc(l), Val(input) {} /// Build an empty unary operator. explicit UnaryOperator(EmptyShell Empty) @@ -1890,6 +1897,18 @@ const_child_range children() const { return const_child_range(&Val, &Val + 1); } + + // Set the FP contractability status of this operator. Only meaningful for + // operations on floating point types. + void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); } + + FPOptions getFPFeatures() const { return FPOptions(FPFeatures); } + + // Get the FENV_ACCESS status of this operator. Only meaningful for + // operations on floating point types. + bool isFEnvAccessOn() const { + return FPOptions(FPFeatures).allowFEnvAccess(); + } }; /// Helper class for OffsetOfExpr. Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -5834,7 +5834,8 @@ return new (Importer.getToContext()) UnaryOperator( SubExpr, E->getOpcode(), T, E->getValueKind(), E->getObjectKind(), - Importer.Import(E->getOperatorLoc()), E->canOverflow()); + Importer.Import(E->getOperatorLoc()), E->canOverflow(), + E->getFPFeatures()); } Expr * Index: lib/Analysis/BodyFarm.cpp =================================================================== --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -150,7 +150,7 @@ UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { return new (C) UnaryOperator(const_cast(Arg), UO_Deref, Ty, VK_LValue, OK_Ordinary, SourceLocation(), - /*CanOverflow*/ false); + /*CanOverflow*/ false, FPOptions()); } ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { @@ -457,7 +457,8 @@ /* QualType=*/ C.IntTy, /* ExprValueKind=*/ VK_RValue, /* ExprObjectKind=*/ OK_Ordinary, SourceLocation(), - /* CanOverflow*/ false); + /* CanOverflow*/ false, + FPOptions()); // Create assignment. BinaryOperator *FlagAssignment = M.makeAssignment( @@ -522,7 +523,7 @@ Expr *DoneValue = new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(), - /*CanOverflow*/false); + /*CanOverflow*/false, FPOptions()); BinaryOperator *B = M.makeAssignment( Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -2171,7 +2171,10 @@ F.convert(*FS, llvm::APFloat::rmTowardZero, &ignored); amt = llvm::ConstantFP::get(VMContext, F); } - value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); + if (E->isFEnvAccessOn()) + value = Builder.CreateConstrainedFAdd(value, amt, isInc ? "inc" : "dec"); + else + value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) { if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) { Index: lib/CodeGen/CGObjC.cpp =================================================================== --- lib/CodeGen/CGObjC.cpp +++ lib/CodeGen/CGObjC.cpp @@ -3267,12 +3267,14 @@ DeclRefExpr DstExpr(&DstDecl, false, DestTy, VK_RValue, SourceLocation()); UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(), - VK_LValue, OK_Ordinary, SourceLocation(), false); + VK_LValue, OK_Ordinary, SourceLocation(), false, + FPOptions()); DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy, VK_RValue, SourceLocation()); UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(), - VK_LValue, OK_Ordinary, SourceLocation(), false); + VK_LValue, OK_Ordinary, SourceLocation(), false, + FPOptions()); Expr *Args[2] = { &DST, &SRC }; CallExpr *CalleeExp = cast(PID->getSetterCXXAssignment()); @@ -3350,7 +3352,8 @@ VK_RValue, SourceLocation()); UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(), - VK_LValue, OK_Ordinary, SourceLocation(), false); + VK_LValue, OK_Ordinary, SourceLocation(), false, + FPOptions()); CXXConstructExpr *CXXConstExpr = cast(PID->getGetterCXXConstructor()); Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -2514,7 +2514,7 @@ OK_Ordinary, S.getBeginLoc(), FPOptions()); // Increment for loop counter. UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, - S.getBeginLoc(), true); + S.getBeginLoc(), true, FPOptions()); auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) { // Iterate through all sections and emit a switch construct: // switch (IV) { Index: lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -2589,7 +2589,8 @@ Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CK_CPointerToObjCPointerCast, Unop); @@ -3294,7 +3295,8 @@ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -3312,7 +3314,8 @@ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); } MsgExprs.push_back(SuperRep); break; @@ -3388,7 +3391,7 @@ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, FPOptions()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -4719,7 +4722,8 @@ return DRE; Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), VK_LValue, OK_Ordinary, - DRE->getLocation(), false); + DRE->getLocation(), false, + FPOptions()); // Need parens to enforce precedence. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), Exp); @@ -5313,7 +5317,7 @@ UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, FPOptions()); InitExprs.push_back(DescRefExpr); // Add initializers for any closure decl refs. @@ -5332,7 +5336,7 @@ QT = Context->getPointerType(QT); Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, OK_Ordinary, SourceLocation(), - false); + false, FPOptions()); } } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getName()); @@ -5349,7 +5353,7 @@ QT = Context->getPointerType(QT); Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, OK_Ordinary, SourceLocation(), - false); + false, FPOptions()); } } @@ -5390,7 +5394,7 @@ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary, SourceLocation(), - false); + false, FPOptions()); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); InitExprs.push_back(Exp); } @@ -5416,7 +5420,8 @@ NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), - VK_RValue, OK_Ordinary, SourceLocation(), false); + VK_RValue, OK_Ordinary, SourceLocation(), false, + FPOptions()); NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep); // Put Paren around the call. @@ -7560,7 +7565,8 @@ Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT, VK_LValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); PE = new (Context) ParenExpr(OldRange.getBegin(), OldRange.getEnd(), Exp); Index: lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- lib/Frontend/Rewrite/RewriteObjC.cpp +++ lib/Frontend/Rewrite/RewriteObjC.cpp @@ -2511,7 +2511,8 @@ Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CK_CPointerToObjCPointerCast, Unop); @@ -2712,7 +2713,8 @@ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -2730,7 +2732,8 @@ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, + FPOptions()); } MsgExprs.push_back(SuperRep); break; @@ -2806,7 +2809,7 @@ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, FPOptions()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -3045,7 +3048,8 @@ VK_LValue, SourceLocation()); Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, SourceLocation(), false); + VK_RValue, OK_Ordinary, SourceLocation(), false, + FPOptions()); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), CK_BitCast, DerefExpr); @@ -3875,7 +3879,8 @@ return DRE; Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), VK_LValue, OK_Ordinary, - DRE->getLocation(), false); + DRE->getLocation(), false, + FPOptions()); // Need parens to enforce precedence. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), Exp); @@ -4438,7 +4443,7 @@ UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue, OK_Ordinary, - SourceLocation(), false); + SourceLocation(), false, FPOptions()); InitExprs.push_back(DescRefExpr); // Add initializers for any closure decl refs. @@ -4457,7 +4462,7 @@ QT = Context->getPointerType(QT); Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, OK_Ordinary, SourceLocation(), - false); + false, FPOptions()); } } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getName()); @@ -4474,7 +4479,7 @@ QT = Context->getPointerType(QT); Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, OK_Ordinary, SourceLocation(), - false); + false, FPOptions()); } } InitExprs.push_back(Exp); @@ -4513,7 +4518,7 @@ if (!isNestedCapturedVar) Exp = new (Context) UnaryOperator( Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue, - OK_Ordinary, SourceLocation(), false); + OK_Ordinary, SourceLocation(), false, FPOptions()); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); InitExprs.push_back(Exp); } @@ -4531,7 +4536,8 @@ FType, VK_LValue, SourceLocation()); NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), - VK_RValue, OK_Ordinary, SourceLocation(), false); + VK_RValue, OK_Ordinary, SourceLocation(), false, + FPOptions()); NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep); BlockDeclRefs.clear(); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -11440,11 +11440,11 @@ Expr *From = FromB.build(S, Loc); From = new (S.Context) UnaryOperator(From, UO_AddrOf, S.Context.getPointerType(From->getType()), - VK_RValue, OK_Ordinary, Loc, false); + VK_RValue, OK_Ordinary, Loc, false, FPOptions()); Expr *To = ToB.build(S, Loc); To = new (S.Context) UnaryOperator(To, UO_AddrOf, S.Context.getPointerType(To->getType()), - VK_RValue, OK_Ordinary, Loc, false); + VK_RValue, OK_Ordinary, Loc, false, FPOptions()); const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = @@ -11688,7 +11688,8 @@ // bound. Expr *Increment = new (S.Context) UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType, - VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue()); + VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue(), + FPOptions()); // Construct the loop that copies all elements of this array. return S.ActOnForStmt( Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12820,7 +12820,8 @@ CheckArrayAccess(Input.get()); auto *UO = new (Context) - UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow); + UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow, + FPFeatures); // Convert the result back to a half vector. if (ConvertHalfVec) return convertVector(UO, Context.HalfTy, *this); Index: lib/Sema/SemaExprObjC.cpp =================================================================== --- lib/Sema/SemaExprObjC.cpp +++ lib/Sema/SemaExprObjC.cpp @@ -4307,7 +4307,8 @@ Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); return new (Context) UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(), - sub->getObjectKind(), uo->getOperatorLoc(), false); + sub->getObjectKind(), uo->getOperatorLoc(), false, + FPFeatures); } else if (GenericSelectionExpr *gse = dyn_cast(e)) { assert(!gse->isResultDependent()); Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -12146,7 +12146,8 @@ if (Input->isTypeDependent()) { if (Fns.empty()) return new (Context) UnaryOperator(Input, Opc, Context.DependentTy, - VK_RValue, OK_Ordinary, OpLoc, false); + VK_RValue, OK_Ordinary, OpLoc, false, + FPFeatures); CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators UnresolvedLookupExpr *Fn @@ -13671,7 +13672,8 @@ return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc(), false); + UnOp->getOperatorLoc(), false, + FPFeatures); } } Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), @@ -13682,7 +13684,8 @@ return new (Context) UnaryOperator(SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()), VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc(), false); + UnOp->getOperatorLoc(), false, + FPFeatures); } // C++ [except.spec]p17: Index: lib/Sema/SemaPseudoObject.cpp =================================================================== --- lib/Sema/SemaPseudoObject.cpp +++ lib/Sema/SemaPseudoObject.cpp @@ -133,7 +133,8 @@ uop->getValueKind(), uop->getObjectKind(), uop->getOperatorLoc(), - uop->canOverflow()); + uop->canOverflow(), + FPOptions()); } if (GenericSelectionExpr *gse = dyn_cast(e)) { @@ -543,7 +544,7 @@ !resultType->isDependentType() ? S.Context.getTypeSize(resultType) >= S.Context.getTypeSize(S.Context.IntTy) - : false); + : false, FPOptions()); return complete(syntactic); } @@ -1564,7 +1565,8 @@ // Do nothing if the operand is dependent. if (op->isTypeDependent()) return new (Context) UnaryOperator(op, opcode, Context.DependentTy, - VK_RValue, OK_Ordinary, opcLoc, false); + VK_RValue, OK_Ordinary, opcLoc, false, + FPOptions()); assert(UnaryOperator::isIncrementDecrementOp(opcode)); Expr *opaqueRef = op->IgnoreParens(); @@ -1650,7 +1652,8 @@ Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); return new (Context) UnaryOperator( op, uop->getOpcode(), uop->getType(), uop->getValueKind(), - uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow()); + uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(), + FPOptions()); } else if (CompoundAssignOperator *cop = dyn_cast(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -603,6 +603,8 @@ E->setOpcode((UnaryOperator::Opcode)Record.readInt()); E->setOperatorLoc(ReadSourceLocation()); E->setCanOverflow(Record.readInt()); + FPOptions FPFeatures(Record.readInt()); + E->setFPFeatures(FPFeatures); } void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -517,6 +517,7 @@ Record.push_back(E->getOpcode()); // FIXME: stable encoding Record.AddSourceLocation(E->getOperatorLoc()); Record.push_back(E->canOverflow()); + Record.push_back(E->getFPFeatures().getInt()); Code = serialization::EXPR_UNARY_OPERATOR; } Index: test/CodeGen/unary-con-fadd.c =================================================================== --- test/CodeGen/unary-con-fadd.c +++ test/CodeGen/unary-con-fadd.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +#pragma STDC FENV_ACCESS ON + +// Is FENV_ACCESS honored in a simple case? +double test_1(double x) { +// CHECK: test_1 +// CHECK: call double @llvm.experimental.constrained.fadd.f64 + x++; + return x; +}