Skip to content

Commit 153ba18

Browse files
authored
Handle EM_ASM/EM_JS in LLVM wasm backend O0 output (#1888)
See emscripten-core/emscripten#7928 - we have been optimizing all wasms until now, and noticed this when the wasm object file path did not do so. When not optimizing, our methods of handling EM_ASM and EM_JS fail since the patterns are different. Specifically, for EM_ASM we hunt for emscripten_asm_const(X, where X is a constant, but without opts it may be a get of a local. For EM_JS, the function body may not just contain a const, but a block with a set of the const and a return of a get later. This adds logic to track gets and sets in basic blocks, which is sufficient to handle this.
1 parent 85e95e3 commit 153ba18

File tree

6 files changed

+327
-18
lines changed

6 files changed

+327
-18
lines changed

src/tools/wasm-emscripten-finalize.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,16 @@ int main(int argc, const char *argv[]) {
173173
EmscriptenGlueGenerator generator(wasm);
174174
generator.fixInvokeFunctionNames();
175175

176-
PassRunner passRunner(&wasm);
177-
passRunner.setDebug(options.debug);
178-
passRunner.setDebugInfo(debugInfo);
179-
passRunner.add(ABI::getLegalizationPass(
180-
legalizeJavaScriptFFI ? ABI::LegalizationLevel::Full
181-
: ABI::LegalizationLevel::Minimal
182-
));
183-
passRunner.run();
176+
{
177+
PassRunner passRunner(&wasm);
178+
passRunner.setDebug(options.debug);
179+
passRunner.setDebugInfo(debugInfo);
180+
passRunner.add(ABI::getLegalizationPass(
181+
legalizeJavaScriptFFI ? ABI::LegalizationLevel::Full
182+
: ABI::LegalizationLevel::Minimal
183+
));
184+
passRunner.run();
185+
}
184186

185187
std::vector<Name> initializerFunctions;
186188

src/wasm/wasm-emscripten.cpp

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -443,18 +443,22 @@ std::string codeForConstAddr(Module& wasm,
443443
return escape(str);
444444
}
445445

446-
struct AsmConstWalker : public PostWalker<AsmConstWalker> {
446+
struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> {
447447
Module& wasm;
448448
std::vector<Address> segmentOffsets; // segment index => address offset
449449

450450
std::map<std::string, std::set<std::string>> sigsForCode;
451451
std::map<std::string, Address> ids;
452452
std::set<std::string> allSigs;
453+
std::map<Index, SetLocal*> sets; // last sets in the current basic block, per index
453454

454455
AsmConstWalker(Module& _wasm)
455456
: wasm(_wasm),
456457
segmentOffsets(getSegmentOffsets(wasm)) { }
457458

459+
void noteNonLinear(Expression* curr);
460+
461+
void visitSetLocal(SetLocal* curr);
458462
void visitCall(Call* curr);
459463
void visitTable(Table* curr);
460464

@@ -471,15 +475,33 @@ struct AsmConstWalker : public PostWalker<AsmConstWalker> {
471475
std::vector<std::unique_ptr<Function>> queuedImports;
472476
};
473477

478+
void AsmConstWalker::noteNonLinear(Expression* curr) {
479+
// End of this basic block; clear sets.
480+
sets.clear();
481+
}
482+
483+
void AsmConstWalker::visitSetLocal(SetLocal* curr) {
484+
sets[curr->index] = curr;
485+
}
486+
474487
void AsmConstWalker::visitCall(Call* curr) {
475488
auto* import = wasm.getFunction(curr->target);
476489
if (import->imported() && import->base.hasSubstring(EMSCRIPTEN_ASM_CONST)) {
477490
auto baseSig = getSig(curr);
478491
auto sig = fixupNameWithSig(curr->target, baseSig);
479-
480-
auto arg = curr->operands[0]->cast<Const>();
481-
auto code = codeForConstAddr(wasm, segmentOffsets, arg);
482-
arg->value = idLiteralForCode(code);
492+
auto* arg = curr->operands[0];
493+
// The argument may be a get, in which case, the last set in this basic block
494+
// has the value.
495+
if (auto* get = arg->dynCast<GetLocal>()) {
496+
auto* set = sets[get->index];
497+
if (set) {
498+
assert(set->index == get->index);
499+
arg = set->value;
500+
}
501+
}
502+
auto* value = arg->cast<Const>();
503+
auto code = codeForConstAddr(wasm, segmentOffsets, value);
504+
value->value = idLiteralForCode(code);
483505
sigsForCode[code].insert(sig);
484506
}
485507
}
@@ -599,16 +621,31 @@ struct EmJsWalker : public PostWalker<EmJsWalker> {
599621
auto addrConst = curr->body->dynCast<Const>();
600622
if (addrConst == nullptr) {
601623
auto block = curr->body->dynCast<Block>();
602-
Expression* first = nullptr;
624+
Expression* value = nullptr;
603625
if (block && block->list.size() > 0) {
604-
first = block->list[0];
626+
value = block->list[0];
627+
// first item may be a set of a local that we get later
628+
auto* set = value->dynCast<SetLocal>();
629+
if (set) {
630+
value = block->list[1];
631+
}
632+
// look into a return value
633+
if (auto* ret = value->dynCast<Return>()) {
634+
value = ret->value;
635+
}
636+
// if it's a get of that set, use that value
637+
if (auto* get = value->dynCast<GetLocal>()) {
638+
if (set && get->index == set->index) {
639+
value = set->value;
640+
}
641+
}
605642
}
606-
if (first) {
607-
addrConst = first->dynCast<Const>();
643+
if (value) {
644+
addrConst = value->dynCast<Const>();
608645
}
609646
}
610647
if (addrConst == nullptr) {
611-
Fatal() << "Unexpected generated __em_js__ function body: " << curr;
648+
Fatal() << "Unexpected generated __em_js__ function body: " << curr->name;
612649
}
613650
auto code = codeForConstAddr(wasm, segmentOffsets, addrConst);
614651
codeByName[funcName] = code;

test/lld/em_asm_O0.wast

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(module
2+
(type $0 (func (param i32) (result i32)))
3+
(type $1 (func (param i32 i32 i32) (result i32)))
4+
(type $2 (func (param i32 i32) (result i32)))
5+
(type $3 (func (result i32)))
6+
(type $4 (func))
7+
(import "env" "_Z24emscripten_asm_const_intIJEEiPKcDpT_" (func $_Z24emscripten_asm_const_intIJEEiPKcDpT_ (param i32) (result i32)))
8+
(import "env" "_Z24emscripten_asm_const_intIJiiEEiPKcDpT_" (func $_Z24emscripten_asm_const_intIJiiEEiPKcDpT_ (param i32 i32 i32) (result i32)))
9+
(import "env" "_Z24emscripten_asm_const_intIJiEEiPKcDpT_" (func $_Z24emscripten_asm_const_intIJiEEiPKcDpT_ (param i32 i32) (result i32)))
10+
(global $global$0 (mut i32) (i32.const 66192))
11+
(global $global$1 i32 (i32.const 66192))
12+
(global $global$2 i32 (i32.const 652))
13+
(table 1 1 funcref)
14+
(memory $0 2)
15+
(data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00")
16+
(export "memory" (memory $0))
17+
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
18+
(export "main" (func $main))
19+
(export "__heap_base" (global $global$1))
20+
(export "__data_end" (global $global$2))
21+
(func $main (; 3 ;) (type $3) (result i32)
22+
(local $t1 i32)
23+
(local $t2 i32)
24+
(drop
25+
(call $_Z24emscripten_asm_const_intIJEEiPKcDpT_
26+
(i32.const 568)
27+
)
28+
)
29+
(local.set $t1 (i32.const 621))
30+
(local.set $t2 (i32.const 601))
31+
(drop
32+
(call $_Z24emscripten_asm_const_intIJiEEiPKcDpT_
33+
(local.get $t1)
34+
(call $_Z24emscripten_asm_const_intIJiiEEiPKcDpT_
35+
(local.get $t2)
36+
(i32.const 13)
37+
(i32.const 27)
38+
)
39+
)
40+
)
41+
(i32.const 0)
42+
)
43+
(func $__wasm_call_ctors (; 4 ;) (type $4)
44+
)
45+
;; custom section "linking", size 3
46+
)
47+

test/lld/em_asm_O0.wast.out

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
(module
2+
(type $0 (func (param i32) (result i32)))
3+
(type $1 (func (param i32 i32 i32) (result i32)))
4+
(type $2 (func (param i32 i32) (result i32)))
5+
(type $3 (func (result i32)))
6+
(type $4 (func))
7+
(type $FUNCSIG$ii (func (param i32) (result i32)))
8+
(type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
9+
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
10+
(import "env" "emscripten_asm_const_i" (func $emscripten_asm_const_i (param i32) (result i32)))
11+
(import "env" "emscripten_asm_const_iii" (func $emscripten_asm_const_iii (param i32 i32 i32) (result i32)))
12+
(import "env" "emscripten_asm_const_ii" (func $emscripten_asm_const_ii (param i32 i32) (result i32)))
13+
(memory $0 2)
14+
(data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00")
15+
(table $0 1 1 funcref)
16+
(global $global$0 (mut i32) (i32.const 16384))
17+
(global $global$1 i32 (i32.const 66192))
18+
(global $global$2 i32 (i32.const 652))
19+
(export "memory" (memory $0))
20+
(export "__post_instantiate" (func $__wasm_call_ctors))
21+
(export "main" (func $main))
22+
(export "__heap_base" (global $global$1))
23+
(export "__data_end" (global $global$2))
24+
(export "stackSave" (func $stackSave))
25+
(export "stackAlloc" (func $stackAlloc))
26+
(export "stackRestore" (func $stackRestore))
27+
(export "__growWasmMemory" (func $__growWasmMemory))
28+
(func $main (; 3 ;) (type $3) (result i32)
29+
(local $t1 i32)
30+
(local $t2 i32)
31+
(drop
32+
(call $emscripten_asm_const_i
33+
(i32.const 0)
34+
)
35+
)
36+
(local.set $t1
37+
(i32.const 2)
38+
)
39+
(local.set $t2
40+
(i32.const 1)
41+
)
42+
(drop
43+
(call $emscripten_asm_const_ii
44+
(local.get $t1)
45+
(call $emscripten_asm_const_iii
46+
(local.get $t2)
47+
(i32.const 13)
48+
(i32.const 27)
49+
)
50+
)
51+
)
52+
(i32.const 0)
53+
)
54+
(func $__wasm_call_ctors (; 4 ;) (type $4)
55+
(nop)
56+
)
57+
(func $stackSave (; 5 ;) (result i32)
58+
(global.get $global$0)
59+
)
60+
(func $stackAlloc (; 6 ;) (param $0 i32) (result i32)
61+
(local $1 i32)
62+
(global.set $global$0
63+
(local.tee $1
64+
(i32.and
65+
(i32.sub
66+
(global.get $global$0)
67+
(local.get $0)
68+
)
69+
(i32.const -16)
70+
)
71+
)
72+
)
73+
(local.get $1)
74+
)
75+
(func $stackRestore (; 7 ;) (param $0 i32)
76+
(global.set $global$0
77+
(local.get $0)
78+
)
79+
)
80+
(func $__growWasmMemory (; 8 ;) (param $newSize i32) (result i32)
81+
(grow_memory
82+
(local.get $newSize)
83+
)
84+
)
85+
)
86+
(;
87+
--BEGIN METADATA --
88+
{
89+
"asmConsts": {
90+
"2": ["{ Module.print(\"Got \" + $0); }", ["ii"], [""]],
91+
"0": ["{ Module.print(\"Hello world\"); }", ["i"], [""]],
92+
"1": ["{ return $0 + $1; }", ["iii"], [""]]
93+
},
94+
"staticBump": 84,
95+
"tableSize": 1,
96+
"initializers": [
97+
"__post_instantiate"
98+
],
99+
"declares": [
100+
],
101+
"externs": [
102+
],
103+
"implementedFunctions": [
104+
"___post_instantiate",
105+
"_main",
106+
"_stackSave",
107+
"_stackAlloc",
108+
"_stackRestore",
109+
"___growWasmMemory"
110+
],
111+
"exports": [
112+
"memory",
113+
"__post_instantiate",
114+
"main",
115+
"__heap_base",
116+
"__data_end",
117+
"stackSave",
118+
"stackAlloc",
119+
"stackRestore",
120+
"__growWasmMemory"
121+
],
122+
"invokeFuncs": [
123+
]
124+
}
125+
-- END METADATA --
126+
;)

0 commit comments

Comments
 (0)