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