Skip to content

Commit b7105d9

Browse files
committed
lower i64.clz/i64.ctz
1 parent ef32bdd commit b7105d9

3 files changed

Lines changed: 146 additions & 3 deletions

File tree

src/passes/I64ToI32Lowering.cpp

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,65 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
599599
replaceCurrent(result);
600600
}
601601

602+
void lowerCountZeros(Unary* curr) {
603+
auto lower = [&](Block* result, UnaryOp op32, TempVar&& first, TempVar&& second) {
604+
TempVar highResult = getTemp();
605+
TempVar firstResult = getTemp();
606+
SetLocal* setFirst = builder->makeSetLocal(
607+
firstResult,
608+
builder->makeUnary(op32, builder->makeGetLocal(first, i32))
609+
);
610+
611+
Binary* check = builder->makeBinary(
612+
EqInt32,
613+
builder->makeGetLocal(firstResult, i32),
614+
builder->makeConst(Literal(int32_t(32)))
615+
);
616+
617+
If* conditional = builder->makeIf(
618+
check,
619+
builder->makeBinary(
620+
AddInt32,
621+
builder->makeUnary(op32, builder->makeGetLocal(second, i32)),
622+
builder->makeConst(Literal(int32_t(32)))
623+
),
624+
builder->makeGetLocal(firstResult, i32)
625+
);
626+
627+
SetLocal* setHigh = builder->makeSetLocal(
628+
highResult,
629+
builder->makeConst(Literal(int32_t(0)))
630+
);
631+
632+
setOutParam(result, std::move(highResult));
633+
634+
replaceCurrent(
635+
builder->blockify(
636+
result,
637+
setFirst,
638+
setHigh,
639+
conditional
640+
)
641+
);
642+
};
643+
644+
TempVar highBits = fetchOutParam(curr->value);
645+
TempVar lowBits = getTemp();
646+
SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value);
647+
Block* result = builder->blockify(setLow);
648+
649+
switch (curr->op) {
650+
case ClzInt64:
651+
lower(result, ClzInt32, std::move(highBits), std::move(lowBits));
652+
break;
653+
case CtzInt64:
654+
lower(result, CtzInt32, std::move(lowBits), std::move(highBits));
655+
break;
656+
default:
657+
abort();
658+
}
659+
}
660+
602661
bool unaryNeedsLowering(UnaryOp op) {
603662
switch (op) {
604663
case ClzInt64:
@@ -632,7 +691,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
632691
assert(hasOutParam(curr->value) || curr->type == i64);
633692
switch (curr->op) {
634693
case ClzInt64:
635-
case CtzInt64: goto err;
694+
case CtzInt64: lowerCountZeros(curr); break;
636695
case PopcntInt64: lowerPopcnt64(curr); break;
637696
case EqZInt64: lowerEqZInt64(curr); break;
638697
case ExtendSInt32: lowerExtendSInt32(curr); break;
@@ -648,7 +707,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
648707
case ConvertUInt64ToFloat32:
649708
case ConvertUInt64ToFloat64:
650709
case ReinterpretInt64:
651-
err: default:
710+
default:
652711
std::cerr << "Unhandled unary operator: " << curr->op << std::endl;
653712
abort();
654713
}

test/unary-ops.2asm.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,40 @@ function asmFunc(global, env, buffer) {
7979
return wasm2asm_i32$0 | 0;
8080
}
8181

82+
function $8($0, $0$hi, r, r$hi) {
83+
$0 = $0 | 0;
84+
$0$hi = $0$hi | 0;
85+
r = r | 0;
86+
r$hi = r$hi | 0;
87+
var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 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, $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;
88+
i64toi32_i32$0 = $0$hi;
89+
i64toi32_i32$1 = $0;
90+
i64toi32_i32$3 = Math_clz32(i64toi32_i32$0);
91+
i64toi32_i32$2 = 0;
92+
if ((i64toi32_i32$3 | 0) == (32 | 0)) $20 = Math_clz32(i64toi32_i32$1) + 32 | 0; else $20 = i64toi32_i32$3;
93+
i64toi32_i32$1 = $20;
94+
i64toi32_i32$0 = r$hi;
95+
i64toi32_i32$3 = r;
96+
return (i64toi32_i32$1 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) | 0 | 0;
97+
}
98+
99+
function $9($0, $0$hi, r, r$hi) {
100+
$0 = $0 | 0;
101+
$0$hi = $0$hi | 0;
102+
r = r | 0;
103+
r$hi = r$hi | 0;
104+
var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 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, $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;
105+
i64toi32_i32$0 = $0$hi;
106+
i64toi32_i32$1 = $0;
107+
i64toi32_i32$3 = __wasm_ctz_i32(i64toi32_i32$1) | 0;
108+
i64toi32_i32$2 = 0;
109+
if ((i64toi32_i32$3 | 0) == (32 | 0)) $20 = (__wasm_ctz_i32(i64toi32_i32$0) | 0) + 32 | 0; else $20 = i64toi32_i32$3;
110+
i64toi32_i32$1 = $20;
111+
i64toi32_i32$0 = r$hi;
112+
i64toi32_i32$3 = r;
113+
return (i64toi32_i32$1 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) | 0 | 0;
114+
}
115+
82116
function __wasm_ctz_i32(x) {
83117
x = x | 0;
84118
var $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $8 = 0, $9 = 0, $10 = 0;
@@ -126,7 +160,9 @@ function asmFunc(global, env, buffer) {
126160
check_extend_si32: $4,
127161
check_eqz_i64: $5,
128162
i32_clz: $6,
129-
i32_ctz: $7
163+
i32_ctz: $7,
164+
check_clz_i64: $8,
165+
check_ctz_i64: $9
130166
};
131167
}
132168

test/wasm2asm/unary-ops.wast

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
(func (export "i32.ctz") (param $0 i32) (result i32)
2323
(i32.ctz (get_local $0)))
24+
25+
(func (export "check_clz_i64") (param $0 i64) (param $r i64) (result i32)
26+
(i64.eq (i64.clz (get_local $0)) (get_local $r)))
27+
28+
(func (export "check_ctz_i64") (param $0 i64) (param $r i64) (result i32)
29+
(i64.eq (i64.ctz (get_local $0)) (get_local $r)))
2430
)
2531

2632
(assert_return (invoke "i32.popcnt" (i32.const 0)) (i32.const 0))
@@ -95,3 +101,45 @@
95101
(assert_return (invoke "i32.ctz" (i32.const 1)) (i32.const 0))
96102
(assert_return (invoke "i32.ctz" (i32.const 0xfffffffe)) (i32.const 1))
97103
(assert_return (invoke "i32.ctz" (i32.const 0x80000000)) (i32.const 31))
104+
105+
(assert_return (invoke "check_clz_i64"
106+
(i32.const 0) (i32.const 0)
107+
(i32.const 64) (i32.const 0))
108+
(i32.const 1))
109+
(assert_return (invoke "check_clz_i64"
110+
(i32.const 1) (i32.const 0)
111+
(i32.const 63) (i32.const 0))
112+
(i32.const 1))
113+
(assert_return (invoke "check_clz_i64"
114+
(i32.const 0x80000000) (i32.const 0)
115+
(i32.const 32) (i32.const 0))
116+
(i32.const 1))
117+
(assert_return (invoke "check_clz_i64"
118+
(i32.const 0) (i32.const 1)
119+
(i32.const 31) (i32.const 0))
120+
(i32.const 1))
121+
(assert_return (invoke "check_clz_i64"
122+
(i32.const 0) (i32.const 0x80000000)
123+
(i32.const 0) (i32.const 0))
124+
(i32.const 1))
125+
126+
(assert_return (invoke "check_ctz_i64"
127+
(i32.const 0) (i32.const 0)
128+
(i32.const 64) (i32.const 0))
129+
(i32.const 1))
130+
(assert_return (invoke "check_ctz_i64"
131+
(i32.const 0) (i32.const 0x80000000)
132+
(i32.const 63) (i32.const 0))
133+
(i32.const 1))
134+
(assert_return (invoke "check_ctz_i64"
135+
(i32.const 0) (i32.const 1)
136+
(i32.const 32) (i32.const 0))
137+
(i32.const 1))
138+
(assert_return (invoke "check_ctz_i64"
139+
(i32.const 0x80000000) (i32.const 0)
140+
(i32.const 31) (i32.const 0))
141+
(i32.const 1))
142+
(assert_return (invoke "check_ctz_i64"
143+
(i32.const 1) (i32.const 0)
144+
(i32.const 0) (i32.const 0))
145+
(i32.const 1))

0 commit comments

Comments
 (0)