diff options
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/LogExecution.cpp | 77 | ||||
-rw-r--r-- | src/passes/pass.cpp | 1 | ||||
-rw-r--r-- | src/passes/passes.h | 2 | ||||
-rw-r--r-- | test/passes/log-execution.txt | 88 | ||||
-rw-r--r-- | test/passes/log-execution.wast | 35 |
6 files changed, 203 insertions, 1 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index 876a71d74..75e634c16 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -8,6 +8,7 @@ SET(passes_SOURCES Inlining.cpp LegalizeJSInterface.cpp LocalCSE.cpp + LogExecution.cpp MemoryPacking.cpp MergeBlocks.cpp Metrics.cpp diff --git a/src/passes/LogExecution.cpp b/src/passes/LogExecution.cpp new file mode 100644 index 000000000..8d555fefe --- /dev/null +++ b/src/passes/LogExecution.cpp @@ -0,0 +1,77 @@ +/* + * 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. + */ + +// +// Instruments the build with code to log execution at each function +// entry and loop header. This can be useful in debugging, to log out +// a trace, and diff it to another (running in another browser, to +// check for bugs, for example). +// +// The logging is performed by calling an ffi with an id for each +// call site. You need to provide that import on the JS side. +// + +#include <wasm.h> +#include <wasm-builder.h> +#include <pass.h> +#include "shared-constants.h" +#include "asmjs/shared-constants.h" +#include "asm_v_wasm.h" + +namespace wasm { + +Name LOGGER("log_execution"); + +struct LogExecution : public WalkerPass<PostWalker<LogExecution>> { + void visitLoop(Loop* curr) { + curr->body = makeLogCall(curr->body); + } + + void visitFunction(Function* curr) { + curr->body = makeLogCall(curr->body); + } + + void visitModule(Module *curr) { + // Add the import + auto import = new Import; + import->name = LOGGER; + import->module = ENV; + import->base = LOGGER; + import->functionType = ensureFunctionType("vi", curr)->name; + import->kind = ExternalKind::Function; + curr->addImport(import); + } + +private: + Expression* makeLogCall(Expression* curr) { + static Index id = 0; + Builder builder(*getModule()); + return builder.makeSequence( + builder.makeCallImport( + LOGGER, + { builder.makeConst(Literal(int32_t(id++))) }, + none + ), + curr + ); + } +}; + +Pass *createLogExecutionPass() { + return new LogExecution(); +} + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index a82b2fa58..577a460cb 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -72,6 +72,7 @@ void PassRegistry::registerPasses() { registerPass("inlining", "inlines functions (currently only ones with a single use)", createInliningPass); registerPass("legalize-js-interface", "legalizes i64 types on the import/export boundary", createLegalizeJSInterfacePass); registerPass("local-cse", "common subexpression elimination inside basic blocks", createLocalCSEPass); + registerPass("log-execution", "instrument the build with logging of where execution goes", createLogExecutionPass); registerPass("memory-packing", "packs memory into separate segments, skipping zeros", createMemoryPackingPass); registerPass("merge-blocks", "merges blocks to their parents", createMergeBlocksPass); registerPass("metrics", "reports metrics", createMetricsPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index c3660b048..f8156d4fe 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -32,7 +32,7 @@ Pass *createFullPrinterPass(); Pass *createInliningPass(); Pass *createLegalizeJSInterfacePass(); Pass *createLocalCSEPass(); -Pass *createLowerIfElsePass(); +Pass *createLogExecutionPass(); Pass *createMemoryPackingPass(); Pass *createMergeBlocksPass(); Pass *createMinifiedPrinterPass(); diff --git a/test/passes/log-execution.txt b/test/passes/log-execution.txt new file mode 100644 index 000000000..32bbd88eb --- /dev/null +++ b/test/passes/log-execution.txt @@ -0,0 +1,88 @@ +(module + (type $0 (func)) + (type $1 (func (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (import "env" "log_execution" (func $log_execution (param i32))) + (memory $0 0) + (func $nopp (type $0) + (call $log_execution + (i32.const 0) + ) + (nop) + ) + (func $intt (type $1) (result i32) + (call $log_execution + (i32.const 1) + ) + (i32.const 10) + ) + (func $workk (type $0) + (call $log_execution + (i32.const 2) + ) + (block + (if + (i32.const 0) + (nop) + ) + (drop + (i32.const 1) + ) + ) + ) + (func $loops (type $0) + (call $log_execution + (i32.const 6) + ) + (block + (loop $x + (call $log_execution + (i32.const 3) + ) + (block + (call $loops) + (br $x) + ) + ) + (if + (call $intt) + (loop $y + (call $log_execution + (i32.const 4) + ) + (call $loops) + ) + ) + (loop $loop-in + (call $log_execution + (i32.const 5) + ) + (block + (drop + (i32.const 10) + ) + (drop + (i32.const 20) + ) + (drop + (i32.const 30) + ) + ) + ) + ) + ) + (func $loops-similar (type $0) + (call $log_execution + (i32.const 8) + ) + (loop $x + (call $log_execution + (i32.const 7) + ) + (block + (call $loops) + (br $x) + ) + ) + ) +) diff --git a/test/passes/log-execution.wast b/test/passes/log-execution.wast new file mode 100644 index 000000000..12175fbcb --- /dev/null +++ b/test/passes/log-execution.wast @@ -0,0 +1,35 @@ +(module + (func $nopp + (nop) + ) + (func $intt (result i32) + (i32.const 10) + ) + (func $workk + (if (i32.const 0) (nop)) + (drop (i32.const 1)) + ) + (func $loops + (loop $x + (call $loops) + (br $x) + ) + (if (call $intt) + (loop $y + (call $loops) + ) + ) + (loop + (drop (i32.const 10)) + (drop (i32.const 20)) + (drop (i32.const 30)) + ) + ) + (func $loops-similar + (loop $x + (call $loops) + (br $x) + ) + ) +) + |