@@ -1885,164 +1885,4 @@ struct Asyncify : public Pass {
18851885
18861886Pass* createAsyncifyPass () { return new Asyncify (); }
18871887
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-
20481888} // namespace wasm
0 commit comments