diff options
-rw-r--r-- | src/passes/I64ToI32Lowering.cpp | 66 | ||||
-rw-r--r-- | test/i64-add-sub.2asm.js | 103 | ||||
-rw-r--r-- | test/wasm2asm/i64-add-sub.wast | 66 |
3 files changed, 227 insertions, 8 deletions
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index fd61a687c..68029188a 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -598,8 +598,10 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { Block* lowerAdd(Block* result, TempVar&& leftLow, TempVar&& leftHigh, TempVar&& rightLow, TempVar&& rightHigh) { + TempVar lowResult = getTemp(); + TempVar highResult = getTemp(); SetLocal* addLow = builder->makeSetLocal( - leftHigh, + lowResult, builder->makeBinary( AddInt32, builder->makeGetLocal(leftLow, i32), @@ -607,7 +609,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ) ); SetLocal* addHigh = builder->makeSetLocal( - rightHigh, + highResult, builder->makeBinary( AddInt32, builder->makeGetLocal(leftHigh, i32), @@ -615,24 +617,67 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ) ); SetLocal* carryBit = builder->makeSetLocal( - rightHigh, + highResult, builder->makeBinary( AddInt32, - builder->makeGetLocal(rightHigh, i32), + builder->makeGetLocal(highResult, i32), builder->makeConst(Literal(int32_t(1))) ) ); If* checkOverflow = builder->makeIf( builder->makeBinary( LtUInt32, - builder->makeGetLocal(leftLow, i32), + builder->makeGetLocal(lowResult, i32), builder->makeGetLocal(rightLow, i32) ), carryBit ); - GetLocal* getLow = builder->makeGetLocal(leftHigh, i32); + GetLocal* getLow = builder->makeGetLocal(lowResult, i32); result = builder->blockify(result, addLow, addHigh, checkOverflow, getLow); - setOutParam(result, std::move(rightHigh)); + setOutParam(result, std::move(highResult)); + return result; + } + + Block* lowerSub(Block* result, TempVar&& leftLow, TempVar&& leftHigh, + TempVar&& rightLow, TempVar&& rightHigh) { + TempVar lowResult = getTemp(); + TempVar highResult = getTemp(); + TempVar borrow = getTemp(); + SetLocal* subLow = builder->makeSetLocal( + lowResult, + builder->makeBinary( + SubInt32, + builder->makeGetLocal(leftLow, i32), + builder->makeGetLocal(rightLow, i32) + ) + ); + SetLocal* borrowBit = builder->makeSetLocal( + borrow, + builder->makeBinary( + LtUInt32, + builder->makeGetLocal(leftLow, i32), + builder->makeGetLocal(rightLow, i32) + ) + ); + SetLocal* subHigh1 = builder->makeSetLocal( + highResult, + builder->makeBinary( + AddInt32, + builder->makeGetLocal(borrow, i32), + builder->makeGetLocal(rightHigh, i32) + ) + ); + SetLocal* subHigh2 = builder->makeSetLocal( + highResult, + builder->makeBinary( + SubInt32, + builder->makeGetLocal(leftHigh, i32), + builder->makeGetLocal(highResult, i32) + ) + ); + GetLocal* getLow = builder->makeGetLocal(lowResult, i32); + result = builder->blockify(result, subLow, borrowBit, subHigh1, subHigh2, getLow); + setOutParam(result, std::move(highResult)); return result; } @@ -1125,7 +1170,12 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { std::move(rightLow), std::move(rightHigh))); break; } - case SubInt64: goto err; + case SubInt64: { + replaceCurrent( + lowerSub(result, std::move(leftLow), std::move(leftHigh), + std::move(rightLow), std::move(rightHigh))); + break; + } case MulInt64: { replaceCurrent( lowerMul(result, std::move(leftLow), std::move(leftHigh), diff --git a/test/i64-add-sub.2asm.js b/test/i64-add-sub.2asm.js new file mode 100644 index 000000000..277ee1996 --- /dev/null +++ b/test/i64-add-sub.2asm.js @@ -0,0 +1,103 @@ +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; + function dummy() { + + } + + function $$1($$0, $$0$hi, $$1, $$1$hi, r, r$hi) { + $$0 = $$0 | 0; + $$0$hi = $$0$hi | 0; + $$1 = $$1 | 0; + $$1$hi = $$1$hi | 0; + r = r | 0; + r$hi = r$hi | 0; + var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$5 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0, $$16 = 0, $$17 = 0, $$18 = 0, $$19 = 0, $$20 = 0, $$21 = 0, $$22 = 0, $$23 = 0, $$24 = 0, $$25 = 0, $$26 = 0, $$27 = 0, $$28 = 0, $$29 = 0, $$30 = 0, $$31 = 0, $$32 = 0, $$33 = 0, $$34 = 0, $$35 = 0, $$36 = 0, $$37 = 0, $$38 = 0, $$39 = 0, $$40 = 0, $$41 = 0, $$42 = 0, $$43 = 0, $$44 = 0, $$45 = 0, $$46 = 0; + i64toi32_i32$0 = $$0$hi; + i64toi32_i32$2 = $$0; + i64toi32_i32$3 = $$1; + i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$3 | 0; + i64toi32_i32$5 = i64toi32_i32$0 + $$1$hi | 0; + if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0; + i64toi32_i32$0 = i64toi32_i32$4; + i64toi32_i32$2 = r$hi; + i64toi32_i32$3 = r; + return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$5 | 0) == (i64toi32_i32$2 | 0) | 0 | 0; + } + + function $$2($$0, $$0$hi, $$1, $$1$hi, r, r$hi) { + $$0 = $$0 | 0; + $$0$hi = $$0$hi | 0; + $$1 = $$1 | 0; + $$1$hi = $$1$hi | 0; + r = r | 0; + r$hi = r$hi | 0; + var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$5 = 0, i64toi32_i32$6 = 0, $$13 = 0, $$14 = 0, $$15 = 0, $$16 = 0, $$17 = 0, $$18 = 0, $$19 = 0, $$20 = 0, $$21 = 0, $$22 = 0, $$23 = 0, $$24 = 0, $$25 = 0, $$26 = 0, $$27 = 0, $$28 = 0, $$29 = 0, $$30 = 0, $$31 = 0, $$32 = 0, $$33 = 0, $$34 = 0, $$35 = 0, $$36 = 0, $$37 = 0, $$38 = 0, $$39 = 0, $$40 = 0, $$41 = 0, $$42 = 0, $$43 = 0, $$44 = 0, $$45 = 0, $$46 = 0, $$47 = 0, $$48 = 0; + i64toi32_i32$0 = $$0$hi; + i64toi32_i32$2 = $$0; + i64toi32_i32$3 = $$1; + i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) + $$1$hi | 0; + i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0; + i64toi32_i32$0 = i64toi32_i32$2 - i64toi32_i32$3 | 0; + i64toi32_i32$2 = r$hi; + i64toi32_i32$3 = r; + return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$5 | 0) == (i64toi32_i32$2 | 0) | 0 | 0; + } + + function __wasm_ctz_i32(x) { + x = x | 0; + var $$1 = 0, $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0; + if ((x | 0) == (0 | 0)) $$9 = 32; else $$9 = 31 - Math_clz32(x ^ (x - 1 | 0) | 0) | 0; + return $$9 | 0; + } + + function __wasm_popcnt_i32(x) { + x = x | 0; + var count = 0, $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0, $$11 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0; + count = 0; + b : { + l : do { + $$5 = 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 $$5 | 0; + } + + function __wasm_rotl_i32(x, k) { + x = x | 0; + k = k | 0; + var $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0, $$11 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0, $$16 = 0, $$17 = 0, $$18 = 0, $$19 = 0, $$20 = 0, wasm2asm_i32$0 = 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 wasm2asm_i32$0 | 0; + } + + function __wasm_rotr_i32(x, k) { + x = x | 0; + k = k | 0; + var $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0, $$11 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0, $$16 = 0, $$17 = 0, $$18 = 0, $$19 = 0, $$20 = 0, wasm2asm_i32$0 = 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 wasm2asm_i32$0 | 0; + } + + return { + check_add_i64: $$1, + check_sub_i64: $$2 + }; +} + diff --git a/test/wasm2asm/i64-add-sub.wast b/test/wasm2asm/i64-add-sub.wast new file mode 100644 index 000000000..b9ab45b79 --- /dev/null +++ b/test/wasm2asm/i64-add-sub.wast @@ -0,0 +1,66 @@ +;; Testing i64 lowering for addition and subtraction. + +(module + (func $dummy) + + (func (export "check_add_i64") (param $0 i64) (param $1 i64) (param $r i64) (result i32) + (i64.eq (i64.add (get_local $0) (get_local $1)) (get_local $r))) + + (func (export "check_sub_i64") (param $0 i64) (param $1 i64) (param $r i64) (result i32) + (i64.eq (i64.sub (get_local $0) (get_local $1)) (get_local $r))) +) + +(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 0)) + (i32.const 1)) +(assert_return (invoke "check_add_i64" (i32.const 1) (i32.const 0) + (i32.const 0) (i32.const 0) + (i32.const 1) (i32.const 0)) + (i32.const 1)) +(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0) + (i32.const 1) (i32.const 0) + (i32.const 1) (i32.const 0)) + (i32.const 1)) +(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 1) + (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 1)) + (i32.const 1)) +(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 1) + (i32.const 0) (i32.const 1)) + (i32.const 1)) +(assert_return (invoke "check_add_i64" (i32.const 0xffffffff) (i32.const 0) + (i32.const 1) (i32.const 0) + (i32.const 0) (i32.const 1)) + (i32.const 1)) + +;; subtraction +(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 0)) + (i32.const 1)) +(assert_return (invoke "check_sub_i64" (i32.const 1) (i32.const 0) + (i32.const 0) (i32.const 0) + (i32.const 1) (i32.const 0)) + (i32.const 1)) +(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0) + (i32.const 1) (i32.const 0) + (i32.const 0xffffffff) (i32.const 0xffffffff)) + (i32.const 1)) +(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 1) + (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 1)) + (i32.const 1)) +(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 1) + (i32.const 0) (i32.const 0xffffffff)) + (i32.const 1)) +(assert_return (invoke "check_sub_i64" (i32.const 0xffffffff) (i32.const 0) + (i32.const 1) (i32.const 0) + (i32.const 0xfffffffe) (i32.const 0)) + (i32.const 1)) +(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 1) + (i32.const 1) (i32.const 1) + (i32.const 0xffffffff) (i32.const 0xffffffff)) + (i32.const 1)) |