Skip to content

Commit c05234e

Browse files
committed
MandatoryPerformanceOptimizations: specialize witness_method instructions
In Embedded Swift, witness method lookup is done from specialized witness tables. For this to work, the type of witness_method must be specialized as well. Otherwise the method call would be done with wrong parameter conventions (indirect instead of direct).
1 parent abbc633 commit c05234e

File tree

6 files changed

+71
-2
lines changed

6 files changed

+71
-2
lines changed

SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ private func optimize(function: Function, _ context: FunctionPassContext, _ modu
116116
if context.options.enableEmbeddedSwift {
117117
_ = context.specializeClassMethodInst(classMethod)
118118
}
119+
case let witnessMethod as WitnessMethodInst:
120+
if context.options.enableEmbeddedSwift {
121+
_ = context.specializeWitnessMethodInst(witnessMethod)
122+
}
119123

120124
case let initExRef as InitExistentialRefInst:
121125
if context.options.enableEmbeddedSwift {

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ struct FunctionPassContext : MutatingContext {
357357
return false
358358
}
359359

360+
func specializeWitnessMethodInst(_ wm: WitnessMethodInst) -> Bool {
361+
if _bridged.specializeWitnessMethodInst(wm.bridged) {
362+
notifyInstructionsChanged()
363+
notifyCallsChanged()
364+
return true
365+
}
366+
return false
367+
}
368+
360369
func specializeApplies(in function: Function, isMandatory: Bool) -> Bool {
361370
if _bridged.specializeAppliesInFunction(function.bridged, isMandatory) {
362371
notifyInstructionsChanged()

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ struct BridgedPassContext {
256256
BridgedSubstitutionMap substitutions) const;
257257
void deserializeAllCallees(BridgedFunction function, bool deserializeAll) const;
258258
bool specializeClassMethodInst(BridgedInstruction cm) const;
259+
bool specializeWitnessMethodInst(BridgedInstruction wm) const;
259260
bool specializeAppliesInFunction(BridgedFunction function, bool isMandatory) const;
260261
BridgedOwnedString mangleOutlinedVariable(BridgedFunction function) const;
261262
BridgedOwnedString mangleAsyncRemoved(BridgedFunction function) const;

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ bool optimizeMemoryAccesses(SILFunction *fn);
607607
bool eliminateDeadAllocations(SILFunction *fn, DominanceInfo *domInfo);
608608

609609
bool specializeClassMethodInst(ClassMethodInst *cm);
610+
bool specializeWitnessMethodInst(WitnessMethodInst *wm);
610611

611612
bool specializeAppliesInFunction(SILFunction &F,
612613
SILTransform *transform,

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,10 @@ bool BridgedPassContext::specializeClassMethodInst(BridgedInstruction cm) const
17711771
return ::specializeClassMethodInst(cm.getAs<ClassMethodInst>());
17721772
}
17731773

1774+
bool BridgedPassContext::specializeWitnessMethodInst(BridgedInstruction wm) const {
1775+
return ::specializeWitnessMethodInst(wm.getAs<WitnessMethodInst>());
1776+
}
1777+
17741778
bool BridgedPassContext::specializeAppliesInFunction(BridgedFunction function, bool isMandatory) const {
17751779
return ::specializeAppliesInFunction(*function.getFunction(), invocation->getTransform(), isMandatory);
17761780
}

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,8 +725,6 @@ void ReabstractionInfo::createSubstitutedAndSpecializedTypes() {
725725
SubstitutedType = createSubstitutedType(Callee, CallerInterfaceSubs,
726726
HasUnboundGenericParams);
727727
}
728-
assert(!SubstitutedType->hasArchetype() &&
729-
"Substituted function type should not contain archetypes");
730728

731729
// Check which parameters and results can be converted from
732730
// indirect to direct ones.
@@ -2363,6 +2361,58 @@ bool swift::specializeClassMethodInst(ClassMethodInst *cm) {
23632361
return true;
23642362
}
23652363

2364+
bool swift::specializeWitnessMethodInst(WitnessMethodInst *wm) {
2365+
SILFunction *f = wm->getFunction();
2366+
SILModule &m = f->getModule();
2367+
2368+
CanType astType = wm->getLookupType();
2369+
if (!isa<OpenedArchetypeType>(astType))
2370+
return false;
2371+
2372+
if (wm->isSpecialized())
2373+
return false;
2374+
2375+
// This should not happen. Just to be on the safe side.
2376+
if (wm->use_empty())
2377+
return false;
2378+
2379+
Operand *firstUse = *wm->use_begin();
2380+
ApplySite AI = ApplySite::isa(firstUse->getUser());
2381+
assert(AI && AI.getCalleeOperand() == firstUse && "wrong use of witness_method instruction");
2382+
2383+
SubstitutionMap subs = AI.getSubstitutionMap();
2384+
2385+
SILType funcTy = wm->getType();
2386+
SILType substitutedType =
2387+
funcTy.substGenericArgs(m, subs, TypeExpansionContext::minimal());
2388+
2389+
ReabstractionInfo reInfo(substitutedType.getAs<SILFunctionType>(), wm->getMember(), m);
2390+
reInfo.createSubstitutedAndSpecializedTypes();
2391+
CanSILFunctionType finalFuncTy = reInfo.getSpecializedType();
2392+
SILType finalSILTy = SILType::getPrimitiveObjectType(finalFuncTy);
2393+
2394+
SILBuilder builder(wm);
2395+
auto *newWM = builder.createWitnessMethod(wm->getLoc(), wm->getLookupType(),
2396+
wm->getConformance(), wm->getMember(), finalSILTy);
2397+
2398+
while (!wm->use_empty()) {
2399+
Operand *use = *wm->use_begin();
2400+
SILInstruction *user = use->getUser();
2401+
ApplySite AI = ApplySite::isa(user);
2402+
if (AI && AI.getCalleeOperand() == use) {
2403+
replaceWithSpecializedCallee(AI, newWM, reInfo);
2404+
AI.getInstruction()->eraseFromParent();
2405+
continue;
2406+
}
2407+
llvm::errs() << "unsupported use of witness method "
2408+
<< newWM->getMember().getDecl()->getName() << " in function "
2409+
<< newWM->getFunction()->getName() << '\n';
2410+
llvm::report_fatal_error("unsupported witness method");
2411+
}
2412+
2413+
return true;
2414+
}
2415+
23662416
/// Create a new apply based on an old one, but with a different
23672417
/// function being applied.
23682418
ApplySite

0 commit comments

Comments
 (0)