@@ -461,40 +461,31 @@ struct EscapeAnalyzer {
461461 }
462462 }
463463 void visitArraySet (ArraySet* curr) {
464- if (!curr->index ->is <Const>()) {
465- // Array operations on nonconstant indexes do not escape in the normal
466- // sense, but they do escape from our being able to analyze them, so
467- // stop as soon as we see one.
468- return ;
469- }
470-
471- // As StructGet.
472- if (curr->ref == child) {
464+ // Arrays flowing into array operations on nonconstant indexes do not
465+ // escape in the normal sense, but they do escape from our being able to
466+ // analyze them, so stop as soon as we see one.
467+ if (child == curr->ref && curr->index ->is <Const>()) {
473468 escapes = false ;
474469 fullyConsumes = true ;
475470 }
476471 }
477472 void visitArrayGet (ArrayGet* curr) {
478- if (!curr->index ->is <Const>()) {
479- return ;
473+ if (child == curr->ref && curr->index ->is <Const>()) {
474+ escapes = false ;
475+ fullyConsumes = true ;
480476 }
481- escapes = false ;
482- fullyConsumes = true ;
483477 }
484478 void visitArrayRMW (ArrayRMW* curr) {
485- if (!curr->index ->is <Const>()) {
486- return ;
487- }
488- if (curr->ref == child) {
479+ if (child == curr->ref && curr->index ->is <Const>()) {
489480 escapes = false ;
490481 fullyConsumes = true ;
491482 }
492483 }
493484 void visitArrayCmpxchg (ArrayCmpxchg* curr) {
494- if (!curr-> index -> is <Const>()) {
495- return ;
496- }
497- if (curr-> ref == child || curr->expected == child ) {
485+ // Allocations flowing into `expected` are fully consumed and
486+ // optimizable even if the index is not constant.
487+ if (child == curr-> expected ||
488+ (child == curr->ref && curr-> index -> is <Const>()) ) {
498489 escapes = false ;
499490 fullyConsumes = true ;
500491 }
@@ -1233,9 +1224,15 @@ struct Struct2Local : PostWalker<Struct2Local> {
12331224 auto refScratch = builder.addVar (func, refType);
12341225 auto * setRefScratch = builder.makeLocalSet (refScratch, curr->ref );
12351226 auto * getRefScratch = builder.makeLocalGet (refScratch, refType);
1227+
1228+ auto indexScratch = builder.addVar (func, Type::i32 );
1229+ auto * setIndexScratch = builder.makeLocalSet (indexScratch, curr->index );
1230+ auto * getIndexScratch = builder.makeLocalGet (indexScratch, Type::i32 );
1231+
12361232 auto * arrayGet = builder.makeArrayGet (
1237- getRefScratch, curr-> index , curr->order , curr->type );
1233+ getRefScratch, getIndexScratch , curr->order , curr->type );
12381234 auto * block = builder.makeBlock ({setRefScratch,
1235+ setIndexScratch,
12391236 builder.makeDrop (curr->expected ),
12401237 builder.makeDrop (curr->replacement ),
12411238 arrayGet});
@@ -1467,19 +1464,19 @@ struct Array2Struct : PostWalker<Array2Struct> {
14671464 return ;
14681465 }
14691466
1470- auto index = getIndex (curr->index );
1471- if (index >= numFields) {
1472- replaceCurrent (builder.makeBlock ({builder.makeDrop (curr->ref ),
1473- builder.makeDrop (curr->expected ),
1474- builder.makeDrop (curr->replacement ),
1475- builder.makeUnreachable ()}));
1476- refinalize = true ;
1477- return ;
1478- }
1479-
14801467 // The allocation might flow into `ref` or `expected`, but not
14811468 // `replacement`, because then it would be considered to have escaped.
14821469 if (analyzer.getInteraction (curr->ref ) == ParentChildInteraction::Flows) {
1470+ auto index = getIndex (curr->index );
1471+ if (index >= numFields) {
1472+ replaceCurrent (builder.makeBlock ({builder.makeDrop (curr->ref ),
1473+ builder.makeDrop (curr->expected ),
1474+ builder.makeDrop (curr->replacement ),
1475+ builder.makeUnreachable ()}));
1476+ refinalize = true ;
1477+ return ;
1478+ }
1479+
14831480 // The accessed array is being optimized. Convert the ArrayCmpxchg into a
14841481 // StructCmpxchg.
14851482 replaceCurrent (builder.makeStructCmpxchg (
0 commit comments