summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-05-18 23:25:55 -0700
committerAlon Zakai <alonzakai@gmail.com>2016-05-18 23:25:55 -0700
commitce03a34d97b1afa3b7abd88d04bbbaffe346f1d9 (patch)
tree3b355032ee402a595954f703558a7dc84b7a55cf /src
parent4a7080b8dc98422b63dc5db3245029d3f689de15 (diff)
parent50c94e3e9fb6cdf043c7841d73299ee8be5d2cbd (diff)
downloadbinaryen-ce03a34d97b1afa3b7abd88d04bbbaffe346f1d9.tar.gz
binaryen-ce03a34d97b1afa3b7abd88d04bbbaffe346f1d9.tar.bz2
binaryen-ce03a34d97b1afa3b7abd88d04bbbaffe346f1d9.zip
Merge pull request #526 from WebAssembly/spec-test-update
Spec test updates, and many validation fixes
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h99
-rw-r--r--src/binaryen-c.cpp142
-rw-r--r--src/binaryen-c.h142
-rw-r--r--src/cfg/Relooper.cpp4
-rw-r--r--src/cfg/Relooper.h2
-rw-r--r--src/passes/OptimizeInstructions.cpp46
-rw-r--r--src/passes/PostEmscripten.cpp2
-rw-r--r--src/passes/Print.cpp200
-rw-r--r--src/passes/Vacuum.cpp2
-rw-r--r--src/s2wasm.h96
-rw-r--r--src/wasm-binary.h247
-rw-r--r--src/wasm-builder.h39
-rw-r--r--src/wasm-interpreter.h191
-rw-r--r--src/wasm-js.cpp10
-rw-r--r--src/wasm-s-parser.h164
-rw-r--r--src/wasm-validator.h111
-rw-r--r--src/wasm.cpp67
-rw-r--r--src/wasm.h126
18 files changed, 1053 insertions, 637 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 0f4852250..d1959b918 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -307,63 +307,58 @@ private:
}
BinaryOp parseAsmBinaryOp(IString op, Ref left, Ref right, AsmData *asmData) {
- if (op == PLUS) return BinaryOp::Add;
- if (op == MINUS) return BinaryOp::Sub;
- if (op == MUL) return BinaryOp::Mul;
- if (op == AND) return BinaryOp::And;
- if (op == OR) return BinaryOp::Or;
- if (op == XOR) return BinaryOp::Xor;
- if (op == LSHIFT) return BinaryOp::Shl;
- if (op == RSHIFT) return BinaryOp::ShrS;
- if (op == TRSHIFT) return BinaryOp::ShrU;
- if (op == EQ) return BinaryOp::Eq;
- if (op == NE) return BinaryOp::Ne;
WasmType leftType = detectWasmType(left, asmData);
-#if 0
- std::cout << "CHECK\n";
- left->stringify(std::cout);
- std::cout << " => " << printWasmType(leftType);
- std::cout << '\n';
- right->stringify(std::cout);
- std::cout << " => " << printWasmType(detectWasmType(right, asmData)) << "\n";
-#endif
bool isInteger = leftType == WasmType::i32;
+
+ if (op == PLUS) return isInteger ? BinaryOp::AddInt32 : (leftType == f32 ? BinaryOp::AddFloat32 : BinaryOp::AddFloat64);
+ if (op == MINUS) return isInteger ? BinaryOp::SubInt32 : (leftType == f32 ? BinaryOp::SubFloat32 : BinaryOp::SubFloat64);
+ if (op == MUL) return isInteger ? BinaryOp::MulInt32 : (leftType == f32 ? BinaryOp::MulFloat32 : BinaryOp::MulFloat64);
+ if (op == AND) return BinaryOp::AndInt32;
+ if (op == OR) return BinaryOp::OrInt32;
+ if (op == XOR) return BinaryOp::XorInt32;
+ if (op == LSHIFT) return BinaryOp::ShlInt32;
+ if (op == RSHIFT) return BinaryOp::ShrSInt32;
+ if (op == TRSHIFT) return BinaryOp::ShrUInt32;
+ if (op == EQ) return isInteger ? BinaryOp::EqInt32 : (leftType == f32 ? BinaryOp::EqFloat32 : BinaryOp::EqFloat64);
+ if (op == NE) return isInteger ? BinaryOp::NeInt32 : (leftType == f32 ? BinaryOp::NeFloat32 : BinaryOp::NeFloat64);
+
bool isUnsigned = isUnsignedCoercion(left) || isUnsignedCoercion(right);
+
if (op == DIV) {
if (isInteger) {
- return isUnsigned ? BinaryOp::DivU : BinaryOp::DivS;
+ return isUnsigned ? BinaryOp::DivUInt32 : BinaryOp::DivSInt32;
}
- return BinaryOp::Div;
+ return leftType == f32 ? BinaryOp::DivFloat32 : BinaryOp::DivFloat64;
}
if (op == MOD) {
if (isInteger) {
- return isUnsigned ? BinaryOp::RemU : BinaryOp::RemS;
+ return isUnsigned ? BinaryOp::RemUInt32 : BinaryOp::RemSInt32;
}
- return BinaryOp::RemS; // XXX no floating-point remainder op, this must be handled by the caller
+ return BinaryOp::RemSInt32; // XXX no floating-point remainder op, this must be handled by the caller
}
if (op == GE) {
if (isInteger) {
- return isUnsigned ? BinaryOp::GeU : BinaryOp::GeS;
+ return isUnsigned ? BinaryOp::GeUInt32 : BinaryOp::GeSInt32;
}
- return BinaryOp::Ge;
+ return leftType == f32 ? BinaryOp::GeFloat32 : BinaryOp::GeFloat64;
}
if (op == GT) {
if (isInteger) {
- return isUnsigned ? BinaryOp::GtU : BinaryOp::GtS;
+ return isUnsigned ? BinaryOp::GtUInt32 : BinaryOp::GtSInt32;
}
- return BinaryOp::Gt;
+ return leftType == f32 ? BinaryOp::GtFloat32 : BinaryOp::GtFloat64;
}
if (op == LE) {
if (isInteger) {
- return isUnsigned ? BinaryOp::LeU : BinaryOp::LeS;
+ return isUnsigned ? BinaryOp::LeUInt32 : BinaryOp::LeSInt32;
}
- return BinaryOp::Le;
+ return leftType == f32 ? BinaryOp::LeFloat32 : BinaryOp::LeFloat64;
}
if (op == LT) {
if (isInteger) {
- return isUnsigned ? BinaryOp::LtU : BinaryOp::LtS;
+ return isUnsigned ? BinaryOp::LtUInt32 : BinaryOp::LtSInt32;
}
- return BinaryOp::Lt;
+ return leftType == f32 ? BinaryOp::LtFloat32 : BinaryOp::LtFloat64;
}
abort_on("bad wasm binary op", op);
abort(); // avoid warning
@@ -733,7 +728,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
assert(functionTableStarts.find(tableName) != functionTableStarts.end());
auto sub = allocator.alloc<Binary>();
// note that the target is already masked, so we just offset it, we don't need to guard against overflow (which would be an error anyhow)
- sub->op = Add;
+ sub->op = AddInt32;
sub->left = call->target;
sub->right = allocator.alloc<Const>()->set(Literal((int32_t)functionTableStarts[tableName]));
sub->type = WasmType::i32;
@@ -1008,7 +1003,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
ret->left = process(ast[2]);
ret->right = process(ast[3]);
ret->finalize();
- if (binary == BinaryOp::RemS && isWasmTypeFloat(ret->type)) {
+ if (binary == BinaryOp::RemSInt32 && isWasmTypeFloat(ret->type)) {
// WebAssembly does not have floating-point remainder, we have to emit a call to a special import of ours
CallImport *call = allocator.alloc<CallImport>();
call->target = F64_REM;
@@ -1126,18 +1121,19 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
if (asmType == ASM_INT) {
// wasm has no unary negation for int, so do 0-
auto ret = allocator.alloc<Binary>();
- ret->op = Sub;
+ ret->op = SubInt32;
ret->left = allocator.alloc<Const>()->set(Literal((int32_t)0));
ret->right = process(ast[2]);
ret->type = WasmType::i32;
return ret;
}
auto ret = allocator.alloc<Unary>();
- ret->op = Neg;
ret->value = process(ast[2]);
if (asmType == ASM_DOUBLE) {
+ ret->op = NegFloat64;
ret->type = WasmType::f64;
} else if (asmType == ASM_FLOAT) {
+ ret->op = NegFloat32;
ret->type = WasmType::f32;
} else {
abort();
@@ -1181,14 +1177,14 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
}
// no bitwise unary not, so do xor with -1
auto ret = allocator.alloc<Binary>();
- ret->op = Xor;
+ ret->op = XorInt32;
ret->left = process(ast[2]);
ret->right = allocator.alloc<Const>()->set(Literal(int32_t(-1)));
ret->type = WasmType::i32;
return ret;
} else if (ast[1] == L_NOT) {
auto ret = allocator.alloc<Unary>();
- ret->op = EqZ;
+ ret->op = EqZInt32;
ret->value = process(ast[2]);
ret->type = i32;
return ret;
@@ -1206,7 +1202,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
if (name == Math_imul) {
assert(ast[2]->size() == 2);
auto ret = allocator.alloc<Binary>();
- ret->op = Mul;
+ ret->op = MulInt32;
ret->left = process(ast[2][0]);
ret->right = process(ast[2][1]);
ret->type = WasmType::i32;
@@ -1215,7 +1211,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
if (name == Math_clz32 || name == llvm_cttz_i32) {
assert(ast[2]->size() == 1);
auto ret = allocator.alloc<Unary>();
- ret->op = name == Math_clz32 ? Clz : Ctz;
+ ret->op = name == Math_clz32 ? ClzInt32 : CtzInt32;
ret->value = process(ast[2][0]);
ret->type = WasmType::i32;
return ret;
@@ -1262,14 +1258,14 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
return ret;
};
auto isNegative = allocator.alloc<Binary>();
- isNegative->op = LtS;
+ isNegative->op = LtSInt32;
isNegative->left = get();
isNegative->right = allocator.alloc<Const>()->set(Literal(0));
isNegative->finalize();
auto block = allocator.alloc<Block>();
block->list.push_back(set);
auto flip = allocator.alloc<Binary>();
- flip->op = Sub;
+ flip->op = SubInt32;
flip->left = allocator.alloc<Const>()->set(Literal(0));
flip->right = get();
flip->type = i32;
@@ -1283,7 +1279,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
return block;
} else if (value->type == f32 || value->type == f64) {
auto ret = allocator.alloc<Unary>();
- ret->op = Abs;
+ ret->op = value->type == f32 ? AbsFloat32 : AbsFloat64;
ret->value = value;
ret->type = value->type;
return ret;
@@ -1294,15 +1290,18 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
if (name == Math_floor || name == Math_sqrt || name == Math_ceil) {
// overloaded on type: f32 or f64
Expression* value = process(ast[2][0]);
- if (value->type == f32 || value->type == f64) {
- auto ret = allocator.alloc<Unary>();
- ret->op = name == Math_floor ? Floor : name == Math_ceil ? Ceil : Sqrt;
- ret->value = value;
+ auto ret = allocator.alloc<Unary>();
+ ret->value = value;
+ if (value->type == f32) {
+ ret->op = name == Math_floor ? FloorFloat32 : name == Math_ceil ? CeilFloat32 : SqrtFloat32;
+ ret->type = value->type;
+ } else if (value->type == f64) {
+ ret->op = name == Math_floor ? FloorFloat64 : name == Math_ceil ? CeilFloat64 : SqrtFloat64;
ret->type = value->type;
- return ret;
} else {
abort();
}
+ return ret;
}
Expression* ret;
ExpressionList* operands;
@@ -1404,7 +1403,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
Break *breakOut = allocator.alloc<Break>();
breakOut->name = out;
If *condition = allocator.alloc<If>();
- condition->condition = builder.makeUnary(EqZ, process(ast[1]));
+ condition->condition = builder.makeUnary(EqZInt32, process(ast[1]));
condition->ifTrue = breakOut;
auto body = allocator.alloc<Block>();
body->list.push_back(condition);
@@ -1501,7 +1500,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
Break *breakOut = allocator.alloc<Break>();
breakOut->name = out;
If *condition = allocator.alloc<If>();
- condition->condition = builder.makeUnary(EqZ, process(fcond));
+ condition->condition = builder.makeUnary(EqZInt32, process(fcond));
condition->ifTrue = breakOut;
auto body = allocator.alloc<Block>();
body->list.push_back(condition);
@@ -1627,7 +1626,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
}
}
Binary* offsetor = allocator.alloc<Binary>();
- offsetor->op = BinaryOp::Sub;
+ offsetor->op = BinaryOp::SubInt32;
offsetor->left = br->condition;
offsetor->right = allocator.alloc<Const>()->set(Literal(min));
offsetor->type = i32;
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 62e35f025..7fb39ffe4 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -98,17 +98,28 @@ BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) { return toBinaryenLiteral
// Expressions
-BinaryenOp BinaryenClz(void) { return Clz; }
-BinaryenOp BinaryenCtz(void) { return Ctz; }
-BinaryenOp BinaryenPopcnt(void) { return Popcnt; }
-BinaryenOp BinaryenNeg(void) { return Neg; }
-BinaryenOp BinaryenAbs(void) { return Abs; }
-BinaryenOp BinaryenCeil(void) { return Ceil; }
-BinaryenOp BinaryenFloor(void) { return Floor; }
-BinaryenOp BinaryenTrunc(void) { return Trunc; }
-BinaryenOp BinaryenNearest(void) { return Nearest; }
-BinaryenOp BinaryenSqrt(void) { return Sqrt; }
-BinaryenOp BinaryenEqZ(void) { return EqZ; }
+BinaryenOp BinaryenClzInt32(void) { return ClzInt32; }
+BinaryenOp BinaryenCtzInt32(void) { return CtzInt32; }
+BinaryenOp BinaryenPopcntInt32(void) { return PopcntInt32; }
+BinaryenOp BinaryenNegFloat32(void) { return NegFloat32; }
+BinaryenOp BinaryenAbsFloat32(void) { return AbsFloat32; }
+BinaryenOp BinaryenCeilFloat32(void) { return CeilFloat32; }
+BinaryenOp BinaryenFloorFloat32(void) { return FloorFloat32; }
+BinaryenOp BinaryenTruncFloat32(void) { return TruncFloat32; }
+BinaryenOp BinaryenNearestFloat32(void) { return NearestFloat32; }
+BinaryenOp BinaryenSqrtFloat32(void) { return SqrtFloat32; }
+BinaryenOp BinaryenEqZInt32(void) { return EqZInt32; }
+BinaryenOp BinaryenClzInt64(void) { return ClzInt64; }
+BinaryenOp BinaryenCtzInt64(void) { return CtzInt64; }
+BinaryenOp BinaryenPopcntInt64(void) { return PopcntInt64; }
+BinaryenOp BinaryenNegFloat64(void) { return NegFloat64; }
+BinaryenOp BinaryenAbsFloat64(void) { return AbsFloat64; }
+BinaryenOp BinaryenCeilFloat64(void) { return CeilFloat64; }
+BinaryenOp BinaryenFloorFloat64(void) { return FloorFloat64; }
+BinaryenOp BinaryenTruncFloat64(void) { return TruncFloat64; }
+BinaryenOp BinaryenNearestFloat64(void) { return NearestFloat64; }
+BinaryenOp BinaryenSqrtFloat64(void) { return SqrtFloat64; }
+BinaryenOp BinaryenEqZInt64(void) { return EqZInt64; }
BinaryenOp BinaryenExtendSInt32(void) { return ExtendSInt32; }
BinaryenOp BinaryenExtentUInt32(void) { return ExtendUInt32; }
BinaryenOp BinaryenWrapInt64(void) { return WrapInt64; }
@@ -134,39 +145,82 @@ BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; }
BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; }
BinaryenOp BinaryenReinterpretInt32(void) { return ReinterpretInt32; }
BinaryenOp BinaryenReinterpretInt64(void) { return ReinterpretInt64; }
-BinaryenOp BinaryenAdd(void) { return Add; }
-BinaryenOp BinaryenSub(void) { return Sub; }
-BinaryenOp BinaryenMul(void) { return Mul; }
-BinaryenOp BinaryenDivS(void) { return DivS; }
-BinaryenOp BinaryenDivU(void) { return DivU; }
-BinaryenOp BinaryenRemS(void) { return RemS; }
-BinaryenOp BinaryenRemU(void) { return RemU; }
-BinaryenOp BinaryenAnd(void) { return And; }
-BinaryenOp BinaryenOr(void) { return Or; }
-BinaryenOp BinaryenXor(void) { return Xor; }
-BinaryenOp BinaryenShl(void) { return Shl; }
-BinaryenOp BinaryenShrU(void) { return ShrU; }
-BinaryenOp BinaryenShrS(void) { return ShrS; }
-BinaryenOp BinaryenRotL(void) { return RotL; }
-BinaryenOp BinaryenRotR(void) { return RotR; }
-BinaryenOp BinaryenDiv(void) { return Div; }
-BinaryenOp BinaryenCopySign(void) { return CopySign; }
-BinaryenOp BinaryenMin(void) { return Min; }
-BinaryenOp BinaryenMax(void) { return Max; }
-BinaryenOp BinaryenEq(void) { return Eq; }
-BinaryenOp BinaryenNe(void) { return Ne; }
-BinaryenOp BinaryenLtS(void) { return LtS; }
-BinaryenOp BinaryenLtU(void) { return LtU; }
-BinaryenOp BinaryenLeS(void) { return LeS; }
-BinaryenOp BinaryenLeU(void) { return LeU; }
-BinaryenOp BinaryenGtS(void) { return GtS; }
-BinaryenOp BinaryenGtU(void) { return GtU; }
-BinaryenOp BinaryenGeS(void) { return GeS; }
-BinaryenOp BinaryenGeU(void) { return GeU; }
-BinaryenOp BinaryenLt(void) { return Lt; }
-BinaryenOp BinaryenLe(void) { return Le; }
-BinaryenOp BinaryenGt(void) { return Gt; }
-BinaryenOp BinaryenGe(void) { return Ge; }
+BinaryenOp BinaryenAddInt32(void) { return AddInt32; }
+BinaryenOp BinaryenSubInt32(void) { return SubInt32; }
+BinaryenOp BinaryenMulInt32(void) { return MulInt32; }
+BinaryenOp BinaryenDivSInt32(void) { return DivSInt32; }
+BinaryenOp BinaryenDivUInt32(void) { return DivUInt32; }
+BinaryenOp BinaryenRemSInt32(void) { return RemSInt32; }
+BinaryenOp BinaryenRemUInt32(void) { return RemUInt32; }
+BinaryenOp BinaryenAndInt32(void) { return AndInt32; }
+BinaryenOp BinaryenOrInt32(void) { return OrInt32; }
+BinaryenOp BinaryenXorInt32(void) { return XorInt32; }
+BinaryenOp BinaryenShlInt32(void) { return ShlInt32; }
+BinaryenOp BinaryenShrUInt32(void) { return ShrUInt32; }
+BinaryenOp BinaryenShrSInt32(void) { return ShrSInt32; }
+BinaryenOp BinaryenRotLInt32(void) { return RotLInt32; }
+BinaryenOp BinaryenRotRInt32(void) { return RotRInt32; }
+BinaryenOp BinaryenEqInt32(void) { return EqInt32; }
+BinaryenOp BinaryenNeInt32(void) { return NeInt32; }
+BinaryenOp BinaryenLtSInt32(void) { return LtSInt32; }
+BinaryenOp BinaryenLtUInt32(void) { return LtUInt32; }
+BinaryenOp BinaryenLeSInt32(void) { return LeSInt32; }
+BinaryenOp BinaryenLeUInt32(void) { return LeUInt32; }
+BinaryenOp BinaryenGtSInt32(void) { return GtSInt32; }
+BinaryenOp BinaryenGtUInt32(void) { return GtUInt32; }
+BinaryenOp BinaryenGeSInt32(void) { return GeSInt32; }
+BinaryenOp BinaryenGeUInt32(void) { return GeUInt32; }
+BinaryenOp BinaryenAddInt64(void) { return AddInt64; }
+BinaryenOp BinaryenSubInt64(void) { return SubInt64; }
+BinaryenOp BinaryenMulInt64(void) { return MulInt64; }
+BinaryenOp BinaryenDivSInt64(void) { return DivSInt64; }
+BinaryenOp BinaryenDivUInt64(void) { return DivUInt64; }
+BinaryenOp BinaryenRemSInt64(void) { return RemSInt64; }
+BinaryenOp BinaryenRemUInt64(void) { return RemUInt64; }
+BinaryenOp BinaryenAndInt64(void) { return AndInt64; }
+BinaryenOp BinaryenOrInt64(void) { return OrInt64; }
+BinaryenOp BinaryenXorInt64(void) { return XorInt64; }
+BinaryenOp BinaryenShlInt64(void) { return ShlInt64; }
+BinaryenOp BinaryenShrUInt64(void) { return ShrUInt64; }
+BinaryenOp BinaryenShrSInt64(void) { return ShrSInt64; }
+BinaryenOp BinaryenRotLInt64(void) { return RotLInt64; }
+BinaryenOp BinaryenRotRInt64(void) { return RotRInt64; }
+BinaryenOp BinaryenEqInt64(void) { return EqInt64; }
+BinaryenOp BinaryenNeInt64(void) { return NeInt64; }
+BinaryenOp BinaryenLtSInt64(void) { return LtSInt64; }
+BinaryenOp BinaryenLtUInt64(void) { return LtUInt64; }
+BinaryenOp BinaryenLeSInt64(void) { return LeSInt64; }
+BinaryenOp BinaryenLeUInt64(void) { return LeUInt64; }
+BinaryenOp BinaryenGtSInt64(void) { return GtSInt64; }
+BinaryenOp BinaryenGtUInt64(void) { return GtUInt64; }
+BinaryenOp BinaryenGeSInt64(void) { return GeSInt64; }
+BinaryenOp BinaryenGeUInt64(void) { return GeUInt64; }
+BinaryenOp BinaryenAddFloat32(void) { return AddFloat32; }
+BinaryenOp BinaryenSubFloat32(void) { return SubFloat32; }
+BinaryenOp BinaryenMulFloat32(void) { return MulFloat32; }
+BinaryenOp BinaryenDivFloat32(void) { return DivFloat32; }
+BinaryenOp BinaryenCopySignFloat32(void) { return CopySignFloat32; }
+BinaryenOp BinaryenMinFloat32(void) { return MinFloat32; }
+BinaryenOp BinaryenMaxFloat32(void) { return MaxFloat32; }
+BinaryenOp BinaryenEqFloat32(void) { return EqFloat32; }
+BinaryenOp BinaryenNeFloat32(void) { return NeFloat32; }
+BinaryenOp BinaryenLtFloat32(void) { return LtFloat32; }
+BinaryenOp BinaryenLeFloat32(void) { return LeFloat32; }
+BinaryenOp BinaryenGtFloat32(void) { return GtFloat32; }
+BinaryenOp BinaryenGeFloat32(void) { return GeFloat32; }
+BinaryenOp BinaryenAddFloat64(void) { return AddFloat64; }
+BinaryenOp BinaryenSubFloat64(void) { return SubFloat64; }
+BinaryenOp BinaryenMulFloat64(void) { return MulFloat64; }
+BinaryenOp BinaryenDivFloat64(void) { return DivFloat64; }
+BinaryenOp BinaryenCopySignFloat64(void) { return CopySignFloat64; }
+BinaryenOp BinaryenMinFloat64(void) { return MinFloat64; }
+BinaryenOp BinaryenMaxFloat64(void) { return MaxFloat64; }
+BinaryenOp BinaryenEqFloat64(void) { return EqFloat64; }
+BinaryenOp BinaryenNeFloat64(void) { return NeFloat64; }
+BinaryenOp BinaryenLtFloat64(void) { return LtFloat64; }
+BinaryenOp BinaryenLeFloat64(void) { return LeFloat64; }
+BinaryenOp BinaryenGtFloat64(void) { return GtFloat64; }
+BinaryenOp BinaryenGeFloat64(void) { return GeFloat64; }
BinaryenOp BinaryenPageSize(void) { return PageSize; }
BinaryenOp BinaryenCurrentMemory(void) { return CurrentMemory; }
BinaryenOp BinaryenGrowMemory(void) { return GrowMemory; }
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index ae3e0c019..d3858489c 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -114,17 +114,28 @@ struct BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x);
typedef int32_t BinaryenOp;
-BinaryenOp BinaryenClz(void);
-BinaryenOp BinaryenCtz(void);
-BinaryenOp BinaryenPopcnt(void);
-BinaryenOp BinaryenNeg(void);
-BinaryenOp BinaryenAbs(void);
-BinaryenOp BinaryenCeil(void);
-BinaryenOp BinaryenFloor(void);
-BinaryenOp BinaryenTrunc(void);
-BinaryenOp BinaryenNearest(void);
-BinaryenOp BinaryenSqrt(void);
-BinaryenOp BinaryenEqZ(void);
+BinaryenOp BinaryenClzInt32(void);
+BinaryenOp BinaryenCtzInt32(void);
+BinaryenOp BinaryenPopcntInt32(void);
+BinaryenOp BinaryenNegFloat32(void);
+BinaryenOp BinaryenAbsFloat32(void);
+BinaryenOp BinaryenCeilFloat32(void);
+BinaryenOp BinaryenFloorFloat32(void);
+BinaryenOp BinaryenTruncFloat32(void);
+BinaryenOp BinaryenNearestFloat32(void);
+BinaryenOp BinaryenSqrtFloat32(void);
+BinaryenOp BinaryenEqZInt32(void);
+BinaryenOp BinaryenClzInt64(void);
+BinaryenOp BinaryenCtzInt64(void);
+BinaryenOp BinaryenPopcntInt64(void);
+BinaryenOp BinaryenNegFloat64(void);
+BinaryenOp BinaryenAbsFloat64(void);
+BinaryenOp BinaryenCeilFloat64(void);
+BinaryenOp BinaryenFloorFloat64(void);
+BinaryenOp BinaryenTruncFloat64(void);
+BinaryenOp BinaryenNearestFloat64(void);
+BinaryenOp BinaryenSqrtFloat64(void);
+BinaryenOp BinaryenEqZInt64(void);
BinaryenOp BinaryenExtendSInt32(void);
BinaryenOp BinaryenExtentUInt32(void);
BinaryenOp BinaryenWrapInt64(void);
@@ -150,39 +161,82 @@ BinaryenOp BinaryenPromoteFloat32(void);
BinaryenOp BinaryenDemoteFloat64(void);
BinaryenOp BinaryenReinterpretInt32(void);
BinaryenOp BinaryenReinterpretInt64(void);
-BinaryenOp BinaryenAdd(void);
-BinaryenOp BinaryenSub(void);
-BinaryenOp BinaryenMul(void);
-BinaryenOp BinaryenDivS(void);
-BinaryenOp BinaryenDivU(void);
-BinaryenOp BinaryenRemS(void);
-BinaryenOp BinaryenRemU(void);
-BinaryenOp BinaryenAnd(void);
-BinaryenOp BinaryenOr(void);
-BinaryenOp BinaryenXor(void);
-BinaryenOp BinaryenShl(void);
-BinaryenOp BinaryenShrU(void);
-BinaryenOp BinaryenShrS(void);
-BinaryenOp BinaryenRotL(void);
-BinaryenOp BinaryenRotR(void);
-BinaryenOp BinaryenDiv(void);
-BinaryenOp BinaryenCopySign(void);
-BinaryenOp BinaryenMin(void);
-BinaryenOp BinaryenMax(void);
-BinaryenOp BinaryenEq(void);
-BinaryenOp BinaryenNe(void);
-BinaryenOp BinaryenLtS(void);
-BinaryenOp BinaryenLtU(void);
-BinaryenOp BinaryenLeS(void);
-BinaryenOp BinaryenLeU(void);
-BinaryenOp BinaryenGtS(void);
-BinaryenOp BinaryenGtU(void);
-BinaryenOp BinaryenGeS(void);
-BinaryenOp BinaryenGeU(void);
-BinaryenOp BinaryenLt(void);
-BinaryenOp BinaryenLe(void);
-BinaryenOp BinaryenGt(void);
-BinaryenOp BinaryenGe(void);
+BinaryenOp BinaryenAddInt32(void);
+BinaryenOp BinaryenSubInt32(void);
+BinaryenOp BinaryenMulInt32(void);
+BinaryenOp BinaryenDivSInt32(void);
+BinaryenOp BinaryenDivUInt32(void);
+BinaryenOp BinaryenRemSInt32(void);
+BinaryenOp BinaryenRemUInt32(void);
+BinaryenOp BinaryenAndInt32(void);
+BinaryenOp BinaryenOrInt32(void);
+BinaryenOp BinaryenXorInt32(void);
+BinaryenOp BinaryenShlInt32(void);
+BinaryenOp BinaryenShrUInt32(void);
+BinaryenOp BinaryenShrSInt32(void);
+BinaryenOp BinaryenRotLInt32(void);
+BinaryenOp BinaryenRotRInt32(void);
+BinaryenOp BinaryenEqInt32(void);
+BinaryenOp BinaryenNeInt32(void);
+BinaryenOp BinaryenLtSInt32(void);
+BinaryenOp BinaryenLtUInt32(void);
+BinaryenOp BinaryenLeSInt32(void);
+BinaryenOp BinaryenLeUInt32(void);
+BinaryenOp BinaryenGtSInt32(void);
+BinaryenOp BinaryenGtUInt32(void);
+BinaryenOp BinaryenGeSInt32(void);
+BinaryenOp BinaryenGeUInt32(void);
+BinaryenOp BinaryenAddInt64(void);
+BinaryenOp BinaryenSubInt64(void);
+BinaryenOp BinaryenMulInt64(void);
+BinaryenOp BinaryenDivSInt64(void);
+BinaryenOp BinaryenDivUInt64(void);
+BinaryenOp BinaryenRemSInt64(void);
+BinaryenOp BinaryenRemUInt64(void);
+BinaryenOp BinaryenAndInt64(void);
+BinaryenOp BinaryenOrInt64(void);
+BinaryenOp BinaryenXorInt64(void);
+BinaryenOp BinaryenShlInt64(void);
+BinaryenOp BinaryenShrUInt64(void);
+BinaryenOp BinaryenShrSInt64(void);
+BinaryenOp BinaryenRotLInt64(void);
+BinaryenOp BinaryenRotRInt64(void);
+BinaryenOp BinaryenEqInt64(void);
+BinaryenOp BinaryenNeInt64(void);
+BinaryenOp BinaryenLtSInt64(void);
+BinaryenOp BinaryenLtUInt64(void);
+BinaryenOp BinaryenLeSInt64(void);
+BinaryenOp BinaryenLeUInt64(void);
+BinaryenOp BinaryenGtSInt64(void);
+BinaryenOp BinaryenGtUInt64(void);
+BinaryenOp BinaryenGeSInt64(void);
+BinaryenOp BinaryenGeUInt64(void);
+BinaryenOp BinaryenAddFloat32(void);
+BinaryenOp BinaryenSubFloat32(void);
+BinaryenOp BinaryenMulFloat32(void);
+BinaryenOp BinaryenDivFloat32(void);
+BinaryenOp BinaryenCopySignFloat32(void);
+BinaryenOp BinaryenMinFloat32(void);
+BinaryenOp BinaryenMaxFloat32(void);
+BinaryenOp BinaryenEqFloat32(void);
+BinaryenOp BinaryenNeFloat32(void);
+BinaryenOp BinaryenLtFloat32(void);
+BinaryenOp BinaryenLeFloat32(void);
+BinaryenOp BinaryenGtFloat32(void);
+BinaryenOp BinaryenGeFloat32(void);
+BinaryenOp BinaryenAddFloat64(void);
+BinaryenOp BinaryenSubFloat64(void);
+BinaryenOp BinaryenMulFloat64(void);
+BinaryenOp BinaryenDivFloat64(void);
+BinaryenOp BinaryenCopySignFloat64(void);
+BinaryenOp BinaryenMinFloat64(void);
+BinaryenOp BinaryenMaxFloat64(void);
+BinaryenOp BinaryenEqFloat64(void);
+BinaryenOp BinaryenNeFloat64(void);
+BinaryenOp BinaryenLtFloat64(void);
+BinaryenOp BinaryenLeFloat64(void);
+BinaryenOp BinaryenGtFloat64(void);
+BinaryenOp BinaryenGeFloat64(void);
BinaryenOp BinaryenPageSize(void);
BinaryenOp BinaryenCurrentMemory(void);
BinaryenOp BinaryenGrowMemory(void);
diff --git a/src/cfg/Relooper.cpp b/src/cfg/Relooper.cpp
index 14941833b..06867c748 100644
--- a/src/cfg/Relooper.cpp
+++ b/src/cfg/Relooper.cpp
@@ -199,9 +199,9 @@ wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
}
}
} else {
- auto* Now = Builder.makeUnary(wasm::EqZ, Details->Condition);
+ auto* Now = Builder.makeUnary(wasm::EqZInt32, Details->Condition);
if (RemainingConditions) {
- RemainingConditions = Builder.makeBinary(wasm::And, RemainingConditions, Now);
+ RemainingConditions = Builder.makeBinary(wasm::AndInt32, RemainingConditions, Now);
} else {
RemainingConditions = Now;
}
diff --git a/src/cfg/Relooper.h b/src/cfg/Relooper.h
index 706b3d065..3040b0fc2 100644
--- a/src/cfg/Relooper.h
+++ b/src/cfg/Relooper.h
@@ -50,7 +50,7 @@ public:
return makeSetLocal(labelHelper, makeConst(wasm::Literal(int32_t(value))));
}
wasm::Binary* makeCheckLabel(wasm::Index value) {
- return makeBinary(wasm::Eq, makeGetLabel(), makeConst(wasm::Literal(int32_t(value))));
+ return makeBinary(wasm::EqInt32, makeGetLabel(), makeConst(wasm::Literal(int32_t(value))));
}
wasm::Break* makeBreak(int id) {
return wasm::Builder::makeBreak(getBreakName(id));
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 368b483ad..3d98d0a67 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -32,28 +32,50 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
// flip branches to get rid of an i32.eqz
if (curr->ifFalse) {
auto condition = curr->condition->dynCast<Unary>();
- if (condition && condition->op == EqZ && condition->value->type == i32) {
+ if (condition && condition->op == EqZInt32 && condition->value->type == i32) {
curr->condition = condition->value;
std::swap(curr->ifTrue, curr->ifFalse);
}
}
}
void visitUnary(Unary* curr) {
- if (curr->op == EqZ) {
+ if (curr->op == EqZInt32) {
// fold comparisons that flow into an EqZ
auto* child = curr->value->dynCast<Binary>();
if (child && (child->type == i32 || child->type == i64)) {
switch (child->op) {
- case Eq: child->op = Ne; break;
- case Ne: child->op = Eq; break;
- case LtS: child->op = GeS; break;
- case LtU: child->op = GeU; break;
- case LeS: child->op = GtS; break;
- case LeU: child->op = GtU; break;
- case GtS: child->op = LeS; break;
- case GtU: child->op = LeU; break;
- case GeS: child->op = LtS; break;
- case GeU: child->op = LtU; break;
+ case EqInt32: child->op = NeInt32; break;
+ case NeInt32: child->op = EqInt32; break;
+ case LtSInt32: child->op = GeSInt32; break;
+ case LtUInt32: child->op = GeUInt32; break;
+ case LeSInt32: child->op = GtSInt32; break;
+ case LeUInt32: child->op = GtUInt32; break;
+ case GtSInt32: child->op = LeSInt32; break;
+ case GtUInt32: child->op = LeUInt32; break;
+ case GeSInt32: child->op = LtSInt32; break;
+ case GeUInt32: child->op = LtUInt32; break;
+ case EqInt64: child->op = NeInt64; break;
+ case NeInt64: child->op = EqInt64; break;
+ case LtSInt64: child->op = GeSInt64; break;
+ case LtUInt64: child->op = GeUInt64; break;
+ case LeSInt64: child->op = GtSInt64; break;
+ case LeUInt64: child->op = GtUInt64; break;
+ case GtSInt64: child->op = LeSInt64; break;
+ case GtUInt64: child->op = LeUInt64; break;
+ case GeSInt64: child->op = LtSInt64; break;
+ case GeUInt64: child->op = LtUInt64; break;
+ case EqFloat32: child->op = NeFloat32; break;
+ case NeFloat32: child->op = EqFloat32; break;
+ case LtFloat32: child->op = GeFloat32; break;
+ case LeFloat32: child->op = GtFloat32; break;
+ case GtFloat32: child->op = LeFloat32; break;
+ case GeFloat32: child->op = LtFloat32; break;
+ case EqFloat64: child->op = NeFloat64; break;
+ case NeFloat64: child->op = EqFloat64; break;
+ case LtFloat64: child->op = GeFloat64; break;
+ case LeFloat64: child->op = GtFloat64; break;
+ case GtFloat64: child->op = LeFloat64; break;
+ case GeFloat64: child->op = LtFloat64; break;
default: return;
}
replaceCurrent(child);
diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp
index 43fd1b2bc..4bd828a00 100644
--- a/src/passes/PostEmscripten.cpp
+++ b/src/passes/PostEmscripten.cpp
@@ -47,7 +47,7 @@ struct PostEmscripten : public WalkerPass<PostWalker<PostEmscripten, Visitor<Pos
if (curr->offset) return;
Expression* ptr = curr->ptr;
auto add = ptr->dynCast<Binary>();
- if (!add || add->op != Add) return;
+ if (!add || add->op != AddInt32) return;
assert(add->type == i32);
auto c = add->right->dynCast<Const>();
if (!c) {
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 121287846..04b1d0edb 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -283,44 +283,55 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitUnary(Unary *curr) {
o << '(';
- prepareColor(o) << printWasmType(curr->isRelational() ? curr->value->type : curr->type) << '.';
+ prepareColor(o);
switch (curr->op) {
- case Clz: o << "clz"; break;
- case Ctz: o << "ctz"; break;
- case Popcnt: o << "popcnt"; break;
- case EqZ: o << "eqz"; break;
- case Neg: o << "neg"; break;
- case Abs: o << "abs"; break;
- case Ceil: o << "ceil"; break;
- case Floor: o << "floor"; break;
- case Trunc: o << "trunc"; break;
- case Nearest: o << "nearest"; break;
- case Sqrt: o << "sqrt"; break;
- case ExtendSInt32: o << "extend_s/i32"; break;
- case ExtendUInt32: o << "extend_u/i32"; break;
- case WrapInt64: o << "wrap/i64"; break;
- case TruncSFloat32ToInt32:
- case TruncSFloat32ToInt64: o << "trunc_s/f32"; break;
- case TruncUFloat32ToInt32:
- case TruncUFloat32ToInt64: o << "trunc_u/f32"; break;
- case TruncSFloat64ToInt32:
- case TruncSFloat64ToInt64: o << "trunc_s/f64"; break;
- case TruncUFloat64ToInt32:
- case TruncUFloat64ToInt64: o << "trunc_u/f64"; break;
- case ReinterpretFloat32: o << "reinterpret/f32"; break;
- case ReinterpretFloat64: o << "reinterpret/f64"; break;
- case ConvertUInt32ToFloat32:
- case ConvertUInt32ToFloat64: o << "convert_u/i32"; break;
- case ConvertSInt32ToFloat32:
- case ConvertSInt32ToFloat64: o << "convert_s/i32"; break;
- case ConvertUInt64ToFloat32:
- case ConvertUInt64ToFloat64: o << "convert_u/i64"; break;
- case ConvertSInt64ToFloat32:
- case ConvertSInt64ToFloat64: o << "convert_s/i64"; break;
- case PromoteFloat32: o << "promote/f32"; break;
- case DemoteFloat64: o << "demote/f64"; break;
- case ReinterpretInt32: o << "reinterpret/i32"; break;
- case ReinterpretInt64: o << "reinterpret/i64"; break;
+ case ClzInt32: o << "i32.clz"; break;
+ case CtzInt32: o << "i32.ctz"; break;
+ case PopcntInt32: o << "i32.popcnt"; break;
+ case EqZInt32: o << "i32.eqz"; break;
+ case ClzInt64: o << "i64.clz"; break;
+ case CtzInt64: o << "i64.ctz"; break;
+ case PopcntInt64: o << "i64.popcnt"; break;
+ case EqZInt64: o << "i64.eqz"; break;
+ case NegFloat32: o << "f32.neg"; break;
+ case AbsFloat32: o << "f32.abs"; break;
+ case CeilFloat32: o << "f32.ceil"; break;
+ case FloorFloat32: o << "f32.floor"; break;
+ case TruncFloat32: o << "f32.trunc"; break;
+ case NearestFloat32: o << "f32.nearest"; break;
+ case SqrtFloat32: o << "f32.sqrt"; break;
+ case NegFloat64: o << "f64.neg"; break;
+ case AbsFloat64: o << "f64.abs"; break;
+ case CeilFloat64: o << "f64.ceil"; break;
+ case FloorFloat64: o << "f64.floor"; break;
+ case TruncFloat64: o << "f64.trunc"; break;
+ case NearestFloat64: o << "f64.nearest"; break;
+ case SqrtFloat64: o << "f64.sqrt"; break;
+ case ExtendSInt32: o << "i64.extend_s/i32"; break;
+ case ExtendUInt32: o << "i64.extend_u/i32"; break;
+ case WrapInt64: o << "i32.wrap/i64"; break;
+ case TruncSFloat32ToInt32: o << "i32.trunc_s/f32"; break;
+ case TruncSFloat32ToInt64: o << "i64.trunc_s/f32"; break;
+ case TruncUFloat32ToInt32: o << "i32.trunc_u/f32"; break;
+ case TruncUFloat32ToInt64: o << "i64.trunc_u/f32"; break;
+ case TruncSFloat64ToInt32: o << "i32.trunc_s/f64"; break;
+ case TruncSFloat64ToInt64: o << "i64.trunc_s/f64"; break;
+ case TruncUFloat64ToInt32: o << "i32.trunc_u/f64"; break;
+ case TruncUFloat64ToInt64: o << "i64.trunc_u/f64"; break;
+ case ReinterpretFloat32: o << "i32.reinterpret/f32"; break;
+ case ReinterpretFloat64: o << "i64.reinterpret/f64"; break;
+ case ConvertUInt32ToFloat32: o << "f32.convert_u/i32"; break;
+ case ConvertUInt32ToFloat64: o << "f64.convert_u/i32"; break;
+ case ConvertSInt32ToFloat32: o << "f32.convert_s/i32"; break;
+ case ConvertSInt32ToFloat64: o << "f64.convert_s/i32"; break;
+ case ConvertUInt64ToFloat32: o << "f32.convert_u/i64"; break;
+ case ConvertUInt64ToFloat64: o << "f64.convert_u/i64"; break;
+ case ConvertSInt64ToFloat32: o << "f32.convert_s/i64"; break;
+ case ConvertSInt64ToFloat64: o << "f64.convert_s/i64"; break;
+ case PromoteFloat32: o << "f64.promote/f32"; break;
+ case DemoteFloat64: o << "f32.demote/f64"; break;
+ case ReinterpretInt32: o << "f32.reinterpret/i32"; break;
+ case ReinterpretInt64: o << "f64.reinterpret/i64"; break;
default: abort();
}
incIndent();
@@ -329,41 +340,88 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
void visitBinary(Binary *curr) {
o << '(';
- prepareColor(o) << printWasmType(curr->isRelational() ? curr->left->type : curr->type) << '.';
+ prepareColor(o);
switch (curr->op) {
- case Add: o << "add"; break;
- case Sub: o << "sub"; break;
- case Mul: o << "mul"; break;
- case DivS: o << "div_s"; break;
- case DivU: o << "div_u"; break;
- case RemS: o << "rem_s"; break;
- case RemU: o << "rem_u"; break;
- case And: o << "and"; break;
- case Or: o << "or"; break;
- case Xor: o << "xor"; break;
- case Shl: o << "shl"; break;
- case ShrU: o << "shr_u"; break;
- case ShrS: o << "shr_s"; break;
- case RotL: o << "rotl"; break;
- case RotR: o << "rotr"; break;
- case Div: o << "div"; break;
- case CopySign: o << "copysign"; break;
- case Min: o << "min"; break;
- case Max: o << "max"; break;
- case Eq: o << "eq"; break;
- case Ne: o << "ne"; break;
- case LtS: o << "lt_s"; break;
- case LtU: o << "lt_u"; break;
- case LeS: o << "le_s"; break;
- case LeU: o << "le_u"; break;
- case GtS: o << "gt_s"; break;
- case GtU: o << "gt_u"; break;
- case GeS: o << "ge_s"; break;
- case GeU: o << "ge_u"; break;
- case Lt: o << "lt"; break;
- case Le: o << "le"; break;
- case Gt: o << "gt"; break;
- case Ge: o << "ge"; break;
+ case AddInt32: o << "i32.add"; break;
+ case SubInt32: o << "i32.sub"; break;
+ case MulInt32: o << "i32.mul"; break;
+ case DivSInt32: o << "i32.div_s"; break;
+ case DivUInt32: o << "i32.div_u"; break;
+ case RemSInt32: o << "i32.rem_s"; break;
+ case RemUInt32: o << "i32.rem_u"; break;
+ case AndInt32: o << "i32.and"; break;
+ case OrInt32: o << "i32.or"; break;
+ case XorInt32: o << "i32.xor"; break;
+ case ShlInt32: o << "i32.shl"; break;
+ case ShrUInt32: o << "i32.shr_u"; break;
+ case ShrSInt32: o << "i32.shr_s"; break;
+ case RotLInt32: o << "i32.rotl"; break;
+ case RotRInt32: o << "i32.rotr"; break;
+ case EqInt32: o << "i32.eq"; break;
+ case NeInt32: o << "i32.ne"; break;
+ case LtSInt32: o << "i32.lt_s"; break;
+ case LtUInt32: o << "i32.lt_u"; break;
+ case LeSInt32: o << "i32.le_s"; break;
+ case LeUInt32: o << "i32.le_u"; break;
+ case GtSInt32: o << "i32.gt_s"; break;
+ case GtUInt32: o << "i32.gt_u"; break;
+ case GeSInt32: o << "i32.ge_s"; break;
+ case GeUInt32: o << "i32.ge_u"; break;
+
+ case AddInt64: o << "i64.add"; break;
+ case SubInt64: o << "i64.sub"; break;
+ case MulInt64: o << "i64.mul"; break;
+ case DivSInt64: o << "i64.div_s"; break;
+ case DivUInt64: o << "i64.div_u"; break;
+ case RemSInt64: o << "i64.rem_s"; break;
+ case RemUInt64: o << "i64.rem_u"; break;
+ case AndInt64: o << "i64.and"; break;
+ case OrInt64: o << "i64.or"; break;
+ case XorInt64: o << "i64.xor"; break;
+ case ShlInt64: o << "i64.shl"; break;
+ case ShrUInt64: o << "i64.shr_u"; break;
+ case ShrSInt64: o << "i64.shr_s"; break;
+ case RotLInt64: o << "i64.rotl"; break;
+ case RotRInt64: o << "i64.rotr"; break;
+ case EqInt64: o << "i64.eq"; break;
+ case NeInt64: o << "i64.ne"; break;
+ case LtSInt64: o << "i64.lt_s"; break;
+ case LtUInt64: o << "i64.lt_u"; break;
+ case LeSInt64: o << "i64.le_s"; break;
+ case LeUInt64: o << "i64.le_u"; break;
+ case GtSInt64: o << "i64.gt_s"; break;
+ case GtUInt64: o << "i64.gt_u"; break;
+ case GeSInt64: o << "i64.ge_s"; break;
+ case GeUInt64: o << "i64.ge_u"; break;
+
+ case AddFloat32: o << "f32.add"; break;
+ case SubFloat32: o << "f32.sub"; break;
+ case MulFloat32: o << "f32.mul"; break;
+ case DivFloat32: o << "f32.div"; break;
+ case CopySignFloat32: o << "f32.copysign"; break;
+ case MinFloat32: o << "f32.min"; break;
+ case MaxFloat32: o << "f32.max"; break;
+ case EqFloat32: o << "f32.eq"; break;
+ case NeFloat32: o << "f32.ne"; break;
+ case LtFloat32: o << "f32.lt"; break;
+ case LeFloat32: o << "f32.le"; break;
+ case GtFloat32: o << "f32.gt"; break;
+ case GeFloat32: o << "f32.ge"; break;
+
+ case AddFloat64: o << "f64.add"; break;
+ case SubFloat64: o << "f64.sub"; break;
+ case MulFloat64: o << "f64.mul"; break;
+ case DivFloat64: o << "f64.div"; break;
+ case CopySignFloat64: o << "f64.copysign"; break;
+ case MinFloat64: o << "f64.min"; break;
+ case MaxFloat64: o << "f64.max"; break;
+ case EqFloat64: o << "f64.eq"; break;
+ case NeFloat64: o << "f64.ne"; break;
+ case LtFloat64: o << "f64.lt"; break;
+ case LeFloat64: o << "f64.le"; break;
+ case GtFloat64: o << "f64.gt"; break;
+ case GeFloat64: o << "f64.ge"; break;
+
default: abort();
}
restoreNormalColor(o);
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index 10d04f160..458ce63ca 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -81,7 +81,7 @@ struct Vacuum : public WalkerPass<PostWalker<Vacuum, Visitor<Vacuum>>> {
} else if (curr->ifTrue->is<Nop>()) {
curr->ifTrue = curr->ifFalse;
curr->ifFalse = nullptr;
- curr->condition = Builder(*getModule()).makeUnary(EqZ, curr->condition);
+ curr->condition = Builder(*getModule()).makeUnary(EqZInt32, curr->condition);
}
}
if (!curr->ifFalse) {
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 54d36011f..082cbed1a 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -529,7 +529,6 @@ class S2WasmBuilder {
last = last->cast<Loop>()->body;
}
last->cast<Block>()->list.push_back(curr);
- last->cast<Block>()->finalize();
};
bstack.push_back(func->body);
std::vector<Expression*> estack;
@@ -635,7 +634,7 @@ class S2WasmBuilder {
auto curr = allocator->alloc<Unary>();
curr->op = op;
curr->value = getInput();
- curr->type = type;
+ curr->finalize();
setOutput(curr, assign);
};
auto makeHost = [&](HostOp op) {
@@ -740,12 +739,15 @@ class S2WasmBuilder {
setOutput(curr, assign);
}
};
+ #define BINARY_INT_OR_FLOAT(op) (type == i32 ? BinaryOp::op##Int32 : (type == i64 ? BinaryOp::op##Int64 : (type == f32 ? BinaryOp::op##Float32 : BinaryOp::op##Float64)))
+ #define BINARY_INT(op) (type == i32 ? BinaryOp::op##Int32 : BinaryOp::op##Int64)
+ #define BINARY_FLOAT(op) (type == f32 ? BinaryOp::op##Float32 : BinaryOp::op##Float64)
auto handleTyped = [&](WasmType type) {
switch (*s) {
case 'a': {
- if (match("add")) makeBinary(BinaryOp::Add, type);
- else if (match("and")) makeBinary(BinaryOp::And, type);
- else if (match("abs")) makeUnary(UnaryOp::Abs, type);
+ if (match("add")) makeBinary(BINARY_INT_OR_FLOAT(Add), type);
+ else if (match("and")) makeBinary(BINARY_INT(And), type);
+ else if (match("abs")) makeUnary(type == f32 ? UnaryOp::AbsFloat32 : UnaryOp::AbsFloat64, type);
else abort_on("type.a");
break;
}
@@ -768,100 +770,100 @@ class S2WasmBuilder {
else if (match("convert_u/i32")) makeUnary(type == f32 ? UnaryOp::ConvertUInt32ToFloat32 : UnaryOp::ConvertUInt32ToFloat64, type);
else if (match("convert_s/i64")) makeUnary(type == f32 ? UnaryOp::ConvertSInt64ToFloat32 : UnaryOp::ConvertSInt64ToFloat64, type);
else if (match("convert_u/i64")) makeUnary(type == f32 ? UnaryOp::ConvertUInt64ToFloat32 : UnaryOp::ConvertUInt64ToFloat64, type);
- else if (match("clz")) makeUnary(UnaryOp::Clz, type);
- else if (match("ctz")) makeUnary(UnaryOp::Ctz, type);
- else if (match("copysign")) makeBinary(BinaryOp::CopySign, type);
- else if (match("ceil")) makeUnary(UnaryOp::Ceil, type);
+ else if (match("clz")) makeUnary(type == i32 ? UnaryOp::ClzInt32 : UnaryOp::ClzInt64, type);
+ else if (match("ctz")) makeUnary(type == i32 ? UnaryOp::CtzInt32 : UnaryOp::CtzInt64, type);
+ else if (match("copysign")) makeBinary(BINARY_FLOAT(CopySign), type);
+ else if (match("ceil")) makeUnary(type == f32 ? UnaryOp::CeilFloat32 : UnaryOp::CeilFloat64, type);
else abort_on("type.c");
break;
}
case 'd': {
if (match("demote/f64")) makeUnary(UnaryOp::DemoteFloat64, type);
- else if (match("div_s")) makeBinary(BinaryOp::DivS, type);
- else if (match("div_u")) makeBinary(BinaryOp::DivU, type);
- else if (match("div")) makeBinary(BinaryOp::Div, type);
+ else if (match("div_s")) makeBinary(BINARY_INT(DivS), type);
+ else if (match("div_u")) makeBinary(BINARY_INT(DivU), type);
+ else if (match("div")) makeBinary(BINARY_FLOAT(Div), type);
else abort_on("type.g");
break;
}
case 'e': {
- if (match("eqz")) makeUnary(UnaryOp::EqZ, i32);
- else if (match("eq")) makeBinary(BinaryOp::Eq, i32);
+ if (match("eqz")) makeUnary(type == i32 ? UnaryOp::EqZInt32 : UnaryOp::EqZInt64, type);
+ else if (match("eq")) makeBinary(BINARY_INT_OR_FLOAT(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");
break;
}
case 'f': {
- if (match("floor")) makeUnary(UnaryOp::Floor, type);
+ if (match("floor")) makeUnary(type == f32 ? UnaryOp::FloorFloat32 : UnaryOp::FloorFloat64, type);
else abort_on("type.e");
break;
}
case 'g': {
- if (match("gt_s")) makeBinary(BinaryOp::GtS, i32);
- else if (match("gt_u")) makeBinary(BinaryOp::GtU, i32);
- else if (match("ge_s")) makeBinary(BinaryOp::GeS, i32);
- else if (match("ge_u")) makeBinary(BinaryOp::GeU, i32);
- else if (match("gt")) makeBinary(BinaryOp::Gt, i32);
- else if (match("ge")) makeBinary(BinaryOp::Ge, i32);
+ if (match("gt_s")) makeBinary(BINARY_INT(GtS), i32);
+ else if (match("gt_u")) makeBinary(BINARY_INT(GtU), i32);
+ else if (match("ge_s")) makeBinary(BINARY_INT(GeS), i32);
+ else if (match("ge_u")) makeBinary(BINARY_INT(GeU), i32);
+ else if (match("gt")) makeBinary(BINARY_FLOAT(Gt), i32);
+ else if (match("ge")) makeBinary(BINARY_FLOAT(Ge), i32);
else abort_on("type.g");
break;
}
case 'l': {
- if (match("lt_s")) makeBinary(BinaryOp::LtS, i32);
- else if (match("lt_u")) makeBinary(BinaryOp::LtU, i32);
- else if (match("le_s")) makeBinary(BinaryOp::LeS, i32);
- else if (match("le_u")) makeBinary(BinaryOp::LeU, i32);
+ if (match("lt_s")) makeBinary(BINARY_INT(LtS), i32);
+ else if (match("lt_u")) makeBinary(BINARY_INT(LtU), i32);
+ else if (match("le_s")) makeBinary(BINARY_INT(LeS), i32);
+ else if (match("le_u")) makeBinary(BINARY_INT(LeU), i32);
else if (match("load")) makeLoad(type);
- else if (match("lt")) makeBinary(BinaryOp::Lt, i32);
- else if (match("le")) makeBinary(BinaryOp::Le, i32);
+ else if (match("lt")) makeBinary(BINARY_FLOAT(Lt), i32);
+ else if (match("le")) makeBinary(BINARY_FLOAT(Le), i32);
else abort_on("type.g");
break;
}
case 'm': {
- if (match("mul")) makeBinary(BinaryOp::Mul, type);
- else if (match("min")) makeBinary(BinaryOp::Min, type);
- else if (match("max")) makeBinary(BinaryOp::Max, type);
+ if (match("mul")) makeBinary(BINARY_INT_OR_FLOAT(Mul), type);
+ else if (match("min")) makeBinary(BINARY_FLOAT(Min), type);
+ else if (match("max")) makeBinary(BINARY_FLOAT(Max), type);
else abort_on("type.m");
break;
}
case 'n': {
- if (match("neg")) makeUnary(UnaryOp::Neg, type);
- else if (match("nearest")) makeUnary(UnaryOp::Nearest, type);
- else if (match("ne")) makeBinary(BinaryOp::Ne, i32);
+ if (match("neg")) makeUnary(type == f32 ? UnaryOp::NegFloat32 : UnaryOp::NegFloat64, type);
+ else if (match("nearest")) makeUnary(type == f32 ? UnaryOp::NearestFloat32 : UnaryOp::NearestFloat64, type);
+ else if (match("ne")) makeBinary(BINARY_INT_OR_FLOAT(Ne), i32);
else abort_on("type.n");
break;
}
case 'o': {
- if (match("or")) makeBinary(BinaryOp::Or, type);
+ if (match("or")) makeBinary(BINARY_INT(Or), type);
else abort_on("type.o");
break;
}
case 'p': {
if (match("promote/f32")) makeUnary(UnaryOp::PromoteFloat32, type);
- else if (match("popcnt")) makeUnary(UnaryOp::Popcnt, type);
+ else if (match("popcnt")) makeUnary(type == i32 ? UnaryOp::PopcntInt32 : UnaryOp::PopcntInt64, type);
else abort_on("type.p");
break;
}
case 'r': {
- if (match("rem_s")) makeBinary(BinaryOp::RemS, type);
- else if (match("rem_u")) makeBinary(BinaryOp::RemU, type);
+ if (match("rem_s")) makeBinary(BINARY_INT(RemS), type);
+ else if (match("rem_u")) makeBinary(BINARY_INT(RemU), type);
else if (match("reinterpret/i32")) makeUnary(UnaryOp::ReinterpretInt32, type);
else if (match("reinterpret/i64")) makeUnary(UnaryOp::ReinterpretInt64, type);
else if (match("reinterpret/f32")) makeUnary(UnaryOp::ReinterpretFloat32, type);
else if (match("reinterpret/f64")) makeUnary(UnaryOp::ReinterpretFloat64, type);
- else if (match("rotl")) makeBinary(BinaryOp::RotL, type);
- else if (match("rotr")) makeBinary(BinaryOp::RotR, type);
+ else if (match("rotl")) makeBinary(BINARY_INT(RotL), type);
+ else if (match("rotr")) makeBinary(BINARY_INT(RotR), type);
else abort_on("type.r");
break;
}
case 's': {
- if (match("shr_s")) makeBinary(BinaryOp::ShrS, type);
- else if (match("shr_u")) makeBinary(BinaryOp::ShrU, type);
- else if (match("shl")) makeBinary(BinaryOp::Shl, type);
- else if (match("sub")) makeBinary(BinaryOp::Sub, type);
+ if (match("shr_s")) makeBinary(BINARY_INT(ShrS), type);
+ else if (match("shr_u")) makeBinary(BINARY_INT(ShrU), type);
+ else if (match("shl")) makeBinary(BINARY_INT(Shl), type);
+ else if (match("sub")) makeBinary(BINARY_INT_OR_FLOAT(Sub), type);
else if (match("store")) makeStore(type);
else if (match("select")) makeSelect(type);
- else if (match("sqrt")) makeUnary(UnaryOp::Sqrt, type);
+ else if (match("sqrt")) makeUnary(type == f32 ? UnaryOp::SqrtFloat32 : UnaryOp::SqrtFloat64, type);
else abort_on("type.s");
break;
}
@@ -870,7 +872,7 @@ class S2WasmBuilder {
else if (match("trunc_u/f32")) makeUnary(type == i32 ? UnaryOp::TruncUFloat32ToInt32 : UnaryOp::TruncUFloat32ToInt64, type);
else if (match("trunc_s/f64")) makeUnary(type == i32 ? UnaryOp::TruncSFloat64ToInt32 : UnaryOp::TruncSFloat64ToInt64, type);
else if (match("trunc_u/f64")) makeUnary(type == i32 ? UnaryOp::TruncUFloat64ToInt32 : UnaryOp::TruncUFloat64ToInt64, type);
- else if (match("trunc")) makeUnary(UnaryOp::Trunc, type);
+ else if (match("trunc")) makeUnary(type == f32 ? UnaryOp::TruncFloat32 : UnaryOp::TruncFloat64, type);
else abort_on("type.t");
break;
}
@@ -880,7 +882,7 @@ class S2WasmBuilder {
break;
}
case 'x': {
- if (match("xor")) makeBinary(BinaryOp::Xor, type);
+ if (match("xor")) makeBinary(BINARY_INT(Xor), type);
else abort_on("type.x");
break;
}
@@ -921,6 +923,7 @@ class S2WasmBuilder {
addToBlock(curr);
bstack.push_back(curr);
} else if (match("end_block")) {
+ bstack.back()->cast<Block>()->finalize();
bstack.pop_back();
} else if (match(".LBB")) {
s = strchr(s, '\n');
@@ -996,6 +999,7 @@ class S2WasmBuilder {
}
}
// finishing touches
+ bstack.back()->cast<Block>()->finalize();
bstack.pop_back(); // remove the base block for the function body
assert(bstack.empty());
assert(estack.empty());
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 795e89d98..9f061db47 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1011,17 +1011,28 @@ public:
if (debug) std::cerr << "zz node: Unary" << std::endl;
recurse(curr->value);
switch (curr->op) {
- case Clz: o << int8_t(curr->type == i32 ? BinaryConsts::I32Clz : BinaryConsts::I64Clz); break;
- case Ctz: o << int8_t(curr->type == i32 ? BinaryConsts::I32Ctz : BinaryConsts::I64Ctz); break;
- case Popcnt: o << int8_t(curr->type == i32 ? BinaryConsts::I32Popcnt : BinaryConsts::I64Popcnt); break;
- case EqZ: o << int8_t(curr->type == i32 ? BinaryConsts::I32EqZ : BinaryConsts::I64EqZ); break;
- case Neg: o << int8_t(curr->type == f32 ? BinaryConsts::F32Neg : BinaryConsts::F64Neg); break;
- case Abs: o << int8_t(curr->type == f32 ? BinaryConsts::F32Abs : BinaryConsts::F64Abs); break;
- case Ceil: o << int8_t(curr->type == f32 ? BinaryConsts::F32Ceil : BinaryConsts::F64Ceil); break;
- case Floor: o << int8_t(curr->type == f32 ? BinaryConsts::F32Floor : BinaryConsts::F64Floor); break;
- case Trunc: o << int8_t(curr->type == f32 ? BinaryConsts::F32Trunc : BinaryConsts::F64Trunc); break;
- case Nearest: o << int8_t(curr->type == f32 ? BinaryConsts::F32NearestInt : BinaryConsts::F64NearestInt); break;
- case Sqrt: o << int8_t(curr->type == f32 ? BinaryConsts::F32Sqrt : BinaryConsts::F64Sqrt); break;
+ case ClzInt32: o << int8_t(BinaryConsts::I32Clz); break;
+ case CtzInt32: o << int8_t(BinaryConsts::I32Ctz); break;
+ case PopcntInt32: o << int8_t(BinaryConsts::I32Popcnt); break;
+ case EqZInt32: o << int8_t(BinaryConsts::I32EqZ); break;
+ case ClzInt64: o << int8_t(BinaryConsts::I64Clz); break;
+ case CtzInt64: o << int8_t(BinaryConsts::I64Ctz); break;
+ case PopcntInt64: o << int8_t(BinaryConsts::I64Popcnt); break;
+ case EqZInt64: o << int8_t(BinaryConsts::I64EqZ); break;
+ case NegFloat32: o << int8_t(BinaryConsts::F32Neg); break;
+ case AbsFloat32: o << int8_t(BinaryConsts::F32Abs); break;
+ case CeilFloat32: o << int8_t(BinaryConsts::F32Ceil); break;
+ case FloorFloat32: o << int8_t(BinaryConsts::F32Floor); break;
+ case TruncFloat32: o << int8_t(BinaryConsts::F32Trunc); break;
+ case NearestFloat32: o << int8_t(BinaryConsts::F32NearestInt); break;
+ case SqrtFloat32: o << int8_t(BinaryConsts::F32Sqrt); break;
+ case NegFloat64: o << int8_t(BinaryConsts::F64Neg); break;
+ case AbsFloat64: o << int8_t(BinaryConsts::F64Abs); break;
+ case CeilFloat64: o << int8_t(BinaryConsts::F64Ceil); break;
+ case FloorFloat64: o << int8_t(BinaryConsts::F64Floor); break;
+ case TruncFloat64: o << int8_t(BinaryConsts::F64Trunc); break;
+ case NearestFloat64: o << int8_t(BinaryConsts::F64NearestInt); break;
+ case SqrtFloat64: o << int8_t(BinaryConsts::F64Sqrt); break;
case ExtendSInt32: o << int8_t(BinaryConsts::I64STruncI32); break;
case ExtendUInt32: o << int8_t(BinaryConsts::I64UTruncI32); break;
case WrapInt64: o << int8_t(BinaryConsts::I32ConvertI64); break;
@@ -1054,72 +1065,89 @@ public:
if (debug) std::cerr << "zz node: Binary" << std::endl;
recurse(curr->left);
recurse(curr->right);
- #define TYPED_CODE(code) { \
- switch (getReachableWasmType(curr->left->type, curr->right->type)) { \
- case i32: o << int8_t(BinaryConsts::I32##code); break; \
- case i64: o << int8_t(BinaryConsts::I64##code); break; \
- case f32: o << int8_t(BinaryConsts::F32##code); break; \
- case f64: o << int8_t(BinaryConsts::F64##code); break; \
- default: abort(); \
- } \
- break; \
- }
- #define INT_TYPED_CODE(code) { \
- switch (getReachableWasmType(curr->left->type, curr->right->type)) { \
- case i32: o << int8_t(BinaryConsts::I32##code); break; \
- case i64: o << int8_t(BinaryConsts::I64##code); break; \
- default: abort(); \
- } \
- break; \
- }
- #define FLOAT_TYPED_CODE(code) { \
- switch (getReachableWasmType(curr->left->type, curr->right->type)) { \
- case f32: o << int8_t(BinaryConsts::F32##code); break; \
- case f64: o << int8_t(BinaryConsts::F64##code); break; \
- default: abort(); \
- } \
- break; \
- }
switch (curr->op) {
- case Add: TYPED_CODE(Add);
- case Sub: TYPED_CODE(Sub);
- case Mul: TYPED_CODE(Mul);
- case DivS: INT_TYPED_CODE(DivS);
- case DivU: INT_TYPED_CODE(DivU);
- case RemS: INT_TYPED_CODE(RemS);
- case RemU: INT_TYPED_CODE(RemU);
- case And: INT_TYPED_CODE(And);
- case Or: INT_TYPED_CODE(Or);
- case Xor: INT_TYPED_CODE(Xor);
- case Shl: INT_TYPED_CODE(Shl);;
- case ShrU: INT_TYPED_CODE(ShrU);
- case ShrS: INT_TYPED_CODE(ShrS);
- case RotL: INT_TYPED_CODE(RotL);
- case RotR: INT_TYPED_CODE(RotR);
- case Div: FLOAT_TYPED_CODE(Div);
- case CopySign: FLOAT_TYPED_CODE(CopySign);
- case Min: FLOAT_TYPED_CODE(Min);
- case Max: FLOAT_TYPED_CODE(Max);
- case Eq: TYPED_CODE(Eq);
- case Ne: TYPED_CODE(Ne);
- case LtS: INT_TYPED_CODE(LtS);
- case LtU: INT_TYPED_CODE(LtU);
- case LeS: INT_TYPED_CODE(LeS);
- case LeU: INT_TYPED_CODE(LeU);
- case GtS: INT_TYPED_CODE(GtS);
- case GtU: INT_TYPED_CODE(GtU);
- case GeS: INT_TYPED_CODE(GeS);
- case GeU: INT_TYPED_CODE(GeU);
- case Lt: FLOAT_TYPED_CODE(Lt);
- case Le: FLOAT_TYPED_CODE(Le);
- case Gt: FLOAT_TYPED_CODE(Gt);
- case Ge: FLOAT_TYPED_CODE(Ge);
- default: abort();
+ case AddInt32: o << int8_t(BinaryConsts::I32Add); break;
+ case SubInt32: o << int8_t(BinaryConsts::I32Sub); break;
+ case MulInt32: o << int8_t(BinaryConsts::I32Mul); break;
+ case DivSInt32: o << int8_t(BinaryConsts::I32DivS); break;
+ case DivUInt32: o << int8_t(BinaryConsts::I32DivU); break;
+ case RemSInt32: o << int8_t(BinaryConsts::I32RemS); break;
+ case RemUInt32: o << int8_t(BinaryConsts::I32RemU); break;
+ case AndInt32: o << int8_t(BinaryConsts::I32And); break;
+ case OrInt32: o << int8_t(BinaryConsts::I32Or); break;
+ case XorInt32: o << int8_t(BinaryConsts::I32Xor); break;
+ case ShlInt32: o << int8_t(BinaryConsts::I32Shl); break;
+ case ShrUInt32: o << int8_t(BinaryConsts::I32ShrU); break;
+ case ShrSInt32: o << int8_t(BinaryConsts::I32ShrS); break;
+ case RotLInt32: o << int8_t(BinaryConsts::I32RotL); break;
+ case RotRInt32: o << int8_t(BinaryConsts::I32RotR); break;
+ case EqInt32: o << int8_t(BinaryConsts::I32Eq); break;
+ case NeInt32: o << int8_t(BinaryConsts::I32Ne); break;
+ case LtSInt32: o << int8_t(BinaryConsts::I32LtS); break;
+ case LtUInt32: o << int8_t(BinaryConsts::I32LtU); break;
+ case LeSInt32: o << int8_t(BinaryConsts::I32LeS); break;
+ case LeUInt32: o << int8_t(BinaryConsts::I32LeU); break;
+ case GtSInt32: o << int8_t(BinaryConsts::I32GtS); break;
+ case GtUInt32: o << int8_t(BinaryConsts::I32GtU); break;
+ case GeSInt32: o << int8_t(BinaryConsts::I32GeS); break;
+ case GeUInt32: o << int8_t(BinaryConsts::I32GeU); break;
+
+ case AddInt64: o << int8_t(BinaryConsts::I64Add); break;
+ case SubInt64: o << int8_t(BinaryConsts::I64Sub); break;
+ case MulInt64: o << int8_t(BinaryConsts::I64Mul); break;
+ case DivSInt64: o << int8_t(BinaryConsts::I64DivS); break;
+ case DivUInt64: o << int8_t(BinaryConsts::I64DivU); break;
+ case RemSInt64: o << int8_t(BinaryConsts::I64RemS); break;
+ case RemUInt64: o << int8_t(BinaryConsts::I64RemU); break;
+ case AndInt64: o << int8_t(BinaryConsts::I64And); break;
+ case OrInt64: o << int8_t(BinaryConsts::I64Or); break;
+ case XorInt64: o << int8_t(BinaryConsts::I64Xor); break;
+ case ShlInt64: o << int8_t(BinaryConsts::I64Shl); break;
+ case ShrUInt64: o << int8_t(BinaryConsts::I64ShrU); break;
+ case ShrSInt64: o << int8_t(BinaryConsts::I64ShrS); break;
+ case RotLInt64: o << int8_t(BinaryConsts::I64RotL); break;
+ case RotRInt64: o << int8_t(BinaryConsts::I64RotR); break;
+ case EqInt64: o << int8_t(BinaryConsts::I64Eq); break;
+ case NeInt64: o << int8_t(BinaryConsts::I64Ne); break;
+ case LtSInt64: o << int8_t(BinaryConsts::I64LtS); break;
+ case LtUInt64: o << int8_t(BinaryConsts::I64LtU); break;
+ case LeSInt64: o << int8_t(BinaryConsts::I64LeS); break;
+ case LeUInt64: o << int8_t(BinaryConsts::I64LeU); break;
+ case GtSInt64: o << int8_t(BinaryConsts::I64GtS); break;
+ case GtUInt64: o << int8_t(BinaryConsts::I64GtU); break;
+ case GeSInt64: o << int8_t(BinaryConsts::I64GeS); break;
+ case GeUInt64: o << int8_t(BinaryConsts::I64GeU); break;
+
+ case AddFloat32: o << int8_t(BinaryConsts::F32Add); break;
+ case SubFloat32: o << int8_t(BinaryConsts::F32Sub); break;
+ case MulFloat32: o << int8_t(BinaryConsts::F32Mul); break;
+ case DivFloat32: o << int8_t(BinaryConsts::F32Div); break;
+ case CopySignFloat32: o << int8_t(BinaryConsts::F32CopySign);break;
+ case MinFloat32: o << int8_t(BinaryConsts::F32Min); break;
+ case MaxFloat32: o << int8_t(BinaryConsts::F32Max); break;
+ case EqFloat32: o << int8_t(BinaryConsts::F32Eq); break;
+ case NeFloat32: o << int8_t(BinaryConsts::F32Ne); break;
+ case LtFloat32: o << int8_t(BinaryConsts::F32Lt); break;
+ case LeFloat32: o << int8_t(BinaryConsts::F32Le); break;
+ case GtFloat32: o << int8_t(BinaryConsts::F32Gt); break;
+ case GeFloat32: o << int8_t(BinaryConsts::F32Ge); break;
+
+ case AddFloat64: o << int8_t(BinaryConsts::F64Add); break;
+ case SubFloat64: o << int8_t(BinaryConsts::F64Sub); break;
+ case MulFloat64: o << int8_t(BinaryConsts::F64Mul); break;
+ case DivFloat64: o << int8_t(BinaryConsts::F64Div); break;
+ case CopySignFloat64: o << int8_t(BinaryConsts::F64CopySign);break;
+ case MinFloat64: o << int8_t(BinaryConsts::F64Min); break;
+ case MaxFloat64: o << int8_t(BinaryConsts::F64Max); break;
+ case EqFloat64: o << int8_t(BinaryConsts::F64Eq); break;
+ case NeFloat64: o << int8_t(BinaryConsts::F64Ne); break;
+ case LtFloat64: o << int8_t(BinaryConsts::F64Lt); break;
+ case LeFloat64: o << int8_t(BinaryConsts::F64Le); break;
+ case GtFloat64: o << int8_t(BinaryConsts::F64Gt); break;
+ case GeFloat64: o << int8_t(BinaryConsts::F64Ge); break;
+ default: abort();
}
- #undef TYPED_CODE
- #undef INT_TYPED_CODE
- #undef FLOAT_TYPED_CODE
}
void visitSelect(Select *curr) {
if (debug) std::cerr << "zz node: Select" << std::endl;
@@ -1896,26 +1924,26 @@ public:
bool maybeVisitUnary(Expression*& out, uint8_t code) {
Unary* curr;
switch (code) {
- case BinaryConsts::I32Clz: curr = allocator.alloc<Unary>(); curr->op = Clz; curr->type = i32; break;
- case BinaryConsts::I64Clz: curr = allocator.alloc<Unary>(); curr->op = Clz; curr->type = i64; break;
- case BinaryConsts::I32Ctz: curr = allocator.alloc<Unary>(); curr->op = Ctz; curr->type = i32; break;
- case BinaryConsts::I64Ctz: curr = allocator.alloc<Unary>(); curr->op = Ctz; curr->type = i64; break;
- case BinaryConsts::I32Popcnt: curr = allocator.alloc<Unary>(); curr->op = Popcnt; curr->type = i32; break;
- case BinaryConsts::I64Popcnt: curr = allocator.alloc<Unary>(); curr->op = Popcnt; curr->type = i64; break;
- case BinaryConsts::I32EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZ; curr->type = i32; break;
- case BinaryConsts::I64EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZ; curr->type = i64; break;
- case BinaryConsts::F32Neg: curr = allocator.alloc<Unary>(); curr->op = Neg; curr->type = f32; break;
- case BinaryConsts::F64Neg: curr = allocator.alloc<Unary>(); curr->op = Neg; curr->type = f64; break;
- case BinaryConsts::F32Abs: curr = allocator.alloc<Unary>(); curr->op = Abs; curr->type = f32; break;
- case BinaryConsts::F64Abs: curr = allocator.alloc<Unary>(); curr->op = Abs; curr->type = f64; break;
- case BinaryConsts::F32Ceil: curr = allocator.alloc<Unary>(); curr->op = Ceil; curr->type = f32; break;
- case BinaryConsts::F64Ceil: curr = allocator.alloc<Unary>(); curr->op = Ceil; curr->type = f64; break;
- case BinaryConsts::F32Floor: curr = allocator.alloc<Unary>(); curr->op = Floor; curr->type = f32; break;
- case BinaryConsts::F64Floor: curr = allocator.alloc<Unary>(); curr->op = Floor; curr->type = f64; break;
- case BinaryConsts::F32NearestInt: curr = allocator.alloc<Unary>(); curr->op = Nearest; curr->type = f32; break;
- case BinaryConsts::F64NearestInt: curr = allocator.alloc<Unary>(); curr->op = Nearest; curr->type = f64; break;
- case BinaryConsts::F32Sqrt: curr = allocator.alloc<Unary>(); curr->op = Sqrt; curr->type = f32; break;
- case BinaryConsts::F64Sqrt: curr = allocator.alloc<Unary>(); curr->op = Sqrt; curr->type = f64; break;
+ case BinaryConsts::I32Clz: curr = allocator.alloc<Unary>(); curr->op = ClzInt32; curr->type = i32; break;
+ case BinaryConsts::I64Clz: curr = allocator.alloc<Unary>(); curr->op = ClzInt64; curr->type = i64; break;
+ case BinaryConsts::I32Ctz: curr = allocator.alloc<Unary>(); curr->op = CtzInt32; curr->type = i32; break;
+ case BinaryConsts::I64Ctz: curr = allocator.alloc<Unary>(); curr->op = CtzInt64; curr->type = i64; break;
+ case BinaryConsts::I32Popcnt: curr = allocator.alloc<Unary>(); curr->op = PopcntInt32; curr->type = i32; break;
+ case BinaryConsts::I64Popcnt: curr = allocator.alloc<Unary>(); curr->op = PopcntInt64; curr->type = i64; break;
+ case BinaryConsts::I32EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZInt32; curr->type = i32; break;
+ case BinaryConsts::I64EqZ: curr = allocator.alloc<Unary>(); curr->op = EqZInt64; curr->type = i32; break;
+ case BinaryConsts::F32Neg: curr = allocator.alloc<Unary>(); curr->op = NegFloat32; curr->type = f32; break;
+ case BinaryConsts::F64Neg: curr = allocator.alloc<Unary>(); curr->op = NegFloat64; curr->type = f64; break;
+ case BinaryConsts::F32Abs: curr = allocator.alloc<Unary>(); curr->op = AbsFloat32; curr->type = f32; break;
+ case BinaryConsts::F64Abs: curr = allocator.alloc<Unary>(); curr->op = AbsFloat64; curr->type = f64; break;
+ case BinaryConsts::F32Ceil: curr = allocator.alloc<Unary>(); curr->op = CeilFloat32; curr->type = f32; break;
+ case BinaryConsts::F64Ceil: curr = allocator.alloc<Unary>(); curr->op = CeilFloat64; curr->type = f64; break;
+ case BinaryConsts::F32Floor: curr = allocator.alloc<Unary>(); curr->op = FloorFloat32; curr->type = f32; break;
+ case BinaryConsts::F64Floor: curr = allocator.alloc<Unary>(); curr->op = FloorFloat64; curr->type = f64; break;
+ case BinaryConsts::F32NearestInt: curr = allocator.alloc<Unary>(); curr->op = NearestFloat32; curr->type = f32; break;
+ case BinaryConsts::F64NearestInt: curr = allocator.alloc<Unary>(); curr->op = NearestFloat64; curr->type = f64; break;
+ case BinaryConsts::F32Sqrt: curr = allocator.alloc<Unary>(); curr->op = SqrtFloat32; curr->type = f32; break;
+ case BinaryConsts::F64Sqrt: curr = allocator.alloc<Unary>(); curr->op = SqrtFloat64; curr->type = f64; break;
case BinaryConsts::F32UConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt32ToFloat32; curr->type = f32; break;
case BinaryConsts::F64UConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertUInt32ToFloat64; curr->type = f64; break;
case BinaryConsts::F32SConvertI32: curr = allocator.alloc<Unary>(); curr->op = ConvertSInt32ToFloat32; curr->type = f32; break;
@@ -1930,16 +1958,16 @@ public:
case BinaryConsts::I32ConvertI64: curr = allocator.alloc<Unary>(); curr->op = WrapInt64; curr->type = i32; break;
case BinaryConsts::I32UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32ToInt32; curr->type = i32; break;
- case BinaryConsts::I32UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64ToInt64; curr->type = i32; break;
+ case BinaryConsts::I32UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64ToInt32; curr->type = i32; break;
case BinaryConsts::I32STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32ToInt32; curr->type = i32; break;
- case BinaryConsts::I32STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64ToInt64; curr->type = i32; break;
- case BinaryConsts::I64UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32ToInt32; curr->type = i64; break;
+ case BinaryConsts::I32STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64ToInt32; curr->type = i32; break;
+ case BinaryConsts::I64UTruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat32ToInt64; curr->type = i64; break;
case BinaryConsts::I64UTruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncUFloat64ToInt64; curr->type = i64; break;
- case BinaryConsts::I64STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32ToInt32; curr->type = i64; break;
+ case BinaryConsts::I64STruncF32: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat32ToInt64; curr->type = i64; break;
case BinaryConsts::I64STruncF64: curr = allocator.alloc<Unary>(); curr->op = TruncSFloat64ToInt64; curr->type = i64; break;
- case BinaryConsts::F32Trunc: curr = allocator.alloc<Unary>(); curr->op = Trunc; curr->type = f32; break;
- case BinaryConsts::F64Trunc: curr = allocator.alloc<Unary>(); curr->op = Trunc; curr->type = f64; break;
+ case BinaryConsts::F32Trunc: curr = allocator.alloc<Unary>(); curr->op = TruncFloat32; curr->type = f32; break;
+ case BinaryConsts::F64Trunc: curr = allocator.alloc<Unary>(); curr->op = TruncFloat64; curr->type = f64; break;
case BinaryConsts::F32ConvertF64: curr = allocator.alloc<Unary>(); curr->op = DemoteFloat64; curr->type = f32; break;
case BinaryConsts::F64ConvertF32: curr = allocator.alloc<Unary>(); curr->op = PromoteFloat32; curr->type = f64; break;
@@ -1957,20 +1985,19 @@ public:
}
bool maybeVisitBinary(Expression*& out, uint8_t code) {
Binary* curr;
- #define TYPED_CODE(code) { \
- case BinaryConsts::I32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i32; break; \
- case BinaryConsts::I64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i64; break; \
- case BinaryConsts::F32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f32; break; \
- case BinaryConsts::F64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f64; break; \
- }
#define INT_TYPED_CODE(code) { \
- case BinaryConsts::I32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i32; break; \
- case BinaryConsts::I64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = i64; break; \
+ case BinaryConsts::I32##code: curr = allocator.alloc<Binary>(); curr->op = code##Int32; curr->type = i32; break; \
+ case BinaryConsts::I64##code: curr = allocator.alloc<Binary>(); curr->op = code##Int64; curr->type = i64; break; \
}
#define FLOAT_TYPED_CODE(code) { \
- case BinaryConsts::F32##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f32; break; \
- case BinaryConsts::F64##code: curr = allocator.alloc<Binary>(); curr->op = code; curr->type = f64; break; \
+ case BinaryConsts::F32##code: curr = allocator.alloc<Binary>(); curr->op = code##Float32; curr->type = f32; break; \
+ case BinaryConsts::F64##code: curr = allocator.alloc<Binary>(); curr->op = code##Float64; curr->type = f64; break; \
}
+ #define TYPED_CODE(code) { \
+ INT_TYPED_CODE(code) \
+ FLOAT_TYPED_CODE(code) \
+ }
+
switch (code) {
TYPED_CODE(Add);
TYPED_CODE(Sub);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index c20c25f06..4dc195d5c 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -136,44 +136,7 @@ public:
Unary* makeUnary(UnaryOp op, Expression *value) {
auto* ret = allocator.alloc<Unary>();
ret->op = op; ret->value = value;
- switch (op) {
- case Clz:
- case Ctz:
- case Popcnt:
- case Neg:
- case Abs:
- case Ceil:
- case Floor:
- case Trunc:
- case Nearest:
- case Sqrt: ret->type = value->type; break;
- case EqZ: ret->type = i32; break;
- case ExtendSInt32: case ExtendUInt32: ret->type = i64; break;
- case WrapInt64: ret->type = i32; break;
- case PromoteFloat32: ret->type = f64; break;
- case DemoteFloat64: ret->type = f32; break;
- case TruncSFloat32ToInt32:
- case TruncUFloat32ToInt32:
- case TruncSFloat64ToInt32:
- case TruncUFloat64ToInt32:
- case ReinterpretFloat32: ret->type = i32; break;
- case TruncSFloat32ToInt64:
- case TruncUFloat32ToInt64:
- case TruncSFloat64ToInt64:
- case TruncUFloat64ToInt64:
- case ReinterpretFloat64: ret->type = i64; break;
- case ReinterpretInt32:
- case ConvertSInt32ToFloat32:
- case ConvertUInt32ToFloat32:
- case ConvertSInt64ToFloat32:
- case ConvertUInt64ToFloat32: ret->type = f32; break;
- case ReinterpretInt64:
- case ConvertSInt32ToFloat64:
- case ConvertUInt32ToFloat64:
- case ConvertSInt64ToFloat64:
- case ConvertUInt64ToFloat64: ret->type = f64; break;
- default: abort();
- }
+ ret->finalize();
return ret;
}
Binary* makeBinary(BinaryOp op, Expression *left, Expression *right) {
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index c40132b18..b8f6554ec 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -145,7 +145,7 @@ private:
class FunctionScope {
public:
- std::map<IString, Literal> locals;
+ std::vector<Literal> locals;
Function* function;
FunctionScope(Function* function, LiteralList& arguments)
@@ -156,6 +156,7 @@ private:
<< arguments.size() << " arguments." << std::endl;
abort();
}
+ locals.resize(function->getNumLocals());
for (size_t i = 0; i < function->getNumLocals(); i++) {
if (i < arguments.size()) {
assert(function->isParam(i));
@@ -166,10 +167,10 @@ private:
<< printWasmType(arguments[i].type) << "." << std::endl;
abort();
}
- locals[function->getLocalName(i)] = arguments[i];
+ locals[i] = arguments[i];
} else {
assert(function->isVar(i));
- locals[function->getLocalName(i)].type = function->getLocalType(i);
+ locals[i].type = function->getLocalType(i);
}
}
}
@@ -358,20 +359,20 @@ private:
Flow visitGetLocal(GetLocal *curr) {
NOTE_ENTER("GetLocal");
- IString name = scope.function->getLocalName(curr->index);
- NOTE_NAME(name);
- NOTE_EVAL1(scope.locals[name]);
- return scope.locals[name];
+ auto index = curr->index;
+ NOTE_EVAL1(index);
+ NOTE_EVAL1(scope.locals[index]);
+ return scope.locals[index];
}
Flow visitSetLocal(SetLocal *curr) {
NOTE_ENTER("SetLocal");
- IString name = scope.function->getLocalName(curr->index);
+ auto index = curr->index;
Flow flow = visit(curr->value);
if (flow.breaking()) return flow;
- NOTE_NAME(name);
+ NOTE_EVAL1(index);
NOTE_EVAL1(flow.value);
assert(flow.value.type == curr->type);
- scope.locals[name] = flow.value;
+ scope.locals[index] = flow.value;
return flow;
}
Flow visitLoad(Load *curr) {
@@ -402,10 +403,10 @@ private:
NOTE_EVAL1(value);
if (value.type == i32) {
switch (curr->op) {
- case Clz: return value.countLeadingZeroes();
- case Ctz: return value.countTrailingZeroes();
- case Popcnt: return value.popCount();
- case EqZ: return Literal(int32_t(value == Literal(int32_t(0))));
+ case ClzInt32: return value.countLeadingZeroes();
+ case CtzInt32: return value.countTrailingZeroes();
+ case PopcntInt32: return value.popCount();
+ case EqZInt32: return Literal(int32_t(value == Literal(int32_t(0))));
case ReinterpretInt32: return value.castToF32();
case ExtendSInt32: return value.extendToSI64();
case ExtendUInt32: return value.extendToUI64();
@@ -418,10 +419,10 @@ private:
}
if (value.type == i64) {
switch (curr->op) {
- case Clz: return value.countLeadingZeroes();
- case Ctz: return value.countTrailingZeroes();
- case Popcnt: return value.popCount();
- case EqZ: return Literal(int32_t(value == Literal(int64_t(0))));
+ case ClzInt64: return value.countLeadingZeroes();
+ case CtzInt64: return value.countTrailingZeroes();
+ case PopcntInt64: return value.popCount();
+ case EqZInt64: return Literal(int32_t(value == Literal(int64_t(0))));
case WrapInt64: return value.truncateToI32();
case ReinterpretInt64: return value.castToF64();
case ConvertUInt64ToFloat32: return value.convertUToF32();
@@ -433,13 +434,13 @@ private:
}
if (value.type == f32) {
switch (curr->op) {
- case Neg: return value.neg();
- case Abs: return value.abs();
- case Ceil: return value.ceil();
- case Floor: return value.floor();
- case Trunc: return value.trunc();
- case Nearest: return value.nearbyint();
- case Sqrt: return value.sqrt();
+ case NegFloat32: return value.neg();
+ case AbsFloat32: return value.abs();
+ case CeilFloat32: return value.ceil();
+ case FloorFloat32: return value.floor();
+ case TruncFloat32: return value.trunc();
+ case NearestFloat32: return value.nearbyint();
+ case SqrtFloat32: return value.sqrt();
case TruncSFloat32ToInt32:
case TruncSFloat32ToInt64: return truncSFloat(curr, value);
case TruncUFloat32ToInt32:
@@ -451,13 +452,13 @@ private:
}
if (value.type == f64) {
switch (curr->op) {
- case Neg: return value.neg();
- case Abs: return value.abs();
- case Ceil: return value.ceil();
- case Floor: return value.floor();
- case Trunc: return value.trunc();
- case Nearest: return value.nearbyint();
- case Sqrt: return value.sqrt();
+ case NegFloat64: return value.neg();
+ case AbsFloat64: return value.abs();
+ case CeilFloat64: return value.ceil();
+ case FloorFloat64: return value.floor();
+ case TruncFloat64: return value.trunc();
+ case NearestFloat64: return value.nearbyint();
+ case SqrtFloat64: return value.sqrt();
case TruncSFloat64ToInt32:
case TruncSFloat64ToInt64: return truncSFloat(curr, value);
case TruncUFloat64ToInt32:
@@ -489,105 +490,105 @@ private:
assert(isConcreteWasmType(curr->right->type) ? right.type == curr->right->type : true);
if (left.type == i32) {
switch (curr->op) {
- case Add: return left.add(right);
- case Sub: return left.sub(right);
- case Mul: return left.mul(right);
- case DivS: {
+ case AddInt32: return left.add(right);
+ case SubInt32: return left.sub(right);
+ case MulInt32: return left.mul(right);
+ case DivSInt32: {
if (right.getInteger() == 0) trap("i32.div_s by 0");
if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) trap("i32.div_s overflow"); // signed division overflow
return left.divS(right);
}
- case DivU: {
+ case DivUInt32: {
if (right.getInteger() == 0) trap("i32.div_u by 0");
return left.divU(right);
}
- case RemS: {
+ case RemSInt32: {
if (right.getInteger() == 0) trap("i32.rem_s by 0");
if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) return Literal(int32_t(0));
return left.remS(right);
}
- case RemU: {
+ case RemUInt32: {
if (right.getInteger() == 0) trap("i32.rem_u by 0");
return left.remU(right);
}
- case And: return left.and_(right);
- case Or: return left.or_(right);
- case Xor: return left.xor_(right);
- case Shl: return left.shl(right.and_(Literal(int32_t(31))));
- case ShrU: return left.shrU(right.and_(Literal(int32_t(31))));
- case ShrS: return left.shrS(right.and_(Literal(int32_t(31))));
- case RotL: return left.rotL(right);
- case RotR: return left.rotR(right);
- case Eq: return left.eq(right);
- case Ne: return left.ne(right);
- case LtS: return left.ltS(right);
- case LtU: return left.ltU(right);
- case LeS: return left.leS(right);
- case LeU: return left.leU(right);
- case GtS: return left.gtS(right);
- case GtU: return left.gtU(right);
- case GeS: return left.geS(right);
- case GeU: return left.geU(right);
+ case AndInt32: return left.and_(right);
+ case OrInt32: return left.or_(right);
+ case XorInt32: return left.xor_(right);
+ case ShlInt32: return left.shl(right.and_(Literal(int32_t(31))));
+ case ShrUInt32: return left.shrU(right.and_(Literal(int32_t(31))));
+ case ShrSInt32: return left.shrS(right.and_(Literal(int32_t(31))));
+ case RotLInt32: return left.rotL(right);
+ case RotRInt32: return left.rotR(right);
+ case EqInt32: return left.eq(right);
+ case NeInt32: return left.ne(right);
+ case LtSInt32: return left.ltS(right);
+ case LtUInt32: return left.ltU(right);
+ case LeSInt32: return left.leS(right);
+ case LeUInt32: return left.leU(right);
+ case GtSInt32: return left.gtS(right);
+ case GtUInt32: return left.gtU(right);
+ case GeSInt32: return left.geS(right);
+ case GeUInt32: return left.geU(right);
default: abort();
}
} else if (left.type == i64) {
switch (curr->op) {
- case Add: return left.add(right);
- case Sub: return left.sub(right);
- case Mul: return left.mul(right);
- case DivS: {
+ case AddInt64: return left.add(right);
+ case SubInt64: return left.sub(right);
+ case MulInt64: return left.mul(right);
+ case DivSInt64: {
if (right.getInteger() == 0) trap("i64.div_s by 0");
if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) trap("i64.div_s overflow"); // signed division overflow
return left.divS(right);
}
- case DivU: {
+ case DivUInt64: {
if (right.getInteger() == 0) trap("i64.div_u by 0");
return left.divU(right);
}
- case RemS: {
+ case RemSInt64: {
if (right.getInteger() == 0) trap("i64.rem_s by 0");
if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) return Literal(int64_t(0));
return left.remS(right);
}
- case RemU: {
+ case RemUInt64: {
if (right.getInteger() == 0) trap("i64.rem_u by 0");
return left.remU(right);
}
- case And: return left.and_(right);
- case Or: return left.or_(right);
- case Xor: return left.xor_(right);
- case Shl: return left.shl(right.and_(Literal(int64_t(63))));
- case ShrU: return left.shrU(right.and_(Literal(int64_t(63))));
- case ShrS: return left.shrS(right.and_(Literal(int64_t(63))));
- case RotL: return left.rotL(right);
- case RotR: return left.rotR(right);
- case Eq: return left.eq(right);
- case Ne: return left.ne(right);
- case LtS: return left.ltS(right);
- case LtU: return left.ltU(right);
- case LeS: return left.leS(right);
- case LeU: return left.leU(right);
- case GtS: return left.gtS(right);
- case GtU: return left.gtU(right);
- case GeS: return left.geS(right);
- case GeU: return left.geU(right);
+ case AndInt64: return left.and_(right);
+ case OrInt64: return left.or_(right);
+ case XorInt64: return left.xor_(right);
+ case ShlInt64: return left.shl(right.and_(Literal(int64_t(63))));
+ case ShrUInt64: return left.shrU(right.and_(Literal(int64_t(63))));
+ case ShrSInt64: return left.shrS(right.and_(Literal(int64_t(63))));
+ case RotLInt64: return left.rotL(right);
+ case RotRInt64: return left.rotR(right);
+ case EqInt64: return left.eq(right);
+ case NeInt64: return left.ne(right);
+ case LtSInt64: return left.ltS(right);
+ case LtUInt64: return left.ltU(right);
+ case LeSInt64: return left.leS(right);
+ case LeUInt64: return left.leU(right);
+ case GtSInt64: return left.gtS(right);
+ case GtUInt64: return left.gtU(right);
+ case GeSInt64: return left.geS(right);
+ case GeUInt64: return left.geU(right);
default: abort();
}
} else if (left.type == f32 || left.type == f64) {
switch (curr->op) {
- case Add: return left.add(right);
- case Sub: return left.sub(right);
- case Mul: return left.mul(right);
- case Div: return left.div(right);
- case CopySign: return left.copysign(right);
- case Min: return left.min(right);
- case Max: return left.max(right);
- case Eq: return left.eq(right);
- case Ne: return left.ne(right);
- case Lt: return left.lt(right);
- case Le: return left.le(right);
- case Gt: return left.gt(right);
- case Ge: return left.ge(right);
+ case AddFloat32: case AddFloat64: return left.add(right);
+ case SubFloat32: case SubFloat64: return left.sub(right);
+ case MulFloat32: case MulFloat64: return left.mul(right);
+ case DivFloat32: case DivFloat64: return left.div(right);
+ case CopySignFloat32: case CopySignFloat64: return left.copysign(right);
+ case MinFloat32: case MinFloat64: return left.min(right);
+ case MaxFloat32: case MaxFloat64: return left.max(right);
+ case EqFloat32: case EqFloat64: return left.eq(right);
+ case NeFloat32: case NeFloat64: return left.ne(right);
+ case LtFloat32: case LtFloat64: return left.lt(right);
+ case LeFloat32: case LeFloat64: return left.le(right);
+ case GtFloat32: case GtFloat64: return left.gt(right);
+ case GeFloat32: case GeFloat64: return left.ge(right);
default: abort();
}
}
diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp
index ea1883072..87059f9be 100644
--- a/src/wasm-js.cpp
+++ b/src/wasm-js.cpp
@@ -91,7 +91,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE load_asm2wasm(char *input) {
auto& global = pair.second;
if (!global.import) continue; // non-imports are initialized to zero in the typed array anyhow, so nothing to do here
double value = EM_ASM_DOUBLE({ return Module['lookupImport'](Pointer_stringify($0), Pointer_stringify($1)) }, global.module.str, global.base.str);
- unsigned address = global.address;
+ uint32_t address = global.address;
switch (global.type) {
case i32: EM_ASM_({ Module['info'].parent['HEAP32'][$0 >> 2] = $1 }, address, value); break;
case f32: EM_ASM_({ Module['info'].parent['HEAPF32'][$0 >> 2] = $1 }, address, value); break;
@@ -196,7 +196,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
var source = Module['HEAP8'].subarray($1, $1 + $2);
var target = new Int8Array(Module['outside']['newBuffer']);
target.set(source, $0);
- }, segment.offset, &segment.data[0], segment.data.size());
+ }, (uint32_t)segment.offset, &segment.data[0], segment.data.size());
}
}
@@ -236,7 +236,8 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
}
}
- Literal load(Load* load, Address addr) override {
+ Literal load(Load* load, Address address) override {
+ uint32_t addr = address;
if (load->align < load->bytes || (addr & (load->bytes-1))) {
int64_t out64;
double ret = EM_ASM_DOUBLE({
@@ -325,7 +326,8 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
}
}
- void store(Store* store_, Address addr, Literal value) override {
+ void store(Store* store_, Address address, Literal value) override {
+ uint32_t addr = address;
// support int64 stores
if (value.type == WasmType::i64) {
Store fake = *store_;
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 4dfba25f8..b59af7215 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -60,8 +60,6 @@ class Element {
IString str_;
bool dollared_;
- size_t line, col;
-
public:
Element(MixedArena& allocator) : isList_(true), list_(allocator), line(-1), col(-1) {}
@@ -69,6 +67,8 @@ public:
bool isStr() { return !isList_; }
bool dollared() { return dollared_; }
+ size_t line, col;
+
// list methods
List& list() {
@@ -300,11 +300,9 @@ private:
if (id == TYPE) return parseType(s);
if (id != FUNC) return;
size_t i = 1;
- Name name;
- if (s[i]->isStr()) {
- name = s[i]->str();
- i++;
- } else {
+ Name name, exportName;
+ i = parseFunctionNames(s, name, exportName);
+ if (!name.is()) {
// unnamed, use an index
name = Name::fromInt(functionCounter);
}
@@ -371,21 +369,26 @@ private:
wasm.addStart(getFunctionName(*s[1]));
}
- void parseFunction(Element& s) {
+ // returns the next index in s
+ size_t parseFunctionNames(Element& s, Name& name, Name& exportName) {
size_t i = 1;
- Name name, exportName;
- if (s[i]->isStr()) {
+ while (i < s.size() && s[i]->isStr()) {
if (!s[i]->dollared()) {
// an export name
exportName = s[i]->str();
i++;
- }
- if (s[i]->isStr()) {
- assert(s[i]->dollared());
+ } else {
name = s[i]->str();
i++;
}
}
+ return i;
+ }
+
+ void parseFunction(Element& s) {
+ size_t i = 1;
+ Name name, exportName;
+ i = parseFunctionNames(s, name, exportName);
if (!name.is()) {
// unnamed, use an index
name = Name::fromInt(functionCounter);
@@ -524,18 +527,21 @@ public:
enum { maxNameSize = 15 };
char op[maxNameSize + 1] = {'\0'};
strncpy(op, dot + 1, maxNameSize);
+ #define BINARY_INT_OR_FLOAT(op) (type == i32 ? BinaryOp::op##Int32 : (type == i64 ? BinaryOp::op##Int64 : (type == f32 ? BinaryOp::op##Float32 : BinaryOp::op##Float64)))
+ #define BINARY_INT(op) (type == i32 ? BinaryOp::op##Int32 : BinaryOp::op##Int64)
+ #define BINARY_FLOAT(op) (type == f32 ? BinaryOp::op##Float32 : BinaryOp::op##Float64)
switch (op[0]) {
case 'a': {
- if (op[1] == 'b') return makeUnary(s, UnaryOp::Abs, type);
- if (op[1] == 'd') return makeBinary(s, BinaryOp::Add, type);
- if (op[1] == 'n') return makeBinary(s, BinaryOp::And, type);
+ if (op[1] == 'b') return makeUnary(s, type == f32 ? UnaryOp::AbsFloat32 : UnaryOp::AbsFloat64, type);
+ if (op[1] == 'd') return makeBinary(s, BINARY_INT_OR_FLOAT(Add), type);
+ if (op[1] == 'n') return makeBinary(s, BINARY_INT(And), type);
abort_on(op);
}
case 'c': {
- if (op[1] == 'e') return makeUnary(s, UnaryOp::Ceil, type);
- if (op[1] == 'l') return makeUnary(s, UnaryOp::Clz, type);
+ if (op[1] == 'e') return makeUnary(s, type == f32 ? UnaryOp::CeilFloat32 : UnaryOp::CeilFloat64, type);
+ if (op[1] == 'l') return makeUnary(s, type == i32 ? UnaryOp::ClzInt32 : UnaryOp::ClzInt64, type);
if (op[1] == 'o') {
- if (op[2] == 'p') return makeBinary(s, BinaryOp::CopySign, type);
+ if (op[2] == 'p') return makeBinary(s, BINARY_FLOAT(CopySign), type);
if (op[2] == 'n') {
if (op[3] == 'v') {
if (op[8] == 's') return makeUnary(s, op[11] == '3' ? (type == f32 ? UnaryOp::ConvertSInt32ToFloat32 : UnaryOp::ConvertSInt32ToFloat64) : (type == f32 ? UnaryOp::ConvertSInt64ToFloat32 : UnaryOp::ConvertSInt64ToFloat64), type);
@@ -544,92 +550,92 @@ public:
if (op[3] == 's') return makeConst(s, type);
}
}
- if (op[1] == 't') return makeUnary(s, UnaryOp::Ctz, type);
+ if (op[1] == 't') return makeUnary(s, type == i32 ? UnaryOp::CtzInt32 : UnaryOp::CtzInt64, type);
abort_on(op);
}
case 'd': {
if (op[1] == 'i') {
- if (op[3] == '_') return makeBinary(s, op[4] == 'u' ? BinaryOp::DivU : BinaryOp::DivS, type);
- if (op[3] == 0) return makeBinary(s, BinaryOp::Div, type);
+ if (op[3] == '_') return makeBinary(s, op[4] == 'u' ? BINARY_INT(DivU) : BINARY_INT(DivS), type);
+ if (op[3] == 0) return makeBinary(s, BINARY_FLOAT(Div), type);
}
if (op[1] == 'e') return makeUnary(s, UnaryOp::DemoteFloat64, type);
abort_on(op);
}
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, i32);
+ if (op[2] == 0) return makeBinary(s, BINARY_INT_OR_FLOAT(Eq), type);
+ if (op[2] == 'z') return makeUnary(s, type == i32 ? UnaryOp::EqZInt32 : UnaryOp::EqZInt64, type);
}
if (op[1] == 'x') return makeUnary(s, op[7] == 'u' ? UnaryOp::ExtendUInt32 : UnaryOp::ExtendSInt32, type);
abort_on(op);
}
case 'f': {
- if (op[1] == 'l') return makeUnary(s, UnaryOp::Floor, type);
+ if (op[1] == 'l') return makeUnary(s, type == f32 ? UnaryOp::FloorFloat32 : UnaryOp::FloorFloat64, type);
abort_on(op);
}
case 'g': {
if (op[1] == 't') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::GtU : BinaryOp::GtS, type);
- if (op[2] == 0) return makeBinary(s, BinaryOp::Gt, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(GtU) : BINARY_INT(GtS), type);
+ if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Gt), type);
}
if (op[1] == 'e') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::GeU : BinaryOp::GeS, type);
- if (op[2] == 0) return makeBinary(s, BinaryOp::Ge, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(GeU) : BINARY_INT(GeS), type);
+ if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Ge), type);
}
abort_on(op);
}
case 'l': {
if (op[1] == 't') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::LtU : BinaryOp::LtS, type);
- if (op[2] == 0) return makeBinary(s, BinaryOp::Lt, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(LtU) : BINARY_INT(LtS), type);
+ if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Lt), type);
}
if (op[1] == 'e') {
- if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BinaryOp::LeU : BinaryOp::LeS, type);
- if (op[2] == 0) return makeBinary(s, BinaryOp::Le, type);
+ if (op[2] == '_') return makeBinary(s, op[3] == 'u' ? BINARY_INT(LeU) : BINARY_INT(LeS), type);
+ if (op[2] == 0) return makeBinary(s, BINARY_FLOAT(Le), type);
}
if (op[1] == 'o') return makeLoad(s, type);
abort_on(op);
}
case 'm': {
- if (op[1] == 'i') return makeBinary(s, BinaryOp::Min, type);
- if (op[1] == 'a') return makeBinary(s, BinaryOp::Max, type);
- if (op[1] == 'u') return makeBinary(s, BinaryOp::Mul, type);
+ if (op[1] == 'i') return makeBinary(s, BINARY_FLOAT(Min), type);
+ if (op[1] == 'a') return makeBinary(s, BINARY_FLOAT(Max), type);
+ if (op[1] == 'u') return makeBinary(s, BINARY_INT_OR_FLOAT(Mul), type);
abort_on(op);
}
case 'n': {
if (op[1] == 'e') {
- if (op[2] == 0) return makeBinary(s, BinaryOp::Ne, type);
- if (op[2] == 'a') return makeUnary(s, UnaryOp::Nearest, type);
- if (op[2] == 'g') return makeUnary(s, UnaryOp::Neg, type);
+ if (op[2] == 0) return makeBinary(s, BINARY_INT_OR_FLOAT(Ne), type);
+ if (op[2] == 'a') return makeUnary(s, type == f32 ? UnaryOp::NearestFloat32 : UnaryOp::NearestFloat64, type);
+ if (op[2] == 'g') return makeUnary(s, type == f32 ? UnaryOp::NegFloat32 : UnaryOp::NegFloat64, type);
}
abort_on(op);
}
case 'o': {
- if (op[1] == 'r') return makeBinary(s, BinaryOp::Or, type);
+ if (op[1] == 'r') return makeBinary(s, BINARY_INT(Or), type);
abort_on(op);
}
case 'p': {
if (op[1] == 'r') return makeUnary(s, UnaryOp::PromoteFloat32, type);
- if (op[1] == 'o') return makeUnary(s, UnaryOp::Popcnt, type);
+ if (op[1] == 'o') return makeUnary(s, type == i32 ? UnaryOp::PopcntInt32 : UnaryOp::PopcntInt64, type);
abort_on(op);
}
case 'r': {
if (op[1] == 'e') {
- if (op[2] == 'm') return makeBinary(s, op[4] == 'u' ? BinaryOp::RemU : BinaryOp::RemS, type);
+ if (op[2] == 'm') return makeBinary(s, op[4] == 'u' ? BINARY_INT(RemU) : BINARY_INT(RemS), type);
if (op[2] == 'i') return makeUnary(s, isWasmTypeFloat(type) ? (type == f32 ? UnaryOp::ReinterpretInt32 : UnaryOp::ReinterpretInt64) : (type == i32 ? UnaryOp::ReinterpretFloat32 : UnaryOp::ReinterpretFloat64), type);
}
if (op[1] == 'o' && op[2] == 't') {
- return makeBinary(s, op[3] == 'l' ? BinaryOp::RotL : BinaryOp::RotR, type);
+ return makeBinary(s, op[3] == 'l' ? BINARY_INT(RotL) : BINARY_INT(RotR), type);
}
abort_on(op);
}
case 's': {
if (op[1] == 'h') {
- if (op[2] == 'l') return makeBinary(s, BinaryOp::Shl, type);
- return makeBinary(s, op[4] == 'u' ? BinaryOp::ShrU : BinaryOp::ShrS, type);
+ if (op[2] == 'l') return makeBinary(s, BINARY_INT(Shl), type);
+ return makeBinary(s, op[4] == 'u' ? BINARY_INT(ShrU) : BINARY_INT(ShrS), type);
}
- if (op[1] == 'u') return makeBinary(s, BinaryOp::Sub, type);
- if (op[1] == 'q') return makeUnary(s, UnaryOp::Sqrt, type);
+ if (op[1] == 'u') return makeBinary(s, BINARY_INT_OR_FLOAT(Sub), type);
+ if (op[1] == 'q') return makeUnary(s, type == f32 ? UnaryOp::SqrtFloat32 : UnaryOp::SqrtFloat64, type);
if (op[1] == 't') return makeStore(s, type);
abort_on(op);
}
@@ -637,7 +643,7 @@ public:
if (op[1] == 'r') {
if (op[6] == 's') return makeUnary(s, op[9] == '3' ? (type == i32 ? UnaryOp::TruncSFloat32ToInt32 : UnaryOp::TruncSFloat32ToInt64) : (type == i32 ? UnaryOp::TruncSFloat64ToInt32 : UnaryOp::TruncSFloat64ToInt64), type);
if (op[6] == 'u') return makeUnary(s, op[9] == '3' ? (type == i32 ? UnaryOp::TruncUFloat32ToInt32 : UnaryOp::TruncUFloat32ToInt64) : (type == i32 ? UnaryOp::TruncUFloat64ToInt32 : UnaryOp::TruncUFloat64ToInt64), type);
- if (op[2] == 'u') return makeUnary(s, UnaryOp::Trunc, type);
+ if (op[2] == 'u') return makeUnary(s, type == f32 ? UnaryOp::TruncFloat32 : UnaryOp::TruncFloat64, type);
}
abort_on(op);
}
@@ -646,7 +652,7 @@ public:
abort_on(op);
}
case 'x': {
- if (op[1] == 'o') return makeBinary(s, BinaryOp::Xor, type);
+ if (op[1] == 'o') return makeBinary(s, BINARY_INT(Xor), type);
abort_on(op);
}
default: abort_on(op);
@@ -736,7 +742,61 @@ private:
auto ret = allocator.alloc<Unary>();
ret->op = op;
ret->value = parseExpression(s[1]);
- ret->type = type;
+ ret->finalize();
+ // type is the reported type, e.g. i64.ctz reports i64 (but has a return type of i32, in this case)
+ // verify the reported type is correct
+ switch (op) {
+ case EqZInt32:
+ case NegFloat32:
+ case AbsFloat32:
+ case CeilFloat32:
+ case FloorFloat32:
+ case TruncFloat32:
+ case NearestFloat32:
+ case SqrtFloat32:
+ case ClzInt32:
+ case CtzInt32:
+ case PopcntInt32:
+ case EqZInt64:
+ case NegFloat64:
+ case AbsFloat64:
+ case CeilFloat64:
+ case FloorFloat64:
+ case TruncFloat64:
+ case NearestFloat64:
+ case SqrtFloat64:
+ case ClzInt64:
+ case CtzInt64:
+ case PopcntInt64: {
+ if (ret->value->type != unreachable && type != ret->value->type) throw ParseException(std::string("bad type for ") + getExpressionName(ret) + ": " + printWasmType(type) + " vs value type " + printWasmType(ret->value->type), s.line, s.col);
+ break;
+ }
+ case ExtendSInt32: case ExtendUInt32:
+ case WrapInt64:
+ case PromoteFloat32:
+ case DemoteFloat64:
+ case TruncSFloat32ToInt32:
+ case TruncUFloat32ToInt32:
+ case TruncSFloat64ToInt32:
+ case TruncUFloat64ToInt32:
+ case ReinterpretFloat32:
+ case TruncSFloat32ToInt64:
+ case TruncUFloat32ToInt64:
+ case TruncSFloat64ToInt64:
+ case TruncUFloat64ToInt64:
+ case ReinterpretFloat64:
+ case ReinterpretInt32:
+ case ConvertSInt32ToFloat32:
+ case ConvertUInt32ToFloat32:
+ case ConvertSInt64ToFloat32:
+ case ConvertUInt64ToFloat32:
+ case ReinterpretInt64:
+ case ConvertSInt32ToFloat64:
+ case ConvertUInt32ToFloat64:
+ case ConvertSInt64ToFloat64:
+ case ConvertUInt64ToFloat64: break;
+ default: WASM_UNREACHABLE();
+ }
return ret;
}
@@ -1149,7 +1209,9 @@ private:
if (s.size() == 2) return;
size_t i = 2;
if (s[i]->isStr()) {
- wasm.memory.max = atoi(s[i]->c_str());
+ uint64_t max = atoll(s[i]->c_str());
+ if (max > Memory::kMaxSize) throw ParseException("total memory must be <= 4GB");
+ wasm.memory.max = max;
i++;
}
while (i < s.size()) {
diff --git a/src/wasm-validator.h b/src/wasm-validator.h
index f93e06524..8e94fd368 100644
--- a/src/wasm-validator.h
+++ b/src/wasm-validator.h
@@ -30,6 +30,7 @@ struct WasmValidator : public PostWalker<WasmValidator, Visitor<WasmValidator>>
bool valid;
std::map<Name, WasmType> breakTypes; // breaks to a label must all have the same type, and the right type
+ WasmType returnType = unreachable; // type used in returns
public:
bool validate(Module& module) {
@@ -51,7 +52,7 @@ public:
}
}
void visitIf(If *curr) {
- shouldBeTrue(curr->condition->type == unreachable || curr->condition->type == i32, curr, "if condition must be i32");
+ shouldBeTrue(curr->condition->type == unreachable || curr->condition->type == i32 || curr->condition->type == i64, curr, "if condition must be valid");
}
void visitLoop(Loop *curr) {
if (curr->in.is()) {
@@ -96,29 +97,39 @@ public:
}
void visitCall(Call *curr) {
auto* target = getModule()->getFunction(curr->target);
+ shouldBeTrue(curr->operands.size() == target->params.size(), curr, "call param number must match");
for (size_t i = 0; i < curr->operands.size(); i++) {
- shouldBeTrue(curr->operands[i]->type == target->params[i], curr, "call param types must match");
+ shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, target->params[i], curr, "call param types must match");
}
}
void visitCallImport(CallImport *curr) {
auto* target = getModule()->getImport(curr->target)->type;
+ shouldBeTrue(curr->operands.size() == target->params.size(), curr, "call param number must match");
for (size_t i = 0; i < curr->operands.size(); i++) {
- shouldBeTrue(curr->operands[i]->type == target->params[i], curr, "call param types must match");
+ shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, target->params[i], curr, "call param types must match");
+ }
+ }
+ void visitCallIndirect(CallIndirect *curr) {
+ auto* type = curr->fullType;
+ shouldBeEqualOrFirstIsUnreachable(curr->target->type, i32, curr, "indirect call target must be an i32");
+ shouldBeTrue(curr->operands.size() == type->params.size(), curr, "call param number must match");
+ for (size_t i = 0; i < curr->operands.size(); i++) {
+ shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type, type->params[i], curr, "call param types must match");
}
}
void visitSetLocal(SetLocal *curr) {
if (curr->value->type != unreachable) {
- shouldBeEqual(curr->type, curr->value->type, curr, "set_local type must be correct");
+ shouldBeEqualOrFirstIsUnreachable(curr->value->type, curr->type, curr, "set_local type must be correct");
}
}
void visitLoad(Load *curr) {
validateAlignment(curr->align);
- shouldBeEqual(curr->ptr->type, i32, curr, "load pointer type must be i32");
+ shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "load pointer type must be i32");
}
void visitStore(Store *curr) {
validateAlignment(curr->align);
- shouldBeEqual(curr->ptr->type, i32, curr, "store pointer type must be i32");
- shouldBeEqual(curr->value->type, curr->type, curr, "store value type must match");
+ shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "store pointer type must be i32");
+ shouldBeEqualOrFirstIsUnreachable(curr->value->type, curr->type, curr, "store value type must match");
}
void visitBinary(Binary *curr) {
if (curr->left->type != unreachable && curr->right->type != unreachable) {
@@ -126,24 +137,45 @@ public:
}
}
void visitUnary(Unary *curr) {
+ shouldBeUnequal(curr->value->type, none, curr, "unaries must not receive a none as their input");
+ switch (curr->op) {
+ case EqZInt32:
+ case EqZInt64: {
+ shouldBeEqual(curr->type, i32, curr, "eqz must return i32");
+ break;
+ }
+ default: {}
+ }
+ if (curr->value->type == unreachable) return;
switch (curr->op) {
- case Clz:
- case Ctz:
- case Popcnt:
- case Neg:
- case Abs:
- case Ceil:
- case Floor:
- case Trunc:
- case Nearest:
- case Sqrt: {
+ case ClzInt32:
+ case CtzInt32:
+ case PopcntInt32:
+ case NegFloat32:
+ case AbsFloat32:
+ case CeilFloat32:
+ case FloorFloat32:
+ case TruncFloat32:
+ case NearestFloat32:
+ case SqrtFloat32:
+ case ClzInt64:
+ case CtzInt64:
+ case PopcntInt64:
+ case NegFloat64:
+ case AbsFloat64:
+ case CeilFloat64:
+ case FloorFloat64:
+ case TruncFloat64:
+ case NearestFloat64:
+ case SqrtFloat64: {
if (curr->value->type != unreachable) {
shouldBeEqual(curr->value->type, curr->type, curr, "non-conversion unaries must return the same type");
}
break;
}
- case EqZ: {
- shouldBeEqual(curr->type, i32, curr, "relational unaries must return i32");
+ case EqZInt32:
+ case EqZInt64: {
+ shouldBeTrue(curr->value->type == i32 || curr->value->type == i64, curr, "eqz input must be i32 or i64");
break;
}
case ExtendSInt32: shouldBeEqual(curr->value->type, i32, curr, "extend type must be correct"); break;
@@ -175,15 +207,42 @@ public:
}
}
+ void visitReturn(Return* curr) {
+ if (curr->value) {
+ returnType = curr->value->type;
+ }
+ }
+
+ void visitHost(Host* curr) {
+ switch (curr->op) {
+ case GrowMemory: {
+ shouldBeEqual(curr->operands.size(), size_t(1), curr, "grow_memory must have 1 operand");
+ shouldBeEqualOrFirstIsUnreachable(curr->operands[0]->type, i32, curr, "grow_memory must have i32 operand");
+ break;
+ }
+ case PageSize:
+ case CurrentMemory:
+ case HasFeature: break;
+ default: WASM_UNREACHABLE();
+ }
+ }
+
void visitFunction(Function *curr) {
// if function has no result, it is ignored
// if body is unreachable, it might be e.g. a return
- if (curr->result != none && curr->body->type != unreachable) {
- shouldBeEqual(curr->result, curr->body->type, curr->body, "function result must match, if function returns");
+ if (curr->result != none) {
+ if (curr->body->type != unreachable) {
+ shouldBeEqual(curr->result, curr->body->type, curr->body, "function body type must match, if function returns");
+ }
+ if (returnType != unreachable) {
+ shouldBeEqual(curr->result, returnType, curr->body, "function result must match, if function returns");
+ }
}
+ returnType = unreachable;
}
void visitMemory(Memory *curr) {
shouldBeFalse(curr->initial > curr->max, "memory", "memory max >= initial");
+ shouldBeTrue(curr->max <= Memory::kMaxSize, "memory", "total memory must be <= 4GB");
size_t top = 0;
for (auto& segment : curr->segments) {
shouldBeFalse(segment.offset < top, "memory", "segment offset is small enough");
@@ -296,6 +355,16 @@ private:
}
template<typename T, typename S>
+ bool shouldBeEqualOrFirstIsUnreachable(S left, S right, T curr, const char* text) {
+ if (left != unreachable && left != right) {
+ fail() << "" << left << " != " << right << ": " << text << ", on \n" << curr << std::endl;
+ valid = false;
+ return false;
+ }
+ return true;
+ }
+
+ template<typename T, typename S>
bool shouldBeUnequal(S left, S right, T curr, const char* text) {
if (left == right) {
fail() << "" << left << " == " << right << ": " << text << ", on \n" << curr << std::endl;
diff --git a/src/wasm.cpp b/src/wasm.cpp
index 98268310a..09d9c3c16 100644
--- a/src/wasm.cpp
+++ b/src/wasm.cpp
@@ -22,66 +22,65 @@ namespace wasm {
struct BlockTypeSeeker : public PostWalker<BlockTypeSeeker, Visitor<BlockTypeSeeker>> {
Block* target; // look for this one
- WasmType type = unreachable;
+ std::vector<WasmType> types;
BlockTypeSeeker(Block* target) : target(target) {}
- void noteType(WasmType other) {
- // once none, stop. it then indicates a poison value, that must not be consumed
- // and ignore unreachable
- if (type != none) {
- if (other == none) {
- type = none;
- } else if (other != unreachable) {
- if (type == unreachable) {
- type = other;
- } else if (type != other) {
- type = none; // poison value, we saw multiple types; this should not be consumed
- }
- }
- }
- }
-
void visitBreak(Break *curr) {
if (curr->name == target->name) {
- noteType(curr->value ? curr->value->type : none);
+ types.push_back(curr->value ? curr->value->type : none);
}
}
void visitSwitch(Switch *curr) {
for (auto name : curr->targets) {
- if (name == target->name) noteType(curr->value ? curr->value->type : none);
+ if (name == target->name) types.push_back(curr->value ? curr->value->type : none);
}
}
void visitBlock(Block *curr) {
if (curr == target) {
- if (curr->list.size() > 0) noteType(curr->list.back()->type);
- } else {
- type = unreachable; // ignore all breaks til now, they were captured by someone with the same name
+ if (curr->list.size() > 0) {
+ types.push_back(curr->list.back()->type);
+ } else {
+ types.push_back(none);
+ }
+ } else if (curr->name == target->name) {
+ types.clear(); // ignore all breaks til now, they were captured by someone with the same name
}
}
};
void Block::finalize() {
- if (list.size() > 0) {
- auto last = list.back()->type;
- if (last != unreachable) {
- // well that was easy
- type = last;
- return;
- }
- }
if (!name.is()) {
- // that was rather silly
- type = unreachable;
+ // nothing branches here, so this is easy
+ if (list.size() > 0) {
+ type = list.back()->type;
+ } else {
+ type = unreachable;
+ }
return;
}
- // oh no this is hard
+
BlockTypeSeeker seeker(this);
Expression* temp = this;
seeker.walk(temp);
- type = seeker.type;
+ type = unreachable;
+ for (auto other : seeker.types) {
+ // once none, stop. it then indicates a poison value, that must not be consumed
+ // and ignore unreachable
+ if (type != none) {
+ if (other == none) {
+ type = none;
+ } else if (other != unreachable) {
+ if (type == unreachable) {
+ type = other;
+ } else if (type != other) {
+ type = none; // poison value, we saw multiple types; this should not be consumed
+ }
+ }
+ }
+ }
}
} // namespace wasm
diff --git a/src/wasm.h b/src/wasm.h
index f68459401..fc0337700 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -775,10 +775,10 @@ private:
// Operators
enum UnaryOp {
- Clz, Ctz, Popcnt, // int
- Neg, Abs, Ceil, Floor, Trunc, Nearest, Sqrt, // float
+ ClzInt32, ClzInt64, CtzInt32, CtzInt64, PopcntInt32, PopcntInt64, // int
+ NegFloat32, NegFloat64, AbsFloat32, AbsFloat64, CeilFloat32, CeilFloat64, FloorFloat32, FloorFloat64, TruncFloat32, TruncFloat64, NearestFloat32, NearestFloat64, SqrtFloat32, SqrtFloat64, // float
// relational
- EqZ,
+ EqZInt32, EqZInt64,
// conversions
ExtendSInt32, ExtendUInt32, // extend i32 to i64
WrapInt64, // i64 to i32
@@ -791,13 +791,29 @@ enum UnaryOp {
};
enum BinaryOp {
- Add, Sub, Mul, // int or float
- DivS, DivU, RemS, RemU, And, Or, Xor, Shl, ShrU, ShrS, RotL, RotR, // int
- Div, CopySign, Min, Max, // float
+ AddInt32, SubInt32, MulInt32, // int or float
+ DivSInt32, DivUInt32, RemSInt32, RemUInt32, AndInt32, OrInt32, XorInt32, ShlInt32, ShrUInt32, ShrSInt32, RotLInt32, RotRInt32, // int
// relational ops
- Eq, Ne, // int or float
- LtS, LtU, LeS, LeU, GtS, GtU, GeS, GeU, // int
- Lt, Le, Gt, Ge // float
+ EqInt32, NeInt32, // int or float
+ LtSInt32, LtUInt32, LeSInt32, LeUInt32, GtSInt32, GtUInt32, GeSInt32, GeUInt32, // int
+
+ AddInt64, SubInt64, MulInt64, // int or float
+ DivSInt64, DivUInt64, RemSInt64, RemUInt64, AndInt64, OrInt64, XorInt64, ShlInt64, ShrUInt64, ShrSInt64, RotLInt64, RotRInt64, // int
+ // relational ops
+ EqInt64, NeInt64, // int or float
+ LtSInt64, LtUInt64, LeSInt64, LeUInt64, GtSInt64, GtUInt64, GeSInt64, GeUInt64, // int
+
+ AddFloat32, SubFloat32, MulFloat32, // int or float
+ DivFloat32, CopySignFloat32, MinFloat32, MaxFloat32, // float
+ // relational ops
+ EqFloat32, NeFloat32, // int or float
+ LtFloat32, LeFloat32, GtFloat32, GeFloat32, // float
+
+ AddFloat64, SubFloat64, MulFloat64, // int or float
+ DivFloat64, CopySignFloat64, MinFloat64, MaxFloat64, // float
+ // relational ops
+ EqFloat64, NeFloat64, // int or float
+ LtFloat64, LeFloat64, GtFloat64, GeFloat64, // float
};
enum HostOp {
@@ -1116,9 +1132,59 @@ public:
UnaryOp op;
Expression *value;
- bool isRelational() { return op == EqZ; }
+ bool isRelational() { return op == EqZInt32 || op == EqZInt64; }
- // no finalize since some opcodes have more than one type, so user must set it anyhow
+ void finalize() {
+ switch (op) {
+ case ClzInt32:
+ case CtzInt32:
+ case PopcntInt32:
+ case NegFloat32:
+ case AbsFloat32:
+ case CeilFloat32:
+ case FloorFloat32:
+ case TruncFloat32:
+ case NearestFloat32:
+ case SqrtFloat32:
+ case ClzInt64:
+ case CtzInt64:
+ case PopcntInt64:
+ case NegFloat64:
+ case AbsFloat64:
+ case CeilFloat64:
+ case FloorFloat64:
+ case TruncFloat64:
+ case NearestFloat64:
+ case SqrtFloat64: type = value->type; break;
+ case EqZInt32:
+ case EqZInt64: type = i32; break;
+ case ExtendSInt32: case ExtendUInt32: type = i64; break;
+ case WrapInt64: type = i32; break;
+ case PromoteFloat32: type = f64; break;
+ case DemoteFloat64: type = f32; break;
+ case TruncSFloat32ToInt32:
+ case TruncUFloat32ToInt32:
+ case TruncSFloat64ToInt32:
+ case TruncUFloat64ToInt32:
+ case ReinterpretFloat32: type = i32; break;
+ case TruncSFloat32ToInt64:
+ case TruncUFloat32ToInt64:
+ case TruncSFloat64ToInt64:
+ case TruncUFloat64ToInt64:
+ case ReinterpretFloat64: type = i64; break;
+ case ReinterpretInt32:
+ case ConvertSInt32ToFloat32:
+ case ConvertUInt32ToFloat32:
+ case ConvertSInt64ToFloat32:
+ case ConvertUInt64ToFloat32: type = f32; break;
+ case ReinterpretInt64:
+ case ConvertSInt32ToFloat64:
+ case ConvertUInt32ToFloat64:
+ case ConvertSInt64ToFloat64:
+ case ConvertUInt64ToFloat64: type = f64; break;
+ default: std::cerr << "waka " << op << '\n'; WASM_UNREACHABLE();
+ }
+ }
};
class Binary : public SpecificExpression<Expression::BinaryId> {
@@ -1132,7 +1198,43 @@ public:
// the type is always the type of the operands,
// except for relationals
- bool isRelational() { return op >= Eq; }
+ bool isRelational() {
+ switch (op) {
+ case EqFloat64:
+ case NeFloat64:
+ case LtFloat64:
+ case LeFloat64:
+ case GtFloat64:
+ case GeFloat64:
+ case EqInt32:
+ case NeInt32:
+ case LtSInt32:
+ case LtUInt32:
+ case LeSInt32:
+ case LeUInt32:
+ case GtSInt32:
+ case GtUInt32:
+ case GeSInt32:
+ case GeUInt32:
+ case EqInt64:
+ case NeInt64:
+ case LtSInt64:
+ case LtUInt64:
+ case LeSInt64:
+ case LeUInt64:
+ case GtSInt64:
+ case GtUInt64:
+ case GeSInt64:
+ case GeUInt64:
+ case EqFloat32:
+ case NeFloat32:
+ case LtFloat32:
+ case LeFloat32:
+ case GtFloat32:
+ case GeFloat32: return true;
+ default: return false;
+ }
+ }
void finalize() {
if (isRelational()) {