فهرست منبع

Use FPContractModeKind universally

FPContractModeKind is the codegen option flag which is already ternary (off,
on, fast).  This makes it universally the type for the contractable info
across the front-end:

* In FPOptions (i.e. in the Sema + in the expression nodes).
* In LangOpts::DefaultFPContractMode which is the option that initializes
FPOptions in the Sema.

Another way to look at this change is that before fp-contractable on/off were
the only states handled to the front-end:
 * For "on", FMA folding was performed by  the front-end
 * For "fast", we simply forwarded the flag to TargetOptions to handle it in
 LLVM

Now off/on/fast are all exposed because for fast we will generate
fast-math-flags during CodeGen.

This is toward moving fp-contraction=fast from an LLVM TargetOption to a
FastMathFlag in order to fix PR25721.

---
This is a recommit of r299027 with an adjustment to the test
CodeGenCUDA/fp-contract.cu.  The test assumed that even
though -ffp-contract=on is passed FE-based folding of FMA won't happen.

This is obviously wrong since the user is asking for this explicitly with the
option.  CUDA is different that -ffp-contract=fast is on by default.

The test used to "work" because contract=fast and contract=on were maintained
separately and we didn't fold in the FE because contract=fast was on due to
the target-default.  This patch consolidates the contract=on/fast/off state
into a ternary state hence the change in behavior.
---

Differential Revision: https://reviews.llvm.org/D31167

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@299033 91177308-0d34-0410-b5e6-96231b3b80d8
Adam Nemet 8 سال پیش
والد
کامیت
922e16babe

+ 3 - 3
include/clang/AST/Expr.h

@@ -2920,7 +2920,7 @@ private:
 
   // This is only meaningful for operations on floating point types and 0
   // otherwise.
-  unsigned FPFeatures : 1;
+  unsigned FPFeatures : 2;
   SourceLocation OpLoc;
 
   enum { LHS, RHS, END_EXPR };
@@ -3078,8 +3078,8 @@ public:
 
   // Get the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
-  bool isFPContractable() const {
-    return FPOptions(FPFeatures).isFPContractable();
+  bool isFPContractableWithinStatement() const {
+    return FPOptions(FPFeatures).allowFPContractWithinStatement();
   }
 
 protected:

+ 3 - 1
include/clang/AST/ExprCXX.h

@@ -117,7 +117,9 @@ public:
 
   // Get the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
-  bool isFPContractable() const { return FPFeatures.isFPContractable(); }
+  bool isFPContractableWithinStatement() const {
+    return FPFeatures.allowFPContractWithinStatement();
+  }
 
   friend class ASTStmtReader;
   friend class ASTStmtWriter;

+ 2 - 1
include/clang/Basic/LangOptions.def

@@ -216,7 +216,8 @@ BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and su
 BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
 LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
 LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
-LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
+/// \brief FP_CONTRACT mode (on/off/fast).
+ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP contraction type")
 LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
 LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
 LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")

+ 25 - 6
include/clang/Basic/LangOptions.h

@@ -88,6 +88,12 @@ public:
     MSVC2015 = 19
   };
 
+  enum FPContractModeKind {
+    FPC_Off,        // Form fused FP ops only where result will not be affected.
+    FPC_On,         // Form fused FP ops according to FP_CONTRACT rules.
+    FPC_Fast        // Aggressively fuse FP ops (E.g. FMA).
+  };
+
 public:
   /// \brief Set of enabled sanitizers.
   SanitizerSet Sanitize;
@@ -180,22 +186,35 @@ public:
 /// \brief Floating point control options
 class FPOptions {
 public:
-  FPOptions() : fp_contract(0) {}
+  FPOptions() : fp_contract(LangOptions::FPC_Off) {}
 
-  explicit FPOptions(unsigned I) : fp_contract(I) {}
+  // Used for serializing.
+  explicit FPOptions(unsigned I)
+      : fp_contract(static_cast<LangOptions::FPContractModeKind>(I)) {}
 
   explicit FPOptions(const LangOptions &LangOpts)
-      : fp_contract(LangOpts.DefaultFPContract) {}
+      : fp_contract(LangOpts.getDefaultFPContractMode()) {}
 
-  void setFPContractable(bool V) { fp_contract = V; }
-  bool isFPContractable() const { return fp_contract; }
+  bool allowFPContractWithinStatement() const {
+    return fp_contract == LangOptions::FPC_On;
+  }
+  bool allowFPContractAcrossStatement() const {
+    return fp_contract == LangOptions::FPC_Fast;
+  }
+  void setAllowFPContractWithinStatement() {
+    fp_contract = LangOptions::FPC_On;
+  }
+  void setAllowFPContractAcrossStatement() {
+    fp_contract = LangOptions::FPC_Fast;
+  }
+  void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; }
 
   /// Used to serialize this.
   unsigned getInt() const { return fp_contract; }
 
 private:
   /// Adjust BinaryOperator::FPFeatures to match the bit-field size of this.
-  unsigned fp_contract : 1;
+  LangOptions::FPContractModeKind fp_contract : 2;
 };
 
 /// \brief Describes the kind of translation unit being processed.

+ 0 - 2
include/clang/Frontend/CodeGenOptions.def

@@ -65,8 +65,6 @@ CODEGENOPT(EmitGcovArcs      , 1, 0) ///< Emit coverage data files, aka. GCDA.
 CODEGENOPT(EmitGcovNotes     , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
 CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
 CODEGENOPT(EmulatedTLS       , 1, 0) ///< Set when -femulated-tls is enabled.
-/// \brief FP_CONTRACT mode (on/off/fast).
-ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On)
 /// \brief Embed Bitcode mode (off/all/bitcode/marker).
 ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
 CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables

+ 0 - 6
include/clang/Frontend/CodeGenOptions.h

@@ -69,12 +69,6 @@ public:
     LocalExecTLSModel
   };
 
-  enum FPContractModeKind {
-    FPC_Off,        // Form fused FP ops only where result will not be affected.
-    FPC_On,         // Form fused FP ops according to FP_CONTRACT rules.
-    FPC_Fast        // Aggressively fuse FP ops (E.g. FMA).
-  };
-
   enum StructReturnConventionKind {
     SRCK_Default,  // No special option was passed.
     SRCK_OnStack,  // Small structs on the stack (-fpcc-struct-return).

+ 4 - 4
lib/CodeGen/BackendUtil.cpp

@@ -561,14 +561,14 @@ void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
           .Default(llvm::FloatABI::Default);
 
   // Set FP fusion mode.
-  switch (CodeGenOpts.getFPContractMode()) {
-  case CodeGenOptions::FPC_Off:
+  switch (LangOpts.getDefaultFPContractMode()) {
+  case LangOptions::FPC_Off:
     Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
     break;
-  case CodeGenOptions::FPC_On:
+  case LangOptions::FPC_On:
     Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
     break;
-  case CodeGenOptions::FPC_Fast:
+  case LangOptions::FPC_Fast:
     Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
     break;
   }

+ 1 - 6
lib/CodeGen/CGExprScalar.cpp

@@ -2672,12 +2672,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
          "Only fadd/fsub can be the root of an fmuladd.");
 
   // Check whether this op is marked as fusable.
-  if (!op.FPFeatures.isFPContractable())
-    return nullptr;
-
-  // Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
-  // either disabled, or handled entirely by the LLVM backend).
-  if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On)
+  if (!op.FPFeatures.allowFPContractWithinStatement())
     return nullptr;
 
   // We have a potentially fusable op. Look for a mul on one of the operands.

+ 16 - 17
lib/Frontend/CompilerInvocation.cpp

@@ -816,18 +816,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
     }
   }
 
-  if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
-    StringRef Val = A->getValue();
-    if (Val == "fast")
-      Opts.setFPContractMode(CodeGenOptions::FPC_Fast);
-    else if (Val == "on")
-      Opts.setFPContractMode(CodeGenOptions::FPC_On);
-    else if (Val == "off")
-      Opts.setFPContractMode(CodeGenOptions::FPC_Off);
-    else
-      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
-  }
-
   if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) {
     StringRef Val = A->getValue();
     if (Val == "ieee")
@@ -1647,7 +1635,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
     Opts.AltiVec = 0;
     Opts.ZVector = 0;
     Opts.LaxVectorConversions = 0;
-    Opts.DefaultFPContract = 1;
+    Opts.setDefaultFPContractMode(LangOptions::FPC_On);
     Opts.NativeHalfType = 1;
     Opts.NativeHalfArgsAndReturns = 1;
     // Include default header file for OpenCL.
@@ -1658,6 +1646,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
 
   Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
               LangStd == LangStandard::lang_cuda;
+  if (Opts.CUDA)
+    // Set default FP_CONTRACT to FAST.
+    Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
 
   Opts.RenderScript = IK == IK_RenderScript;
   if (Opts.RenderScript) {
@@ -2282,6 +2273,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
                       Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
                       Args.hasArg(OPT_cl_fast_relaxed_math);
 
+  if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
+    StringRef Val = A->getValue();
+    if (Val == "fast")
+      Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
+    else if (Val == "on")
+      Opts.setDefaultFPContractMode(LangOptions::FPC_On);
+    else if (Val == "off")
+      Opts.setDefaultFPContractMode(LangOptions::FPC_Off);
+    else
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+  }
+
   Opts.RetainCommentsFromSystemHeaders =
       Args.hasArg(OPT_fretain_comments_from_system_headers);
 
@@ -2536,10 +2539,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
     // triple used for host compilation.
     if (LangOpts.CUDAIsDevice)
       Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
-
-    // Set default FP_CONTRACT to FAST.
-    if (!Args.hasArg(OPT_ffp_contract))
-      Res.getCodeGenOpts().setFPContractMode(CodeGenOptions::FPC_Fast);
   }
 
   // FIXME: Override value name discarding when asan or msan is used because the

+ 6 - 3
lib/Sema/SemaAttr.cpp

@@ -450,13 +450,16 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
 void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) {
   switch (OOS) {
   case tok::OOS_ON:
-    FPFeatures.setFPContractable(true);
+    FPFeatures.setAllowFPContractWithinStatement();
     break;
   case tok::OOS_OFF:
-    FPFeatures.setFPContractable(false);
+    FPFeatures.setDisallowFPContract();
     break;
   case tok::OOS_DEFAULT:
-    FPFeatures.setFPContractable(getLangOpts().DefaultFPContract);
+    if (getLangOpts().getDefaultFPContractMode() == LangOptions::FPC_On)
+      FPFeatures.setAllowFPContractWithinStatement();
+    else
+      FPFeatures.setDisallowFPContract();
     break;
   }
 }

+ 2 - 2
test/CodeGenCUDA/fp-contract.cu

@@ -10,10 +10,10 @@
 // RUN:   -ffp-contract=fast -disable-llvm-passes -o - %s \
 // RUN:   | FileCheck -check-prefix ENABLED %s
 
-// Explicit -ffp-contract=on -- fusing by front-end (disabled).
+// Explicit -ffp-contract=on -- fusing by front-end.
 // RUN: %clang_cc1 -fcuda-is-device -triple nvptx-nvidia-cuda -S \
 // RUN:   -ffp-contract=on -disable-llvm-passes -o - %s \
-// RUN:   | FileCheck -check-prefix DISABLED %s
+// RUN:   | FileCheck -check-prefix ENABLED %s
 
 // Explicit -ffp-contract=off should disable instruction fusing.
 // RUN: %clang_cc1 -fcuda-is-device -triple nvptx-nvidia-cuda -S \