Skip to content

Commit 27bb2a3

Browse files
authored
[mlir][Pass] Handle escaped pipline option values (#97667)
The PassRegistry parser properly handles escape tokens (', ", {}) when parsing pass options from string but then does not strip the escape tokens when providing the values back to the caller. This change updates the parser such that escape tokens are properly removed and whitespace is trimmed when extracting option values.
1 parent a14a53e commit 27bb2a3

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

mlir/include/mlir/Pass/PassOptions.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ template <typename ParserT>
6060
static void printOptionValue(raw_ostream &os, const bool &value) {
6161
os << (value ? StringRef("true") : StringRef("false"));
6262
}
63+
template <typename ParserT>
64+
static void printOptionValue(raw_ostream &os, const std::string &str) {
65+
// Check if the string needs to be escaped before writing it to the ostream.
66+
const size_t spaceIndex = str.find_first_of(' ');
67+
const size_t escapeIndex =
68+
std::min({str.find_first_of('{'), str.find_first_of('\''),
69+
str.find_first_of('"')});
70+
const bool requiresEscape = spaceIndex < escapeIndex;
71+
if (requiresEscape)
72+
os << "{";
73+
os << str;
74+
if (requiresEscape)
75+
os << "}";
76+
}
6377
template <typename ParserT, typename DataT>
6478
static std::enable_if_t<has_stream_operator<DataT>::value>
6579
printOptionValue(raw_ostream &os, const DataT &value) {

mlir/lib/Pass/PassRegistry.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,20 @@ parseNextArg(StringRef options) {
218218
auto extractArgAndUpdateOptions = [&](size_t argSize) {
219219
StringRef str = options.take_front(argSize).trim();
220220
options = options.drop_front(argSize).ltrim();
221+
// Handle escape sequences
222+
if (str.size() > 2) {
223+
const auto escapePairs = {std::make_pair('\'', '\''),
224+
std::make_pair('"', '"'),
225+
std::make_pair('{', '}')};
226+
for (const auto &escape : escapePairs) {
227+
if (str.front() == escape.first && str.back() == escape.second) {
228+
// Drop the escape characters and trim.
229+
str = str.drop_front().drop_back().trim();
230+
// Don't process additional escape sequences.
231+
break;
232+
}
233+
}
234+
}
221235
return str;
222236
};
223237
// Try to process the given punctuation, properly escaping any contained

mlir/test/Pass/pipeline-options-parsing.mlir

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='builtin.module(func.func(test-options-pass{string-list=a list=1,2,3,4 string-list=b,c list=5 string-list=d string=nested_pipeline{arg1=10 arg2=" {} " arg3=true}}))' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_1 %s
88
// RUN: mlir-opt %s -verify-each=false -test-options-pass-pipeline='list=1 string-list=a,b enum=one' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_2 %s
99
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='builtin.module(builtin.module(func.func(test-options-pass{list=3}), func.func(test-options-pass{enum=one list=1,2,3,4})))' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_3 %s
10+
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='builtin.module(builtin.module(func.func(test-options-pass{list=3}), func.func(test-options-pass{enum=one list=1,2,3,4 string="foobar"})))' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_4 %s
11+
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='builtin.module(builtin.module(func.func(test-options-pass{list=3}), func.func(test-options-pass{enum=one list=1,2,3,4 string="foo bar baz"})))' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_5 %s
12+
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='builtin.module(builtin.module(func.func(test-options-pass{list=3}), func.func(test-options-pass{enum=one list=1,2,3,4 string={foo bar baz}})))' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_5 %s
13+
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='builtin.module(builtin.module(func.func(test-options-pass{list=3}), func.func(test-options-pass{enum=one list=1,2,3,4 string=foo"bar"baz})))' -dump-pass-pipeline 2>&1 | FileCheck --check-prefix=CHECK_6 %s
1014

1115
// CHECK_ERROR_1: missing closing '}' while processing pass options
1216
// CHECK_ERROR_2: no such option test-option
@@ -17,3 +21,6 @@
1721
// CHECK_1: test-options-pass{enum=zero list=1,2,3,4,5 string=nested_pipeline{arg1=10 arg2=" {} " arg3=true} string-list=a,b,c,d}
1822
// CHECK_2: test-options-pass{enum=one list=1 string= string-list=a,b}
1923
// CHECK_3: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list=3 string= }),func.func(test-options-pass{enum=one list=1,2,3,4 string= })))
24+
// CHECK_4: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list=3 string= }),func.func(test-options-pass{enum=one list=1,2,3,4 string=foobar })))
25+
// CHECK_5: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list=3 string= }),func.func(test-options-pass{enum=one list=1,2,3,4 string={foo bar baz} })))
26+
// CHECK_6: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list=3 string= }),func.func(test-options-pass{enum=one list=1,2,3,4 string=foo"bar"baz })))

0 commit comments

Comments
 (0)