summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/I64ToI32Lowering.cpp66
-rw-r--r--test/i64-add-sub.2asm.js103
-rw-r--r--test/wasm2asm/i64-add-sub.wast66
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))