Skip to content

Commit 998c7ae

Browse files
committed
IRGen: Outline some of the relative protocol witness table code generation to save on code size
rdar://98583748
1 parent 2626f23 commit 998c7ae

File tree

2 files changed

+95
-57
lines changed

2 files changed

+95
-57
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,7 +2660,19 @@ llvm::Value *irgen::loadParentProtocolWitnessTable(IRGenFunction &IGF,
26602660
index);
26612661
return baseWTable;
26622662
}
2663-
auto &Builder = IGF.Builder;
2663+
2664+
llvm::SmallString<40> fnName;
2665+
llvm::raw_svector_ostream(fnName)
2666+
<< "__swift_relative_protocol_witness_table_parent_"
2667+
<< index.getValue();
2668+
2669+
auto helperFn = cast<llvm::Function>(IGM.getOrCreateHelperFunction(
2670+
fnName, IGM.WitnessTablePtrTy, {IGM.WitnessTablePtrTy},
2671+
[&](IRGenFunction &subIGF) {
2672+
2673+
auto it = subIGF.CurFn->arg_begin();
2674+
llvm::Value *wtable = &*it;
2675+
auto &Builder = subIGF.Builder;
26642676
auto *ptrVal = Builder.CreatePtrToInt(wtable, IGM.IntPtrTy);
26652677
auto *one = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
26662678
auto *isCond = Builder.CreateAnd(ptrVal, one);
@@ -2674,30 +2686,30 @@ llvm::Value *irgen::loadParentProtocolWitnessTable(IRGenFunction &IGF,
26742686
auto *mask = Builder.CreateNot(one);
26752687
auto *wtableAddr = Builder.CreateAnd(ptrVal, mask);
26762688
wtableAddr = Builder.CreateIntToPtr(wtableAddr, IGM.WitnessTablePtrTy);
2677-
auto addr = slotForLoadOfOpaqueWitness(IGF, wtableAddr, index,
2689+
auto addr = slotForLoadOfOpaqueWitness(subIGF, wtableAddr, index,
26782690
false /*isRelative*/);
26792691
llvm::Value *baseWTable = Builder.CreateLoad(addr);
2680-
baseWTable = IGF.Builder.CreateBitCast(baseWTable, IGF.IGM.WitnessTablePtrTy);
2692+
baseWTable = subIGF.Builder.CreateBitCast(baseWTable, IGM.WitnessTablePtrTy);
26812693
Builder.CreateBr(endBB);
26822694

26832695
Builder.emitBlock(isNotCondBB);
2684-
if (auto &schema = IGF.getOptions().PointerAuth.RelativeProtocolWitnessTable) {
2685-
auto info = PointerAuthInfo::emit(IGF, schema, nullptr,
2696+
if (auto &schema = subIGF.getOptions().PointerAuth.RelativeProtocolWitnessTable) {
2697+
auto info = PointerAuthInfo::emit(subIGF, schema, nullptr,
26862698
PointerAuthEntity());
2687-
wtable = emitPointerAuthAuth(IGF, wtable, info);
2699+
wtable = emitPointerAuthAuth(subIGF, wtable, info);
26882700
}
26892701
auto baseWTable2 =
2690-
emitInvariantLoadOfOpaqueWitness(IGF,/*isProtocolWitness*/true, wtable,
2702+
emitInvariantLoadOfOpaqueWitness(subIGF,/*isProtocolWitness*/true, wtable,
26912703
index);
2692-
baseWTable2 = IGF.Builder.CreateBitCast(baseWTable2,
2693-
IGF.IGM.WitnessTablePtrTy);
2694-
if (auto &schema = IGF.getOptions().PointerAuth.RelativeProtocolWitnessTable) {
2695-
auto info = PointerAuthInfo::emit(IGF, schema, nullptr,
2704+
baseWTable2 = subIGF.Builder.CreateBitCast(baseWTable2,
2705+
subIGF.IGM.WitnessTablePtrTy);
2706+
if (auto &schema = subIGF.getOptions().PointerAuth.RelativeProtocolWitnessTable) {
2707+
auto info = PointerAuthInfo::emit(subIGF, schema, nullptr,
26962708
PointerAuthEntity());
2697-
baseWTable2 = emitPointerAuthSign(IGF, baseWTable2, info);
2709+
baseWTable2 = emitPointerAuthSign(subIGF, baseWTable2, info);
26982710

2699-
baseWTable2 = IGF.Builder.CreateBitCast(baseWTable2,
2700-
IGF.IGM.WitnessTablePtrTy);
2711+
baseWTable2 = subIGF.Builder.CreateBitCast(baseWTable2,
2712+
IGM.WitnessTablePtrTy);
27012713
}
27022714

27032715
Builder.CreateBr(endBB);
@@ -2706,7 +2718,15 @@ llvm::Value *irgen::loadParentProtocolWitnessTable(IRGenFunction &IGF,
27062718
auto *phi = Builder.CreatePHI(wtable->getType(), 2);
27072719
phi->addIncoming(baseWTable, isCondBB);
27082720
phi->addIncoming(baseWTable2, isNotCondBB);
2709-
return phi;
2721+
Builder.CreateRet(phi);
2722+
2723+
}, true /*noinline*/));
2724+
2725+
auto *call = IGF.Builder.CreateCallWithoutDbgLoc(
2726+
helperFn->getFunctionType(), helperFn, {wtable});
2727+
call->setCallingConv(IGF.IGM.DefaultCC);
2728+
call->setDoesNotThrow();
2729+
return call;
27102730
}
27112731

27122732
llvm::Value *irgen::loadConditionalConformance(IRGenFunction &IGF,
@@ -3827,6 +3847,49 @@ static llvm::Value *emitWTableSlotLoad(IRGenFunction &IGF, llvm::Value *wtable,
38273847
return IGF.emitInvariantLoad(slot);
38283848
}
38293849

3850+
static FunctionPointer emitRelativeProtocolWitnessTableAccess(IRGenFunction &IGF,
3851+
WitnessIndex index,
3852+
llvm::Value *wtable,
3853+
SILDeclRef member) {
3854+
auto witnessTableTy = wtable->getType();
3855+
auto &IGM = IGF.IGM;
3856+
llvm::SmallString<40> fnName;
3857+
auto entity = LinkEntity::forMethodDescriptor(member);
3858+
auto mangled = entity.mangleAsString();
3859+
llvm::raw_svector_ostream(fnName)
3860+
<< "__swift_relative_protocol_witness_table_access_"
3861+
<< index.forProtocolWitnessTable().getValue()
3862+
<< "_" << mangled;
3863+
3864+
auto fnType = IGF.IGM.getSILTypes().getConstantFunctionType(
3865+
IGF.IGM.getMaximalTypeExpansionContext(), member);
3866+
Signature signature = IGF.IGM.getSignature(fnType);
3867+
3868+
auto helperFn = cast<llvm::Function>(IGM.getOrCreateHelperFunction(
3869+
fnName, IGM.Int8PtrTy, {witnessTableTy},
3870+
[&](IRGenFunction &subIGF) {
3871+
3872+
auto it = subIGF.CurFn->arg_begin();
3873+
llvm::Value *wtable = &*it;
3874+
wtable = subIGF.optionallyLoadFromConditionalProtocolWitnessTable(wtable);
3875+
auto slot = slotForLoadOfOpaqueWitness(subIGF, wtable,
3876+
index.forProtocolWitnessTable(),
3877+
true);
3878+
llvm::Value *witnessFnPtr = emitWTableSlotLoad(subIGF, wtable, member, slot,
3879+
true);
3880+
3881+
subIGF.Builder.CreateRet(witnessFnPtr);
3882+
3883+
}, true /*noinline*/));
3884+
3885+
auto *call = IGF.Builder.CreateCallWithoutDbgLoc(
3886+
helperFn->getFunctionType(), helperFn, {wtable});
3887+
call->setCallingConv(IGF.IGM.DefaultCC);
3888+
call->setDoesNotThrow();
3889+
auto fn = IGF.Builder.CreateBitCast(call, signature.getType()->getPointerTo());
3890+
return FunctionPointer::createUnsigned(fnType, fn, signature, true);
3891+
}
3892+
38303893
FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
38313894
llvm::Value *wtable,
38323895
SILDeclRef member) {
@@ -3839,22 +3902,22 @@ FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF,
38393902
auto &fnProtoInfo = IGF.IGM.getProtocolInfo(proto, ProtocolInfoKind::Full);
38403903
auto index = fnProtoInfo.getFunctionIndex(member);
38413904
auto isRelativeTable = IGF.IGM.IRGen.Opts.UseRelativeProtocolWitnessTables;
3905+
if (isRelativeTable) {
3906+
return emitRelativeProtocolWitnessTableAccess(IGF, index, wtable, member);
3907+
}
3908+
38423909
wtable = IGF.optionallyLoadFromConditionalProtocolWitnessTable(wtable);
38433910
auto slot =
38443911
slotForLoadOfOpaqueWitness(IGF, wtable, index.forProtocolWitnessTable(),
3845-
isRelativeTable);
3912+
false/*isRelativeTable*/);
38463913
llvm::Value *witnessFnPtr = emitWTableSlotLoad(IGF, wtable, member, slot,
3847-
isRelativeTable);
3914+
false/*isRelativeTable*/);
38483915

38493916
auto fnType = IGF.IGM.getSILTypes().getConstantFunctionType(
38503917
IGF.IGM.getMaximalTypeExpansionContext(), member);
38513918
Signature signature = IGF.IGM.getSignature(fnType);
38523919
witnessFnPtr = IGF.Builder.CreateBitCast(witnessFnPtr,
38533920
signature.getType()->getPointerTo());
3854-
if (isRelativeTable) {
3855-
return FunctionPointer::createUnsigned(fnType, witnessFnPtr, signature,
3856-
true);
3857-
}
38583921

38593922
auto &schema = fnType->isAsync()
38603923
? IGF.getOptions().PointerAuth.AsyncProtocolWitnesses

test/IRGen/relative_protocol_witness_table.swift

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ func instantiate_conditional_conformance_2nd<T>(_ t : T) where T: Sub, T.S == T
204204

205205
// CHECK: define{{.*}} swiftcc void @"$s1A14requireWitnessyyxAA8FuncOnlyRzlF"(%swift.opaque* noalias nocapture {{%.*}}, %swift.type* {{%.*}}, i8** [[PWT:%.*]])
206206
// CHECK:[[ENTRY:.*]]:
207+
// CHECK: [[T4:%.*]] = call i8* @"__swift_relative_protocol_witness_table_access_1_$s1A8FuncOnlyP1ayyFTq"(i8** [[PWT]])
208+
// CHECK: [[T5:%.*]] = bitcast i8* [[T4]] to void (%swift.opaque*, %swift.type*, i8**)*
209+
// CHECK: call{{.*}} swiftcc void [[T5]]
210+
211+
// CHECK: define{{.*}} hidden i8* @"__swift_relative_protocol_witness_table_access_1_$s1A8FuncOnlyP1ayyFTq"(i8** [[PWT:%.*]])
207212
// CHECK: [[T0:%.*]] = ptrtoint i8** [[PWT]] to i64
208213
// CHECK: [[T1:%.*]] = and i64 [[T0]], 1
209214
// CHECK: [[C:%.*]] = icmp eq i64 [[T1]], 1
@@ -229,12 +234,15 @@ func instantiate_conditional_conformance_2nd<T>(_ t : T) where T: Sub, T.S == T
229234
// CHECK: [[T2:%.*]] = ptrtoint i32* [[SLOT]] to i64
230235
// CHECK: [[T3:%.*]] = add i64 [[T2]], [[T1]]
231236
// CHECK: [[T4:%.*]] = inttoptr i64 [[T3]] to i8*
232-
// CHECK: [[T5:%.*]] = bitcast i8* [[T4]] to void (%swift.opaque*, %swift.type*, i8**)*
233-
// CHECK: call{{.*}} swiftcc void [[T5]]
237+
// CHECK: ret i8* [[T4]]
234238

235239
// Parent witness entry access.
236240

237241
// CHECK: define hidden swiftcc void @"$s1A15requireWitness2yyxAA9InheritedRzlF"(%swift.opaque* noalias nocapture {{%.*}}, %swift.type* {{%.*}}, i8** [[T_INHERITED:%.*]])
242+
// CHECK: [[T_FUNCONLY:%.*]] = call i8** @__swift_relative_protocol_witness_table_parent_1(i8** [[T_INHERITED]])
243+
// CHECK: call i8* @"__swift_relative_protocol_witness_table_access_1_$s1A8FuncOnlyP1ayyFTq"(i8** [[T_FUNCONLY]])
244+
245+
// CHECK: define{{.*}} hidden i8** @__swift_relative_protocol_witness_table_parent_1(i8** [[T_INHERITED:%.*]])
238246
// CHECK: [[T0:%.*]] = ptrtoint i8** [[T_INHERITED]] to i64
239247
// CHECK: [[T1:%.*]] = and i64 [[T0]], 1
240248
// CHECK: [[T2:%.*]] = icmp eq i64 [[T1]], 1
@@ -323,40 +331,7 @@ func instantiate_conditional_conformance_2nd<T>(_ t : T) where T: Sub, T.S == T
323331
// CHECK: [[T2:%.*]] = bitcast i8** [[C1]] to i8***
324332
// CHECK: [[T3:%.*]] = getelementptr inbounds i8**, i8*** [[T2]], i32 0
325333
// CHECK: [[T4:%.*]] = load i8**, i8*** [[T3]]
326-
// CHECK: [[T5:%.*]] = ptrtoint i8** [[T4]] to i64
327-
// CHECK: [[T6:%.*]] = and i64 [[T5]], 1
328-
// CHECK: [[T7:%.*]] = icmp eq i64 [[T6]], 1
329-
// CHECK: br i1 [[T7]], label %[[T8:.*]], label %[[T14:.*]]
330-
331-
// CHECK: [[T8]]:
332-
// CHECK: [[T9:%.*]] = and i64 [[T5]], -2
333-
// CHECK: [[T10:%.*]] = inttoptr i64 [[T9]] to i8**
334-
// CHECK: [[T11:%.*]] = getelementptr inbounds i8*, i8** [[T10]], i32 1
335-
// CHECK: [[T12:%.*]] = load i8*, i8** [[T11]]
336-
// CHECK: [[T13:%.*]] = bitcast i8* [[T12]] to i8**
337-
// CHECK: br label %[[T23:.*]]
338-
339-
// CHECK: [[T14]]:
340-
// CHECK-arm64e: [[P0:%.*]] = ptrtoint i8** [[T4]] to i64
341-
// CHECK-arm64e: [[P1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P0]], i32 2, i64 47152)
342-
// CHECK-arm64e: [[P2:%.*]] = inttoptr i64 [[P1]] to i8**
343-
// CHECK-arm64e: [[T15:%.*]] = bitcast i8** [[P2]] to i32*
344-
// CHECK-x86_64: [[T15:%.*]] = bitcast i8** [[T4]] to i32*
345-
// CHECK-arm64: [[T15:%.*]] = bitcast i8** [[T4]] to i32*
346-
// CHECK: [[T16:%.*]] = getelementptr inbounds i32, i32* [[T15]], i32 1
347-
// CHECK: [[T17:%.*]] = load i32, i32* [[T16]]
348-
// CHECK: [[T18:%.*]] = sext i32 [[T17]] to i64
349-
// CHECK: [[T19:%.*]] = ptrtoint i32* [[T16]] to i64
350-
// CHECK: [[T20:%.*]] = add i64 [[T19]], [[T18]]
351-
// CHECK: [[T21:%.*]] = inttoptr i64 [[T20]] to i8*
352-
// CHECK: [[T22:%.*]] = bitcast i8* [[T21]] to i8**
353-
// CHECK-arm64e: [[P0:%.*]] = ptrtoint i8** [[T22]] to i64
354-
// CHECK-arm64e: [[P1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[P0]], i32 2, i64 47152)
355-
// CHECK-arm64e: [[T22:%.*]] = inttoptr i64 [[P1]] to i8**
356-
// CHECK: br label %[[T23]]
357-
358-
// CHECK: [[T23]]:
359-
// CHECK: [[TBASE:%.*]] = phi i8** [ [[T13]], %[[T8]] ], [ [[T22]], %[[T14]] ]
334+
// CHECK: [[TBASE:%.*]] = call i8** @__swift_relative_protocol_witness_table_parent_1(i8** [[T4]])
360335
// CHECK: [[T24:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* [[C2]], i32 0, i32 0
361336
// CHECK: [[T25:%.*]] = getelementptr inbounds i8**, i8*** [[T24]], i32 0
362337
// CHECK: store i8** [[TBASE]], i8*** [[T25]]

0 commit comments

Comments
 (0)