@@ -90,7 +90,7 @@ class StringOptimization {
90
90
91
91
bool optimizeStringAppend (ApplyInst *appendCall,
92
92
llvm::DenseMap<SILValue, SILValue> &storedStrings);
93
-
93
+ bool optimizeStringConcat (ApplyInst *concatCall);
94
94
bool optimizeTypeName (ApplyInst *typeNameCall);
95
95
96
96
static ApplyInst *isSemanticCall (SILInstruction *inst, StringRef attr,
@@ -102,8 +102,8 @@ class StringOptimization {
102
102
static StringInfo getStringFromStaticLet (SILValue value);
103
103
104
104
static Optional<int > getIntConstant (SILValue value);
105
- static void replaceAppendWith (ApplyInst *appendCall, SILValue newValue,
106
- bool copyNewValue );
105
+ static void replaceAppendWith (ApplyInst *appendCall, SILValue newValue);
106
+ static SILValue copyValue (SILValue value, SILInstruction *before );
107
107
ApplyInst *createStringInit (StringRef str, SILInstruction *beforeInst);
108
108
};
109
109
@@ -144,6 +144,12 @@ bool StringOptimization::optimizeBlock(SILBasicBlock &block) {
144
144
continue ;
145
145
}
146
146
}
147
+ if (ApplyInst *append = isSemanticCall (inst, semantics::STRING_CONCAT, 3 )) {
148
+ if (optimizeStringConcat (append)) {
149
+ changed = true ;
150
+ continue ;
151
+ }
152
+ }
147
153
if (ApplyInst *typeName = isSemanticCall (inst, semantics::TYPENAME, 2 )) {
148
154
if (optimizeTypeName (typeName)) {
149
155
changed = true ;
@@ -184,7 +190,7 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
184
190
185
191
// Replace lhs.append(rhs) with 'lhs = rhs' if lhs is empty.
186
192
if (lhsString.isEmpty ()) {
187
- replaceAppendWith (appendCall, rhs, /* copyNewValue */ true );
193
+ replaceAppendWith (appendCall, copyValue ( rhs, appendCall) );
188
194
storedStrings[lhsAddr] = rhs;
189
195
return true ;
190
196
}
@@ -195,7 +201,7 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
195
201
std::string concat = lhsString.str ;
196
202
concat += rhsString.str ;
197
203
if (ApplyInst *stringInit = createStringInit (concat, appendCall)) {
198
- replaceAppendWith (appendCall, stringInit, /* copyNewValue */ false );
204
+ replaceAppendWith (appendCall, stringInit);
199
205
storedStrings[lhsAddr] = stringInit;
200
206
return true ;
201
207
}
@@ -204,6 +210,43 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
204
210
return false ;
205
211
}
206
212
213
+ // / Optimize String.+ in case anything is known about the parameters.
214
+ bool StringOptimization::optimizeStringConcat (ApplyInst *concatCall) {
215
+ SILValue lhs = concatCall->getArgument (0 );
216
+ SILValue rhs = concatCall->getArgument (1 );
217
+ StringInfo rhsString = getStringInfo (rhs);
218
+
219
+ // Replace lhs + "" with lhs
220
+ if (rhsString.isEmpty ()) {
221
+ lhs = copyValue (lhs, concatCall);
222
+ concatCall->replaceAllUsesWith (lhs);
223
+ concatCall->eraseFromParent ();
224
+ return true ;
225
+ }
226
+
227
+ // Replace "" + rhs with rhs
228
+ StringInfo lhsString = getStringInfo (lhs);
229
+ if (lhsString.isEmpty ()) {
230
+ rhs = copyValue (rhs, concatCall);
231
+ concatCall->replaceAllUsesWith (rhs);
232
+ concatCall->eraseFromParent ();
233
+ return true ;
234
+ }
235
+
236
+ // Replace lhs + rhs with "lhs + rhs" if both lhs and rhs are constant.
237
+ if (lhsString.isConstant () && rhsString.isConstant ()) {
238
+ std::string concat = lhsString.str ;
239
+ concat += rhsString.str ;
240
+ if (ApplyInst *stringInit = createStringInit (concat, concatCall)) {
241
+ concatCall->replaceAllUsesWith (stringInit);
242
+ concatCall->eraseFromParent ();
243
+ return true ;
244
+ }
245
+ }
246
+
247
+ return false ;
248
+ }
249
+
207
250
// / Checks if the demangling tree contains any node which prevents constant
208
251
// / folding of the type name.
209
252
static bool containsProblematicNode (Demangle::Node *node, bool qualified) {
@@ -499,25 +542,33 @@ Optional<int> StringOptimization::getIntConstant(SILValue value) {
499
542
500
543
// / Replace a String.append() with a store of \p newValue to the destination.
501
544
void StringOptimization::replaceAppendWith (ApplyInst *appendCall,
502
- SILValue newValue, bool copyNewValue ) {
545
+ SILValue newValue ) {
503
546
SILBuilder builder (appendCall);
504
547
SILLocation loc = appendCall->getLoc ();
505
548
SILValue destAddr = appendCall->getArgument (1 );
506
549
if (appendCall->getFunction ()->hasOwnership ()) {
507
- if (copyNewValue)
508
- newValue = builder.createCopyValue (loc, newValue);
509
550
builder.createStore (loc, newValue, destAddr,
510
551
StoreOwnershipQualifier::Assign);
511
552
} else {
512
- if (copyNewValue)
513
- builder.createRetainValue (loc, newValue, builder.getDefaultAtomicity ());
514
553
builder.createDestroyAddr (loc, destAddr);
515
554
builder.createStore (loc, newValue, destAddr,
516
555
StoreOwnershipQualifier::Unqualified);
517
556
}
518
557
appendCall->eraseFromParent ();
519
558
}
520
559
560
+ // / Returns a copy of \p value. Depending if the function is in OSSA, insert
561
+ // / either a copy_value or retain_value.
562
+ SILValue StringOptimization::copyValue (SILValue value, SILInstruction *before) {
563
+ SILBuilder builder (before);
564
+ SILLocation loc = before->getLoc ();
565
+ if (before->getFunction ()->hasOwnership ())
566
+ return builder.createCopyValue (loc, value);
567
+
568
+ builder.createRetainValue (loc, value, builder.getDefaultAtomicity ());
569
+ return value;
570
+ }
571
+
521
572
// / Creates a call to a string initializer.
522
573
ApplyInst *StringOptimization::createStringInit (StringRef str,
523
574
SILInstruction *beforeInst) {
0 commit comments