diff options
-rw-r--r-- | src/asmjs/shared-constants.cpp | 4 | ||||
-rw-r--r-- | src/asmjs/shared-constants.h | 4 | ||||
-rw-r--r-- | src/emscripten-optimizer/simple_ast.h | 15 | ||||
-rw-r--r-- | src/passes/I64ToI32Lowering.cpp | 252 | ||||
-rw-r--r-- | src/tools/wasm2asm.cpp | 3 | ||||
-rw-r--r-- | src/wasm2asm.h | 252 | ||||
-rw-r--r-- | test/wasm2asm.asserts.js | 45 | ||||
-rw-r--r-- | test/wasm2asm.traps.js | 49 | ||||
-rw-r--r-- | test/wasm2asm/conversions-modified.2asm.js | 260 | ||||
-rw-r--r-- | test/wasm2asm/conversions-modified.wast | 419 | ||||
-rw-r--r-- | test/wasm2asm/float-ops.2asm.js | 126 | ||||
-rw-r--r-- | test/wasm2asm/float-ops.wast | 37 |
12 files changed, 1401 insertions, 65 deletions
diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp index c6efe64f9..bf956f173 100644 --- a/src/asmjs/shared-constants.cpp +++ b/src/asmjs/shared-constants.cpp @@ -89,5 +89,7 @@ cashew::IString GLOBAL("global"), WASM_ROTR32("__wasm_rotr_i32"), WASM_ROTR64("__wasm_rotr_i64"), WASM_GROW_MEMORY("__wasm_grow_memory"), - WASM_CURRENT_MEMORY("__wasm_current_memory"); + WASM_CURRENT_MEMORY("__wasm_current_memory"), + WASM_FETCH_HIGH_BITS("__wasm_fetch_high_bits"), + INT64_TO_32_HIGH_BITS("i64toi32_i32$HIGH_BITS"); } diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h index 28142fecc..973b5eb49 100644 --- a/src/asmjs/shared-constants.h +++ b/src/asmjs/shared-constants.h @@ -92,7 +92,9 @@ extern cashew::IString GLOBAL, WASM_ROTR32, WASM_ROTR64, WASM_GROW_MEMORY, - WASM_CURRENT_MEMORY; + WASM_CURRENT_MEMORY, + WASM_FETCH_HIGH_BITS, + INT64_TO_32_HIGH_BITS; } #endif // wasm_asmjs_shared_constants_h diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h index 62bf975f0..64aab7708 100644 --- a/src/emscripten-optimizer/simple_ast.h +++ b/src/emscripten-optimizer/simple_ast.h @@ -836,6 +836,19 @@ struct JSPrinter { } static char* numToString(double d, bool finalize=true) { + if (std::isnan(d)) { + if (std::signbit(d)) { + return (char*) "-NaN"; + } else { + return (char*) "NaN"; + } + } else if (!std::isfinite(d)) { + if (std::signbit(d)) { + return (char*) "-Infinity"; + } else { + return (char*) "Infinity"; + } + } bool neg = d < 0; if (neg) d = -d; // try to emit the fewest necessary characters @@ -1046,6 +1059,8 @@ struct JSPrinter { ensure(1); // we temporarily append a 0 char *curr = buffer + last; // ensure might invalidate buffer[used] = 0; + if (strstr(curr, "Infinity")) return; + if (strstr(curr, "NaN")) return; if (strchr(curr, '.')) return; // already a decimal point, all good char *e = strchr(curr, 'e'); if (!e) { diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index e6da9a1b8..2f6fdf122 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -40,10 +40,10 @@ static Name makeHighName(Name n) { struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { struct TempVar { - TempVar(Index idx, I64ToI32Lowering& pass) : - idx(idx), pass(pass), moved(false) {} + TempVar(Index idx, Type ty, I64ToI32Lowering& pass) : + idx(idx), pass(pass), moved(false), ty(ty) {} - TempVar(TempVar&& other) : idx(other), pass(other.pass), moved(false) { + TempVar(TempVar&& other) : idx(other), pass(other.pass), moved(false), ty(other.ty) { assert(!other.moved); other.moved = true; } @@ -78,18 +78,17 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { private: void freeIdx() { - assert(std::find(pass.freeTemps.begin(), pass.freeTemps.end(), idx) == - pass.freeTemps.end()); - pass.freeTemps.push_back(idx); + auto &freeList = pass.freeTemps[(int) ty]; + assert(std::find(freeList.begin(), freeList.end(), idx) == freeList.end()); + freeList.push_back(idx); } Index idx; I64ToI32Lowering& pass; bool moved; // since C++ will still destruct moved-from values + Type ty; }; - static Name highBitsGlobal; - // false since function types need to be lowered // TODO: allow module-level transformations in parallel passes bool isFunctionParallel() override { return false; } @@ -114,7 +113,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { // to return the high 32 bits. auto* highBits = new Global(); highBits->type = i32; - highBits->name = highBitsGlobal; + highBits->name = INT64_TO_32_HIGH_BITS; highBits->init = builder->makeConst(Literal(int32_t(0))); highBits->mutable_ = true; module->addGlobal(highBits); @@ -159,7 +158,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { BinaryOp secondOp = leftShift ? ShrUInt32 : ShlInt32; Block* equalRotateBlock = builder->blockify( builder->makeSetGlobal( - highBitsGlobal, + INT64_TO_32_HIGH_BITS, builder->makeGetLocal(lowBits, i32) ), builder->makeGetLocal(highBits, i32) @@ -182,7 +181,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ) ), builder->makeSetGlobal( - highBitsGlobal, + INT64_TO_32_HIGH_BITS, builder->makeBinary( OrInt32, builder->makeBinary( @@ -221,7 +220,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ) ), builder->makeSetGlobal( - highBitsGlobal, + INT64_TO_32_HIGH_BITS, builder->makeBinary( OrInt32, builder->makeBinary( @@ -328,18 +327,17 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { func->body ); SetGlobal* setHigh = builder->makeSetGlobal( - highBitsGlobal, + INT64_TO_32_HIGH_BITS, builder->makeGetLocal(highBits, i32) ); GetLocal* getLow = builder->makeGetLocal(lowBits, i32); func->body = builder->blockify(setLow, setHigh, getLow); } } - assert(freeTemps.size() == nextTemp - func->getNumLocals()); int idx = 0; for (size_t i = func->getNumLocals(); i < nextTemp; i++) { Name tmpName("i64toi32_i32$" + std::to_string(idx++)); - builder->addVar(func, tmpName, i32); + builder->addVar(func, tmpName, tempTypes[i]); } } @@ -488,7 +486,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ); SetLocal* setHigh = builder->makeSetLocal( highBits, - builder->makeGetGlobal(highBitsGlobal, i32) + builder->makeGetGlobal(INT64_TO_32_HIGH_BITS, i32) ); GetLocal* getLow = builder->makeGetLocal(lowBits, i32); Block* result = builder->blockify(doCall, setHigh, getLow); @@ -733,15 +731,14 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { void lowerReinterpretFloat64(Unary* curr) { // Assume that the wasm file assumes the address 0 is invalid and roundtrip // our f64 through memory at address 0 - Expression* zero = builder->makeConst(Literal(int32_t(0))); TempVar highBits = getTemp(); Block *result = builder->blockify( - builder->makeStore(8, 0, 8, zero, curr->value, f64), + builder->makeStore(8, 0, 8, builder->makeConst(Literal(int32_t(0))), curr->value, f64), builder->makeSetLocal( highBits, - builder->makeLoad(4, true, 4, 4, zero, i32) + builder->makeLoad(4, true, 4, 4, builder->makeConst(Literal(int32_t(0))), i32) ), - builder->makeLoad(4, true, 0, 4, zero, i32) + builder->makeLoad(4, true, 0, 4, builder->makeConst(Literal(int32_t(0))), i32) ); setOutParam(result, std::move(highBits)); replaceCurrent(result); @@ -751,13 +748,192 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { // Assume that the wasm file assumes the address 0 is invalid and roundtrip // our i64 through memory at address 0 TempVar highBits = fetchOutParam(curr->value); - TempVar lowBits = getTemp(); - Expression* zero = builder->makeConst(Literal(int32_t(0))); Block *result = builder->blockify( - builder->makeStore(4, 0, 4, zero, curr->value, i32), - builder->makeStore(4, 4, 4, zero, builder->makeGetLocal(highBits, i32), i32), - builder->makeLoad(8, true, 0, 8, zero, f64) + builder->makeStore(4, 0, 4, builder->makeConst(Literal(int32_t(0))), curr->value, i32), + builder->makeStore(4, 4, 4, builder->makeConst(Literal(int32_t(0))), builder->makeGetLocal(highBits, i32), i32), + builder->makeLoad(8, true, 0, 8, builder->makeConst(Literal(int32_t(0))), f64) + ); + replaceCurrent(result); + } + + void lowerTruncFloatToInt(Unary *curr) { + // hiBits = if abs(f) >= 1.0 { + // if f > 0.0 { + // (unsigned) min( + // floor(f / (float) U32_MAX), + // (float) U32_MAX - 1, + // ) + // } else { + // (unsigned) ceil((f - (float) (unsigned) f) / ((float) U32_MAX)) + // } + // } else { + // 0 + // } + // + // loBits = (unsigned) f; + + Literal litZero, litOne, u32Max; + UnaryOp trunc, convert, abs, floor, ceil; + Type localType; + BinaryOp ge, gt, min, div, sub; + switch (curr->op) { + case TruncSFloat32ToInt64: + case TruncUFloat32ToInt64: { + litZero = Literal((float) 0); + litOne = Literal((float) 1); + u32Max = Literal(((float) UINT_MAX) + 1); + trunc = TruncUFloat32ToInt32; + convert = ConvertUInt32ToFloat32; + localType = f32; + abs = AbsFloat32; + ge = GeFloat32; + gt = GtFloat32; + min = MinFloat32; + floor = FloorFloat32; + ceil = CeilFloat32; + div = DivFloat32; + sub = SubFloat32; + break; + } + case TruncSFloat64ToInt64: + case TruncUFloat64ToInt64: { + litZero = Literal((double) 0); + litOne = Literal((double) 1); + u32Max = Literal(((double) UINT_MAX) + 1); + trunc = TruncUFloat64ToInt32; + convert = ConvertUInt32ToFloat64; + localType = f64; + abs = AbsFloat64; + ge = GeFloat64; + gt = GtFloat64; + min = MinFloat64; + floor = FloorFloat64; + ceil = CeilFloat64; + div = DivFloat64; + sub = SubFloat64; + break; + } + default: abort(); + } + + TempVar f = getTemp(localType); + TempVar highBits = getTemp(); + + Expression *gtZeroBranch = builder->makeBinary( + min, + builder->makeUnary( + floor, + builder->makeBinary( + div, + builder->makeGetLocal(f, localType), + builder->makeConst(u32Max) + ) + ), + builder->makeBinary(sub, builder->makeConst(u32Max), builder->makeConst(litOne)) + ); + Expression *ltZeroBranch = builder->makeUnary( + ceil, + builder->makeBinary( + div, + builder->makeBinary( + sub, + builder->makeGetLocal(f, localType), + builder->makeUnary(convert, + builder->makeUnary(trunc, builder->makeGetLocal(f, localType)) + ) + ), + builder->makeConst(u32Max) + ) + ); + + If *highBitsCalc = builder->makeIf( + builder->makeBinary( + gt, + builder-> makeGetLocal(f, localType), + builder->makeConst(litZero) + ), + builder->makeUnary(trunc, gtZeroBranch), + builder->makeUnary(trunc, ltZeroBranch) + ); + If *highBitsVal = builder->makeIf( + builder->makeBinary( + ge, + builder->makeUnary(abs, builder->makeGetLocal(f, localType)), + builder->makeConst(litOne) + ), + highBitsCalc, + builder->makeConst(Literal(int32_t(0))) + ); + Block *result = builder->blockify( + builder->makeSetLocal(f, curr->value), + builder->makeSetLocal(highBits, highBitsVal), + builder->makeUnary(trunc, builder->makeGetLocal(f, localType)) + ); + setOutParam(result, std::move(highBits)); + replaceCurrent(result); + } + + void lowerConvertIntToFloat(Unary *curr) { + // Here the same strategy as `emcc` is taken which takes the two halves of + // the 64-bit integer and creates a mathematical expression using float + // arithmetic to reassemble the final floating point value. + // + // For example for i64 -> f32 we generate: + // + // ((double) (unsigned) lowBits) + ((double) U32_MAX) * ((double) (int) highBits) + // + // Mostly just shuffling things around here with coercions and whatnot! + // Note though that all arithmetic is done with f64 to have as much + // precision as we can. + TempVar highBits = fetchOutParam(curr->value); + TempVar lowBits = getTemp(); + TempVar highResult = getTemp(); + + UnaryOp convertHigh; + switch (curr->op) { + case ConvertSInt64ToFloat32: + case ConvertSInt64ToFloat64: + convertHigh = ConvertSInt32ToFloat64; + break; + case ConvertUInt64ToFloat32: + case ConvertUInt64ToFloat64: + convertHigh = ConvertUInt32ToFloat64; + break; + default: abort(); + } + + Expression *result = builder->blockify( + builder->makeSetLocal(lowBits, curr->value), + builder->makeSetLocal( + highResult, + builder->makeConst(Literal(int32_t(0))) + ), + builder->makeBinary( + AddFloat64, + builder->makeUnary( + ConvertUInt32ToFloat64, + builder->makeGetLocal(lowBits, i32) + ), + builder->makeBinary( + MulFloat64, + builder->makeConst(Literal((double)UINT_MAX + 1)), + builder->makeUnary( + convertHigh, + builder->makeGetLocal(highBits, i32) + ) + ) + ) ); + + switch (curr->op) { + case ConvertSInt64ToFloat32: + case ConvertUInt64ToFloat32: { + result = builder->makeUnary(DemoteFloat64, result); + break; + } + default: break; + } + replaceCurrent(result); } @@ -889,11 +1065,11 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { case TruncSFloat32ToInt64: case TruncUFloat32ToInt64: case TruncSFloat64ToInt64: - case TruncUFloat64ToInt64: + case TruncUFloat64ToInt64: lowerTruncFloatToInt(curr); break; case ConvertSInt64ToFloat32: case ConvertSInt64ToFloat64: case ConvertUInt64ToFloat32: - case ConvertUInt64ToFloat64: + case ConvertUInt64ToFloat64: lowerConvertIntToFloat(curr); break; default: std::cerr << "Unhandled unary operator: " << curr->op << std::endl; abort(); @@ -1386,7 +1562,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ), builder->makeSetLocal( rightHigh, - builder->makeGetGlobal(highBitsGlobal, i32) + builder->makeGetGlobal(INT64_TO_32_HIGH_BITS, i32) ), builder->makeGetLocal(lowResult, i32) ); @@ -1680,7 +1856,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { TempVar highBits = fetchOutParam(curr->value); SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value); SetGlobal* setHigh = builder->makeSetGlobal( - highBitsGlobal, + INT64_TO_32_HIGH_BITS, builder->makeGetLocal(highBits, i32) ); curr->value = builder->makeGetLocal(lowBits, i32); @@ -1693,20 +1869,24 @@ private: std::unordered_map<Index, Index> indexMap; std::unordered_map<Expression*, TempVar> highBitVars; std::unordered_map<Name, TempVar> labelHighBitVars; - std::vector<Index> freeTemps; + std::unordered_map<int, std::vector<Index>> freeTemps; + std::unordered_map<Index, Type> tempTypes; Index nextTemp; bool needRotl64 = false; bool needRotr64 = false; - TempVar getTemp() { + TempVar getTemp(Type ty = i32) { Index ret; - if (freeTemps.size() > 0) { - ret = freeTemps.back(); - freeTemps.pop_back(); + auto &freeList = freeTemps[(int) ty]; + if (freeList.size() > 0) { + ret = freeList.back(); + freeList.pop_back(); } else { ret = nextTemp++; + tempTypes[ret] = ty; } - return TempVar(ret, *this); + assert(tempTypes[ret] == ty); + return TempVar(ret, ty, *this); } bool hasOutParam(Expression* e) { @@ -1726,8 +1906,6 @@ private: } }; -Name I64ToI32Lowering::highBitsGlobal("i64toi32_i32$HIGH_BITS"); - Pass *createI64ToI32LoweringPass() { return new I64ToI32Lowering(); } diff --git a/src/tools/wasm2asm.cpp b/src/tools/wasm2asm.cpp index cc53dc834..2251a332c 100644 --- a/src/tools/wasm2asm.cpp +++ b/src/tools/wasm2asm.cpp @@ -39,7 +39,8 @@ int main(int argc, const char *argv[]) { }) .add("--allow-asserts", "", "Allow compilation of .wast testing asserts", Options::Arguments::Zero, - [](Options* o, const std::string& argument) { + [&](Options* o, const std::string& argument) { + builderFlags.allowAsserts = true; o->extra["asserts"] = "1"; }) .add("--pedantic", "", "Emulate WebAssembly trapping behavior", diff --git a/src/wasm2asm.h b/src/wasm2asm.h index 9e3abaa25..8dd569d82 100644 --- a/src/wasm2asm.h +++ b/src/wasm2asm.h @@ -114,6 +114,7 @@ public: struct Flags { bool debug = false; bool pedantic = false; + bool allowAsserts = false; }; Wasm2AsmBuilder(Flags f) : flags(f) {} @@ -213,6 +214,9 @@ private: Ref makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, Builder& wasmBuilder, Element& e, Name testFuncName); + Ref makeAssertReturnNanFunc(SExpressionWasmBuilder& sexpBuilder, + Builder& wasmBuilder, + Element& e, Name testFuncName); Ref makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder, Builder& wasmBuilder, Element& e, Name testFuncName); @@ -416,13 +420,35 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm) { } tableSize = pow2ed; // globals + bool generateFetchHighBits = false; for (auto& global : wasm->globals) { addGlobal(asmFunc[3], global.get()); + if (flags.allowAsserts && global->name == INT64_TO_32_HIGH_BITS) { + generateFetchHighBits = true; + } } // functions for (auto& func : wasm->functions) { asmFunc[3]->push_back(processFunction(func.get())); } + if (generateFetchHighBits) { + Builder builder(allocator); + std::vector<Type> params; + std::vector<Type> vars; + asmFunc[3]->push_back(processFunction(builder.makeFunction( + WASM_FETCH_HIGH_BITS, + std::move(params), + i32, + std::move(vars), + builder.makeGetGlobal(INT64_TO_32_HIGH_BITS, i32) + ))); + auto e = new Export(); + e->name = WASM_FETCH_HIGH_BITS; + e->value = WASM_FETCH_HIGH_BITS; + e->kind = ExternalKind::Function; + wasm->addExport(e); + } + addTables(asmFunc[3], wasm); // memory XXX addExports(asmFunc[3], wasm); @@ -1320,6 +1346,18 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { Ref visitConst(Const* curr) { switch (curr->type) { case i32: return ValueBuilder::makeInt(curr->value.geti32()); + // An i64 argument translates to two actual arguments to asm.js + // functions, so we do a bit of a hack here to get our one `Ref` to look + // like two function arguments. + case i64: { + unsigned lo = (unsigned) curr->value.geti64(); + unsigned hi = (unsigned) (curr->value.geti64() >> 32); + std::ostringstream out; + out << lo << "," << hi; + std::string os = out.str(); + IString name(os.c_str(), false); + return ValueBuilder::makeName(name); + } case f32: { Ref ret = ValueBuilder::makeCall(MATH_FROUND); Const fake(allocator); @@ -1393,6 +1431,31 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32), zero) ); } + // generate (~~expr), what Emscripten does + case TruncSFloat32ToInt32: + case TruncSFloat64ToInt32: + return ValueBuilder::makeUnary( + B_NOT, + ValueBuilder::makeUnary( + B_NOT, + visit(curr->value, EXPRESSION_RESULT) + )); + + // generate (~~expr >>> 0), what Emscripten does + case TruncUFloat32ToInt32: + case TruncUFloat64ToInt32: + return ValueBuilder::makeBinary( + ValueBuilder::makeUnary( + B_NOT, + ValueBuilder::makeUnary( + B_NOT, + visit(curr->value, EXPRESSION_RESULT) + ) + ), + TRSHIFT, + ValueBuilder::makeNum(0) + ); + default: { std::cerr << "Unhandled unary i32 operator: " << curr << std::endl; @@ -1470,6 +1533,37 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32), zero) ); } + // Coerce the integer to a float as emscripten does + case ConvertSInt32ToFloat32: + return makeAsmCoercion( + makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), ASM_INT), + ASM_FLOAT + ); + case ConvertSInt32ToFloat64: + return makeAsmCoercion( + makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), ASM_INT), + ASM_DOUBLE + ); + + // Generate (expr >>> 0), followed by a coercion + case ConvertUInt32ToFloat32: + return makeAsmCoercion( + ValueBuilder::makeBinary( + visit(curr->value, EXPRESSION_RESULT), + TRSHIFT, + ValueBuilder::makeInt(0) + ), + ASM_FLOAT + ); + case ConvertUInt32ToFloat64: + return makeAsmCoercion( + ValueBuilder::makeBinary( + visit(curr->value, EXPRESSION_RESULT), + TRSHIFT, + ValueBuilder::makeInt(0) + ), + ASM_DOUBLE + ); // TODO: more complex unary conversions default: std::cerr << "Unhandled unary float operator: " << curr @@ -1756,7 +1850,36 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { return ExpressionProcessor(this, func).visit(func->body, result); } -static Ref makeInstantiation() { +static void makeInstantiation(Ref ret) { + // var __array_buffer = new ArrayBuffer(..) + Ref mem = ValueBuilder::makeNew( + ValueBuilder::makeCall(ARRAY_BUFFER, ValueBuilder::makeInt(0x10000))); + Ref arrayBuffer = ValueBuilder::makeVar(); + Name buffer("__array_buffer"); + ValueBuilder::appendToVar(arrayBuffer, buffer, mem); + flattenAppend(ret, arrayBuffer); + + // var HEAP32 = new Int32Array(__array_buffer); + Ref heap32Array = ValueBuilder::makeNew( + ValueBuilder::makeCall(INT32ARRAY, ValueBuilder::makeName(buffer))); + Ref heap32 = ValueBuilder::makeVar(); + ValueBuilder::appendToVar(heap32, HEAP32, heap32Array); + flattenAppend(ret, heap32); + + // var HEAPF32 = new Float32Array(__array_buffer); + Ref heapf32Array = ValueBuilder::makeNew( + ValueBuilder::makeCall(FLOAT32ARRAY, ValueBuilder::makeName(buffer))); + Ref heapf32 = ValueBuilder::makeVar(); + ValueBuilder::appendToVar(heapf32, HEAPF32, heapf32Array); + flattenAppend(ret, heapf32); + + // var HEAPF64 = new Float64Array(__array_buffer); + Ref heapf64Array = ValueBuilder::makeNew( + ValueBuilder::makeCall(FLOAT64ARRAY, ValueBuilder::makeName(buffer))); + Ref heapf64 = ValueBuilder::makeVar(); + ValueBuilder::appendToVar(heapf64, HEAPF64, heapf64Array); + flattenAppend(ret, heapf64); + Ref lib = ValueBuilder::makeObject(); auto insertItem = [&](IString item) { ValueBuilder::appendToObject(lib, item, ValueBuilder::makeName(item)); @@ -1771,12 +1894,56 @@ static Ref makeInstantiation() { insertItem(FLOAT32ARRAY); insertItem(FLOAT64ARRAY); Ref env = ValueBuilder::makeObject(); - Ref mem = ValueBuilder::makeNew( - ValueBuilder::makeCall(ARRAY_BUFFER, ValueBuilder::makeInt(0x10000))); - Ref call = ValueBuilder::makeCall(IString(ASM_FUNC), lib, env, mem); - Ref ret = ValueBuilder::makeVar(); - ValueBuilder::appendToVar(ret, ASM_MODULE, call); - return ret; + Ref call = ValueBuilder::makeCall(IString(ASM_FUNC), lib, env, + ValueBuilder::makeName(buffer)); + Ref module = ValueBuilder::makeVar(); + ValueBuilder::appendToVar(module, ASM_MODULE, call); + flattenAppend(ret, module); + + // When equating floating point values in spec tests we want to use bitwise + // equality like wasm does. Unfortunately though NaN makes this tricky. JS + // implementations like Spidermonkey and JSC will canonicalize NaN loads from + // `Float32Array`, but V8 will not. This means that NaN representations are + // kind of all over the place and difficult to bitwise equate. + // + // To work around this problem we just use a small shim which considers all + // NaN representations equivalent and otherwise tests for bitwise equality. + flattenAppend(ret, ValueBuilder::makeName(R"( + function f32Equal(a, b) { + var i = new Int32Array(1); + var f = new Float32Array(i.buffer); + f[0] = a; + var ai = f[0]; + f[0] = b; + var bi = f[0]; + + return (isNaN(a) && isNaN(b)) || a == b; + } + )")); + flattenAppend(ret, ValueBuilder::makeName(R"( + function f64Equal(a, b) { + var i = new Int32Array(2); + var f = new Float64Array(i.buffer); + f[0] = a; + var ai1 = f[0]; + var ai2 = f[1]; + f[0] = b; + var bi1 = f[0]; + var bi2 = f[1]; + + return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2); + } + )")); + + // 64-bit numbers get a different ABI w/ wasm2asm, and in general you can't + // actually export them from wasm at the boundary. We hack around this though + // to get the spec tests working. + flattenAppend(ret, ValueBuilder::makeName(R"( + function i64Equal(actual_lo, expected_lo, expected_hi) { + return actual_lo == (expected_lo | 0) && + asmModule.__wasm_fetch_high_bits() == (expected_hi | 0); + } + )")); } static void prefixCalls(Ref asmjs) { @@ -1787,11 +1954,25 @@ static void prefixCalls(Ref asmjs) { } if (arr.size() > 0 && arr[0]->isString() && arr[0]->getIString() == CALL) { assert(arr.size() >= 2); - Ref prefixed = ValueBuilder::makeDot(ValueBuilder::makeName(ASM_MODULE), - arr[1]->getIString()); - arr[1]->setArray(prefixed->getArray()); + if (arr[1]->getIString() == "f32Equal" || + arr[1]->getIString() == "f64Equal" || + arr[1]->getIString() == "i64Equal") { + // ... + } else if (arr[1]->getIString() == "Math_fround") { + arr[1]->setString("Math.fround"); + } else { + Name name = arr[1]->getIString() == "isNaN" ? "Math" : ASM_MODULE; + Ref prefixed = ValueBuilder::makeDot(ValueBuilder::makeName(name), + arr[1]->getIString()); + arr[1]->setArray(prefixed->getArray()); + } } } + + if (asmjs->isAssign()) { + prefixCalls(asmjs->asAssign()->target()); + prefixCalls(asmjs->asAssign()->value()); + } } Ref Wasm2AsmBuilder::makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, @@ -1812,18 +1993,29 @@ Ref Wasm2AsmBuilder::makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, Expression* expected = sexpBuilder.parseExpression(e[2]); Type resType = expected->type; actual->type = resType; - BinaryOp eqOp; switch (resType) { - case i32: eqOp = EqInt32; break; - case i64: eqOp = EqInt64; break; - case f32: eqOp = EqFloat32; break; - case f64: eqOp = EqFloat64; break; + case i32: + body = wasmBuilder.makeBinary(EqInt32, actual, expected); + break; + + case i64: + body = wasmBuilder.makeCall("i64Equal", {actual, expected}, i32); + break; + + case f32: { + body = wasmBuilder.makeCall("f32Equal", {actual, expected}, i32); + break; + } + case f64: { + body = wasmBuilder.makeCall("f64Equal", {actual, expected}, i32); + break; + } + default: { std::cerr << "Unhandled type in assert: " << resType << std::endl; abort(); } } - body = wasmBuilder.makeBinary(eqOp, actual, expected); } else { assert(false && "Unexpected number of parameters in assert_return"); } @@ -1841,6 +2033,25 @@ Ref Wasm2AsmBuilder::makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, return jsFunc; } +Ref Wasm2AsmBuilder::makeAssertReturnNanFunc(SExpressionWasmBuilder& sexpBuilder, + Builder& wasmBuilder, + Element& e, Name testFuncName) { + Expression* actual = sexpBuilder.parseExpression(e[1]); + Expression* body = wasmBuilder.makeCallImport("isNaN", {actual}, i32); + std::unique_ptr<Function> testFunc( + wasmBuilder.makeFunction( + testFuncName, + std::vector<NameType>{}, + body->type, + std::vector<NameType>{}, + body + ) + ); + Ref jsFunc = processFunction(testFunc.get()); + prefixCalls(jsFunc); + return jsFunc; +} + Ref Wasm2AsmBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder, Builder& wasmBuilder, Element& e, Name testFuncName) { @@ -1855,6 +2066,7 @@ Ref Wasm2AsmBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder, ); IString expectedErr = e[2]->str(); Ref innerFunc = processFunction(exprFunc.get()); + prefixCalls(innerFunc); Ref outerFunc = ValueBuilder::makeFunction(testFuncName); outerFunc[3]->push_back(innerFunc); Ref tryBlock = ValueBuilder::makeBlock(); @@ -2042,6 +2254,7 @@ void Wasm2AsmBuilder::addMemoryGrowthFuncs(Ref ast) { bool Wasm2AsmBuilder::isAssertHandled(Element& e) { return e.isList() && e.size() >= 2 && e[0]->isStr() && (e[0]->str() == Name("assert_return") || + e[0]->str() == Name("assert_return_nan") || (flags.pedantic && e[0]->str() == Name("assert_trap"))) && e[1]->isList() && e[1]->size() >= 2 && (*e[1])[0]->isStr() && (*e[1])[0]->str() == Name("invoke"); @@ -2051,7 +2264,7 @@ Ref Wasm2AsmBuilder::processAsserts(Element& root, SExpressionWasmBuilder& sexpBuilder) { Builder wasmBuilder(sexpBuilder.getAllocator()); Ref ret = ValueBuilder::makeBlock(); - flattenAppend(ret, makeInstantiation()); + makeInstantiation(ret); for (size_t i = 1; i < root.size(); ++i) { Element& e = *root[i]; if (!isAssertHandled(e)) { @@ -2060,6 +2273,7 @@ Ref Wasm2AsmBuilder::processAsserts(Element& root, } Name testFuncName(IString(("check" + std::to_string(i)).c_str(), false)); bool isReturn = (e[0]->str() == Name("assert_return")); + bool isReturnNan = (e[0]->str() == Name("assert_return_nan")); Element& testOp = *e[1]; // Replace "invoke" with "call" testOp[0]->setString(IString("call"), false, false); @@ -2068,7 +2282,9 @@ Ref Wasm2AsmBuilder::processAsserts(Element& root, Ref testFunc = isReturn ? makeAssertReturnFunc(sexpBuilder, wasmBuilder, e, testFuncName) : - makeAssertTrapFunc(sexpBuilder, wasmBuilder, e, testFuncName); + (isReturnNan ? + makeAssertReturnNanFunc(sexpBuilder, wasmBuilder, e, testFuncName) : + makeAssertTrapFunc(sexpBuilder, wasmBuilder, e, testFuncName)); flattenAppend(ret, testFunc); std::stringstream failFuncName; diff --git a/test/wasm2asm.asserts.js b/test/wasm2asm.asserts.js index 0b347b02c..a79b4dc7a 100644 --- a/test/wasm2asm.asserts.js +++ b/test/wasm2asm.asserts.js @@ -70,13 +70,22 @@ function asmFunc(global, env, buffer) { return ((4294967295 << (k & 31 | 0) | 0) & x | 0) >>> (k & 31 | 0) | 0 | (((4294967295 >>> (32 - (k & 31 | 0) | 0) | 0) & x | 0) << (32 - (k & 31 | 0) | 0) | 0) | 0 | 0; } + function __wasm_fetch_high_bits() { + return i64toi32_i32$HIGH_BITS | 0; + } + return { empty: $0, add: $1, - div_s: $2 + div_s: $2, + __wasm_fetch_high_bits: __wasm_fetch_high_bits }; } +var __array_buffer = new ArrayBuffer(65536); +var HEAP32 = new Int32Array(__array_buffer); +var HEAPF32 = new Float32Array(__array_buffer); +var HEAPF64 = new Float64Array(__array_buffer); var asmModule = asmFunc({ Math: Math, Int8Array: Int8Array, @@ -89,7 +98,39 @@ var asmModule = asmFunc({ Float64Array: Float64Array }, { -}, new ArrayBuffer(65536)); +}, __array_buffer); + + function f32Equal(a, b) { + var i = new Int32Array(1); + var f = new Float32Array(i.buffer); + f[0] = a; + var ai = f[0]; + f[0] = b; + var bi = f[0]; + + return (isNaN(a) && isNaN(b)) || a == b; + } + ; + + function f64Equal(a, b) { + var i = new Int32Array(2); + var f = new Float64Array(i.buffer); + f[0] = a; + var ai1 = f[0]; + var ai2 = f[1]; + f[0] = b; + var bi1 = f[0]; + var bi2 = f[1]; + + return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2); + } + ; + + function i64Equal(actual_lo, expected_lo, expected_hi) { + return actual_lo == (expected_lo | 0) && + asmModule.__wasm_fetch_high_bits() == (expected_hi | 0); + } + ; function check1() { var wasm2asm_i32$0 = 0; asmModule.empty(); diff --git a/test/wasm2asm.traps.js b/test/wasm2asm.traps.js index 45a04f4f1..cc16410f1 100644 --- a/test/wasm2asm.traps.js +++ b/test/wasm2asm.traps.js @@ -70,13 +70,22 @@ function asmFunc(global, env, buffer) { return ((4294967295 << (k & 31 | 0) | 0) & x | 0) >>> (k & 31 | 0) | 0 | (((4294967295 >>> (32 - (k & 31 | 0) | 0) | 0) & x | 0) << (32 - (k & 31 | 0) | 0) | 0) | 0 | 0; } + function __wasm_fetch_high_bits() { + return i64toi32_i32$HIGH_BITS | 0; + } + return { empty: $0, add: $1, - div_s: $2 + div_s: $2, + __wasm_fetch_high_bits: __wasm_fetch_high_bits }; } +var __array_buffer = new ArrayBuffer(65536); +var HEAP32 = new Int32Array(__array_buffer); +var HEAPF32 = new Float32Array(__array_buffer); +var HEAPF64 = new Float64Array(__array_buffer); var asmModule = asmFunc({ Math: Math, Int8Array: Int8Array, @@ -89,7 +98,39 @@ var asmModule = asmFunc({ Float64Array: Float64Array }, { -}, new ArrayBuffer(65536)); +}, __array_buffer); + + function f32Equal(a, b) { + var i = new Int32Array(1); + var f = new Float32Array(i.buffer); + f[0] = a; + var ai = f[0]; + f[0] = b; + var bi = f[0]; + + return (isNaN(a) && isNaN(b)) || a == b; + } + ; + + function f64Equal(a, b) { + var i = new Int32Array(2); + var f = new Float64Array(i.buffer); + f[0] = a; + var ai1 = f[0]; + var ai2 = f[1]; + f[0] = b; + var bi1 = f[0]; + var bi2 = f[1]; + + return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2); + } + ; + + function i64Equal(actual_lo, expected_lo, expected_hi) { + return actual_lo == (expected_lo | 0) && + asmModule.__wasm_fetch_high_bits() == (expected_hi | 0); + } + ; function check1() { var wasm2asm_i32$0 = 0; asmModule.empty(); @@ -105,7 +146,7 @@ function check2() { if (!check2()) fail2(); function check3() { function f() { - div_s(0 | 0, 0 | 0); + asmModule.div_s(0 | 0, 0 | 0); } try { @@ -119,7 +160,7 @@ function check3() { if (!check3()) fail3(); function check4() { function f() { - div_s(2147483648 | 0, 4294967295 | 0); + asmModule.div_s(2147483648 | 0, 4294967295 | 0); } try { diff --git a/test/wasm2asm/conversions-modified.2asm.js b/test/wasm2asm/conversions-modified.2asm.js new file mode 100644 index 000000000..89c52e3a5 --- /dev/null +++ b/test/wasm2asm/conversions-modified.2asm.js @@ -0,0 +1,260 @@ +function asmFunc(global, env, buffer) { + "use asm"; + var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); + var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); + var HEAPF64 = new global.Float64Array(buffer); + var Math_imul = global.Math.imul; + var Math_fround = global.Math.fround; + var Math_abs = global.Math.abs; + var Math_clz32 = global.Math.clz32; + var Math_min = global.Math.min; + var Math_max = global.Math.max; + var Math_floor = global.Math.floor; + var Math_ceil = global.Math.ceil; + var Math_sqrt = global.Math.sqrt; + var i64toi32_i32$HIGH_BITS = 0; + function $0(x) { + x = x | 0; + var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0; + i64toi32_i32$1 = x; + i64toi32_i32$0 = i64toi32_i32$1 >> 31 | 0; + i64toi32_i32$1 = i64toi32_i32$1; + i64toi32_i32$HIGH_BITS = i64toi32_i32$0; + return i64toi32_i32$1 | 0; + } + + function $1(x) { + x = x | 0; + i64toi32_i32$HIGH_BITS = 0; + return x | 0; + } + + function $2(x, x$hi) { + x = x | 0; + x$hi = x$hi | 0; + return x | 0; + } + + function $3(x) { + x = Math_fround(x); + return ~~x | 0; + } + + function $4(x) { + x = Math_fround(x); + return ~~x >>> 0 | 0; + } + + function $5(x) { + x = +x; + return ~~x | 0; + } + + function $6(x) { + x = +x; + return ~~x >>> 0 | 0; + } + + function $7(x) { + x = Math_fround(x); + var i64toi32_i32$0 = Math_fround(0), $2 = 0, $3 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { + if (i64toi32_i32$0 > Math_fround(0.0)) $2 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0; else $2 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0; + $3 = $2; + } else $3 = 0; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; + i64toi32_i32$HIGH_BITS = $3; + return i64toi32_i32$2 | 0; + } + + function $8(x) { + x = Math_fround(x); + var i64toi32_i32$0 = Math_fround(0), $2 = 0, $3 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { + if (i64toi32_i32$0 > Math_fround(0.0)) $2 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0; else $2 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0; + $3 = $2; + } else $3 = 0; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; + i64toi32_i32$HIGH_BITS = $3; + return i64toi32_i32$2 | 0; + } + + function $9(x) { + x = +x; + var i64toi32_i32$0 = 0.0, $2 = 0, $3 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_abs(i64toi32_i32$0) >= 1.0) { + if (i64toi32_i32$0 > 0.0) $2 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0; else $2 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0; + $3 = $2; + } else $3 = 0; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; + i64toi32_i32$HIGH_BITS = $3; + return i64toi32_i32$2 | 0; + } + + function $10(x) { + x = +x; + var i64toi32_i32$0 = 0.0, $2 = 0, $3 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_abs(i64toi32_i32$0) >= 1.0) { + if (i64toi32_i32$0 > 0.0) $2 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0; else $2 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0; + $3 = $2; + } else $3 = 0; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; + i64toi32_i32$HIGH_BITS = $3; + return i64toi32_i32$2 | 0; + } + + function $11(x) { + x = x | 0; + return Math_fround(Math_fround(x | 0)); + } + + function $12(x, x$hi) { + x = x | 0; + x$hi = x$hi | 0; + return Math_fround(Math_fround(+(x >>> 0) + 4294967296.0 * +(x$hi | 0))); + } + + function $13(x) { + x = x | 0; + return +(+(x | 0)); + } + + function $14(x, x$hi) { + x = x | 0; + x$hi = x$hi | 0; + return +(+(x >>> 0) + 4294967296.0 * +(x$hi | 0)); + } + + function $15(x) { + x = x | 0; + return Math_fround(Math_fround(x >>> 0)); + } + + function $16(x, x$hi) { + x = x | 0; + x$hi = x$hi | 0; + return Math_fround(Math_fround(+(x >>> 0) + 4294967296.0 * +(x$hi >>> 0))); + } + + function $17(x) { + x = x | 0; + return +(+(x >>> 0)); + } + + function $18(x, x$hi) { + x = x | 0; + x$hi = x$hi | 0; + return +(+(x >>> 0) + 4294967296.0 * +(x$hi >>> 0)); + } + + function $19(x) { + x = Math_fround(x); + return +(+x); + } + + function $20(x) { + x = +x; + return Math_fround(Math_fround(x)); + } + + function $21(x) { + x = x | 0; + return Math_fround((HEAP32[0] = x, HEAPF32[0])); + } + + function $22(x, x$hi) { + x = x | 0; + x$hi = x$hi | 0; + HEAP32[0 >> 2] = x; + HEAP32[(0 + 4 | 0) >> 2] = x$hi; + return +(+HEAPF64[0 >> 3]); + } + + function $23(x) { + x = Math_fround(x); + return (HEAPF32[0] = x, HEAP32[0]) | 0; + } + + function $24(x) { + x = +x; + var i64toi32_i32$1 = 0; + HEAPF64[0 >> 3] = x; + i64toi32_i32$1 = HEAP32[0 >> 2] | 0; + i64toi32_i32$HIGH_BITS = HEAP32[(0 + 4 | 0) >> 2] | 0; + return i64toi32_i32$1 | 0; + } + + function __wasm_ctz_i32(x) { + x = x | 0; + var $1 = 0; + if ((x | 0) == (0 | 0)) $1 = 32; else $1 = 31 - Math_clz32(x ^ (x - 1 | 0) | 0) | 0; + return $1 | 0; + } + + function __wasm_popcnt_i32(x) { + x = x | 0; + var count = 0, $2 = 0; + count = 0; + b : { + l : do { + $2 = count; + if ((x | 0) == (0 | 0)) break b; + x = x & (x - 1 | 0) | 0; + count = count + 1 | 0; + continue l; + break l; + } while (1); + }; + return $2 | 0; + } + + function __wasm_rotl_i32(x, k) { + x = x | 0; + k = k | 0; + return ((4294967295 >>> (k & 31 | 0) | 0) & x | 0) << (k & 31 | 0) | 0 | (((4294967295 << (32 - (k & 31 | 0) | 0) | 0) & x | 0) >>> (32 - (k & 31 | 0) | 0) | 0) | 0 | 0; + } + + function __wasm_rotr_i32(x, k) { + x = x | 0; + k = k | 0; + return ((4294967295 << (k & 31 | 0) | 0) & x | 0) >>> (k & 31 | 0) | 0 | (((4294967295 >>> (32 - (k & 31 | 0) | 0) | 0) & x | 0) << (32 - (k & 31 | 0) | 0) | 0) | 0 | 0; + } + + return { + i64_extend_s_i32: $0, + i64_extend_u_i32: $1, + i32_wrap_i64: $2, + i32_trunc_s_f32: $3, + i32_trunc_u_f32: $4, + i32_trunc_s_f64: $5, + i32_trunc_u_f64: $6, + i64_trunc_s_f32: $7, + i64_trunc_u_f32: $8, + i64_trunc_s_f64: $9, + i64_trunc_u_f64: $10, + f32_convert_s_i32: $11, + f32_convert_s_i64: $12, + f64_convert_s_i32: $13, + f64_convert_s_i64: $14, + f32_convert_u_i32: $15, + f32_convert_u_i64: $16, + f64_convert_u_i32: $17, + f64_convert_u_i64: $18, + f64_promote_f32: $19, + f32_demote_f64: $20, + f32_reinterpret_i32: $21, + f64_reinterpret_i64: $22, + i32_reinterpret_f32: $23, + i64_reinterpret_f64: $24 + }; +} + diff --git a/test/wasm2asm/conversions-modified.wast b/test/wasm2asm/conversions-modified.wast new file mode 100644 index 000000000..4e410032b --- /dev/null +++ b/test/wasm2asm/conversions-modified.wast @@ -0,0 +1,419 @@ +(module + (func (export "i64.extend_s_i32") (param $x i32) (result i64) (i64.extend_s/i32 (get_local $x))) + (func (export "i64.extend_u_i32") (param $x i32) (result i64) (i64.extend_u/i32 (get_local $x))) + (func (export "i32.wrap_i64") (param $x i64) (result i32) (i32.wrap/i64 (get_local $x))) + (func (export "i32.trunc_s_f32") (param $x f32) (result i32) (i32.trunc_s/f32 (get_local $x))) + (func (export "i32.trunc_u_f32") (param $x f32) (result i32) (i32.trunc_u/f32 (get_local $x))) + (func (export "i32.trunc_s_f64") (param $x f64) (result i32) (i32.trunc_s/f64 (get_local $x))) + (func (export "i32.trunc_u_f64") (param $x f64) (result i32) (i32.trunc_u/f64 (get_local $x))) + (func (export "i64.trunc_s_f32") (param $x f32) (result i64) (i64.trunc_s/f32 (get_local $x))) + (func (export "i64.trunc_u_f32") (param $x f32) (result i64) (i64.trunc_u/f32 (get_local $x))) + (func (export "i64.trunc_s_f64") (param $x f64) (result i64) (i64.trunc_s/f64 (get_local $x))) + (func (export "i64.trunc_u_f64") (param $x f64) (result i64) (i64.trunc_u/f64 (get_local $x))) + (func (export "f32.convert_s_i32") (param $x i32) (result f32) (f32.convert_s/i32 (get_local $x))) + (func (export "f32.convert_s_i64") (param $x i64) (result f32) (f32.convert_s/i64 (get_local $x))) + (func (export "f64.convert_s_i32") (param $x i32) (result f64) (f64.convert_s/i32 (get_local $x))) + (func (export "f64.convert_s_i64") (param $x i64) (result f64) (f64.convert_s/i64 (get_local $x))) + (func (export "f32.convert_u_i32") (param $x i32) (result f32) (f32.convert_u/i32 (get_local $x))) + (func (export "f32.convert_u_i64") (param $x i64) (result f32) (f32.convert_u/i64 (get_local $x))) + (func (export "f64.convert_u_i32") (param $x i32) (result f64) (f64.convert_u/i32 (get_local $x))) + (func (export "f64.convert_u_i64") (param $x i64) (result f64) (f64.convert_u/i64 (get_local $x))) + (func (export "f64.promote_f32") (param $x f32) (result f64) (f64.promote/f32 (get_local $x))) + (func (export "f32.demote_f64") (param $x f64) (result f32) (f32.demote/f64 (get_local $x))) + (func (export "f32.reinterpret_i32") (param $x i32) (result f32) (f32.reinterpret/i32 (get_local $x))) + (func (export "f64.reinterpret_i64") (param $x i64) (result f64) (f64.reinterpret/i64 (get_local $x))) + (func (export "i32.reinterpret_f32") (param $x f32) (result i32) (i32.reinterpret/f32 (get_local $x))) + (func (export "i64.reinterpret_f64") (param $x f64) (result i64) (i64.reinterpret/f64 (get_local $x))) +) + +(assert_return (invoke "i64.extend_s_i32" (i32.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend_s_i32" (i32.const 10000)) (i64.const 10000)) +(assert_return (invoke "i64.extend_s_i32" (i32.const -10000)) (i64.const -10000)) +(assert_return (invoke "i64.extend_s_i32" (i32.const -1)) (i64.const -1)) +(assert_return (invoke "i64.extend_s_i32" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff)) +(assert_return (invoke "i64.extend_s_i32" (i32.const 0x80000000)) (i64.const 0xffffffff80000000)) + +(assert_return (invoke "i64.extend_u_i32" (i32.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend_u_i32" (i32.const 10000)) (i64.const 10000)) +(assert_return (invoke "i64.extend_u_i32" (i32.const -10000)) (i64.const 0x00000000ffffd8f0)) +(assert_return (invoke "i64.extend_u_i32" (i32.const -1)) (i64.const 0xffffffff)) +(assert_return (invoke "i64.extend_u_i32" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff)) +(assert_return (invoke "i64.extend_u_i32" (i32.const 0x80000000)) (i64.const 0x0000000080000000)) + +(assert_return (invoke "i32.wrap_i64" (i64.const -1)) (i32.const -1)) +(assert_return (invoke "i32.wrap_i64" (i64.const -100000)) (i32.const -100000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x80000000)) (i32.const 0x80000000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff7fffffff)) (i32.const 0x7fffffff)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000000)) (i32.const 0x00000000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xfffffffeffffffff)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000001)) (i32.const 0x00000001)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0)) (i32.const 0)) +(assert_return (invoke "i32.wrap_i64" (i64.const 1311768467463790320)) (i32.const 0x9abcdef0)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x00000000ffffffff)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000000)) (i32.const 0x00000000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000001)) (i32.const 0x00000001)) + +(assert_return (invoke "i32.trunc_s_f32" (f32.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1.19999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1.19999ap+0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.5)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.9)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -2.0)) (i32.const -2)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const 2147483520.0)) (i32.const 2147483520)) +(assert_return (invoke "i32.trunc_s_f32" (f32.const -2147483648.0)) (i32.const -2147483648)) +(assert_trap (invoke "i32.trunc_s_f32" (f32.const 2147483648.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const -2147483904.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i32.trunc_u_f32" (f32.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1.19999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.9)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 2.0)) (i32.const 2)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000 +(assert_return (invoke "i32.trunc_u_f32" (f32.const 4294967040.0)) (i32.const -256)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1.ccccccp-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1.fffffep-1)) (i32.const 0)) +(assert_trap (invoke "i32.trunc_u_f32" (f32.const 4294967296.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const -1.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i32.trunc_s_f64" (f64.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x1.199999999999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x1.199999999999ap+0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.5)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.9)) (i32.const -1)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -2.0)) (i32.const -2)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const 2147483647.0)) (i32.const 2147483647)) +(assert_return (invoke "i32.trunc_s_f64" (f64.const -2147483648.0)) (i32.const -2147483648)) +(assert_trap (invoke "i32.trunc_s_f64" (f64.const 2147483648.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const -2147483649.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i32.trunc_u_f64" (f64.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x1.199999999999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.9)) (i32.const 1)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 2.0)) (i32.const 2)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000 +(assert_return (invoke "i32.trunc_u_f64" (f64.const 4294967295.0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x1.ccccccccccccdp-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x1.fffffffffffffp-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_u_f64" (f64.const 1e8)) (i32.const 100000000)) +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 4294967296.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const -1.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e16)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e30)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 9223372036854775808)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i64.trunc_s_f32" (f32.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1.19999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1.19999ap+0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.5)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.9)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -2.0)) (i64.const -2)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000 +(assert_return (invoke "i64.trunc_s_f32" (f32.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000 +(assert_return (invoke "i64.trunc_s_f32" (f32.const 9223371487098961920.0)) (i64.const 9223371487098961920)) +(assert_return (invoke "i64.trunc_s_f32" (f32.const -9223372036854775808.0)) (i64.const -9223372036854775808)) +(assert_trap (invoke "i64.trunc_s_f32" (f32.const 9223372036854775808.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const -9223373136366403584.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i64.trunc_u_f32" (f32.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1.19999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 4294967296)) (i64.const 4294967296)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const 18446742974197923840.0)) (i64.const -1099511627776)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1.ccccccp-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1.fffffep-1)) (i64.const 0)) +(assert_trap (invoke "i64.trunc_u_f32" (f32.const 18446744073709551616.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const -1.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i64.trunc_s_f64" (f64.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x1.199999999999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x1.199999999999ap+0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.5)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.9)) (i64.const -1)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -2.0)) (i64.const -2)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000 +(assert_return (invoke "i64.trunc_s_f64" (f64.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000 +(assert_return (invoke "i64.trunc_s_f64" (f64.const 9223372036854774784.0)) (i64.const 9223372036854774784)) +(assert_return (invoke "i64.trunc_s_f64" (f64.const -9223372036854775808.0)) (i64.const -9223372036854775808)) +(assert_trap (invoke "i64.trunc_s_f64" (f64.const 9223372036854775808.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const -9223372036854777856.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const nan)) "invalid conversion to integer") + +(assert_return (invoke "i64.trunc_u_f64" (f64.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x1.199999999999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 4294967295)) (i64.const 0xffffffff)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 4294967296)) (i64.const 0x100000000)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 18446744073709549568.0)) (i64.const -2048)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x1.ccccccccccccdp-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x1.fffffffffffffp-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 1e8)) (i64.const 100000000)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 1e16)) (i64.const 10000000000000000)) +(assert_return (invoke "i64.trunc_u_f64" (f64.const 9223372036854775808)) (i64.const -9223372036854775808)) +(assert_trap (invoke "i64.trunc_u_f64" (f64.const 18446744073709551616.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const -1.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const nan)) "invalid conversion to integer") + +(assert_return (invoke "f32.convert_s_i32" (i32.const 1)) (f32.const 1.0)) +(assert_return (invoke "f32.convert_s_i32" (i32.const -1)) (f32.const -1.0)) +(assert_return (invoke "f32.convert_s_i32" (i32.const 0)) (f32.const 0.0)) +(assert_return (invoke "f32.convert_s_i32" (i32.const 2147483647)) (f32.const 2147483648)) +(assert_return (invoke "f32.convert_s_i32" (i32.const -2147483648)) (f32.const -2147483648)) +(assert_return (invoke "f32.convert_s_i32" (i32.const 1234567890)) (f32.const 0x1.26580cp+30)) +;; Test rounding directions. +(assert_return (invoke "f32.convert_s_i32" (i32.const 16777217)) (f32.const 16777216.0)) +(assert_return (invoke "f32.convert_s_i32" (i32.const -16777217)) (f32.const -16777216.0)) +(assert_return (invoke "f32.convert_s_i32" (i32.const 16777219)) (f32.const 16777220.0)) +(assert_return (invoke "f32.convert_s_i32" (i32.const -16777219)) (f32.const -16777220.0)) + +(assert_return (invoke "f32.convert_s_i64" (i64.const 1)) (f32.const 1.0)) +(assert_return (invoke "f32.convert_s_i64" (i64.const -1)) (f32.const -1.0)) +(assert_return (invoke "f32.convert_s_i64" (i64.const 0)) (f32.const 0.0)) +(assert_return (invoke "f32.convert_s_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807)) +(assert_return (invoke "f32.convert_s_i64" (i64.const -9223372036854775808)) (f32.const -9223372036854775808)) +(assert_return (invoke "f32.convert_s_i64" (i64.const 314159265358979)) (f32.const 0x1.1db9e8p+48)) ;; PI +;; Test rounding directions. +(assert_return (invoke "f32.convert_s_i64" (i64.const 16777217)) (f32.const 16777216.0)) +(assert_return (invoke "f32.convert_s_i64" (i64.const -16777217)) (f32.const -16777216.0)) +(assert_return (invoke "f32.convert_s_i64" (i64.const 16777219)) (f32.const 16777220.0)) +(assert_return (invoke "f32.convert_s_i64" (i64.const -16777219)) (f32.const -16777220.0)) + +(assert_return (invoke "f64.convert_s_i32" (i32.const 1)) (f64.const 1.0)) +(assert_return (invoke "f64.convert_s_i32" (i32.const -1)) (f64.const -1.0)) +(assert_return (invoke "f64.convert_s_i32" (i32.const 0)) (f64.const 0.0)) +(assert_return (invoke "f64.convert_s_i32" (i32.const 2147483647)) (f64.const 2147483647)) +(assert_return (invoke "f64.convert_s_i32" (i32.const -2147483648)) (f64.const -2147483648)) +(assert_return (invoke "f64.convert_s_i32" (i32.const 987654321)) (f64.const 987654321)) + +(assert_return (invoke "f64.convert_s_i64" (i64.const 1)) (f64.const 1.0)) +(assert_return (invoke "f64.convert_s_i64" (i64.const -1)) (f64.const -1.0)) +(assert_return (invoke "f64.convert_s_i64" (i64.const 0)) (f64.const 0.0)) +(assert_return (invoke "f64.convert_s_i64" (i64.const 9223372036854775807)) (f64.const 9223372036854775807)) +(assert_return (invoke "f64.convert_s_i64" (i64.const -9223372036854775808)) (f64.const -9223372036854775808)) +(assert_return (invoke "f64.convert_s_i64" (i64.const 4669201609102990)) (f64.const 4669201609102990)) ;; Feigenbaum +;; Test rounding directions. +(assert_return (invoke "f64.convert_s_i64" (i64.const 9007199254740993)) (f64.const 9007199254740992)) +(assert_return (invoke "f64.convert_s_i64" (i64.const -9007199254740993)) (f64.const -9007199254740992)) +(assert_return (invoke "f64.convert_s_i64" (i64.const 9007199254740995)) (f64.const 9007199254740996)) +(assert_return (invoke "f64.convert_s_i64" (i64.const -9007199254740995)) (f64.const -9007199254740996)) + +(assert_return (invoke "f32.convert_u_i32" (i32.const 1)) (f32.const 1.0)) +(assert_return (invoke "f32.convert_u_i32" (i32.const 0)) (f32.const 0.0)) +(assert_return (invoke "f32.convert_u_i32" (i32.const 2147483647)) (f32.const 2147483648)) +(assert_return (invoke "f32.convert_u_i32" (i32.const -2147483648)) (f32.const 2147483648)) +(assert_return (invoke "f32.convert_u_i32" (i32.const 0x12345678)) (f32.const 0x1.234568p+28)) +(assert_return (invoke "f32.convert_u_i32" (i32.const 0xffffffff)) (f32.const 4294967296.0)) +;; Test rounding directions. +(assert_return (invoke "f32.convert_u_i32" (i32.const 16777217)) (f32.const 16777216.0)) +(assert_return (invoke "f32.convert_u_i32" (i32.const 16777219)) (f32.const 16777220.0)) + +(assert_return (invoke "f32.convert_u_i64" (i64.const 1)) (f32.const 1.0)) +(assert_return (invoke "f32.convert_u_i64" (i64.const 0)) (f32.const 0.0)) +(assert_return (invoke "f32.convert_u_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807)) +(assert_return (invoke "f32.convert_u_i64" (i64.const -9223372036854775808)) (f32.const 9223372036854775808)) +(assert_return (invoke "f32.convert_u_i64" (i64.const 0xffffffffffffffff)) (f32.const 18446744073709551616.0)) +;; Test rounding directions. +(assert_return (invoke "f32.convert_u_i64" (i64.const 16777217)) (f32.const 16777216.0)) +(assert_return (invoke "f32.convert_u_i64" (i64.const 16777219)) (f32.const 16777220.0)) + +(assert_return (invoke "f64.convert_u_i32" (i32.const 1)) (f64.const 1.0)) +(assert_return (invoke "f64.convert_u_i32" (i32.const 0)) (f64.const 0.0)) +(assert_return (invoke "f64.convert_u_i32" (i32.const 2147483647)) (f64.const 2147483647)) +(assert_return (invoke "f64.convert_u_i32" (i32.const -2147483648)) (f64.const 2147483648)) +(assert_return (invoke "f64.convert_u_i32" (i32.const 0xffffffff)) (f64.const 4294967295.0)) + +(assert_return (invoke "f64.convert_u_i64" (i64.const 1)) (f64.const 1.0)) +(assert_return (invoke "f64.convert_u_i64" (i64.const 0)) (f64.const 0.0)) +(assert_return (invoke "f64.convert_u_i64" (i64.const 9223372036854775807)) (f64.const 9223372036854775807)) +(assert_return (invoke "f64.convert_u_i64" (i64.const -9223372036854775808)) (f64.const 9223372036854775808)) +(assert_return (invoke "f64.convert_u_i64" (i64.const 0xffffffffffffffff)) (f64.const 18446744073709551616.0)) +;; Test rounding directions. +(assert_return (invoke "f64.convert_u_i64" (i64.const 9007199254740993)) (f64.const 9007199254740992)) +(assert_return (invoke "f64.convert_u_i64" (i64.const 9007199254740995)) (f64.const 9007199254740996)) + +(assert_return (invoke "f64.promote_f32" (f32.const 0.0)) (f64.const 0.0)) +(assert_return (invoke "f64.promote_f32" (f32.const -0.0)) (f64.const -0.0)) +(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-149)) (f64.const 0x1p-149)) +(assert_return (invoke "f64.promote_f32" (f32.const -0x1p-149)) (f64.const -0x1p-149)) +(assert_return (invoke "f64.promote_f32" (f32.const 1.0)) (f64.const 1.0)) +(assert_return (invoke "f64.promote_f32" (f32.const -1.0)) (f64.const -1.0)) +(assert_return (invoke "f64.promote_f32" (f32.const -0x1.fffffep+127)) (f64.const -0x1.fffffep+127)) +(assert_return (invoke "f64.promote_f32" (f32.const 0x1.fffffep+127)) (f64.const 0x1.fffffep+127)) +;; Generated randomly by picking a random int and reinterpret it to float. +(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-119)) (f64.const 0x1p-119)) +;; Generated randomly by picking a random float. +(assert_return (invoke "f64.promote_f32" (f32.const 0x1.8f867ep+125)) (f64.const 6.6382536710104395e+37)) +(assert_return (invoke "f64.promote_f32" (f32.const infinity)) (f64.const infinity)) +(assert_return (invoke "f64.promote_f32" (f32.const -infinity)) (f64.const -infinity)) +(assert_return (invoke "f64.promote_f32" (f32.const nan)) (f64.const nan)) + +(assert_return (invoke "f32.demote_f64" (f64.const 0.0)) (f32.const 0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const -0.0)) (f32.const -0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x0.0000000000001p-1022)) (f32.const 0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x0.0000000000001p-1022)) (f32.const -0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 1.0)) (f32.const 1.0)) +(assert_return (invoke "f32.demote_f64" (f64.const -1.0)) (f32.const -1.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffe0000000p-127)) (f32.const 0x1p-126)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffe0000000p-127)) (f32.const -0x1p-126)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffdfffffffp-127)) (f32.const 0x1.fffffcp-127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffdfffffffp-127)) (f32.const -0x1.fffffcp-127)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-149)) (f32.const 0x1p-149)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-149)) (f32.const -0x1p-149)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffd0000000p+127)) (f32.const 0x1.fffffcp+127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffd0000000p+127)) (f32.const -0x1.fffffcp+127)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffd0000001p+127)) (f32.const 0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffd0000001p+127)) (f32.const -0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffefffffffp+127)) (f32.const 0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffefffffffp+127)) (f32.const -0x1.fffffep+127)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.ffffffp+127)) (f32.const infinity)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.ffffffp+127)) (f32.const -infinity)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-119)) (f32.const 0x1p-119)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.8f867ep+125)) (f32.const 0x1.8f867ep+125)) +(assert_return (invoke "f32.demote_f64" (f64.const infinity)) (f32.const infinity)) +(assert_return (invoke "f32.demote_f64" (f64.const -infinity)) (f32.const -infinity)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p+0)) (f32.const 1.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffffffffffp-1)) (f32.const 1.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000000p+0)) (f32.const 0x1.000000p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000001p+0)) (f32.const 0x1.000002p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.000002fffffffp+0)) (f32.const 0x1.000002p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+0)) (f32.const 0x1.000004p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000050000000p+0)) (f32.const 0x1.000004p+0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000000p+24)) (f32.const 0x1.0p+24)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000001p+24)) (f32.const 0x1.000002p+24)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.000002fffffffp+24)) (f32.const 0x1.000002p+24)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+24)) (f32.const 0x1.000004p+24)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.4eae4f7024c7p+108)) (f32.const 0x1.4eae5p+108)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.a12e71e358685p-113)) (f32.const 0x1.a12e72p-113)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.cb98354d521ffp-127)) (f32.const 0x1.cb9834p-127)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.6972b30cfb562p+1)) (f32.const -0x1.6972b4p+1)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.bedbe4819d4c4p+112)) (f32.const -0x1.bedbe4p+112)) +(assert_return (invoke "f32.demote_f64" (f64.const nan)) (f32.const nan)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-1022)) (f32.const 0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-1022)) (f32.const -0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0p-150)) (f32.const 0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0p-150)) (f32.const -0.0)) +(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p-150)) (f32.const 0x1p-149)) +(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0000000000001p-150)) (f32.const -0x1p-149)) + +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0)) (f32.const 0.0)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x80000000)) (f32.const -0.0)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 1)) (f32.const 0x1p-149)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const -1)) (f32.const -nan:0x7fffff)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 123456789)) (f32.const 0x1.b79a2ap-113)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const -2147483647)) (f32.const -0x1p-149)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7f800000)) (f32.const infinity)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xff800000)) (f32.const -infinity)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fc00000)) (f32.const nan)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffc00000)) (f32.const -nan)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fa00000)) (f32.const nan:0x200000)) +(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffa00000)) (f32.const -nan:0x200000)) + +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0)) (f64.const 0.0)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 1)) (f64.const 0x0.0000000000001p-1022)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const -1)) (f64.const -nan:0xfffffffffffff)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x8000000000000000)) (f64.const -0.0)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 1234567890)) (f64.const 0x0.00000499602d2p-1022)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const -9223372036854775807)) (f64.const -0x0.0000000000001p-1022)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff0000000000000)) (f64.const infinity)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff0000000000000)) (f64.const -infinity)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff8000000000000)) (f64.const nan)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff8000000000000)) (f64.const -nan)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff4000000000000)) (f64.const nan:0x4000000000000)) +(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff4000000000000)) (f64.const -nan:0x4000000000000)) + +(assert_return (invoke "i32.reinterpret_f32" (f32.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const -0.0)) (i32.const 0x80000000)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1p-149)) (i32.const 1)) +;;(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x7fffff)) (i32.const -1)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1p-149)) (i32.const 0x80000001)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const 1.0)) (i32.const 1065353216)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const 3.1415926)) (i32.const 1078530010)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1.fffffep+127)) (i32.const 2139095039)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1.fffffep+127)) (i32.const -8388609)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const infinity)) (i32.const 0x7f800000)) +(assert_return (invoke "i32.reinterpret_f32" (f32.const -infinity)) (i32.const 0xff800000)) +;;(assert_return (invoke "i32.reinterpret_f32" (f32.const nan)) (i32.const 0x7fc00000)) +;;(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan)) (i32.const 0xffc00000)) +;;(assert_return (invoke "i32.reinterpret_f32" (f32.const nan:0x200000)) (i32.const 0x7fa00000)) +;;(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x200000)) (i32.const 0xffa00000)) + +(assert_return (invoke "i64.reinterpret_f64" (f64.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const -0.0)) (i64.const 0x8000000000000000)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 1)) +;;(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0xfffffffffffff)) (i64.const -1)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0x8000000000000001)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const 1.0)) (i64.const 4607182418800017408)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const 3.14159265358979)) (i64.const 4614256656552045841)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x1.fffffffffffffp+1023)) (i64.const 9218868437227405311)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x1.fffffffffffffp+1023)) (i64.const -4503599627370497)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const infinity)) (i64.const 0x7ff0000000000000)) +(assert_return (invoke "i64.reinterpret_f64" (f64.const -infinity)) (i64.const 0xfff0000000000000)) +;;(assert_return (invoke "i64.reinterpret_f64" (f64.const nan)) (i64.const 0x7ff8000000000000)) +;;(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan)) (i64.const 0xfff8000000000000)) +;;(assert_return (invoke "i64.reinterpret_f64" (f64.const nan:0x4000000000000)) (i64.const 0x7ff4000000000000)) +;;(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0x4000000000000)) (i64.const 0xfff4000000000000)) diff --git a/test/wasm2asm/float-ops.2asm.js b/test/wasm2asm/float-ops.2asm.js index bad4bae9d..4d34766db 100644 --- a/test/wasm2asm/float-ops.2asm.js +++ b/test/wasm2asm/float-ops.2asm.js @@ -235,6 +235,114 @@ function asmFunc(global, env, buffer) { return Math_fround((HEAP32[0] = (HEAPF32[0] = $0, HEAP32[0]) & 2147483647 | 0 | ((HEAPF32[0] = $1, HEAP32[0]) & 2147483648 | 0) | 0, HEAPF32[0])); } + function $35($0) { + $0 = $0 | 0; + return Math_fround(Math_fround($0 | 0)); + } + + function $36($0) { + $0 = $0 | 0; + return +(+($0 | 0)); + } + + function $37($0) { + $0 = $0 | 0; + return Math_fround(Math_fround($0 >>> 0)); + } + + function $38($0) { + $0 = $0 | 0; + return +(+($0 >>> 0)); + } + + function $39($0) { + $0 = Math_fround($0); + return ~~$0 | 0; + } + + function $40($0) { + $0 = +$0; + return ~~$0 | 0; + } + + function $41($0) { + $0 = Math_fround($0); + return ~~$0 >>> 0 | 0; + } + + function $42($0) { + $0 = +$0; + return ~~$0 >>> 0 | 0; + } + + function $43($0, $0$hi) { + $0 = $0 | 0; + $0$hi = $0$hi | 0; + return Math_fround(Math_fround(+($0 >>> 0) + 4294967296.0 * +($0$hi | 0))); + } + + function $44($0, $0$hi) { + $0 = $0 | 0; + $0$hi = $0$hi | 0; + return +(+($0 >>> 0) + 4294967296.0 * +($0$hi | 0)); + } + + function $45($0, $0$hi) { + $0 = $0 | 0; + $0$hi = $0$hi | 0; + return Math_fround(Math_fround(+($0 >>> 0) + 4294967296.0 * +($0$hi >>> 0))); + } + + function $46($0, $0$hi) { + $0 = $0 | 0; + $0$hi = $0$hi | 0; + return +(+($0 >>> 0) + 4294967296.0 * +($0$hi >>> 0)); + } + + function $47($0) { + $0 = Math_fround($0); + var i64toi32_i32$0 = Math_fround(0), $2 = 0, $3 = 0; + i64toi32_i32$0 = $0; + if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { + if (i64toi32_i32$0 > Math_fround(0.0)) $2 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0; else $2 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0; + $3 = $2; + } else $3 = 0; + return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & ($3 | 0) == (0 | 0) | 0 | 0; + } + + function $48($0) { + $0 = +$0; + var i64toi32_i32$0 = 0.0, $2 = 0, $3 = 0; + i64toi32_i32$0 = $0; + if (Math_abs(i64toi32_i32$0) >= 1.0) { + if (i64toi32_i32$0 > 0.0) $2 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0; else $2 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0; + $3 = $2; + } else $3 = 0; + return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & ($3 | 0) == (0 | 0) | 0 | 0; + } + + function $49($0) { + $0 = Math_fround($0); + var i64toi32_i32$0 = Math_fround(0), $2 = 0, $3 = 0; + i64toi32_i32$0 = $0; + if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { + if (i64toi32_i32$0 > Math_fround(0.0)) $2 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0; else $2 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0; + $3 = $2; + } else $3 = 0; + return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & ($3 | 0) == (0 | 0) | 0 | 0; + } + + function $50($0) { + $0 = +$0; + var i64toi32_i32$0 = 0.0, $2 = 0, $3 = 0; + i64toi32_i32$0 = $0; + if (Math_abs(i64toi32_i32$0) >= 1.0) { + if (i64toi32_i32$0 > 0.0) $2 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0; else $2 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0; + $3 = $2; + } else $3 = 0; + return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & ($3 | 0) == (0 | 0) | 0 | 0; + } + function __wasm_ctz_i32(x) { x = x | 0; var $1 = 0; @@ -303,7 +411,23 @@ function asmFunc(global, env, buffer) { f64_floor: $29, f64_ceil: $30, f32_sqrt: $31, - f64_sqrt: $32 + f64_sqrt: $32, + i32_to_f32: $35, + i32_to_f64: $36, + u32_to_f32: $37, + u32_to_f64: $38, + f32_to_i32: $39, + f64_to_i32: $40, + f32_to_u32: $41, + f64_to_u32: $42, + i64_to_f32: $43, + i64_to_f64: $44, + u64_to_f32: $45, + u64_to_f64: $46, + f32_to_i64: $47, + f64_to_i64: $48, + f32_to_u64: $49, + f64_to_u64: $50 }; } diff --git a/test/wasm2asm/float-ops.wast b/test/wasm2asm/float-ops.wast index de26c9931..f724149cb 100644 --- a/test/wasm2asm/float-ops.wast +++ b/test/wasm2asm/float-ops.wast @@ -107,4 +107,41 @@ (f64.copysign (get_local $0) (get_local $1))) (func $copysign32 (param $0 f32) (param $1 f32) (result f32) (f32.copysign (get_local $0) (get_local $1))) + + ;; float<->int + (func (export "i32_to_f32") (param $0 i32) (result f32) + (f32.convert_s/i32 (get_local $0))) + (func (export "i32_to_f64") (param $0 i32) (result f64) + (f64.convert_s/i32 (get_local $0))) + (func (export "u32_to_f32") (param $0 i32) (result f32) + (f32.convert_u/i32 (get_local $0))) + (func (export "u32_to_f64") (param $0 i32) (result f64) + (f64.convert_u/i32 (get_local $0))) + + (func (export "f32_to_i32") (param $0 f32) (result i32) + (i32.trunc_s/f32 (get_local $0))) + (func (export "f64_to_i32") (param $0 f64) (result i32) + (i32.trunc_s/f64 (get_local $0))) + (func (export "f32_to_u32") (param $0 f32) (result i32) + (i32.trunc_u/f32 (get_local $0))) + (func (export "f64_to_u32") (param $0 f64) (result i32) + (i32.trunc_u/f64 (get_local $0))) + + (func (export "i64_to_f32") (param $0 i64) (result f32) + (f32.convert_s/i64 (get_local $0))) + (func (export "i64_to_f64") (param $0 i64) (result f64) + (f64.convert_s/i64 (get_local $0))) + (func (export "u64_to_f32") (param $0 i64) (result f32) + (f32.convert_u/i64 (get_local $0))) + (func (export "u64_to_f64") (param $0 i64) (result f64) + (f64.convert_u/i64 (get_local $0))) + + (func (export "f32_to_i64") (param $0 f32) (result i32) + (i64.eq (i64.trunc_s/f32 (get_local $0)) (i64.const 0))) + (func (export "f64_to_i64") (param $0 f64) (result i32) + (i64.eq (i64.trunc_s/f64 (get_local $0)) (i64.const 0))) + (func (export "f32_to_u64") (param $0 f32) (result i32) + (i64.eq (i64.trunc_u/f32 (get_local $0)) (i64.const 0))) + (func (export "f64_to_u64") (param $0 f64) (result i32) + (i64.eq (i64.trunc_u/f64 (get_local $0)) (i64.const 0))) ) |