Skip to content

Commit

Permalink
[Flang] Add support for fsave-optimization-record
Browse files Browse the repository at this point in the history
Add support for generating and saving the optimization record.
Optimization record lists the optimizations performed by LLVM.

This patch enables the flag in Flang. Clang handles this functionality
using the BackendConsumer which Flang doesn't have, hence, was
implemented in CodeGenAction::executeAction

FlangOption added to all variants of fsave-optimization-record in
clang/include/clang/Driver/Options.td . Clang handles it the
same way.

opt_record_file, opt_record_passes and opt_record_format flags
in Options.td were moved out of the group [CC1Option, NoDriverOption]
to allow flang -fc1 support.

The renderRemarksOptions and willEmitRemarks functions in
clang/lib/Driver/ToolChains/Flang.cpp follow same syntax as clang.
In flang/lib/Frontend/CompilerInvocation.cpp we update the field
OptRecordFile with the provided optimization file value. Clang
doesn't do this as it processes the Options.td, mapping the
OptRecordFile earlier on.

Reviewed By: awarzynski, tblah

Differential Revision: https://reviews.llvm.org/D155452
  • Loading branch information
victorkingi authored and kiranchandramohan committed Jul 28, 2023
1 parent 1478d4d commit f04ccad
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 25 deletions.
26 changes: 13 additions & 13 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3084,18 +3084,18 @@ def foperator_arrow_depth_EQ : Joined<["-"], "foperator-arrow-depth=">, Group<f_
HelpText<"Maximum number of 'operator->'s to call for a member access">,
MarshallingInfoInt<LangOpts<"ArrowDepth">, "256">;

def fsave_optimization_record : Flag<["-"], "fsave-optimization-record">,
def fsave_optimization_record : Flag<["-"], "fsave-optimization-record">, Flags<[FlangOption]>,
Group<f_Group>, HelpText<"Generate a YAML optimization record file">;
def fsave_optimization_record_EQ : Joined<["-"], "fsave-optimization-record=">,
def fsave_optimization_record_EQ : Joined<["-"], "fsave-optimization-record=">, Flags<[FlangOption]>,
Group<f_Group>, HelpText<"Generate an optimization record file in a specific format">,
MetaVarName<"<format>">;
def fno_save_optimization_record : Flag<["-"], "fno-save-optimization-record">,
Group<f_Group>, Flags<[NoArgumentUnused]>;
def foptimization_record_file_EQ : Joined<["-"], "foptimization-record-file=">,
Group<f_Group>, Flags<[FlangOption, NoArgumentUnused]>;
def foptimization_record_file_EQ : Joined<["-"], "foptimization-record-file=">, Flags<[FlangOption]>,
Group<f_Group>,
HelpText<"Specify the output name of the file containing the optimization remarks. Implies -fsave-optimization-record. On Darwin platforms, this cannot be used with multiple -arch <arch> options.">,
MetaVarName<"<file>">;
def foptimization_record_passes_EQ : Joined<["-"], "foptimization-record-passes=">,
def foptimization_record_passes_EQ : Joined<["-"], "foptimization-record-passes=">, Flags<[FlangOption]>,
Group<f_Group>,
HelpText<"Only include passes which match a specified regular expression in the generated optimization record (by default, include all passes)">,
MetaVarName<"<regex>">;
Expand Down Expand Up @@ -6390,14 +6390,6 @@ def arcmt_action_EQ : Joined<["-"], "arcmt-action=">, Flags<[CC1Option, NoDriver
NormalizedValues<["ARCMT_Check", "ARCMT_Modify", "ARCMT_Migrate"]>,
MarshallingInfoEnum<FrontendOpts<"ARCMTAction">, "ARCMT_None">;

def opt_record_file : Separate<["-"], "opt-record-file">,
HelpText<"File name to use for YAML optimization record output">,
MarshallingInfoString<CodeGenOpts<"OptRecordFile">>;
def opt_record_passes : Separate<["-"], "opt-record-passes">,
HelpText<"Only record remark information for passes whose names match the given regular expression">;
def opt_record_format : Separate<["-"], "opt-record-format">,
HelpText<"The format used for serializing remarks (default: YAML)">;

def print_stats : Flag<["-"], "print-stats">,
HelpText<"Print performance metrics and statistics">,
MarshallingInfoFlag<FrontendOpts<"ShowStats">>;
Expand Down Expand Up @@ -6838,6 +6830,14 @@ defm debug_pass_manager : BoolOption<"f", "debug-pass-manager",
PosFlag<SetTrue, [], "Prints debug information for the new pass manager">,
NegFlag<SetFalse, [], "Disables debug printing for the new pass manager">>;

def opt_record_file : Separate<["-"], "opt-record-file">,
HelpText<"File name to use for YAML optimization record output">,
MarshallingInfoString<CodeGenOpts<"OptRecordFile">>;
def opt_record_passes : Separate<["-"], "opt-record-passes">,
HelpText<"Only record remark information for passes whose names match the given regular expression">;
def opt_record_format : Separate<["-"], "opt-record-format">,
HelpText<"The format used for serializing remarks (default: YAML)">;

} // let Flags = [CC1Option, FC1Option, NoDriverOption]

//===----------------------------------------------------------------------===//
Expand Down
50 changes: 50 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "clang/Driver/Options.h"
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

#include <cassert>

Expand Down Expand Up @@ -387,6 +389,50 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
CmdArgs.push_back("-freciprocal-math");
}

static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
const InputInfo &Input) {
StringRef Format = "yaml";
if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
Format = A->getValue();

CmdArgs.push_back("-opt-record-file");

const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
if (A) {
CmdArgs.push_back(A->getValue());
} else {
SmallString<128> F;

if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {
if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))
F = FinalOutput->getValue();
}

if (F.empty()) {
// Use the input filename.
F = llvm::sys::path::stem(Input.getBaseInput());
}

SmallString<32> Extension;
Extension += "opt.";
Extension += Format;

llvm::sys::path::replace_extension(F, Extension);
CmdArgs.push_back(Args.MakeArgString(F));
}

if (const Arg *A =
Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) {
CmdArgs.push_back("-opt-record-passes");
CmdArgs.push_back(A->getValue());
}

if (!Format.empty()) {
CmdArgs.push_back("-opt-record-format");
CmdArgs.push_back(Format.data());
}
}

void Flang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const char *LinkingOutput) const {
Expand Down Expand Up @@ -471,6 +517,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Add Codegen options
addCodegenOptions(Args, CmdArgs);

// Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
if (willEmitRemarks(Args))
renderRemarksOptions(Args, CmdArgs, Input);

// Add other compile options
addOtherOptions(Args, CmdArgs);

Expand Down
11 changes: 11 additions & 0 deletions flang/include/flang/Frontend/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// The directory where temp files are stored if specified by -save-temps
std::optional<std::string> SaveTempsDir;

/// The name of the file to which the backend should save YAML optimization
/// records.
std::string OptRecordFile;

/// The regex that filters the passes that should be saved to the optimization
/// records.
std::string OptRecordPasses;

/// The format used for serializing remarks (default: YAML)
std::string OptRecordFormat;

// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
Expand Down
20 changes: 16 additions & 4 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,12 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
opts.DebugPassManager = 1;

if (args.hasFlag(clang::driver::options::OPT_fstack_arrays,
clang::driver::options::OPT_fno_stack_arrays, false)) {
clang::driver::options::OPT_fno_stack_arrays, false))
opts.StackArrays = 1;
}

if (args.hasFlag(clang::driver::options::OPT_floop_versioning,
clang::driver::options::OPT_fno_loop_versioning, false)) {
clang::driver::options::OPT_fno_loop_versioning, false))
opts.LoopVersioning = 1;
}

for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ))
opts.LLVMPassPlugins.push_back(a->getValue());
Expand All @@ -190,6 +189,19 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
opts.PrepareForThinLTO = true;
}

// -f[no-]save-optimization-record[=<format>]
if (const llvm::opt::Arg *a =
args.getLastArg(clang::driver::options::OPT_opt_record_file))
opts.OptRecordFile = a->getValue();

if (const llvm::opt::Arg *a =
args.getLastArg(clang::driver::options::OPT_opt_record_format))
opts.OptRecordFormat = a->getValue();

if (const llvm::opt::Arg *a =
args.getLastArg(clang::driver::options::OPT_opt_record_passes))
opts.OptRecordPasses = a->getValue();

if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ))
opts.SaveTempsDir = a->getValue();

Expand Down
62 changes: 54 additions & 8 deletions flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
Expand All @@ -55,6 +57,7 @@
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
Expand Down Expand Up @@ -939,9 +942,32 @@ void CodeGenAction::embedOffloadObjects() {
}
}

static void reportOptRecordError(llvm::Error e, clang::DiagnosticsEngine &diags,
const CodeGenOptions &codeGenOpts) {
handleAllErrors(
std::move(e),
[&](const llvm::LLVMRemarkSetupFileError &e) {
diags.Report(clang::diag::err_cannot_open_file)
<< codeGenOpts.OptRecordFile << e.message();
},
[&](const llvm::LLVMRemarkSetupPatternError &e) {
diags.Report(clang::diag::err_drv_optimization_remark_pattern)
<< e.message() << codeGenOpts.OptRecordPasses;
},
[&](const llvm::LLVMRemarkSetupFormatError &e) {
diags.Report(clang::diag::err_drv_optimization_remark_format)
<< codeGenOpts.OptRecordFormat;
});
}

void CodeGenAction::executeAction() {
CompilerInstance &ci = this->getInstance();

clang::DiagnosticsEngine &diags = ci.getDiagnostics();
const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts();
Fortran::lower::LoweringOptions &loweringOpts =
ci.getInvocation().getLoweringOpts();

// If the output stream is a file, generate it and define the corresponding
// output stream. If a pre-defined output stream is available, we will use
// that instead.
Expand All @@ -959,23 +985,23 @@ void CodeGenAction::executeAction() {
os = getOutputStream(ci, getCurrentFileOrBufferName(), action);

if (!os) {
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
unsigned diagID = diags.getCustomDiagID(
clang::DiagnosticsEngine::Error, "failed to create the output file");
ci.getDiagnostics().Report(diagID);
diags.Report(diagID);
return;
}
}

if (action == BackendActionTy::Backend_EmitFIR) {
if (ci.getInvocation().getLoweringOpts().getLowerToHighLevelFIR()) {
if (loweringOpts.getLowerToHighLevelFIR()) {
lowerHLFIRToFIR();
}
mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
return;
}

if (action == BackendActionTy::Backend_EmitHLFIR) {
assert(ci.getInvocation().getLoweringOpts().getLowerToHighLevelFIR() &&
assert(loweringOpts.getLowerToHighLevelFIR() &&
"Lowering must have been configured to emit HLFIR");
mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
return;
Expand All @@ -994,8 +1020,7 @@ void CodeGenAction::executeAction() {
const std::string &theTriple = tm->getTargetTriple().str();

if (llvmModule->getTargetTriple() != theTriple) {
ci.getDiagnostics().Report(clang::diag::warn_fe_override_module)
<< theTriple;
diags.Report(clang::diag::warn_fe_override_module) << theTriple;
}

// Always set the triple and data layout, to make sure they match and are set.
Expand All @@ -1005,9 +1030,30 @@ void CodeGenAction::executeAction() {
llvmModule->setDataLayout(tm->createDataLayout());

// Embed offload objects specified with -fembed-offload-object
if (!ci.getInvocation().getCodeGenOpts().OffloadObjects.empty())
if (!codeGenOpts.OffloadObjects.empty())
embedOffloadObjects();

// write optimization-record
llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
setupLLVMOptimizationRemarks(
llvmModule->getContext(), codeGenOpts.OptRecordFile,
codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat,
/*DiagnosticsWithHotness=*/false,
/*DiagnosticsHotnessThreshold=*/0);

if (llvm::Error e = optRecordFileOrErr.takeError()) {
reportOptRecordError(std::move(e), diags, codeGenOpts);
return;
}

std::unique_ptr<llvm::ToolOutputFile> optRecordFile =
std::move(*optRecordFileOrErr);

if (optRecordFile) {
optRecordFile->keep();
optRecordFile->os().flush();
}

// Run LLVM's middle-end (i.e. the optimizer).
runOptimizationPipeline(ci.isOutputStreamNull() ? *os : ci.getOutputStream());

Expand All @@ -1026,7 +1072,7 @@ void CodeGenAction::executeAction() {
if (action == BackendActionTy::Backend_EmitAssembly ||
action == BackendActionTy::Backend_EmitObj) {
generateMachineCodeOrAssemblyImpl(
ci.getDiagnostics(), *tm, action, *llvmModule,
diags, *tm, action, *llvmModule,
ci.isOutputStreamNull() ? *os : ci.getOutputStream());
return;
}
Expand Down
8 changes: 8 additions & 0 deletions flang/test/Driver/driver-help-hidden.f90
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,16 @@
! CHECK-NEXT: -fopenmp-version=<value>
! CHECK-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 50 for OpenMP 5.0). Default value is 50 for Clang and 11 for Flang
! CHECK-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code.
! CHECK-NEXT: -foptimization-record-file=<file>
! CHECK-NEXT: Specify the output name of the file containing the optimization remarks. Implies -fsave-optimization-record. On Darwin platforms, this cannot be used with multiple -arch <arch> options.
! CHECK-NEXT: -foptimization-record-passes=<regex>
! CHECK-NEXT: Only include passes which match a specified regular expression in the generated optimization record (by default, include all passes)
! CHECK-NEXT: -fpass-plugin=<dsopath> Load pass plugin from a dynamic shared object file (only with new pass manager).
! CHECK-NEXT: -freciprocal-math Allow division operations to be reassociated
! CHECK-NEXT: -fsave-optimization-record=<format>
! CHECK-NEXT: Generate an optimization record file in a specific format
! CHECK-NEXT: -fsave-optimization-record
! CHECK-NEXT: Generate a YAML optimization record file
! CHECK-NEXT: -fstack-arrays Attempt to allocate array temporaries on the stack, no matter their size
! CHECK-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages
! CHECK-NEXT: -funderscoring Appends one trailing underscore to external names
Expand Down
14 changes: 14 additions & 0 deletions flang/test/Driver/driver-help.f90
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,16 @@
! HELP-NEXT: -fopenmp-version=<value>
! HELP-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 50 for OpenMP 5.0). Default value is 50 for Clang and 11 for Flang
! HELP-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code.
! HELP-NEXT: -foptimization-record-file=<file>
! HELP-NEXT: Specify the output name of the file containing the optimization remarks. Implies -fsave-optimization-record. On Darwin platforms, this cannot be used with multiple -arch <arch> options.
! HELP-NEXT: -foptimization-record-passes=<regex>
! HELP-NEXT: Only include passes which match a specified regular expression in the generated optimization record (by default, include all passes)
! HELP-NEXT: -fpass-plugin=<dsopath> Load pass plugin from a dynamic shared object file (only with new pass manager).
! HELP-NEXT: -freciprocal-math Allow division operations to be reassociated
! HELP-NEXT: -fsave-optimization-record=<format>
! HELP-NEXT: Generate an optimization record file in a specific format
! HELP-NEXT: -fsave-optimization-record
! HELP-NEXT: Generate a YAML optimization record file
! HELP-NEXT: -fstack-arrays Attempt to allocate array temporaries on the stack, no matter their size
! HELP-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages
! HELP-NEXT: -funderscoring Appends one trailing underscore to external names
Expand Down Expand Up @@ -186,6 +194,12 @@
! HELP-FC1-NEXT: -mrelocation-model <value>
! HELP-FC1-NEXT: The relocation model to use
! HELP-FC1-NEXT: -nocpp Disable predefined and command line preprocessor macros
! HELP-FC1-NEXT: -opt-record-file <value>
! HELP-FC1-NEXT: File name to use for YAML optimization record output
! HELP-FC1-NEXT: -opt-record-format <value>
! HELP-FC1-NEXT: The format used for serializing remarks (default: YAML)
! HELP-FC1-NEXT: -opt-record-passes <value>
! HELP-FC1-NEXT: Only record remark information for passes whose names match the given regular expression
! HELP-FC1-NEXT: -o <file> Write output to <file>
! HELP-FC1-NEXT: -pedantic Warn on language extensions
! HELP-FC1-NEXT: -pic-is-pie File is for a position independent executable
Expand Down

0 comments on commit f04ccad

Please sign in to comment.