Skip to content

Commit 6bbc96b

Browse files
committed
[IRGen] Added fn ptr to async FunctionPointer.
The address of the function to be called when generating code to invoke the function associated with FunctionPointer which is produced via direct reference is by definition statically known; it is neither necessary nor desireable to load this address out of the AsyncFunctionPointer corresponding to the function. Here, that spurious additional work is skipped. The approach is to add a second value to the FunctionPointer struct. For FunctionPointers whose kind is AsyncFunctionPointer, this value is either null or else the address of the corresponding function. rdar://71376092
1 parent 59a218a commit 6bbc96b

File tree

6 files changed

+82
-20
lines changed

6 files changed

+82
-20
lines changed

lib/IRGen/Callee.h

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ namespace irgen {
234234
/// The actual pointer, either to the function or to its descriptor.
235235
llvm::Value *Value;
236236

237+
/// An additional value whose meaning varies by the FunctionPointer's Kind:
238+
/// - Kind::AsyncFunctionPointer -> pointer to the corresponding function
239+
/// if the FunctionPointer was created via
240+
/// forDirect; nullptr otherwise.
241+
llvm::Value *SecondaryValue;
242+
237243
PointerAuthInfo AuthInfo;
238244

239245
Signature Sig;
@@ -243,9 +249,11 @@ namespace irgen {
243249
/// We may add more arguments to this; try to use the other
244250
/// constructors/factories if possible.
245251
explicit FunctionPointer(Kind kind, llvm::Value *value,
252+
llvm::Value *secondaryValue,
246253
PointerAuthInfo authInfo,
247254
const Signature &signature)
248-
: kind(kind), Value(value), AuthInfo(authInfo), Sig(signature) {
255+
: kind(kind), Value(value), SecondaryValue(secondaryValue),
256+
AuthInfo(authInfo), Sig(signature) {
249257
// The function pointer should have function type.
250258
assert(value->getType()->getPointerElementType()->isFunctionTy());
251259
// TODO: maybe assert similarity to signature.getType()?
@@ -258,18 +266,25 @@ namespace irgen {
258266
}
259267
}
260268

269+
explicit FunctionPointer(Kind kind, llvm::Value *value,
270+
PointerAuthInfo authInfo,
271+
const Signature &signature)
272+
: FunctionPointer(kind, value, nullptr, authInfo, signature){};
273+
261274
// Temporary only!
262275
explicit FunctionPointer(Kind kind, llvm::Value *value,
263276
const Signature &signature)
264277
: FunctionPointer(kind, value, PointerAuthInfo(), signature) {}
265278

266-
static FunctionPointer forDirect(IRGenModule &IGM,
267-
llvm::Constant *value,
279+
static FunctionPointer forDirect(IRGenModule &IGM, llvm::Constant *value,
280+
llvm::Constant *secondaryValue,
268281
CanSILFunctionType fnType);
269282

270283
static FunctionPointer forDirect(Kind kind, llvm::Constant *value,
284+
llvm::Constant *secondaryValue,
271285
const Signature &signature) {
272-
return FunctionPointer(kind, value, PointerAuthInfo(), signature);
286+
return FunctionPointer(kind, value, secondaryValue, PointerAuthInfo(),
287+
signature);
273288
}
274289

275290
static FunctionPointer forExplosionValue(IRGenFunction &IGF,
@@ -295,6 +310,13 @@ namespace irgen {
295310
/// Return the actual function pointer.
296311
llvm::Value *getRawPointer() const { return Value; }
297312

313+
/// Assuming that the receiver is of kind AsyncFunctionPointer, returns the
314+
/// pointer to the corresponding function if available.
315+
llvm::Value *getRawAsyncFunction() const {
316+
assert(kind.isAsyncFunctionPointer());
317+
return SecondaryValue;
318+
}
319+
298320
/// Given that this value is known to have been constructed from
299321
/// a direct function, return the function pointer.
300322
llvm::Constant *getDirectPointer() const {

lib/IRGen/GenCall.cpp

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,18 +1985,33 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
19851985
assert(functionPointer.getKind() != FunctionPointer::Kind::Function);
19861986
bool emitFunction = values.first;
19871987
bool emitSize = values.second;
1988-
auto *ptr = functionPointer.getRawPointer();
1989-
if (auto authInfo = functionPointer.getAuthInfo()) {
1990-
ptr = emitPointerAuthAuth(IGF, ptr, authInfo);
1991-
}
1992-
auto *afpPtr =
1993-
IGF.Builder.CreateBitCast(ptr, IGF.IGM.AsyncFunctionPointerPtrTy);
1988+
// Ensure that the AsyncFunctionPointer is not auth'd if it is not used and
1989+
// that it is not auth'd more than once if it is needed.
1990+
//
1991+
// The AsyncFunctionPointer is not needed in the case where only the function
1992+
// is being loaded and the FunctionPointer was created from a function_ref
1993+
// instruction.
1994+
llvm::Optional<llvm::Value *> afpPtrValue = llvm::None;
1995+
auto getAFPPtr = [&]() {
1996+
if (!afpPtrValue) {
1997+
auto *ptr = functionPointer.getRawPointer();
1998+
if (auto authInfo = functionPointer.getAuthInfo()) {
1999+
ptr = emitPointerAuthAuth(IGF, ptr, authInfo);
2000+
}
2001+
auto *afpPtr =
2002+
IGF.Builder.CreateBitCast(ptr, IGF.IGM.AsyncFunctionPointerPtrTy);
2003+
afpPtrValue = afpPtr;
2004+
}
2005+
return *afpPtrValue;
2006+
};
19942007
llvm::Value *fn = nullptr;
19952008
if (emitFunction) {
19962009
if (functionPointer.useStaticContextSize()) {
19972010
fn = functionPointer.getRawPointer();
2011+
} else if (auto *function = functionPointer.getRawAsyncFunction()) {
2012+
fn = function;
19982013
} else {
1999-
llvm::Value *addrPtr = IGF.Builder.CreateStructGEP(afpPtr, 0);
2014+
llvm::Value *addrPtr = IGF.Builder.CreateStructGEP(getAFPPtr(), 0);
20002015
fn = IGF.emitLoadOfRelativePointer(
20012016
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
20022017
/*expectedType*/ functionPointer.getFunctionType()->getPointerTo());
@@ -2014,7 +2029,7 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
20142029
initialContextSize.getValue());
20152030
} else {
20162031
assert(!functionPointer.useStaticContextSize());
2017-
auto *sizePtr = IGF.Builder.CreateStructGEP(afpPtr, 1);
2032+
auto *sizePtr = IGF.Builder.CreateStructGEP(getAFPPtr(), 1);
20182033
size = IGF.Builder.CreateLoad(sizePtr, IGF.IGM.getPointerAlignment());
20192034
}
20202035
}
@@ -4667,8 +4682,9 @@ Callee irgen::getCFunctionPointerCallee(IRGenFunction &IGF,
46674682

46684683
FunctionPointer FunctionPointer::forDirect(IRGenModule &IGM,
46694684
llvm::Constant *fnPtr,
4685+
llvm::Constant *secondaryValue,
46704686
CanSILFunctionType fnType) {
4671-
return forDirect(fnType, fnPtr, IGM.getSignature(fnType));
4687+
return forDirect(fnType, fnPtr, secondaryValue, IGM.getSignature(fnType));
46724688
}
46734689

46744690
StringRef FunctionPointer::getName(IRGenModule &IGM) const {
@@ -4690,6 +4706,14 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
46904706
case BasicKind::Function:
46914707
return Value;
46924708
case BasicKind::AsyncFunctionPointer: {
4709+
if (auto *rawFunction = getRawAsyncFunction()) {
4710+
// If the pointer to the underlying function is available, it means that
4711+
// this FunctionPointer instance was created via
4712+
// FunctionPointer::forDirect and as such has no AuthInfo.
4713+
assert(!AuthInfo && "have PointerAuthInfo for an async FunctionPointer "
4714+
"for which the raw function is known");
4715+
return rawFunction;
4716+
}
46934717
auto *fnPtr = Value;
46944718
if (auto authInfo = AuthInfo) {
46954719
fnPtr = emitPointerAuthAuth(IGF, fnPtr, authInfo);

lib/IRGen/GenClass.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2653,7 +2653,15 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
26532653
case ClassMetadataLayout::MethodInfo::Kind::DirectImpl: {
26542654
auto fnPtr = llvm::ConstantExpr::getBitCast(methodInfo.getDirectImpl(),
26552655
signature.getType()->getPointerTo());
2656-
return FunctionPointer::forDirect(methodType, fnPtr, signature);
2656+
llvm::Constant *secondaryValue = nullptr;
2657+
if (cast<AbstractFunctionDecl>(method.getDecl())->hasAsync()) {
2658+
auto *silFn = IGF.IGM.getSILFunctionForAsyncFunctionPointer(
2659+
methodInfo.getDirectImpl());
2660+
secondaryValue = cast<llvm::Constant>(
2661+
IGF.IGM.getAddrOfSILFunction(silFn, NotForDefinition));
2662+
}
2663+
return FunctionPointer::forDirect(methodType, fnPtr, secondaryValue,
2664+
signature);
26572665
}
26582666
}
26592667

lib/IRGen/GenKeyPath.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,9 @@ getAccessorForComputedComponent(IRGenModule &IGM,
252252
&ignoreWitnessMetadata,
253253
forwardedArgs);
254254
}
255-
auto fnPtr = FunctionPointer::forDirect(IGM, accessorFn,
256-
accessor->getLoweredFunctionType());
255+
auto fnPtr =
256+
FunctionPointer::forDirect(IGM, accessorFn, /*secondaryValue*/ nullptr,
257+
accessor->getLoweredFunctionType());
257258
auto call = IGF.Builder.CreateCall(fnPtr, forwardedArgs.claimAll());
258259

259260
if (call->getType()->isVoidTy())

lib/IRGen/GenObjC.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,8 +658,9 @@ Callee irgen::getObjCMethodCallee(IRGenFunction &IGF,
658658
Selector selector(method);
659659
llvm::Value *selectorValue = IGF.emitObjCSelectorRefLoad(selector.str());
660660

661-
auto fn = FunctionPointer::forDirect(FunctionPointer::Kind::Function,
662-
messenger, sig);
661+
auto fn =
662+
FunctionPointer::forDirect(FunctionPointer::Kind::Function, messenger,
663+
/*secondaryValue*/ nullptr, sig);
663664
return Callee(std::move(info), fn, receiverValue, selectorValue);
664665
}
665666

lib/IRGen/IRGenSIL.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2526,13 +2526,17 @@ void IRGenSILFunction::visitFunctionRefBaseInst(FunctionRefBaseInst *i) {
25262526
fn, NotForDefinition, false /*isDynamicallyReplaceableImplementation*/,
25272527
isa<PreviousDynamicFunctionRefInst>(i));
25282528
llvm::Constant *value;
2529+
llvm::Constant *secondaryValue;
25292530
if (fpKind.isAsyncFunctionPointer()) {
25302531
value = IGM.getAddrOfAsyncFunctionPointer(fn);
25312532
value = llvm::ConstantExpr::getBitCast(value, fnPtr->getType());
2533+
secondaryValue = IGM.getAddrOfSILFunction(fn, NotForDefinition);
25322534
} else {
25332535
value = fnPtr;
2536+
secondaryValue = nullptr;
25342537
}
2535-
FunctionPointer fp = FunctionPointer(fpKind, value, sig);
2538+
FunctionPointer fp =
2539+
FunctionPointer::forDirect(fpKind, value, secondaryValue, sig);
25362540

25372541
// Store the function as a FunctionPointer so we can avoid bitcasting
25382542
// or thunking if we don't need to.
@@ -6525,16 +6529,18 @@ void IRGenSILFunction::visitWitnessMethodInst(swift::WitnessMethodInst *i) {
65256529
if (IGM.isResilient(conformance.getRequirement(),
65266530
ResilienceExpansion::Maximal)) {
65276531
llvm::Constant *fnPtr = IGM.getAddrOfDispatchThunk(member, NotForDefinition);
6532+
llvm::Constant *secondaryValue = nullptr;
65286533

65296534
if (fnType->isAsync()) {
6535+
secondaryValue = fnPtr;
65306536
auto *fnPtrType = fnPtr->getType();
65316537
fnPtr = IGM.getAddrOfAsyncFunctionPointer(
65326538
LinkEntity::forDispatchThunk(member));
65336539
fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, fnPtrType);
65346540
}
65356541

65366542
auto sig = IGM.getSignature(fnType);
6537-
auto fn = FunctionPointer::forDirect(fnType, fnPtr, sig);
6543+
auto fn = FunctionPointer::forDirect(fnType, fnPtr, secondaryValue, sig);
65386544

65396545
setLoweredFunctionPointer(i, fn);
65406546
return;

0 commit comments

Comments
 (0)