summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast_utils.h23
-rw-r--r--src/passes/RemoveUnusedBrs.cpp9
-rw-r--r--src/wasm-linker.cpp6
3 files changed, 25 insertions, 13 deletions
diff --git a/src/ast_utils.h b/src/ast_utils.h
index 55499d808..66dbf039a 100644
--- a/src/ast_utils.h
+++ b/src/ast_utils.h
@@ -49,6 +49,11 @@ struct BreakSeeker : public PostWalker<BreakSeeker, Visitor<BreakSeeker>> {
// TODO: optimize
struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer>> {
+ EffectAnalyzer() {}
+ EffectAnalyzer(Expression *ast) {
+ walk(ast);
+ }
+
bool branches = false;
bool calls = false;
std::set<Index> localsRead;
@@ -115,9 +120,21 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer
};
struct ExpressionManipulator {
- // Nop is the smallest node, so we can always nop-ify another node in our arena
- static void nop(Expression* target) {
- *static_cast<Nop*>(target) = Nop();
+ // Re-use a node's memory. This helps avoid allocation when optimizing.
+ template<typename InputType, typename OutputType>
+ static OutputType* convert(InputType *input) {
+ static_assert(sizeof(OutputType) <= sizeof(InputType),
+ "Can only convert to a smaller size Expression node");
+ input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
+ OutputType* output = (OutputType*)(input);
+ new (output) OutputType;
+ return output;
+ }
+
+ // Convenience method for nop, which is a common conversion
+ template<typename InputType>
+ static void nop(InputType* target) {
+ convert<InputType, Nop>(target);
}
};
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index f4efef173..5c21908a8 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -181,14 +181,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R
if (curr->ifFalse) {
// if with else, consider turning it into a select if there is no control flow
// TODO: estimate cost
- EffectAnalyzer condition;
- condition.walk(curr->condition);
+ EffectAnalyzer condition(curr->condition);
if (!condition.hasSideEffects()) {
- EffectAnalyzer ifTrue;
- ifTrue.walk(curr->ifTrue);
+ EffectAnalyzer ifTrue(curr->ifTrue);
if (!ifTrue.hasSideEffects()) {
- EffectAnalyzer ifFalse;
- ifFalse.walk(curr->ifFalse);
+ EffectAnalyzer ifFalse(curr->ifFalse);
if (!ifFalse.hasSideEffects()) {
auto* select = getModule()->allocator.alloc<Select>();
select->condition = curr->condition;
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index 4fb7ea4ae..7524f439a 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -16,6 +16,7 @@
#include "wasm-linker.h"
#include "asm_v_wasm.h"
+#include "ast_utils.h"
#include "support/utilities.h"
#include "wasm-builder.h"
#include "wasm-printing.h"
@@ -64,12 +65,9 @@ void Linker::layout() {
// Change each call. The target is the same since it's still the name.
// Delete and re-allocate the Expression as CallImport to avoid undefined
// behavior.
- static_assert(sizeof(Call) >= sizeof(CallImport),
- "Cannot reallocate a CallImport in a Call arena slot");
for (auto* call : f.second) {
Call callCopy = std::move(*call);
- call->~Call();
- CallImport* newCall = new (call) CallImport;
+ CallImport* newCall = ExpressionManipulator::convert<Call, CallImport>(call);
newCall->type = callCopy.type;
newCall->operands = std::move(callCopy.operands);
newCall->target = target;