Skip to content

Commit a4deb14

Browse files
committed
[LLVM][Support] Support for llvm::cl::list's default values
This patch introduces support for default values of list of CL options. It fixes the issue in #52667 Reviewed By: bkramer Differential Revision: https://reviews.llvm.org/D135311
1 parent 7404b85 commit a4deb14

File tree

4 files changed

+97
-5
lines changed

4 files changed

+97
-5
lines changed

llvm/include/llvm/Support/CommandLine.h

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,10 +437,22 @@ template <class Ty> struct initializer {
437437
template <class Opt> void apply(Opt &O) const { O.setInitialValue(Init); }
438438
};
439439

440+
template <class Ty> struct list_initializer {
441+
ArrayRef<Ty> Inits;
442+
list_initializer(ArrayRef<Ty> Vals) : Inits(Vals) {}
443+
444+
template <class Opt> void apply(Opt &O) const { O.setInitialValues(Inits); }
445+
};
446+
440447
template <class Ty> initializer<Ty> init(const Ty &Val) {
441448
return initializer<Ty>(Val);
442449
}
443450

451+
template <class Ty>
452+
list_initializer<Ty> list_init(ArrayRef<Ty> Vals) {
453+
return list_initializer<Ty>(Vals);
454+
}
455+
444456
// Allow the user to specify which external variable they want to store the
445457
// results of the command line argument processing into, if they don't want to
446458
// store it in the option itself.
@@ -1504,6 +1516,9 @@ extern template class opt<bool>;
15041516
//
15051517
template <class DataType, class StorageClass> class list_storage {
15061518
StorageClass *Location = nullptr; // Where to store the object...
1519+
std::vector<OptionValue<DataType>> Default =
1520+
std::vector<OptionValue<DataType>>();
1521+
bool DefaultAssigned = false;
15071522

15081523
public:
15091524
list_storage() = default;
@@ -1517,12 +1532,22 @@ template <class DataType, class StorageClass> class list_storage {
15171532
return false;
15181533
}
15191534

1520-
template <class T> void addValue(const T &V) {
1535+
template <class T> void addValue(const T &V, bool initial = false) {
15211536
assert(Location != nullptr &&
15221537
"cl::location(...) not specified for a command "
15231538
"line option with external storage!");
15241539
Location->push_back(V);
1540+
if (initial)
1541+
Default.push_back(V);
1542+
}
1543+
1544+
const std::vector<OptionValue<DataType>> &getDefault() const {
1545+
return Default;
15251546
}
1547+
1548+
void assignDefault() { DefaultAssigned = true; }
1549+
void overwriteDefault() { DefaultAssigned = false; }
1550+
bool isDefaultAssigned() { return DefaultAssigned; }
15261551
};
15271552

15281553
// Define how to hold a class type object, such as a string.
@@ -1535,6 +1560,8 @@ template <class DataType, class StorageClass> class list_storage {
15351560
//
15361561
template <class DataType> class list_storage<DataType, bool> {
15371562
std::vector<DataType> Storage;
1563+
std::vector<OptionValue<DataType>> Default;
1564+
bool DefaultAssigned = false;
15381565

15391566
public:
15401567
using iterator = typename std::vector<DataType>::iterator;
@@ -1598,7 +1625,19 @@ template <class DataType> class list_storage<DataType, bool> {
15981625
std::vector<DataType> *operator&() { return &Storage; }
15991626
const std::vector<DataType> *operator&() const { return &Storage; }
16001627

1601-
template <class T> void addValue(const T &V) { Storage.push_back(V); }
1628+
template <class T> void addValue(const T &V, bool initial = false) {
1629+
Storage.push_back(V);
1630+
if (initial)
1631+
Default.push_back(OptionValue<DataType>(V));
1632+
}
1633+
1634+
const std::vector<OptionValue<DataType>> &getDefault() const {
1635+
return Default;
1636+
}
1637+
1638+
void assignDefault() { DefaultAssigned = true; }
1639+
void overwriteDefault() { DefaultAssigned = false; }
1640+
bool isDefaultAssigned() { return DefaultAssigned; }
16021641
};
16031642

16041643
//===----------------------------------------------------------------------===//
@@ -1622,6 +1661,10 @@ class list : public Option, public list_storage<DataType, StorageClass> {
16221661
StringRef Arg) override {
16231662
typename ParserClass::parser_data_type Val =
16241663
typename ParserClass::parser_data_type();
1664+
if (list_storage<DataType, StorageClass>::isDefaultAssigned()) {
1665+
clear();
1666+
list_storage<DataType, StorageClass>::overwriteDefault();
1667+
}
16251668
if (Parser.parse(*this, ArgName, Arg, Val))
16261669
return true; // Parse Error!
16271670
list_storage<DataType, StorageClass>::addValue(Val);
@@ -1647,6 +1690,8 @@ class list : public Option, public list_storage<DataType, StorageClass> {
16471690
void setDefault() override {
16481691
Positions.clear();
16491692
list_storage<DataType, StorageClass>::clear();
1693+
for (auto &Val : list_storage<DataType, StorageClass>::getDefault())
1694+
list_storage<DataType, StorageClass>::addValue(Val.getValue());
16501695
}
16511696

16521697
void done() {
@@ -1666,6 +1711,20 @@ class list : public Option, public list_storage<DataType, StorageClass> {
16661711
return Positions[optnum];
16671712
}
16681713

1714+
void clear() {
1715+
Positions.clear();
1716+
list_storage<DataType, StorageClass>::clear();
1717+
}
1718+
1719+
// setInitialValues - Used by the cl::list_init modifier...
1720+
void setInitialValues(ArrayRef<DataType> Vs) {
1721+
assert(!(list_storage<DataType, StorageClass>::isDefaultAssigned()) &&
1722+
"Cannot have two default values");
1723+
list_storage<DataType, StorageClass>::assignDefault();
1724+
for (auto &Val : Vs)
1725+
list_storage<DataType, StorageClass>::addValue(Val, true);
1726+
}
1727+
16691728
void setNumAdditionalVals(unsigned n) { Option::setNumAdditionalVals(n); }
16701729

16711730
template <class... Mods>

llvm/unittests/Support/CommandLineTest.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,23 +1038,40 @@ TEST(CommandLineTest, ResponseFileEOLs) {
10381038
}
10391039
}
10401040

1041-
TEST(CommandLineTest, SetDefautValue) {
1041+
TEST(CommandLineTest, SetDefaultValue) {
10421042
cl::ResetCommandLineParser();
10431043

10441044
StackOption<std::string> Opt1("opt1", cl::init("true"));
10451045
StackOption<bool> Opt2("opt2", cl::init(true));
10461046
cl::alias Alias("alias", llvm::cl::aliasopt(Opt2));
10471047
StackOption<int> Opt3("opt3", cl::init(3));
10481048

1049-
const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"};
1049+
llvm::SmallVector<int, 3> IntVals = {1, 2, 3};
1050+
llvm::SmallVector<std::string, 3> StrVals = {"foo", "bar", "baz"};
1051+
1052+
StackOption<int, cl::list<int>> List1(
1053+
"list1", cl::list_init<int>(llvm::ArrayRef<int>(IntVals)),
1054+
cl::CommaSeparated);
1055+
StackOption<std::string, cl::list<std::string>> List2(
1056+
"list2", cl::list_init<std::string>(llvm::ArrayRef<std::string>(StrVals)),
1057+
cl::CommaSeparated);
1058+
cl::alias ListAlias("list-alias", llvm::cl::aliasopt(List2));
1059+
1060+
const char *args[] = {"prog", "-opt1=false", "-list1", "4",
1061+
"-list1", "5,6", "-opt2", "-opt3"};
10501062

10511063
EXPECT_TRUE(
1052-
cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
1064+
cl::ParseCommandLineOptions(7, args, StringRef(), &llvm::nulls()));
10531065

10541066
EXPECT_EQ(Opt1, "false");
10551067
EXPECT_TRUE(Opt2);
10561068
EXPECT_EQ(Opt3, 3);
10571069

1070+
for (size_t I = 0, E = IntVals.size(); I < E; ++I) {
1071+
EXPECT_EQ(IntVals[I] + 3, List1[I]);
1072+
EXPECT_EQ(StrVals[I], List2[I]);
1073+
}
1074+
10581075
Opt2 = false;
10591076
Opt3 = 1;
10601077

@@ -1071,7 +1088,13 @@ TEST(CommandLineTest, SetDefautValue) {
10711088
EXPECT_EQ(Opt1, "true");
10721089
EXPECT_TRUE(Opt2);
10731090
EXPECT_EQ(Opt3, 3);
1091+
for (size_t I = 0, E = IntVals.size(); I < E; ++I) {
1092+
EXPECT_EQ(IntVals[I], List1[I]);
1093+
EXPECT_EQ(StrVals[I], List2[I]);
1094+
}
1095+
10741096
Alias.removeArgument();
1097+
ListAlias.removeArgument();
10751098
}
10761099

10771100
TEST(CommandLineTest, ReadConfigFile) {

mlir/include/mlir/Pass/PassOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ class PassOptions : protected llvm::cl::SubCommand {
229229

230230
bool handleOccurrence(unsigned pos, StringRef argName,
231231
StringRef arg) override {
232+
if (this->isDefaultAssigned()) {
233+
this->clear();
234+
this->overwriteDefault();
235+
}
232236
this->optHasValue = true;
233237
return failed(detail::pass_options::parseCommaSeparatedList(
234238
*this, argName, arg, elementParser,
@@ -418,6 +422,7 @@ struct OptionValue<mlir::OpPassManager> final : GenericOptionValue {
418422
using WrapperType = mlir::OpPassManager;
419423

420424
OptionValue();
425+
OptionValue(const OptionValue<mlir::OpPassManager> &rhs);
421426
OptionValue(const mlir::OpPassManager &value);
422427
OptionValue<mlir::OpPassManager> &operator=(const mlir::OpPassManager &rhs);
423428
~OptionValue();

mlir/lib/Pass/PassRegistry.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ llvm::cl::OptionValue<OpPassManager>::OptionValue(
348348
const mlir::OpPassManager &value) {
349349
setValue(value);
350350
}
351+
llvm::cl::OptionValue<OpPassManager>::OptionValue(
352+
const llvm::cl::OptionValue<mlir::OpPassManager> &rhs) {
353+
if (rhs.hasValue())
354+
setValue(rhs.getValue());
355+
}
351356
llvm::cl::OptionValue<OpPassManager> &
352357
llvm::cl::OptionValue<OpPassManager>::operator=(
353358
const mlir::OpPassManager &rhs) {

0 commit comments

Comments
 (0)