@@ -1744,6 +1744,273 @@ a call to ``llvm.coro.suspend.retcon`` after resuming abnormally.
1744
1744
In a yield-once coroutine, it is undefined behavior if the coroutine
1745
1745
executes a call to ``llvm.coro.suspend.retcon `` after resuming in any way.
1746
1746
1747
+ .. _coro.await.suspend :
1748
+
1749
+ 'llvm.coro.await.suspend' Intrinsic
1750
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1751
+ ::
1752
+
1753
+ declare void @llvm.coro.await.suspend(
1754
+ ptr <awaiter>,
1755
+ ptr <handle>,
1756
+ ptr <await_suspend_function>)
1757
+
1758
+ Overview:
1759
+ """""""""
1760
+
1761
+ The '``llvm.coro.await.suspend ``' intrinsic hides C++ `await-suspend `
1762
+ block code from optimizations on presplit coroutine body
1763
+ to avoid miscompilations. This version of intrinsic corresponds to
1764
+ '``void awaiter.await_suspend(...) ``' variant.
1765
+
1766
+ Arguments:
1767
+ """"""""""
1768
+
1769
+ The first argument is a pointer to `awaiter ` object.
1770
+
1771
+ The second argument is a pointer to the current coroutine's frame.
1772
+
1773
+ The third argument is a pointer to the helper function encapsulating
1774
+ `await-suspend ` logic. Its signature must be
1775
+
1776
+ .. code-block :: llvm
1777
+
1778
+ declare void @await_suspend_function(ptr %awaiter, ptr %hdl)
1779
+
1780
+ Semantics:
1781
+ """"""""""
1782
+
1783
+ The intrinsic must be used between corresponding `coro.save `_ and
1784
+ `coro.suspend `_ calls. It is lowered to an inlined
1785
+ `await_suspend_function ` call during `CoroSplit `_ pass.
1786
+
1787
+ Example:
1788
+ """"""""
1789
+
1790
+ .. code-block :: llvm
1791
+
1792
+ ; before lowering
1793
+ await.suspend:
1794
+ %save = call token @llvm.coro.save(ptr %hdl)
1795
+ call void @llvm.coro.await.suspend(
1796
+ ptr %awaiter,
1797
+ ptr %hdl,
1798
+ ptr @await_suspend_function)
1799
+ %suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
1800
+ ...
1801
+
1802
+ ; after lowering
1803
+ await.suspend:
1804
+ %save = call token @llvm.coro.save(ptr %hdl)
1805
+ ; the call to await_suspend_function is inlined
1806
+ call void @await_suspend_function(
1807
+ ptr %awaiter,
1808
+ ptr %hdl)
1809
+ %suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
1810
+ ...
1811
+
1812
+ ; helper function example
1813
+ define void @await_suspend_function(ptr %awaiter, ptr %hdl)
1814
+ entry:
1815
+ %hdl.tmp = alloca %"struct.std::coroutine_handle"
1816
+ %hdl.result.tmp = alloca %"struct.std::coroutine_handle"
1817
+ %hdl.promise.tmp = alloca %"struct.std::coroutine_handle.0"
1818
+ %hdl.promise = call ptr @"std::corouine_handle<promise_type>::from_address"(ptr %hdl)
1819
+ %hdl.promise.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle.0",
1820
+ ptr %hdl.promise.tmp, i32 0, i32 0
1821
+ %hdl.promise.tmp.dive2 = getelementptr inbounds %"struct.std::coroutine_handle",
1822
+ ptr %hdl.promise.tmp.dive, i32 0, i32 0
1823
+ store ptr %hdl.promise, ptr %hdl.promise.tmp.dive2
1824
+ call void @llvm.memcpy.p0.p0.i64(ptr %hdl.tmp, ptr %hdl.promise.tmp, i64 8, i1 false)
1825
+ %hdl.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle",
1826
+ ptr %hdl.tmp, i32 0, i32 0
1827
+ %hdl.arg = load ptr, ptr %hdl.tmp.dive
1828
+ call void @"Awaiter::await_suspend"(ptr %awaiter, ptr %hdl.arg)
1829
+ ret void
1830
+
1831
+ .. _coro.await.suspend.bool :
1832
+
1833
+ 'llvm.coro.await.suspend.bool' Intrinsic
1834
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1835
+ ::
1836
+
1837
+ declare i1 @llvm.coro.await.suspend.bool(
1838
+ ptr <awaiter>,
1839
+ ptr <handle>,
1840
+ ptr <await_suspend_function>)
1841
+
1842
+ Overview:
1843
+ """""""""
1844
+
1845
+ The '``llvm.coro.await.suspend.bool ``' intrinsic hides C++ `await-suspend `
1846
+ block code from optimizations on presplit coroutine body
1847
+ to avoid miscompilations. This version of intrinsic corresponds to
1848
+ '``bool awaiter.await_suspend(...) ``' variant.
1849
+
1850
+ Arguments:
1851
+ """"""""""
1852
+
1853
+ The first argument is a pointer to `awaiter ` object.
1854
+
1855
+ The second argument is a pointer to the current coroutine's frame.
1856
+
1857
+ The third argument is a pointer to the helper function encapsulating
1858
+ `await-suspend ` logic. Its signature must be
1859
+
1860
+ .. code-block :: llvm
1861
+
1862
+ declare i1 @await_suspend_function(ptr %awaiter, ptr %hdl)
1863
+
1864
+ Semantics:
1865
+ """"""""""
1866
+
1867
+ The intrinsic must be used between corresponding `coro.save `_ and
1868
+ `coro.suspend `_ calls. It is lowered to an inlined
1869
+ `await_suspend_function ` call during `CoroSplit `_ pass.
1870
+
1871
+ If `await_suspend_function ` call returns `true `, the current coroutine is
1872
+ immediately resumed.
1873
+
1874
+ Example:
1875
+ """"""""
1876
+
1877
+ .. code-block :: llvm
1878
+
1879
+ ; before lowering
1880
+ await.suspend:
1881
+ %save = call token @llvm.coro.save(ptr %hdl)
1882
+ %resume = call i1 @llvm.coro.await.suspend(
1883
+ ptr %awaiter,
1884
+ ptr %hdl,
1885
+ ptr @await_suspend_function)
1886
+ br i1 %resume, %await.suspend.bool, %await.ready
1887
+ await.suspend.bool:
1888
+ %suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
1889
+ ...
1890
+ await.ready:
1891
+ call void @"Awaiter::await_ready"(ptr %awaiter)
1892
+ ...
1893
+
1894
+ ; after lowering
1895
+ await.suspend:
1896
+ %save = call token @llvm.coro.save(ptr %hdl)
1897
+ ; the call to await_suspend_function is inlined
1898
+ %resume = call i1 @await_suspend_function(
1899
+ ptr %awaiter,
1900
+ ptr %hdl)
1901
+ br i1 %resume, %await.suspend.bool, %await.ready
1902
+ ...
1903
+
1904
+ ; helper function example
1905
+ define i1 @await_suspend_function(ptr %awaiter, ptr %hdl)
1906
+ entry:
1907
+ %hdl.tmp = alloca %"struct.std::coroutine_handle"
1908
+ %hdl.result.tmp = alloca %"struct.std::coroutine_handle"
1909
+ %hdl.promise.tmp = alloca %"struct.std::coroutine_handle.0"
1910
+ %hdl.promise = call ptr @"std::corouine_handle<promise_type>::from_address"(ptr %hdl)
1911
+ %hdl.promise.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle.0",
1912
+ ptr %hdl.promise.tmp, i32 0, i32 0
1913
+ %hdl.promise.tmp.dive2 = getelementptr inbounds %"struct.std::coroutine_handle",
1914
+ ptr %hdl.promise.tmp.dive, i32 0, i32 0
1915
+ store ptr %hdl.promise, ptr %hdl.promise.tmp.dive2
1916
+ call void @llvm.memcpy.p0.p0.i64(ptr %hdl.tmp, ptr %hdl.promise.tmp, i64 8, i1 false)
1917
+ %hdl.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle",
1918
+ ptr %hdl.tmp, i32 0, i32 0
1919
+ %hdl.arg = load ptr, ptr %hdl.tmp.dive
1920
+ %resume = call i1 @"Awaiter::await_suspend"(ptr %awaiter, ptr %hdl.arg)
1921
+ ret i1 %resume
1922
+
1923
+ .. _coro.await.suspend.handle :
1924
+
1925
+ 'llvm.coro.await.suspend.handle' Intrinsic
1926
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1927
+ ::
1928
+
1929
+ declare ptr @llvm.coro.await.suspend.handle(
1930
+ ptr <awaiter>,
1931
+ ptr <handle>,
1932
+ ptr <await_suspend_function>)
1933
+
1934
+ Overview:
1935
+ """""""""
1936
+
1937
+ The '``llvm.coro.await.suspend.handle ``' intrinsic hides C++ `await-suspend `
1938
+ block code from optimizations on presplit coroutine body
1939
+ to avoid miscompilations. This version of intrinsic corresponds to
1940
+ '``std::corouine_handle<> awaiter.await_suspend(...) ``' variant.
1941
+
1942
+ Arguments:
1943
+ """"""""""
1944
+
1945
+ The first argument is a pointer to `awaiter ` object.
1946
+
1947
+ The second argument is a pointer to the current coroutine's frame.
1948
+
1949
+ The third argument is a pointer to the helper function encapsulating
1950
+ `await-suspend ` logic. Its signature must be
1951
+
1952
+ .. code-block :: llvm
1953
+
1954
+ declare ptr @await_suspend_function(ptr %awaiter, ptr %hdl)
1955
+
1956
+ Semantics:
1957
+ """"""""""
1958
+
1959
+ The intrinsic must be used between corresponding `coro.save `_ and
1960
+ `coro.suspend `_ calls. It is lowered to an inlined
1961
+ `await_suspend_function ` call during `CoroSplit `_ pass.
1962
+
1963
+ `await_suspend_function ` must return a pointer to a valid
1964
+ coroutine frame, which is immediately resumed
1965
+
1966
+ Example:
1967
+ """"""""
1968
+
1969
+ .. code-block :: llvm
1970
+
1971
+ ; before lowering
1972
+ await.suspend:
1973
+ %save = call token @llvm.coro.save(ptr %hdl)
1974
+ %next = call ptr @llvm.coro.await.suspend(
1975
+ ptr %awaiter,
1976
+ ptr %hdl,
1977
+ ptr @await_suspend_function)
1978
+ call void @llvm.coro.resume(%next)
1979
+ ...
1980
+
1981
+ ; after lowering
1982
+ await.suspend:
1983
+ %save = call token @llvm.coro.save(ptr %hdl)
1984
+ ; the call to await_suspend_function is inlined
1985
+ %next = call ptr @await_suspend_function(
1986
+ ptr %awaiter,
1987
+ ptr %hdl)
1988
+ call void @llvm.coro.resume(%next)
1989
+ ...
1990
+
1991
+ ; helper function example
1992
+ define ptr @await_suspend_function(ptr %awaiter, ptr %hdl)
1993
+ entry:
1994
+ %hdl.tmp = alloca %"struct.std::coroutine_handle"
1995
+ %hdl.result.tmp = alloca %"struct.std::coroutine_handle"
1996
+ %hdl.promise.tmp = alloca %"struct.std::coroutine_handle.0"
1997
+ %hdl.promise = call ptr @"std::corouine_handle<promise_type>::from_address"(ptr %hdl)
1998
+ %hdl.promise.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle.0",
1999
+ ptr %hdl.promise.tmp, i32 0, i32 0
2000
+ %hdl.promise.tmp.dive2 = getelementptr inbounds %"struct.std::coroutine_handle",
2001
+ ptr %hdl.promise.tmp.dive, i32 0, i32 0
2002
+ store ptr %hdl.promise, ptr %hdl.promise.tmp.dive2
2003
+ call void @llvm.memcpy.p0.p0.i64(ptr %hdl.tmp, ptr %hdl.promise.tmp, i64 8, i1 false)
2004
+ %hdl.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle",
2005
+ ptr %hdl.tmp, i32 0, i32 0
2006
+ %hdl.arg = load ptr, ptr %hdl.tmp.dive
2007
+ %hdl.result = call ptr @"Awaiter::await_suspend"(ptr %awaiter, ptr %hdl.arg)
2008
+ %hdl.result.tmp.dive = getelementptr inbounds %"struct.std::coroutine_handle",
2009
+ ptr %hdl.result.tmp, i32 0, i32 0
2010
+ store ptr %hdl.result, ptr %hdl.result.tmp.dive
2011
+ %result.address = call ptr @"std::corouine_handle<>::address"(ptr %hdl.result.tmp)
2012
+ ret ptr %result.address
2013
+
1747
2014
Coroutine Transformation Passes
1748
2015
===============================
1749
2016
CoroEarly
@@ -1758,7 +2025,9 @@ and `coro.promise`_ intrinsics.
1758
2025
CoroSplit
1759
2026
---------
1760
2027
The pass CoroSplit builds coroutine frame and outlines resume and destroy parts
1761
- into separate functions.
2028
+ into separate functions. This pass also lowers `coro.await.suspend `_,
2029
+ `coro.await.suspend.bool `_ and `coro.await.suspend.handle `_ intrinsics.
2030
+
1762
2031
1763
2032
CoroElide
1764
2033
---------
0 commit comments