sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall, andrew.w.kaylor, efriedma, 
mibintc, kpn, sammccall, hokein.
Herald added a subscriber: martong.
Herald added a project: clang.

The patch D76599 <https://reviews.llvm.org/D76599> proposed a new statement 
node to represent pragmas that
modifies floating point environment. These nodes are used to implement
FP environment tracking and control in a function. Such node modify FP
environment in enclosing compound statement thus organizing FP
environment in hierarchical manner.

That solution however cannot be applied to initializers of global
variables and some other objects. They represent expressions outside
function bodies and thus cannot be embedded into compound statements.

Expression node introduced here (FPEnvironmentExpr) is to represent
FP environment in such cases. It contains a field of type FPOptions,
which specifies FP environment in which subexpression of
FPEnvironmentExpr should be executed. The patch implements FP
environment in the following cases:

- Initializers of global variables, like:

  float v1 = 3,1415926535;

- Inline initializers of fields:

  struct C1 { float f1 = 1,4142135623; };

- Arguments of base constructors in constructors:

  struct C3 : public C2 { C3(double x, double y) : C2(x + y) {} };

- Default function arguments:

  void func_01(float x = 1.1);

In contrast to the solution for compound statements in D76599 
<https://reviews.llvm.org/D76599>, this
solution does not keep reference to the source code construct that set
the FP environment, namely the file scope pragma. It may cause problems
for AST consumers like source analyzers.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77545

Files:
  clang/include/clang/AST/EvaluatedExprVisitor.h
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/Basic/LangOptions.h
  clang/include/clang/Basic/StmtNodes.td
  clang/include/clang/Sema/Sema.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/lib/AST/Expr.cpp
  clang/lib/AST/ExprClassification.cpp
  clang/lib/AST/ExprConstant.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/AST/StmtProfile.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Basic/LangOptions.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGExprConstant.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/CodeGen/CGOpenCLRuntime.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/ConstantEmitter.h
  clang/lib/Sema/SemaCUDA.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/test/AST/ast-dump-pragma.cpp
  clang/test/CodeGen/fp-contract-pragma.cpp
  clang/tools/libclang/CXCursor.cpp

Index: clang/tools/libclang/CXCursor.cpp
===================================================================
--- clang/tools/libclang/CXCursor.cpp
+++ clang/tools/libclang/CXCursor.cpp
@@ -336,6 +336,7 @@
   case Stmt::ObjCBoxedExprClass:
   case Stmt::ObjCSubscriptRefExprClass:
   case Stmt::RecoveryExprClass:
+  case Stmt::FPEnvironmentExprClass:
     K = CXCursor_UnexposedExpr;
     break;
 
Index: clang/test/CodeGen/fp-contract-pragma.cpp
===================================================================
--- clang/test/CodeGen/fp-contract-pragma.cpp
+++ clang/test/CodeGen/fp-contract-pragma.cpp
@@ -89,3 +89,15 @@
   #pragma STDC FP_CONTRACT ON
   return c - a * b;
 }
+
+
+#pragma STDC FP_CONTRACT ON
+struct C1 {
+  C1(float);
+};
+struct C2 : public C1 {
+  C2(float a, float b, float c);
+};
+C2::C2(float a, float b, float c) : C1(a*b+c) {}
+// CHECK: _ZN2C2C2Efff
+// CHECK: call float @llvm.fmuladd.f32
Index: clang/test/AST/ast-dump-pragma.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/ast-dump-pragma.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck --check-prefixes=CHECK,NOOPT %s
+
+#pragma STDC FP_CONTRACT ON
+
+float var_01 = 1.1;
+
+// CHECK: VarDecl {{.*}} var_01
+// CHECK-NEXT: FPEnvironmentExpr {{.*}} contract(on)
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: FloatingLiteral
+
+struct C1 {
+  float f1 = 1.1;
+};
+
+// CHECK: CXXRecordDecl {{.*}} struct C1
+// CHECK: FieldDecl {{.*}} f1
+// CHECK-NEXT: FPEnvironmentExpr {{.*}} contract(on)
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: FloatingLiteral
+
+struct C2 {
+  C2(float);
+};
+
+struct C3 : public C2 {
+  C3(double x) : C2(x) {}
+};
+
+// CHECK: CXXRecordDecl {{.*}} struct C3
+// CHECK: CXXConstructorDecl {{.*}} C3 'void (double)'
+// CHECK: CXXCtorInitializer 'C2'
+// CHECK-NEXT: FPEnvironmentExpr {{.*}} contract(on)
+// CHECK-NEXT: CXXConstructExpr {{.*}} 'C2' 'void (float)'
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT: DeclRefExpr {{.*}} 'x'
+
+void func_01(float x = 1.1);
+
+// CHECK: FunctionDecl {{.*}} func_01
+// CHECK-NEXT: ParmVarDecl
+// CHECK: FPEnvironmentExpr {{.*}} contract(on)
+// CHECK: ImplicitCastExpr
+// CHECK: FloatingLiteral
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1389,6 +1389,7 @@
     case Stmt::ConceptSpecializationExprClass:
     case Stmt::CXXRewrittenBinaryOperatorClass:
     case Stmt::RequiresExprClass:
+    case Stmt::FPEnvironmentExprClass:
       // Fall through.
 
     // Cases we intentionally don't evaluate, since they don't need
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1209,6 +1209,13 @@
   Code = serialization::EXPR_ATOMIC;
 }
 
+void ASTStmtWriter::VisitFPEnvironmentExpr(FPEnvironmentExpr *E) {
+  VisitExpr(E);
+  Record.push_back(E->getFPOptions().getInt());
+  Record.AddStmt(E->getSubExpr());
+  Code = serialization::EXPR_FP_ENVIRONMENT;
+}
+
 //===----------------------------------------------------------------------===//
 // Objective-C Expressions and Statements.
 //===----------------------------------------------------------------------===//
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1335,6 +1335,13 @@
   E->RParenLoc = readSourceLocation();
 }
 
+void ASTStmtReader::VisitFPEnvironmentExpr(FPEnvironmentExpr *E) {
+  VisitExpr(E);
+  E->getFPOptions() = FPOptions(Record.readInt());
+  Expr *SubExpr = Record.readSubExpr();
+  E->SubExpr = SubExpr;
+}
+
 //===----------------------------------------------------------------------===//
 // Objective-C Expressions and Statements
 
@@ -3035,6 +3042,10 @@
           /*NumAssocs=*/Record[ASTStmtReader::NumExprFields]);
       break;
 
+    case EXPR_FP_ENVIRONMENT:
+      S = new (Context) FPEnvironmentExpr(Empty);
+      break;
+
     case EXPR_OBJC_STRING_LITERAL:
       S = new (Context) ObjCStringLiteral(Empty);
       break;
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -3533,6 +3533,10 @@
     return getSema().CreateRecoveryExpr(BeginLoc, EndLoc, SubExprs);
   }
 
+  ExprResult RebuildFPEnvironmentExpr(Expr *SubExpr, const FPOptions &FPO) {
+    return getSema().BuildFPEnvironmentExpr(SubExpr, FPO);
+  }
+
 private:
   TypeLoc TransformTypeInObjectScope(TypeLoc TL,
                                      QualType ObjectType,
@@ -9922,6 +9926,15 @@
                                           Children);
 }
 
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformFPEnvironmentExpr(
+                                                         FPEnvironmentExpr *E) {
+  ExprResult Result = getDerived().TransformExpr(E->getSubExpr());
+  if (Result.isInvalid())
+    return ExprError();
+  return getDerived().RebuildFPEnvironmentExpr(Result.get(), E->getFPOptions());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -8531,10 +8531,14 @@
           // Do not diagnose if the file-scope variable does not have initializer
           // since this has already been diagnosed when parsing the variable
           // declaration.
-          if (!Var->getInit() || !isa<ImplicitCastExpr>(Var->getInit()))
+          const Expr *VarInit = Var->getInit();
+          if (VarInit)
+            if (auto FPE = dyn_cast<FPEnvironmentExpr>(VarInit))
+              VarInit = FPE->getSubExpr();
+          if (!VarInit || !isa<ImplicitCastExpr>(VarInit))
             break;
-          Init = cast<ImplicitCastExpr>(const_cast<Expr*>(
-            Var->getInit()))->getSubExpr();
+          Init =
+              cast<ImplicitCastExpr>(const_cast<Expr *>(VarInit))->getSubExpr();
           SourceType = Init->getType();
         }
       } else {
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -18733,3 +18733,7 @@
 
   return RecoveryExpr::Create(Context, Begin, End, SubExprs);
 }
+
+ExprResult Sema::BuildFPEnvironmentExpr(Expr *E, const FPOptions &FPO) {
+  return new (Context) FPEnvironmentExpr(E, FPO);
+}
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1285,6 +1285,7 @@
   case Expr::StmtExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::VAArgExprClass:
+  case Expr::FPEnvironmentExprClass:
     return canSubStmtsThrow(*this, S);
 
   case Expr::CompoundLiteralExprClass:
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -274,6 +274,11 @@
   CheckCompletedExpr(Arg, EqualLoc);
   Arg = MaybeCreateExprWithCleanups(Arg);
 
+  // If the current set of floating point options is not default, wrap the
+  // default argument in a special node that keeps the options.
+  if (!FPFeatures.isDefault())
+    Arg = BuildFPEnvironmentExpr(Arg, FPFeatures).get();
+
   // Okay: add the default argument to the parameter
   Param->setDefaultArg(Arg);
 
@@ -3932,6 +3937,11 @@
     }
   }
 
+  // If the current set of floating point options is not default, wrap the
+  // initializer in a special node that keeps the options.
+  if (Init.isUsable() && !FPFeatures.isDefault())
+    Init = BuildFPEnvironmentExpr(Init.get(), FPFeatures);
+
   // C++11 [class.base.init]p7:
   //   The initialization of each base and member constitutes a
   //   full-expression.
@@ -4489,6 +4499,11 @@
   if (BaseInit.isInvalid())
     return true;
 
+  // If the current set of floating point options is not default, wrap the
+  // initializer in a special node that keeps the options.
+  if (BaseInit.isUsable() && !FPFeatures.isDefault())
+    BaseInit = BuildFPEnvironmentExpr(BaseInit.get(), FPFeatures);
+
   // If we are in a dependent context, template instantiation will
   // perform this type-checking again. Just save the arguments that we
   // received in a ParenListExpr.
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -12062,6 +12062,14 @@
   }
   Init = Result.get();
 
+  // If the current set of floating point options is not default, wrap the
+  // initializer in a special node that keeps the options.
+  if (VDecl->isFileVarDecl() && !FPFeatures.isDefault()) {
+    ExprResult NewInit = BuildFPEnvironmentExpr(Init, FPFeatures);
+    assert(NewInit.isUsable());
+    Init = NewInit.get();
+  }
+
   // Attach the initializer to the decl.
   VDecl->setInit(Init);
 
Index: clang/lib/Sema/SemaCUDA.cpp
===================================================================
--- clang/lib/Sema/SemaCUDA.cpp
+++ clang/lib/Sema/SemaCUDA.cpp
@@ -429,8 +429,10 @@
   // The only form of initializer allowed is an empty constructor.
   // This will recursively check all base classes and member initializers
   if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) {
-        if (const CXXConstructExpr *CE =
-                dyn_cast<CXXConstructExpr>(CI->getInit()))
+        const Expr *Init = CI->getInit();
+        if (auto FPE = dyn_cast<FPEnvironmentExpr>(Init))
+          Init = FPE->getSubExpr();
+        if (auto CE = dyn_cast<CXXConstructExpr>(Init))
           return isEmptyCudaConstructor(Loc, CE->getConstructor());
         return false;
       }))
@@ -491,6 +493,8 @@
   if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage())
     return;
   const Expr *Init = VD->getInit();
+  if (auto FPE = dyn_cast<FPEnvironmentExpr>(Init))
+    Init = FPE->getSubExpr();
   if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() ||
       VD->hasAttr<CUDASharedAttr>()) {
     if (LangOpts.GPUAllowDeviceInit)
@@ -505,7 +509,7 @@
     // but allows us to handle things like constexpr constructors.
     if (!AllowedInit &&
         (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>()))
-      AllowedInit = VD->getInit()->isConstantInitializer(
+      AllowedInit = Init->isConstantInitializer(
           Context, VD->getType()->isReferenceType());
 
     // Also make sure that destructor, if there is one, is empty.
Index: clang/lib/CodeGen/ConstantEmitter.h
===================================================================
--- clang/lib/CodeGen/ConstantEmitter.h
+++ clang/lib/CodeGen/ConstantEmitter.h
@@ -24,6 +24,7 @@
 public:
   CodeGenModule &CGM;
   CodeGenFunction *const CGF;
+  FPOptions FPFeatures;
 
 private:
   bool Abstract = false;
@@ -49,13 +50,16 @@
 
 public:
   ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr)
-    : CGM(CGM), CGF(CGF) {}
+    : CGM(CGM), CGF(CGF) {
+    if (CGF)
+      FPFeatures = CGF->FPFeatures;
+  }
 
   /// Initialize this emission in the context of the given function.
   /// Use this if the expression might contain contextual references like
   /// block addresses or PredefinedExprs.
   ConstantEmitter(CodeGenFunction &CGF)
-    : CGM(CGF.CGM), CGF(&CGF) {}
+    : CGM(CGF.CGM), CGF(&CGF), FPFeatures(CGF.FPFeatures) {}
 
   ConstantEmitter(const ConstantEmitter &other) = delete;
   ConstantEmitter &operator=(const ConstantEmitter &other) = delete;
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -366,6 +366,7 @@
 
   CodeGenModule &CGM;  // Per-module state.
   const TargetInfo &Target;
+  FPOptions FPFeatures;
 
   typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
   LoopInfoStack LoopStack;
Index: clang/lib/CodeGen/CGOpenCLRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenCLRuntime.cpp
+++ clang/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -134,6 +134,8 @@
     E = E->IgnoreCasts();
     if (auto DR = dyn_cast<DeclRefExpr>(E)) {
       E = cast<VarDecl>(DR->getDecl())->getInit();
+      if (auto FPE = dyn_cast<FPEnvironmentExpr>(E))
+        E = FPE->getSubExpr();
     }
   }
   return cast<BlockExpr>(E);
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -852,6 +852,7 @@
   }
   Value *VisitAsTypeExpr(AsTypeExpr *CE);
   Value *VisitAtomicExpr(AtomicExpr *AE);
+  Value *VisitFPEnvironmentExpr(FPEnvironmentExpr *E);
 };
 }  // end anonymous namespace.
 
@@ -4456,6 +4457,12 @@
   return CGF.EmitBlockLiteral(block);
 }
 
+Value *ScalarExprEmitter::VisitFPEnvironmentExpr(FPEnvironmentExpr *E) {
+  FPOptions SavedFPFeatures = CGF.FPFeatures;
+  return Visit(E->getSubExpr());
+  CGF.FPFeatures = SavedFPFeatures;
+}
+
 // Convert a vec3 to vec4, or vice versa.
 static Value *ConvertVec3AndVec4(CGBuilderTy &Builder, CodeGenFunction &CGF,
                                  Value *Src, unsigned NumElementsDst) {
Index: clang/lib/CodeGen/CGExprConstant.cpp
===================================================================
--- clang/lib/CodeGen/CGExprConstant.cpp
+++ clang/lib/CodeGen/CGExprConstant.cpp
@@ -1308,6 +1308,14 @@
     return Visit(E->getSubExpr(), T);
   }
 
+  llvm::Constant *VisitFPEnvironmentExpr(FPEnvironmentExpr *E, QualType T) {
+    FPOptions SavedFPFeatures = Emitter.FPFeatures;
+    Emitter.FPFeatures = E->getFPOptions();
+    llvm::Constant *Result = Visit(E->getSubExpr(), T);
+    Emitter.FPFeatures = SavedFPFeatures;
+    return Result;
+  }
+
   // Utility methods
   llvm::Type *ConvertType(QualType T) {
     return CGM.getTypes().ConvertType(T);
Index: clang/lib/CodeGen/CGExprAgg.cpp
===================================================================
--- clang/lib/CodeGen/CGExprAgg.cpp
+++ clang/lib/CodeGen/CGExprAgg.cpp
@@ -207,6 +207,11 @@
     RValue Res = CGF.EmitAtomicExpr(E);
     EmitFinalDestCopy(E->getType(), Res);
   }
+  void VisitFPEnvironmentExpr(FPEnvironmentExpr* E) {
+    FPOptions SavedFPFeatures = CGF.FPFeatures;
+    return Visit(E->getSubExpr());
+    CGF.FPFeatures = SavedFPFeatures;
+  }
 };
 }  // end anonymous namespace.
 
Index: clang/lib/Basic/LangOptions.cpp
===================================================================
--- clang/lib/Basic/LangOptions.cpp
+++ clang/lib/Basic/LangOptions.cpp
@@ -47,3 +47,15 @@
   const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion;
   return VersionTuple(Ver / 100, (Ver % 100) / 10);
 }
+
+StringRef clang::spell(LangOptions::FPContractModeKind X, bool ShortForm) {
+  switch (X) {
+  case LangOptions::FPC_Off:
+    return ShortForm ? "OFF" : "contract(off)";
+  case LangOptions::FPC_On:
+    return ShortForm ? "ON" : "contract(on)";
+  case LangOptions::FPC_Fast:
+    return ShortForm ? "FAST" : "contract(fast)";
+  }
+  llvm_unreachable("Unexpected value");
+}
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -468,6 +468,10 @@
     llvm_unreachable("unexpected cleanup type");
 }
 
+void TextNodeDumper::dumpFPOptions(const FPOptions& FPO) {
+  OS << spell(FPO.getContract(), false);
+}
+
 void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) {
   if (!D)
     return;
@@ -1103,6 +1107,11 @@
   }
 }
 
+void TextNodeDumper::VisitFPEnvironmentExpr(const FPEnvironmentExpr *Node) {
+  OS << " ";
+  dumpFPOptions(Node->getFPOptions());
+}
+
 void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) {
   if (T->isSpelledAsLValue())
     OS << " written as lvalue reference";
Index: clang/lib/AST/StmtProfile.cpp
===================================================================
--- clang/lib/AST/StmtProfile.cpp
+++ clang/lib/AST/StmtProfile.cpp
@@ -2036,6 +2036,10 @@
 
 void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) { VisitExpr(E); }
 
+void StmtProfiler::VisitFPEnvironmentExpr(const FPEnvironmentExpr *E) {
+  VisitExpr(E);
+}
+
 void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
   VisitExpr(S);
 }
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -2556,6 +2556,10 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitFPEnvironmentExpr(FPEnvironmentExpr *Node) {
+  PrintExpr(Node->getSubExpr());
+}
+
 //===----------------------------------------------------------------------===//
 // Stmt method implementations
 //===----------------------------------------------------------------------===//
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -4476,6 +4476,10 @@
     Out << "v18co_yield";
     mangleExpression(cast<CoawaitExpr>(E)->getOperand());
     break;
+
+  case Expr::FPEnvironmentExprClass:
+    mangleExpression(cast<FPEnvironmentExpr>(E)->getSubExpr());
+    break;
   }
 }
 
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -748,6 +748,9 @@
   public:
     ASTContext &Ctx;
 
+    /// Keeps floating point options used in evaluation.
+    FPOptions FPFeatures;
+
     /// EvalStatus - Contains information about the evaluation.
     Expr::EvalStatus &EvalStatus;
 
@@ -1335,6 +1338,18 @@
   };
   typedef ScopeRAII<false> BlockScopeRAII;
   typedef ScopeRAII<true> FullExpressionRAII;
+
+  class FPOptionsStateRAII {
+    EvalInfo &Info;
+    FPOptions SavedState;
+
+  public:
+    explicit FPOptionsStateRAII(EvalInfo &Info)
+        : Info(Info), SavedState(Info.FPFeatures) {
+    }
+
+    ~FPOptionsStateRAII() { Info.FPFeatures = SavedState; }
+  };
 }
 
 bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
@@ -7298,6 +7313,12 @@
     llvm_unreachable("Return from function from the loop above.");
   }
 
+  bool VisitFPEnvironmentExpr(const FPEnvironmentExpr *E) {
+    FPOptionsStateRAII SavedFPFeatures(Info);
+    Info.FPFeatures = E->getFPOptions();
+    return StmtVisitorTy::Visit(E->getSubExpr());
+  }
+
   /// Visit a value which is evaluated, but whose value is ignored.
   void VisitIgnoredValue(const Expr *E) {
     EvaluateIgnoredValue(Info, E);
@@ -14531,6 +14552,8 @@
       return ICEDiag(IK_NotICE, E->getBeginLoc());
     return CheckICE(cast<CastExpr>(E)->getSubExpr(), Ctx);
   }
+  case Expr::FPEnvironmentExprClass:
+    return CheckICE(cast<FPEnvironmentExpr>(E)->getSubExpr(), Ctx);
   }
 
   llvm_unreachable("Invalid StmtClass!");
Index: clang/lib/AST/ExprClassification.cpp
===================================================================
--- clang/lib/AST/ExprClassification.cpp
+++ clang/lib/AST/ExprClassification.cpp
@@ -430,6 +430,9 @@
   case Expr::CoawaitExprClass:
   case Expr::CoyieldExprClass:
     return ClassifyInternal(Ctx, cast<CoroutineSuspendExpr>(E)->getResumeExpr());
+
+  case Expr::FPEnvironmentExprClass:
+    return ClassifyInternal(Ctx, cast<FPEnvironmentExpr>(E)->getSubExpr());
   }
 
   llvm_unreachable("unhandled expression kind in classification");
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -3228,6 +3228,9 @@
   case CXXDefaultInitExprClass:
     return cast<CXXDefaultInitExpr>(this)->getExpr()
       ->isConstantInitializer(Ctx, false, Culprit);
+  case FPEnvironmentExprClass:
+    return cast<FPEnvironmentExpr>(this)->getSubExpr()
+      ->isConstantInitializer(Ctx, IsForRef, Culprit);
   }
   // Allow certain forms of UB in constant initializers: signed integer
   // overflow and floating-point division by zero. We'll give a warning on
@@ -3417,6 +3420,7 @@
   case ShuffleVectorExprClass:
   case ConvertVectorExprClass:
   case AsTypeExprClass:
+  case FPEnvironmentExprClass:
     // These have a side-effect if any subexpression does.
     break;
 
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1643,6 +1643,9 @@
       /// A RecoveryExpr record.
       EXPR_RECOVERY,
 
+      /// An FPEnvironmentExpr,
+      EXPR_FP_ENVIRONMENT,
+
       // Objective-C
 
       /// An ObjCStringLiteral record.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6013,6 +6013,8 @@
                                        SourceLocation TildeLoc,
                                        const DeclSpec& DS);
 
+  ExprResult BuildFPEnvironmentExpr(Expr *S, const FPOptions &FPO);
+
   /// MaybeCreateExprWithCleanups - If the current full-expression
   /// requires any cleanups, surround it with a ExprWithCleanups node.
   /// Otherwise, just returns the passed-in expression.
Index: clang/include/clang/Basic/StmtNodes.td
===================================================================
--- clang/include/clang/Basic/StmtNodes.td
+++ clang/include/clang/Basic/StmtNodes.td
@@ -97,6 +97,7 @@
 def GenericSelectionExpr : StmtNode<Expr>;
 def PseudoObjectExpr : StmtNode<Expr>;
 def SourceLocExpr : StmtNode<Expr>;
+def FPEnvironmentExpr : StmtNode<Expr>;
 
 // Wrapper expressions
 def FullExpr : StmtNode<Expr, 1>;
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -384,6 +384,12 @@
   }
 };
 
+/// Returns text representation for the given contract mode value.
+/// If \a ShortMode is true, only corresponding switch value ("ON", "OFF" or
+/// "FAST") is returned, otherwise the output string looks like "contract(on)".
+///
+StringRef spell(LangOptions::FPContractModeKind X, bool ShortForm);
+
 /// Floating point control options
 class FPOptions {
 public:
@@ -427,6 +433,12 @@
 
   void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; }
 
+  LangOptions::FPContractModeKind getContract() const {
+    return static_cast<LangOptions::FPContractModeKind>(fp_contract);
+  }
+
+  void setContract(LangOptions::FPContractModeKind X) { fp_contract = X; }
+
   bool allowFEnvAccess() const {
     return fenv_access == LangOptions::FEA_On;
   }
@@ -459,12 +471,23 @@
            allowFEnvAccess();
   }
 
+  bool isDefault() const { return *this == FPOptions(); }
+
   /// Used to serialize this.
   unsigned getInt() const {
     return fp_contract | (fenv_access << 2) | (rounding << 3)
         | (exceptions << 6);
   }
 
+  bool operator == (const FPOptions &O) const {
+    return fp_contract == O.fp_contract &&
+           fenv_access == O.fenv_access &&
+           rounding == O.rounding &&
+           exceptions == O.exceptions;
+  }
+
+  bool operator != (const FPOptions &O) const { return !operator==(O); }
+
 private:
   /// Adjust BinaryOperatorBitfields::FPFeatures and
   /// CXXOperatorCallExprBitfields::FPFeatures to match the total bit-field size
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -185,6 +185,7 @@
   void dumpName(const NamedDecl *ND);
   void dumpAccessSpecifier(AccessSpecifier AS);
   void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C);
+  void dumpFPOptions(const FPOptions &FPO);
 
   void dumpDeclRef(const Decl *D, StringRef Label = {});
 
@@ -275,6 +276,7 @@
   void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node);
   void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node);
   void VisitOMPIteratorExpr(const OMPIteratorExpr *Node);
+  void VisitFPEnvironmentExpr(const FPEnvironmentExpr *Node);
 
   void VisitRValueReferenceType(const ReferenceType *T);
   void VisitArrayType(const ArrayType *T);
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2688,6 +2688,7 @@
 DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
 DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
+DEF_TRAVERSE_STMT(FPEnvironmentExpr, {})
 
 DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {
   if (S->getLifetimeExtendedTemporaryDecl()) {
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -6039,6 +6039,50 @@
   friend class ASTStmtWriter;
 };
 
+class FPEnvironmentExpr : public Expr {
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+
+  /// Expression that is calculated in floating point environment specified by
+  /// this node.
+  Stmt *SubExpr;
+
+  /// FP Environment in which the contained expression is evaluated.
+  FPOptions FPFeatures;
+
+public:
+  FPEnvironmentExpr(EmptyShell Empty) : Expr(FPEnvironmentExprClass, Empty) {}
+  FPEnvironmentExpr(Expr *E, const FPOptions &F)
+    : Expr(FPEnvironmentExprClass, E->getType(), E->getValueKind(),
+           E->getObjectKind()), SubExpr(E), FPFeatures(F) {}
+
+  const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+  Expr *getSubExpr() { return cast<Expr>(SubExpr); }
+
+  const FPOptions &getFPOptions() const { return FPFeatures; }
+  FPOptions &getFPOptions() { return FPFeatures; }
+
+  SourceLocation getBeginLoc() const LLVM_READONLY {
+    return SubExpr->getBeginLoc();
+  }
+  SourceLocation getEndLoc() const LLVM_READONLY {
+    return SubExpr->getEndLoc();
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == FPEnvironmentExprClass;
+  }
+  static bool classof(const FPEnvironmentExpr *T) { return true; }
+
+  // Iterators
+  child_range children() {
+    return child_range(&SubExpr, &SubExpr + 1);
+  }
+  const_child_range children() const {
+    return const_child_range(&SubExpr, &SubExpr + 1);
+  }
+};
+
 } // end namespace clang
 
 #endif // LLVM_CLANG_AST_EXPR_H
Index: clang/include/clang/AST/EvaluatedExprVisitor.h
===================================================================
--- clang/include/clang/AST/EvaluatedExprVisitor.h
+++ clang/include/clang/AST/EvaluatedExprVisitor.h
@@ -95,6 +95,10 @@
         this->Visit(*I);
   }
 
+  void VisitFPEnvironmentExpr(PTR(FPEnvironmentExpr) E) {
+    this->Visit(E->getSubExpr());
+  }
+
   /// The basis case walks all of the children of the statement or
   /// expression, assuming they are all potentially evaluated.
   void VisitStmt(PTR(Stmt) S) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to