@@ -349,6 +349,12 @@ struct EscapeAnalyzer {
349349 void visitLocalSet (LocalSet* curr) { escapes = false ; }
350350
351351 // Reference operations. TODO add more
352+ void visitRefEq (RefEq* curr) {
353+ // The reference is compared for identity, but nothing more.
354+ escapes = false ;
355+ fullyConsumes = true ;
356+ }
357+
352358 void visitRefAs (RefAs* curr) {
353359 // TODO General OptimizeInstructions integration, that is, since we know
354360 // that our allocation is what flows into this RefAs, we can
@@ -507,14 +513,18 @@ struct EscapeAnalyzer {
507513// efficient, but it would need to be more complex.
508514struct Struct2Local : PostWalker<Struct2Local> {
509515 StructNew* allocation;
510- const EscapeAnalyzer& analyzer;
516+
517+ // The analyzer is not |const| because we update |analyzer.reached| as we go
518+ // (see replaceCurrent, below).
519+ EscapeAnalyzer& analyzer;
520+
511521 Function* func;
512522 Module& wasm;
513523 Builder builder;
514524 const FieldList& fields;
515525
516526 Struct2Local (StructNew* allocation,
517- const EscapeAnalyzer& analyzer,
527+ EscapeAnalyzer& analyzer,
518528 Function* func,
519529 Module& wasm)
520530 : allocation(allocation), analyzer(analyzer), func(func), wasm(wasm),
@@ -539,6 +549,15 @@ struct Struct2Local : PostWalker<Struct2Local> {
539549 // In rare cases we may need to refinalize, see below.
540550 bool refinalize = false ;
541551
552+ Expression* replaceCurrent (Expression* expression) {
553+ PostWalker<Struct2Local>::replaceCurrent (expression);
554+ // Also update |reached|: we are replacing something that was reached, so
555+ // logically the replacement is also reached. This update is necessary if
556+ // the parent of an expression cares about whether a child was reached.
557+ analyzer.reached .insert (expression);
558+ return expression;
559+ }
560+
542561 // Rewrite the code in visit* methods. The general approach taken is to
543562 // replace the allocation with a null reference (which may require changing
544563 // types in some places, like making a block return value nullable), and to
@@ -688,6 +707,27 @@ struct Struct2Local : PostWalker<Struct2Local> {
688707 replaceCurrent (builder.makeBlock (contents));
689708 }
690709
710+ void visitRefEq (RefEq* curr) {
711+ if (!analyzer.reached .count (curr)) {
712+ return ;
713+ }
714+
715+ if (curr->type == Type::unreachable) {
716+ // The result does not matter. Leave things as they are (and let DCE
717+ // handle it).
718+ return ;
719+ }
720+
721+ // If our reference is compared to itself, the result is 1. If it is
722+ // compared to something else, the result must be 0, as our reference does
723+ // not escape to any other place.
724+ int32_t result = analyzer.reached .count (curr->left ) > 0 &&
725+ analyzer.reached .count (curr->right ) > 0 ;
726+ // For simplicity, simply drop the RefEq and put a constant result after.
727+ replaceCurrent (builder.makeSequence (builder.makeDrop (curr),
728+ builder.makeConst (Literal (result))));
729+ }
730+
691731 void visitRefAs (RefAs* curr) {
692732 if (!analyzer.reached .count (curr)) {
693733 return ;
0 commit comments