diff --git a/mlir/include/mlir/Pass/PassOptions.h b/mlir/include/mlir/Pass/PassOptions.h index b99d91f07dd1c..6bffa84f7b16b 100644 --- a/mlir/include/mlir/Pass/PassOptions.h +++ b/mlir/include/mlir/Pass/PassOptions.h @@ -60,6 +60,20 @@ template static void printOptionValue(raw_ostream &os, const bool &value) { os << (value ? StringRef("true") : StringRef("false")); } +template +static void printOptionValue(raw_ostream &os, const std::string &str) { + // Check if the string needs to be escaped before writing it to the ostream. + const size_t spaceIndex = str.find_first_of(' '); + const size_t escapeIndex = + std::min({str.find_first_of('{'), str.find_first_of('\''), + str.find_first_of('"')}); + const bool requiresEscape = spaceIndex < escapeIndex; + if (requiresEscape) + os << "{"; + os << str; + if (requiresEscape) + os << "}"; +} template static std::enable_if_t::value> printOptionValue(raw_ostream &os, const DataT &value) { diff --git a/mlir/lib/Pass/PassRegistry.cpp b/mlir/lib/Pass/PassRegistry.cpp index f8149673a4093..483cbe80faba6 100644 --- a/mlir/lib/Pass/PassRegistry.cpp +++ b/mlir/lib/Pass/PassRegistry.cpp @@ -218,6 +218,20 @@ parseNextArg(StringRef options) { auto extractArgAndUpdateOptions = [&](size_t argSize) { StringRef str = options.take_front(argSize).trim(); options = options.drop_front(argSize).ltrim(); + // Handle escape sequences + if (str.size() > 2) { + const auto escapePairs = {std::make_pair('\'', '\''), + std::make_pair('"', '"'), + std::make_pair('{', '}')}; + for (const auto &escape : escapePairs) { + if (str.front() == escape.first && str.back() == escape.second) { + // Drop the escape characters and trim. + str = str.drop_front().drop_back().trim(); + // Don't process additional escape sequences. + break; + } + } + } return str; }; // Try to process the given punctuation, properly escaping any contained diff --git a/mlir/test/Pass/pipeline-options-parsing.mlir b/mlir/test/Pass/pipeline-options-parsing.mlir index 34313cd556603..50f08241ee5cf 100644 --- a/mlir/test/Pass/pipeline-options-parsing.mlir +++ b/mlir/test/Pass/pipeline-options-parsing.mlir @@ -7,6 +7,10 @@ // 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 // 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 // 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 +// 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 +// 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 +// 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 +// 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 // CHECK_ERROR_1: missing closing '}' while processing pass options // CHECK_ERROR_2: no such option test-option @@ -17,3 +21,6 @@ // 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} // CHECK_2: test-options-pass{enum=one list=1 string= string-list=a,b} // 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= }))) +// 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 }))) +// 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} }))) +// 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 })))