blob: 542311d59d9304930d81e9656217d9b33f8f6df3 [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: foreach %s %t wasm-opt -all --reorder-globals-always -S -o - | filecheck %s
;; RUN: foreach %s %t wasm-opt -all --reorder-globals-always --roundtrip -S -o - | filecheck %s
;; Also check roundtripping here, so verify we don't end up emitting invalid
;; binaries.
;; Global $b has more uses, so it should be sorted first.
(module
;; CHECK: (global $b i32 (i32.const 20))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
(global $b i32 (i32.const 20))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
)
)
;; As above, but now with global.sets. Again $b should be sorted first.
(module
;; CHECK: (global $b (mut i32) (i32.const 20))
;; CHECK: (global $a (mut i32) (i32.const 10))
(global $a (mut i32) (i32.const 10))
(global $b (mut i32) (i32.const 20))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (global.set $b
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $b
;; CHECK-NEXT: (i32.const 40)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(global.set $b
(i32.const 30)
)
(global.set $b
(i32.const 40)
)
(drop
(global.get $a)
)
)
)
;; As above, but flipped so now $a has more, and should remain first.
(module
;; CHECK: (global $a (mut i32) (i32.const 10))
(global $a (mut i32) (i32.const 10))
;; CHECK: (global $b (mut i32) (i32.const 20))
(global $b (mut i32) (i32.const 20))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (global.set $a
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $a
;; CHECK-NEXT: (i32.const 40)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(global.set $a
(i32.const 30)
)
(global.set $a
(i32.const 40)
)
(drop
(global.get $b)
)
)
)
;; $b has more uses, but it depends on $a and cannot be sorted before it.
(module
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
)
)
;; $c has more uses, but it depends on $b and $a and cannot be sorted before
;; them. Likewise $b cannot be before $a.
(module
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (global $c i32 (global.get $b))
(global $c i32 (global.get $b))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
(drop
(global.get $c)
)
(drop
(global.get $c)
)
)
)
;; As above, but without dependencies, so now $c is first and then $b.
(module
;; CHECK: (global $c i32 (i32.const 30))
;; CHECK: (global $b i32 (i32.const 20))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
(global $b i32 (i32.const 20))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
(drop
(global.get $c)
)
(drop
(global.get $c)
)
)
)
;; As above, but a mixed case: $b depends on $a but $c has no dependencies, and
;; the counts are $c with the most, followed by $b, and then $a. $c can be
;; first here, but $b must follow $a.
(module
;; CHECK: (global $c i32 (i32.const 30))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
;; ($a already has one use in the global $b)
(drop
(global.get $b)
)
(drop
(global.get $b)
)
(drop
(global.get $c)
)
(drop
(global.get $c)
)
(drop
(global.get $c)
)
)
)
;; As above, but with the counts adjusted: before we had $c, $b, $a from most to
;; least uses, and now $b, $c, $a.
;;
;; A greedy sort would do $c, $a, $b (as the first choice is between $c and $a,
;; and $c wins), but that leaves $b, the highest count, for the end. The
;; smoothed-out LEB costs (1 byte at the start, +1/128 each index later) are:
;;
;; $c $a $b
;; 1 * 2 + 129/128 * 1 + 130/128 * 3 = 775/128
;;
;; The original sort is
;;
;; $a $b $c
;; 1 * 1 + 129/128 * 3 + 130/128 * 2 = 775/128
;;
;; As they are equal we prefer the original order.
(module
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (global $c i32 (i32.const 30))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
(drop
(global.get $b)
)
(drop
(global.get $b)
)
(drop
(global.get $c)
)
(drop
(global.get $c)
)
)
)
;; As above, but with the counts adjusted to $b, $a, $c.
(module
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (global $c i32 (i32.const 30))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
(drop
(global.get $b)
)
)
)
;; As above, but with the counts adjusted to $c, $a, $b.
(module
;; CHECK: (global $c i32 (i32.const 30))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $c)
)
(drop
(global.get $c)
)
)
)
;; As above, but with the counts adjusted to $a, $b, $c.
(module
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (global $c i32 (i32.const 30))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $a)
)
(drop
(global.get $b)
)
)
)
;; As above, but with the counts adjusted to $a, $c, $b.
(module
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (global $c i32 (i32.const 30))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
(global $c i32 (i32.const 30))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $a)
)
(drop
(global.get $c)
)
)
)
;; $b has more uses, but $a is an import and must remain first.
(module
;; CHECK: (import "a" "b" (global $a i32))
(import "a" "b" (global $a i32))
;; CHECK: (global $b i32 (i32.const 10))
(global $b i32 (i32.const 10))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $b)
)
)
)
;; As above, but with a and b's names flipped, to check that the names do not
;; matter, and we keep imports first.
(module
;; CHECK: (import "a" "b" (global $b i32))
(import "a" "b" (global $b i32))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
(drop
(global.get $a)
)
)
)
;; Lower letters have lower counts: $a has the least, and $e has the most.
;;
;; Dependency graph (left depends on right):
;;
;; $c - $a
;; /
;; $e
;; \
;; $d - $b
;;
;; $e has the most uses, followed by $c and $d. $a and $b have a reverse
;; ordering from their dependers, so a naive topological sort will fail to
;; be optimal. There are multiple optimal orders however, including:
;;
;; $b, $a, $c, $d, $e
;; $b, $d, $a, $c, $e
;;
;; $b and $e must be at the edges, but there is no single way to sort the
;; others: the first sorting here puts $a before both $d (though $a has
;; lower count) while the second puts $d before $c. Our greedy algorithm
;; picks the second order here.
(module
;; CHECK: (global $b i32 (i32.const 20))
;; CHECK: (global $d i32 (global.get $b))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
(global $b i32 (i32.const 20))
;; CHECK: (global $c i32 (global.get $a))
(global $c i32 (global.get $a))
(global $d i32 (global.get $b))
;; CHECK: (global $e i32 (i32.add
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: ))
(global $e i32 (i32.add
(global.get $c)
(global.get $d)
))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
;; $a, $b, $c, $d each have one already from the globals. Add more so that
;; $a has the least, and $e has the most
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $d))
(drop (global.get $d))
(drop (global.get $d))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $b))
)
)
;; As above, but add a direct dep from $d to $a:
;;
;; $c - $a
;; / /
;; $e / <-- this was added
;; \ /
;; $d - $b
;;
;; This forces $a to appear before $d: the order goes from before, which was
;; $b, $d, $a, $c, $e
;; to
;; $b, $a, $d, $c, $e
(module
;; CHECK: (global $b i32 (i32.const 20))
;; CHECK: (global $a i32 (i32.const 10))
(global $a i32 (i32.const 10))
(global $b i32 (i32.const 20))
;; CHECK: (global $d i32 (i32.add
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: (global.get $a)
;; CHECK-NEXT: ))
;; CHECK: (global $c i32 (global.get $a))
(global $c i32 (global.get $a))
(global $d i32 (i32.add
(global.get $b)
(global.get $a) ;; this was added
))
;; CHECK: (global $e i32 (i32.add
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: ))
(global $e i32 (i32.add
(global.get $c)
(global.get $d)
))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $d)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
;; $b, $c, $d each have one already from the globals, and $a has two. Add
;; more so that $a has the least, and $e has the most.
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $e))
(drop (global.get $d))
(drop (global.get $d))
(drop (global.get $d))
(drop (global.get $d))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $b))
(drop (global.get $b))
)
)
;; A situation where the simple greedy sort fails to be optimal. We have a
;; chain and one more independent global
;;
;; a <- b <- c
;;
;; other
;;
;; The candidates for the first global emitted are a and other, as they have no
;; dependencies, and other has a higher count so greedy sorting would pick it.
;; however, c has the highest count by far, so it is worth being less greedy and
;; doing a just in order to be able to do b and then c, and to emit other last.
;; In other words, the original order is best.
(module
;; CHECK: (global $a i32 (i32.const 0))
(global $a i32 (i32.const 0))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (global $c i32 (global.get $b))
(global $c i32 (global.get $b))
;; CHECK: (global $other i32 (i32.const 1))
(global $other i32 (i32.const 1))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
;; Ten uses for $c, far more than all the rest combined.
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
;; Two uses for other, which is more than $a's single use.
(drop (global.get $other))
(drop (global.get $other))
)
)
;; As above, but with the original order a little different. This is again a
;; case where the greedy sort is unoptimal (see above), but now also the
;; original sort is unoptimal as well, and instead we use the "sum" sort, which
;; counts the sum of the uses of a global and all the things it depends on and
;; uses that as the count for that global (which in effect means that we take
;; into consideration not only its own size but the entire size that it may
;; unlock, which happens to work well here).
;;
;; The only change in the input compared to the previous test is that $other
;; was moved up to between $b and $c. Sum sort works well here because the
;; first comparison is $a and $other, and sum takes into account $b and $c in
;; $a's favor, so it wins. Likewise $b and $c win against $other as well, so
;; the order is $a, $b, $c, $other which is optimal here.
(module
;; CHECK: (global $a i32 (i32.const 0))
(global $a i32 (i32.const 0))
;; CHECK: (global $b i32 (global.get $a))
(global $b i32 (global.get $a))
;; CHECK: (global $c i32 (global.get $b))
;; CHECK: (global $other i32 (i32.const 1))
(global $other i32 (i32.const 1))
(global $c i32 (global.get $b))
;; CHECK: (func $uses (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $c)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uses
;; Ten uses for $c, far more than all the rest combined.
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
(drop (global.get $c))
;; Two uses for other, which is more than $a's single use.
(drop (global.get $other))
(drop (global.get $other))
)
)