[clang] [clang] Allow `pragma float_control(precise, *)` to... (PR #105912)

Egor Chesakov via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 5 12:30:17 PDT 2024


https://github.com/echesakov updated https://github.com/llvm/llvm-project/pull/105912

>From 1231a5658bf7dde633e2d84967c6e540b3259e4b Mon Sep 17 00:00:00 2001
From: Egor Chesakov <5292656+echesakov at users.noreply.github.com>
Date: Sat, 5 Oct 2024 12:22:27 -0700
Subject: [PATCH] [clang] Allow `ConditionalOperator` fast-math flags to be
 overridden by `pragma float_control`

Currently, the fast-math flags set on `select` or `phi` instruction
emitted by CodeGen when visiting `ConditionalOperator` take into account
only global `FPOptions` and ignore `pragma float_control`.

This involves storing `FPOptionsOverride` in trailing storage of
`ConditionalOperator` and storing `CurFPOptionsOverride` when creating
an AST node.

Fixes #84648
---
 clang/include/clang/AST/Expr.h                | 67 +++++++++++++++++--
 clang/include/clang/AST/Stmt.h                | 11 +++
 clang/include/clang/AST/TextNodeDumper.h      |  1 +
 clang/lib/AST/ASTImporter.cpp                 |  6 +-
 clang/lib/AST/Expr.cpp                        | 22 ++++++
 clang/lib/AST/TextNodeDumper.cpp              |  5 ++
 clang/lib/CodeGen/CGExprScalar.cpp            |  2 +
 .../Frontend/Rewrite/RewriteModernObjC.cpp    |  7 +-
 clang/lib/Frontend/Rewrite/RewriteObjC.cpp    | 13 ++--
 clang/lib/Sema/SemaExpr.cpp                   |  6 +-
 clang/lib/Sema/SemaOpenMP.cpp                 | 12 ++--
 clang/lib/Serialization/ASTReaderStmt.cpp     |  8 ++-
 clang/lib/Serialization/ASTWriterStmt.cpp     |  3 +
 clang/test/AST/conditional-operator.c         | 21 ++++++
 clang/test/CodeGen/conditional-operator.c     | 36 ++++++++++
 15 files changed, 193 insertions(+), 27 deletions(-)
 create mode 100644 clang/test/AST/conditional-operator.c
 create mode 100644 clang/test/CodeGen/conditional-operator.c

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 7bacf028192c65..848c9676d5f11e 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4210,26 +4210,45 @@ class AbstractConditionalOperator : public Expr {
 
 /// ConditionalOperator - The ?: ternary operator.  The GNU "missing
 /// middle" extension is a BinaryConditionalOperator.
-class ConditionalOperator : public AbstractConditionalOperator {
+class ConditionalOperator final
+    : public AbstractConditionalOperator,
+      private llvm::TrailingObjects<ConditionalOperator, FPOptionsOverride> {
   enum { COND, LHS, RHS, END_EXPR };
   Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
 
   friend class ASTStmtReader;
-public:
+
   ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs,
                       SourceLocation CLoc, Expr *rhs, QualType t,
-                      ExprValueKind VK, ExprObjectKind OK)
+                      ExprValueKind VK, ExprObjectKind OK,
+                      FPOptionsOverride FPFeatures)
       : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK, QLoc,
                                     CLoc) {
     SubExprs[COND] = cond;
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
+    ConditionalOperatorBits.HasFPFeatures =
+        FPFeatures.requiresTrailingStorage();
+    if (hasStoredFPFeatures())
+      setStoredFPFeatures(FPFeatures);
     setDependence(computeDependence(this));
   }
 
   /// Build an empty conditional operator.
-  explicit ConditionalOperator(EmptyShell Empty)
-    : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { }
+  ConditionalOperator(EmptyShell Empty, bool HasFPFeatures)
+      : AbstractConditionalOperator(ConditionalOperatorClass, Empty) {
+    ConditionalOperatorBits.HasFPFeatures = HasFPFeatures;
+  }
+
+public:
+  static ConditionalOperator *CreateEmpty(const ASTContext &C, EmptyShell Empty,
+                                          bool HasFPFeatures);
+
+  static ConditionalOperator *Create(const ASTContext &C, Expr *cond,
+                                     SourceLocation QLoc, Expr *lhs,
+                                     SourceLocation CLoc, Expr *rhs, QualType t,
+                                     ExprValueKind VK, ExprObjectKind OK,
+                                     FPOptionsOverride FPFeatures);
 
   /// getCond - Return the expression representing the condition for
   ///   the ?: operator.
@@ -4265,6 +4284,44 @@ class ConditionalOperator : public AbstractConditionalOperator {
   const_child_range children() const {
     return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
   }
+
+  /// Is FPFeatures in trailing storage?
+  bool hasStoredFPFeatures() const {
+    return ConditionalOperatorBits.HasFPFeatures;
+  }
+  /// Get FPFeatures from trailing storage.
+  FPOptionsOverride getStoredFPFeatures() const {
+    return *getTrailingFPFeatures();
+  }
+
+  // Get the FP features status of this operator. Only meaningful for
+  // operations on floating point types.
+  FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
+    if (hasStoredFPFeatures())
+      return getStoredFPFeatures().applyOverrides(LO);
+    return FPOptions::defaultWithoutTrailingStorage(LO);
+  }
+  FPOptionsOverride getFPFeatures() const {
+    return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
+  }
+
+private:
+  /// Set FPFeatures in trailing storage, used only by Serialization.
+  void setStoredFPFeatures(FPOptionsOverride F) {
+    *getTrailingFPFeatures() = F;
+  }
+
+  FPOptionsOverride *getTrailingFPFeatures() {
+    assert(ConditionalOperatorBits.HasFPFeatures);
+    return getTrailingObjects<FPOptionsOverride>();
+  }
+
+  const FPOptionsOverride *getTrailingFPFeatures() const {
+    assert(ConditionalOperatorBits.HasFPFeatures);
+    return getTrailingObjects<FPOptionsOverride>();
+  }
+
+  friend class TrailingObjects;
 };
 
 /// BinaryConditionalOperator - The GNU extension to the conditional
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index f1a2aac0a8b2f8..df751a0bbfc450 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -658,6 +658,16 @@ class alignas(void *) Stmt {
     SourceLocation OpLoc;
   };
 
+  class ConditionalOperatorBitfields {
+    friend class ConditionalOperator;
+
+    unsigned : NumExprBits;
+
+    /// This is only meaningful when the second and third operands have floating
+    /// point types.
+    unsigned HasFPFeatures : 1;
+  };
+
   class InitListExprBitfields {
     friend class InitListExpr;
 
@@ -1233,6 +1243,7 @@ class alignas(void *) Stmt {
     MemberExprBitfields MemberExprBits;
     CastExprBitfields CastExprBits;
     BinaryOperatorBitfields BinaryOperatorBits;
+    ConditionalOperatorBitfields ConditionalOperatorBits;
     InitListExprBitfields InitListExprBits;
     ParenListExprBitfields ParenListExprBits;
     GenericSelectionExprBitfields GenericSelectionExprBits;
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 88d5535829910f..1767972e9a0264 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -286,6 +286,7 @@ class TextNodeDumper
   void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node);
   void VisitBinaryOperator(const BinaryOperator *Node);
   void VisitCompoundAssignOperator(const CompoundAssignOperator *Node);
+  void VisitConditionalOperator(const ConditionalOperator *Node);
   void VisitAddrLabelExpr(const AddrLabelExpr *Node);
   void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node);
   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 3bc0a647ebf94f..1e46b1a9ce87e0 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7827,9 +7827,9 @@ ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
   if (Err)
     return std::move(Err);
 
-  return new (Importer.getToContext()) ConditionalOperator(
-      ToCond, ToQuestionLoc, ToLHS, ToColonLoc, ToRHS, ToType,
-      E->getValueKind(), E->getObjectKind());
+  return ConditionalOperator::Create(
+      Importer.getToContext(), ToCond, ToQuestionLoc, ToLHS, ToColonLoc, ToRHS,
+      ToType, E->getValueKind(), E->getObjectKind(), E->getFPFeatures());
 }
 
 ExpectedStmt
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 25ab6f3b2addfb..2b054646e54560 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3870,6 +3870,8 @@ FPOptions Expr::getFPFeaturesInEffect(const LangOptions &LO) const {
     return BO->getFPFeaturesInEffect(LO);
   if (auto Cast = dyn_cast<CastExpr>(this))
     return Cast->getFPFeaturesInEffect(LO);
+  if (auto CO = dyn_cast<ConditionalOperator>(this))
+    return CO->getFPFeaturesInEffect(LO);
   return FPOptions::defaultWithoutTrailingStorage(LO);
 }
 
@@ -4892,6 +4894,26 @@ CompoundAssignOperator::Create(const ASTContext &C, Expr *lhs, Expr *rhs,
                              CompLHSType, CompResultType);
 }
 
+ConditionalOperator *
+ConditionalOperator::Create(const ASTContext &C, Expr *cond,
+                            SourceLocation QLoc, Expr *lhs, SourceLocation CLoc,
+                            Expr *rhs, QualType t, ExprValueKind VK,
+                            ExprObjectKind OK, FPOptionsOverride FPFeatures) {
+  bool HasFPFeatures = FPFeatures.requiresTrailingStorage();
+  void *Mem = C.Allocate(totalSizeToAlloc<FPOptionsOverride>(HasFPFeatures),
+                         alignof(ConditionalOperator));
+  return new (Mem)
+      ConditionalOperator(cond, QLoc, lhs, CLoc, rhs, t, VK, OK, FPFeatures);
+}
+
+ConditionalOperator *ConditionalOperator::CreateEmpty(const ASTContext &C,
+                                                      EmptyShell Empty,
+                                                      bool HasFPFeatures) {
+  void *Mem = C.Allocate(totalSizeToAlloc<FPOptionsOverride>(HasFPFeatures),
+                         alignof(ConditionalOperator));
+  return new (Mem) ConditionalOperator(EmptyShell(), HasFPFeatures);
+}
+
 UnaryOperator *UnaryOperator::CreateEmpty(const ASTContext &C,
                                           bool hasFPFeatures) {
   void *Mem = C.Allocate(totalSizeToAlloc<FPOptionsOverride>(hasFPFeatures),
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 2c962253c8bea4..079fe65a10738d 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1518,6 +1518,11 @@ void TextNodeDumper::VisitCompoundAssignOperator(
     printFPOptions(Node->getStoredFPFeatures());
 }
 
+void TextNodeDumper::VisitConditionalOperator(const ConditionalOperator *Node) {
+  if (Node->hasStoredFPFeatures())
+    printFPOptions(Node->getStoredFPFeatures());
+}
+
 void TextNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
   OS << " " << Node->getLabel()->getName();
   dumpPointer(Node->getLabel());
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 2a726bba2dd304..e7ccd3ce661a41 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -5217,6 +5217,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
   Expr *lhsExpr = E->getTrueExpr();
   Expr *rhsExpr = E->getFalseExpr();
 
+  CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
+
   // If the condition constant folds and can be elided, try to avoid emitting
   // the condition and the dead arm.
   bool CondExprBool;
diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index f618c536b5f3c6..2871f8a0655839 100644
--- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -4568,9 +4568,10 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
     Expr *RHSExp = CEXPR->getRHS();
     Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);
     Expr *CONDExp = CEXPR->getCond();
-    ConditionalOperator *CondExpr = new (Context) ConditionalOperator(
-        CONDExp, SourceLocation(), cast<Expr>(LHSStmt), SourceLocation(),
-        cast<Expr>(RHSStmt), Exp->getType(), VK_PRValue, OK_Ordinary);
+    ConditionalOperator *CondExpr = ConditionalOperator::Create(
+        *Context, CONDExp, SourceLocation(), cast<Expr>(LHSStmt),
+        SourceLocation(), cast<Expr>(RHSStmt), Exp->getType(), VK_PRValue,
+        OK_Ordinary, FPOptionsOverride());
     return CondExpr;
   } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
     CPT = IRE->getType()->getAs<BlockPointerType>();
diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
index 9db6ddbf0b8908..42d26617fc8bef 100644
--- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -2997,9 +2997,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
         *Context, sizeofExpr, limit, BO_LE, Context->IntTy, VK_PRValue,
         OK_Ordinary, SourceLocation(), FPOptionsOverride());
     // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
-    ConditionalOperator *CondExpr = new (Context) ConditionalOperator(
-        lessThanExpr, SourceLocation(), CE, SourceLocation(), STCE, returnType,
-        VK_PRValue, OK_Ordinary);
+    ConditionalOperator *CondExpr = ConditionalOperator::Create(
+        *Context, lessThanExpr, SourceLocation(), CE, SourceLocation(), STCE,
+        returnType, VK_PRValue, OK_Ordinary, FPOptionsOverride());
     ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
                                             CondExpr);
   }
@@ -3738,9 +3738,10 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
     Expr *RHSExp = CEXPR->getRHS();
     Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);
     Expr *CONDExp = CEXPR->getCond();
-    ConditionalOperator *CondExpr = new (Context) ConditionalOperator(
-        CONDExp, SourceLocation(), cast<Expr>(LHSStmt), SourceLocation(),
-        cast<Expr>(RHSStmt), Exp->getType(), VK_PRValue, OK_Ordinary);
+    ConditionalOperator *CondExpr = ConditionalOperator::Create(
+        *Context, CONDExp, SourceLocation(), cast<Expr>(LHSStmt),
+        SourceLocation(), cast<Expr>(RHSStmt), Exp->getType(), VK_PRValue,
+        OK_Ordinary, FPOptionsOverride());
     return CondExpr;
   } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
     CPT = IRE->getType()->getAs<BlockPointerType>();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ea57316ad8014e..b0a0228922e741 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8795,9 +8795,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
                                          Context);
 
   if (!commonExpr)
-    return new (Context)
-        ConditionalOperator(Cond.get(), QuestionLoc, LHS.get(), ColonLoc,
-                            RHS.get(), result, VK, OK);
+    return ConditionalOperator::Create(Context, Cond.get(), QuestionLoc,
+                                       LHS.get(), ColonLoc, RHS.get(), result,
+                                       VK, OK, CurFPFeatureOverrides());
 
   return new (Context) BinaryConditionalOperator(
       commonExpr, opaqueValue, Cond.get(), LHS.get(), RHS.get(), QuestionLoc,
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 74c646f64b42f2..a8e62c102081fb 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -14330,10 +14330,10 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
     Expr *Cond = AssertSuccess(SemaRef.BuildBinOp(
         CurScope, {}, BO_LE,
         AssertSuccess(CopyTransformer.TransformExpr(DimTileSizeExpr)), Zero));
-    Expr *MinOne = new (Context) ConditionalOperator(
-        Cond, {}, One, {},
+    Expr *MinOne = ConditionalOperator::Create(
+        Context, Cond, {}, One, {},
         AssertSuccess(CopyTransformer.TransformExpr(DimTileSizeExpr)), DimTy,
-        VK_PRValue, OK_Ordinary);
+        VK_PRValue, OK_Ordinary, FPOptionsOverride());
     return MinOne;
   };
 
@@ -18858,9 +18858,9 @@ static bool actOnOMPReductionKindClause(
                 S.BuildBinOp(Stack->getCurScope(), ReductionId.getBeginLoc(),
                              BO_Assign, LHSDRE, ReductionOp.get());
           } else {
-            auto *ConditionalOp = new (Context)
-                ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc,
-                                    RHSDRE, Type, VK_LValue, OK_Ordinary);
+            auto *ConditionalOp = ConditionalOperator::Create(
+                Context, ReductionOp.get(), ELoc, LHSDRE, ELoc, RHSDRE, Type,
+                VK_LValue, OK_Ordinary, FPOptionsOverride());
             ReductionOp =
                 S.BuildBinOp(Stack->getCurScope(), ReductionId.getBeginLoc(),
                              BO_Assign, LHSDRE, ConditionalOp);
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 8ae07907a04aba..c4b809fbf18ccb 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1145,11 +1145,16 @@ void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
 
 void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
   VisitExpr(E);
+  bool HasFPFeatures = Record.readInt();
+  assert(HasFPFeatures == E->hasStoredFPFeatures());
   E->SubExprs[ConditionalOperator::COND] = Record.readSubExpr();
   E->SubExprs[ConditionalOperator::LHS] = Record.readSubExpr();
   E->SubExprs[ConditionalOperator::RHS] = Record.readSubExpr();
   E->QuestionLoc = readSourceLocation();
   E->ColonLoc = readSourceLocation();
+  if (HasFPFeatures)
+    E->setStoredFPFeatures(
+        FPOptionsOverride::getFromOpaqueInt(Record.readInt()));
 }
 
 void
@@ -3182,7 +3187,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
     }
 
     case EXPR_CONDITIONAL_OPERATOR:
-      S = new (Context) ConditionalOperator(Empty);
+      S = ConditionalOperator::CreateEmpty(
+          Context, Empty, Record[ASTStmtReader::NumExprFields]);
       break;
 
     case EXPR_BINARY_CONDITIONAL_OPERATOR:
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index c292d0a789c7cd..8787c376fe873c 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1091,11 +1091,14 @@ void ASTStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
 
 void ASTStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
   VisitExpr(E);
+  Record.push_back(E->hasStoredFPFeatures());
   Record.AddStmt(E->getCond());
   Record.AddStmt(E->getLHS());
   Record.AddStmt(E->getRHS());
   Record.AddSourceLocation(E->getQuestionLoc());
   Record.AddSourceLocation(E->getColonLoc());
+  if (E->hasStoredFPFeatures())
+    Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
   Code = serialization::EXPR_CONDITIONAL_OPERATOR;
 }
 
diff --git a/clang/test/AST/conditional-operator.c b/clang/test/AST/conditional-operator.c
new file mode 100644
index 00000000000000..518703b1fa2c62
--- /dev/null
+++ b/clang/test/AST/conditional-operator.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+// RUN: %clang_cc1 -ast-dump -menable-no-infs -fapprox-func -funsafe-math-optimizations \
+// RUN: -fno-signed-zeros -mreassociate -freciprocal-math -ffp-contract=fast -ffast-math %s | FileCheck %s
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c -include-pch %t -ast-dump-all /dev/null | FileCheck %s
+
+float test_precise_off(int c, float t, float f) {
+#pragma float_control(precise, off)
+  return c ? t : f;
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_precise_off
+// CHECK: ConditionalOperator {{.*}} FPContractMode=2 AllowFPReassociate=1 NoHonorNaNs=1 NoHonorInfs=1 NoSignedZero=1 AllowReciprocal=1 AllowApproxFunc=1 MathErrno=0
+
+float test_precise_on(int c, float t, float f) {
+#pragma float_control(precise, on)
+  return c ? t : f;
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_precise_on
+// CHECK: ConditionalOperator {{.*}} FPContractMode=1 AllowFPReassociate=0 NoHonorNaNs=0 NoHonorInfs=0 NoSignedZero=0 AllowReciprocal=0 AllowApproxFunc=0 MathErrno=1
diff --git a/clang/test/CodeGen/conditional-operator.c b/clang/test/CodeGen/conditional-operator.c
new file mode 100644
index 00000000000000..ebf530a4bb0298
--- /dev/null
+++ b/clang/test/CodeGen/conditional-operator.c
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -disable-llvm-passes -emit-llvm -menable-no-infs -fapprox-func\
+// RUN: -funsafe-math-optimizations -fno-signed-zeros -mreassociate -freciprocal-math\
+// RUN: -ffp-contract=fast -ffast-math %s -o - | FileCheck %s
+
+float test_precise_off_select(int c) {
+#pragma float_control(precise, off)
+  return c ? 0.0f : 1.0f;
+}
+
+// CHECK-LABEL: test_precise_off_select
+// CHECK: select fast i1 {{%.+}}, float 0.000000e+00, float 1.000000e+00
+
+float test_precise_off_phi(int c, float t, float f) {
+#pragma float_control(precise, off)
+    return c ? t : f;
+}
+
+// CHECK-LABEL: test_precise_off_phi
+// CHECK: phi fast float [ {{%.+}}, {{%.+}} ], [ {{%.+}}, {{%.+}} ]
+
+float test_precise_on_select(int c) {
+#pragma float_control(precise, on)
+    return c ? 0.0f : 1.0f;
+}
+
+// CHECK-LABEL: test_precise_on_select
+// CHECK: select i1 {{%.+}}, float 0.000000e+00, float 1.000000e+00
+
+float test_precise_on_phi(int c, float t, float f) {
+#pragma float_control(precise, on)
+  return c ? t : f;
+}
+
+// CHECK-LABEL: test_precise_on_phi
+// CHECK: phi float [ {{%.+}}, {{%.+}} ], [ {{%.+}}, {{%.+}} ]



More information about the cfe-commits mailing list