[flang-commits] [flang] 3a1513c - [flang][driver] Add forced form flags and -ffixed-line-length

Faris Rehman via flang-commits flang-commits at lists.llvm.org
Thu Feb 4 04:24:40 PST 2021


Author: Faris Rehman
Date: 2021-02-04T12:24:15Z
New Revision: 3a1513c142f4a1ddb97d882a12c89f90cb2529ac

URL: https://github.com/llvm/llvm-project/commit/3a1513c142f4a1ddb97d882a12c89f90cb2529ac
DIFF: https://github.com/llvm/llvm-project/commit/3a1513c142f4a1ddb97d882a12c89f90cb2529ac.diff

LOG: [flang][driver] Add forced form flags and -ffixed-line-length

Add support for the following layout options:
* -ffree-form
* -ffixed-form
- -ffixed-line-length=n (alias -ffixed-line-length-n)
Additionally remove options `-fno-free-form` and `-fno-fixed-form` as they were initially added to forward to gfortran but gfortran does not support these flags.

This patch adds the flag FlangOnlyOption to the existing options `-ffixed-form`, `-ffree-form` and `-ffree-line-length-` in Options.td. As of commit 6a75496836ea14bcfd2f4b59d35a1cad4ac58cee, these flags are not currently forwarded to gfortran anyway.

The default fixed line length in FrontendOptions is 72, based off the current default in Fortran::parser::Options. The line length cannot be set to a negative integer, or a positive integer less than 7 excluding 0, consistent with the behaviour of gfortran.

This patch does not add `-ffree-line-length-n` as Fortran::parser::Options does not have a variable for free form columns.
Whilst the `fixedFormColumns` variable is used in f18 for `-ffree-line-length-n`, f18 only allows `-ffree-line-length-none`/`-ffree-line-length-0` and not a user-specified value. `fixedFormcolumns` cannot be used in the new driver as it is ignored in the frontend when dealing with free form files.

Summary of changes:
- Remove -fno-fixed-form and -fno-free-form from Options.td
- Make -ffixed-form, -ffree-form and -ffree-line-length-n FlangOnlyOption in Options.td
- Create AddFortranDialectOptions method in Flang.cpp
- Create FortranForm enum in FrontendOptions.h
- Add fortranForm_ and fixedFormColumns_ to Fortran::frontend::FrontendOptions
- Update fixed-form-test.f so that it guarantees that it fails when forced as a free form file to better facilitate testing.

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

Added: 
    flang/test/Flang-Driver/Inputs/fixed-line-length-test.f
    flang/test/Flang-Driver/fixed-free-flag.f90
    flang/test/Flang-Driver/fixed-line-length.f90

Modified: 
    clang/include/clang/Driver/Options.td
    clang/lib/Driver/ToolChains/Flang.cpp
    clang/lib/Driver/ToolChains/Flang.h
    flang/include/flang/Frontend/FrontendOptions.h
    flang/lib/Frontend/CompilerInstance.cpp
    flang/lib/Frontend/CompilerInvocation.cpp
    flang/test/Flang-Driver/Inputs/fixed-form-test.f
    flang/test/Flang-Driver/driver-help-hidden.f90
    flang/test/Flang-Driver/driver-help.f90

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index b7eac8e67573..920b6c0adf89 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4129,7 +4129,6 @@ def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran
 def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
 def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>;
 def fconvert_EQ : Joined<["-"], "fconvert=">, Group<gfortran_Group>;
-def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<gfortran_Group>;
 def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
 def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
 def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
@@ -4163,8 +4162,6 @@ defm dump_fortran_original : BooleanFFlag<"dump-fortran-original">, Group<gfortr
 defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group<gfortran_Group>;
 defm external_blas : BooleanFFlag<"external-blas">, Group<gfortran_Group>;
 defm f2c : BooleanFFlag<"f2c">, Group<gfortran_Group>;
-defm fixed_form : BooleanFFlag<"fixed-form">, Group<gfortran_Group>;
-defm free_form : BooleanFFlag<"free-form">, Group<gfortran_Group>;
 defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group<gfortran_Group>;
 defm implicit_none : BooleanFFlag<"implicit-none">, Group<gfortran_Group>;
 defm init_local_zero : BooleanFFlag<"init-local-zero">, Group<gfortran_Group>;
@@ -4207,6 +4204,20 @@ def sycl_std_EQ : Joined<["-"], "sycl-std=">, Group<sycl_Group>, Flags<[CC1Optio
 def test_io : Flag<["-"], "test-io">, Flags<[HelpHidden, FlangOption, FC1Option, FlangOnlyOption]>, Group<Action_Group>,
   HelpText<"Run the InputOuputTest action. Use for development and testing only.">;
 
+let Flags = [FC1Option, FlangOption, FlangOnlyOption] in {
+
+def ffixed_form : Flag<["-"], "ffixed-form">, Group<f_Group>,
+  HelpText<"Process source files in fixed form">;
+def ffree_form : Flag<["-"], "ffree-form">, Group<f_Group>,
+  HelpText<"Process source files in free form">;
+def ffixed_line_length_EQ : Joined<["-"], "ffixed-line-length=">, Group<f_Group>,
+  HelpText<"Use <value> as character line width in fixed mode">,
+  DocBrief<[{Set column after which characters are ignored in typical fixed-form lines in the source
+file}]>;
+def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<f_Group>, Alias<ffixed_line_length_EQ>;
+
+}
+
 //===----------------------------------------------------------------------===//
 // CC1 Options
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 669d911de18a..1b8d03406f30 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -19,6 +19,12 @@ using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+void Flang::AddFortranDialectOptions(const ArgList &Args,
+                                     ArgStringList &CmdArgs) const {
+  Args.AddAllArgs(CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form,
+                            options::OPT_ffixed_line_length_EQ});
+}
+
 void Flang::AddPreprocessingOptions(const ArgList &Args,
                                     ArgStringList &CmdArgs) const {
   Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I});
@@ -79,6 +85,8 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
   if (types::getPreprocessedType(InputType) != types::TY_INVALID)
     AddPreprocessingOptions(Args, CmdArgs);
 
+  AddFortranDialectOptions(Args, CmdArgs);
+
   if (Output.isFilename()) {
     CmdArgs.push_back("-o");
     CmdArgs.push_back(Output.getFilename());

diff  --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h
index 83b79505e0a9..a6efa9ae9bda 100644
--- a/clang/lib/Driver/ToolChains/Flang.h
+++ b/clang/lib/Driver/ToolChains/Flang.h
@@ -24,6 +24,14 @@ namespace tools {
 /// Flang compiler tool.
 class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
 private:
+  /// Extract fortran dialect options from the driver arguments and add them to
+  /// the list of arguments for the generated command/job.
+  ///
+  /// \param [in] Args The list of input driver arguments
+  /// \param [out] CmdArgs The list of output command arguments
+  void AddFortranDialectOptions(const llvm::opt::ArgList &Args,
+                                llvm::opt::ArgStringList &CmdArgs) const;
+
   /// Extract preprocessing options from the driver arguments and add them to
   /// the preprocessor command arguments.
   ///

diff  --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h
index 44fac37cd322..1afda10cc6b4 100644
--- a/flang/include/flang/Frontend/FrontendOptions.h
+++ b/flang/include/flang/Frontend/FrontendOptions.h
@@ -74,6 +74,18 @@ enum class Language : uint8_t {
   Fortran,
 };
 
+// Source file layout
+enum class FortranForm {
+  /// The user has not specified a form. Base the form off the file extension.
+  Unknown,
+
+  /// -ffree-form
+  FixedForm,
+
+  /// -ffixed-form
+  FreeForm
+};
+
 /// The kind of a file that we've been handed as an input.
 class InputKind {
 private:
@@ -159,6 +171,13 @@ class FrontendOptions {
   /// The frontend action to perform.
   frontend::ActionKind programAction_;
 
+  // The form to process files in, if specified.
+  FortranForm fortranForm_ = FortranForm::Unknown;
+
+  // The column after which characters are ignored in fixed form lines in the
+  // source file.
+  int fixedFormColumns_ = 72;
+
 public:
   FrontendOptions() : showHelp_(false), showVersion_(false) {}
 

diff  --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index 8e9ee0ec671c..438aeb8a84e5 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -148,12 +148,14 @@ bool CompilerInstance::ExecuteAction(FrontendAction &act) {
   // Run the frontend action `act` for every input file.
   for (const FrontendInputFile &fif : frontendOpts().inputs_) {
     if (act.BeginSourceFile(*this, fif)) {
-      // Switch between fixed and free form format based on the input file
-      // extension. Ideally we should have all Fortran options set before
-      // entering this loop (i.e. processing any input files). However, we
-      // can't decide between fixed and free form based on the file extension
-      // earlier than this.
-      invoc.fortranOpts().isFixedForm = fif.IsFixedForm();
+      if (invoc.frontendOpts().fortranForm_ == FortranForm::Unknown) {
+        // Switch between fixed and free form format based on the input file
+        // extension. Ideally we should have all Fortran options set before
+        // entering this loop (i.e. processing any input files). However, we
+        // can't decide between fixed and free form based on the file extension
+        // earlier than this.
+        invoc.fortranOpts().isFixedForm = fif.IsFixedForm();
+      }
       if (llvm::Error err = act.Execute()) {
         consumeError(std::move(err));
       }

diff  --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 5077d068b36c..563953f76969 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -162,6 +162,40 @@ static InputKind ParseFrontendArgs(FrontendOptions &opts,
 
     opts.inputs_.emplace_back(std::move(inputs[i]), ik);
   }
+
+  // Set fortranForm_ based on options -ffree-form and -ffixed-form.
+  if (const auto *arg = args.getLastArg(clang::driver::options::OPT_ffixed_form,
+          clang::driver::options::OPT_ffree_form)) {
+    opts.fortranForm_ =
+        arg->getOption().matches(clang::driver::options::OPT_ffixed_form)
+        ? FortranForm::FixedForm
+        : FortranForm::FreeForm;
+  }
+
+  // Set fixedFormColumns_ based on -ffixed-line-length=<value>
+  if (const auto *arg =
+          args.getLastArg(clang::driver::options::OPT_ffixed_line_length_EQ)) {
+    llvm::StringRef argValue = llvm::StringRef(arg->getValue());
+    std::int64_t columns = -1;
+    if (argValue == "none") {
+      columns = 0;
+    } else if (argValue.getAsInteger(/*Radix=*/10, columns)) {
+      columns = -1;
+    }
+    if (columns < 0) {
+      diags.Report(clang::diag::err_drv_invalid_value_with_suggestion)
+          << arg->getOption().getName() << arg->getValue()
+          << "value must be 'none' or a non-negative integer";
+    } else if (columns == 0) {
+      opts.fixedFormColumns_ = 1000000;
+    } else if (columns < 7) {
+      diags.Report(clang::diag::err_drv_invalid_value_with_suggestion)
+          << arg->getOption().getName() << arg->getValue()
+          << "value must be at least seven";
+    } else {
+      opts.fixedFormColumns_ = columns;
+    }
+  }
   return dashX;
 }
 
@@ -278,8 +312,15 @@ void CompilerInvocation::SetDefaultFortranOpts() {
 
 void CompilerInvocation::setFortranOpts() {
   auto &fortranOptions = fortranOpts();
+  const auto &frontendOptions = frontendOpts();
   const auto &preprocessorOptions = preprocessorOpts();
 
+  if (frontendOptions.fortranForm_ != FortranForm::Unknown) {
+    fortranOptions.isFixedForm =
+        frontendOptions.fortranForm_ == FortranForm::FixedForm;
+  }
+  fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns_;
+
   collectMacroDefinitions(preprocessorOptions, fortranOptions);
 
   fortranOptions.searchDirectories.insert(

diff  --git a/flang/test/Flang-Driver/Inputs/fixed-form-test.f b/flang/test/Flang-Driver/Inputs/fixed-form-test.f
index 758ce2a0189a..1bd523c32649 100644
--- a/flang/test/Flang-Driver/Inputs/fixed-form-test.f
+++ b/flang/test/Flang-Driver/Inputs/fixed-form-test.f
@@ -1,2 +1,3 @@
       program FixedForm
+c     end
       end

diff  --git a/flang/test/Flang-Driver/Inputs/fixed-line-length-test.f b/flang/test/Flang-Driver/Inputs/fixed-line-length-test.f
new file mode 100644
index 000000000000..a609de2e1a9e
--- /dev/null
+++ b/flang/test/Flang-Driver/Inputs/fixed-line-length-test.f
@@ -0,0 +1,3 @@
+! The length of the line below is exactly 73 characters
+      program aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+      end

diff  --git a/flang/test/Flang-Driver/driver-help-hidden.f90 b/flang/test/Flang-Driver/driver-help-hidden.f90
index 8118221bf4c7..93fbac87b80f 100644
--- a/flang/test/Flang-Driver/driver-help-hidden.f90
+++ b/flang/test/Flang-Driver/driver-help-hidden.f90
@@ -23,6 +23,10 @@
 ! CHECK-NEXT: -D <macro>=<value>     Define <macro> to <value> (or 1 if <value> omitted)
 ! CHECK-NEXT: -E        Only run the preprocessor
 ! CHECK-NEXT: -fcolor-diagnostics    Enable colors in diagnostics
+! CHECK-NEXT: -ffixed-form           Process source files in fixed form
+! CHECK-NEXT: -ffixed-line-length=<value>
+! CHECK-NEXT: Use <value> as character line width in fixed mode
+! CHECK-NEXT: -ffree-form            Process source files in free form
 ! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics
 ! CHECK-NEXT: -help     Display available options
 ! CHECK-NEXT: -I <dir>               Add directory to the end of the list of include search paths

diff  --git a/flang/test/Flang-Driver/driver-help.f90 b/flang/test/Flang-Driver/driver-help.f90
index 9dfd770cbb2f..bd300df7e2f0 100644
--- a/flang/test/Flang-Driver/driver-help.f90
+++ b/flang/test/Flang-Driver/driver-help.f90
@@ -23,6 +23,10 @@
 ! HELP-NEXT: -D <macro>=<value>     Define <macro> to <value> (or 1 if <value> omitted)
 ! HELP-NEXT: -E                     Only run the preprocessor
 ! HELP-NEXT: -fcolor-diagnostics    Enable colors in diagnostics
+! HELP-NEXT: -ffixed-form           Process source files in fixed form
+! HELP-NEXT: -ffixed-line-length=<value>
+! HELP-NEXT: Use <value> as character line width in fixed mode
+! HELP-NEXT: -ffree-form            Process source files in free form
 ! HELP-NEXT: -fno-color-diagnostics Disable colors in diagnostics
 ! HELP-NEXT: -help                  Display available options
 ! HELP-NEXT: -I <dir>               Add directory to the end of the list of include search paths
@@ -39,6 +43,10 @@
 ! HELP-FC1-NEXT: -D <macro>=<value>     Define <macro> to <value> (or 1 if <value> omitted)
 ! HELP-FC1-NEXT: -emit-obj Emit native object files
 ! HELP-FC1-NEXT: -E                     Only run the preprocessor
+! HELP-FC1-NEXT: -ffixed-form           Process source files in fixed form
+! HELP-FC1-NEXT: -ffixed-line-length=<value>
+! HELP-FC1-NEXT: Use <value> as character line width in fixed mode
+! HELP-FC1-NEXT: -ffree-form            Process source files in free form
 ! HELP-FC1-NEXT: -help                  Display available options
 ! HELP-FC1-NEXT: -I <dir>               Add directory to the end of the list of include search paths
 ! HELP-FC1-NEXT: -o <file>              Write output to <file>

diff  --git a/flang/test/Flang-Driver/fixed-free-flag.f90 b/flang/test/Flang-Driver/fixed-free-flag.f90
new file mode 100644
index 000000000000..532175cce5d2
--- /dev/null
+++ b/flang/test/Flang-Driver/fixed-free-flag.f90
@@ -0,0 +1,25 @@
+! Ensure arguments -ffree-form and -ffixed-form work as expected.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: not %flang-new -fsyntax-only -ffree-form %S/Inputs/fixed-form-test.f  2>&1 | FileCheck %s --check-prefix=FREEFORM
+! RUN: %flang-new -fsyntax-only -ffixed-form %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FIXEDFORM
+
+!----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: not %flang-new -fc1 -fsyntax-only -ffree-form %S/Inputs/fixed-form-test.f  2>&1 | FileCheck %s --check-prefix=FREEFORM
+! RUN: %flang-new -fc1 -fsyntax-only -ffixed-form %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FIXEDFORM
+
+!------------------------------------
+! EXPECTED OUTPUT FOR FREE FORM MODE
+!------------------------------------
+! FREEFORM:error: Could not parse
+
+!-------------------------------------
+! EXPECTED OUTPUT FOR FIXED FORM MODE
+!-------------------------------------
+! FIXEDFORM:free-form-test.f90:1:1: Character in fixed-form label field must be a digit

diff  --git a/flang/test/Flang-Driver/fixed-line-length.f90 b/flang/test/Flang-Driver/fixed-line-length.f90
new file mode 100644
index 000000000000..06cfa521524f
--- /dev/null
+++ b/flang/test/Flang-Driver/fixed-line-length.f90
@@ -0,0 +1,56 @@
+! Ensure argument -ffixed-line-length=n works as expected.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new -E %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=DEFAULTLENGTH
+! RUN: not %flang-new -E -ffixed-line-length=-2 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=NEGATIVELENGTH
+! RUN: not %flang-new -E -ffixed-line-length=3 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=INVALIDLENGTH
+! RUN: %flang-new -E -ffixed-line-length=none %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -E -ffixed-line-length=0 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -E -ffixed-line-length=13 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=LENGTH13
+
+!----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: %flang-new -fc1 -E %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=DEFAULTLENGTH
+! RUN: not %flang-new -fc1 -E -ffixed-line-length=-2 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=NEGATIVELENGTH
+! RUN: not %flang-new -fc1 -E -ffixed-line-length=3 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=INVALIDLENGTH
+! RUN: %flang-new -fc1 -E -ffixed-line-length=none %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -fc1 -E -ffixed-line-length=0 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -fc1 -E -ffixed-line-length=13 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=LENGTH13
+
+!-------------------------------------
+! COMMAND ALIAS -ffixed-line-length-n
+!-------------------------------------
+! RUN: %flang-new -E -ffixed-line-length-13 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=LENGTH13
+! RUN: %flang-new -fc1 -E -ffixed-line-length-13 %S/Inputs/fixed-line-length-test.f  2>&1 | FileCheck %s --check-prefix=LENGTH13
+
+!-------------------------------------
+! EXPECTED OUTPUT WITH DEFAULT LENGTH
+!-------------------------------------
+! The line should be trimmed to 72 characters when reading based on the default value of fixed line length.
+! DEFAULTLENGTH: program{{(a{58})}}
+
+!-----------------------------------------
+! EXPECTED OUTPUT WITH A NEGATIVE LENGTH
+!-----------------------------------------
+! NEGATIVELENGTH: invalid value '-2' in 'ffixed-line-length=','value must be 'none' or a non-negative integer'
+
+!-----------------------------------------
+! EXPECTED OUTPUT WITH LENGTH LESS THAN 7
+!-----------------------------------------
+! INVALIDLENGTH: invalid value '3' in 'ffixed-line-length=','value must be at least seven'
+
+!---------------------------------------
+! EXPECTED OUTPUT WITH UNLIMITED LENGTH
+!---------------------------------------
+! The line should not be trimmed and so 73 characters (including spaces) should be read.
+! UNLIMITEDLENGTH: program{{(a{59})}}
+
+!--------------------------------
+! EXPECTED OUTPUT WITH LENGTH 13
+!--------------------------------
+! LENGTH13: program


        


More information about the flang-commits mailing list