@@ -2163,6 +2163,42 @@ static bool isConstantWitnessTable(SILWitnessTable *wt) {
2163
2163
return true ;
2164
2164
}
2165
2165
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
+
2166
2202
void IRGenModule::emitSILWitnessTable (SILWitnessTable *wt) {
2167
2203
// Don't emit a witness table if it is a declaration.
2168
2204
if (wt->isDeclaration ())
@@ -2207,6 +2243,10 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
2207
2243
global->setAlignment (
2208
2244
llvm::MaybeAlign (getWitnessTableAlignment ().getValue ()));
2209
2245
2246
+ if (getOptions ().WitnessMethodElimination ) {
2247
+ addWTableTypeMetadata (*this , global, wt);
2248
+ }
2249
+
2210
2250
tableSize = wtableBuilder.getTableSize ();
2211
2251
instantiationFunction = wtableBuilder.buildInstantiationFunction ();
2212
2252
} else {
@@ -3378,6 +3418,35 @@ void irgen::expandTrailingWitnessSignature(IRGenModule &IGM,
3378
3418
out.push_back (IGM.WitnessTablePtrTy );
3379
3419
}
3380
3420
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
+
3381
3450
FunctionPointer irgen::emitWitnessMethodValue (IRGenFunction &IGF,
3382
3451
llvm::Value *wtable,
3383
3452
SILDeclRef member) {
@@ -3389,10 +3458,9 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
3389
3458
// Find the witness we're interested in.
3390
3459
auto &fnProtoInfo = IGF.IGM .getProtocolInfo (proto, ProtocolInfoKind::Full);
3391
3460
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);
3396
3464
3397
3465
auto fnType = IGF.IGM .getSILTypes ().getConstantFunctionType (
3398
3466
IGF.IGM .getMaximalTypeExpansionContext (), member);
@@ -3403,7 +3471,7 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
3403
3471
auto &schema = fnType->isAsync ()
3404
3472
? IGF.getOptions ().PointerAuth .AsyncProtocolWitnesses
3405
3473
: IGF.getOptions ().PointerAuth .ProtocolWitnesses ;
3406
- auto authInfo = PointerAuthInfo::emit (IGF, schema, slot, member);
3474
+ auto authInfo = PointerAuthInfo::emit (IGF, schema, slot. getAddress () , member);
3407
3475
3408
3476
return FunctionPointer (fnType, witnessFnPtr, authInfo, signature);
3409
3477
}
0 commit comments