diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -437,10 +437,22 @@ template void apply(Opt &O) const { O.setInitialValue(Init); } }; +template struct list_initializer { + ArrayRef Inits; + list_initializer(ArrayRef Vals) : Inits(Vals) {} + + template void apply(Opt &O) const { O.setInitialValues(Inits); } +}; + template initializer init(const Ty &Val) { return initializer(Val); } +template +list_initializer list_init(ArrayRef Vals) { + return list_initializer(Vals); +} + // Allow the user to specify which external variable they want to store the // results of the command line argument processing into, if they don't want to // store it in the option itself. @@ -1504,6 +1516,9 @@ // template class list_storage { StorageClass *Location = nullptr; // Where to store the object... + std::vector> Default = + std::vector>(); + bool DefaultAssigned = false; public: list_storage() = default; @@ -1517,12 +1532,22 @@ return false; } - template void addValue(const T &V) { + template void addValue(const T &V, bool initial = false) { assert(Location != nullptr && "cl::location(...) not specified for a command " "line option with external storage!"); Location->push_back(V); + if (initial) + Default.push_back(V); + } + + const std::vector> &getDefault() const { + return Default; } + + void assignDefault() { DefaultAssigned = true; } + void overwriteDefault() { DefaultAssigned = false; } + bool isDefaultAssigned() { return DefaultAssigned; } }; // Define how to hold a class type object, such as a string. @@ -1535,6 +1560,8 @@ // template class list_storage { std::vector Storage; + std::vector> Default; + bool DefaultAssigned = false; public: using iterator = typename std::vector::iterator; @@ -1598,7 +1625,19 @@ std::vector *operator&() { return &Storage; } const std::vector *operator&() const { return &Storage; } - template void addValue(const T &V) { Storage.push_back(V); } + template void addValue(const T &V, bool initial = false) { + Storage.push_back(V); + if (initial) + Default.push_back(OptionValue(V)); + } + + const std::vector> &getDefault() const { + return Default; + } + + void assignDefault() { DefaultAssigned = true; } + void overwriteDefault() { DefaultAssigned = false; } + bool isDefaultAssigned() { return DefaultAssigned; } }; //===----------------------------------------------------------------------===// @@ -1622,6 +1661,10 @@ StringRef Arg) override { typename ParserClass::parser_data_type Val = typename ParserClass::parser_data_type(); + if (list_storage::isDefaultAssigned()) { + clear(); + list_storage::overwriteDefault(); + } if (Parser.parse(*this, ArgName, Arg, Val)) return true; // Parse Error! list_storage::addValue(Val); @@ -1647,6 +1690,8 @@ void setDefault() override { Positions.clear(); list_storage::clear(); + for (auto &Val : list_storage::getDefault()) + list_storage::addValue(Val.getValue()); } void done() { @@ -1666,6 +1711,20 @@ return Positions[optnum]; } + void clear() { + Positions.clear(); + list_storage::clear(); + } + + // setInitialValues - Used by the cl::list_init modifier... + void setInitialValues(ArrayRef Vs) { + assert(!(list_storage::isDefaultAssigned()) && + "Cannot have two default values"); + list_storage::assignDefault(); + for (auto &Val : Vs) + list_storage::addValue(Val, true); + } + void setNumAdditionalVals(unsigned n) { Option::setNumAdditionalVals(n); } template diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -1038,7 +1038,7 @@ } } -TEST(CommandLineTest, SetDefautValue) { +TEST(CommandLineTest, SetDefaultValue) { cl::ResetCommandLineParser(); StackOption Opt1("opt1", cl::init("true")); @@ -1046,15 +1046,32 @@ cl::alias Alias("alias", llvm::cl::aliasopt(Opt2)); StackOption Opt3("opt3", cl::init(3)); - const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"}; + llvm::SmallVector IntVals = {1, 2, 3}; + llvm::SmallVector StrVals = {"foo", "bar", "baz"}; + + StackOption> List1( + "list1", cl::list_init(llvm::ArrayRef(IntVals)), + cl::CommaSeparated); + StackOption> List2( + "list2", cl::list_init(llvm::ArrayRef(StrVals)), + cl::CommaSeparated); + cl::alias ListAlias("list-alias", llvm::cl::aliasopt(List2)); + + const char *args[] = {"prog", "-opt1=false", "-list1", "4", + "-list1", "5,6", "-opt2", "-opt3"}; EXPECT_TRUE( - cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); + cl::ParseCommandLineOptions(7, args, StringRef(), &llvm::nulls())); EXPECT_EQ(Opt1, "false"); EXPECT_TRUE(Opt2); EXPECT_EQ(Opt3, 3); + for (size_t I = 0, E = IntVals.size(); I < E; ++I) { + EXPECT_EQ(IntVals[I] + 3, List1[I]); + EXPECT_EQ(StrVals[I], List2[I]); + } + Opt2 = false; Opt3 = 1; @@ -1071,7 +1088,13 @@ EXPECT_EQ(Opt1, "true"); EXPECT_TRUE(Opt2); EXPECT_EQ(Opt3, 3); + for (size_t I = 0, E = IntVals.size(); I < E; ++I) { + EXPECT_EQ(IntVals[I], List1[I]); + EXPECT_EQ(StrVals[I], List2[I]); + } + Alias.removeArgument(); + ListAlias.removeArgument(); } TEST(CommandLineTest, ReadConfigFile) { diff --git a/mlir/include/mlir/Pass/PassOptions.h b/mlir/include/mlir/Pass/PassOptions.h --- a/mlir/include/mlir/Pass/PassOptions.h +++ b/mlir/include/mlir/Pass/PassOptions.h @@ -229,6 +229,10 @@ bool handleOccurrence(unsigned pos, StringRef argName, StringRef arg) override { + if (this->isDefaultAssigned()) { + this->clear(); + this->overwriteDefault(); + } this->optHasValue = true; return failed(detail::pass_options::parseCommaSeparatedList( *this, argName, arg, elementParser, @@ -418,6 +422,7 @@ using WrapperType = mlir::OpPassManager; OptionValue(); + OptionValue(const OptionValue &rhs); OptionValue(const mlir::OpPassManager &value); OptionValue &operator=(const mlir::OpPassManager &rhs); ~OptionValue(); diff --git a/mlir/lib/Pass/PassRegistry.cpp b/mlir/lib/Pass/PassRegistry.cpp --- a/mlir/lib/Pass/PassRegistry.cpp +++ b/mlir/lib/Pass/PassRegistry.cpp @@ -348,6 +348,11 @@ const mlir::OpPassManager &value) { setValue(value); } +llvm::cl::OptionValue::OptionValue( + const llvm::cl::OptionValue &rhs) { + if (rhs.hasValue()) + setValue(rhs.getValue()); +} llvm::cl::OptionValue & llvm::cl::OptionValue::operator=( const mlir::OpPassManager &rhs) {