@@ -1977,6 +1977,46 @@ void IRGenFunction::emitAllExtractValues(llvm::Value *value,
1977
1977
out.add (Builder.CreateExtractValue (value, i));
1978
1978
}
1979
1979
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
+
1980
2020
std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize (
1981
2021
IRGenFunction &IGF, SILFunctionTypeRepresentation representation,
1982
2022
FunctionPointer functionPointer, llvm::Value *thickContext,
@@ -1998,9 +2038,11 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
1998
2038
if (auto authInfo = functionPointer.getAuthInfo ()) {
1999
2039
ptr = emitPointerAuthAuth (IGF, ptr, authInfo);
2000
2040
}
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 );
2004
2046
}
2005
2047
return *afpPtrValue;
2006
2048
};
@@ -4800,6 +4842,8 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
4800
4842
auto *fnPtr = Value;
4801
4843
if (auto authInfo = AuthInfo) {
4802
4844
fnPtr = emitPointerAuthAuth (IGF, fnPtr, authInfo);
4845
+ if (IGF.IGM .getOptions ().IndirectAsyncFunctionPointer )
4846
+ fnPtr = emitIndirectAsyncFunctionPointer (IGF, fnPtr);
4803
4847
}
4804
4848
auto *descriptorPtr =
4805
4849
IGF.Builder .CreateBitCast (fnPtr, IGF.IGM .AsyncFunctionPointerPtrTy );
0 commit comments