Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 58 additions & 8 deletions src/passes/I64ToI32Lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,41 +598,86 @@ 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),
builder->makeGetLocal(rightLow, i32)
)
);
SetLocal* addHigh = builder->makeSetLocal(
rightHigh,
highResult,
builder->makeBinary(
AddInt32,
builder->makeGetLocal(leftHigh, i32),
builder->makeGetLocal(rightHigh, i32)
)
);
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;
}

Expand Down Expand Up @@ -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),
Expand Down
103 changes: 103 additions & 0 deletions test/i64-add-sub.2asm.js
Original file line number Diff line number Diff line change
@@ -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
};
}

66 changes: 66 additions & 0 deletions test/wasm2asm/i64-add-sub.wast
Original file line number Diff line number Diff line change
@@ -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))