diff options
author | Nathan Froyd <froydnj@gmail.com> | 2018-02-26 16:56:43 -0500 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2018-02-26 13:56:43 -0800 |
commit | 8bbf9b759b92f5d5248ee66096f07835caf6062a (patch) | |
tree | f96904c0f2c89e7ab8eaa4fc131cae49d7f831fa /src/passes/I64ToI32Lowering.cpp | |
parent | efeff741fc53fd0a253e6a4d73c85ac149fb66ca (diff) | |
download | binaryen-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.cpp | 128 |
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(); } |