Skip to content

Mutli-Memories Support in IR #4811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 78 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
fd11edc
Updating wasm.h/.cpp
ashleynh Jun 16, 2022
71b0eef
Updated wasm-binary.h/cpp
ashleynh Jun 19, 2022
74c77a7
Updated wasm-s-parser.cpp
ashleynh Jun 19, 2022
44946d4
Update wasm2js.h
ashleynh Jun 19, 2022
bcd6039
wasm-interpreter.h
ashleynh Jun 20, 2022
79bca3c
update src/abi/stack.h
ashleynh Jun 20, 2022
15c144d
updated binaryen-c.cpp
ashleynh Jun 20, 2022
4d5f7c3
shell-interface.h & wasm-builder.h
ashleynh Jun 20, 2022
c0c4f2a
Update src/ir
ashleynh Jun 20, 2022
6c9893b
src/wasm
ashleynh Jun 20, 2022
9382618
src/passes
ashleynh Jun 20, 2022
e26e2f4
src/tools/
ashleynh Jun 20, 2022
d782e2c
src/wasm-traversal.h
ashleynh Jun 20, 2022
229ffbb
It builds
ashleynh Jun 20, 2022
f33e5f7
Added empty checks
ashleynh Jun 21, 2022
c1ee8ac
more empty changes
ashleynh Jun 21, 2022
c4461dc
Making progress
ashleynh Jun 23, 2022
426fc5d
it builds
ashleynh Jun 26, 2022
c5d0499
making sure data segments have valid memory names
ashleynh Jun 27, 2022
c31ebd9
fixing ensure exists
ashleynh Jun 27, 2022
7a63097
parsing memory name for every relevant instruction
ashleynh Jun 28, 2022
4c8f27d
Updated flatten
ashleynh Jun 28, 2022
b844b03
updating
ashleynh Jun 28, 2022
4c55570
update
ashleynh Jun 28, 2022
de54f52
switching to using idx
ashleynh Jun 29, 2022
02e67e4
update
ashleynh Jun 30, 2022
3bb69ea
Added memory name param to all memory instructions.
ashleynh Jul 1, 2022
dda71a8
Adding memory to fields to be copied
ashleynh Jul 3, 2022
527933d
copying data segment name
ashleynh Jul 3, 2022
8b35c36
added memory name
ashleynh Jul 4, 2022
a8a1f61
fixing bugs
ashleynh Jul 4, 2022
496eaf2
parsing fixes
ashleynh Jul 5, 2022
58e3e47
bug fixes
ashleynh Jul 5, 2022
f9d4a9f
bug fixes
ashleynh Jul 11, 2022
3ef831b
through spec passes
ashleynh Jul 12, 2022
fc02ee1
Added more checks
ashleynh Jul 13, 2022
d8b3dde
Changed RemoveUnusedModuleElements back to working with a single memory
ashleynh Jul 13, 2022
1d8ba1e
bug fixes
ashleynh Jul 14, 2022
084cc5d
Fixing example tests
ashleynh Jul 14, 2022
e37fca2
test fix
ashleynh Jul 15, 2022
d23f062
Fixes for tests
ashleynh Jul 18, 2022
2d18836
Removed multi-memory assumed failure asserts. Rearranged memory expor…
ashleynh Jul 18, 2022
a006a94
Ran clang-format
ashleynh Jul 18, 2022
5018f49
lint
ashleynh Jul 18, 2022
5c41ffe
CI build error
ashleynh Jul 18, 2022
d820c76
lint
ashleynh Jul 18, 2022
0e90a2b
removing print_trace
ashleynh Jul 18, 2022
ab6fb81
Resolving binaryen_js test errors
ashleynh Jul 21, 2022
eeae770
clang-format
ashleynh Jul 21, 2022
ef2df16
rebased with main
ashleynh Jul 22, 2022
59640ce
asan
ashleynh Jul 22, 2022
feff650
review & cleanup
ashleynh Jul 24, 2022
18e9b06
clang-format
ashleynh Jul 25, 2022
cd1e3b3
memcopy & alignment
ashleynh Jul 25, 2022
74ae82c
clang-format
ashleynh Jul 25, 2022
3709558
metrics
ashleynh Jul 25, 2022
2dbe0ce
validate & metrics
ashleynh Jul 25, 2022
4acd9df
printing name
ashleynh Jul 25, 2022
7b44ae4
clang-format
ashleynh Jul 25, 2022
73716db
updating gufa
ashleynh Jul 25, 2022
0249723
updating binaryenjs test output
ashleynh Jul 26, 2022
6bd54f5
converted memoryRefs to vector of Name*
ashleynh Jul 27, 2022
2340669
parsing
ashleynh Jul 28, 2022
af99ee0
helper func
ashleynh Jul 28, 2022
432d05e
mem access
ashleynh Jul 29, 2022
c04851c
tests
ashleynh Jul 29, 2022
ee685b7
fixing merge conflict in test output
ashleynh Jul 29, 2022
d1b2723
clang-format
ashleynh Jul 29, 2022
2d7d965
only emitting binary idx when non 0
ashleynh Jul 29, 2022
236d6c7
updating tests
ashleynh Aug 5, 2022
fc85a8e
removing resize
ashleynh Aug 5, 2022
e9dea49
fuzzing fixes
ashleynh Aug 11, 2022
d28e552
fuzzer ignore multi-memories test files
ashleynh Aug 11, 2022
6e7a30d
printing the memory name only if memories > 0 or no module set
ashleynh Aug 15, 2022
a5c6413
clang-format
ashleynh Aug 15, 2022
e535ad7
updating test
ashleynh Aug 16, 2022
b849e74
clang-format
ashleynh Aug 17, 2022
94d52a5
updating test with memory
ashleynh Aug 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions scripts/fuzz_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ def is_git_repo():
'fib2_emptylocspan_dwarf.wasm',
'fannkuch3_dwarf.wasm',
'multi_unit_abbrev_noprint.wasm',
# TODO fuzzer support for multi-memories
'multi-memories-atomics64.wast',
'multi-memories-basics.wast',
'multi-memories-simd.wast',
'multi-memories-atomics64.wasm',
'multi-memories-basics.wasm',
'multi-memories-simd.wasm',
'multi-memories_size.wast',
]


Expand Down
3 changes: 2 additions & 1 deletion src/abi/stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ getStackSpace(Index local, Function* func, Index size, Module& wasm) {
}
// align the size
size = stackAlign(size);
auto pointerType = wasm.memory.indexType;
auto pointerType =
!wasm.memories.empty() ? wasm.memories[0]->indexType : Type::i32;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pass can probably halt with an error (like on line 49 above) if there are no memories. Please also add a comment that we are assuming that memory 0 is the "main" memory here.

// TODO: find existing stack usage, and add on top of that - carefully
Builder builder(wasm);
auto* block = builder.makeBlock();
Expand Down
288 changes: 218 additions & 70 deletions src/binaryen-c.cpp

Large diffs are not rendered by default.

84 changes: 53 additions & 31 deletions src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,8 @@ BINARYEN_API BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
uint32_t offset,
uint32_t align,
BinaryenType type,
BinaryenExpressionRef ptr);
BinaryenExpressionRef ptr,
const char* name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure name is clear enough here. Perhaps memoryName?

// Store: align can be 0, in which case it will be the natural alignment (equal
// to bytes)
BINARYEN_API BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
Expand All @@ -755,7 +756,8 @@ BINARYEN_API BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
uint32_t align,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
BinaryenType type);
BinaryenType type,
const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
struct BinaryenLiteral value);
BINARYEN_API BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module,
Expand All @@ -776,51 +778,57 @@ BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
// Return: value can be NULL
BINARYEN_API BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
BinaryenExpressionRef value);
BINARYEN_API BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryGrow(BinaryenModuleRef module, BinaryenExpressionRef delta);
BINARYEN_API BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module,
const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenMemoryGrow(
BinaryenModuleRef module, BinaryenExpressionRef delta, const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
BinaryenUnreachable(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicLoad(BinaryenModuleRef module,
uint32_t bytes,
uint32_t offset,
BinaryenType type,
BinaryenExpressionRef ptr);
BINARYEN_API BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
uint32_t bytes,
uint32_t offset,
BinaryenType type,
BinaryenExpressionRef ptr,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicStore(BinaryenModuleRef module,
uint32_t bytes,
uint32_t offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
BinaryenType type);
BinaryenType type,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicRMW(BinaryenModuleRef module,
BinaryenOp op,
BinaryenIndex bytes,
BinaryenIndex offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
BinaryenType type);
BinaryenType type,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicCmpxchg(BinaryenModuleRef module,
BinaryenIndex bytes,
BinaryenIndex offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef expected,
BinaryenExpressionRef replacement,
BinaryenType type);
BinaryenType type,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicWait(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
BinaryenExpressionRef expected,
BinaryenExpressionRef timeout,
BinaryenType type);
BinaryenType type,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicNotify(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
BinaryenExpressionRef notifyCount);
BinaryenExpressionRef notifyCount,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicFence(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
Expand Down Expand Up @@ -853,33 +861,39 @@ BINARYEN_API BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
BinaryenOp op,
uint32_t offset,
uint32_t align,
BinaryenExpressionRef ptr);
BinaryenExpressionRef ptr,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenSIMDLoadStoreLane(BinaryenModuleRef module,
BinaryenOp op,
uint32_t offset,
uint32_t align,
uint8_t index,
BinaryenExpressionRef ptr,
BinaryenExpressionRef vec);
BinaryenExpressionRef vec,
const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryInit(BinaryenModuleRef module,
uint32_t segment,
BinaryenExpressionRef dest,
BinaryenExpressionRef offset,
BinaryenExpressionRef size);
BinaryenExpressionRef size,
const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
uint32_t segment);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryCopy(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef source,
BinaryenExpressionRef size);
BinaryenExpressionRef size,
const char* destMemory,
const char* sourceMemory);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryFill(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef value,
BinaryenExpressionRef size);
BinaryenExpressionRef size,
const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
BinaryenType type);
BINARYEN_API BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module,
Expand Down Expand Up @@ -2194,6 +2208,9 @@ BINARYEN_API void BinaryenAddTagImport(BinaryenModuleRef module,
BinaryenType params,
BinaryenType results);

// Memory
BINARYEN_REF(Memory);

// Exports

BINARYEN_REF(Export);
Expand Down Expand Up @@ -2310,8 +2327,7 @@ BinaryenGetElementSegment(BinaryenModuleRef module, const char* name);
BINARYEN_API BinaryenElementSegmentRef
BinaryenGetElementSegmentByIndex(BinaryenModuleRef module, BinaryenIndex index);

// Memory. One per module

// This will create a memory, overwriting any existing memory
// Each memory has data in segments, a start offset in segmentOffsets, and a
// size in segmentSizes. exportName can be NULL
BINARYEN_API void BinaryenSetMemory(BinaryenModuleRef module,
Expand All @@ -2323,16 +2339,22 @@ BINARYEN_API void BinaryenSetMemory(BinaryenModuleRef module,
BinaryenExpressionRef* segmentOffsets,
BinaryenIndex* segmentSizes,
BinaryenIndex numSegments,
bool shared);
bool shared,
const char* name);

BINARYEN_API bool BinaryenHasMemory(BinaryenModuleRef module);
BINARYEN_API BinaryenIndex BinaryenMemoryGetInitial(BinaryenModuleRef module);
BINARYEN_API bool BinaryenMemoryHasMax(BinaryenModuleRef module);
BINARYEN_API BinaryenIndex BinaryenMemoryGetMax(BinaryenModuleRef module);
BINARYEN_API const char*
BinaryenMemoryImportGetModule(BinaryenModuleRef module);
BINARYEN_API const char* BinaryenMemoryImportGetBase(BinaryenModuleRef module);
BINARYEN_API bool BinaryenMemoryIsShared(BinaryenModuleRef module);
BINARYEN_API BinaryenIndex BinaryenMemoryGetInitial(BinaryenModuleRef module,
const char* name);
BINARYEN_API bool BinaryenMemoryHasMax(BinaryenModuleRef module,
const char* name);
BINARYEN_API BinaryenIndex BinaryenMemoryGetMax(BinaryenModuleRef module,
const char* name);
BINARYEN_API const char* BinaryenMemoryImportGetModule(BinaryenModuleRef module,
const char* name);
BINARYEN_API const char* BinaryenMemoryImportGetBase(BinaryenModuleRef module,
const char* name);
BINARYEN_API bool BinaryenMemoryIsShared(BinaryenModuleRef module,
const char* name);

// Memory segments. Query utilities.

Expand Down
14 changes: 13 additions & 1 deletion src/ir/import-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct ImportInfo {
std::vector<Global*> importedGlobals;
std::vector<Function*> importedFunctions;
std::vector<Table*> importedTables;
std::vector<Memory*> importedMemories;
std::vector<Tag*> importedTags;

ImportInfo(Module& wasm) : wasm(wasm) {
Expand All @@ -48,6 +49,11 @@ struct ImportInfo {
importedTables.push_back(import.get());
}
}
for (auto& import : wasm.memories) {
if (import->imported()) {
importedMemories.push_back(import.get());
}
}
for (auto& import : wasm.tags) {
if (import->imported()) {
importedTags.push_back(import.get());
Expand Down Expand Up @@ -88,11 +94,13 @@ struct ImportInfo {

Index getNumImportedTables() { return importedTables.size(); }

Index getNumImportedMemories() { return importedMemories.size(); }

Index getNumImportedTags() { return importedTags.size(); }

Index getNumImports() {
return getNumImportedGlobals() + getNumImportedFunctions() +
getNumImportedTags() + (wasm.memory.imported() ? 1 : 0) +
getNumImportedTags() + getNumImportedMemories() +
getNumImportedTables();
}

Expand All @@ -108,6 +116,10 @@ struct ImportInfo {
return wasm.tables.size() - getNumImportedTables();
}

Index getNumDefinedMemories() {
return wasm.memories.size() - getNumImportedMemories();
}

Index getNumDefinedTags() { return wasm.tags.size() - getNumImportedTags(); }
};

Expand Down
5 changes: 4 additions & 1 deletion src/ir/memory-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
namespace wasm::MemoryUtils {

bool flatten(Module& wasm) {
// Flatten does not currently have support for multi-memories
if (wasm.memories.size() > 1) {
return false;
}
// The presence of any MemoryInit instructions is a problem because they care
// about segment identity, which flattening gets rid of ( when it merges them
// all into one big segment).
Expand Down Expand Up @@ -62,7 +66,6 @@ bool flatten(Module& wasm) {
}
std::copy(segment->data.begin(), segment->data.end(), data.begin() + start);
}
dataSegments.resize(1);
dataSegments[0]->offset->cast<Const>()->value = Literal(int32_t(0));
dataSegments[0]->data.swap(data);
wasm.removeDataSegments(
Expand Down
18 changes: 13 additions & 5 deletions src/ir/memory-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,25 @@ namespace wasm::MemoryUtils {
// Flattens memory into a single data segment, or no segment. If there is
// a segment, it starts at 0.
// Returns true if successful (e.g. relocatable segments cannot be flattened).
// Does not yet support multi-memories
bool flatten(Module& wasm);

// Ensures that the memory exists (of minimal size).
inline void ensureExists(Memory& memory) {
if (!memory.exists) {
memory.exists = true;
memory.initial = memory.max = 1;
// Ensures that a memory exists (of minimal size).
inline void ensureExists(Module* wasm) {
if (wasm->memories.empty()) {
auto memory = Builder::makeMemory("0");
memory->initial = memory->max = 1;
wasm->addMemory(std::move(memory));
}
}

// Try to merge segments until they fit into web limitations.
// Return true if successful.
// Does not yet support multi-memories
inline bool ensureLimitedSegments(Module& module) {
if (module.memories.size() > 1) {
return false;
}
Comment on lines +49 to +51
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should produce a fatal error here (and in similar places) so we don't forget to come back and fix it up later. @kripken, wdyt?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that fatal errors are better in places like this.

auto& dataSegments = module.dataSegments;
if (dataSegments.size() <= WebLimitations::MaxDataSegments) {
return true;
Expand Down Expand Up @@ -136,6 +142,7 @@ inline bool ensureLimitedSegments(Module& module) {
c->type = Type::i32;

auto combined = Builder::makeDataSegment();
combined->memory = module.memories[0]->name;
combined->offset = c;
for (Index j = i; j < dataSegments.size(); j++) {
auto& segment = dataSegments[j];
Expand All @@ -156,6 +163,7 @@ inline bool ensureLimitedSegments(Module& module) {
}

dataSegments.swap(mergedSegments);
module.updateDataSegmentsMap();
return true;
}
} // namespace wasm::MemoryUtils
Expand Down
11 changes: 3 additions & 8 deletions src/ir/module-splitting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,14 +612,9 @@ void ModuleSplitter::shareImportableItems() {
// TODO: Be more selective by only sharing global items that are actually used
// in the secondary module, just like we do for functions.

if (primary.memory.exists) {
secondary.memory.exists = true;
secondary.memory.initial = primary.memory.initial;
secondary.memory.max = primary.memory.max;
secondary.memory.shared = primary.memory.shared;
secondary.memory.indexType = primary.memory.indexType;
makeImportExport(
primary.memory, secondary.memory, "memory", ExternalKind::Memory);
for (auto& memory : primary.memories) {
auto secondaryMemory = ModuleUtils::copyMemory(memory.get(), secondary);
makeImportExport(*memory, *secondaryMemory, "memory", ExternalKind::Memory);
}

for (auto& table : primary.tables) {
Expand Down
Loading