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