Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,14 +618,17 @@
("i31.get_u", "makeI31Get(false)"),
("ref.test", "makeRefTest()"),
("ref.cast", "makeRefCast(false)"),
("ref.cast_desc", "makeRefCast(true)"),
("ref.cast_desc", "makeRefCast(true)"), # Deprecated
("ref.cast_desc_eq", "makeRefCast(true)"),
("ref.get_desc", "makeRefGetDesc()"),
("br_on_null", "makeBrOnNull()"),
("br_on_non_null", "makeBrOnNull(true)"),
("br_on_cast", "makeBrOnCast(BrOnCast)"),
("br_on_cast_fail", "makeBrOnCast(BrOnCastFail)"),
("br_on_cast_desc", "makeBrOnCast(BrOnCastDesc)"),
("br_on_cast_desc_fail", "makeBrOnCast(BrOnCastDescFail)"),
("br_on_cast_desc", "makeBrOnCast(BrOnCastDescEq)"), # Deprecated
("br_on_cast_desc_fail", "makeBrOnCast(BrOnCastDescEqFail)"), # Deprecated
("br_on_cast_desc_eq", "makeBrOnCast(BrOnCastDescEq)"),
("br_on_cast_desc_eq_fail", "makeBrOnCast(BrOnCastDescEqFail)"),
("struct.new", "makeStructNew(false, false)"),
("struct.new_default", "makeStructNew(true, false)"),
("struct.new_desc", "makeStructNew(false, true)"),
Expand Down
55 changes: 44 additions & 11 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -276,16 +276,38 @@ switch (buf[0]) {
switch (buf[15]) {
case '\0':
if (op == "br_on_cast_desc"sv) {
CHECK_ERR(makeBrOnCast(ctx, pos, annotations, BrOnCastDesc));
CHECK_ERR(makeBrOnCast(ctx, pos, annotations, BrOnCastDescEq));
return Ok{};
}
goto parse_error;
case '_':
if (op == "br_on_cast_desc_fail"sv) {
CHECK_ERR(makeBrOnCast(ctx, pos, annotations, BrOnCastDescFail));
return Ok{};
case '_': {
switch (buf[16]) {
case 'e': {
switch (buf[18]) {
case '\0':
if (op == "br_on_cast_desc_eq"sv) {
CHECK_ERR(makeBrOnCast(ctx, pos, annotations, BrOnCastDescEq));
return Ok{};
}
goto parse_error;
case '_':
if (op == "br_on_cast_desc_eq_fail"sv) {
CHECK_ERR(makeBrOnCast(ctx, pos, annotations, BrOnCastDescEqFail));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
case 'f':
if (op == "br_on_cast_desc_fail"sv) {
CHECK_ERR(makeBrOnCast(ctx, pos, annotations, BrOnCastDescEqFail));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
goto parse_error;
}
default: goto parse_error;
}
}
Expand Down Expand Up @@ -4894,12 +4916,23 @@ switch (buf[0]) {
return Ok{};
}
goto parse_error;
case '_':
if (op == "ref.cast_desc"sv) {
CHECK_ERR(makeRefCast(ctx, pos, annotations, true));
return Ok{};
case '_': {
switch (buf[13]) {
case '\0':
if (op == "ref.cast_desc"sv) {
CHECK_ERR(makeRefCast(ctx, pos, annotations, true));
return Ok{};
}
goto parse_error;
case '_':
if (op == "ref.cast_desc_eq"sv) {
CHECK_ERR(makeRefCast(ctx, pos, annotations, true));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
goto parse_error;
}
default: goto parse_error;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/ir/child-typer.h
Original file line number Diff line number Diff line change
Expand Up @@ -911,15 +911,15 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
return;
case BrOnCast:
case BrOnCastFail:
case BrOnCastDesc:
case BrOnCastDescFail: {
case BrOnCastDescEq:
case BrOnCastDescEqFail: {
if (!target) {
assert(curr->castType.isRef());
target = curr->castType;
}
auto top = target->getHeapType().getTop();
note(&curr->ref, Type(top, Nullable));
if (curr->op == BrOnCastDesc || curr->op == BrOnCastDescFail) {
if (curr->op == BrOnCastDescEq || curr->op == BrOnCastDescEqFail) {
auto desc = target->getHeapType().getDescriptorType();
assert(desc);
note(&curr->desc, Type(*desc, Nullable));
Expand Down
4 changes: 2 additions & 2 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -692,8 +692,8 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
case BrOnCast:
case BrOnCastFail:
return CastCost + visit(curr->ref);
case BrOnCastDesc:
case BrOnCastDescFail:
case BrOnCastDescEq:
case BrOnCastDescEqFail:
// These are not as expensive as full casts, since they just do a
// identity check on the descriptor.
return 2 + visit(curr->ref) + visit(curr->desc);
Expand Down
2 changes: 1 addition & 1 deletion src/ir/struct-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ struct StructScanner

void visitBrOn(BrOn* curr) {
if (curr->desc &&
(curr->op == BrOnCastDesc || curr->op == BrOnCastDescFail)) {
(curr->op == BrOnCastDescEq || curr->op == BrOnCastDescEqFail)) {
handleDescRead(curr->getCastType());
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/ir/subtype-exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
break;
case BrOnCast:
case BrOnCastFail:
case BrOnCastDesc:
case BrOnCastDescFail:
case BrOnCastDescEq:
case BrOnCastDescEqFail:
self()->noteCast(curr->ref, curr->castType);
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/passes/AbstractTypeRefining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ struct AbstractTypeRefining : public Pass {

// We may have casts like this:
//
// (ref.cast_desc (ref null $optimized-to-bottom)
// (ref.cast_desc_eq (ref null $optimized-to-bottom)
// (some struct...)
// (some desc...)
// )
Expand Down Expand Up @@ -435,7 +435,7 @@ struct AbstractTypeRefining : public Pass {
}
// Optimize the same way we optimize ref.cast*.
Builder builder(*getModule());
bool isFail = curr->op == BrOnCastDescFail;
bool isFail = curr->op == BrOnCastDescEqFail;
if (curr->castType.isExact() || (curr->desc && optimized->isBottom())) {
if (curr->desc) {
if (curr->desc->type.isNullable() &&
Expand Down
19 changes: 10 additions & 9 deletions src/passes/GlobalStructInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ struct GlobalStructInference : public Pass {
// type-based inference, and this remains empty.
std::unordered_map<HeapType, std::vector<Name>> typeGlobals;

// Whether to optimize ref.cast to ref.cast_desc. This increases code size, so
// it may not always be beneficial (perhaps running it late in the pipeline,
// and before type-merging, could make sense).
// Whether to optimize ref.cast to ref.cast_desc_eq. This increases code size,
// so it may not always be beneficial (perhaps running it late in the
// pipeline, and before type-merging, could make sense).
bool optimizeToDescCasts;

std::unique_ptr<SubTypes> subTypes;
Expand Down Expand Up @@ -515,10 +515,11 @@ struct GlobalStructInference : public Pass {

void visitRefCast(RefCast* curr) {
// When we see (ref.cast $T), and the type has a descriptor, and that
// descriptor only has a single global, then we can do (ref.cast_desc)
// using the descriptor. Descriptor casts are usually more efficient
// than normal ones (and even more so if we get lucky and are in a loop,
// where the global.get of the descriptor can be hoisted).
// descriptor only has a single global, then we can do
// (ref.cast_desc_eq) using the descriptor. Descriptor casts are usually
// more efficient than normal ones (and even more so if we get lucky and
// are in a loop, where the global.get of the descriptor can be
// hoisted).
// TODO: only do this when shrinkLevel == 0?
if (!parent.optimizeToDescCasts) {
return;
Expand All @@ -535,8 +536,8 @@ struct GlobalStructInference : public Pass {
return;
}

// Check if the type has no (relevant) subtypes, as a ref.cast_desc will
// find precisely that type and nothing else.
// Check if the type has no (relevant) subtypes, as a ref.cast_desc_eq
// will find precisely that type and nothing else.
if (!type.isExact() &&
!parent.subTypes->getStrictSubTypes(heapType).empty()) {
return;
Expand Down
16 changes: 8 additions & 8 deletions src/passes/Heap2Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,10 @@ struct EscapeAnalyzer {
}
} else {
// Either the child is the descriptor, in which case we consume it, or
// we have already optimized this ref.cast_desc for an allocation that
// flowed through as its `ref`. In the latter case the current child
// must have originally been the descriptor, so we can still say it's
// fully consumed, but we cannot assert that curr->desc == child.
// we have already optimized this ref.cast_desc_eq for an allocation
// that flowed through as its `ref`. In the latter case the current
// child must have originally been the descriptor, so we can still say
// it's fully consumed, but we cannot assert that curr->desc == child.
fullyConsumes = true;
}
}
Expand Down Expand Up @@ -869,23 +869,23 @@ struct Struct2Local : PostWalker<Struct2Local> {
builder.makeUnreachable()));
};

// If we are doing a ref.cast_desc of the optimized allocation, but the
// If we are doing a ref.cast_desc_eq of the optimized allocation, but the
// allocation does not have a descriptor, then we know the cast must fail.
// We also know the cast must fail (except for nulls it might let through)
// if the optimized allocation flows in as the descriptor, since it cannot
// possibly have been used in the allocation of the cast value without
// having been considered to escape.
bool allocIsCastRef =
analyzer.getInteraction(curr->ref) == ParentChildInteraction::Flows;
bool allocIsCastDesc =
bool allocIsCastDescEq =
analyzer.getInteraction(curr->desc) == ParentChildInteraction::Flows;
if (!allocation->desc || allocIsCastDesc) {
if (!allocation->desc || allocIsCastDescEq) {
// It would seem convenient to use ChildLocalizer here, but we cannot.
// ChildLocalizer would create a local.set for a desc operand with
// side effects, but that local.set would not be reflected in the parent
// map, so it would not be updated if the allocation flowing through
// that desc operand were later optimized.
if (allocIsCastDesc && !allocIsCastRef && curr->type.isNullable()) {
if (allocIsCastDescEq && !allocIsCastRef && curr->type.isNullable()) {
// There might be a null value to let through. Reuse curr as a cast to
// null. Use a scratch local to move the reference value past the desc
// value.
Expand Down
16 changes: 8 additions & 8 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2223,7 +2223,7 @@ struct PrintExpressionContents
}
void visitRefCast(RefCast* curr) {
if (curr->desc) {
printMedium(o, "ref.cast_desc ");
printMedium(o, "ref.cast_desc_eq ");
} else {
printMedium(o, "ref.cast ");
}
Expand Down Expand Up @@ -2257,21 +2257,21 @@ struct PrintExpressionContents
curr->name.print(o);
return;
case BrOnCast:
case BrOnCastDesc:
case BrOnCastDescEq:
case BrOnCastFail:
case BrOnCastDescFail:
case BrOnCastDescEqFail:
switch (curr->op) {
case BrOnCast:
printMedium(o, "br_on_cast");
break;
case BrOnCastFail:
printMedium(o, "br_on_cast_fail");
break;
case BrOnCastDesc:
printMedium(o, "br_on_cast_desc");
case BrOnCastDescEq:
printMedium(o, "br_on_cast_desc_eq");
break;
case BrOnCastDescFail:
printMedium(o, "br_on_cast_desc_fail");
case BrOnCastDescEqFail:
printMedium(o, "br_on_cast_desc_eq_fail");
break;
default:
WASM_UNREACHABLE("unexpected op");
Expand All @@ -2292,7 +2292,7 @@ struct PrintExpressionContents
return;
printMedium(o,
curr->op == BrOnCastFail ? "br_on_cast_fail "
: "br_on_cast_desc_fail ");
: "br_on_cast_desc_eq_fail ");
curr->name.print(o);
o << ' ';
if (curr->ref->type == Type::unreachable) {
Expand Down
8 changes: 4 additions & 4 deletions src/passes/RemoveUnusedBrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,12 +945,12 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
return;
case BrOnCast:
case BrOnCastFail:
case BrOnCastDesc:
case BrOnCastDescFail: {
case BrOnCastDescEq:
case BrOnCastDescEqFail: {
bool onFail =
curr->op == BrOnCastFail || curr->op == BrOnCastDescFail;
curr->op == BrOnCastFail || curr->op == BrOnCastDescEqFail;
bool isDesc =
curr->op == BrOnCastDesc || curr->op == BrOnCastDescFail;
curr->op == BrOnCastDescEq || curr->op == BrOnCastDescEqFail;

// Improve the cast target type as much as possible given what we
// know about the input. Unlike in BrOn::finalize(), we consider
Expand Down
7 changes: 4 additions & 3 deletions src/passes/pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,10 @@ void PassRegistry::registerPasses() {
"global-refining", "refine the types of globals", createGlobalRefiningPass);
registerPass(
"gsi", "globally optimize struct values", createGlobalStructInferencePass);
registerPass("gsi-desc-cast",
"globally optimize struct values, also emitting ref.cast_desc",
createGlobalStructInferenceDescCastPass);
registerPass(
"gsi-desc-cast",
"globally optimize struct values, also emitting ref.cast_desc_eq",
createGlobalStructInferenceDescCastPass);
registerPass(
"gto", "globally optimize GC types", createGlobalTypeOptimizationPass);
registerPass("gufa",
Expand Down
8 changes: 4 additions & 4 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1183,12 +1183,12 @@ enum ASTNodes {
RefTestNull = 0x15,
RefCast = 0x16,
RefCastNull = 0x17,
RefCastDesc = 0x23,
RefCastDescNull = 0x24,
RefCastDescEq = 0x23,
RefCastDescEqNull = 0x24,
BrOnCast = 0x18,
BrOnCastFail = 0x19,
BrOnCastDesc = 0x25,
BrOnCastDescFail = 0x26,
BrOnCastDescEq = 0x25,
BrOnCastDescEqFail = 0x26,
AnyConvertExtern = 0x1a,
ExternConvertAny = 0x1b,
RefI31 = 0x1c,
Expand Down
4 changes: 2 additions & 2 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -957,8 +957,8 @@ class Builder {
Expression* ref,
Type castType = Type::none,
Expression* desc = nullptr) {
assert((desc && (op == BrOnCastDesc || op == BrOnCastDescFail)) ||
(!desc && op != BrOnCastDesc && op != BrOnCastDescFail));
assert((desc && (op == BrOnCastDescEq || op == BrOnCastDescEqFail)) ||
(!desc && op != BrOnCastDescEq && op != BrOnCastDescEqFail));
auto* ret = wasm.allocator.alloc<BrOn>();
ret->op = op;
ret->name = name;
Expand Down
8 changes: 4 additions & 4 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2098,21 +2098,21 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
switch (curr->op) {
case BrOnCast:
case BrOnCastFail:
case BrOnCastDesc:
case BrOnCastDescFail: {
case BrOnCastDescEq:
case BrOnCastDescEqFail: {
auto cast = curr->desc ? doDescCast(curr) : doCast(curr);
if (auto* breaking = cast.getBreaking()) {
return *breaking;
} else if (auto* original = cast.getFailure()) {
if (curr->op == BrOnCast || curr->op == BrOnCastDesc) {
if (curr->op == BrOnCast || curr->op == BrOnCastDescEq) {
return *original;
} else {
return Flow(curr->name, *original);
}
} else {
auto* result = cast.getSuccess();
assert(result);
if (curr->op == BrOnCast || curr->op == BrOnCastDesc) {
if (curr->op == BrOnCast || curr->op == BrOnCastDescEq) {
return Flow(curr->name, *result);
} else {
return *result;
Expand Down
Loading
Loading