kpn updated this revision to Diff 165995.
kpn added a comment.

Rebase.

Correct obvious error with powi. Fix test and test both C and (partial) C++.

Ping.


https://reviews.llvm.org/D51372

Files:
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  lib/AST/ASTImporter.cpp
  lib/AST/Expr.cpp
  lib/Analysis/BodyFarm.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Frontend/Rewrite/RewriteModernObjC.cpp
  lib/Frontend/Rewrite/RewriteObjC.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOpenMP.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  test/CodeGen/fenv-access-pragma.c
  test/CodeGen/fenv-access-pragma.cpp
  test/CodeGen/fenv-math-builtins.c

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/CodeGen/fenv-access-pragma.cpp
===================================================================
--- test/CodeGen/fenv-access-pragma.cpp
+++ test/CodeGen/fenv-access-pragma.cpp
@@ -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 <typename T>
+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<float>(a);
+}
+
+template <typename T>
+class fenv_access_4 {
+  float method(float a) {
+#pragma STDC FENV_ACCESS ON
+    return __builtin_cos(a);
+  }
+};
+
+template class fenv_access_4<int>;
+// 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-access-pragma.c
===================================================================
--- test/CodeGen/fenv-access-pragma.c
+++ test/CodeGen/fenv-access-pragma.c
@@ -0,0 +1,35 @@
+// 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: fenv_access_1
+// 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: fenv_access_2
+  // CHECK: call double @llvm.cos.f64
+  {
+#pragma STDC FENV_ACCESS ON
+  }
+  return __builtin_cos(a);
+}
+
+// Check file-scoped FENV_ACCESS
+#pragma STDC FENV_ACCESS ON
+float fenv_access_3(float a) {
+  // CHECK: fenv_access_3
+  // CHECK: call double @llvm.experimental.constrained.cos.f64
+  return __builtin_cos(a);
+}
+
+#pragma STDC FENV_ACCESS OFF
+float fenv_access_4(float a) {
+  // CHECK: fenv_access_4
+  // CHECK: call double @llvm.cos.f64
+  return __builtin_cos(a);
+}
+
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<CallExpr>(TheCall.get()));
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -6964,7 +6964,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,
@@ -11946,7 +11946,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);
@@ -12828,7 +12829,8 @@
 
   if (isa<CXXPseudoDestructorExpr>(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/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -10886,7 +10886,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/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -5321,7 +5321,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);
@@ -5343,7 +5344,8 @@
             Fn->getBeginLoc());
 
         return new (Context) CallExpr(
-            Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc);
+            Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc,
+            FPFeatures);
       }
     }
 
@@ -5372,7 +5374,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<UnresolvedLookupExpr>(ovl))
         return BuildOverloadedCallExpr(
@@ -5525,7 +5528,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
@@ -16429,7 +16432,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/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<FunctionType>();
   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<FunctionType>();
   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/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<FunctionType>();
   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<FunctionType>();
   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 <NSCopying> [])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<FunctionType>();
   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<FunctionType>();
   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/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,23 +1379,35 @@
     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:
     case Builtin::BIexpl:
     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:
     case Builtin::BIexp2l:
     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,47 +1473,71 @@
     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:
     case Builtin::BIlog10l:
     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:
     case Builtin::BIlog2l:
     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:
     case Builtin::BInearbyintl:
     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:
     case Builtin::BIpowl:
     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:
     case Builtin::BIrintl:
     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,15 +1553,23 @@
     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:
     case Builtin::BIsqrtl:
     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(emitBinaryBuiltin(*this, E, Intrinsic::powi));
 
   case Builtin::BI__builtin_isgreater:
   case Builtin::BI__builtin_isgreaterequal:
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/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<Expr *> preargs, ArrayRef<Expr *> 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<Expr *> args, QualType t, ExprValueKind VK,
-                   SourceLocation rparenloc)
-    : CallExpr(C, SC, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc) {}
+                   SourceLocation rparenloc, FPOptions FPFeatures)
+    : CallExpr(C, SC, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc, 
+               FPFeatures) {}
 
 CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args,
-                   QualType t, ExprValueKind VK, SourceLocation rparenloc)
-    : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc) {
-}
+                   QualType t, ExprValueKind VK, SourceLocation rparenloc,
+                   FPOptions FPFeatures)
+    : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, 
+               rparenloc, FPFeatures) {}
 
 CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
     : CallExpr(C, SC, /*NumPreArgs=*/0, Empty) {}
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -6730,7 +6730,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<LambdaCapture>
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<Expr*> 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();
   }
 
@@ -140,16 +138,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();
   }
 };
 
@@ -165,7 +157,8 @@
 public:
   CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> 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) {}
@@ -208,7 +201,8 @@
   CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
                      ArrayRef<Expr*> 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) {}
@@ -485,7 +479,8 @@
   UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> 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: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -2288,15 +2288,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<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
-           ExprValueKind VK, SourceLocation rparenloc);
+           ExprValueKind VK, SourceLocation rparenloc, FPOptions FPFeatures);
   CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> 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);
 
@@ -2317,7 +2322,7 @@
 
 public:
   CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> 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);
@@ -2449,6 +2454,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.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D51372: FENV_ACCESS ... Kevin P. Neal via Phabricator via cfe-commits

Reply via email to