[Mlir-commits] [mlir] 7476e56 - [mlir][Pass] Enable printing pass options as part of `-help`.
River Riddle
llvmlistbot at llvm.org
Fri Feb 7 14:18:01 PST 2020
Author: River Riddle
Date: 2020-02-07T14:11:50-08:00
New Revision: 7476e569b55ab260522751e9c2e8c5646956f8d1
URL: https://github.com/llvm/llvm-project/commit/7476e569b55ab260522751e9c2e8c5646956f8d1
DIFF: https://github.com/llvm/llvm-project/commit/7476e569b55ab260522751e9c2e8c5646956f8d1.diff
LOG: [mlir][Pass] Enable printing pass options as part of `-help`.
Summary:
This revision adds support for printing pass options as part of the normal help description. This also moves registered passes and pipelines into different sections of the help.
Example:
```
Compiler passes to run
--pass-pipeline - ...
Passes:
--affine-data-copy-generate - ...
--convert-gpu-to-spirv - ...
--workgroup-size=<long> - ...
--test-options-pass - ...
--list=<int> - ...
--string=<string> - ...
--string-list=<string> - ...
Pass Pipelines:
--test-options-pass-pipeline - ...
--list=<int> - ...
--string=<string> - ...
--string-list=<string> - ...
```
Differential Revision: https://reviews.llvm.org/D74246
Added:
Modified:
mlir/include/mlir/Pass/Pass.h
mlir/include/mlir/Pass/PassOptions.h
mlir/include/mlir/Pass/PassRegistry.h
mlir/lib/Pass/PassRegistry.cpp
Removed:
################################################################################
diff --git a/mlir/include/mlir/Pass/Pass.h b/mlir/include/mlir/Pass/Pass.h
index 1ff64a276be8..279aeac2429a 100644
--- a/mlir/include/mlir/Pass/Pass.h
+++ b/mlir/include/mlir/Pass/Pass.h
@@ -121,6 +121,7 @@ class Pass {
protected:
explicit Pass(const PassID *passID, Optional<StringRef> opName = llvm::None)
: passID(passID), opName(opName) {}
+ Pass(const Pass &other) : Pass(other.passID, other.opName) {}
/// Returns the current pass state.
detail::PassExecutionState &getPassState() {
@@ -178,6 +179,9 @@ class Pass {
/// Allow access to 'clone' and 'run'.
friend class OpPassManager;
+
+ /// Allow access to 'passOptions'.
+ friend class PassInfo;
};
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Pass/PassOptions.h b/mlir/include/mlir/Pass/PassOptions.h
index c6e2eb60fb5e..7b35609b8c32 100644
--- a/mlir/include/mlir/Pass/PassOptions.h
+++ b/mlir/include/mlir/Pass/PassOptions.h
@@ -182,6 +182,9 @@ class PassOptions : protected llvm::cl::SubCommand {
};
PassOptions() = default;
+ /// Delete the copy constructor to avoid copying the internal options map.
+ PassOptions(const PassOptions &) = delete;
+ PassOptions(PassOptions &&) = delete;
/// Copy the option values from 'other' into 'this', where 'other' has the
/// same options as 'this'.
@@ -196,6 +199,13 @@ class PassOptions : protected llvm::cl::SubCommand {
/// 'parseFromString'.
void print(raw_ostream &os);
+ /// Print the help string for the options held by this struct. `descIndent` is
+ /// the indent that the descriptions should be aligned.
+ void printHelp(size_t indent, size_t descIndent) const;
+
+ /// Return the maximum width required when printing the help string.
+ size_t getOptionWidth() const;
+
private:
/// A list of all of the opaque options.
std::vector<OptionBase *> options;
diff --git a/mlir/include/mlir/Pass/PassRegistry.h b/mlir/include/mlir/Pass/PassRegistry.h
index 5324302e6089..fab118d229c6 100644
--- a/mlir/include/mlir/Pass/PassRegistry.h
+++ b/mlir/include/mlir/Pass/PassRegistry.h
@@ -21,6 +21,10 @@ namespace mlir {
class OpPassManager;
class Pass;
+namespace detail {
+class PassOptions;
+} // end namespace detail
+
/// A registry function that adds passes to the given pass manager. This should
/// also parse options and return success() if parsing succeeded.
using PassRegistryFunction =
@@ -55,28 +59,45 @@ class PassRegistryEntry {
/// Returns a description for the pass, this never returns null.
StringRef getPassDescription() const { return description; }
+ /// Print the help information for this pass. This includes the argument,
+ /// description, and any pass options. `descIndent` is the indent that the
+ /// descriptions should be aligned.
+ void printHelpStr(size_t indent, size_t descIndent) const;
+
+ /// Return the maximum width required when printing the options of this entry.
+ size_t getOptionWidth() const;
+
protected:
- PassRegistryEntry(StringRef arg, StringRef description,
- const PassRegistryFunction &builder)
- : arg(arg), description(description), builder(builder) {}
+ PassRegistryEntry(
+ StringRef arg, StringRef description, const PassRegistryFunction &builder,
+ std::function<void(function_ref<void(const detail::PassOptions &)>)>
+ optHandler)
+ : arg(arg), description(description), builder(builder),
+ optHandler(optHandler) {}
private:
- // The argument with which to invoke the pass via mlir-opt.
+ /// The argument with which to invoke the pass via mlir-opt.
StringRef arg;
- // Description of the pass.
+ /// Description of the pass.
StringRef description;
- // Function to register this entry to a pass manager pipeline.
+ /// Function to register this entry to a pass manager pipeline.
PassRegistryFunction builder;
+
+ /// Function to invoke a handler for a pass options instance.
+ std::function<void(function_ref<void(const detail::PassOptions &)>)>
+ optHandler;
};
/// A structure to represent the information of a registered pass pipeline.
class PassPipelineInfo : public PassRegistryEntry {
public:
- PassPipelineInfo(StringRef arg, StringRef description,
- const PassRegistryFunction &builder)
- : PassRegistryEntry(arg, description, builder) {}
+ PassPipelineInfo(
+ StringRef arg, StringRef description, const PassRegistryFunction &builder,
+ std::function<void(function_ref<void(const detail::PassOptions &)>)>
+ optHandler)
+ : PassRegistryEntry(arg, description, builder, optHandler) {}
};
/// A structure to represent the information for a derived pass class.
@@ -94,8 +115,10 @@ class PassInfo : public PassRegistryEntry {
/// Register a specific dialect pipeline registry function with the system,
/// typically used through the PassPipelineRegistration template.
-void registerPassPipeline(StringRef arg, StringRef description,
- const PassRegistryFunction &function);
+void registerPassPipeline(
+ StringRef arg, StringRef description, const PassRegistryFunction &function,
+ std::function<void(function_ref<void(const detail::PassOptions &)>)>
+ optHandler);
/// Register a specific dialect pass allocator function with the system,
/// typically used through the PassRegistration template.
@@ -113,7 +136,6 @@ void registerPass(StringRef arg, StringRef description, const PassID *passID,
/// static PassRegistration<MyPass> reg("my-pass", "My Pass Description.");
///
template <typename ConcretePass> struct PassRegistration {
-
PassRegistration(StringRef arg, StringRef description,
const PassAllocatorFunction &constructor) {
registerPass(arg, description, PassID::getID<ConcretePass>(), constructor);
@@ -142,14 +164,18 @@ struct PassPipelineRegistration {
PassPipelineRegistration(
StringRef arg, StringRef description,
std::function<void(OpPassManager &, const Options &options)> builder) {
- registerPassPipeline(arg, description,
- [builder](OpPassManager &pm, StringRef optionsStr) {
- Options options;
- if (failed(options.parseFromString(optionsStr)))
- return failure();
- builder(pm, options);
- return success();
- });
+ registerPassPipeline(
+ arg, description,
+ [builder](OpPassManager &pm, StringRef optionsStr) {
+ Options options;
+ if (failed(options.parseFromString(optionsStr)))
+ return failure();
+ builder(pm, options);
+ return success();
+ },
+ [](function_ref<void(const detail::PassOptions &)> optHandler) {
+ optHandler(Options());
+ });
}
};
@@ -158,13 +184,15 @@ struct PassPipelineRegistration {
template <> struct PassPipelineRegistration<EmptyPipelineOptions> {
PassPipelineRegistration(StringRef arg, StringRef description,
std::function<void(OpPassManager &)> builder) {
- registerPassPipeline(arg, description,
- [builder](OpPassManager &pm, StringRef optionsStr) {
- if (!optionsStr.empty())
- return failure();
- builder(pm);
- return success();
- });
+ registerPassPipeline(
+ arg, description,
+ [builder](OpPassManager &pm, StringRef optionsStr) {
+ if (!optionsStr.empty())
+ return failure();
+ builder(pm);
+ return success();
+ },
+ [](function_ref<void(const detail::PassOptions &)>) {});
}
};
diff --git a/mlir/lib/Pass/PassRegistry.cpp b/mlir/lib/Pass/PassRegistry.cpp
index fe2bae340972..403bac944ec1 100644
--- a/mlir/lib/Pass/PassRegistry.cpp
+++ b/mlir/lib/Pass/PassRegistry.cpp
@@ -35,13 +35,48 @@ buildDefaultRegistryFn(const PassAllocatorFunction &allocator) {
};
}
+/// Utility to print the help string for a specific option.
+void printOptionHelp(StringRef arg, StringRef desc, size_t indent,
+ size_t descIndent, bool isTopLevel) {
+ size_t numSpaces = descIndent - indent - 4;
+ llvm::outs().indent(indent)
+ << "--" << llvm::left_justify(arg, numSpaces) << "- " << desc << '\n';
+}
+
+//===----------------------------------------------------------------------===//
+// PassRegistry
+//===----------------------------------------------------------------------===//
+
+/// Print the help information for this pass. This includes the argument,
+/// description, and any pass options. `descIndent` is the indent that the
+/// descriptions should be aligned.
+void PassRegistryEntry::printHelpStr(size_t indent, size_t descIndent) const {
+ printOptionHelp(getPassArgument(), getPassDescription(), indent, descIndent,
+ /*isTopLevel=*/true);
+ // If this entry has options, print the help for those as well.
+ optHandler([=](const PassOptions &options) {
+ options.printHelp(indent, descIndent);
+ });
+}
+
+/// Return the maximum width required when printing the options of this
+/// entry.
+size_t PassRegistryEntry::getOptionWidth() const {
+ size_t maxLen = 0;
+ optHandler([&](const PassOptions &options) mutable {
+ maxLen = options.getOptionWidth() + 2;
+ });
+ return maxLen;
+}
+
//===----------------------------------------------------------------------===//
// PassPipelineInfo
//===----------------------------------------------------------------------===//
-void mlir::registerPassPipeline(StringRef arg, StringRef description,
- const PassRegistryFunction &function) {
- PassPipelineInfo pipelineInfo(arg, description, function);
+void mlir::registerPassPipeline(
+ StringRef arg, StringRef description, const PassRegistryFunction &function,
+ std::function<void(function_ref<void(const PassOptions &)>)> optHandler) {
+ PassPipelineInfo pipelineInfo(arg, description, function, optHandler);
bool inserted = passPipelineRegistry->try_emplace(arg, pipelineInfo).second;
assert(inserted && "Pass pipeline registered multiple times");
(void)inserted;
@@ -53,7 +88,12 @@ void mlir::registerPassPipeline(StringRef arg, StringRef description,
PassInfo::PassInfo(StringRef arg, StringRef description, const PassID *passID,
const PassAllocatorFunction &allocator)
- : PassRegistryEntry(arg, description, buildDefaultRegistryFn(allocator)) {}
+ : PassRegistryEntry(
+ arg, description, buildDefaultRegistryFn(allocator),
+ // Use a temporary pass to provide an options instance.
+ [=](function_ref<void(const PassOptions &)> optHandler) {
+ optHandler(allocator()->passOptions);
+ }) {}
void mlir::registerPass(StringRef arg, StringRef description,
const PassID *passID,
@@ -137,20 +177,46 @@ void detail::PassOptions::print(raw_ostream &os) {
return;
// Sort the options to make the ordering deterministic.
- SmallVector<OptionBase *, 4> orderedOptions(options.begin(), options.end());
- llvm::array_pod_sort(orderedOptions.begin(), orderedOptions.end(),
- [](OptionBase *const *lhs, OptionBase *const *rhs) {
- return (*lhs)->getArgStr().compare(
- (*rhs)->getArgStr());
- });
+ SmallVector<OptionBase *, 4> orderedOps(options.begin(), options.end());
+ auto compareOptionArgs = [](OptionBase *const *lhs, OptionBase *const *rhs) {
+ return (*lhs)->getArgStr().compare((*rhs)->getArgStr());
+ };
+ llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs);
// Interleave the options with ' '.
os << '{';
interleave(
- orderedOptions, os, [&](OptionBase *option) { option->print(os); }, " ");
+ orderedOps, os, [&](OptionBase *option) { option->print(os); }, " ");
os << '}';
}
+/// Print the help string for the options held by this struct. `descIndent` is
+/// the indent within the stream that the descriptions should be aligned.
+void detail::PassOptions::printHelp(size_t indent, size_t descIndent) const {
+ // Sort the options to make the ordering deterministic.
+ SmallVector<OptionBase *, 4> orderedOps(options.begin(), options.end());
+ auto compareOptionArgs = [](OptionBase *const *lhs, OptionBase *const *rhs) {
+ return (*lhs)->getArgStr().compare((*rhs)->getArgStr());
+ };
+ llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs);
+ for (OptionBase *option : orderedOps) {
+ // TODO(riverriddle) printOptionInfo assumes a specific indent and will
+ // print options with values with incorrect indentation. We should add
+ // support to llvm::cl::Option for passing in a base indent to use when
+ // printing.
+ llvm::outs().indent(indent);
+ option->getOption()->printOptionInfo(descIndent - indent);
+ }
+}
+
+/// Return the maximum width required when printing the help string.
+size_t detail::PassOptions::getOptionWidth() const {
+ size_t max = 0;
+ for (auto *option : options)
+ max = std::max(max, option->getOption()->getOptionWidth());
+ return max;
+}
+
//===----------------------------------------------------------------------===//
// TextualPassPipeline Parser
//===----------------------------------------------------------------------===//
@@ -443,6 +509,7 @@ struct PassNameParser : public llvm::cl::parser<PassArgData> {
void initialize();
void printOptionInfo(const llvm::cl::Option &opt,
size_t globalWidth) const override;
+ size_t getOptionWidth(const llvm::cl::Option &opt) const override;
bool parse(llvm::cl::Option &opt, StringRef argName, StringRef arg,
PassArgData &value);
};
@@ -467,15 +534,54 @@ void PassNameParser::initialize() {
}
}
-void PassNameParser::printOptionInfo(const llvm::cl::Option &O,
- size_t GlobalWidth) const {
- PassNameParser *TP = const_cast<PassNameParser *>(this);
- llvm::array_pod_sort(TP->Values.begin(), TP->Values.end(),
- [](const PassNameParser::OptionInfo *VT1,
- const PassNameParser::OptionInfo *VT2) {
- return VT1->Name.compare(VT2->Name);
- });
- llvm::cl::parser<PassArgData>::printOptionInfo(O, GlobalWidth);
+void PassNameParser::printOptionInfo(const llvm::cl::Option &opt,
+ size_t globalWidth) const {
+ // Print the information for the top-level option.
+ if (opt.hasArgStr()) {
+ llvm::outs() << " --" << opt.ArgStr;
+ opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 7);
+ } else {
+ llvm::outs() << " " << opt.HelpStr << '\n';
+ }
+
+ // Print the top-level pipeline argument.
+ printOptionHelp(passPipelineArg,
+ "A textual description of a pass pipeline to run",
+ /*indent=*/4, globalWidth, /*isTopLevel=*/!opt.hasArgStr());
+
+ // Functor used to print the ordered entries of a registration map.
+ auto printOrderedEntries = [&](StringRef header, auto &map) {
+ llvm::SmallVector<PassRegistryEntry *, 32> orderedEntries;
+ for (auto &kv : map)
+ orderedEntries.push_back(&kv.second);
+ llvm::array_pod_sort(
+ orderedEntries.begin(), orderedEntries.end(),
+ [](PassRegistryEntry *const *lhs, PassRegistryEntry *const *rhs) {
+ return (*lhs)->getPassArgument().compare((*rhs)->getPassArgument());
+ });
+
+ llvm::outs().indent(4) << header << ":\n";
+ for (PassRegistryEntry *entry : orderedEntries)
+ entry->printHelpStr(/*indent=*/6, globalWidth);
+ };
+
+ // Print the available passes.
+ printOrderedEntries("Passes", *passRegistry);
+
+ // Print the available pass pipelines.
+ if (!passPipelineRegistry->empty())
+ printOrderedEntries("Pass Pipelines", *passPipelineRegistry);
+}
+
+size_t PassNameParser::getOptionWidth(const llvm::cl::Option &opt) const {
+ size_t maxWidth = llvm::cl::parser<PassArgData>::getOptionWidth(opt) + 2;
+
+ // Check for any wider pass or pipeline options.
+ for (auto &entry : *passRegistry)
+ maxWidth = std::max(maxWidth, entry.second.getOptionWidth() + 4);
+ for (auto &entry : *passPipelineRegistry)
+ maxWidth = std::max(maxWidth, entry.second.getOptionWidth() + 4);
+ return maxWidth;
}
bool PassNameParser::parse(llvm::cl::Option &opt, StringRef argName,
More information about the Mlir-commits
mailing list