Skip to content

Re-apply "SIL: Use objc_method instruction for Objective-C protocol method calls" #13159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1282,11 +1282,10 @@ class SILBuilder {

WitnessMethodInst *createWitnessMethod(SILLocation Loc, CanType LookupTy,
ProtocolConformanceRef Conformance,
SILDeclRef Member, SILType MethodTy,
bool Volatile = false) {
SILDeclRef Member, SILType MethodTy) {
return insert(WitnessMethodInst::create(
getSILDebugLocation(Loc), LookupTy, Conformance, Member, MethodTy,
&getFunction(), OpenedArchetypes, Volatile));
&getFunction(), OpenedArchetypes));
}

OpenExistentialAddrInst *
Expand Down
3 changes: 1 addition & 2 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1640,8 +1640,7 @@ SILCloner<ImplClass>::visitWitnessMethodInst(WitnessMethodInst *Inst) {
.createWitnessMethod(
getOpLocation(Inst->getLoc()),
newLookupType, conformance,
Inst->getMember(), Inst->getType(),
Inst->isVolatile()));
Inst->getMember(), Inst->getType()));
}

template<typename ImplClass>
Expand Down
12 changes: 3 additions & 9 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5464,16 +5464,13 @@ class WitnessMethodInst final
CanType LookupType;
ProtocolConformanceRef Conformance;
unsigned NumOperands;
bool Volatile;

WitnessMethodInst(SILDebugLocation DebugLoc, CanType LookupType,
ProtocolConformanceRef Conformance, SILDeclRef Member,
SILType Ty, ArrayRef<SILValue> TypeDependentOperands,
bool Volatile = false)
SILType Ty, ArrayRef<SILValue> TypeDependentOperands)
: InstructionBase(DebugLoc, Ty, Member),
LookupType(LookupType), Conformance(Conformance),
NumOperands(TypeDependentOperands.size()),
Volatile(Volatile) {
NumOperands(TypeDependentOperands.size()) {
TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
TypeDependentOperands);
}
Expand All @@ -5493,8 +5490,7 @@ class WitnessMethodInst final
static WitnessMethodInst *
create(SILDebugLocation DebugLoc, CanType LookupType,
ProtocolConformanceRef Conformance, SILDeclRef Member, SILType Ty,
SILFunction *Parent, SILOpenedArchetypesState &OpenedArchetypes,
bool Volatile = false);
SILFunction *Parent, SILOpenedArchetypesState &OpenedArchetypes);

public:
~WitnessMethodInst() {
Expand All @@ -5510,8 +5506,6 @@ class WitnessMethodInst final
->getAsProtocolOrProtocolExtensionContext();
}

bool isVolatile() const { return Volatile; }

ProtocolConformanceRef getConformance() const { return Conformance; }

ArrayRef<Operand> getAllOperands() const {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 389; // Last change: don't serialize 'self'
const uint16_t VERSION_MINOR = 340; // Last change: remove 'volatile' bit from witness_method

using DeclIDField = BCFixed<31>;

Expand Down
7 changes: 0 additions & 7 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5024,13 +5024,6 @@ IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) {
}

void IRGenSILFunction::visitWitnessMethodInst(swift::WitnessMethodInst *i) {
// For Objective-C classes we need to arrange for a msgSend
// to happen when the method is called.
if (i->getMember().isForeign) {
setLoweredObjCMethod(i, i->getMember());
return;
}

CanType baseTy = i->getLookupType();
ProtocolConformanceRef conformance = i->getConformance();
SILDeclRef member = i->getMember();
Expand Down
1 change: 0 additions & 1 deletion lib/IRGen/LoadableByAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1997,7 +1997,6 @@ static void rewriteFunction(StructLoweringState &pass,
}
case SILInstructionKind::WitnessMethodInst: {
auto *WMI = dyn_cast<WitnessMethodInst>(instr);
assert(!WMI->isVolatile());
assert(WMI && "ValueKind is Witness Method but dyn_cast failed");
newInstr = methodBuilder.createWitnessMethod(
loc, WMI->getLookupType(), WMI->getConformance(), member, newSILType);
Expand Down
5 changes: 1 addition & 4 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3902,9 +3902,6 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
break;
}
case SILInstructionKind::WitnessMethodInst: {
bool IsVolatile = false;
if (parseSILOptional(IsVolatile, *this, "volatile"))
return true;
CanType LookupTy;
SILDeclRef Member;
SILType MethodTy;
Expand Down Expand Up @@ -3945,7 +3942,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
}

ResultVal = B.createWitnessMethod(InstLoc, LookupTy, Conformance, Member,
MethodTy, IsVolatile);
MethodTy);
break;
}
case SILInstructionKind::CopyAddrInst: {
Expand Down
2 changes: 0 additions & 2 deletions lib/SIL/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,6 @@ namespace {

bool visitWitnessMethodInst(const WitnessMethodInst *RHS) {
auto *X = cast<WitnessMethodInst>(LHS);
if (X->isVolatile() != RHS->isVolatile())
return false;
if (X->getMember() != RHS->getMember())
return false;
if (X->getLookupType() != RHS->getLookupType())
Expand Down
5 changes: 2 additions & 3 deletions lib/SIL/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1688,8 +1688,7 @@ WitnessMethodInst *
WitnessMethodInst::create(SILDebugLocation Loc, CanType LookupType,
ProtocolConformanceRef Conformance, SILDeclRef Member,
SILType Ty, SILFunction *F,
SILOpenedArchetypesState &OpenedArchetypes,
bool Volatile) {
SILOpenedArchetypesState &OpenedArchetypes) {
assert(cast<ProtocolDecl>(Member.getDecl()->getDeclContext())
== Conformance.getRequirement());

Expand All @@ -1704,7 +1703,7 @@ WitnessMethodInst::create(SILDebugLocation Loc, CanType LookupType,

declareWitnessTable(Mod, Conformance);
return ::new (Buffer) WitnessMethodInst(Loc, LookupType, Conformance, Member,
Ty, TypeDependentOperands, Volatile);
Ty, TypeDependentOperands);
}

ObjCMethodInst *
Expand Down
2 changes: 0 additions & 2 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,8 +1669,6 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
PrintOptions QualifiedSILTypeOptions =
PrintOptions::printQualifiedSILType();
QualifiedSILTypeOptions.CurrentModule = WMI->getModule().getSwiftModule();
if (WMI->isVolatile())
*this << "[volatile] ";
*this << "$" << WMI->getLookupType() << ", " << WMI->getMember() << " : ";
WMI->getMember().getDecl()->getInterfaceType().print(
PrintState.OS, QualifiedSILTypeOptions);
Expand Down
18 changes: 10 additions & 8 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2184,22 +2184,24 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"result of objc_method");
require(!methodType->getExtInfo().hasContext(),
"result method must be of a context-free function type");
require(methodType->getRepresentation()
== SILFunctionTypeRepresentation::ObjCMethod,
"wrong function type representation");

auto methodSelfType = getMethodSelfType(methodType);
auto operandType = OMI->getOperand()->getType();
auto operandInstanceType = operandType.getSwiftRValueType();
if (auto metatypeType = dyn_cast<MetatypeType>(operandInstanceType))
operandInstanceType = metatypeType.getInstanceType();

if (methodSelfType.isClassOrClassMetatype()) {
if (operandInstanceType.getClassOrBoundGenericClass()) {
auto overrideTy = TC.getConstantOverrideType(member);
requireSameType(
OMI->getType(), SILType::getPrimitiveObjectType(overrideTy),
"result type of objc_method must match abstracted type of method");
require(operandType.isClassOrClassMetatype(),
"operand must be of a class type");
} else {
require(getDynamicMethodType(operandType, OMI->getMember())
.getSwiftRValueType()
->isBindableTo(OMI->getType().getSwiftRValueType()),
"result must be of the method's type");
require(isa<ArchetypeType>(operandInstanceType) ||
operandInstanceType->isObjCExistentialType(),
"operand type must be an archetype or self-conforming existential");
verifyOpenedArchetype(OMI, OMI->getType().getSwiftRValueType());
}

Expand Down
15 changes: 13 additions & 2 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,10 @@ class Callee {
case Kind::IndirectValue:
case Kind::StandaloneFunction:
case Kind::EnumElement:
return false;
case Kind::WitnessMethod:
if (Constant.isForeign)
return true;
return false;
case Kind::ClassMethod:
case Kind::SuperMethod:
Expand Down Expand Up @@ -548,9 +551,17 @@ class Callee {
->getRValueInstanceType()
->getCanonicalType();

SILValue fn = SGF.B.createWitnessMethod(
SILValue fn;

if (!constant->isForeign) {
fn = SGF.B.createWitnessMethod(
Loc, lookupType, ProtocolConformanceRef(proto), *constant,
constantInfo.getSILType(), constant->isForeign);
constantInfo.getSILType());
} else {
fn = SGF.B.createObjCMethod(Loc, borrowedSelf->getValue(),
*constant, constantInfo.getSILType());
}

return ManagedValue::forUnmanaged(fn);
}
case Kind::DynamicMethod: {
Expand Down
24 changes: 5 additions & 19 deletions lib/SILGen/SILGenBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1498,31 +1498,17 @@ getThunkedForeignFunctionRef(SILGenFunction &SGF,
const SILConstantInfo &foreignCI) {
assert(!foreign.isCurried
&& "should not thunk calling convention when curried");
assert(foreign.isForeign);

// Produce a witness_method when thunking ObjC protocol methods.
auto dc = foreign.getDecl()->getDeclContext();
if (isa<ProtocolDecl>(dc) && cast<ProtocolDecl>(dc)->isObjC()) {
assert(subs.size() == 1);
auto thisType = subs[0].getReplacement()->getCanonicalType();
assert(isa<ArchetypeType>(thisType) && "no archetype for witness?!");
SILValue thisArg = args.back().getValue();

SILValue OpenedExistential;
if (!cast<ArchetypeType>(thisType)->getOpenedExistentialType().isNull())
OpenedExistential = thisArg;
auto conformance = ProtocolConformanceRef(cast<ProtocolDecl>(dc));
return SGF.B.createWitnessMethod(loc, thisType, conformance, foreign,
foreignCI.getSILType(),
OpenedExistential);

// Produce a class_method when thunking imported ObjC methods.
} else if (foreignCI.SILFnType->getRepresentation()
// Produce an objc_method when thunking ObjC methods.
if (foreignCI.SILFnType->getRepresentation()
== SILFunctionTypeRepresentation::ObjCMethod) {
SILValue thisArg = args.back().getValue();

return SGF.B.createObjCMethod(loc, thisArg, foreign,
SILType::getPrimitiveObjectType(foreignCI.SILFnType));
foreignCI.getSILType());
}

// Otherwise, emit a function_ref.
return SGF.emitGlobalFunctionRef(loc, foreign);
}
Expand Down
6 changes: 1 addition & 5 deletions lib/SILGen/SILGenThunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,8 @@ static SILValue getNextUncurryLevelRef(SILGenFunction &SGF,
auto origSelfType = protocol->getSelfInterfaceType()->getCanonicalType();
auto substSelfType = origSelfType.subst(subMap)->getCanonicalType();
auto conformance = subMap.lookupConformance(origSelfType, protocol);
SILValue OpenedExistential;
if (substSelfType->isOpenedExistential())
OpenedExistential = selfArg;
return SGF.B.createWitnessMethod(loc, substSelfType, *conformance, next,
constantInfo.getSILType(),
OpenedExistential);
constantInfo.getSILType());
}
}

Expand Down
3 changes: 0 additions & 3 deletions lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,6 @@ CalleeList CalleeCache::getCalleeList(SILDeclRef Decl) const {

// Return a callee list for the given witness method.
CalleeList CalleeCache::getCalleeList(WitnessMethodInst *WMI) const {
if (WMI->isVolatile())
return CalleeList();

// First attempt to see if we can narrow it down to a single
// function based on the conformance.
if (auto *CalleeFn = getSingleCalleeForWitnessMethod(WMI))
Expand Down
3 changes: 1 addition & 2 deletions lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,8 +1050,7 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI,
auto *NewWMI = Builder.createWitnessMethod(WMI->getLoc(),
ConcreteType,
Conformance, WMI->getMember(),
WMI->getType(),
WMI->isVolatile());
WMI->getType());
// Replace only uses of the witness_method in the apply that is going to
// be changed.
MutableArrayRef<Operand> Operands = AI.getInstruction()->getAllOperands();
Expand Down
4 changes: 1 addition & 3 deletions lib/SILOptimizer/Transforms/CSE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,9 +880,6 @@ bool CSE::canHandle(SILInstruction *Inst) {
return false;
return !BI->mayReadOrWriteMemory();
}
if (auto *WMI = dyn_cast<WitnessMethodInst>(Inst)) {
return !WMI->isVolatile();
}
if (auto *EMI = dyn_cast<ExistentialMetatypeInst>(Inst)) {
return !EMI->getOperand()->getType().isAddress();
}
Expand Down Expand Up @@ -937,6 +934,7 @@ bool CSE::canHandle(SILInstruction *Inst) {
case SILInstructionKind::PointerToThinFunctionInst:
case SILInstructionKind::MarkDependenceInst:
case SILInstructionKind::OpenExistentialRefInst:
case SILInstructionKind::WitnessMethodInst:
return true;
default:
return false;
Expand Down
4 changes: 2 additions & 2 deletions lib/SILOptimizer/Transforms/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2371,8 +2371,8 @@ static SILBasicBlock *isObjCMethodCallBlock(SILBasicBlock &Block) {
auto *Apply = dyn_cast<ApplyInst>(&Inst);
if (!Apply)
continue;
auto *Callee = dyn_cast<WitnessMethodInst>(Apply->getCallee());
if (!Callee || !Callee->getMember().isForeign)
auto *Callee = dyn_cast<ObjCMethodInst>(Apply->getCallee());
if (!Callee)
continue;

return Branch->getDestBB();
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1985,7 +1985,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
ExistentialOperand = getLocalValue(ValID3, ExistentialOperandTy);
}
ResultVal = Builder.createWitnessMethod(
Loc, Ty, Conformance, DRef, OperandTy, Attr);
Loc, Ty, Conformance, DRef, OperandTy);
break;
}
case SILInstructionKind::DynamicMethodBranchInst: {
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1730,7 +1730,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {

SILInstWitnessMethodLayout::emitRecord(
Out, ScratchRecord, SILAbbrCodes[SILInstWitnessMethodLayout::Code],
S.addTypeRef(Ty), 0, WMI->isVolatile(),
S.addTypeRef(Ty), 0, 0,
S.addTypeRef(Ty2.getSwiftRValueType()), (unsigned)Ty2.getCategory(),
OperandTy, OperandTyCategory, OperandValueId, ListOfValues);

Expand Down
29 changes: 10 additions & 19 deletions test/SIL/Parser/basic.sil
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ bb0(%0: $Optional<D>):
// Generated from:
// func archetype_member_ref<T:Runcible>(x:T) {
// x.free_method()
// var u = x.associated_method()
// T.static_method()
// }

Expand All @@ -290,28 +289,20 @@ protocol Runcible {
static func static_method()
}

/* SIL parsing of substitutions in apply insts is totally busted.
// C/HECK: $@convention(thin) <T : Runcible> (@in T) -> ()
// CHECK: $@convention(thin) <T where T : Runcible> (@in T) -> ()
sil @_T4arch20archetype_member_refUS_8Runcible___FT1xQ__T_ : $@convention(thin) <T : Runcible> (@in T) -> () {
bb0(%0 : $*T):
// C/HECK: witness_method $*T, #Runcible.free_method!1
%1 = witness_method $*T, #Runcible.free_method!1 : $@cc(method) (@inout T) -> Int
%2 = apply %1(%0) : $@cc(method) (@inout T) -> Int
%3 = alloc_stack $@thick T.U.Type
// C/HECK: witness_method $*T, #Runcible.associated_method!1
%4 = witness_method $*T, #Runcible.associated_method!1 : $@cc(method) (@inout T) -> @thick T.U.Type
%5 = apply %4(%0) : $@cc(method) (@inout T) -> @thick T.U.Type
store %5 to %3 : $*@thick T.U.Type
%7 = metatype $@thick T.Type
// C/HECK: witness_method [volatile] $*T, #Runcible.static_method!1
%8 = witness_method [volatile] $*T, #Runcible.static_method!1 : $(@thick T.Type) -> ()
%9 = apply %8(%7) : $(@thick T.Type) -> ()
dealloc_stack %3 : $*@thick T.U.Type
%11 = tuple ()
// CHECK: witness_method $T, #Runcible.free_method!1
%1 = witness_method $T, #Runcible.free_method!1 : $@convention(witness_method: Runcible) <Self : Runcible> (@in Self) -> Int
%2 = apply %1<T>(%0) : $@convention(witness_method: Runcible) <Self : Runcible> (@in Self) -> Int
%3 = metatype $@thick T.Type
// CHECK: witness_method $T, #Runcible.static_method!1
%4 = witness_method $T, #Runcible.static_method!1 : $@convention(witness_method: Runcible) <Self : Runcible> (@thick T.Type) -> ()
%5 = apply %4<T>(%3) : $@convention(witness_method: Runcible) <Self : Runcible> (@thick T.Type) -> ()
%6 = tuple ()
destroy_addr %0 : $*T
return %11 : $()
return %6 : $()
}
*/

protocol Bendable { }

Expand Down
4 changes: 2 additions & 2 deletions test/SILGen/foreign_errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,13 @@ class VeryErrorProne : ErrorProne {
func testProtocol(_ p: ErrorProneProtocol) throws {
// CHECK: [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]]
// CHECK: [[T0:%.*]] = open_existential_ref [[BORROWED_ARG0]] : $ErrorProneProtocol to $[[OPENED:@opened(.*) ErrorProneProtocol]]
// CHECK: [[T1:%.*]] = witness_method [volatile] $[[OPENED]], #ErrorProneProtocol.obliterate!1.foreign : {{.*}}, [[T0]] : $[[OPENED]] :
// CHECK: [[T1:%.*]] = objc_method [[T0]] : $[[OPENED]], #ErrorProneProtocol.obliterate!1.foreign : {{.*}}
// CHECK: apply [[T1]]<[[OPENED]]>({{%.*}}, [[T0]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : ErrorProneProtocol> (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, τ_0_0) -> ObjCBool
try p.obliterate()

// CHECK: [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]]
// CHECK: [[T0:%.*]] = open_existential_ref [[BORROWED_ARG0]] : $ErrorProneProtocol to $[[OPENED:@opened(.*) ErrorProneProtocol]]
// CHECK: [[T1:%.*]] = witness_method [volatile] $[[OPENED]], #ErrorProneProtocol.invigorate!1.foreign : {{.*}}, [[T0]] : $[[OPENED]] :
// CHECK: [[T1:%.*]] = objc_method [[T0]] : $[[OPENED]], #ErrorProneProtocol.invigorate!1.foreign : {{.*}}
// CHECK: apply [[T1]]<[[OPENED]]>({{%.*}}, {{%.*}}, [[T0]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : ErrorProneProtocol> (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, Optional<@convention(block) () -> ()>, τ_0_0) -> ObjCBool
try p.invigorate(callback: {})
}
Expand Down
Loading