|
154 | 154 | #include "ir/bits.h"
|
155 | 155 | #include "ir/branch-utils.h"
|
156 | 156 | #include "ir/eh-utils.h"
|
157 |
| -#include "ir/find_all.h" |
158 | 157 | #include "ir/local-graph.h"
|
159 | 158 | #include "ir/parents.h"
|
160 | 159 | #include "ir/properties.h"
|
@@ -402,7 +401,11 @@ struct EscapeAnalyzer {
|
402 | 401 | fullyConsumes = true;
|
403 | 402 | }
|
404 | 403 | } else {
|
405 |
| - assert(curr->desc == child); |
| 404 | + // Either the child is the descriptor, in which case we consume it, or |
| 405 | + // we have already optimized this ref.cast_desc for an allocation that |
| 406 | + // flowed through as its `ref`. In the latter case the current child |
| 407 | + // must have originally been the descriptor, so we can still say it's |
| 408 | + // fully consumed, but we cannot assert that curr->desc == child. |
406 | 409 | fullyConsumes = true;
|
407 | 410 | }
|
408 | 411 | }
|
@@ -850,19 +853,42 @@ struct Struct2Local : PostWalker<Struct2Local> {
|
850 | 853 | }
|
851 | 854 |
|
852 | 855 | if (curr->desc) {
|
853 |
| - // If we are doing a ref.cast_desc of the optimized allocation, but we |
854 |
| - // know it does not have a descriptor, then we know the cast must fail. We |
855 |
| - // also know the cast must fail if the optimized allocation flows in as |
856 |
| - // the descriptor, since it cannot possibly have been used in the |
857 |
| - // allocation of the cast value without having been considered to escape. |
858 |
| - if (!allocation->desc || analyzer.getInteraction(curr->desc) == |
859 |
| - ParentChildInteraction::Flows) { |
860 |
| - // The allocation does not have a descriptor, so there is no way for the |
861 |
| - // cast to succeed. |
862 |
| - replaceCurrent(builder.blockify(builder.makeDrop(curr->ref), |
863 |
| - builder.makeDrop(curr->desc), |
864 |
| - builder.makeUnreachable())); |
| 856 | + // If we are doing a ref.cast_desc of the optimized allocation, but the |
| 857 | + // allocation does not have a descriptor, then we know the cast must fail. |
| 858 | + // We also know the cast must fail (except for nulls it might let through) |
| 859 | + // if the optimized allocation flows in as the descriptor, since it cannot |
| 860 | + // possibly have been used in the allocation of the cast value without |
| 861 | + // having been considered to escape. |
| 862 | + bool allocIsCastDesc = |
| 863 | + analyzer.getInteraction(curr->desc) == ParentChildInteraction::Flows; |
| 864 | + if (!allocation->desc || allocIsCastDesc) { |
| 865 | + // It would seem convenient to use ChildLocalizer here, but we cannot. |
| 866 | + // ChildLocalizer would create a local.set for a desc operand with |
| 867 | + // side effects, but that local.set would not be reflected in the parent |
| 868 | + // map, so it would not be updated if the allocation flowing through |
| 869 | + // that desc operand were later optimized. |
| 870 | + if (allocIsCastDesc && curr->type.isNullable()) { |
| 871 | + // There might be a null value to let through. Reuse curr as a cast to |
| 872 | + // null. Use a scratch local to move the reference value past the desc |
| 873 | + // value. |
| 874 | + Index scratch = builder.addVar(func, curr->ref->type); |
| 875 | + replaceCurrent( |
| 876 | + builder.blockify(builder.makeLocalSet(scratch, curr->ref), |
| 877 | + builder.makeDrop(curr->desc), |
| 878 | + curr)); |
| 879 | + curr->desc = nullptr; |
| 880 | + curr->type = curr->type.with(curr->type.getHeapType().getBottom()); |
| 881 | + curr->ref = builder.makeLocalGet(scratch, curr->ref->type); |
| 882 | + } else { |
| 883 | + // Either the cast does not allow nulls or we know the value isn't |
| 884 | + // null anyway, so the cast certainly fails. |
| 885 | + replaceCurrent(builder.blockify(builder.makeDrop(curr->ref), |
| 886 | + builder.makeDrop(curr->desc), |
| 887 | + builder.makeUnreachable())); |
| 888 | + } |
865 | 889 | } else {
|
| 890 | + assert(analyzer.getInteraction(curr->ref) == |
| 891 | + ParentChildInteraction::Flows); |
866 | 892 | // The cast succeeds iff the optimized allocation's descriptor is the
|
867 | 893 | // same as the given descriptor and traps otherwise.
|
868 | 894 | auto type = allocation->desc->type;
|
|
0 commit comments