summaryrefslogtreecommitdiff
path: root/src/passes/I64ToI32Lowering.cpp
diff options
context:
space:
mode:
authorNathan Froyd <froydnj@gmail.com>2018-02-26 16:56:43 -0500
committerAlon Zakai <alonzakai@gmail.com>2018-02-26 13:56:43 -0800
commit8bbf9b759b92f5d5248ee66096f07835caf6062a (patch)
treef96904c0f2c89e7ab8eaa4fc131cae49d7f831fa /src/passes/I64ToI32Lowering.cpp
parentefeff741fc53fd0a253e6a4d73c85ac149fb66ca (diff)
downloadbinaryen-8bbf9b759b92f5d5248ee66096f07835caf6062a.tar.gz
binaryen-8bbf9b759b92f5d5248ee66096f07835caf6062a.tar.bz2
binaryen-8bbf9b759b92f5d5248ee66096f07835caf6062a.zip
fix and implement more unary ops (#1442)
* add tests for i32.popcnt * lower i64.popcnt * add tests for i64.extend_u/i32 * lower i64.extend_s/i32 * fix lowering i64.eqz * lower i64.eqz more efficiently * add tests for i32.clz/i32.ctz * lower i64.clz/i64.ctz
Diffstat (limited to 'src/passes/I64ToI32Lowering.cpp')
-rw-r--r--src/passes/I64ToI32Lowering.cpp128
1 files changed, 120 insertions, 8 deletions
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 68029188a..a359d22d8 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -516,13 +516,17 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
void lowerEqZInt64(Unary* curr) {
TempVar highBits = fetchOutParam(curr->value);
- replaceCurrent(
+
+ auto* result = builder->makeUnary(
+ EqZInt32,
builder->makeBinary(
- AndInt32,
- builder->makeUnary(EqZInt32, builder->makeGetLocal(highBits, i32)),
- builder->makeUnary(EqZInt32, curr->value)
+ OrInt32,
+ curr->value,
+ builder->makeGetLocal(highBits, i32)
)
);
+
+ replaceCurrent(result);
}
void lowerExtendUInt32(Unary* curr) {
@@ -535,12 +539,120 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
replaceCurrent(result);
}
+ void lowerExtendSInt32(Unary* curr) {
+ TempVar highBits = getTemp();
+ TempVar lowBits = getTemp();
+
+ SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value);
+ SetLocal* setHigh = builder->makeSetLocal(
+ highBits,
+ builder->makeBinary(
+ ShrSInt32,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeConst(Literal(int32_t(31)))
+ )
+ );
+
+ Block* result = builder->blockify(
+ setLow,
+ setHigh,
+ builder->makeGetLocal(lowBits, i32)
+ );
+
+ setOutParam(result, std::move(highBits));
+ replaceCurrent(result);
+ }
+
void lowerWrapInt64(Unary* curr) {
// free the temp var
fetchOutParam(curr->value);
replaceCurrent(curr->value);
}
+ void lowerPopcnt64(Unary* curr) {
+ TempVar highBits = fetchOutParam(curr->value);
+ TempVar lowBits = getTemp();
+ TempVar highResult = getTemp();
+
+ SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value);
+ SetLocal* setHigh = builder->makeSetLocal(
+ highResult,
+ builder->makeConst(Literal(int32_t(0)))
+ );
+
+ Block* result = builder->blockify(
+ setLow,
+ setHigh,
+ builder->makeBinary(
+ AddInt32,
+ builder->makeUnary(PopcntInt32, builder->makeGetLocal(highBits, i32)),
+ builder->makeUnary(PopcntInt32, builder->makeGetLocal(lowBits, i32))
+ )
+ );
+
+ setOutParam(result, std::move(highResult));
+ replaceCurrent(result);
+ }
+
+ void lowerCountZeros(Unary* curr) {
+ auto lower = [&](Block* result, UnaryOp op32, TempVar&& first, TempVar&& second) {
+ TempVar highResult = getTemp();
+ TempVar firstResult = getTemp();
+ SetLocal* setFirst = builder->makeSetLocal(
+ firstResult,
+ builder->makeUnary(op32, builder->makeGetLocal(first, i32))
+ );
+
+ Binary* check = builder->makeBinary(
+ EqInt32,
+ builder->makeGetLocal(firstResult, i32),
+ builder->makeConst(Literal(int32_t(32)))
+ );
+
+ If* conditional = builder->makeIf(
+ check,
+ builder->makeBinary(
+ AddInt32,
+ builder->makeUnary(op32, builder->makeGetLocal(second, i32)),
+ builder->makeConst(Literal(int32_t(32)))
+ ),
+ builder->makeGetLocal(firstResult, i32)
+ );
+
+ SetLocal* setHigh = builder->makeSetLocal(
+ highResult,
+ builder->makeConst(Literal(int32_t(0)))
+ );
+
+ setOutParam(result, std::move(highResult));
+
+ replaceCurrent(
+ builder->blockify(
+ result,
+ setFirst,
+ setHigh,
+ conditional
+ )
+ );
+ };
+
+ TempVar highBits = fetchOutParam(curr->value);
+ TempVar lowBits = getTemp();
+ SetLocal* setLow = builder->makeSetLocal(lowBits, curr->value);
+ Block* result = builder->blockify(setLow);
+
+ switch (curr->op) {
+ case ClzInt64:
+ lower(result, ClzInt32, std::move(highBits), std::move(lowBits));
+ break;
+ case CtzInt64:
+ lower(result, CtzInt32, std::move(lowBits), std::move(highBits));
+ break;
+ default:
+ abort();
+ }
+ }
+
bool unaryNeedsLowering(UnaryOp op) {
switch (op) {
case ClzInt64:
@@ -574,10 +686,10 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
assert(hasOutParam(curr->value) || curr->type == i64);
switch (curr->op) {
case ClzInt64:
- case CtzInt64:
- case PopcntInt64: goto err;
+ case CtzInt64: lowerCountZeros(curr); break;
+ case PopcntInt64: lowerPopcnt64(curr); break;
case EqZInt64: lowerEqZInt64(curr); break;
- case ExtendSInt32: goto err;
+ case ExtendSInt32: lowerExtendSInt32(curr); break;
case ExtendUInt32: lowerExtendUInt32(curr); break;
case WrapInt64: lowerWrapInt64(curr); break;
case TruncSFloat32ToInt64:
@@ -590,7 +702,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
case ConvertUInt64ToFloat32:
case ConvertUInt64ToFloat64:
case ReinterpretInt64:
- err: default:
+ default:
std::cerr << "Unhandled unary operator: " << curr->op << std::endl;
abort();
}