@@ -1885,164 +1885,4 @@ struct Asyncify : public Pass {
1885
1885
1886
1886
Pass* createAsyncifyPass () { return new Asyncify (); }
1887
1887
1888
- // Helper passes that can be run after Asyncify.
1889
-
1890
- template <bool neverRewind, bool neverUnwind, bool importsAlwaysUnwind>
1891
- struct ModAsyncify
1892
- : public WalkerPass<LinearExecutionWalker<
1893
- ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>>> {
1894
- bool isFunctionParallel () override { return true ; }
1895
-
1896
- std::unique_ptr<Pass> create () override {
1897
- return std::make_unique<
1898
- ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>>();
1899
- }
1900
-
1901
- void doWalkFunction (Function* func) {
1902
- // Find the asyncify state name.
1903
- auto * unwind = this ->getModule ()->getExport (ASYNCIFY_STOP_UNWIND);
1904
- auto * unwindFunc = this ->getModule ()->getFunction (
1905
- ((unwind->kind == ExternalKind::Function)) ? *unwind->getInternalName ()
1906
- : Name ());
1907
- FindAll<GlobalSet> sets (unwindFunc->body );
1908
- assert (sets.list .size () == 1 );
1909
- asyncifyStateName = sets.list [0 ]->name ;
1910
- // Walk and optimize.
1911
- this ->walk (func->body );
1912
- }
1913
-
1914
- // Note that we don't just implement GlobalGet as we may know the value is
1915
- // *not* 0, 1, or 2, but not know the actual value. So what we can say depends
1916
- // on the comparison being done on it, and so we implement Binary and
1917
- // Select.
1918
-
1919
- void visitBinary (Binary* curr) {
1920
- // Check if this is a comparison of the asyncify state to a specific
1921
- // constant, which we may know is impossible.
1922
- bool flip = false ;
1923
- if (curr->op == NeInt32) {
1924
- flip = true ;
1925
- } else if (curr->op != EqInt32) {
1926
- return ;
1927
- }
1928
- auto * c = curr->right ->dynCast <Const>();
1929
- if (!c) {
1930
- return ;
1931
- }
1932
- auto * get = curr->left ->dynCast <GlobalGet>();
1933
- if (!get || get->name != asyncifyStateName) {
1934
- return ;
1935
- }
1936
- // This is a comparison of the state to a constant, check if we know the
1937
- // value.
1938
- int32_t value;
1939
- auto checkedValue = c->value .geti32 ();
1940
- if ((checkedValue == int (State::Unwinding) && neverUnwind) ||
1941
- (checkedValue == int (State::Rewinding) && neverRewind)) {
1942
- // We know the state is checked against an impossible value.
1943
- value = 0 ;
1944
- } else if (checkedValue == int (State::Unwinding) && this ->unwinding ) {
1945
- // We know we are in fact unwinding right now.
1946
- value = 1 ;
1947
- unsetUnwinding ();
1948
- } else {
1949
- return ;
1950
- }
1951
- if (flip) {
1952
- value = 1 - value;
1953
- }
1954
- Builder builder (*this ->getModule ());
1955
- this ->replaceCurrent (builder.makeConst (int32_t (value)));
1956
- }
1957
-
1958
- void visitSelect (Select* curr) {
1959
- auto * get = curr->condition ->dynCast <GlobalGet>();
1960
- if (!get || get->name != asyncifyStateName) {
1961
- return ;
1962
- }
1963
- // This is a comparison of the normal state, which means we are checking
1964
- // "if running normally, run this code, but if rewinding, ignore it". If
1965
- // we know we'll never rewind, we can optimize this.
1966
- if (neverRewind) {
1967
- Builder builder (*this ->getModule ());
1968
- curr->condition = builder.makeConst (int32_t (0 ));
1969
- }
1970
- }
1971
-
1972
- void visitUnary (Unary* curr) {
1973
- if (curr->op != EqZInt32) {
1974
- return ;
1975
- }
1976
- auto * get = curr->value ->dynCast <GlobalGet>();
1977
- if (!get || get->name != asyncifyStateName) {
1978
- return ;
1979
- }
1980
- // This is a comparison of the state to zero, which means we are checking
1981
- // "if running normally, run this code, but if rewinding, ignore it". If
1982
- // we know we'll never rewind, we can optimize this.
1983
- if (neverRewind) {
1984
- Builder builder (*this ->getModule ());
1985
- // The whole expression will be 1 because it is (i32.eqz (i32.const 0))
1986
- this ->replaceCurrent (builder.makeConst (int32_t (1 )));
1987
- }
1988
- }
1989
-
1990
- void visitCall (Call* curr) {
1991
- unsetUnwinding ();
1992
- if (!importsAlwaysUnwind) {
1993
- return ;
1994
- }
1995
- auto * target = this ->getModule ()->getFunction (curr->target );
1996
- if (!target->imported ()) {
1997
- return ;
1998
- }
1999
- // This is an import that definitely unwinds. Await the next check of
2000
- // the state in this linear execution trace, which we can turn into a
2001
- // constant.
2002
- this ->unwinding = true ;
2003
- }
2004
-
2005
- void visitCallIndirect (CallIndirect* curr) { unsetUnwinding (); }
2006
-
2007
- static void doNoteNonLinear (
2008
- ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>* self,
2009
- Expression**) {
2010
- // When control flow branches, stop tracking an unwinding.
2011
- self->unsetUnwinding ();
2012
- }
2013
-
2014
- void visitGlobalSet (GlobalSet* set) {
2015
- // TODO: this could be more precise
2016
- unsetUnwinding ();
2017
- }
2018
-
2019
- private:
2020
- Name asyncifyStateName;
2021
-
2022
- // Whether we just did a call to an import that indicates we are unwinding.
2023
- bool unwinding = false ;
2024
-
2025
- void unsetUnwinding () { this ->unwinding = false ; }
2026
- };
2027
-
2028
- //
2029
- // Assume imports that may unwind will always unwind, and that rewinding never
2030
- // happens.
2031
- //
2032
-
2033
- Pass* createModAsyncifyAlwaysOnlyUnwindPass () {
2034
- return new ModAsyncify<true , false , true >();
2035
- }
2036
-
2037
- //
2038
- // Assume that we never unwind, but may still rewind.
2039
- //
2040
- struct ModAsyncifyNeverUnwind : public Pass {
2041
- void run (Module* module ) override {}
2042
- };
2043
-
2044
- Pass* createModAsyncifyNeverUnwindPass () {
2045
- return new ModAsyncify<false , true , false >();
2046
- }
2047
-
2048
1888
} // namespace wasm
0 commit comments