Skip to content

Commit 4d479b4

Browse files
authored
1 parent 4d04c22 commit 4d479b4

File tree

78 files changed

+539
-306
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+539
-306
lines changed

scripts/test/shared.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,6 @@ def get_tests(test_dir, extensions=[], recursive=False):
405405
'threads/atomic.wast',
406406
]
407407
SPEC_TESTSUITE_PROPOSALS_TO_SKIP = [
408-
'custom-page-sizes',
409408
'wide-arithmetic',
410409
]
411410

src/binaryen-c.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,9 @@ BinaryenFeatures BinaryenFeatureCallIndirectOverlong(void) {
502502
BinaryenFeatures BinaryenFeatureRelaxedAtomics(void) {
503503
return static_cast<BinaryenFeatures>(FeatureSet::RelaxedAtomics);
504504
}
505+
BinaryenFeatures BinaryenFeatureCustomPageSizes(void) {
506+
return static_cast<BinaryenFeatures>(FeatureSet::CustomPageSizes);
507+
}
505508
BinaryenFeatures BinaryenFeatureAll(void) {
506509
return static_cast<BinaryenFeatures>(FeatureSet::All);
507510
}

src/binaryen-c.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ BINARYEN_API BinaryenFeatures BinaryenFeatureFP16(void);
244244
BINARYEN_API BinaryenFeatures BinaryenFeatureBulkMemoryOpt(void);
245245
BINARYEN_API BinaryenFeatures BinaryenFeatureCallIndirectOverlong(void);
246246
BINARYEN_API BinaryenFeatures BinaryenFeatureRelaxedAtomics(void);
247+
BINARYEN_API BinaryenFeatures BinaryenFeatureCustomPageSizes(void);
247248
BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void);
248249

249250
// Modules

src/ir/memory-utils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ namespace wasm::MemoryUtils {
2222

2323
bool isSubType(const Memory& a, const Memory& b) {
2424
return a.shared == b.shared && a.addressType == b.addressType &&
25-
a.initial >= b.initial && a.max <= b.max;
25+
a.initial >= b.initial && a.max <= b.max &&
26+
a.pageSizeLog2 == b.pageSizeLog2;
2627
}
2728

2829
bool flatten(Module& wasm) {

src/ir/module-utils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ Memory* copyMemory(const Memory* memory, Module& out) {
173173
ret->hasExplicitName = memory->hasExplicitName;
174174
ret->initial = memory->initial;
175175
ret->max = memory->max;
176+
ret->pageSizeLog2 = memory->pageSizeLog2;
176177
ret->shared = memory->shared;
177178
ret->addressType = memory->addressType;
178179
ret->module = memory->module;

src/js/binaryen.js-post.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ function initializeConstants() {
193193
'BulkMemoryOpt',
194194
'CallIndirectOverlong',
195195
'RelaxedAtomics',
196+
'CustomPageSizes',
196197
'All'
197198
].forEach(name => {
198199
Module['Features'][name] = Module['_BinaryenFeature' + name]();

src/parser/context-decls.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ Result<Memory*> ParseDeclsCtx::addMemoryDecl(Index pos,
144144
m->initial = type.limits.initial;
145145
m->max = type.limits.max ? *type.limits.max : Memory::kUnlimitedSize;
146146
m->shared = type.shared;
147+
m->pageSizeLog2 = type.pageSizeLog2;
147148
if (name) {
148149
// TODO: if the existing memory is not explicitly named, fix its name
149150
// and continue.

src/parser/contexts.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct Limits {
4949
struct MemType {
5050
Type addressType;
5151
Limits limits;
52+
uint8_t pageSizeLog2;
5253
bool shared;
5354
};
5455

@@ -174,8 +175,6 @@ struct NullTypeParserCtx {
174175
DataStringT makeDataString() { return Ok{}; }
175176
void appendDataString(DataStringT&, std::string_view) {}
176177

177-
MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; }
178-
179178
BlockTypeT getBlockTypeFromResult(size_t results) { return Ok{}; }
180179

181180
Result<> getBlockTypeFromTypeUse(Index, TypeUseT) { return Ok{}; }
@@ -353,9 +352,8 @@ template<typename Ctx> struct TypeParserCtx {
353352
void appendDataString(DataStringT&, std::string_view) {}
354353

355354
Result<LimitsT> makeLimits(uint64_t, std::optional<uint64_t>) { return Ok{}; }
356-
LimitsT getLimitsFromData(DataStringT) { return Ok{}; }
357355

358-
MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; }
356+
MemTypeT makeMemType(Type, LimitsT, bool, uint8_t) { return Ok{}; }
359357

360358
HeapType getBlockTypeFromResult(const std::vector<Type> results) {
361359
assert(results.size() == 1);
@@ -1086,13 +1084,18 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
10861084
data.insert(data.end(), str.begin(), str.end());
10871085
}
10881086

1089-
Limits getLimitsFromData(const std::vector<char>& data) {
1090-
uint64_t size = (data.size() + Memory::kPageSize - 1) / Memory::kPageSize;
1087+
Limits getLimitsFromData(const std::vector<char>& data,
1088+
uint8_t pageSizeLog2) {
1089+
uint64_t size =
1090+
(data.size() + (1 << pageSizeLog2) - 1) / (1 << pageSizeLog2);
10911091
return {size, size};
10921092
}
10931093

1094-
MemType makeMemType(Type addressType, Limits limits, bool shared) {
1095-
return {addressType, limits, shared};
1094+
MemType makeMemType(Type addressType,
1095+
Limits limits,
1096+
bool shared,
1097+
uint8_t pageSizeLog2) {
1098+
return {addressType, limits, pageSizeLog2, shared};
10961099
}
10971100

10981101
Result<TypeUseT>
@@ -1474,8 +1477,8 @@ struct ParseModuleTypesCtx : TypeParserCtx<ParseModuleTypesCtx>,
14741477

14751478
Type makeTableType(Type addressType, LimitsT, Type type) { return type; }
14761479

1477-
LimitsT getLimitsFromData(DataStringT) { return Ok{}; }
1478-
MemTypeT makeMemType(Type, LimitsT, bool) { return Ok{}; }
1480+
LimitsT getLimitsFromData(DataStringT, uint8_t) { return Ok{}; }
1481+
MemTypeT makeMemType(Type, LimitsT, bool, uint8_t) { return Ok{}; }
14791482

14801483
Result<> addFunc(Name name,
14811484
const std::vector<Name>&,

src/parser/parsers.h

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "common.h"
2121
#include "contexts.h"
2222
#include "lexer.h"
23+
#include "wasm.h"
2324
#include "wat-parser-internal.h"
2425

2526
namespace wasm::WATParser {
@@ -829,7 +830,34 @@ template<typename Ctx> Result<typename Ctx::LimitsT> limits64(Ctx& ctx) {
829830
return ctx.makeLimits(uint64_t(*n), m);
830831
}
831832

832-
// memtype ::= (limits32 | 'i32' limits32 | 'i64' limit64) shared?
833+
// mempagesize? ::= ('(' 'pagesize' u64 ')') ?
834+
template<typename Ctx> MaybeResult<uint8_t> mempagesize(Ctx& ctx) {
835+
if (!ctx.in.takeSExprStart("pagesize"sv)) {
836+
return {}; // No pagesize specified
837+
}
838+
auto pageSize = ctx.in.takeU64();
839+
if (!pageSize) {
840+
return ctx.in.err("expected page size");
841+
}
842+
843+
if (!Bits::isPowerOf2(*pageSize)) {
844+
return ctx.in.err("page size must be a power of two");
845+
}
846+
847+
if (!ctx.in.takeRParen()) {
848+
return ctx.in.err("expected end of mempagesize");
849+
}
850+
851+
uint8_t pageSizeLog2 = (uint8_t)Bits::ceilLog2(*pageSize);
852+
853+
if (pageSizeLog2 != 0 && pageSizeLog2 != Memory::kDefaultPageSizeLog2) {
854+
return ctx.in.err("memory page size can only be 1 or 64 KiB");
855+
}
856+
857+
return pageSizeLog2;
858+
}
859+
860+
// memtype ::= (limits32 | 'i32' limits32 | 'i64' limit64) shared? mempagesize?
833861
// note: the index type 'i32' or 'i64' is already parsed to simplify parsing of
834862
// memory abbreviations.
835863
template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx& ctx) {
@@ -851,7 +879,11 @@ Result<typename Ctx::MemTypeT> memtypeContinued(Ctx& ctx, Type addressType) {
851879
if (ctx.in.takeKeyword("shared"sv)) {
852880
shared = true;
853881
}
854-
return ctx.makeMemType(addressType, *limits, shared);
882+
MaybeResult<uint8_t> mempageSize = mempagesize(ctx);
883+
CHECK_ERR(mempageSize);
884+
const uint8_t pageSizeLog2 =
885+
mempageSize ? *mempageSize : Memory::kDefaultPageSizeLog2;
886+
return ctx.makeMemType(addressType, *limits, shared, pageSizeLog2);
855887
}
856888

857889
// memorder ::= 'seqcst' | 'acqrel'
@@ -3584,6 +3616,8 @@ template<typename Ctx> MaybeResult<> memory(Ctx& ctx) {
35843616

35853617
std::optional<typename Ctx::MemTypeT> mtype;
35863618
std::optional<typename Ctx::DataStringT> data;
3619+
MaybeResult<uint8_t> mempageSize = mempagesize(ctx);
3620+
CHECK_ERR(mempageSize);
35873621
if (ctx.in.takeSExprStart("data"sv)) {
35883622
if (import) {
35893623
return ctx.in.err("imported memories cannot have inline data");
@@ -3593,9 +3627,17 @@ template<typename Ctx> MaybeResult<> memory(Ctx& ctx) {
35933627
if (!ctx.in.takeRParen()) {
35943628
return ctx.in.err("expected end of inline data");
35953629
}
3596-
mtype =
3597-
ctx.makeMemType(addressType, ctx.getLimitsFromData(*datastr), false);
3630+
const uint8_t pageSizeLog2 =
3631+
mempageSize.getPtr() ? *mempageSize : Memory::kDefaultPageSizeLog2;
3632+
mtype = ctx.makeMemType(addressType,
3633+
ctx.getLimitsFromData(*datastr, pageSizeLog2),
3634+
false,
3635+
pageSizeLog2);
35983636
data = *datastr;
3637+
} else if (mempageSize) {
3638+
// If we have a memory page size not within a memtype expression, we expect
3639+
// a memory abbreviation.
3640+
return ctx.in.err("expected data segment in memory abbreviation");
35993641
} else {
36003642
auto type = memtypeContinued(ctx, addressType);
36013643
CHECK_ERR(type);

src/passes/LLVMMemoryCopyFillLowering.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,17 @@ struct LLVMMemoryCopyFillLowering
117117
void createMemoryCopyFunc(Module* module) {
118118
Builder b(*module);
119119
Index dst = 0, src = 1, size = 2, start = 3, end = 4, step = 5, i = 6;
120-
Name memory = module->memories.front()->name;
120+
Name memoryName = module->memories.front()->name;
121+
Address::address32_t pageSizeLog2 = module->memories.front()->pageSizeLog2;
121122
Block* body = b.makeBlock();
122123
// end = memory size in bytes
123-
body->list.push_back(
124-
b.makeLocalSet(end,
125-
b.makeBinary(BinaryOp::MulInt32,
126-
b.makeMemorySize(memory),
127-
b.makeConst(Memory::kPageSize))));
124+
body->list.push_back(b.makeLocalSet(
125+
end,
126+
pageSizeLog2 == 0
127+
? static_cast<Expression*>(b.makeMemorySize(memoryName))
128+
: static_cast<Expression*>(b.makeBinary(BinaryOp::ShlInt32,
129+
b.makeMemorySize(memoryName),
130+
b.makeConst(pageSizeLog2)))));
128131
// if dst + size > memsize or src + size > memsize, then trap.
129132
body->list.push_back(b.makeIf(
130133
b.makeBinary(BinaryOp::OrInt32,
@@ -187,9 +190,9 @@ struct LLVMMemoryCopyFillLowering
187190
b.makeLocalGet(src, Type::i32),
188191
b.makeLocalGet(i, Type::i32)),
189192
Type::i32,
190-
memory),
193+
memoryName),
191194
Type::i32,
192-
memory),
195+
memoryName),
193196
// i += step
194197
b.makeLocalSet(i,
195198
b.makeBinary(BinaryOp::AddInt32,
@@ -203,19 +206,23 @@ struct LLVMMemoryCopyFillLowering
203206
void createMemoryFillFunc(Module* module) {
204207
Builder b(*module);
205208
Index dst = 0, val = 1, size = 2;
206-
Name memory = module->memories.front()->name;
209+
Name memoryName = module->memories.front()->name;
210+
Address::address32_t pageSizeLog2 = module->memories.front()->pageSizeLog2;
207211
Block* body = b.makeBlock();
208212

209213
// if dst + size > memsize in bytes, then trap.
210-
body->list.push_back(
211-
b.makeIf(b.makeBinary(BinaryOp::GtUInt32,
212-
b.makeBinary(BinaryOp::AddInt32,
213-
b.makeLocalGet(dst, Type::i32),
214-
b.makeLocalGet(size, Type::i32)),
215-
b.makeBinary(BinaryOp::MulInt32,
216-
b.makeMemorySize(memory),
217-
b.makeConst(Memory::kPageSize))),
218-
b.makeUnreachable()));
214+
body->list.push_back(b.makeIf(
215+
b.makeBinary(
216+
BinaryOp::GtUInt32,
217+
b.makeBinary(BinaryOp::AddInt32,
218+
b.makeLocalGet(dst, Type::i32),
219+
b.makeLocalGet(size, Type::i32)),
220+
pageSizeLog2 == 0
221+
? static_cast<Expression*>(b.makeMemorySize(memoryName))
222+
: static_cast<Expression*>(b.makeBinary(BinaryOp::ShlInt32,
223+
b.makeMemorySize(memoryName),
224+
b.makeConst(pageSizeLog2)))),
225+
b.makeUnreachable()));
219226

220227
body->list.push_back(b.makeBlock(
221228
"out",
@@ -241,7 +248,7 @@ struct LLVMMemoryCopyFillLowering
241248
b.makeLocalGet(size, Type::i32)),
242249
b.makeLocalGet(val, Type::i32),
243250
Type::i32,
244-
memory),
251+
memoryName),
245252
b.makeBreak("copy", nullptr)}))));
246253
module->getFunction(memFillFuncName)->body = body;
247254
}

0 commit comments

Comments
 (0)