diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1916,7 +1916,7 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group; def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group; def ffp_contract : Joined<["-"], "ffp-contract=">, Group, - Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs):" + Flags<[CC1Option, FC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs):" " fast (fuses across statements disregarding pragmas)" " | on (only fuses in the same statement unless dictated by pragmas)" " | off (never fuses)" diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -80,6 +80,25 @@ } } +static void AddFloatingPointOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + // TODO: share RenderFloatingPointOptions from ./Clang.cpp and use that instead + // of duplicating code here + StringRef FPContract; + + if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { + const StringRef Val = A->getValue(); + if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) { + FPContract = Val; + } else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } + + if (!FPContract.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); +} + void Flang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -142,6 +161,9 @@ // -fPIC and related options. AddPicOptions(Args, CmdArgs); + // Floating point related options + AddFloatingPointOptions(D, Args, CmdArgs); + // Handle options which are simply forwarded to -fc1. forwardOptions(Args, CmdArgs); diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h --- a/flang/include/flang/Frontend/CompilerInvocation.h +++ b/flang/include/flang/Frontend/CompilerInvocation.h @@ -15,6 +15,7 @@ #include "flang/Frontend/CodeGenOptions.h" #include "flang/Frontend/FrontendOptions.h" +#include "flang/Frontend/LangOptions.h" #include "flang/Frontend/PreprocessorOptions.h" #include "flang/Frontend/TargetOptions.h" #include "flang/Lower/LoweringOptions.h" @@ -78,6 +79,9 @@ /// Options controlling IRgen and the backend. Fortran::frontend::CodeGenOptions codeGenOpts; + /// Options controlling language dialect. + Fortran::frontend::LangOptions langOpts; + // Semantics context std::unique_ptr semanticsContext; @@ -140,6 +144,9 @@ CodeGenOptions &getCodeGenOpts() { return codeGenOpts; } const CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; } + LangOptions &getLangOpts() { return langOpts; } + const LangOptions &getLangOpts() const { return langOpts; } + Fortran::lower::LoweringOptions &getLoweringOpts() { return loweringOpts; } const Fortran::lower::LoweringOptions &getLoweringOpts() const { return loweringOpts; diff --git a/flang/include/flang/Frontend/LangOptions.h b/flang/include/flang/Frontend/LangOptions.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Frontend/LangOptions.h @@ -0,0 +1,66 @@ +//===------ LangOptions.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeGenOptions interface, which holds the +// configuration for LLVM's middle-end and back-end. It controls LLVM's code +// generation into assembly or machine code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FLANG_FRONTEND_CODEGENOPTIONS_H +#define LLVM_FLANG_FRONTEND_CODEGENOPTIONS_H + +namespace Fortran::frontend { + +/// Bitfields of LangOptions, split out from LangOptions to ensure +/// that this large collection of bitfields is a trivial class type. +class LangOptionsBase { + +public: + enum FPModeKind { + // Disable the floating point pragma + FPM_Off, + + // Enable the floating point pragma + FPM_On, + + // Aggressively fuse FP ops (E.g. FMA) disregarding pragmas. + FPM_Fast, + + // Aggressively fuse FP ops and honor pragmas. + FPM_FastHonorPragmas + }; + +#define LANGOPT(Name, Bits, Default) unsigned Name : Bits; +#define ENUM_LANGOPT(Name, Type, Bits, Default) +#include "flang/Frontend/LangOptions.def" + +protected: +#define LANGOPT(Name, Bits, Default) +#define ENUM_LANGOPT(Name, Type, Bits, Default) unsigned Name : Bits; +#include "flang/Frontend/LangOptions.def" +}; + +/// Tracks various options which control the dialect of fortran that is accepted. +/// Based on clang::LangOptions +class LangOptions : public LangOptionsBase { + +public: + // Define accessors/mutators for code generation options of enumeration type. +#define LANGOPT(Name, Bits, Default) +#define ENUM_LANGOPT(Name, Type, Bits, Default) \ + Type get##Name() const { return static_cast(Name); } \ + void set##Name(Type Value) { Name = static_cast(Value); } +#include "flang/Frontend/LangOptions.def" + + LangOptions(); +}; + +} // end namespace Fortran::frontend + +#endif diff --git a/flang/include/flang/Frontend/LangOptions.def b/flang/include/flang/Frontend/LangOptions.def new file mode 100644 --- /dev/null +++ b/flang/include/flang/Frontend/LangOptions.def @@ -0,0 +1,25 @@ +//===------ LangOptions.def - Code generation option database ----- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the code generation options. Users of this file +// must define the CODEGENOPT macro to make use of this information. +// +//===----------------------------------------------------------------------===// +#ifndef LANGOPT +# error Define the LANGOPT macro to handle language options +#endif + +#ifndef ENUM_LANGOPT +# define ENUM_LANGOPT(Name, Type, Bits, Default) \ +LANGOPT(Name, Bits, Default) +#endif + +ENUM_LANGOPT(FPContractMode, FPModeKind, 2, FPM_On) ///< FP Contract Mode (on/off/fast) + +#undef LANGOPT +#undef ENUM_LANGOPT diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -7,6 +7,7 @@ FrontendAction.cpp FrontendActions.cpp FrontendOptions.cpp + LangOptions.cpp TextDiagnosticPrinter.cpp TextDiagnosticBuffer.cpp TextDiagnostic.cpp diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -658,6 +658,47 @@ return diags.getNumErrors() == numErrorsBefore; } +/// Parses all floating point related arguments and populates the variables +/// options accordingly. Returns false if new errors are generated. +/// +/// \param [out] res Stores the processed arguments +/// \param [in] args The arguments to parse +/// \param [out] diags DiagnosticsEngine to report erros with +static bool parseFloatingPointArgs(CompilerInvocation &res, + llvm::opt::ArgList &args, + clang::DiagnosticsEngine &diags) { + using Fortran::frontend::CodeGenOptions; + LangOptions &opts = res.getLangOpts(); + const unsigned diagUnimplemented = diags.getCustomDiagID( + clang::DiagnosticsEngine::Warning, "%0 is not currently implemented"); + + if (const llvm::opt::Arg *a = + args.getLastArg(clang::driver::options::OPT_ffp_contract)) { + const llvm::StringRef val = a->getValue(); + enum LangOptions::FPModeKind fpContractMode; + + if (val.equals("on")) + fpContractMode = LangOptions::FPM_On; + else if (val.equals("off")) + fpContractMode = LangOptions::FPM_Off; + else if (val.equals("fast")) + fpContractMode = LangOptions::FPM_Fast; + else if (val.equals("fast-honor-pragmas")) + fpContractMode = LangOptions::FPM_FastHonorPragmas; + else { + diags.Report(clang::diag::err_drv_unsupported_option_argument) + << a->getOption().getName() << val; + return false; + } + + // TODO: actually use the flag in codegen + diags.Report(diagUnimplemented) << a->getOption().getName(); + opts.setFPContractMode(fpContractMode); + } + + return true; +} + bool CompilerInvocation::createFromArgs( CompilerInvocation &res, llvm::ArrayRef commandLineArgs, clang::DiagnosticsEngine &diags) { @@ -712,6 +753,8 @@ res.frontendOpts.mlirArgs = args.getAllArgValues(clang::driver::options::OPT_mmlir); + success &= parseFloatingPointArgs(res, args, diags); + return success; } diff --git a/flang/lib/Frontend/LangOptions.cpp b/flang/lib/Frontend/LangOptions.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Frontend/LangOptions.cpp @@ -0,0 +1,24 @@ +//===------ LangOptions.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Frontend/LangOptions.h" +#include + +namespace Fortran::frontend { + +LangOptions::LangOptions() { +#define LANGOPT(Name, Bits, Default) Name = Default; +#define ENUM_LANGOPT(Name, Type, Bits, Default) set##Name(Default); +#include "flang/Frontend/LangOptions.def" +} + +} // end namespace Fortran::frontend diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -105,6 +105,7 @@ ! HELP-FC1-NEXT: -ffixed-form Process source files in fixed form ! HELP-FC1-NEXT: -ffixed-line-length= ! HELP-FC1-NEXT: Use as character line width in fixed mode +! HELP-FC1-NEXT: -ffp-contract= Form fused FP ops (e.g. FMAs): fast (fuses across statements disregarding pragmas) | on (only fuses in the same statement unless dictated by pragmas) | off (never fuses) | fast-honor-pragmas (fuses across statements unless diectated by pragmas). Default is 'fast' for CUDA, 'fast-honor-pragmas' for HIP, and 'on' otherwise. ! HELP-FC1-NEXT: -ffree-form Process source files in free form ! HELP-FC1-NEXT: -fget-definition ! HELP-FC1-NEXT: Get the symbol definition from diff --git a/flang/test/Driver/flang_fp_opts.f90 b/flang/test/Driver/flang_fp_opts.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/flang_fp_opts.f90 @@ -0,0 +1,10 @@ +! Test for passing of floating point options between the compiler and frontend +! drivers. + +! RUN: %flang -### -S -ffp-contract=fast %s 2>&1 | FileCheck %s --check-prefix=CHECK1 + +! CHECK1-LABEL: "-fc1" +! CHECK1: -ffp-contract=fast + +! RUN: %flang_fc1 -ffp-contract=fast %s 2>&1 | FileCheck %s --check-prefix=CHECK2 +! CHECK2: ffp-contract= is not currently implemented