diff options
author | Daniel Wirtz <dcode@dcode.io> | 2020-01-17 18:43:45 +0100 |
---|---|---|
committer | Alon Zakai <azakai@google.com> | 2020-01-17 09:43:44 -0800 |
commit | 98f5507c508d6fde326347df3fcad70740b634ea (patch) | |
tree | 3b8a7f1420ba81ca8e8df5b10a9e744a3602e6b4 | |
parent | e873e2a84db3fda3c8df5ed8e0b39578a1fb2f2d (diff) | |
download | binaryen-98f5507c508d6fde326347df3fcad70740b634ea.tar.gz binaryen-98f5507c508d6fde326347df3fcad70740b634ea.tar.bz2 binaryen-98f5507c508d6fde326347df3fcad70740b634ea.zip |
Expose ExpressionAnalyzer in C-/JS-API (#2585)
Instead of reinventing the wheel on our side, this adds ExpressionAnalyzer
bindings to the C- and JS-APIs, which can be useful for generators. For
example, a generator may decide to simplify a compilation step if a
subexpression doesn't have any side effects, or simply skip emitting
something that is likely to compile to a drop or an empty block right away.
-rw-r--r-- | src/binaryen-c.cpp | 59 | ||||
-rw-r--r-- | src/binaryen-c.h | 22 | ||||
-rw-r--r-- | src/ir/effects.h | 51 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 23 | ||||
-rw-r--r-- | test/binaryen.js/sideffects.js | 94 | ||||
-rw-r--r-- | test/binaryen.js/sideffects.js.txt | 12 |
6 files changed, 261 insertions, 0 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 79571bd96..d0c672abd 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -4449,6 +4449,65 @@ void BinaryenAddCustomSection(BinaryenModuleRef module, } // +// ========= Effect analyzer ========= +// + +BinaryenSideEffects BinaryenSideEffectNone(void) { + return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::None); +} +BinaryenSideEffects BinaryenSideEffectBranches(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::Branches); +} +BinaryenSideEffects BinaryenSideEffectCalls(void) { + return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Calls); +} +BinaryenSideEffects BinaryenSideEffectReadsLocal(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::ReadsLocal); +} +BinaryenSideEffects BinaryenSideEffectWritesLocal(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::WritesLocal); +} +BinaryenSideEffects BinaryenSideEffectReadsGlobal(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::ReadsGlobal); +} +BinaryenSideEffects BinaryenSideEffectWritesGlobal(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::WritesGlobal); +} +BinaryenSideEffects BinaryenSideEffectReadsMemory(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::ReadsMemory); +} +BinaryenSideEffects BinaryenSideEffectWritesMemory(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::WritesMemory); +} +BinaryenSideEffects BinaryenSideEffectImplicitTrap(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::ImplicitTrap); +} +BinaryenSideEffects BinaryenSideEffectIsAtomic(void) { + return static_cast<BinaryenSideEffects>( + EffectAnalyzer::SideEffects::IsAtomic); +} +BinaryenSideEffects BinaryenSideEffectAny(void) { + return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Any); +} + +BinaryenSideEffects +BinaryenExpressionGetSideEffects(BinaryenExpressionRef expr) { + if (tracing) { + std::cout << " BinaryenExpressionGetSideEffects(expressions[" + << expressions[expr] << "]);\n"; + } + return EffectAnalyzer(globalPassOptions, (Expression*)expr).getSideEffects(); +} + +// // ========== CFG / Relooper ========== // diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 36d82ecb0..067812438 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -1479,6 +1479,28 @@ BINARYEN_API void BinaryenAddCustomSection(BinaryenModuleRef module, BinaryenIndex contentsSize); // +// ========= Effect analyzer ========= +// + +typedef uint32_t BinaryenSideEffects; + +BINARYEN_API BinaryenSideEffects BinaryenSideEffectNone(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectBranches(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectCalls(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsLocal(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesLocal(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsGlobal(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesGlobal(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsMemory(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesMemory(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectImplicitTrap(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectIsAtomic(void); +BINARYEN_API BinaryenSideEffects BinaryenSideEffectAny(void); + +BINARYEN_API BinaryenSideEffects +BinaryenExpressionGetSideEffects(BinaryenExpressionRef expr); + +// // ========== CFG / Relooper ========== // // General usage is (1) create a relooper, (2) create blocks, (3) add diff --git a/src/ir/effects.h b/src/ir/effects.h index 9c8887333..0d1e2c2b1 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -408,6 +408,57 @@ struct EffectAnalyzer EffectAnalyzer bEffects(passOptions, b); return !aEffects.invalidates(bEffects); } + + // C-API + + enum SideEffects : uint32_t { + None = 0, + Branches = 1 << 0, + Calls = 1 << 1, + ReadsLocal = 1 << 2, + WritesLocal = 1 << 3, + ReadsGlobal = 1 << 4, + WritesGlobal = 1 << 5, + ReadsMemory = 1 << 6, + WritesMemory = 1 << 7, + ImplicitTrap = 1 << 8, + IsAtomic = 1 << 9, + Any = (1 << 10) - 1 + }; + uint32_t getSideEffects() const { + uint32_t effects = 0; + if (branches) { + effects |= SideEffects::Branches; + } + if (calls) { + effects |= SideEffects::Calls; + } + if (localsRead.size() > 0) { + effects |= SideEffects::ReadsLocal; + } + if (localsWritten.size() > 0) { + effects |= SideEffects::WritesLocal; + } + if (globalsRead.size() > 0) { + effects |= SideEffects::ReadsGlobal; + } + if (globalsWritten.size() > 0) { + effects |= SideEffects::WritesGlobal; + } + if (readsMemory) { + effects |= SideEffects::ReadsMemory; + } + if (writesMemory) { + effects |= SideEffects::WritesMemory; + } + if (implicitTrap) { + effects |= SideEffects::ImplicitTrap; + } + if (isAtomic) { + effects |= SideEffects::IsAtomic; + } + return effects; + } }; } // namespace wasm diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 2993573d1..54f21ed07 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -457,6 +457,24 @@ function initializeConstants() { ].forEach(function(name) { Module['Operations'][name] = Module[name] = Module['_Binaryen' + name](); }); + + // Expression side effects + Module['SideEffects'] = {}; + [ 'None', + 'Branches', + 'Calls', + 'ReadsLocal', + 'WritesLocal', + 'ReadsGlobal', + 'WritesGlobal', + 'ReadsMemory', + 'WritesMemory', + 'ImplicitTrap', + 'IsAtomic', + 'Any' + ].forEach(function(name) { + Module['SideEffects'][name] = Module['_BinaryenSideEffect' + name](); + }); } // 'Module' interface @@ -2739,6 +2757,11 @@ Module['getExpressionInfo'] = function(expr) { } }; +// Gets the side effects of the specified expression +Module['getSideEffects'] = function(expr) { + return Module['_BinaryenExpressionGetSideEffects'](expr); +}; + Module['createType'] = function(types) { return preserveStack(function() { var array = i32sToStack(types); diff --git a/test/binaryen.js/sideffects.js b/test/binaryen.js/sideffects.js new file mode 100644 index 000000000..a486099dc --- /dev/null +++ b/test/binaryen.js/sideffects.js @@ -0,0 +1,94 @@ +console.log("SideEffects.None=" + binaryen.SideEffects.None); +console.log("SideEffects.Branches=" + binaryen.SideEffects.Branches); +console.log("SideEffects.Calls=" + binaryen.SideEffects.Calls); +console.log("SideEffects.ReadsLocal=" + binaryen.SideEffects.ReadsLocal); +console.log("SideEffects.WritesLocal=" + binaryen.SideEffects.WritesLocal); +console.log("SideEffects.ReadsGlobal=" + binaryen.SideEffects.ReadsGlobal); +console.log("SideEffects.WritesGlobal=" + binaryen.SideEffects.WritesGlobal); +console.log("SideEffects.ReadsMemory=" + binaryen.SideEffects.ReadsMemory); +console.log("SideEffects.WritesMemory=" + binaryen.SideEffects.WritesMemory); +console.log("SideEffects.ImplicitTrap=" + binaryen.SideEffects.ImplicitTrap); +console.log("SideEffects.IsAtomic=" + binaryen.SideEffects.IsAtomic); +console.log("SideEffects.Any=" + binaryen.SideEffects.Any); + +var module = new binaryen.Module(); +assert( + binaryen.getSideEffects( + module.i32.const(1) + ) + == + binaryen.SideEffects.None +); +assert( + binaryen.getSideEffects( + module.br("test") + ) + == + binaryen.SideEffects.Branches +); +assert( + binaryen.getSideEffects( + module.call("test", [], binaryen.i32) + ) + == + binaryen.SideEffects.Calls +); +assert( + binaryen.getSideEffects( + module.local.get("test", binaryen.i32) + ) + == + binaryen.SideEffects.ReadsLocal +); +assert( + binaryen.getSideEffects( + module.local.set("test", + module.i32.const(1) + ) + ) + == + binaryen.SideEffects.WritesLocal +); +assert( + binaryen.getSideEffects( + module.global.get("test", binaryen.i32) + ) + == + binaryen.SideEffects.ReadsGlobal +); +assert( + binaryen.getSideEffects( + module.global.set("test", module.i32.const(1)) + ) + == + binaryen.SideEffects.WritesGlobal +); +assert( + binaryen.getSideEffects( + module.i32.load(0, 0, + module.i32.const(0) + ) + ) + == + binaryen.SideEffects.ReadsMemory | binaryen.SideEffects.ImplicitTrap +); +assert( + binaryen.getSideEffects( + module.i32.store(0, 0, + module.i32.const(0), + module.i32.const(1) + ) + ) + == + binaryen.SideEffects.WritesMemory | binaryen.SideEffects.ImplicitTrap +); +assert( + binaryen.getSideEffects( + module.i32.div_s( + module.i32.const(1), + module.i32.const(0) + ) + ) + == + binaryen.SideEffects.ImplicitTrap +); diff --git a/test/binaryen.js/sideffects.js.txt b/test/binaryen.js/sideffects.js.txt new file mode 100644 index 000000000..54a1e14bc --- /dev/null +++ b/test/binaryen.js/sideffects.js.txt @@ -0,0 +1,12 @@ +SideEffects.None=0 +SideEffects.Branches=1 +SideEffects.Calls=2 +SideEffects.ReadsLocal=4 +SideEffects.WritesLocal=8 +SideEffects.ReadsGlobal=16 +SideEffects.WritesGlobal=32 +SideEffects.ReadsMemory=64 +SideEffects.WritesMemory=128 +SideEffects.ImplicitTrap=256 +SideEffects.IsAtomic=512 +SideEffects.Any=1023 |