Skip to content

Commit 792dee2

Browse files
committed
SIL: support specialized 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 895eb2a commit 792dee2

File tree

11 files changed

+56
-34
lines changed

11 files changed

+56
-34
lines changed

include/swift/SIL/InstructionUtils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
#include "swift/SIL/InstWrappers.h"
1717
#include "swift/SIL/RuntimeEffect.h"
18-
#include "swift/SIL/SILInstruction.h"
18+
#include "swift/SIL/SILModule.h"
1919

2020
namespace swift {
2121

@@ -233,6 +233,9 @@ bool visitExplodedTupleType(SILType type,
233233
bool visitExplodedTupleValue(SILValue value,
234234
llvm::function_ref<SILValue(SILValue, std::optional<unsigned>)> callback);
235235

236+
std::pair<SILFunction *, SILWitnessTable *>
237+
lookUpFunctionInWitnessTable(WitnessMethodInst *wmi, SILModule::LinkingMode linkingMode);
238+
236239
} // end namespace swift
237240

238241
#endif

include/swift/SIL/SILInstruction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7715,6 +7715,13 @@ class WitnessMethodInst final
77157715
return getMember().getDecl()->getDeclContext()->getSelfProtocolDecl();
77167716
}
77177717

7718+
// Returns true if it's expected that the witness method is looked up up from
7719+
// a specialized witness table.
7720+
// This is the case in Embedded Swift.
7721+
bool isSpecialized() const {
7722+
return !getType().castTo<SILFunctionType>()->isPolymorphic();
7723+
}
7724+
77187725
ProtocolConformanceRef getConformance() const { return Conformance; }
77197726
};
77207727

include/swift/SIL/SILModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ class SILModule {
853853
std::pair<SILFunction *, SILWitnessTable *>
854854
lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
855855
SILDeclRef Requirement,
856+
bool lookupInSpecializedWitnessTable,
856857
SILModule::LinkingMode linkingMode);
857858

858859
/// Look up the SILDefaultWitnessTable representing the default witnesses

lib/SIL/IR/SILModule.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ SerializedSILLoader *SILModule::getSILLoader() {
531531
std::pair<SILFunction *, SILWitnessTable *>
532532
SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
533533
SILDeclRef Requirement,
534+
bool lookupInSpecializedWitnessTable,
534535
SILModule::LinkingMode linkingMode) {
535536
if (!C.isConcrete())
536537
return {nullptr, nullptr};
@@ -539,7 +540,12 @@ SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
539540
SILLinkerVisitor linker(*this, linkingMode);
540541
linker.processConformance(C);
541542
}
542-
SILWitnessTable *wt = lookUpWitnessTable(C.getConcrete()->getRootConformance());
543+
ProtocolConformance *conf = C.getConcrete();
544+
if (!isa<SpecializedProtocolConformance>(conf) || !lookupInSpecializedWitnessTable) {
545+
conf = conf->getRootConformance();
546+
}
547+
548+
SILWitnessTable *wt = lookUpWitnessTable(conf);
543549

544550
if (!wt) {
545551
LLVM_DEBUG(llvm::dbgs() << " Failed speculative lookup of "

lib/SIL/Utils/CalleeCache.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "swift/SIL/CalleeCache.h"
1414
#include "swift/SIL/SILModule.h"
15+
#include "swift/SIL/InstructionUtils.h"
1516
#include "swift/AST/ProtocolConformance.h"
1617
#include "swift/Basic/Assertions.h"
1718
#include "llvm/Support/Compiler.h"
@@ -256,8 +257,7 @@ CalleeCache::getSingleCalleeForWitnessMethod(WitnessMethodInst *WMI) const {
256257
SILWitnessTable *WT;
257258

258259
// Attempt to find a specific callee for the given conformance and member.
259-
std::tie(CalleeFn, WT) = WMI->getModule().lookUpFunctionInWitnessTable(
260-
WMI->getConformance(), WMI->getMember(), SILModule::LinkingMode::LinkNormal);
260+
std::tie(CalleeFn, WT) = lookUpFunctionInWitnessTable(WMI, SILModule::LinkingMode::LinkNormal);
261261

262262
return CalleeFn;
263263
}

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,3 +1389,11 @@ bool swift::visitExplodedTupleValue(
13891389

13901390
return true;
13911391
}
1392+
1393+
std::pair<SILFunction *, SILWitnessTable *>
1394+
swift::lookUpFunctionInWitnessTable(WitnessMethodInst *wmi,
1395+
SILModule::LinkingMode linkingMode) {
1396+
SILModule &mod = wmi->getModule();
1397+
return mod.lookUpFunctionInWitnessTable(wmi->getConformance(), wmi->getMember(),
1398+
wmi->isSpecialized(), linkingMode);
1399+
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4114,29 +4114,31 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
41144114
== F.getModule().Types.getProtocolWitnessRepresentation(protocol),
41154115
"result of witness_method must have correct representation for protocol");
41164116

4117-
require(methodType->isPolymorphic(),
4118-
"result of witness_method must be polymorphic");
4119-
4120-
auto genericSig = methodType->getInvocationGenericSignature();
4121-
4122-
auto selfGenericParam = genericSig.getGenericParams()[0];
4123-
require(selfGenericParam->getDepth() == 0
4124-
&& selfGenericParam->getIndex() == 0,
4125-
"method should be polymorphic on Self parameter at depth 0 index 0");
4126-
std::optional<Requirement> selfRequirement;
4127-
for (auto req : genericSig.getRequirements()) {
4128-
if (req.getKind() != RequirementKind::SameType) {
4129-
selfRequirement = req;
4130-
break;
4117+
if (methodType->isPolymorphic()) {
4118+
require(methodType->isPolymorphic(),
4119+
"result of witness_method must be polymorphic");
4120+
4121+
auto genericSig = methodType->getInvocationGenericSignature();
4122+
4123+
auto selfGenericParam = genericSig.getGenericParams()[0];
4124+
require(selfGenericParam->getDepth() == 0
4125+
&& selfGenericParam->getIndex() == 0,
4126+
"method should be polymorphic on Self parameter at depth 0 index 0");
4127+
std::optional<Requirement> selfRequirement;
4128+
for (auto req : genericSig.getRequirements()) {
4129+
if (req.getKind() != RequirementKind::SameType) {
4130+
selfRequirement = req;
4131+
break;
4132+
}
41314133
}
4132-
}
41334134

4134-
require(selfRequirement &&
4135-
selfRequirement->getKind() == RequirementKind::Conformance,
4136-
"first non-same-typerequirement should be conformance requirement");
4137-
const auto protos = genericSig->getRequiredProtocols(selfGenericParam);
4138-
require(std::find(protos.begin(), protos.end(), protocol) != protos.end(),
4139-
"requirement Self parameter must conform to called protocol");
4135+
require(selfRequirement &&
4136+
selfRequirement->getKind() == RequirementKind::Conformance,
4137+
"first non-same-typerequirement should be conformance requirement");
4138+
const auto protos = genericSig->getRequiredProtocols(selfGenericParam);
4139+
require(std::find(protos.begin(), protos.end(), protocol) != protos.end(),
4140+
"requirement Self parameter must conform to called protocol");
4141+
}
41404142

41414143
auto lookupType = AMI->getLookupType();
41424144
if (getLocalArchetypeOf(lookupType) || lookupType->hasDynamicSelfType()) {

lib/SILOptimizer/Mandatory/DiagnoseInfiniteRecursion.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ static bool isRecursiveCall(FullApplySite applySite) {
122122
}
123123

124124
if (auto *WMI = dyn_cast<WitnessMethodInst>(callee)) {
125-
auto funcAndTable = parentFunc->getModule().lookUpFunctionInWitnessTable(
126-
WMI->getConformance(), WMI->getMember(), SILModule::LinkingMode::LinkNormal);
125+
auto funcAndTable = lookUpFunctionInWitnessTable(WMI, SILModule::LinkingMode::LinkNormal);
127126
return funcAndTable.first == parentFunc;
128127
}
129128
return false;

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,8 +1134,6 @@ SILInstruction *SILCombiner::createApplyWithConcreteType(
11341134
FullApplySite Apply,
11351135
const llvm::SmallDenseMap<unsigned, ConcreteOpenedExistentialInfo> &COAIs,
11361136
SILBuilderContext &BuilderCtx) {
1137-
// Ensure that the callee is polymorphic.
1138-
assert(Apply.getOrigCalleeType()->isPolymorphic());
11391137

11401138
// Create the new set of arguments to apply including their substitutions.
11411139
SubstitutionMap NewCallSubs = Apply.getSubstitutionMap();

lib/SILOptimizer/Utils/ConstExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) {
433433
UnknownReason::UnknownWitnessMethodConformance);
434434
auto &module = wmi->getModule();
435435
SILFunction *fn =
436-
module.lookUpFunctionInWitnessTable(conf, wmi->getMember(),
436+
module.lookUpFunctionInWitnessTable(conf, wmi->getMember(), wmi->isSpecialized(),
437437
SILModule::LinkingMode::LinkAll).first;
438438
// If we were able to resolve it, then we can proceed.
439439
if (fn)

0 commit comments

Comments
 (0)