@@ -90,7 +90,7 @@ class StringOptimization {
9090
9191 bool optimizeStringAppend (ApplyInst *appendCall,
9292 llvm::DenseMap<SILValue, SILValue> &storedStrings);
93-
93+ bool optimizeStringConcat (ApplyInst *concatCall);
9494 bool optimizeTypeName (ApplyInst *typeNameCall);
9595
9696 static ApplyInst *isSemanticCall (SILInstruction *inst, StringRef attr,
@@ -102,8 +102,8 @@ class StringOptimization {
102102 static StringInfo getStringFromStaticLet (SILValue value);
103103
104104 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 );
107107 ApplyInst *createStringInit (StringRef str, SILInstruction *beforeInst);
108108};
109109
@@ -144,6 +144,12 @@ bool StringOptimization::optimizeBlock(SILBasicBlock &block) {
144144 continue ;
145145 }
146146 }
147+ if (ApplyInst *append = isSemanticCall (inst, semantics::STRING_CONCAT, 3 )) {
148+ if (optimizeStringConcat (append)) {
149+ changed = true ;
150+ continue ;
151+ }
152+ }
147153 if (ApplyInst *typeName = isSemanticCall (inst, semantics::TYPENAME, 2 )) {
148154 if (optimizeTypeName (typeName)) {
149155 changed = true ;
@@ -184,7 +190,7 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
184190
185191 // Replace lhs.append(rhs) with 'lhs = rhs' if lhs is empty.
186192 if (lhsString.isEmpty ()) {
187- replaceAppendWith (appendCall, rhs, /* copyNewValue */ true );
193+ replaceAppendWith (appendCall, copyValue ( rhs, appendCall) );
188194 storedStrings[lhsAddr] = rhs;
189195 return true ;
190196 }
@@ -195,7 +201,7 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
195201 std::string concat = lhsString.str ;
196202 concat += rhsString.str ;
197203 if (ApplyInst *stringInit = createStringInit (concat, appendCall)) {
198- replaceAppendWith (appendCall, stringInit, /* copyNewValue */ false );
204+ replaceAppendWith (appendCall, stringInit);
199205 storedStrings[lhsAddr] = stringInit;
200206 return true ;
201207 }
@@ -204,6 +210,43 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall,
204210 return false ;
205211}
206212
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+
207250// / Checks if the demangling tree contains any node which prevents constant
208251// / folding of the type name.
209252static bool containsProblematicNode (Demangle::Node *node, bool qualified) {
@@ -499,25 +542,33 @@ Optional<int> StringOptimization::getIntConstant(SILValue value) {
499542
500543// / Replace a String.append() with a store of \p newValue to the destination.
501544void StringOptimization::replaceAppendWith (ApplyInst *appendCall,
502- SILValue newValue, bool copyNewValue ) {
545+ SILValue newValue ) {
503546 SILBuilder builder (appendCall);
504547 SILLocation loc = appendCall->getLoc ();
505548 SILValue destAddr = appendCall->getArgument (1 );
506549 if (appendCall->getFunction ()->hasOwnership ()) {
507- if (copyNewValue)
508- newValue = builder.createCopyValue (loc, newValue);
509550 builder.createStore (loc, newValue, destAddr,
510551 StoreOwnershipQualifier::Assign);
511552 } else {
512- if (copyNewValue)
513- builder.createRetainValue (loc, newValue, builder.getDefaultAtomicity ());
514553 builder.createDestroyAddr (loc, destAddr);
515554 builder.createStore (loc, newValue, destAddr,
516555 StoreOwnershipQualifier::Unqualified);
517556 }
518557 appendCall->eraseFromParent ();
519558}
520559
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+
521572// / Creates a call to a string initializer.
522573ApplyInst *StringOptimization::createStringInit (StringRef str,
523574 SILInstruction *beforeInst) {
0 commit comments