mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user