Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -2409,15 +2409,20 @@ unsigned NumArgs; SourceLocation RParenLoc; + // This is only meaningful for operations on floating point types and 0 + // otherwise. + unsigned FPFeatures : 3; + void updateDependenciesFromArg(Expr *Arg); protected: // These versions of the constructor are for derived classes. CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef preargs, ArrayRef args, QualType t, - ExprValueKind VK, SourceLocation rparenloc); + ExprValueKind VK, SourceLocation rparenloc, FPOptions FPFeatures); CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef args, - QualType t, ExprValueKind VK, SourceLocation rparenloc); + QualType t, ExprValueKind VK, SourceLocation rparenloc, + FPOptions FPFeatures); CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty); @@ -2438,7 +2443,7 @@ public: CallExpr(const ASTContext& C, Expr *fn, ArrayRef args, QualType t, - ExprValueKind VK, SourceLocation rparenloc); + ExprValueKind VK, SourceLocation rparenloc, FPOptions FPFeatures); /// Build an empty call expression. CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty); @@ -2578,6 +2583,18 @@ return const_child_range(&SubExprs[0], &SubExprs[0] + NumArgs + getNumPreArgs() + PREARGS_START); } + + // 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(); + } }; /// Extra data stored in some MemberExpr objects. Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -81,9 +81,6 @@ SourceRange Range; - // Only meaningful for floating point types. - FPOptions FPFeatures; - SourceRange getSourceRangeImpl() const LLVM_READONLY; public: @@ -93,8 +90,9 @@ CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, ArrayRef args, QualType t, ExprValueKind VK, SourceLocation operatorloc, FPOptions FPFeatures) - : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc), - Operator(Op), FPFeatures(FPFeatures) { + : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc, + FPFeatures), + Operator(Op) { Range = getSourceRangeImpl(); } @@ -148,16 +146,10 @@ return T->getStmtClass() == CXXOperatorCallExprClass; } - // Set the FP contractability status of this operator. Only meaningful for - // operations on floating point types. - void setFPFeatures(FPOptions F) { FPFeatures = F; } - - FPOptions getFPFeatures() const { return FPFeatures; } - // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement() const { - return FPFeatures.allowFPContractWithinStatement(); + return getFPFeatures().allowFPContractWithinStatement(); } }; @@ -173,7 +165,8 @@ public: CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef args, QualType t, ExprValueKind VK, SourceLocation RP) - : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {} + : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, FPOptions(0)) + {} CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) : CallExpr(C, CXXMemberCallExprClass, Empty) {} @@ -216,7 +209,8 @@ CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config, ArrayRef args, QualType t, ExprValueKind VK, SourceLocation RP) - : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP) {} + : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP, + FPOptions(0)) {} CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) {} @@ -501,7 +495,8 @@ UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef Args, QualType T, ExprValueKind VK, SourceLocation LitEndLoc, SourceLocation SuffixLoc) - : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc), + : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc, + FPOptions(0)), UDSuffixLoc(SuffixLoc) {} explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty) Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -6716,7 +6716,7 @@ return new (Importer.getToContext()) CallExpr(Importer.getToContext(), ToCallee, llvm::makeArrayRef(ToArgs_Copied, NumArgs), T, E->getValueKind(), - Importer.Import(E->getRParenLoc())); + Importer.Import(E->getRParenLoc()), E->getFPFeatures()); } Optional Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -1194,11 +1194,12 @@ CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef preargs, ArrayRef args, QualType t, - ExprValueKind VK, SourceLocation rparenloc) + ExprValueKind VK, SourceLocation rparenloc, + FPOptions FPFeatures) : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), - NumArgs(args.size()) { + NumArgs(args.size()), FPFeatures(FPFeatures.getInt()) { unsigned NumPreArgs = preargs.size(); SubExprs = new (C) Stmt *[args.size()+PREARGS_START+NumPreArgs]; @@ -1218,13 +1219,15 @@ CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef args, QualType t, ExprValueKind VK, - SourceLocation rparenloc) - : CallExpr(C, SC, fn, ArrayRef(), args, t, VK, rparenloc) {} + SourceLocation rparenloc, FPOptions FPFeatures) + : CallExpr(C, SC, fn, ArrayRef(), args, t, VK, rparenloc, + FPFeatures) {} CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef args, - QualType t, ExprValueKind VK, SourceLocation rparenloc) - : CallExpr(C, CallExprClass, fn, ArrayRef(), args, t, VK, rparenloc) { -} + QualType t, ExprValueKind VK, SourceLocation rparenloc, + FPOptions FPFeatures) + : CallExpr(C, CallExprClass, fn, ArrayRef(), args, t, VK, + rparenloc, FPFeatures) {} CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty) : CallExpr(C, SC, /*NumPreArgs=*/0, Empty) {} Index: lib/Analysis/BodyFarm.cpp =================================================================== --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -271,7 +271,8 @@ } return new (C) - CallExpr(C, SubExpr, CallArgs, C.VoidTy, VK_RValue, SourceLocation()); + CallExpr(C, SubExpr, CallArgs, C.VoidTy, VK_RValue, SourceLocation(), + FPOptions()); } static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, @@ -516,7 +517,8 @@ /*args=*/None, /*QualType=*/C.VoidTy, /*ExprValueType=*/VK_RValue, - /*SourceLocation=*/SourceLocation()); + /*SourceLocation=*/SourceLocation(), + /*FPOptions=*/FPOptions()); // (2) Create the assignment to the predicate. Expr *DoneValue = @@ -581,7 +583,7 @@ DeclRefExpr *DR = M.makeDeclRefExpr(PV); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, - SourceLocation()); + SourceLocation(), FPOptions()); return CE; } Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -29,6 +29,7 @@ #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Support/ConvertUTF.h" @@ -230,8 +231,74 @@ ValueType); } +static void getConstrainedMetadata(CodeGenFunction &CGF, + llvm::Value **RoundingV, + llvm::Value **ExceptV) +{ + if (RoundingV) { + auto *RoundingMD = MDString::get(CGF.getLLVMContext(), + "round.dynamic"); + *RoundingV = MetadataAsValue::get(CGF.getLLVMContext(), RoundingMD); + } + + if (ExceptV) { + auto *ExceptMD = MDString::get(CGF.getLLVMContext(), + "fpexcept.strict"); + *ExceptV = MetadataAsValue::get(CGF.getLLVMContext(), ExceptMD); + } +} + // Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. +// Include metadata needed since this is for a constrained FP intrinsic. +static Value *emitUnaryConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, + unsigned IntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Rounding; + llvm::Value *Except; + + getConstrainedMetadata(CGF, &Rounding, &Except); + + Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CGF.Builder.CreateCall(F, { Src0, Rounding, Except }); +} + +// Emit an intrinsic that has 2 operands of the same type as its result. +// Include metadata needed since this is for a constrained FP intrinsic. +static Value *emitBinaryConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, + unsigned IntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); + llvm::Value *Rounding; + llvm::Value *Except; + + getConstrainedMetadata(CGF, &Rounding, &Except); + + Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CGF.Builder.CreateCall(F, { Src0, Src1, Rounding, Except }); +} + +// Emit an intrinsic that has 3 operands of the same type as its result. +// Include metadata needed since this is for a constrained FP intrinsic. +static Value *emitTernaryConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, + unsigned IntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); + llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2)); + llvm::Value *Rounding; + llvm::Value *Except; + + getConstrainedMetadata(CGF, &Rounding, &Except); + + Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CGF.Builder.CreateCall(F, { Src0, Src1, Src2, Rounding, Except }); +} + +// Emit a simple mangled intrinsic that has 1 argument and a return type +// matching the argument type. static Value *emitUnaryBuiltin(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID) { @@ -1312,7 +1379,11 @@ case Builtin::BI__builtin_cos: case Builtin::BI__builtin_cosf: case Builtin::BI__builtin_cosl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_cos)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -1320,7 +1391,11 @@ case Builtin::BI__builtin_exp: case Builtin::BI__builtin_expf: case Builtin::BI__builtin_expl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_exp)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp)); case Builtin::BIexp2: case Builtin::BIexp2f: @@ -1328,7 +1403,11 @@ case Builtin::BI__builtin_exp2: case Builtin::BI__builtin_exp2f: case Builtin::BI__builtin_exp2l: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_exp2)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2)); case Builtin::BIfabs: case Builtin::BIfabsf: @@ -1353,7 +1432,11 @@ case Builtin::BI__builtin_fma: case Builtin::BI__builtin_fmaf: case Builtin::BI__builtin_fmal: - return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma)); + if (E->isFEnvAccessOn()) + return RValue::get(emitTernaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_fma)); + else + return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma)); case Builtin::BIfmax: case Builtin::BIfmaxf: @@ -1390,7 +1473,11 @@ case Builtin::BI__builtin_log: case Builtin::BI__builtin_logf: case Builtin::BI__builtin_logl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_log)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log)); case Builtin::BIlog10: case Builtin::BIlog10f: @@ -1398,7 +1485,11 @@ case Builtin::BI__builtin_log10: case Builtin::BI__builtin_log10f: case Builtin::BI__builtin_log10l: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_log10)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10)); case Builtin::BIlog2: case Builtin::BIlog2f: @@ -1406,7 +1497,11 @@ case Builtin::BI__builtin_log2: case Builtin::BI__builtin_log2f: case Builtin::BI__builtin_log2l: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_log2)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2)); case Builtin::BInearbyint: case Builtin::BInearbyintf: @@ -1414,7 +1509,11 @@ case Builtin::BI__builtin_nearbyint: case Builtin::BI__builtin_nearbyintf: case Builtin::BI__builtin_nearbyintl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_nearbyint)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint)); case Builtin::BIpow: case Builtin::BIpowf: @@ -1422,7 +1521,11 @@ case Builtin::BI__builtin_pow: case Builtin::BI__builtin_powf: case Builtin::BI__builtin_powl: - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow)); + if (E->isFEnvAccessOn()) + return RValue::get(emitBinaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_pow)); + else + return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow)); case Builtin::BIrint: case Builtin::BIrintf: @@ -1430,7 +1533,11 @@ case Builtin::BI__builtin_rint: case Builtin::BI__builtin_rintf: case Builtin::BI__builtin_rintl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_rint)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint)); case Builtin::BIround: case Builtin::BIroundf: @@ -1446,7 +1553,11 @@ case Builtin::BI__builtin_sin: case Builtin::BI__builtin_sinf: case Builtin::BI__builtin_sinl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_sin)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin)); case Builtin::BIsqrt: case Builtin::BIsqrtf: @@ -1454,7 +1565,11 @@ case Builtin::BI__builtin_sqrt: case Builtin::BI__builtin_sqrtf: case Builtin::BI__builtin_sqrtl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt)); + if (E->isFEnvAccessOn()) + return RValue::get(emitUnaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_sqrt)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt)); case Builtin::BItrunc: case Builtin::BItruncf: @@ -1814,13 +1929,12 @@ case Builtin::BI__builtin_powi: case Builtin::BI__builtin_powif: - case Builtin::BI__builtin_powil: { - Value *Base = EmitScalarExpr(E->getArg(0)); - Value *Exponent = EmitScalarExpr(E->getArg(1)); - llvm::Type *ArgType = Base->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::powi, ArgType); - return RValue::get(Builder.CreateCall(F, {Base, Exponent})); - } + case Builtin::BI__builtin_powil: + if (E->isFEnvAccessOn()) + return RValue::get(emitBinaryConstrainedFPBuiltin(*this, E, + Intrinsic::experimental_constrained_powi)); + else + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::powi)); case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: Index: lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -2109,7 +2109,7 @@ CallExpr *Exp = new (Context) CallExpr(*Context, ICE, Args, FT->getCallResultType(*Context), - VK_RValue, EndLoc); + VK_RValue, EndLoc, FPOptions()); return Exp; } @@ -2692,7 +2692,8 @@ const FunctionType *FT = msgSendType->getAs(); CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); + CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc, + FPOptions()); ReplaceStmt(Exp, CE); return CE; } @@ -2733,7 +2734,8 @@ InitExprs.push_back(Exp->getElement(i)); Expr *NSArrayCallExpr = new (Context) CallExpr(*Context, NSArrayDRE, InitExprs, - NSArrayFType, VK_LValue, SourceLocation()); + NSArrayFType, VK_LValue, SourceLocation(), + FPOptions()); FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), @@ -2815,7 +2817,8 @@ const FunctionType *FT = msgSendType->getAs(); CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); + CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc, + FPOptions()); ReplaceStmt(Exp, CE); return CE; } @@ -2864,7 +2867,8 @@ // (const id [])objects Expr *NSValueCallExpr = new (Context) CallExpr(*Context, NSDictDRE, ValueExprs, - NSDictFType, VK_LValue, SourceLocation()); + NSDictFType, VK_LValue, SourceLocation(), + FPOptions()); FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), @@ -2884,7 +2888,8 @@ // (const id [])keys Expr *NSKeyCallExpr = new (Context) CallExpr(*Context, NSDictDRE, KeyExprs, - NSDictFType, VK_LValue, SourceLocation()); + NSDictFType, VK_LValue, SourceLocation(), + FPOptions()); MemberExpr *DictLiteralKeyME = new (Context) MemberExpr(NSKeyCallExpr, false, SourceLocation(), ARRFD, @@ -2969,7 +2974,8 @@ const FunctionType *FT = msgSendType->getAs(); CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); + CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc, + FPOptions()); ReplaceStmt(Exp, CE); return CE; } @@ -3182,7 +3188,8 @@ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue, SourceLocation()); CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs, - castType, VK_LValue, SourceLocation()); + castType, VK_LValue, + SourceLocation(), FPOptions()); FieldDecl *FieldD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), @@ -3284,7 +3291,7 @@ SourceLocation()); SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, superType, VK_LValue, - SourceLocation()); + SourceLocation(), FPOptions()); // The code for super is a little tricky to prevent collision with // the structure definition in the header. The rewriter has it's own // internal definition (__rw_objc_super) that is uses. This is why @@ -3378,7 +3385,8 @@ false, superType, VK_LValue, SourceLocation()); SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, - superType, VK_LValue, SourceLocation()); + superType, VK_LValue, SourceLocation(), + FPOptions()); // The code for super is a little tricky to prevent collision with // the structure definition in the header. The rewriter has it's own // internal definition (__rw_objc_super) that is uses. This is why @@ -3543,7 +3551,8 @@ const FunctionType *FT = msgSendType->getAs(); CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); + CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc, + FPOptions()); Stmt *ReplacingStmt = CE; if (MsgSendStretFlavor) { // We have the method which returns a struct/union. Must also generate @@ -4657,7 +4666,7 @@ } CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, Exp->getType(), VK_RValue, - SourceLocation()); + SourceLocation(), FPOptions()); return CE; } @@ -5405,7 +5414,8 @@ InitExprs.push_back(FlagExp); } NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, - FType, VK_LValue, SourceLocation()); + FType, VK_LValue, SourceLocation(), + FPOptions()); if (GlobalBlockExpr) { assert (!GlobalConstructionExp && Index: lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- lib/Frontend/Rewrite/RewriteObjC.cpp +++ lib/Frontend/Rewrite/RewriteObjC.cpp @@ -2022,7 +2022,7 @@ CallExpr *Exp = new (Context) CallExpr(*Context, ICE, Args, FT->getCallResultType(*Context), - VK_RValue, EndLoc); + VK_RValue, EndLoc, FPOptions()); return Exp; } @@ -2609,7 +2609,8 @@ const FunctionType *FT = msgSendType->getAs(); CallExpr *STCE = new (Context) CallExpr( - *Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, SourceLocation()); + *Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, SourceLocation(), + FPOptions()); return STCE; } @@ -2702,7 +2703,7 @@ SourceLocation()); SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, superType, VK_LValue, - SourceLocation()); + SourceLocation(), FPOptions()); // The code for super is a little tricky to prevent collision with // the structure definition in the header. The rewriter has it's own // internal definition (__rw_objc_super) that is uses. This is why @@ -2796,7 +2797,8 @@ false, superType, VK_LValue, SourceLocation()); SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, - superType, VK_LValue, SourceLocation()); + superType, VK_LValue, SourceLocation(), + FPOptions()); // The code for super is a little tricky to prevent collision with // the structure definition in the header. The rewriter has it's own // internal definition (__rw_objc_super) that is uses. This is why @@ -2961,7 +2963,8 @@ const FunctionType *FT = msgSendType->getAs(); CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); + CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc, + FPOptions()); Stmt *ReplacingStmt = CE; if (MsgSendStretFlavor) { // We have the method which returns a struct/union. Must also generate @@ -3813,7 +3816,7 @@ } CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, Exp->getType(), VK_RValue, - SourceLocation()); + SourceLocation(), FPOptions()); return CE; } @@ -4528,7 +4531,8 @@ InitExprs.push_back(FlagExp); } NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, - FType, VK_LValue, SourceLocation()); + FType, VK_LValue, SourceLocation(), + FPOptions()); NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary, SourceLocation(), false); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -5320,7 +5320,8 @@ } return new (Context) - CallExpr(Context, Fn, None, Context.VoidTy, VK_RValue, RParenLoc); + CallExpr(Context, Fn, None, Context.VoidTy, VK_RValue, RParenLoc, + FPFeatures); } if (Fn->getType() == Context.PseudoObjectTy) { ExprResult result = CheckPlaceholderExpr(Fn); @@ -5348,7 +5349,8 @@ Fn->getBeginLoc()); return new (Context) CallExpr( - Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); + Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc, + FPFeatures); } } @@ -5377,7 +5379,8 @@ if (!find.HasFormOfMemberPointer) { if (Expr::hasAnyTypeDependentArguments(ArgExprs)) return new (Context) CallExpr( - Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); + Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc, + FPFeatures); OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast(ovl)) return BuildOverloadedCallExpr( @@ -5530,7 +5533,7 @@ RParenLoc); else TheCall = new (Context) CallExpr(Context, Fn, Args, Context.BoolTy, - VK_RValue, RParenLoc); + VK_RValue, RParenLoc, FPFeatures); if (!getLangOpts().CPlusPlus) { // C cannot always handle TypoExpr nodes in builtin calls and direct @@ -16424,7 +16427,7 @@ E = ImpCastExprToType(E, Context.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr).get(); return new (Context) CallExpr(Context, E, None, Context.IntTy, - VK_RValue, SourceLocation()); + VK_RValue, SourceLocation(), FPFeatures); } } Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -10781,7 +10781,8 @@ S.DefaultLvalueConversion(DeclareReductionRef.get()).get()); Expr *Args[] = {LHS.get(), RHS.get()}; ReductionOp = new (Context) - CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc); + CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc, + S.FPFeatures); } else { ReductionOp = S.BuildBinOp( Stack->getCurScope(), ReductionId.getBeginLoc(), BOK, LHSDRE, RHSDRE); Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -6963,7 +6963,7 @@ // allocator). QualType CallResultType = ConversionType.getNonLValueExprType(Context); CallExpr Call(Context, &ConversionFn, None, CallResultType, VK, - From->getBeginLoc()); + From->getBeginLoc(), FPFeatures); ImplicitConversionSequence ICS = TryCopyInitialization(*this, &Call, ToType, /*SuppressUserConversions=*/true, @@ -11945,7 +11945,8 @@ // to instantiation time to be able to search into type dependent base // classes. CallExpr *CE = new (Context) CallExpr( - Context, Fn, Args, Context.DependentTy, VK_RValue, RParenLoc); + Context, Fn, Args, Context.DependentTy, VK_RValue, RParenLoc, + FPFeatures); CE->setTypeDependent(true); CE->setValueDependent(true); CE->setInstantiationDependent(true); @@ -12827,7 +12828,8 @@ if (isa(NakedMemExpr)) return new (Context) - CallExpr(Context, MemExprE, Args, Context.VoidTy, VK_RValue, RParenLoc); + CallExpr(Context, MemExprE, Args, Context.VoidTy, VK_RValue, RParenLoc, + FPFeatures); UnbridgedCastsSet UnbridgedCasts; if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -3134,7 +3134,8 @@ // Build the CallExpr ExprResult TheCall = new (SemaRef.Context) CallExpr( SemaRef.Context, Callee, SubExprs, Builtin->getCallResultType(), - Expr::getValueKindForType(Builtin->getReturnType()), RParenLoc); + Expr::getValueKindForType(Builtin->getReturnType()), RParenLoc, + SemaRef.FPFeatures); // Type-check the __builtin_shufflevector expression. return SemaRef.SemaBuiltinShuffleVector(cast(TheCall.get())); Index: test/CodeGen/fenv-access-pragma.c =================================================================== --- test/CodeGen/fenv-access-pragma.c +++ test/CodeGen/fenv-access-pragma.c @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s + +// Is FENV_ACCESS honored in a simple case? +float fenv_access_1(float a) { +// CHECK: _Z13fenv_access_1f +// CHECK: call double @llvm.experimental.constrained.cos.f64 +#pragma STDC FENV_ACCESS ON + return __builtin_cos(a); +} + +// Is FENV_ACCESS state cleared on exiting compound statements? +float fenv_access_2(float a) { + // CHECK: _Z13fenv_access_2f + // CHECK: call double @llvm.cos.f64 + { +#pragma STDC FENV_ACCESS ON + } + return __builtin_cos(a); +} + +// Does FENV_ACCESS survive template instantiation? +template +T template_bcos(T a) { +#pragma STDC FENV_ACCESS ON + return __builtin_cos(a); +} + +float fenv_access_3(float a) { + // CHECK: _Z13fenv_access_3f + // FIXME: This should be call double @llvm.experimental.constrained.cos.f64 + // FIXME: Templates are known incomplete with FP_CONTRACT and FENV_ACCESS. + // CHECK: call double @llvm.cos.f64 + return template_bcos(a); +} + +template +class fenv_access_4 { + float method(float a) { +#pragma STDC FENV_ACCESS ON + return __builtin_cos(a); + } +}; + +template class fenv_access_4; +// CHECK: _ZN13fenv_access_4IiE6methodEf +// FIXME: This should be call double @llvm.experimental.constrained.cos.f64 +// CHECK: call double @llvm.cos.f64 + +// Check file-scoped FENV_ACCESS +#pragma STDC FENV_ACCESS ON +float fenv_access_5(float a) { + // CHECK: _Z13fenv_access_5f + // CHECK: call double @llvm.experimental.constrained.cos.f64 + return __builtin_cos(a); +} + +#pragma STDC FENV_ACCESS OFF +float fenv_access_6(float a) { + // CHECK: _Z13fenv_access_6f + // CHECK: call double @llvm.cos.f64 + return __builtin_cos(a); +} + Index: test/CodeGen/fenv-math-builtins.c =================================================================== --- test/CodeGen/fenv-math-builtins.c +++ test/CodeGen/fenv-math-builtins.c @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm %s | FileCheck %s + +// Test codegen of math builtins when using FENV_ACCESS ON. +// Derived from math-builtins.c and keeps calls in the same order. +#pragma STDC FENV_ACCESS ON + +void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) { + __builtin_pow(f,f); __builtin_powf(f,f); __builtin_powl(f,f); + +// CHECK: declare double @llvm.experimental.constrained.pow.f64(double, double, metadata, metadata) [[MATH_INTRINSIC:#[0-9]+]] +// CHECK: declare float @llvm.experimental.constrained.pow.f32(float, float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.pow.f80(x86_fp80, x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_powi(f,f); __builtin_powif(f,f); __builtin_powil(f,f); + +// CHECK: declare double @llvm.experimental.constrained.powi.f64(double, i32, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.powi.f32(float, i32, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.powi.f80(x86_fp80, i32, metadata, metadata) [[MATH_INTRINSIC]] + + /* math */ + __builtin_cos(f); __builtin_cosf(f); __builtin_cosl(f); +// CHECK: declare double @llvm.experimental.constrained.cos.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.cos.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.cos.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_exp(f); __builtin_expf(f); __builtin_expl(f); +// CHECK: declare double @llvm.experimental.constrained.exp.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.exp.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.exp.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_exp2(f); __builtin_exp2f(f); __builtin_exp2l(f); + +// CHECK: declare double @llvm.experimental.constrained.exp2.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.exp2.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.exp2.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_fma(f,f,f); __builtin_fmaf(f,f,f); __builtin_fmal(f,f,f); + +// CHECK: declare double @llvm.experimental.constrained.fma.f64(double, double, double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.fma.f80(x86_fp80, x86_fp80, x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_log(f); __builtin_logf(f); __builtin_logl(f); + +// CHECK: declare double @llvm.experimental.constrained.log.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.log.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.log.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_log10(f); __builtin_log10f(f); __builtin_log10l(f); + +// CHECK: declare double @llvm.experimental.constrained.log10.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.log10.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.log10.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_nearbyint(f); __builtin_nearbyintf(f); __builtin_nearbyintl(f); + +// CHECK: declare double @llvm.experimental.constrained.nearbyint.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.nearbyint.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.nearbyint.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_nextafter(f,f); __builtin_nextafterf(f,f); __builtin_nextafterl(f,f); + + __builtin_rint(f); __builtin_rintf(f); __builtin_rintl(f); + +// CHECK: declare double @llvm.experimental.constrained.rint.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.rint.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.rint.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_sin(f); __builtin_sinf(f); __builtin_sinl(f); + +// CHECK: declare double @llvm.experimental.constrained.sin.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.sin.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.sin.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + + __builtin_sqrt(f); __builtin_sqrtf(f); __builtin_sqrtl(f); + +// CHECK: declare double @llvm.experimental.constrained.sqrt.f64(double, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) [[MATH_INTRINSIC]] +// CHECK: declare x86_fp80 @llvm.experimental.constrained.sqrt.f80(x86_fp80, metadata, metadata) [[MATH_INTRINSIC]] + +} + +// CHECK: attributes [[MATH_INTRINSIC]] = { {{.*}}inaccessiblememonly nounwind{{.*}} } + Index: test/Parser/pragma-fenv-access.c =================================================================== --- test/Parser/pragma-fenv-access.c +++ test/Parser/pragma-fenv-access.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void f1(void) { + int x = 0; +/* expected-error@+1 {{'#pragma fenv_access' can only appear at file scope or at the start of a compound statement}} */ +#pragma STDC FENV_ACCESS ON +} + +void f2(void) { + #pragma STDC FENV_ACCESS OFF + #pragma STDC FENV_ACCESS ON +}