test
diff --git a/test/lit/passes/cfp_local.wast b/test/lit/passes/cfp_local.wast
index 46e8e0b..7229ae3 100644
--- a/test/lit/passes/cfp_local.wast
+++ b/test/lit/passes/cfp_local.wast
@@ -1730,6 +1730,242 @@
)
)
+;; As before, but the vtables are in *mutable* globals, which prevents
+;; optimization.
+(module
+ ;; A function type that receives |this| and returns an i32.
+ ;; CHECK: (type $parent (struct (field (ref $parent.vtable))))
+
+ ;; CHECK: (type $func (func (param anyref) (result i32)))
+ (type $func (func (param anyref) (result i32)))
+
+ ;; A parent struct type, with a vtable.
+ (type $parent (struct (field (ref $parent.vtable))))
+
+ ;; CHECK: (type $parent.vtable (struct (field (ref $func))))
+ (type $parent.vtable (struct (field (ref $func))))
+
+ ;; A child struct type that extends the parent. It adds a field to both the
+ ;; struct and its vtable.
+ ;; CHECK: (type $child.vtable (struct (field (ref $func)) (field (ref $func))) (extends $parent.vtable))
+ (type $child.vtable (struct (field (ref $func)) (field (ref $func))) (extends $parent.vtable))
+
+ ;; CHECK: (type $none_=>_anyref (func (result anyref)))
+
+ ;; CHECK: (type $child (struct (field (ref $child.vtable)) (field i32)) (extends $parent))
+ (type $child (struct (field (ref $child.vtable)) (field i32)) (extends $parent))
+
+ ;; CHECK: (type $none_=>_i32 (func (result i32)))
+
+ ;; CHECK: (global $parent.vtable (mut (ref $parent.vtable)) (struct.new_with_rtt $parent.vtable
+ ;; CHECK-NEXT: (ref.func $parent.func)
+ ;; CHECK-NEXT: (rtt.canon $parent.vtable)
+ ;; CHECK-NEXT: ))
+ (global $parent.vtable (mut (ref $parent.vtable))
+ (struct.new_with_rtt $parent.vtable
+ (ref.func $parent.func)
+ (rtt.canon $parent.vtable)
+ )
+ )
+ ;; CHECK: (global $child.vtable (mut (ref $child.vtable)) (struct.new_with_rtt $child.vtable
+ ;; CHECK-NEXT: (ref.func $child.func)
+ ;; CHECK-NEXT: (ref.func $child.func)
+ ;; CHECK-NEXT: (rtt.canon $child.vtable)
+ ;; CHECK-NEXT: ))
+ (global $child.vtable (mut (ref $child.vtable))
+ (struct.new_with_rtt $child.vtable
+ (ref.func $child.func)
+ (ref.func $child.func)
+ (rtt.canon $child.vtable)
+ )
+ )
+
+ ;; CHECK: (elem declare func $child.func $parent.func)
+
+ ;; CHECK: (func $keepalive-parent (result anyref)
+ ;; CHECK-NEXT: (struct.new_with_rtt $parent
+ ;; CHECK-NEXT: (struct.new_with_rtt $parent.vtable
+ ;; CHECK-NEXT: (ref.func $parent.func)
+ ;; CHECK-NEXT: (rtt.canon $parent.vtable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (rtt.canon $parent)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $keepalive-parent (result anyref)
+ (struct.new_with_rtt $parent
+ (struct.new_with_rtt $parent.vtable
+ (ref.func $parent.func)
+ (rtt.canon $parent.vtable)
+ )
+ (rtt.canon $parent)
+ )
+ )
+
+ ;; CHECK: (func $keepalive-child (result anyref)
+ ;; CHECK-NEXT: (struct.new_with_rtt $child
+ ;; CHECK-NEXT: (struct.new_with_rtt $child.vtable
+ ;; CHECK-NEXT: (ref.func $child.func)
+ ;; CHECK-NEXT: (ref.func $child.func)
+ ;; CHECK-NEXT: (rtt.canon $child.vtable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 9999)
+ ;; CHECK-NEXT: (rtt.canon $child)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $keepalive-child (result anyref)
+ (struct.new_with_rtt $child
+ (struct.new_with_rtt $child.vtable
+ (ref.func $child.func)
+ (ref.func $child.func)
+ (rtt.canon $child.vtable)
+ )
+ (i32.const 9999)
+ (rtt.canon $child)
+ )
+ )
+
+ ;; CHECK: (func $parent.func (param $this anyref) (result i32)
+ ;; CHECK-NEXT: (i32.const 128)
+ ;; CHECK-NEXT: )
+ (func $parent.func (param $this anyref) (result i32)
+ (i32.const 128)
+ )
+
+ ;; CHECK: (func $child.func (param $this anyref) (result i32)
+ ;; CHECK-NEXT: (i32.const 4096)
+ ;; CHECK-NEXT: )
+ (func $child.func (param $this anyref) (result i32)
+ (i32.const 4096)
+ )
+
+ ;; CHECK: (func $create-parent-call-parent (result i32)
+ ;; CHECK-NEXT: (local $x (ref null $parent))
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (struct.new_with_rtt $parent
+ ;; CHECK-NEXT: (global.get $parent.vtable)
+ ;; CHECK-NEXT: (rtt.canon $parent)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (call_ref
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (struct.get $parent.vtable 0
+ ;; CHECK-NEXT: (struct.get $parent 0
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call_ref
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (struct.get $parent.vtable 0
+ ;; CHECK-NEXT: (struct.get $parent 0
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $create-parent-call-parent (result i32)
+ (local $x (ref null $parent))
+ (local.set $x
+ (struct.new_with_rtt $parent
+ ;; To be able to infer the precise type of the parent's vtable, we need
+ ;; to know what is in this global. As the globals are mutable, we
+ ;; fail to optimize here.
+ (global.get $parent.vtable)
+ (rtt.canon $parent)
+ )
+ )
+ (i32.add
+ (call_ref
+ (local.get $x)
+ (struct.get $parent.vtable 0
+ (struct.get $parent 0
+ (local.get $x)
+ )
+ )
+ )
+ (call_ref
+ (local.get $x)
+ (struct.get $parent.vtable 0
+ (struct.get $parent 0
+ (local.get $x)
+ )
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $create-child-call-parent (result i32)
+ ;; CHECK-NEXT: (local $x (ref null $parent))
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (struct.new_with_rtt $child
+ ;; CHECK-NEXT: (global.get $child.vtable)
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (rtt.canon $child)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (call_ref
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (block (result (ref $func))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (struct.get $parent 0
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.func $child.func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call_ref
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (block (result (ref $func))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (struct.get $parent 0
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.func $child.func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $create-child-call-parent (result i32)
+ (local $x (ref null $parent))
+ (local.set $x
+ (struct.new_with_rtt $child
+ (global.get $child.vtable)
+ (i32.const 42)
+ (rtt.canon $child)
+ )
+ )
+ ;; As above, we don't need global info for the child, so we do optimize
+ ;; here.
+ (i32.add
+ (call_ref
+ (local.get $x)
+ (struct.get $parent.vtable 0
+ (struct.get $parent 0
+ (local.get $x)
+ )
+ )
+ )
+ (call_ref
+ (local.get $x)
+ (struct.get $parent.vtable 0
+ (struct.get $parent 0
+ (local.get $x)
+ )
+ )
+ )
+ )
+ )
+)
+
(module
;; CHECK: (type $E (struct (field i64) (field i64) (field i64) (field (mut i64))) (extends $D))
(type $E (struct i64 i64 i64 (mut i64)) (extends $D))