Skip to content

Commit 3049fb8

Browse files
authored
SimplifyGlobals: Apply constant globals to segment offsets (#6226)
We already applied such globals to other globals, but can do the same to offsets of data and element segments. Suggested in #6220
1 parent 823bf60 commit 3049fb8

File tree

2 files changed

+117
-8
lines changed

2 files changed

+117
-8
lines changed

src/passes/SimplifyGlobals.cpp

+32-8
Original file line numberDiff line numberDiff line change
@@ -646,23 +646,47 @@ struct SimplifyGlobals : public Pass {
646646
// since we do know the value during startup, it can't be modified until
647647
// code runs.
648648
void propagateConstantsToGlobals() {
649-
// Go over the list of globals in order, which is the order of
650-
// initialization as well, tracking their constant values.
649+
Builder builder(*module);
650+
651+
// We will note constant globals here as we compute them.
651652
std::map<Name, Literals> constantGlobals;
653+
654+
// Given an init expression (something like the init of a global or a
655+
// segment), see if it is a simple global.get of a constant that we can
656+
// apply.
657+
auto applyGlobals = [&](Expression*& init) {
658+
if (!init) {
659+
// This is the init of a passive segment, which is null.
660+
return;
661+
}
662+
if (auto* get = init->dynCast<GlobalGet>()) {
663+
auto iter = constantGlobals.find(get->name);
664+
if (iter != constantGlobals.end()) {
665+
init = builder.makeConstantExpression(iter->second);
666+
}
667+
}
668+
};
669+
670+
// Go over the list of globals first, and note their constant values as we
671+
// go, as well as applying them where possible.
652672
for (auto& global : module->globals) {
653673
if (!global->imported()) {
654674
if (Properties::isConstantExpression(global->init)) {
655675
constantGlobals[global->name] =
656676
getLiteralsFromConstExpression(global->init);
657-
} else if (auto* get = global->init->dynCast<GlobalGet>()) {
658-
auto iter = constantGlobals.find(get->name);
659-
if (iter != constantGlobals.end()) {
660-
Builder builder(*module);
661-
global->init = builder.makeConstantExpression(iter->second);
662-
}
677+
} else {
678+
applyGlobals(global->init);
663679
}
664680
}
665681
}
682+
683+
// Go over other things with inits and apply globals there.
684+
for (auto& elementSegment : module->elementSegments) {
685+
applyGlobals(elementSegment->offset);
686+
}
687+
for (auto& dataSegment : module->dataSegments) {
688+
applyGlobals(dataSegment->offset);
689+
}
666690
}
667691

668692
// Constant propagation part 2: apply the values of immutable globals
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.
3+
4+
;; RUN: foreach %s %t wasm-opt --simplify-globals -all -S -o - | filecheck %s
5+
6+
;; Apply constant globals to segment offsets. The non-imported global.gets will
7+
;; be applied in the segments named $use-defined.
8+
9+
(module
10+
;; CHECK: (type $0 (func))
11+
12+
;; CHECK: (import "env" "memory" (memory $memory 256))
13+
(import "env" "memory" (memory $memory 256))
14+
15+
;; CHECK: (import "env" "table" (table $table 0 funcref))
16+
(import "env" "table" (table $table 0 funcref))
17+
18+
;; CHECK: (import "env" "imported" (global $imported i32))
19+
(import "env" "imported" (global $imported i32))
20+
21+
;; CHECK: (global $defined i32 (i32.const 42))
22+
(global $defined i32 (i32.const 42))
23+
24+
;; CHECK: (global $use-defined i32 (i32.const 42))
25+
(global $use-defined i32 (global.get $defined))
26+
27+
;; CHECK: (data $use-imported (global.get $imported) "hello, world!")
28+
(data $use-imported (global.get $imported) "hello, world!")
29+
30+
;; CHECK: (data $use-defined (i32.const 42) "hello, world!")
31+
(data $use-defined (global.get $defined) "hello, world!")
32+
33+
;; A passive segment has no offset to test, which we should not error on.
34+
;; CHECK: (data $dropped "hello, world!")
35+
(data $dropped "hello, world!")
36+
37+
;; CHECK: (elem $use-imported (global.get $imported) $func)
38+
(elem $use-imported (global.get $imported) $func)
39+
40+
;; CHECK: (elem $use-defined (i32.const 42) $func $func)
41+
(elem $use-defined (global.get $defined) $func $func)
42+
43+
;; CHECK: (export "func" (func $func))
44+
(export "func" (func $func))
45+
46+
;; CHECK: (func $func (type $0)
47+
;; CHECK-NEXT: (drop
48+
;; CHECK-NEXT: (i32.load
49+
;; CHECK-NEXT: (i32.const 0)
50+
;; CHECK-NEXT: )
51+
;; CHECK-NEXT: )
52+
;; CHECK-NEXT: (drop
53+
;; CHECK-NEXT: (table.get $table
54+
;; CHECK-NEXT: (i32.const 0)
55+
;; CHECK-NEXT: )
56+
;; CHECK-NEXT: )
57+
;; CHECK-NEXT: (drop
58+
;; CHECK-NEXT: (global.get $imported)
59+
;; CHECK-NEXT: )
60+
;; CHECK-NEXT: (drop
61+
;; CHECK-NEXT: (i32.const 42)
62+
;; CHECK-NEXT: )
63+
;; CHECK-NEXT: (data.drop $dropped)
64+
;; CHECK-NEXT: )
65+
(func $func
66+
;; Use things to avoid DCE.
67+
(drop
68+
(i32.load
69+
(i32.const 0)
70+
)
71+
)
72+
(drop
73+
(table.get $table
74+
(i32.const 0)
75+
)
76+
)
77+
(drop
78+
(global.get $imported)
79+
)
80+
(drop
81+
(global.get $use-defined)
82+
)
83+
(data.drop $dropped)
84+
)
85+
)

0 commit comments

Comments
 (0)