summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/I64ToI32Lowering.cpp21
1 files changed, 21 insertions, 0 deletions
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index a1686d27d..33bb7229e 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -28,6 +28,7 @@
#include "support/name.h"
#include "wasm-builder.h"
#include "ir/flat.h"
+#include "ir/iteration.h"
#include "ir/memory-utils.h"
#include "ir/module-utils.h"
#include "ir/names.h"
@@ -464,6 +465,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
void visitSetGlobal(SetGlobal* curr) {
+ if (handleUnreachable(curr)) return;
if (!originallyI64Globals.count(curr->name)) return;
TempVar highBits = fetchOutParam(curr->value);
auto* setHigh = builder->makeSetGlobal(
@@ -1578,6 +1580,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
}
void visitSelect(Select* curr) {
+ if (handleUnreachable(curr)) return;
if (!hasOutParam(curr->ifTrue)) {
assert(!hasOutParam(curr->ifFalse));
return;
@@ -1669,6 +1672,24 @@ private:
highBitVars.erase(e);
return ret;
}
+
+ // If e.g. a select is unreachable, then one arm may have an out param
+ // but not the other. In this case dce should really have been run
+ // before; handle it in a simple way here.
+ bool handleUnreachable(Expression* curr) {
+ if (curr->type != unreachable) return false;
+ std::vector<Expression*> children;
+ for (auto* child : ChildIterator(curr)) {
+ if (isConcreteType(child->type)) {
+ child = builder->makeDrop(child);
+ }
+ children.push_back(child);
+ }
+ auto* block = builder->makeBlock(children);
+ assert(block->type == unreachable);
+ replaceCurrent(block);
+ return true;
+ }
};
Pass *createI64ToI32LoweringPass() {