Setting LLVM command-line compiler options
A common situation is passing command-line options to control the compiler’s code generation. This is left to the target as is it ultimately a target-specific situation; some guidance is provided here on how this may be achieved.
The snippet of code below can be used to parse command-line options from an
array of strings into the global in-process LLVM state. Note that this state is
truly global and not per LLVMContext
.
std::array<const char *, 3> cl_args = {
"ComputeAortaCL",
"--foo", "2",
};
llvm::cl::ParseCommandLineOptions(cl_args.size(), cl_args.data(), "");
In a debug build of ComputeMux, command-line options may be provided by the
user via the CA_LLVM_OPTIONS
environment variable. These options are
automatically parsed in the BaseContext
constructor.
The snippet of code above will reset all previously set options, including
CA_LLVM_OPTIONS
options.
Instead, targets may wish to use the following:
#if defined(NDEBUG)
llvm::cl::ParseCommandLineOptions(cl_args.size(), cl_args.data(), "");
#else
llvm::cl::ParseCommandLineOptions(cl_args.size(), cl_args.data(), "",
nullptr, "CA_LLVM_OPTIONS");
#endif
This form will preserve CA_LLVM_OPTIONS
in debug builds.
Warning
Targets should be aware that before LLVM 15 it is possible that if a
command-line option was set in both cl_args
and CA_LLVM_OPTIONS
,
the process may crash with the following error:
for the --foo option: may only occur one or more times!
for the --bar option: may only occur zero or one times!
This affected all options not explicitly defined in LLVM as
llvm::cl::OneOrMore
or llvm::cl::ZeroOrMore
.
This issue was resolved in LLVM 15 so that this will no longer be an error,
but rather the last occurrence of an option always wins. The implementation
of llvm::cl::ParseCommandLineOptions
parses CA_LLVM_OPTIONS
first,
followed by the cl_args
. This means that users are unable to override
options with CA_LLVM_OPTIONS
, with their attempts silently ignored. It is
advised that this is documented to users.
Parsing of command-line options could take place in several places.
If options are inherent to a target and not dictated by the specific compilation
process, then they should be parsed somewhere such as the initialization of
target’s derived compiler::Info
class. This would ensure that the options
are parsed and the LLVM state is set up once per target.
If options depend on the compilation process (such as on the compiler build
options) then they may need to be parsed before the llvm::TargetMachine
is
created, or before the IR passes are run, or before the backend pass pipeline
is added via llvm::TargetMachine::addPassesToEmitFile
. This is ultimately
up to the target. One suggestion is parsing options in the target’s derived
compiler::Module::createPassMachinery
as these are created before all of
the main compilation pipelines in ComputeMux.
Warning
Targets using the lld
linker should be aware that lld::elf::link
(and
compiler::utils::lldLinkToBinary
by extension) resets the LLVM global
command-line state except for CA_LLVM_OPTIONS
(in a debug build).
Targets may supply additional options prefixed with -mllvm
to ensure they
are reparsed by lld
. for example, --foo 1 --bar
would be need to be
passed to lld
as -mllvm --foo=1 -mllvm --bar
. A helper function –
compiler::utils::appendMLLVMOptions
is provided to make this process
easier.
Targets may alternatively need to re-parse options after linking, or before starting the next compilation process, being careful on LLVM 14 and below for the “may only occur one or more times” error detailed above.