@@ -1977,6 +1977,46 @@ void IRGenFunction::emitAllExtractValues(llvm::Value *value,
19771977 out.add (Builder.CreateExtractValue (value, i));
19781978}
19791979
1980+ namespace {
1981+ // TODO(compnerd) analyze if this should be out-lined via a runtime call rather
1982+ // than be open-coded. This needs to account for the fact that we are able to
1983+ // statically optimize this often times due to CVP changing the select to a
1984+ // `select i1 true, ...`.
1985+ llvm::Value *emitIndirectAsyncFunctionPointer (IRGenFunction &IGF,
1986+ llvm::Value *pointer) {
1987+ llvm::IntegerType *IntPtrTy = IGF.IGM .IntPtrTy ;
1988+ llvm::Type *AsyncFunctionPointerPtrTy = IGF.IGM .AsyncFunctionPointerPtrTy ;
1989+ llvm::Constant *Zero =
1990+ llvm::Constant::getIntegerValue (IntPtrTy, APInt (IntPtrTy->getBitWidth (),
1991+ 0 ));
1992+ llvm::Constant *One =
1993+ llvm::Constant::getIntegerValue (IntPtrTy, APInt (IntPtrTy->getBitWidth (),
1994+ 1 ));
1995+ llvm::Constant *NegativeOne =
1996+ llvm::Constant::getIntegerValue (IntPtrTy, APInt (IntPtrTy->getBitWidth (),
1997+ -2 ));
1998+ swift::irgen::Alignment PointerAlignment = IGF.IGM .getPointerAlignment ();
1999+
2000+ llvm::Value *PtrToInt = IGF.Builder .CreatePtrToInt (pointer, IntPtrTy);
2001+ llvm::Value *And = IGF.Builder .CreateAnd (PtrToInt, One);
2002+ llvm::Value *ICmp = IGF.Builder .CreateICmpEQ (And, Zero);
2003+
2004+ llvm::Value *BitCast =
2005+ IGF.Builder .CreateBitCast (pointer, AsyncFunctionPointerPtrTy);
2006+
2007+ llvm::Value *UntaggedPointer = IGF.Builder .CreateAnd (PtrToInt, NegativeOne);
2008+ llvm::Value *IntToPtr =
2009+ IGF.Builder .CreateIntToPtr (UntaggedPointer,
2010+ AsyncFunctionPointerPtrTy->getPointerTo ());
2011+ llvm::Value *Load = IGF.Builder .CreateLoad (IntToPtr, PointerAlignment);
2012+
2013+ // (select (icmp eq, (and (ptrtoint %AsyncFunctionPointer), 1), 0),
2014+ // (%AsyncFunctionPointer),
2015+ // (inttoptr (and (ptrtoint %AsyncFunctionPointer), -2)))
2016+ return IGF.Builder .CreateSelect (ICmp, BitCast, Load);
2017+ }
2018+ }
2019+
19802020std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize (
19812021 IRGenFunction &IGF, SILFunctionTypeRepresentation representation,
19822022 FunctionPointer functionPointer, llvm::Value *thickContext,
@@ -1998,9 +2038,11 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
19982038 if (auto authInfo = functionPointer.getAuthInfo ()) {
19992039 ptr = emitPointerAuthAuth (IGF, ptr, authInfo);
20002040 }
2001- auto *afpPtr =
2002- IGF.Builder .CreateBitCast (ptr, IGF.IGM .AsyncFunctionPointerPtrTy );
2003- afpPtrValue = afpPtr;
2041+ afpPtrValue =
2042+ (IGF.IGM .getOptions ().IndirectAsyncFunctionPointer )
2043+ ? emitIndirectAsyncFunctionPointer (IGF, ptr)
2044+ : IGF.Builder .CreateBitCast (ptr,
2045+ IGF.IGM .AsyncFunctionPointerPtrTy );
20042046 }
20052047 return *afpPtrValue;
20062048 };
@@ -4800,6 +4842,8 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
48004842 auto *fnPtr = Value;
48014843 if (auto authInfo = AuthInfo) {
48024844 fnPtr = emitPointerAuthAuth (IGF, fnPtr, authInfo);
4845+ if (IGF.IGM .getOptions ().IndirectAsyncFunctionPointer )
4846+ fnPtr = emitIndirectAsyncFunctionPointer (IGF, fnPtr);
48034847 }
48044848 auto *descriptorPtr =
48054849 IGF.Builder .CreateBitCast (fnPtr, IGF.IGM .AsyncFunctionPointerPtrTy );
0 commit comments