Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/passes/Asyncify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,14 @@ class ModuleAnalyzer {
}
// TODO optimize the other case, at least by type
}
void visitCallRef(CallRef* curr) {
if (curr->isReturn) {
Fatal() << "tail calls not yet supported in asyncify";
}
if (canIndirectChangeState) {
info.canChangeState = true;
}
}
};
Walker walker(info, module, canIndirectChangeState);
walker.walk(func->body);
Expand Down Expand Up @@ -834,6 +842,7 @@ class ModuleAnalyzer {
}
}
void visitCallIndirect(CallIndirect* curr) { hasIndirectCall = true; }
void visitCallRef(CallRef* curr) { hasIndirectCall = true; }
Module* module;
ModuleAnalyzer* analyzer;
Map* map;
Expand Down Expand Up @@ -863,16 +872,16 @@ class ModuleAnalyzer {
bool verbose;
};

// Checks if something performs a call: either a direct or indirect call,
// and perhaps it is dropped or assigned to a local. This captures all the
// cases of a call in flat IR.
// Checks if something performs a call: a direct call, indirect call, or
// call_ref, and perhaps it is dropped or assigned to a local. This captures
// all the cases of a call in flat IR.
static bool doesCall(Expression* curr) {
if (auto* set = curr->dynCast<LocalSet>()) {
curr = set->value;
} else if (auto* drop = curr->dynCast<Drop>()) {
curr = drop->value;
}
return curr->is<Call>() || curr->is<CallIndirect>();
return curr->is<Call>() || curr->is<CallIndirect>() || curr->is<CallRef>();
}

class AsyncifyBuilder : public Builder {
Expand Down
113 changes: 113 additions & 0 deletions test/lit/passes/asyncify-call-ref.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.

;; Test that asyncify properly instruments call_ref, just like call_indirect.

;; RUN: wasm-opt %s --asyncify --pass-arg=asyncify-addlist@caller -all -S -o - | filecheck %s

(module
;; CHECK: (type $func-type (func))
(type $func-type (func))

;; CHECK: (import "env" "import" (func $import (type $func-type)))
(import "env" "import" (func $import))

(memory 1 2)

;; CHECK: (func $caller (type $func-type)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $__asyncify_unwind (result i32)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.store
;; CHECK-NEXT: (global.get $__asyncify_data)
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (global.get $__asyncify_data)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const -4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (global.get $__asyncify_data)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.or
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (call_ref $func-type
;; CHECK-NEXT: (ref.func $import)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eq
;; CHECK-NEXT: (global.get $__asyncify_state)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (br $__asyncify_unwind
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (i32.store
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (global.get $__asyncify_data)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.store
;; CHECK-NEXT: (global.get $__asyncify_data)
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (global.get $__asyncify_data)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $caller
(call_ref $func-type
(ref.func $import)
)
)
)
Loading