@@ -2163,6 +2163,42 @@ static bool isConstantWitnessTable(SILWitnessTable *wt) {
21632163 return true ;
21642164}
21652165
2166+ static void addWTableTypeMetadata (IRGenModule &IGM,
2167+ llvm::GlobalVariable *global,
2168+ SILWitnessTable *wt) {
2169+ auto conf = wt->getConformance ();
2170+ for (auto entry : wt->getEntries ()) {
2171+ if (entry.getKind () != SILWitnessTable::WitnessKind::Method)
2172+ continue ;
2173+
2174+ auto mw = entry.getMethodWitness ();
2175+ auto member = mw.Requirement ;
2176+ auto &fnProtoInfo =
2177+ IGM.getProtocolInfo (conf->getProtocol (), ProtocolInfoKind::Full);
2178+ auto index = fnProtoInfo.getFunctionIndex (member).forProtocolWitnessTable ();
2179+ auto offset = index.getValue () * IGM.getPointerSize ().getValue ();
2180+ global->addTypeMetadata (offset, typeIdForMethod (IGM, member));
2181+ }
2182+
2183+ auto linkage = stripExternalFromLinkage (wt->getLinkage ());
2184+ switch (linkage) {
2185+ case SILLinkage::Private:
2186+ global->setVCallVisibilityMetadata (
2187+ llvm::GlobalObject::VCallVisibility::VCallVisibilityTranslationUnit);
2188+ break ;
2189+ case SILLinkage::Hidden:
2190+ case SILLinkage::Shared:
2191+ global->setVCallVisibilityMetadata (
2192+ llvm::GlobalObject::VCallVisibility::VCallVisibilityLinkageUnit);
2193+ break ;
2194+ case SILLinkage::Public:
2195+ default :
2196+ global->setVCallVisibilityMetadata (
2197+ llvm::GlobalObject::VCallVisibility::VCallVisibilityPublic);
2198+ break ;
2199+ }
2200+ }
2201+
21662202void IRGenModule::emitSILWitnessTable (SILWitnessTable *wt) {
21672203 // Don't emit a witness table if it is a declaration.
21682204 if (wt->isDeclaration ())
@@ -2207,6 +2243,10 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
22072243 global->setAlignment (
22082244 llvm::MaybeAlign (getWitnessTableAlignment ().getValue ()));
22092245
2246+ if (getOptions ().WitnessMethodElimination ) {
2247+ addWTableTypeMetadata (*this , global, wt);
2248+ }
2249+
22102250 tableSize = wtableBuilder.getTableSize ();
22112251 instantiationFunction = wtableBuilder.buildInstantiationFunction ();
22122252 } else {
@@ -3378,6 +3418,35 @@ void irgen::expandTrailingWitnessSignature(IRGenModule &IGM,
33783418 out.push_back (IGM.WitnessTablePtrTy );
33793419}
33803420
3421+ static llvm::Value *emitWTableSlotLoad (IRGenFunction &IGF, llvm::Value *wtable,
3422+ SILDeclRef member, Address slot) {
3423+ if (IGF.IGM .getOptions ().WitnessMethodElimination ) {
3424+ // For LLVM IR WME, emit a @llvm.type.checked.load with the type of the
3425+ // method.
3426+ llvm::Function *checkedLoadIntrinsic = llvm::Intrinsic::getDeclaration (
3427+ &IGF.IGM .Module , llvm::Intrinsic::type_checked_load);
3428+ auto slotAsPointer = IGF.Builder .CreateBitCast (slot, IGF.IGM .Int8PtrTy );
3429+ auto typeId = typeIdForMethod (IGF.IGM , member);
3430+
3431+ // Arguments for @llvm.type.checked.load: 1) target address, 2) offset -
3432+ // always 0 because target address is directly pointing to the right slot,
3433+ // 3) type identifier, i.e. the mangled name of the *base* method.
3434+ SmallVector<llvm::Value *, 8 > args;
3435+ args.push_back (slotAsPointer.getAddress ());
3436+ args.push_back (llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ));
3437+ args.push_back (llvm::MetadataAsValue::get (*IGF.IGM .LLVMContext , typeId));
3438+
3439+ // TODO/FIXME: Using @llvm.type.checked.load loses the "invariant" marker
3440+ // which could mean redundant loads don't get removed.
3441+ llvm::Value *checkedLoad =
3442+ IGF.Builder .CreateCall (checkedLoadIntrinsic, args);
3443+ return IGF.Builder .CreateExtractValue (checkedLoad, 0 );
3444+ }
3445+
3446+ // Not doing LLVM IR WME, can just be a direct load.
3447+ return IGF.emitInvariantLoad (slot);
3448+ }
3449+
33813450FunctionPointer irgen::emitWitnessMethodValue (IRGenFunction &IGF,
33823451 llvm::Value *wtable,
33833452 SILDeclRef member) {
@@ -3389,10 +3458,9 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
33893458 // Find the witness we're interested in.
33903459 auto &fnProtoInfo = IGF.IGM .getProtocolInfo (proto, ProtocolInfoKind::Full);
33913460 auto index = fnProtoInfo.getFunctionIndex (member);
3392- llvm::Value *slot;
3393- llvm::Value *witnessFnPtr =
3394- emitInvariantLoadOfOpaqueWitness (IGF, wtable,
3395- index.forProtocolWitnessTable (), &slot);
3461+ auto slot =
3462+ slotForLoadOfOpaqueWitness (IGF, wtable, index.forProtocolWitnessTable ());
3463+ llvm::Value *witnessFnPtr = emitWTableSlotLoad (IGF, wtable, member, slot);
33963464
33973465 auto fnType = IGF.IGM .getSILTypes ().getConstantFunctionType (
33983466 IGF.IGM .getMaximalTypeExpansionContext (), member);
@@ -3403,7 +3471,7 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
34033471 auto &schema = fnType->isAsync ()
34043472 ? IGF.getOptions ().PointerAuth .AsyncProtocolWitnesses
34053473 : IGF.getOptions ().PointerAuth .ProtocolWitnesses ;
3406- auto authInfo = PointerAuthInfo::emit (IGF, schema, slot, member);
3474+ auto authInfo = PointerAuthInfo::emit (IGF, schema, slot. getAddress () , member);
34073475
34083476 return FunctionPointer (fnType, witnessFnPtr, authInfo, signature);
34093477}
0 commit comments