summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/Print.cpp2
-rw-r--r--src/s2wasm-main.cpp21
-rw-r--r--src/s2wasm.h66
-rw-r--r--src/wasm-s-parser.h2
-rw-r--r--src/wasm.h9
5 files changed, 87 insertions, 13 deletions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 0fdb4255f..77dcb6154 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -259,7 +259,7 @@ struct PrintSExpression : public WasmVisitor<PrintSExpression, void> {
}
void visitUnary(Unary *curr) {
o << '(';
- prepareColor(o) << printWasmType(curr->type) << '.';
+ prepareColor(o) << printWasmType(curr->isRelational() ? curr->value->type : curr->type) << '.';
switch (curr->op) {
case Clz: o << "clz"; break;
case Ctz: o << "ctz"; break;
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp
index d7a18f547..752494aac 100644
--- a/src/s2wasm-main.cpp
+++ b/src/s2wasm-main.cpp
@@ -58,6 +58,16 @@ int main(int argc, const char *argv[]) {
[](Options *o, const std::string &argument) {
o->extra["stack-allocation"] = argument;
})
+ .add("--initial-memory", "-i", "Initial size of the linear memory",
+ Options::Arguments::One,
+ [](Options *o, const std::string &argument) {
+ o->extra["initial-memory"] = argument;
+ })
+ .add("--max-memory", "-m", "Maximum size of the linear memory",
+ Options::Arguments::One,
+ [](Options *o, const std::string &argument) {
+ o->extra["max-memory"] = argument;
+ })
.add_positional("INFILE", Options::Arguments::One,
[](Options *o, const std::string &argument) {
o->extra["infile"] = argument;
@@ -75,9 +85,18 @@ int main(int argc, const char *argv[]) {
options.extra.find("stack-allocation") != options.extra.end()
? std::stoull(options.extra["stack-allocation"])
: 0;
+ size_t initialMem =
+ options.extra.find("initial-memory") != options.extra.end()
+ ? std::stoull(options.extra["initial-memory"])
+ : 0;
+ size_t maxMem =
+ options.extra.find("max-memory") != options.extra.end()
+ ? std::stoull(options.extra["max-memory"])
+ : 0;
if (options.debug) std::cerr << "Global base " << globalBase << '\n';
S2WasmBuilder s2wasm(wasm, input.c_str(), options.debug, globalBase,
- stackAllocation, ignoreUnknownSymbols, startFunction);
+ stackAllocation, initialMem, maxMem, ignoreUnknownSymbols,
+ startFunction);
if (options.debug) std::cerr << "Emscripten gluing..." << std::endl;
std::stringstream meta;
diff --git a/src/s2wasm.h b/src/s2wasm.h
index eeff5ba04..87c0c2881 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -49,6 +49,7 @@ class S2WasmBuilder {
public:
S2WasmBuilder(AllocatingModule& wasm, const char* input, bool debug,
size_t globalBase, size_t stackAllocation,
+ size_t userInitialMemory, size_t userMaxMemory,
bool ignoreUnknownSymbols, Name startFunction)
: wasm(wasm),
allocator(wasm.allocator),
@@ -57,7 +58,19 @@ class S2WasmBuilder {
startFunction(startFunction),
globalBase(globalBase),
nextStatic(globalBase),
- initialMemory(0) {
+ minInitialMemory(0),
+ userInitialMemory(userInitialMemory),
+ userMaxMemory(userMaxMemory) {
+ if (userMaxMemory && userMaxMemory < userInitialMemory) {
+ Fatal() << "Specified max memory " << userMaxMemory <<
+ " is < specified initial memory " << userInitialMemory;
+ }
+ if (roundUpToPageSize(userMaxMemory) != userMaxMemory) {
+ Fatal() << "Specified max memory " << userMaxMemory << " is not a multiple of 64k";
+ }
+ if (roundUpToPageSize(userInitialMemory) != userInitialMemory) {
+ Fatal() << "Specified initial memory " << userInitialMemory << " is not a multiple of 64k";
+ }
s = input;
scan();
s = input;
@@ -77,7 +90,10 @@ class S2WasmBuilder {
size_t globalBase, // where globals can start to be statically allocated, i.e., the data segment
nextStatic; // location of next static allocation
std::map<Name, int32_t> staticAddresses; // name => address
- size_t initialMemory; // Initial size (in bytes) of memory (after linking, this is rounded and set on the wasm object in pages)
+ size_t minInitialMemory; // Minimum initial size (in bytes) of memory.
+ size_t userInitialMemory; // Initial memory size (in bytes) specified by the user.
+ size_t userMaxMemory; // Max memory size (in bytes) specified by the user.
+ //(after linking, this is rounded and set on the wasm object in pages)
struct Relocation {
uint32_t* data;
@@ -96,6 +112,23 @@ class S2WasmBuilder {
// utilities
+ // For fatal errors which could arise from input (i.e. not assertion failures)
+ class Fatal {
+ public:
+ Fatal() {
+ std::cerr << "Fatal: ";
+ }
+ template<typename T>
+ Fatal &operator<<(T arg) {
+ std::cerr << std::forward<T>(arg);
+ return *this;
+ }
+ ~Fatal() {
+ std::cerr << "\n";
+ exit(1);
+ }
+ };
+
void skipWhitespace() {
while (1) {
while (*s && isspace(*s)) s++;
@@ -399,7 +432,7 @@ class S2WasmBuilder {
addressSegments[nextStatic] = wasm.memory.segments.size();
wasm.memory.segments.emplace_back(
nextStatic, reinterpret_cast<char*>(raw), pointerSize);
- initialMemory = nextStatic + pointerSize;
+ minInitialMemory = nextStatic + pointerSize;
}
nextStatic += pointerSize;
}
@@ -410,7 +443,7 @@ class S2WasmBuilder {
nextStatic = (nextStatic + 15) & static_cast<size_t>(-16);
staticAddresses[".stack"] = nextStatic;
nextStatic += stackAllocation;
- initialMemory = nextStatic;
+ minInitialMemory = nextStatic;
}
void process() {
@@ -812,7 +845,8 @@ class S2WasmBuilder {
break;
}
case 'e': {
- if (match("eq")) makeBinary(BinaryOp::Eq, i32);
+ if (match("eqz")) makeUnary(UnaryOp::EqZ, i32);
+ else if (match("eq")) makeBinary(BinaryOp::Eq, i32);
else if (match("extend_s/i32")) makeUnary(UnaryOp::ExtendSInt32, type);
else if (match("extend_u/i32")) makeUnary(UnaryOp::ExtendUInt32, type);
else abort_on("type.e");
@@ -1154,7 +1188,7 @@ class S2WasmBuilder {
wasm.memory.segments.emplace_back(nextStatic, (const char*)&(*raw)[0], size);
}
nextStatic += size;
- initialMemory = nextStatic;
+ minInitialMemory = nextStatic;
}
void parseLcomm(Name name, size_t align=1) {
@@ -1168,7 +1202,7 @@ class S2WasmBuilder {
while (nextStatic % align) nextStatic++;
staticAddresses[name] = nextStatic;
nextStatic += size;
- initialMemory = nextStatic;
+ minInitialMemory = nextStatic;
}
void skipImports() {
@@ -1182,11 +1216,25 @@ class S2WasmBuilder {
}
}
+ static size_t roundUpToPageSize(size_t size) {
+ return (size + Memory::kPageSize - 1) & Memory::kPageMask;
+ }
+
void fix() {
// Round the memory size up to a page, and update the page-increment versions
// of initial and max
- wasm.memory.initial = ((initialMemory + Memory::kPageSize - 1) & Memory::kPageMask) /
- Memory::kPageSize;
+ size_t initialMem = roundUpToPageSize(minInitialMemory);
+ if (userInitialMemory) {
+ if (initialMem > userInitialMemory) {
+ Fatal() << "Specified initial memory size " << userInitialMemory <<
+ " is smaller than required size " << initialMem;
+ }
+ wasm.memory.initial = userInitialMemory / Memory::kPageSize;
+ } else {
+ wasm.memory.initial = initialMem / Memory::kPageSize;
+ }
+
+ if (userMaxMemory) wasm.memory.max = userMaxMemory / Memory::kPageSize;
wasm.memory.exportName = MEMORY;
// XXX For now, export all functions marked .globl.
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 5bb2b44ee..965336857 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -489,7 +489,7 @@ public:
case 'e': {
if (op[1] == 'q') {
if (op[2] == 0) return makeBinary(s, BinaryOp::Eq, type);
- if (op[2] == 'z') return makeUnary(s, UnaryOp::EqZ, type);
+ if (op[2] == 'z') return makeUnary(s, UnaryOp::EqZ, i32);
}
if (op[1] == 'x') return makeUnary(s, op[7] == 'u' ? UnaryOp::ExtendUInt32 : UnaryOp::ExtendSInt32, type);
abort_on(op);
diff --git a/src/wasm.h b/src/wasm.h
index 2fcc3cddc..7422dd85d 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -681,8 +681,10 @@ public:
// Operators
enum UnaryOp {
- Clz, Ctz, Popcnt, EqZ, // int
+ Clz, Ctz, Popcnt, // int
Neg, Abs, Ceil, Floor, Trunc, Nearest, Sqrt, // float
+ // relational
+ EqZ,
// conversions
ExtendSInt32, ExtendUInt32, WrapInt64, TruncSFloat32, TruncUFloat32, TruncSFloat64, TruncUFloat64, ReinterpretFloat, // int
ConvertSInt32, ConvertUInt32, ConvertSInt64, ConvertUInt64, PromoteFloat32, DemoteFloat64, ReinterpretInt // float
@@ -972,6 +974,11 @@ public:
UnaryOp op;
Expression *value;
+
+ // the type is always the type of the operands,
+ // except for relationals
+
+ bool isRelational() { return op == EqZ; }
};
class Binary : public Expression {