StringOptimization: optimize interpolated C strings.

Optimize code like:

   puts("\(String.self)")

Optimizing string interpolation and optimizing C-strings are both done in StringOptimization.
A second run of the StringOptimization is needed in the pipeline to optimize such code, because the result of the interpolation-optimization must be cleaned up so that the C-String optimization can kick in.

Also, StringOptimization must handle struct_extract(struct(literal)), where the struct_extract may be in a called function.
To solve a phase ordering problem with inlining String semantics and inlining the `String(stringInterpolation: DefaultStringInterpolation)` constructor, we do a simple analysis of the callee. Doing this simple "interprocedural" analysis avoids relying on inlining that String constructor.

rdar://74941849
This commit is contained in:
Erik Eckstein
2021-07-06 16:25:03 +02:00
parent 286d22b2e6
commit 88a74a288c
4 changed files with 109 additions and 1 deletions

View File

@@ -471,11 +471,60 @@ void StringOptimization::invalidateModifiedObjects(SILInstruction *inst,
}
}
/// If \p value is a struct_extract, return its operand and field.
static std::pair<SILValue, VarDecl *> skipStructExtract(SILValue value) {
if (auto *sei = dyn_cast<StructExtractInst>(value))
return {sei->getOperand(), sei->getField()};
// Look through function calls, which do the struct_extract in the callee.
// This specifically targets
// String(stringInterpolation: DefaultStringInterpolation)
// which is not inlined in the high level pipeline (due to the specified
// effects).
auto *apply = dyn_cast<ApplyInst>(value);
if (!apply)
return {value, nullptr};
SILFunction *callee = apply->getReferencedFunctionOrNull();
if (!callee || !callee->isDefinition())
return {value, nullptr};
// `String(stringInterpolation: DefaultStringInterpolation)` has only a single
// basic block. Avoid the effort of searching all blocks for a `return`.
auto *ret = dyn_cast<ReturnInst>(callee->getEntryBlock()->getTerminator());
if (!ret)
return {value, nullptr};
auto *sei = dyn_cast<StructExtractInst>(ret->getOperand());
if (!sei)
return {value, nullptr};
auto *arg = dyn_cast<SILFunctionArgument>(sei->getOperand());
if (!arg)
return {value, nullptr};
value = apply->getArgument(arg->getIndex());
return {value, sei->getField()};
}
/// Returns information about value if it's a constant string.
StringOptimization::StringInfo StringOptimization::getStringInfo(SILValue value) {
if (!value)
return StringInfo::unknown();
// Look through struct_extract(struct(value)).
// This specifically targets calls to
// String(stringInterpolation: DefaultStringInterpolation)
// which are not inlined in the high level pipeline.
VarDecl *field = nullptr;
std::tie(value, field) = skipStructExtract(value);
if (field) {
auto *si = dyn_cast<StructInst>(value);
if (!si)
return StringInfo::unknown();
value = si->getFieldValue(field);
}
auto *apply = dyn_cast<ApplyInst>(value);
if (!apply) {
return getStringFromStaticLet(value);