@@ -1986,6 +1986,46 @@ void IRGenFunction::emitAllExtractValues(llvm::Value *value,
19861986 out.add (Builder.CreateExtractValue (value, i));
19871987}
19881988
1989+ namespace {
1990+ // TODO(compnerd) analyze if this should be out-lined via a runtime call rather
1991+ // than be open-coded. This needs to account for the fact that we are able to
1992+ // statically optimize this often times due to CVP changing the select to a
1993+ // `select i1 true, ...`.
1994+ llvm::Value *emitIndirectAsyncFunctionPointer (IRGenFunction &IGF,
1995+ llvm::Value *pointer) {
1996+ llvm::IntegerType *IntPtrTy = IGF.IGM .IntPtrTy ;
1997+ llvm::Type *AsyncFunctionPointerPtrTy = IGF.IGM .AsyncFunctionPointerPtrTy ;
1998+ llvm::Constant *Zero =
1999+ llvm::Constant::getIntegerValue (IntPtrTy, APInt (IntPtrTy->getBitWidth (),
2000+ 0 ));
2001+ llvm::Constant *One =
2002+ llvm::Constant::getIntegerValue (IntPtrTy, APInt (IntPtrTy->getBitWidth (),
2003+ 1 ));
2004+ llvm::Constant *NegativeOne =
2005+ llvm::Constant::getIntegerValue (IntPtrTy, APInt (IntPtrTy->getBitWidth (),
2006+ -2 ));
2007+ swift::irgen::Alignment PointerAlignment = IGF.IGM .getPointerAlignment ();
2008+
2009+ llvm::Value *PtrToInt = IGF.Builder .CreatePtrToInt (pointer, IntPtrTy);
2010+ llvm::Value *And = IGF.Builder .CreateAnd (PtrToInt, One);
2011+ llvm::Value *ICmp = IGF.Builder .CreateICmpEQ (And, Zero);
2012+
2013+ llvm::Value *BitCast =
2014+ IGF.Builder .CreateBitCast (pointer, AsyncFunctionPointerPtrTy);
2015+
2016+ llvm::Value *UntaggedPointer = IGF.Builder .CreateAnd (PtrToInt, NegativeOne);
2017+ llvm::Value *IntToPtr =
2018+ IGF.Builder .CreateIntToPtr (UntaggedPointer,
2019+ AsyncFunctionPointerPtrTy->getPointerTo ());
2020+ llvm::Value *Load = IGF.Builder .CreateLoad (IntToPtr, PointerAlignment);
2021+
2022+ // (select (icmp eq, (and (ptrtoint %AsyncFunctionPointer), 1), 0),
2023+ // (%AsyncFunctionPointer),
2024+ // (inttoptr (and (ptrtoint %AsyncFunctionPointer), -2)))
2025+ return IGF.Builder .CreateSelect (ICmp, BitCast, Load);
2026+ }
2027+ }
2028+
19892029std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize (
19902030 IRGenFunction &IGF, SILFunctionTypeRepresentation representation,
19912031 FunctionPointer functionPointer, llvm::Value *thickContext,
@@ -2007,9 +2047,11 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
20072047 if (auto authInfo = functionPointer.getAuthInfo ()) {
20082048 ptr = emitPointerAuthAuth (IGF, ptr, authInfo);
20092049 }
2010- auto *afpPtr =
2011- IGF.Builder .CreateBitCast (ptr, IGF.IGM .AsyncFunctionPointerPtrTy );
2012- afpPtrValue = afpPtr;
2050+ afpPtrValue =
2051+ (IGF.IGM .getOptions ().IndirectAsyncFunctionPointer )
2052+ ? emitIndirectAsyncFunctionPointer (IGF, ptr)
2053+ : IGF.Builder .CreateBitCast (ptr,
2054+ IGF.IGM .AsyncFunctionPointerPtrTy );
20132055 }
20142056 return *afpPtrValue;
20152057 };
@@ -4831,6 +4873,8 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
48314873 auto *fnPtr = Value;
48324874 if (auto authInfo = AuthInfo) {
48334875 fnPtr = emitPointerAuthAuth (IGF, fnPtr, authInfo);
4876+ if (IGF.IGM .getOptions ().IndirectAsyncFunctionPointer )
4877+ fnPtr = emitIndirectAsyncFunctionPointer (IGF, fnPtr);
48344878 }
48354879 auto *descriptorPtr =
48364880 IGF.Builder .CreateBitCast (fnPtr, IGF.IGM .AsyncFunctionPointerPtrTy );
0 commit comments