diff options
Diffstat (limited to 'src/passes')
-rw-r--r-- | src/passes/AlignmentLowering.cpp | 214 | ||||
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | src/passes/passes.h | 1 |
4 files changed, 219 insertions, 0 deletions
diff --git a/src/passes/AlignmentLowering.cpp b/src/passes/AlignmentLowering.cpp new file mode 100644 index 000000000..fc03a8b74 --- /dev/null +++ b/src/passes/AlignmentLowering.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Lowers unaligned loads and stores into aligned loads and stores +// that are smaller. This leaves only aligned operations. +// + +#include "ir/bits.h" +#include "pass.h" +#include "wasm-builder.h" +#include "wasm.h" + +namespace wasm { + +struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> { + void visitLoad(Load* curr) { + if (curr->align == 0 || curr->align == curr->bytes) { + return; + } + Builder builder(*getModule()); + if (curr->type == unreachable) { + replaceCurrent(curr->ptr); + return; + } + assert(curr->type == i32); // TODO: i64, f32, f64 + auto temp = builder.addVar(getFunction(), i32); + Expression* ret; + if (curr->bytes == 2) { + ret = builder.makeBinary( + OrInt32, + builder.makeLoad( + 1, false, curr->offset, 1, builder.makeGetLocal(temp, i32), i32), + builder.makeBinary(ShlInt32, + builder.makeLoad(1, + false, + curr->offset + 1, + 1, + builder.makeGetLocal(temp, i32), + i32), + builder.makeConst(Literal(int32_t(8))))); + if (curr->signed_) { + ret = Bits::makeSignExt(ret, 2, *getModule()); + } + } else if (curr->bytes == 4) { + if (curr->align == 1) { + ret = builder.makeBinary( + OrInt32, + builder.makeBinary( + OrInt32, + builder.makeLoad( + 1, false, curr->offset, 1, builder.makeGetLocal(temp, i32), i32), + builder.makeBinary(ShlInt32, + builder.makeLoad(1, + false, + curr->offset + 1, + 1, + builder.makeGetLocal(temp, i32), + i32), + builder.makeConst(Literal(int32_t(8))))), + builder.makeBinary( + OrInt32, + builder.makeBinary(ShlInt32, + builder.makeLoad(1, + false, + curr->offset + 2, + 1, + builder.makeGetLocal(temp, i32), + i32), + builder.makeConst(Literal(int32_t(16)))), + builder.makeBinary(ShlInt32, + builder.makeLoad(1, + false, + curr->offset + 3, + 1, + builder.makeGetLocal(temp, i32), + i32), + builder.makeConst(Literal(int32_t(24)))))); + } else if (curr->align == 2) { + ret = builder.makeBinary( + OrInt32, + builder.makeLoad( + 2, false, curr->offset, 2, builder.makeGetLocal(temp, i32), i32), + builder.makeBinary(ShlInt32, + builder.makeLoad(2, + false, + curr->offset + 2, + 2, + builder.makeGetLocal(temp, i32), + i32), + builder.makeConst(Literal(int32_t(16))))); + } else { + WASM_UNREACHABLE(); + } + } else { + WASM_UNREACHABLE(); + } + replaceCurrent( + builder.makeBlock({builder.makeSetLocal(temp, curr->ptr), ret})); + } + + void visitStore(Store* curr) { + if (curr->align == 0 || curr->align == curr->bytes) { + return; + } + Builder builder(*getModule()); + if (curr->type == unreachable) { + replaceCurrent(builder.makeBlock( + {builder.makeDrop(curr->ptr), builder.makeDrop(curr->value)})); + return; + } + assert(curr->value->type == i32); // TODO: i64, f32, f64 + auto tempPtr = builder.addVar(getFunction(), i32); + auto tempValue = builder.addVar(getFunction(), i32); + auto* block = + builder.makeBlock({builder.makeSetLocal(tempPtr, curr->ptr), + builder.makeSetLocal(tempValue, curr->value)}); + if (curr->bytes == 2) { + block->list.push_back( + builder.makeStore(1, + curr->offset, + 1, + builder.makeGetLocal(tempPtr, i32), + builder.makeGetLocal(tempValue, i32), + i32)); + block->list.push_back(builder.makeStore( + 1, + curr->offset + 1, + 1, + builder.makeGetLocal(tempPtr, i32), + builder.makeBinary(ShrUInt32, + builder.makeGetLocal(tempValue, i32), + builder.makeConst(Literal(int32_t(8)))), + i32)); + } else if (curr->bytes == 4) { + if (curr->align == 1) { + block->list.push_back( + builder.makeStore(1, + curr->offset, + 1, + builder.makeGetLocal(tempPtr, i32), + builder.makeGetLocal(tempValue, i32), + i32)); + block->list.push_back(builder.makeStore( + 1, + curr->offset + 1, + 1, + builder.makeGetLocal(tempPtr, i32), + builder.makeBinary(ShrUInt32, + builder.makeGetLocal(tempValue, i32), + builder.makeConst(Literal(int32_t(8)))), + i32)); + block->list.push_back(builder.makeStore( + 1, + curr->offset + 2, + 1, + builder.makeGetLocal(tempPtr, i32), + builder.makeBinary(ShrUInt32, + builder.makeGetLocal(tempValue, i32), + builder.makeConst(Literal(int32_t(16)))), + i32)); + block->list.push_back(builder.makeStore( + 1, + curr->offset + 3, + 1, + builder.makeGetLocal(tempPtr, i32), + builder.makeBinary(ShrUInt32, + builder.makeGetLocal(tempValue, i32), + builder.makeConst(Literal(int32_t(24)))), + i32)); + } else if (curr->align == 2) { + block->list.push_back( + builder.makeStore(2, + curr->offset, + 2, + builder.makeGetLocal(tempPtr, i32), + builder.makeGetLocal(tempValue, i32), + i32)); + block->list.push_back(builder.makeStore( + 2, + curr->offset + 2, + 2, + builder.makeGetLocal(tempPtr, i32), + builder.makeBinary(ShrUInt32, + builder.makeGetLocal(tempValue, i32), + builder.makeConst(Literal(int32_t(16)))), + i32)); + } else { + WASM_UNREACHABLE(); + } + } else { + WASM_UNREACHABLE(); + } + block->finalize(); + replaceCurrent(block); + } +}; + +Pass* createAlignmentLoweringPass() { return new AlignmentLowering(); } + +} // namespace wasm diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index 8a4b04de8..935c3bec8 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -5,6 +5,7 @@ add_custom_command( SET(passes_SOURCES pass.cpp + AlignmentLowering.cpp CoalesceLocals.cpp CodePushing.cpp CodeFolding.cpp diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 7cfb21dfe..e4fbc5343 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -69,6 +69,9 @@ std::string PassRegistry::getPassDescription(std::string name) { void PassRegistry::registerPasses() { registerPass( "dae", "removes arguments to calls in an lto-like manner", createDAEPass); + registerPass("alignment-lowering", + "lower unaligned loads and stores to smaller aligned ones", + createAlignmentLoweringPass); registerPass("dae-optimizing", "removes arguments to calls in an lto-like manner, and " "optimizes where we removed", diff --git a/src/passes/passes.h b/src/passes/passes.h index fc01c1cd5..e562f4a42 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -22,6 +22,7 @@ namespace wasm { class Pass; // All passes: +Pass* createAlignmentLoweringPass(); Pass* createCoalesceLocalsPass(); Pass* createCoalesceLocalsWithLearningPass(); Pass* createCodeFoldingPass(); |