diff options
Diffstat (limited to 'src/ir')
-rw-r--r-- | src/ir/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ir/effects.h | 10 | ||||
-rw-r--r-- | src/ir/intrinsics.cpp | 42 | ||||
-rw-r--r-- | src/ir/intrinsics.h | 95 |
4 files changed, 146 insertions, 2 deletions
diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index c17a48ac0..f598f3d72 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -2,6 +2,7 @@ FILE(GLOB ir_HEADERS *.h) set(ir_SOURCES ExpressionAnalyzer.cpp ExpressionManipulator.cpp + intrinsics.cpp names.cpp properties.cpp LocalGraph.cpp diff --git a/src/ir/effects.h b/src/ir/effects.h index ad8f68efa..ee45d8205 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -17,6 +17,7 @@ #ifndef wasm_ir_effects_h #define wasm_ir_effects_h +#include "ir/intrinsics.h" #include "pass.h" #include "wasm-traversal.h" @@ -31,7 +32,7 @@ public: Expression* ast = nullptr) : ignoreImplicitTraps(passOptions.ignoreImplicitTraps), trapsNeverHappen(passOptions.trapsNeverHappen), - debugInfo(passOptions.debugInfo), module(&module), + debugInfo(passOptions.debugInfo), module(module), features(module.features) { if (ast) { walk(ast); @@ -41,7 +42,7 @@ public: bool ignoreImplicitTraps; bool trapsNeverHappen; bool debugInfo; - Module* module; + Module& module; FeatureSet features; // Walk an expression and all its children. @@ -393,6 +394,11 @@ private: } void visitCall(Call* curr) { + // call.without.effects has no effects. + if (Intrinsics(parent.module).isCallWithoutEffects(curr)) { + return; + } + parent.calls = true; // When EH is enabled, any call can throw. if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) { diff --git a/src/ir/intrinsics.cpp b/src/ir/intrinsics.cpp new file mode 100644 index 000000000..c2318cabf --- /dev/null +++ b/src/ir/intrinsics.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2021 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. + */ + +#include "ir/intrinsics.h" +#include "wasm-builder.h" + +namespace wasm { + +static Name BinaryenIntrinsics("binaryen-intrinsics"), + CallWithoutEffects("call.without.effects"); + +bool Intrinsics::isCallWithoutEffects(Function* func) { + return func->module == BinaryenIntrinsics && func->base == CallWithoutEffects; +} + +Call* Intrinsics::isCallWithoutEffects(Expression* curr) { + if (auto* call = curr->dynCast<Call>()) { + // The target function may not exist if the module is still being + // constructed. + if (auto* func = module.getFunctionOrNull(call->target)) { + if (isCallWithoutEffects(func)) { + return call; + } + } + } + return nullptr; +} + +} // namespace wasm diff --git a/src/ir/intrinsics.h b/src/ir/intrinsics.h new file mode 100644 index 000000000..9a1356029 --- /dev/null +++ b/src/ir/intrinsics.h @@ -0,0 +1,95 @@ +/* + * Copyright 2021 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. + */ + +#ifndef wasm_ir_intrinsics_h +#define wasm_ir_intrinsics_h + +#include "pass.h" +#include "wasm-traversal.h" + +// +// See the README.md for background on intrinsic functions. +// +// Intrinsics can be recognized by Intrinsics::isFoo() methods, that check if a +// function is a particular intrinsic, or if a call to a function is so. The +// latter returns nullptr if the input is not that intrinsic, and otherwise the +// intrinsic itself cast to a Call*. +// + +namespace wasm { + +class Intrinsics { + Module& module; + +public: + Intrinsics(Module& module) : module(module) {} + + // + // Check if an instruction is the call.without.effects intrinsic. + // + // (import "binaryen-intrinsics" "call.without.effects" + // (func (..params..) (param $target funcref) (..results..))) + // + // call.without.effects can take any parameters, and in addition a funcref, + // and return any result. + // + // Precise semantics: + // + // * The optimizer will assume this instruction has no side effects. + // * Final lowering turns a call.without.effects into a call of the given + // function with the given parameters. (This will either be a direct call, + // or a call_ref; note that either way, the function reference that appears + // here must have the proper type - if not, you will get an error.) + // + // call.without.effects is useful to be able to get rid of an unused result + // that has side effects. For example, + // + // (drop (call $get-something)) + // + // cannot be removed, as a call has side effects. But if a code generator + // knows that it is fine to not make the call given that the result is + // dropped (perhaps the side effects are to initialize a global cache, for + // example) then instead of emitting + // + // (call $get-something) + // + // it can emit + // + // (call $call.without.effects (ref.func $get-something)) + // + // which will have this behavior in the optimizer if it is dropped: + // + // (drop (call $call.without.effects (ref.func $get-something))) + // => + // (drop (ref.func $get-something)) + // + // Later optimizations can remove the dropped ref.func. Or, if the result is + // actually used, + // + // (local.set $x (call $call.without.effects (ref.func $get-something))) + // => + // (local.set $x (call $get-something)) + // + // Later passes will then turn that into a direct call and further optimize + // things. + // + bool isCallWithoutEffects(Function* func); + Call* isCallWithoutEffects(Expression* curr); +}; + +} // namespace wasm + +#endif // wasm_ir_intrinsics_h |