summaryrefslogtreecommitdiff
path: root/src/passes/I64ToI32Lowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/I64ToI32Lowering.cpp')
-rw-r--r--src/passes/I64ToI32Lowering.cpp195
1 files changed, 193 insertions, 2 deletions
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 657df4896..e6da9a1b8 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -28,7 +28,7 @@
#include "support/name.h"
#include "wasm-builder.h"
#include "ir/names.h"
-
+#include "asmjs/shared-constants.h"
namespace wasm {
@@ -119,6 +119,149 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
highBits->mutable_ = true;
module->addGlobal(highBits);
PostWalker<I64ToI32Lowering>::doWalkModule(module);
+
+ if (needRotl64) {
+ module->addFunction(createRot64(true));
+ }
+ if (needRotr64) {
+ module->addFunction(createRot64(false));
+ }
+ }
+
+ Function* createRot64(bool leftShift) {
+ Name name = leftShift ? WASM_ROTL64 : WASM_ROTR64;
+
+ // if rotate == 32
+ // hi = leftLow
+ // lo = leftHigh
+ // if rotate > 32
+ // rotate = rotate - 32
+ // hi = (leftLow << rotate) | (leftHigh >> (32 - rotate))
+ // lo = (leftHigh << rotate) | (leftLow >> (32 - rotate))
+ // else
+ // hi = (leftHigh << rotate) | (leftLow >> (32 - rotate))
+ // lo = (leftLow << rotate) | (leftHigh >> (32 - rotate))
+ Index lowBits = 0;
+ Index highBits = 1;
+ Index rotate = 2;
+ Index widthLessRotate = 3;
+ Binary* is32Rotate = builder->makeBinary(
+ EqInt32,
+ builder->makeGetLocal(rotate, i32),
+ builder->makeConst(Literal(int32_t(32)))
+ );
+ Binary* isLargeRotate = builder->makeBinary(
+ GeUInt32,
+ builder->makeGetLocal(rotate, i32),
+ builder->makeConst(Literal(int32_t(32)))
+ );
+ BinaryOp firstOp = leftShift ? ShlInt32 : ShrUInt32;
+ BinaryOp secondOp = leftShift ? ShrUInt32 : ShlInt32;
+ Block* equalRotateBlock = builder->blockify(
+ builder->makeSetGlobal(
+ highBitsGlobal,
+ builder->makeGetLocal(lowBits, i32)
+ ),
+ builder->makeGetLocal(highBits, i32)
+ );
+ Block* largeRotateBlock = builder->blockify(
+ builder->makeSetLocal(
+ rotate,
+ builder->makeBinary(
+ SubInt32,
+ builder->makeGetLocal(rotate, i32),
+ builder->makeConst(Literal(int32_t(32)))
+ )
+ ),
+ builder->makeSetLocal(
+ widthLessRotate,
+ builder->makeBinary(
+ SubInt32,
+ builder->makeConst(Literal(int32_t(32))),
+ builder->makeGetLocal(rotate, i32)
+ )
+ ),
+ builder->makeSetGlobal(
+ highBitsGlobal,
+ builder->makeBinary(
+ OrInt32,
+ builder->makeBinary(
+ firstOp,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeGetLocal(rotate, i32)
+ ),
+ builder->makeBinary(
+ secondOp,
+ builder->makeGetLocal(highBits, i32),
+ builder->makeGetLocal(widthLessRotate, i32)
+ )
+ )
+ ),
+ builder->makeBinary(
+ OrInt32,
+ builder->makeBinary(
+ firstOp,
+ builder->makeGetLocal(highBits, i32),
+ builder->makeGetLocal(rotate, i32)
+ ),
+ builder->makeBinary(
+ secondOp,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeGetLocal(widthLessRotate, i32)
+ )
+ )
+ );
+ Block* smallRotateBlock = builder->blockify(
+ builder->makeSetLocal(
+ widthLessRotate,
+ builder->makeBinary(
+ SubInt32,
+ builder->makeConst(Literal(int32_t(32))),
+ builder->makeGetLocal(rotate, i32)
+ )
+ ),
+ builder->makeSetGlobal(
+ highBitsGlobal,
+ builder->makeBinary(
+ OrInt32,
+ builder->makeBinary(
+ firstOp,
+ builder->makeGetLocal(highBits, i32),
+ builder->makeGetLocal(rotate, i32)
+ ),
+ builder->makeBinary(
+ secondOp,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeGetLocal(widthLessRotate, i32)
+ )
+ )
+ ),
+ builder->makeBinary(
+ OrInt32,
+ builder->makeBinary(
+ firstOp,
+ builder->makeGetLocal(lowBits, i32),
+ builder->makeGetLocal(rotate, i32)
+ ),
+ builder->makeBinary(
+ secondOp,
+ builder->makeGetLocal(highBits, i32),
+ builder->makeGetLocal(widthLessRotate, i32)
+ )
+ )
+ );
+ If* condition = builder->makeIf(
+ is32Rotate,
+ equalRotateBlock,
+ builder->makeIf(
+ isLargeRotate,
+ largeRotateBlock,
+ smallRotateBlock
+ )
+ );
+ std::vector<Type> params = {i32, i32, i32};
+ std::vector<Type> vars = {i32};
+ return builder->makeFunction(name, std::move(params), i32, std::move(vars), condition);
}
void visitFunctionType(FunctionType* curr) {
@@ -1211,6 +1354,46 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
return result;
}
+ Block* lowerRotate(BinaryOp op, Block* result, TempVar&& leftLow,
+ TempVar&& leftHigh, TempVar&& rightLow, TempVar&& rightHigh) {
+ assert(op == RotLInt64 || op == RotRInt64);
+ Name name;
+ if (op == RotLInt64) {
+ needRotl64 = true;
+ name = WASM_ROTL64;
+ } else {
+ needRotr64 = true;
+ name = WASM_ROTR64;
+ }
+ TempVar lowResult = getTemp();
+ result = builder->blockify(
+ result,
+ builder->makeSetLocal(
+ lowResult,
+ builder->makeCall(
+ name,
+ {
+ builder->makeGetLocal(leftLow, i32),
+ builder->makeGetLocal(leftHigh, i32),
+ builder->makeBinary(
+ AndInt32,
+ builder->makeGetLocal(rightLow, i32),
+ builder->makeConst(Literal(int32_t(64 - 1)))
+ )
+ },
+ i32
+ )
+ ),
+ builder->makeSetLocal(
+ rightHigh,
+ builder->makeGetGlobal(highBitsGlobal, i32)
+ ),
+ builder->makeGetLocal(lowResult, i32)
+ );
+ setOutParam(result, std::move(rightHigh));
+ return result;
+ }
+
Block* lowerEq(Block* result, TempVar&& leftLow, TempVar&& leftHigh,
TempVar&& rightLow, TempVar&& rightHigh) {
return builder->blockify(
@@ -1434,7 +1617,13 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
break;
}
case RotLInt64:
- case RotRInt64: goto err;
+ case RotRInt64: {
+ replaceCurrent(
+ lowerRotate(curr->op, result, std::move(leftLow), std::move(leftHigh),
+ std::move(rightLow), std::move(rightHigh))
+ );
+ break;
+ }
case EqInt64: {
replaceCurrent(
lowerEq(result, std::move(leftLow), std::move(leftHigh),
@@ -1506,6 +1695,8 @@ private:
std::unordered_map<Name, TempVar> labelHighBitVars;
std::vector<Index> freeTemps;
Index nextTemp;
+ bool needRotl64 = false;
+ bool needRotr64 = false;
TempVar getTemp() {
Index ret;