summaryrefslogtreecommitdiff
path: root/src/passes/StackIR.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/StackIR.cpp')
-rw-r--r--src/passes/StackIR.cpp44
1 files changed, 40 insertions, 4 deletions
diff --git a/src/passes/StackIR.cpp b/src/passes/StackIR.cpp
index fbb990fe0..a3d9442bf 100644
--- a/src/passes/StackIR.cpp
+++ b/src/passes/StackIR.cpp
@@ -51,10 +51,14 @@ class StackIROptimizer {
Function* func;
PassOptions& passOptions;
StackIR& insts;
+ FeatureSet features;
public:
- StackIROptimizer(Function* func, PassOptions& passOptions)
- : func(func), passOptions(passOptions), insts(*func->stackIR.get()) {
+ StackIROptimizer(Function* func,
+ PassOptions& passOptions,
+ FeatureSet features)
+ : func(func), passOptions(passOptions), insts(*func->stackIR.get()),
+ features(features) {
assert(func->stackIR);
}
@@ -65,7 +69,39 @@ public:
if (passOptions.optimizeLevel >= 3 || passOptions.shrinkLevel >= 1) {
local2Stack();
}
- removeUnneededBlocks();
+ // Removing unneeded blocks is dangerous with GC, as if we do this:
+ //
+ // (call
+ // (rtt)
+ // (block
+ // (nop)
+ // (i32)
+ // )
+ // )
+ // === remove inner block ==>
+ // (call
+ // (rtt)
+ // (nop)
+ // (i32)
+ // )
+ //
+ // Then we end up with a nop that forces us to emit this during load:
+ //
+ // (call
+ // (block
+ // (local.set
+ // (rtt)
+ // )
+ // (nop)
+ // (local.get)
+ // )
+ // (i32)
+ // )
+ //
+ // However, that is not valid as an rtt cannot be set to a local.
+ if (!features.hasGC()) {
+ removeUnneededBlocks();
+ }
dce();
}
@@ -340,7 +376,7 @@ struct OptimizeStackIR : public WalkerPass<PostWalker<OptimizeStackIR>> {
if (!func->stackIR) {
return;
}
- StackIROptimizer(func, getPassOptions()).run();
+ StackIROptimizer(func, getPassOptions(), getModule()->features).run();
}
};