Skip to content

Commit 5f3e79b

Browse files
committed
StringOptimization: bug fixes
Fix some bugs in the optimization and in the test files. rdar://problem/66283894
1 parent a6e2f8b commit 5f3e79b

File tree

6 files changed

+99
-8
lines changed

6 files changed

+99
-8
lines changed

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ std::string ASTMangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) {
534534
}
535535

536536
std::string ASTMangler::mangleTypeForTypeName(Type type) {
537-
beginMangling();
537+
beginManglingWithoutPrefix();
538538
appendType(type);
539539
return finalize();
540540
}

lib/SILOptimizer/Transforms/StringOptimization.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,32 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
199199
return false;
200200
}
201201

202+
/// Checks if the demangling tree contains any node which prevents constant
203+
/// folding of the type name.
204+
static bool containsProblematicNode(Demangle::Node *node, bool qualified) {
205+
switch (node->getKind()) {
206+
case Demangle::Node::Kind::LocalDeclName:
207+
// The printing of contexts for local types is completely different
208+
// in the runtime. Don't constant fold if we need to print the context.
209+
if (qualified)
210+
return true;
211+
break;
212+
case Demangle::Node::Kind::Class:
213+
// ObjC class names are not derived from the mangling but from the
214+
// ObjC runtime. We cannot constant fold this.
215+
if (node->getChild(0)->getText() == "__C")
216+
return true;
217+
break;
218+
default:
219+
break;
220+
}
221+
for (Demangle::Node *child : *node) {
222+
if (containsProblematicNode(child, qualified))
223+
return true;
224+
}
225+
return false;
226+
}
227+
202228
/// Try to replace a _typeName() call with a constant string if the type is
203229
/// statically known.
204230
bool StringOptimization::optimizeTypeName(ApplyInst *typeNameCall) {
@@ -217,20 +243,29 @@ bool StringOptimization::optimizeTypeName(ApplyInst *typeNameCall) {
217243
return false;
218244

219245
// Usually the "qualified" parameter of _typeName() is a constant boolean.
220-
Optional<int> isQualified = getIntConstant(typeNameCall->getArgument(1));
221-
if (!isQualified)
246+
Optional<int> isQualifiedOpt = getIntConstant(typeNameCall->getArgument(1));
247+
if (!isQualifiedOpt)
222248
return false;
249+
bool isQualified = isQualifiedOpt.getValue();
223250

224251
// Create the constant type string by mangling + demangling.
225252
Mangle::ASTMangler mangler;
226253
std::string mangledTypeName = mangler.mangleTypeForTypeName(ty);
227254

228255
Demangle::DemangleOptions options;
229256
options.PrintForTypeName = true;
230-
options.QualifyEntities = (isQualified.getValue() != 0);
231-
std::string typeStr = Demangle::demangleSymbolAsString(mangledTypeName,
232-
options);
233-
257+
options.DisplayLocalNameContexts = false;
258+
options.QualifyEntities = isQualified;
259+
260+
Demangle::Context ctx;
261+
Demangle::NodePointer root = ctx.demangleTypeAsNode(mangledTypeName);
262+
if (!root || containsProblematicNode(root, isQualified))
263+
return false;
264+
265+
std::string typeStr = nodeToString(root, options);
266+
if (typeStr.empty())
267+
return false;
268+
234269
ApplyInst *stringInit = createStringInit(typeStr, typeNameCall);
235270
if (!stringInit)
236271
return false;

test/SILOptimizer/string_optimization.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
// REQUIRES: executable_test,swift_stdlib_no_asserts
88

9+
#if _runtime(_ObjC)
10+
import Foundation
11+
#endif
12+
913
struct Outer {
1014
struct Inner { }
1115
}
@@ -50,17 +54,60 @@ public func testQualifiedTypeName() -> String {
5054
return _typeName(Outer.Inner.self, qualified: true)
5155
}
5256

57+
// CHECK-LABEL: sil [noinline] @$s4test0A20UnqualifiedLocalTypeSSyF
58+
// CHECK-NOT: apply
59+
// CHECK-NOT: bb1
60+
// CHECK: } // end sil function '$s4test0A20UnqualifiedLocalTypeSSyF'
61+
@inline(never)
62+
public func testUnqualifiedLocalType() -> String {
63+
struct LocalStruct { }
64+
return _typeName(LocalStruct.self, qualified: false)
65+
}
66+
67+
// CHECK-LABEL: sil [noinline] @$s4test0A18QualifiedLocalTypeSSyF
68+
// CHECK: [[F:%[0-9]+]] = function_ref @$ss9_typeName_9qualifiedSSypXp_SbtF
69+
// CHECK: apply [[F]]
70+
// CHECK: } // end sil function '$s4test0A18QualifiedLocalTypeSSyF'
71+
@inline(never)
72+
public func testQualifiedLocalType() -> String {
73+
struct LocalStruct { }
74+
return _typeName(LocalStruct.self, qualified: true)
75+
}
76+
77+
#if _runtime(_ObjC)
78+
@inline(never)
79+
public func testObjcClassName(qualified: Bool) -> String {
80+
return _typeName(NSObject.self, qualified: qualified)
81+
}
82+
#endif
83+
5384
@inline(never)
5485
func printEmbeeded(_ s: String) {
5586
print("<\(s)>")
5687
}
5788

5889
// CHECK-OUTPUT: <-Inner+>
5990
printEmbeeded(testTypeNameInterpolation())
91+
6092
// CHECK-OUTPUT: <-Array<Int> is cool+>
6193
printEmbeeded(testFoldCompleteInterpolation())
94+
6295
// CHECK-OUTPUT: <Inner>
6396
printEmbeeded(testUnqualifiedTypeName())
97+
6498
// CHECK-OUTPUT: <test.Outer.Inner>
6599
printEmbeeded(testQualifiedTypeName())
66100

101+
// CHECK-OUTPUT: <LocalStruct>
102+
printEmbeeded(testUnqualifiedLocalType())
103+
104+
// CHECK-OUTPUT: <test.(unknown context at {{.*}}).LocalStruct>
105+
printEmbeeded(testQualifiedLocalType())
106+
107+
#if _runtime(_ObjC)
108+
// CHECK-OUTPUT: <NSObject>
109+
printEmbeeded(testObjcClassName(qualified: false))
110+
// CHECK-OUTPUT: <NSObject>
111+
printEmbeeded(testObjcClassName(qualified: true))
112+
#endif
113+

test/stdlib/TypeName.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-build-swift -O -module-name=main %s -o %t/O.out
3+
// RUN: %target-codesign %t/O.out
34
// RUN: %target-run %t/O.out
45
// RUN: %target-build-swift -Onone -module-name=main %s -o %t/Onone.out
6+
// RUN: %target-codesign %t/Onone.out
57
// RUN: %target-run %t/Onone.out
68

79
// REQUIRES: executable_test

test/stdlib/TypeNameInterpolation.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33

44
// RUN: %empty-directory(%t)
55
// RUN: %target-build-swift -O -module-name=test %s -o %t/O.out
6+
// RUN: %target-codesign %t/O.out
67
// RUN: %target-run %t/O.out
78
// RUN: %target-build-swift -Onone -module-name=test %s -o %t/Onone.out
9+
// RUN: %target-codesign %t/Onone.out
810
// RUN: %target-run %t/Onone.out
911

1012
// REQUIRES: executable_test

validation-test/stdlib/StringUTF8.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ extension String {
2525
var isFastUTF8: Bool {
2626
return withFastUTF8IfAvailable({ _ in return 0 }) != nil
2727
}
28-
mutating func makeNative() { self += "" }
28+
29+
// Prevent that the optimizer removes 'self += ""' in makeNative()
30+
@inline(never)
31+
static func emptyString() -> String { return "" }
32+
33+
mutating func makeNative() { self += String.emptyString() }
2934

3035
var isASCII: Bool { return utf8.allSatisfy { $0 < 0x7f } }
3136
}

0 commit comments

Comments
 (0)