Skip to content

Commit 229e392

Browse files
committed
[llvm][StringExtras] Merge StringExtras from MLIR into LLVM
Summary: This revision adds two utilities currently present in MLIR to LLVM StringExtras: * convertToSnakeFromCamelCase Convert a string from a camel case naming scheme, to a snake case scheme * convertToCamelFromSnakeCase Convert a string from a snake case naming scheme, to a camel case scheme Differential Revision: https://reviews.llvm.org/D78167
1 parent 8da5b90 commit 229e392

File tree

14 files changed

+133
-169
lines changed

14 files changed

+133
-169
lines changed

llvm/include/llvm/ADT/StringExtras.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,18 @@ void printHTMLEscaped(StringRef String, raw_ostream &Out);
292292
/// printLowerCase - Print each character as lowercase if it is uppercase.
293293
void printLowerCase(StringRef String, raw_ostream &Out);
294294

295+
/// Converts a string from camel-case to snake-case by replacing all uppercase
296+
/// letters with '_' followed by the letter in lowercase, except if the
297+
/// uppercase letter is the first character of the string.
298+
std::string convertToSnakeFromCamelCase(StringRef input);
299+
300+
/// Converts a string from snake-case to camel-case by replacing all occurrences
301+
/// of '_' followed by a lowercase letter with the letter in uppercase.
302+
/// Optionally allow capitalization of the first letter (if it is a lowercase
303+
/// letter)
304+
std::string convertToCamelFromSnakeCase(StringRef input,
305+
bool capitalizeFirst = false);
306+
295307
namespace detail {
296308

297309
template <typename IteratorT>

llvm/lib/Support/StringExtras.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,46 @@ void llvm::printLowerCase(StringRef String, raw_ostream &Out) {
9090
for (const char C : String)
9191
Out << toLower(C);
9292
}
93+
94+
std::string llvm::convertToSnakeFromCamelCase(StringRef input) {
95+
if (input.empty())
96+
return "";
97+
98+
std::string snakeCase;
99+
snakeCase.reserve(input.size());
100+
for (char c : input) {
101+
if (!std::isupper(c)) {
102+
snakeCase.push_back(c);
103+
continue;
104+
}
105+
106+
if (!snakeCase.empty() && snakeCase.back() != '_')
107+
snakeCase.push_back('_');
108+
snakeCase.push_back(llvm::toLower(c));
109+
}
110+
return snakeCase;
111+
}
112+
113+
std::string llvm::convertToCamelFromSnakeCase(StringRef input,
114+
bool capitalizeFirst) {
115+
if (input.empty())
116+
return "";
117+
118+
std::string output;
119+
output.reserve(input.size());
120+
121+
// Push the first character, capatilizing if necessary.
122+
if (capitalizeFirst && std::islower(input.front()))
123+
output.push_back(llvm::toUpper(input.front()));
124+
else
125+
output.push_back(input.front());
126+
127+
// Walk the input converting any `*_[a-z]` snake case into `*[A-Z]` camelCase.
128+
for (size_t pos = 1, e = input.size(); pos < e; ++pos) {
129+
if (input[pos] == '_' && pos != (e - 1) && std::islower(input[pos + 1]))
130+
output.push_back(llvm::toUpper(input[++pos]));
131+
else
132+
output.push_back(input[pos]);
133+
}
134+
return output;
135+
}

llvm/unittests/ADT/StringExtrasTest.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,56 @@ TEST(StringExtrasTest, printHTMLEscaped) {
118118
printHTMLEscaped("ABCdef123&<>\"'", OS);
119119
EXPECT_EQ("ABCdef123&amp;&lt;&gt;&quot;&apos;", OS.str());
120120
}
121+
122+
TEST(StringExtras, ConvertToSnakeFromCamelCase) {
123+
auto testConvertToSnakeCase = [](llvm::StringRef input,
124+
llvm::StringRef expected) {
125+
EXPECT_EQ(convertToSnakeFromCamelCase(input), expected.str());
126+
};
127+
128+
testConvertToSnakeCase("OpName", "op_name");
129+
testConvertToSnakeCase("opName", "op_name");
130+
testConvertToSnakeCase("_OpName", "_op_name");
131+
testConvertToSnakeCase("Op_Name", "op_name");
132+
testConvertToSnakeCase("", "");
133+
testConvertToSnakeCase("A", "a");
134+
testConvertToSnakeCase("_", "_");
135+
testConvertToSnakeCase("a", "a");
136+
testConvertToSnakeCase("op_name", "op_name");
137+
testConvertToSnakeCase("_op_name", "_op_name");
138+
testConvertToSnakeCase("__op_name", "__op_name");
139+
testConvertToSnakeCase("op__name", "op__name");
140+
}
141+
142+
TEST(StringExtras, ConvertToCamelFromSnakeCase) {
143+
auto testConvertToCamelCase = [](bool capitalizeFirst, llvm::StringRef input,
144+
llvm::StringRef expected) {
145+
EXPECT_EQ(convertToCamelFromSnakeCase(input, capitalizeFirst),
146+
expected.str());
147+
};
148+
149+
testConvertToCamelCase(false, "op_name", "opName");
150+
testConvertToCamelCase(false, "_op_name", "_opName");
151+
testConvertToCamelCase(false, "__op_name", "_OpName");
152+
testConvertToCamelCase(false, "op__name", "op_Name");
153+
testConvertToCamelCase(false, "", "");
154+
testConvertToCamelCase(false, "A", "A");
155+
testConvertToCamelCase(false, "_", "_");
156+
testConvertToCamelCase(false, "a", "a");
157+
testConvertToCamelCase(false, "OpName", "OpName");
158+
testConvertToCamelCase(false, "opName", "opName");
159+
testConvertToCamelCase(false, "_OpName", "_OpName");
160+
testConvertToCamelCase(false, "Op_Name", "Op_Name");
161+
testConvertToCamelCase(true, "op_name", "OpName");
162+
testConvertToCamelCase(true, "_op_name", "_opName");
163+
testConvertToCamelCase(true, "__op_name", "_OpName");
164+
testConvertToCamelCase(true, "op__name", "Op_Name");
165+
testConvertToCamelCase(true, "", "");
166+
testConvertToCamelCase(true, "A", "A");
167+
testConvertToCamelCase(true, "_", "_");
168+
testConvertToCamelCase(true, "a", "A");
169+
testConvertToCamelCase(true, "OpName", "OpName");
170+
testConvertToCamelCase(true, "_OpName", "_OpName");
171+
testConvertToCamelCase(true, "Op_Name", "Op_Name");
172+
testConvertToCamelCase(true, "opName", "OpName");
173+
}

mlir/include/mlir/Support/StringExtras.h

Lines changed: 0 additions & 74 deletions
This file was deleted.

mlir/lib/Dialect/SPIRV/SPIRVDialect.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "mlir/IR/MLIRContext.h"
2020
#include "mlir/IR/StandardTypes.h"
2121
#include "mlir/Parser.h"
22-
#include "mlir/Support/StringExtras.h"
2322
#include "mlir/Transforms/InliningUtils.h"
2423
#include "llvm/ADT/DenseMap.h"
2524
#include "llvm/ADT/Sequence.h"
@@ -133,7 +132,7 @@ SPIRVDialect::SPIRVDialect(MLIRContext *context)
133132
}
134133

135134
std::string SPIRVDialect::getAttributeName(Decoration decoration) {
136-
return convertToSnakeCase(stringifyDecoration(decoration));
135+
return llvm::convertToSnakeFromCamelCase(stringifyDecoration(decoration));
137136
}
138137

139138
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/SPIRV/SPIRVOps.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "mlir/IR/OpImplementation.h"
2222
#include "mlir/IR/StandardTypes.h"
2323
#include "mlir/Interfaces/CallInterfaces.h"
24-
#include "mlir/Support/StringExtras.h"
24+
#include "llvm/ADT/StringExtras.h"
2525
#include "llvm/ADT/bit.h"
2626

2727
using namespace mlir;
@@ -335,15 +335,15 @@ static LogicalResult verifyLoadStorePtrAndValTypes(LoadStoreOpTy op, Value ptr,
335335

336336
static ParseResult parseVariableDecorations(OpAsmParser &parser,
337337
OperationState &state) {
338-
auto builtInName =
339-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::BuiltIn));
338+
auto builtInName = llvm::convertToSnakeFromCamelCase(
339+
stringifyDecoration(spirv::Decoration::BuiltIn));
340340
if (succeeded(parser.parseOptionalKeyword("bind"))) {
341341
Attribute set, binding;
342342
// Parse optional descriptor binding
343-
auto descriptorSetName = convertToSnakeCase(
343+
auto descriptorSetName = llvm::convertToSnakeFromCamelCase(
344344
stringifyDecoration(spirv::Decoration::DescriptorSet));
345-
auto bindingName =
346-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::Binding));
345+
auto bindingName = llvm::convertToSnakeFromCamelCase(
346+
stringifyDecoration(spirv::Decoration::Binding));
347347
Type i32Type = parser.getBuilder().getIntegerType(32);
348348
if (parser.parseLParen() ||
349349
parser.parseAttribute(set, i32Type, descriptorSetName,
@@ -373,10 +373,10 @@ static ParseResult parseVariableDecorations(OpAsmParser &parser,
373373
static void printVariableDecorations(Operation *op, OpAsmPrinter &printer,
374374
SmallVectorImpl<StringRef> &elidedAttrs) {
375375
// Print optional descriptor binding
376-
auto descriptorSetName =
377-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::DescriptorSet));
378-
auto bindingName =
379-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::Binding));
376+
auto descriptorSetName = llvm::convertToSnakeFromCamelCase(
377+
stringifyDecoration(spirv::Decoration::DescriptorSet));
378+
auto bindingName = llvm::convertToSnakeFromCamelCase(
379+
stringifyDecoration(spirv::Decoration::Binding));
380380
auto descriptorSet = op->getAttrOfType<IntegerAttr>(descriptorSetName);
381381
auto binding = op->getAttrOfType<IntegerAttr>(bindingName);
382382
if (descriptorSet && binding) {
@@ -387,8 +387,8 @@ static void printVariableDecorations(Operation *op, OpAsmPrinter &printer,
387387
}
388388

389389
// Print BuiltIn attribute if present
390-
auto builtInName =
391-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::BuiltIn));
390+
auto builtInName = llvm::convertToSnakeFromCamelCase(
391+
stringifyDecoration(spirv::Decoration::BuiltIn));
392392
if (auto builtin = op->getAttrOfType<StringAttr>(builtInName)) {
393393
printer << " " << builtInName << "(\"" << builtin.getValue() << "\")";
394394
elidedAttrs.push_back(builtInName);
@@ -2625,12 +2625,12 @@ static LogicalResult verify(spirv::VariableOp varOp) {
26252625

26262626
// TODO(antiagainst): generate these strings using ODS.
26272627
auto *op = varOp.getOperation();
2628-
auto descriptorSetName =
2629-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::DescriptorSet));
2630-
auto bindingName =
2631-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::Binding));
2632-
auto builtInName =
2633-
convertToSnakeCase(stringifyDecoration(spirv::Decoration::BuiltIn));
2628+
auto descriptorSetName = llvm::convertToSnakeFromCamelCase(
2629+
stringifyDecoration(spirv::Decoration::DescriptorSet));
2630+
auto bindingName = llvm::convertToSnakeFromCamelCase(
2631+
stringifyDecoration(spirv::Decoration::Binding));
2632+
auto builtInName = llvm::convertToSnakeFromCamelCase(
2633+
stringifyDecoration(spirv::Decoration::BuiltIn));
26342634

26352635
for (const auto &attr : {descriptorSetName, bindingName, builtInName}) {
26362636
if (op->getAttr(attr))

mlir/lib/Dialect/SPIRV/Serialization/Deserializer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
#include "mlir/IR/Builders.h"
2121
#include "mlir/IR/Location.h"
2222
#include "mlir/Support/LogicalResult.h"
23-
#include "mlir/Support/StringExtras.h"
2423
#include "llvm/ADT/STLExtras.h"
2524
#include "llvm/ADT/Sequence.h"
2625
#include "llvm/ADT/SetVector.h"
2726
#include "llvm/ADT/SmallVector.h"
27+
#include "llvm/ADT/StringExtras.h"
2828
#include "llvm/ADT/bit.h"
2929
#include "llvm/Support/Debug.h"
3030
#include "llvm/Support/raw_ostream.h"
@@ -647,7 +647,7 @@ LogicalResult Deserializer::processDecoration(ArrayRef<uint32_t> words) {
647647
if (decorationName.empty()) {
648648
return emitError(unknownLoc, "invalid Decoration code : ") << words[1];
649649
}
650-
auto attrName = convertToSnakeCase(decorationName);
650+
auto attrName = llvm::convertToSnakeFromCamelCase(decorationName);
651651
auto symbol = opBuilder.getIdentifier(attrName);
652652
switch (static_cast<spirv::Decoration>(words[1])) {
653653
case spirv::Decoration::DescriptorSet:

mlir/lib/Dialect/SPIRV/Serialization/Serializer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
#include "mlir/IR/Builders.h"
2121
#include "mlir/IR/RegionGraphTraits.h"
2222
#include "mlir/Support/LogicalResult.h"
23-
#include "mlir/Support/StringExtras.h"
2423
#include "llvm/ADT/DepthFirstIterator.h"
2524
#include "llvm/ADT/Sequence.h"
2625
#include "llvm/ADT/SmallPtrSet.h"
2726
#include "llvm/ADT/SmallVector.h"
27+
#include "llvm/ADT/StringExtras.h"
2828
#include "llvm/ADT/TypeSwitch.h"
2929
#include "llvm/ADT/bit.h"
3030
#include "llvm/Support/Debug.h"
@@ -627,7 +627,7 @@ LogicalResult Serializer::processUndefOp(spirv::UndefOp op) {
627627
LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
628628
NamedAttribute attr) {
629629
auto attrName = attr.first.strref();
630-
auto decorationName = mlir::convertToCamelCase(attrName, true);
630+
auto decorationName = llvm::convertToCamelFromSnakeCase(attrName, true);
631631
auto decoration = spirv::symbolizeDecoration(decorationName);
632632
if (!decoration) {
633633
return emitError(

mlir/tools/mlir-tblgen/DialectGen.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "mlir/Support/StringExtras.h"
1413
#include "mlir/TableGen/Format.h"
1514
#include "mlir/TableGen/GenInfo.h"
1615
#include "mlir/TableGen/OpClass.h"

mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "OpFormatGen.h"
15-
#include "mlir/Support/StringExtras.h"
1615
#include "mlir/TableGen/Format.h"
1716
#include "mlir/TableGen/GenInfo.h"
1817
#include "mlir/TableGen/OpClass.h"

0 commit comments

Comments
 (0)