Skip to content

Commit 34cfd6b

Browse files
committed
Document added intrinsics
1 parent 4fa5620 commit 34cfd6b

File tree

1 file changed

+270
-1
lines changed

1 file changed

+270
-1
lines changed

llvm/docs/Coroutines.rst

Lines changed: 270 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,273 @@ a call to ``llvm.coro.suspend.retcon`` after resuming abnormally.
17441744
In a yield-once coroutine, it is undefined behavior if the coroutine
17451745
executes a call to ``llvm.coro.suspend.retcon`` after resuming in any way.
17461746

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+
17472014
Coroutine Transformation Passes
17482015
===============================
17492016
CoroEarly
@@ -1758,7 +2025,9 @@ and `coro.promise`_ intrinsics.
17582025
CoroSplit
17592026
---------
17602027
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+
17622031

17632032
CoroElide
17642033
---------

0 commit comments

Comments
 (0)