Skip to content

Commit b63fea1

Browse files
authored
[ctor-eval] Stop if there are any memory.init instructions (#4442)
This tool depends (atm) on flattening memory segments. That is not compatible with memory.init which cares about segment identities. This changes flatten() only by adding the check for MemoryInit. The rest is unchanged, although I saw the other two params are not needed and I removed them while I was there.
1 parent cc36ffd commit b63fea1

File tree

7 files changed

+140
-57
lines changed

7 files changed

+140
-57
lines changed

src/ir/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(ir_SOURCES
55
eh-utils.cpp
66
intrinsics.cpp
77
lubs.cpp
8+
memory-utils.cpp
89
names.cpp
910
properties.cpp
1011
LocalGraph.cpp

src/ir/memory-utils.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2022 WebAssembly Community Group participants
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "ir/memory-utils.h"
18+
#include "wasm.h"
19+
20+
namespace wasm::MemoryUtils {
21+
22+
bool flatten(Module& wasm) {
23+
// The presence of any MemoryInit instructions is a problem because they care
24+
// about segment identity, which flattening gets rid of ( when it merges them
25+
// all into one big segment).
26+
ModuleUtils::ParallelFunctionAnalysis<bool> analysis(
27+
wasm, [&](Function* func, bool& hasMemoryInit) {
28+
if (func->imported()) {
29+
return;
30+
}
31+
hasMemoryInit = FindAll<MemoryInit>(func->body).list.size() > 0;
32+
});
33+
34+
for (auto& [func, hasMemoryInit] : analysis.map) {
35+
if (hasMemoryInit) {
36+
return false;
37+
}
38+
}
39+
40+
auto& memory = wasm.memory;
41+
42+
if (memory.segments.size() == 0) {
43+
return true;
44+
}
45+
46+
std::vector<char> data;
47+
for (auto& segment : memory.segments) {
48+
if (segment.isPassive) {
49+
return false;
50+
}
51+
auto* offset = segment.offset->dynCast<Const>();
52+
if (!offset) {
53+
return false;
54+
}
55+
}
56+
for (auto& segment : memory.segments) {
57+
auto* offset = segment.offset->dynCast<Const>();
58+
Index start = offset->value.getInteger();
59+
Index end = start + segment.data.size();
60+
if (end > data.size()) {
61+
data.resize(end);
62+
}
63+
std::copy(segment.data.begin(), segment.data.end(), data.begin() + start);
64+
}
65+
memory.segments.resize(1);
66+
memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0));
67+
memory.segments[0].data.swap(data);
68+
69+
return true;
70+
}
71+
72+
} // namespace wasm::MemoryUtils

src/ir/memory-utils.h

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,46 +29,8 @@ namespace wasm::MemoryUtils {
2929

3030
// Flattens memory into a single data segment, or no segment. If there is
3131
// a segment, it starts at 0.
32-
// If ensuredSegmentSize is provided, then a segment is always emitted,
33-
// and of at least that size.
3432
// Returns true if successful (e.g. relocatable segments cannot be flattened).
35-
inline bool flatten(Memory& memory,
36-
Index ensuredSegmentSize = 0,
37-
Module* module = nullptr) {
38-
if (memory.segments.size() == 0) {
39-
if (ensuredSegmentSize > 0) {
40-
assert(module); // must provide a module if ensuring a size.
41-
Builder builder(*module);
42-
memory.segments.emplace_back(builder.makeConst(int32_t(0)));
43-
memory.segments[0].data.resize(ensuredSegmentSize);
44-
}
45-
return true;
46-
}
47-
std::vector<char> data;
48-
data.resize(ensuredSegmentSize);
49-
for (auto& segment : memory.segments) {
50-
if (segment.isPassive) {
51-
return false;
52-
}
53-
auto* offset = segment.offset->dynCast<Const>();
54-
if (!offset) {
55-
return false;
56-
}
57-
}
58-
for (auto& segment : memory.segments) {
59-
auto* offset = segment.offset->dynCast<Const>();
60-
Index start = offset->value.getInteger();
61-
Index end = start + segment.data.size();
62-
if (end > data.size()) {
63-
data.resize(end);
64-
}
65-
std::copy(segment.data.begin(), segment.data.end(), data.begin() + start);
66-
}
67-
memory.segments.resize(1);
68-
memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0));
69-
memory.segments[0].data.swap(data);
70-
return true;
71-
}
33+
bool flatten(Module& wasm);
7234

7335
// Ensures that the memory exists (of minimal size).
7436
inline void ensureExists(Memory& memory) {

src/tools/wasm-ctor-eval.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -663,11 +663,6 @@ void evalCtors(Module& wasm,
663663

664664
CtorEvalExternalInterface interface(linkedInstances);
665665
try {
666-
// flatten memory, so we do not depend on the layout of data segments
667-
if (!MemoryUtils::flatten(wasm.memory)) {
668-
Fatal() << " ...stopping since could not flatten memory\n";
669-
}
670-
671666
// create an instance for evalling
672667
EvallingModuleInstance instance(wasm, &interface, linkedInstances);
673668
// we should not add new globals from here on; as a result, using
@@ -712,6 +707,16 @@ void evalCtors(Module& wasm,
712707
}
713708
}
714709

710+
static bool canEval(Module& wasm) {
711+
// Check if we can flatten memory. We need to do so currently because of how
712+
// we assume memory is simple and flat. TODO
713+
if (!MemoryUtils::flatten(wasm)) {
714+
std::cout << " ...stopping since could not flatten memory\n";
715+
return false;
716+
}
717+
return true;
718+
}
719+
715720
} // anonymous namespace
716721

717722
//
@@ -808,19 +813,21 @@ int main(int argc, const char* argv[]) {
808813
Fatal() << "error in validating input";
809814
}
810815

811-
evalCtors(wasm, ctors, keptExports);
812-
813-
// Do some useful optimizations after the evalling
814-
{
815-
PassRunner passRunner(&wasm);
816-
passRunner.add("memory-packing"); // we flattened it, so re-optimize
817-
// TODO: just do -Os for the one function
818-
passRunner.add("remove-unused-names");
819-
passRunner.add("dce");
820-
passRunner.add("merge-blocks");
821-
passRunner.add("vacuum");
822-
passRunner.add("remove-unused-module-elements");
823-
passRunner.run();
816+
if (canEval(wasm)) {
817+
evalCtors(wasm, ctors, keptExports);
818+
819+
// Do some useful optimizations after the evalling
820+
{
821+
PassRunner passRunner(&wasm);
822+
passRunner.add("memory-packing"); // we flattened it, so re-optimize
823+
// TODO: just do -Os for the one function
824+
passRunner.add("remove-unused-names");
825+
passRunner.add("dce");
826+
passRunner.add("merge-blocks");
827+
passRunner.add("vacuum");
828+
passRunner.add("remove-unused-module-elements");
829+
passRunner.run();
830+
}
824831
}
825832

826833
if (options.extra.count("output") > 0) {

test/ctor-eval/memory-init.wast

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(module
2+
(memory $0 1)
3+
(data (i32.const 0) "__________")
4+
(data (i32.const 20) "__________")
5+
(func "test1"
6+
;; A store that can be evalled.
7+
(i32.store8
8+
(i32.const 4)
9+
(i32.const 100)
10+
)
11+
12+
;; A memory init cannot be evalled since ctor-eval flattens memory segments
13+
;; atm. We lose the identity of them as a result as they are all merged
14+
;; into a single big segment. We could fix that eventually.
15+
(memory.init 1
16+
(i32.const 0)
17+
(i32.const 0)
18+
(i32.const 1)
19+
)
20+
)
21+
)
22+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test1
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
(module
2+
(type $none_=>_none (func))
3+
(memory $0 1)
4+
(data (i32.const 0) "__________")
5+
(data (i32.const 20) "__________")
6+
(export "test1" (func $0))
7+
(func $0
8+
(i32.store8
9+
(i32.const 4)
10+
(i32.const 100)
11+
)
12+
(memory.init 1
13+
(i32.const 0)
14+
(i32.const 0)
15+
(i32.const 1)
16+
)
17+
)
18+
)

0 commit comments

Comments
 (0)