@@ -351,13 +351,10 @@ struct GlobalStructInference : public Pass {
351351 if (!global->mutable_ && !global->imported ()) {
352352 if (auto * structNew = global->init ->dynCast <StructNew>()) {
353353 auto value = readFromStructNew (structNew, fieldIndex, field);
354- // TODO: handle non-constant values using unnesting, as below.
355- if (value.isConstant ()) {
356- replaceCurrent (value.getConstant ().makeExpression (wasm));
357- return ;
358- }
359- // Otherwise, continue to try the main type-based optimization
360- // below.
354+ // We know the exact global being read here.
355+ value.globals .push_back (global->name );
356+ replaceCurrent (getReadValue (value, fieldIndex, field, curr));
357+ return ;
361358 }
362359 }
363360 }
@@ -433,52 +430,6 @@ struct GlobalStructInference : public Pass {
433430 }
434431 }
435432
436- // Helper for optimization: Given a Value, returns what we should read
437- // for it.
438- auto getReadValue = [&](const Value& value) -> Expression* {
439- Expression* ret;
440- if (value.isConstant ()) {
441- // This is known to be a constant, so simply emit an expression for
442- // that constant, and handle if the field is packed.
443- ret = value.getConstant ().makeExpression (wasm);
444- if (field) {
445- ret = Bits::makePackedFieldGet (
446- ret, *field, curr->cast <StructGet>()->signed_ , wasm);
447- }
448- } else {
449- // Otherwise, this is non-constant, so we are in the situation where
450- // we want to un-nest the value out of the struct.new it is in. Note
451- // that for later work, as we cannot add a global in parallel.
452-
453- // There can only be one global in a value that is not constant,
454- // which is the global we want to read from.
455- assert (value.globals .size () == 1 );
456-
457- // Create a global.get with temporary name, leaving only the
458- // updating of the name to later work.
459- auto * get = builder.makeGlobalGet (value.globals [0 ],
460- value.getExpression ()->type );
461-
462- globalsToUnnest.emplace_back (
463- GlobalToUnnest{value.globals [0 ], fieldIndex, get});
464-
465- ret = get;
466- }
467-
468- // If the type is more refined, we must refinalize. For example, we
469- // might have a struct.get that normally returns anyref, and know that
470- // field contains null, so we return nullref.
471- if (ret->type != curr->type ) {
472- refinalize = true ;
473- }
474-
475- // This value replaces the struct.get, so it should have the same
476- // source location.
477- debuginfo::copyOriginalToReplacement (curr, ret, getFunction ());
478-
479- return ret;
480- };
481-
482433 // We have some globals (at least 2), and so must have at least one
483434 // value. And we have already exited if we have more than 2 values (see
484435 // the early return above) so that only leaves 1 and 2.
@@ -489,7 +440,7 @@ struct GlobalStructInference : public Pass {
489440 // not need a fence.
490441 replaceCurrent (builder.makeSequence (
491442 builder.makeDrop (builder.makeRefAs (RefAsNonNull, ref)),
492- getReadValue (values[0 ])));
443+ getReadValue (values[0 ], fieldIndex, field, curr )));
493444 return ;
494445 }
495446 assert (values.size () == 2 );
@@ -513,8 +464,8 @@ struct GlobalStructInference : public Pass {
513464 auto checkGlobal = values[0 ].globals [0 ];
514465 // Compute the left and right values before the next line, as the order
515466 // of their execution matters (they may note globals for un-nesting).
516- auto * left = getReadValue (values[0 ]);
517- auto * right = getReadValue (values[1 ]);
467+ auto * left = getReadValue (values[0 ], fieldIndex, field, curr );
468+ auto * right = getReadValue (values[1 ], fieldIndex, field, curr );
518469 // Note that we must trap on null, so add a ref.as_non_null here. As
519470 // before, the get cannot have synchronized with anything.
520471 Expression* getGlobal =
@@ -556,6 +507,64 @@ struct GlobalStructInference : public Pass {
556507 }
557508 return value;
558509 }
510+
511+ // Given a Value, returns what we should read for it.
512+ Expression* getReadValue (const Value& value,
513+ Index fieldIndex,
514+ std::optional<Field>& field,
515+ Expression* curr) {
516+ auto & wasm = *getModule ();
517+ Builder builder (wasm);
518+
519+ Expression* ret;
520+ if (value.isConstant ()) {
521+ // This is known to be a constant, so simply emit an expression for
522+ // that constant, and handle if the field is packed.
523+ ret = value.getConstant ().makeExpression (wasm);
524+ if (field) {
525+ ret = Bits::makePackedFieldGet (
526+ ret, *field, curr->cast <StructGet>()->signed_ , wasm);
527+ }
528+ } else {
529+ // Otherwise, this is non-constant, so we are in the situation where
530+ // we want to un-nest the value out of the struct.new it is in. Note
531+ // that for later work, as we cannot add a global in parallel.
532+
533+ // There can only be one global in a value that is not constant,
534+ // which is the global we want to read from.
535+ assert (value.globals .size () == 1 );
536+
537+ // Create a global.get with temporary name, leaving only the
538+ // updating of the name to later work.
539+ auto * get = builder.makeGlobalGet (value.globals [0 ],
540+ value.getExpression ()->type );
541+
542+ globalsToUnnest.emplace_back (
543+ GlobalToUnnest{value.globals [0 ], fieldIndex, get});
544+
545+ ret = get;
546+ }
547+
548+ // We must add a cast to non-null in some cases: A read of a null
549+ // descriptor returns a non-null value, so if there was a null in the
550+ // global, that would not validate by itself.
551+ if (ret->type .isNullable () && curr->type .isNonNullable ()) {
552+ ret = builder.makeRefAs (RefAsNonNull, ret);
553+ }
554+
555+ // If the type is more refined, we must refinalize. For example, we
556+ // might have a struct.get that normally returns anyref, and know that
557+ // field contains null, so we return nullref.
558+ if (ret->type != curr->type ) {
559+ refinalize = true ;
560+ }
561+
562+ // This value replaces the struct.get, so it should have the same
563+ // source location.
564+ debuginfo::copyOriginalToReplacement (curr, ret, getFunction ());
565+
566+ return ret;
567+ }
559568 };
560569
561570 // Find the optimization opportunitites in parallel.
0 commit comments