|
| 1 | +<!--===- docs/FlangDriver.md |
| 2 | +
|
| 3 | + Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | + See https://llvm.org/LICENSE.txt for license information. |
| 5 | + SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +
|
| 7 | +--> |
| 8 | + |
| 9 | +# Flang drivers |
| 10 | + |
| 11 | +```eval_rst |
| 12 | +.. contents:: |
| 13 | + :local: |
| 14 | +``` |
| 15 | + |
| 16 | +There are two main drivers in Flang: |
| 17 | +* the compiler driver, `flang-new` |
| 18 | +* the frontend driver, `flang-new -fc1` |
| 19 | + |
| 20 | +The compiler driver will allow you to control all compilation phases (i.e. |
| 21 | +preprocessing, frontend code-generation, middlend/backend code-optimisation and |
| 22 | +lowering, linking). For frontend specific tasks, the compiler driver creates a |
| 23 | +Fortran compilation job and delegates it to `flang-new -fc1`, the frontend driver. |
| 24 | + |
| 25 | +The frontend driver glues all of the frontend libraries together and provides |
| 26 | +an easy-to-use and intuitive interface to the frontend. It accepts many |
| 27 | +frontend-specific options not available in `flang-new` and as such it provides a |
| 28 | +finer control over the frontend. Similarly to `-Xclang` in `clang`, you can use |
| 29 | +`-Xflang` to forward the frontend specific flags from the compiler directly to |
| 30 | +the frontend driver. |
| 31 | + |
| 32 | +## Compiler Driver |
| 33 | + |
| 34 | +The main entry point for Flang's compiler driver is implemented in |
| 35 | +`flang/tools/flang-driver/driver.cpp`. Flang's compiler driver is implemented |
| 36 | +in terms of Clang's driver library, `clangDriver`. This approach allows us to: |
| 37 | +* benefit from Clang's support for various targets, platforms and operating systems |
| 38 | +* leverage Clang's ability to drive various backends available in LLVM, as well |
| 39 | + as linkers and assemblers. |
| 40 | +One implication of this dependency on Clang is that all of Flang's compiler |
| 41 | +options are defined alongside Clang's options in |
| 42 | +`clang/include/clang/Driver/Options.td`. For options that are common for both |
| 43 | +Flang and Clang, the corresponding definitions are shared. |
| 44 | + |
| 45 | +Internally, a `clangDriver` based compiler driver works by creating actions |
| 46 | +that correspond to various compilation phases, e.g. `PreprocessJobClass`, |
| 47 | +`CompileJobClass`, `BackendJobClass` or `LinkJobClass` from the |
| 48 | +`clang::driver::Action::ActionClass` enum. There are also other, more |
| 49 | +specialised actions, e.g. `MigrateJobClass` or `InputClass`, that do not map |
| 50 | +directly to common compilation steps. The actions to run are determined from |
| 51 | +the supplied compiler flags, e.g. |
| 52 | + |
| 53 | +* `-E` for `PreprocessJobClass`, |
| 54 | +* `-c` for `CompileJobClass`. |
| 55 | + |
| 56 | +In most cases, the driver creates a chain of actions/jobs/phases where the |
| 57 | +output from one action is the input for the subsequent one. You can use the |
| 58 | +`-ccc-print-phases` flag to see the sequence of actions that the driver will |
| 59 | +create for your compiler invocation: |
| 60 | +```bash |
| 61 | +flang-new -ccc-print-phases -E file.f |
| 62 | ++- 0: input, "file.f", f95-cpp-input |
| 63 | +1: preprocessor, {0}, f95 |
| 64 | +``` |
| 65 | +As you can see, for `-E` the driver creates only two jobs and stops immediately |
| 66 | +after preprocessing. The first job simply prepares the input. For `-c`, the |
| 67 | +pipeline of the created jobs is more complex: |
| 68 | +```bash |
| 69 | +flang-new -ccc-print-phases -c file.f |
| 70 | + +- 0: input, "file.f", f95-cpp-input |
| 71 | + +- 1: preprocessor, {0}, f95 |
| 72 | + +- 2: compiler, {1}, ir |
| 73 | ++- 3: backend, {2}, assembler |
| 74 | +4: assembler, {3}, object |
| 75 | +``` |
| 76 | +Note that currently Flang does not support code-generation and `flang-new` will |
| 77 | +fail during the second step above with the following error: |
| 78 | +```bash |
| 79 | +error: code-generation is not available yet |
| 80 | +``` |
| 81 | +The other phases are printed nonetheless when using `-ccc-print-phases`, as |
| 82 | +that reflects what `clangDriver`, the library, will try to create and run. |
| 83 | + |
| 84 | +For actions specific to the frontend (e.g. preprocessing or code generation), a |
| 85 | +command to call the frontend driver is generated (more specifically, an |
| 86 | +instance of `clang::driver::Command`). Every command is bound to an instance of |
| 87 | +`clang::driver::Tool`. For Flang we introduced a specialisation of this class: |
| 88 | +`clang::driver::Flang`. This class implements the logic to either translate or |
| 89 | +forward compiler options to the frontend driver, `flang-new -fc1`. |
| 90 | + |
| 91 | +You can read more on the design of `clangDriver` in Clang's [Driver Design & |
| 92 | +Internals](https://clang.llvm.org/docs/DriverInternals.html). |
| 93 | + |
| 94 | +## Frontend Driver |
| 95 | +Flang's frontend driver is the main interface between end-users and the Flang |
| 96 | +frontend. The high-level design is similar to Clang's frontend driver, `clang |
| 97 | +-cc1` and consists of the following classes: |
| 98 | +* `CompilerInstance`, which is a helper class that encapsulates and manages |
| 99 | + various objects that are always required by the frontend (e.g. `AllSources`, |
| 100 | + `AllCookedSources, `Parsing`, `CompilerInvocation`, etc.). In most cases |
| 101 | + `CompilerInstance` owns these objects, but it also can share them with its |
| 102 | + clients when required. It also implements utility methods to construct and |
| 103 | + manipulate them. |
| 104 | +* `CompilerInvocation` encapsulates the configuration of the current |
| 105 | + invocation of the compiler as derived from the command-line options and the |
| 106 | + input files (in particular, file extensions). Among other things, it holds an |
| 107 | + instance of `FrontendOptions`. Like `CompilerInstance`, it owns the objects |
| 108 | + that it manages. It can share them with its clients that want to access them |
| 109 | + even after the corresponding `CompilerInvocation` has been destructed. |
| 110 | +* `FrontendOptions` holds options that control the behaviour of the frontend, |
| 111 | + as well as e.g. the list of the input files. These options come either |
| 112 | + directly from the users (through command-line flags) or are derived from |
| 113 | + e.g. the host system configuration. |
| 114 | +* `FrontendAction` and `FrontendActions` (the former being the base class for |
| 115 | + the latter) implement the actual actions to perform by the frontend. Usually |
| 116 | + there is one specialisation of `FrontendActions` for every compiler action flag |
| 117 | + (e.g. `-E`, `-fdebug-unparse`). These classes also contain various hooks that |
| 118 | + allow you to e.g. fine-tune the configuration of the frontend based on the |
| 119 | + input. |
| 120 | + |
| 121 | +This list is not exhaustive and only covers the main classes that implement the |
| 122 | +driver. The main entry point for the frontend driver, `fc1_main`, is |
| 123 | +implemented in `flang/tools/flang-driver/driver.cpp`. It can be accessed by |
| 124 | +invoking the compiler driver, `flang-new`, with the `-fc1` flag. |
| 125 | + |
| 126 | +The frontend driver will only run one action at a time. If you specify multiple |
| 127 | +action flags, only the last one will be taken into account. The default action |
| 128 | +is `ParseSyntaxOnlyAction`, which corresponds to `-fsyntax-only`. In other |
| 129 | +words, `flang-new -fc1 <input-file>` is equivalent to `flang-new -fc1 -fsyntax-only |
| 130 | +<input-file>`. |
| 131 | + |
| 132 | +## Adding new Compiler Options |
| 133 | +Adding a new compiler option in Flang consists of two steps: |
| 134 | +* define the new option in a dedicated TableGen file, |
| 135 | +* parse and implement the option in the relevant drivers that support it. |
| 136 | + |
| 137 | +### Option Definition |
| 138 | +All of Flang's compiler and frontend driver options are defined in |
| 139 | +`clang/include/clang/Driver/Options.td` in Clang. When adding a new option to |
| 140 | +Flang, you will either: |
| 141 | + * extend the existing definition for an option that is already available |
| 142 | + in one of Clang's drivers (e.g. `clang`), but not yet available in Flang, or |
| 143 | + * add a completely new definition if the option that you are adding has not |
| 144 | + been defined yet. |
| 145 | + |
| 146 | +There are many predefined TableGen classes and records that you can use to fine |
| 147 | +tune your new option. The list of available configurations can be overwhelming |
| 148 | +at times. Sometimes the easiest approach is to find an existing option that has |
| 149 | +similar semantics to your new option and start by copying that. |
| 150 | + |
| 151 | +For every new option, you will also have to define the visibility of the new |
| 152 | +option. This is controlled through the `Flags` field. You can use the following |
| 153 | +Flang specific option flags to control this: |
| 154 | + * `FlangOption` - this option will be available in the `flang-new` compiler driver, |
| 155 | + * `FC1Option` - this option will be available in the `flang-new -fc1` frontend driver, |
| 156 | + * `FlangOnlyOption` - this option will not be visible in Clang drivers. |
| 157 | + |
| 158 | +Please make sure that options that you add are only visible in drivers that can |
| 159 | +support it. For example, options that only make sense for Fortran input files |
| 160 | +(e.g. `-ffree-form`) should not be visible in Clang and be marked as |
| 161 | +`FlangOnlyOption`. |
| 162 | + |
| 163 | +When deciding what `OptionGroup` to use when defining a new option in the |
| 164 | +`Options.td` file, many new options fall into one of the following two |
| 165 | +categories: |
| 166 | + * `Action_Group` - options that define an action to run (e.g. |
| 167 | + `-fsyntax-only`, `-E`) |
| 168 | + * `f_Group` - target independent compiler flags (e.g. `-ffixed-form`, |
| 169 | + `-fopenmp`) |
| 170 | +There are also other groups and occasionally you will use them instead of the |
| 171 | +groups listed above. |
| 172 | + |
| 173 | +### Option Implementation |
| 174 | +First, every option needs to be parsed. Flang compiler options are parsed in |
| 175 | +two different places, depending on which driver they belong to: |
| 176 | + |
| 177 | +* frontend driver: `flang/lib/Frontend/CompilerInvocation.cpp`, |
| 178 | +* compiler driver: `clang/lib/Driver/ToolChains/Flang.cpp`. |
| 179 | + |
| 180 | +The parsing will depend on the semantics encoded in the TableGen definition. |
| 181 | + |
| 182 | +When adding a compiler driver option (i.e. an option that contains |
| 183 | +`FlangOption` among its `Flags`) that you also intend to be understood by the |
| 184 | +frontend, make sure that it is either forwarded to `flang-new -fc1` or translated |
| 185 | +into some other option that is accepted by the frontend driver. In the case of |
| 186 | +options that contain both `FlangOption` and `FC1Option` among its flags, we |
| 187 | +usually just forward from `flang-new` to `flang-new -fc1`. This is then tested in |
| 188 | +`flang/test/Driver/frontend-forward.F90`. |
| 189 | + |
| 190 | +What follows is usually very dependant on the meaning of the corresponding |
| 191 | +option. In general, regular compiler flags (e.g. `-ffree-form`) are mapped to |
| 192 | +some state within the driver. A lot of this state is stored within an instance |
| 193 | +of `FrontendOptions`, but there are other more specialised classes too. Action |
| 194 | +flags (e.g. `-fsyntax-only`) are usually more complex overall, but also more |
| 195 | +structured in terms of the implementation. |
| 196 | + |
| 197 | +### Action Options |
| 198 | +For options that correspond to an action (i.e. marked as `Action_Group`), you |
| 199 | +will have to define a dedicated instance of `FrontendActions` in |
| 200 | +`flang/include/flang/Frontend/FrontendOptions.h`. For example, for |
| 201 | +`-fsyntax-only` we defined: |
| 202 | +```cpp |
| 203 | +class ParseSyntaxOnlyAction : public PrescanAndSemaAction { |
| 204 | + void ExecuteAction() override; |
| 205 | +}; |
| 206 | +``` |
| 207 | +Command line options are mapped to frontend actions through the |
| 208 | +`Fortran::frontend::ActionKind` enum. For every new action option that you |
| 209 | +add, you will have to add a dedicated entry in that enum (e.g. |
| 210 | +`ParseSyntaxOnly` for `-fsyntax-only`) and a corresponding `case` in |
| 211 | +`ParseFrontendArgs` function in the `CompilerInvocation.cpp` file, e.g.: |
| 212 | +```cpp |
| 213 | + case clang::driver::options::OPT_fsyntax_only: |
| 214 | + opts.programAction = ParseSyntaxOnly; |
| 215 | + break; |
| 216 | +``` |
| 217 | +Note that this simply sets the program/frontend action within the frontend |
| 218 | +driver. You still have make sure that the corresponding frontend action class |
| 219 | +is instantiated when your new action option is used. The relevant `switch` |
| 220 | +statement is implemented in `Fortran::frontend::CreatedFrontendBaseAction` in |
| 221 | +the `ExecuteCompilerInvocation.cpp` file. Here's an example for |
| 222 | +`-fsyntax-only`: |
| 223 | +```cpp |
| 224 | + case ParseSyntaxOnly: |
| 225 | + return std::make_unique<ParseSyntaxOnlyAction>(); |
| 226 | +``` |
| 227 | +At this point you should be able to trigger that frontend action that you have |
| 228 | +just added using your new frontend option. |
| 229 | + |
| 230 | +# Testing |
| 231 | +In LIT, we define two variables that you can use to invoke Flang's drivers: |
| 232 | +* `%flang` is expanded as `flang-new` (i.e. the compiler driver) |
| 233 | +* `%flang_fc1` is expanded as `flang-new -fc1` (i.e. the frontend driver) |
| 234 | + |
| 235 | +For most regression tests for the frontend, you will want to use `%flang_fc1`. |
| 236 | +In some cases, the observable behaviour will be identical regardless of whether |
| 237 | +`%flang` or `%flang_fc1` is used. However, when you are using `%flang` instead |
| 238 | +of `%flang_fc1`, the compiler driver will add extra flags to the frontend |
| 239 | +driver invocation (i.e. `flang-new -fc1 -<extra-flags>`). In some cases that might |
| 240 | +be exactly what you want to test. In fact, you can check these additional |
| 241 | +flags by using the `-###` compiler driver command line option. |
| 242 | + |
| 243 | +Lastly, you can use `! REQUIRES: <feature>` for tests that will only work when |
| 244 | +`<feature>` is available. For example, you can use`! REQUIRES: shell` to mark a |
| 245 | +test as only available on Unix-like systems (i.e. systems that contain a Unix |
| 246 | +shell). In practice this means that the corresponding test is skipped on |
| 247 | +Windows. |
0 commit comments