Skip to content

Commit 7f684b6

Browse files
committed
SIL optimizer: Add a new string optimization.
Optimizes String operations with constant operands. Specifically: * Replaces x.append(y) with x = y if x is empty. * Removes x.append("") * Replaces x.append(y) with x = x + y if x and y are constant strings. * Replaces _typeName(T.self) with a constant string if T is statically known. With this optimization it's possible to constant fold string interpolations, like "the \(Int.self) type" -> "the Int type" This new pass runs on high-level SIL, where semantic calls are still in place. rdar://problem/65642843
1 parent bf4e61f commit 7f684b6

File tree

11 files changed

+791
-3
lines changed

11 files changed

+791
-3
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,9 @@ class ASTContext final {
553553
/// Array.reserveCapacityForAppend(newElementsCount: Int)
554554
FuncDecl *getArrayReserveCapacityDecl() const;
555555

556+
/// Retrieve the declaration of String.init(_builtinStringLiteral ...)
557+
ConstructorDecl *getMakeUTF8StringDecl() const;
558+
556559
// Retrieve the declaration of Swift._stdlib_isOSVersionAtLeast.
557560
FuncDecl *getIsOSVersionAtLeastDecl() const;
558561

include/swift/AST/SemanticAttrs.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ SEMANTICS_ATTR(STRING_ESCAPE_PERCENT_GET, "string.escapePercent.get")
3030
SEMANTICS_ATTR(STRING_CONCAT, "string.concat")
3131
SEMANTICS_ATTR(STRING_APPEND, "string.append")
3232
SEMANTICS_ATTR(STRING_INIT_EMPTY, "string.init_empty")
33+
SEMANTICS_ATTR(STRING_INIT_EMPTY_WITH_CAPACITY, "string.init_empty_with_capacity")
3334
SEMANTICS_ATTR(STRING_PLUS_EQUALS, "string.plusequals")
3435
SEMANTICS_ATTR(FIND_STRING_SWITCH_CASE, "findStringSwitchCase")
3536
SEMANTICS_ATTR(FIND_STRING_SWITCH_CASE_WITH_CACHE, "findStringSwitchCaseWithCache")
@@ -63,6 +64,7 @@ SEMANTICS_ATTR(ARRAY_UNINITIALIZED_INTRINSIC, "array.uninitialized_intrinsic")
6364
SEMANTICS_ATTR(ARRAY_FINALIZE_INTRINSIC, "array.finalize_intrinsic")
6465

6566
SEMANTICS_ATTR(SEQUENCE_FOR_EACH, "sequence.forEach")
67+
SEMANTICS_ATTR(TYPENAME, "typeName")
6668

6769
SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_GENERIC_NEVER, "optimize.sil.specialize.generic.never")
6870
SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_GENERIC_PARTIAL_NEVER,

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ PASS(StackPromotion, "stack-promotion",
317317
"Stack Promotion of Class Objects")
318318
PASS(StripDebugInfo, "strip-debug-info",
319319
"Strip Debug Information")
320+
PASS(StringOptimization, "string-optimization",
321+
"Optimization for String operations")
320322
PASS(SwiftArrayPropertyOpt, "array-property-opt",
321323
"Loop Specialization for Array Properties")
322324
PASS(UnsafeGuaranteedPeephole, "unsafe-guaranteed-peephole",

lib/AST/ASTContext.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "swift/AST/PropertyWrappers.h"
4141
#include "swift/AST/ProtocolConformance.h"
4242
#include "swift/AST/RawComment.h"
43+
#include "swift/AST/SemanticAttrs.h"
4344
#include "swift/AST/SourceFile.h"
4445
#include "swift/AST/SubstitutionMap.h"
4546
#include "swift/AST/SILLayout.h"
@@ -240,6 +241,9 @@ struct ASTContext::Implementation {
240241
/// func append(Element) -> void
241242
FuncDecl *ArrayAppendElementDecl = nullptr;
242243

244+
/// init(Builtin.RawPointer, Builtin.Word, Builtin.Int1)
245+
ConstructorDecl *MakeUTF8StringDecl = nullptr;
246+
243247
/// func reserveCapacityForAppend(newElementsCount: Int)
244248
FuncDecl *ArrayReserveCapacityDecl = nullptr;
245249

@@ -1247,6 +1251,33 @@ FuncDecl *ASTContext::getArrayReserveCapacityDecl() const {
12471251
return nullptr;
12481252
}
12491253

1254+
ConstructorDecl *ASTContext::getMakeUTF8StringDecl() const {
1255+
if (getImpl().MakeUTF8StringDecl)
1256+
return getImpl().MakeUTF8StringDecl;
1257+
1258+
auto initializers =
1259+
getStringDecl()->lookupDirect(DeclBaseName::createConstructor());
1260+
1261+
for (Decl *initializer : initializers) {
1262+
auto *constructor = cast<ConstructorDecl>(initializer);
1263+
auto Attrs = constructor->getAttrs();
1264+
for (auto *A : Attrs.getAttributes<SemanticsAttr, false>()) {
1265+
if (A->Value != semantics::STRING_MAKE_UTF8)
1266+
continue;
1267+
auto ParamList = constructor->getParameters();
1268+
if (ParamList->size() != 3)
1269+
continue;
1270+
ParamDecl *param = constructor->getParameters()->get(0);
1271+
if (param->getArgumentName().str() != "_builtinStringLiteral")
1272+
continue;
1273+
1274+
getImpl().MakeUTF8StringDecl = constructor;
1275+
return constructor;
1276+
}
1277+
}
1278+
return nullptr;
1279+
}
1280+
12501281
FuncDecl *ASTContext::getIsOSVersionAtLeastDecl() const {
12511282
if (getImpl().IsOSVersionAtLeastDecl)
12521283
return getImpl().IsOSVersionAtLeastDecl;

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,9 @@ static void addSerializePipeline(SILPassPipelinePlan &P) {
524524

525525
static void addMidLevelFunctionPipeline(SILPassPipelinePlan &P) {
526526
P.startPipeline("MidLevel,Function", true /*isFunctionPassPipeline*/);
527+
528+
P.addStringOptimization();
529+
527530
addFunctionPasses(P, OptimizationLevelKind::MidLevel);
528531

529532
// Specialize partially applied functions with dead arguments as a preparation

lib/SILOptimizer/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ target_sources(swiftSILOptimizer PRIVATE
3939
Sink.cpp
4040
SpeculativeDevirtualizer.cpp
4141
StackPromotion.cpp
42+
StringOptimization.cpp
4243
TempLValueOpt.cpp
4344
TempRValueElimination.cpp
4445
UnsafeGuaranteedPeephole.cpp)

0 commit comments

Comments
 (0)