Skip to content

Commit e0f86a2

Browse files
froydnjkripken
authored andcommitted
implement lowering for i64 subtraction (#1429)
* fix lowering of i64 adds We're not permitted to reuse the input as temporary variables for the results. Weird things happen otherwise. * add support for lowering i64 subtraction
1 parent 4a592c7 commit e0f86a2

File tree

3 files changed

+227
-8
lines changed

3 files changed

+227
-8
lines changed

src/passes/I64ToI32Lowering.cpp

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -598,41 +598,86 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
598598

599599
Block* lowerAdd(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
600600
TempVar&& rightLow, TempVar&& rightHigh) {
601+
TempVar lowResult = getTemp();
602+
TempVar highResult = getTemp();
601603
SetLocal* addLow = builder->makeSetLocal(
602-
leftHigh,
604+
lowResult,
603605
builder->makeBinary(
604606
AddInt32,
605607
builder->makeGetLocal(leftLow, i32),
606608
builder->makeGetLocal(rightLow, i32)
607609
)
608610
);
609611
SetLocal* addHigh = builder->makeSetLocal(
610-
rightHigh,
612+
highResult,
611613
builder->makeBinary(
612614
AddInt32,
613615
builder->makeGetLocal(leftHigh, i32),
614616
builder->makeGetLocal(rightHigh, i32)
615617
)
616618
);
617619
SetLocal* carryBit = builder->makeSetLocal(
618-
rightHigh,
620+
highResult,
619621
builder->makeBinary(
620622
AddInt32,
621-
builder->makeGetLocal(rightHigh, i32),
623+
builder->makeGetLocal(highResult, i32),
622624
builder->makeConst(Literal(int32_t(1)))
623625
)
624626
);
625627
If* checkOverflow = builder->makeIf(
626628
builder->makeBinary(
627629
LtUInt32,
628-
builder->makeGetLocal(leftLow, i32),
630+
builder->makeGetLocal(lowResult, i32),
629631
builder->makeGetLocal(rightLow, i32)
630632
),
631633
carryBit
632634
);
633-
GetLocal* getLow = builder->makeGetLocal(leftHigh, i32);
635+
GetLocal* getLow = builder->makeGetLocal(lowResult, i32);
634636
result = builder->blockify(result, addLow, addHigh, checkOverflow, getLow);
635-
setOutParam(result, std::move(rightHigh));
637+
setOutParam(result, std::move(highResult));
638+
return result;
639+
}
640+
641+
Block* lowerSub(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
642+
TempVar&& rightLow, TempVar&& rightHigh) {
643+
TempVar lowResult = getTemp();
644+
TempVar highResult = getTemp();
645+
TempVar borrow = getTemp();
646+
SetLocal* subLow = builder->makeSetLocal(
647+
lowResult,
648+
builder->makeBinary(
649+
SubInt32,
650+
builder->makeGetLocal(leftLow, i32),
651+
builder->makeGetLocal(rightLow, i32)
652+
)
653+
);
654+
SetLocal* borrowBit = builder->makeSetLocal(
655+
borrow,
656+
builder->makeBinary(
657+
LtUInt32,
658+
builder->makeGetLocal(leftLow, i32),
659+
builder->makeGetLocal(rightLow, i32)
660+
)
661+
);
662+
SetLocal* subHigh1 = builder->makeSetLocal(
663+
highResult,
664+
builder->makeBinary(
665+
AddInt32,
666+
builder->makeGetLocal(borrow, i32),
667+
builder->makeGetLocal(rightHigh, i32)
668+
)
669+
);
670+
SetLocal* subHigh2 = builder->makeSetLocal(
671+
highResult,
672+
builder->makeBinary(
673+
SubInt32,
674+
builder->makeGetLocal(leftHigh, i32),
675+
builder->makeGetLocal(highResult, i32)
676+
)
677+
);
678+
GetLocal* getLow = builder->makeGetLocal(lowResult, i32);
679+
result = builder->blockify(result, subLow, borrowBit, subHigh1, subHigh2, getLow);
680+
setOutParam(result, std::move(highResult));
636681
return result;
637682
}
638683

@@ -1125,7 +1170,12 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
11251170
std::move(rightLow), std::move(rightHigh)));
11261171
break;
11271172
}
1128-
case SubInt64: goto err;
1173+
case SubInt64: {
1174+
replaceCurrent(
1175+
lowerSub(result, std::move(leftLow), std::move(leftHigh),
1176+
std::move(rightLow), std::move(rightHigh)));
1177+
break;
1178+
}
11291179
case MulInt64: {
11301180
replaceCurrent(
11311181
lowerMul(result, std::move(leftLow), std::move(leftHigh),

test/i64-add-sub.2asm.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
function asmFunc(global, env, buffer) {
2+
"use asm";
3+
var HEAP8 = new global.Int8Array(buffer);
4+
var HEAP16 = new global.Int16Array(buffer);
5+
var HEAP32 = new global.Int32Array(buffer);
6+
var HEAPU8 = new global.Uint8Array(buffer);
7+
var HEAPU16 = new global.Uint16Array(buffer);
8+
var HEAPU32 = new global.Uint32Array(buffer);
9+
var HEAPF32 = new global.Float32Array(buffer);
10+
var HEAPF64 = new global.Float64Array(buffer);
11+
var Math_imul = global.Math.imul;
12+
var Math_fround = global.Math.fround;
13+
var Math_abs = global.Math.abs;
14+
var Math_clz32 = global.Math.clz32;
15+
function dummy() {
16+
17+
}
18+
19+
function $$1($$0, $$0$hi, $$1, $$1$hi, r, r$hi) {
20+
$$0 = $$0 | 0;
21+
$$0$hi = $$0$hi | 0;
22+
$$1 = $$1 | 0;
23+
$$1$hi = $$1$hi | 0;
24+
r = r | 0;
25+
r$hi = r$hi | 0;
26+
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;
27+
i64toi32_i32$0 = $$0$hi;
28+
i64toi32_i32$2 = $$0;
29+
i64toi32_i32$3 = $$1;
30+
i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
31+
i64toi32_i32$5 = i64toi32_i32$0 + $$1$hi | 0;
32+
if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0;
33+
i64toi32_i32$0 = i64toi32_i32$4;
34+
i64toi32_i32$2 = r$hi;
35+
i64toi32_i32$3 = r;
36+
return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$5 | 0) == (i64toi32_i32$2 | 0) | 0 | 0;
37+
}
38+
39+
function $$2($$0, $$0$hi, $$1, $$1$hi, r, r$hi) {
40+
$$0 = $$0 | 0;
41+
$$0$hi = $$0$hi | 0;
42+
$$1 = $$1 | 0;
43+
$$1$hi = $$1$hi | 0;
44+
r = r | 0;
45+
r$hi = r$hi | 0;
46+
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;
47+
i64toi32_i32$0 = $$0$hi;
48+
i64toi32_i32$2 = $$0;
49+
i64toi32_i32$3 = $$1;
50+
i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) + $$1$hi | 0;
51+
i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0;
52+
i64toi32_i32$0 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
53+
i64toi32_i32$2 = r$hi;
54+
i64toi32_i32$3 = r;
55+
return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$5 | 0) == (i64toi32_i32$2 | 0) | 0 | 0;
56+
}
57+
58+
function __wasm_ctz_i32(x) {
59+
x = x | 0;
60+
var $$1 = 0, $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0;
61+
if ((x | 0) == (0 | 0)) $$9 = 32; else $$9 = 31 - Math_clz32(x ^ (x - 1 | 0) | 0) | 0;
62+
return $$9 | 0;
63+
}
64+
65+
function __wasm_popcnt_i32(x) {
66+
x = x | 0;
67+
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;
68+
count = 0;
69+
b : {
70+
l : do {
71+
$$5 = count;
72+
if ((x | 0) == (0 | 0)) break b;
73+
x = x & (x - 1 | 0) | 0;
74+
count = count + 1 | 0;
75+
continue l;
76+
break l;
77+
} while (1);
78+
};
79+
return $$5 | 0;
80+
}
81+
82+
function __wasm_rotl_i32(x, k) {
83+
x = x | 0;
84+
k = k | 0;
85+
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;
86+
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;
87+
return wasm2asm_i32$0 | 0;
88+
}
89+
90+
function __wasm_rotr_i32(x, k) {
91+
x = x | 0;
92+
k = k | 0;
93+
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;
94+
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;
95+
return wasm2asm_i32$0 | 0;
96+
}
97+
98+
return {
99+
check_add_i64: $$1,
100+
check_sub_i64: $$2
101+
};
102+
}
103+

test/wasm2asm/i64-add-sub.wast

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
;; Testing i64 lowering for addition and subtraction.
2+
3+
(module
4+
(func $dummy)
5+
6+
(func (export "check_add_i64") (param $0 i64) (param $1 i64) (param $r i64) (result i32)
7+
(i64.eq (i64.add (get_local $0) (get_local $1)) (get_local $r)))
8+
9+
(func (export "check_sub_i64") (param $0 i64) (param $1 i64) (param $r i64) (result i32)
10+
(i64.eq (i64.sub (get_local $0) (get_local $1)) (get_local $r)))
11+
)
12+
13+
(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0)
14+
(i32.const 0) (i32.const 0)
15+
(i32.const 0) (i32.const 0))
16+
(i32.const 1))
17+
(assert_return (invoke "check_add_i64" (i32.const 1) (i32.const 0)
18+
(i32.const 0) (i32.const 0)
19+
(i32.const 1) (i32.const 0))
20+
(i32.const 1))
21+
(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0)
22+
(i32.const 1) (i32.const 0)
23+
(i32.const 1) (i32.const 0))
24+
(i32.const 1))
25+
(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 1)
26+
(i32.const 0) (i32.const 0)
27+
(i32.const 0) (i32.const 1))
28+
(i32.const 1))
29+
(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0)
30+
(i32.const 0) (i32.const 1)
31+
(i32.const 0) (i32.const 1))
32+
(i32.const 1))
33+
(assert_return (invoke "check_add_i64" (i32.const 0xffffffff) (i32.const 0)
34+
(i32.const 1) (i32.const 0)
35+
(i32.const 0) (i32.const 1))
36+
(i32.const 1))
37+
38+
;; subtraction
39+
(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0)
40+
(i32.const 0) (i32.const 0)
41+
(i32.const 0) (i32.const 0))
42+
(i32.const 1))
43+
(assert_return (invoke "check_sub_i64" (i32.const 1) (i32.const 0)
44+
(i32.const 0) (i32.const 0)
45+
(i32.const 1) (i32.const 0))
46+
(i32.const 1))
47+
(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0)
48+
(i32.const 1) (i32.const 0)
49+
(i32.const 0xffffffff) (i32.const 0xffffffff))
50+
(i32.const 1))
51+
(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 1)
52+
(i32.const 0) (i32.const 0)
53+
(i32.const 0) (i32.const 1))
54+
(i32.const 1))
55+
(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0)
56+
(i32.const 0) (i32.const 1)
57+
(i32.const 0) (i32.const 0xffffffff))
58+
(i32.const 1))
59+
(assert_return (invoke "check_sub_i64" (i32.const 0xffffffff) (i32.const 0)
60+
(i32.const 1) (i32.const 0)
61+
(i32.const 0xfffffffe) (i32.const 0))
62+
(i32.const 1))
63+
(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 1)
64+
(i32.const 1) (i32.const 1)
65+
(i32.const 0xffffffff) (i32.const 0xffffffff))
66+
(i32.const 1))

0 commit comments

Comments
 (0)