diff --git a/scripts/test/fuzzing.py b/scripts/test/fuzzing.py index 0a0d39ffe10..c4b6ae23865 100644 --- a/scripts/test/fuzzing.py +++ b/scripts/test/fuzzing.py @@ -123,6 +123,7 @@ 'type-merging-desc.wast', 'heap2local-desc.wast', 'minimize-rec-groups-desc.wast', + 'precompute-desc.wast', # TODO: fix split_wast() on tricky escaping situations like a string ending # in \\" (the " is not escaped - there is an escaped \ before it) 'string-lifting-section.wast', diff --git a/src/ir/child-typer.h b/src/ir/child-typer.h index f802266e33a..459fb2b3b42 100644 --- a/src/ir/child-typer.h +++ b/src/ir/child-typer.h @@ -948,7 +948,7 @@ template struct ChildTyper : OverriddenVisitor { } auto desc = curr->type.getHeapType().getDescriptorType(); if (desc) { - note(&curr->descriptor, Type(*desc, NonNullable, Exact)); + note(&curr->desc, Type(*desc, NonNullable, Exact)); } } diff --git a/src/ir/cost.h b/src/ir/cost.h index 3827dfb2460..69aff667e05 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -694,7 +694,7 @@ struct CostAnalyzer : public OverriddenVisitor { for (auto* child : curr->operands) { ret += visit(child); } - ret += maybeVisit(curr->descriptor); + ret += maybeVisit(curr->desc); return ret; } CostType visitStructGet(StructGet* curr) { diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp index 9dc76f04950..1e6744ea8fe 100644 --- a/src/passes/Heap2Local.cpp +++ b/src/passes/Heap2Local.cpp @@ -612,9 +612,8 @@ struct Struct2Local : PostWalker { for (auto field : fields) { localIndexes.push_back(builder.addVar(func, field.type)); } - if (allocation->descriptor) { - localIndexes.push_back( - builder.addVar(func, allocation->descriptor->type)); + if (allocation->desc) { + localIndexes.push_back(builder.addVar(func, allocation->desc->type)); } // Replace the things we need to using the visit* methods. @@ -732,7 +731,7 @@ struct Struct2Local : PostWalker { // computed do we copy them into the locals representing the fields. std::vector tempIndexes; Index numTemps = - (curr->isWithDefault() ? 0 : fields.size()) + bool(curr->descriptor); + (curr->isWithDefault() ? 0 : fields.size()) + bool(curr->desc); tempIndexes.reserve(numTemps); // Create the temp variables. @@ -741,8 +740,8 @@ struct Struct2Local : PostWalker { tempIndexes.push_back(builder.addVar(func, field.type)); } } - if (curr->descriptor) { - tempIndexes.push_back(builder.addVar(func, curr->descriptor->type)); + if (curr->desc) { + tempIndexes.push_back(builder.addVar(func, curr->desc->type)); } // Store the initial values into the temp locals. @@ -752,9 +751,9 @@ struct Struct2Local : PostWalker { builder.makeLocalSet(tempIndexes[i], curr->operands[i])); } } - if (curr->descriptor) { + if (curr->desc) { contents.push_back( - builder.makeLocalSet(tempIndexes[numTemps - 1], curr->descriptor)); + builder.makeLocalSet(tempIndexes[numTemps - 1], curr->desc)); } // Store the values into the locals representing the fields. @@ -765,9 +764,9 @@ struct Struct2Local : PostWalker { : builder.makeLocalGet(tempIndexes[i], fields[i].type); contents.push_back(builder.makeLocalSet(localIndexes[i], val)); } - if (curr->descriptor) { + if (curr->desc) { auto* val = - builder.makeLocalGet(tempIndexes[numTemps - 1], curr->descriptor->type); + builder.makeLocalGet(tempIndexes[numTemps - 1], curr->desc->type); contents.push_back( builder.makeLocalSet(localIndexes[fields.size()], val)); } @@ -851,8 +850,8 @@ struct Struct2Local : PostWalker { // also know the cast must fail 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. - if (!allocation->descriptor || analyzer.getInteraction(curr->desc) == - ParentChildInteraction::Flows) { + if (!allocation->desc || analyzer.getInteraction(curr->desc) == + ParentChildInteraction::Flows) { // The allocation does not have a descriptor, so there is no way for the // cast to succeed. replaceCurrent(builder.blockify(builder.makeDrop(curr->ref), @@ -861,7 +860,7 @@ struct Struct2Local : PostWalker { } else { // The cast succeeds iff the optimized allocation's descriptor is the // same as the given descriptor and traps otherwise. - auto type = allocation->descriptor->type; + auto type = allocation->desc->type; replaceCurrent(builder.blockify( builder.makeDrop(curr->ref), builder.makeIf( @@ -897,7 +896,7 @@ struct Struct2Local : PostWalker { return; } - auto type = allocation->descriptor->type; + auto type = allocation->desc->type; if (type != curr->type) { // We know exactly the allocation that flows into this expression, so we // know the exact type of the descriptor. This type may be more precise diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 6b307730344..f101cc525b6 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -240,12 +240,6 @@ class PrecomputingExpressionRunner // string.encode_wtf16_array anyhow.) return Flow(NONCONSTANT_FLOW); } - - Flow visitRefGetDesc(RefGetDesc* curr) { - // TODO: Implement this. For now, return nonconstant so that we skip it and - // do not error. - return Flow(NONCONSTANT_FLOW); - } }; struct Precompute diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index cbb1180231e..a84a0b0b539 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -485,8 +485,8 @@ struct Analyzer { // Use the descriptor right now, normally. (We only have special // optimization for struct.new operands, below.) - if (new_->descriptor) { - use(new_->descriptor); + if (new_->desc) { + use(new_->desc); } auto type = new_->type.getHeapType(); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 7bee64c2407..e31d905548e 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -931,7 +931,7 @@ class Builder { Expression* descriptor = nullptr) { auto* ret = wasm.allocator.alloc(); ret->operands.set(args); - ret->descriptor = descriptor; + ret->desc = descriptor; ret->type = Type(type, NonNullable, Exact); ret->finalize(); return ret; @@ -941,7 +941,7 @@ class Builder { Expression* descriptor = nullptr) { auto* ret = wasm.allocator.alloc(); ret->operands = std::move(args); - ret->descriptor = descriptor; + ret->desc = descriptor; ret->type = Type(type, NonNullable, Exact); ret->finalize(); return ret; @@ -952,7 +952,7 @@ class Builder { Expression* descriptor = nullptr) { auto* ret = wasm.allocator.alloc(); ret->operands.set(args); - ret->descriptor = descriptor; + ret->desc = descriptor; ret->type = Type(type, NonNullable, Exact); ret->finalize(); return ret; diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index e2627e72fc1..b7e9d935580 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -671,7 +671,7 @@ DELEGATE_FIELD_CHILD(BrOn, ref) DELEGATE_FIELD_CASE_END(BrOn) DELEGATE_FIELD_CASE_START(StructNew) -DELEGATE_FIELD_OPTIONAL_CHILD(StructNew, descriptor) +DELEGATE_FIELD_OPTIONAL_CHILD(StructNew, desc) DELEGATE_FIELD_CHILD_VECTOR(StructNew, operands) DELEGATE_FIELD_CASE_END(StructNew) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 0ae93c4bd71..b4f56e7dfcb 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1781,8 +1781,8 @@ class ExpressionRunner : public OverriddenVisitor { return value; } } - if (curr->descriptor) { - auto value = self()->visit(curr->descriptor); + if (curr->desc) { + auto value = self()->visit(curr->desc); if (value.breaking()) { return value; } @@ -1804,10 +1804,10 @@ class ExpressionRunner : public OverriddenVisitor { data[i] = truncateForPacking(value.getSingleValue(), field); } } - if (!curr->descriptor) { + if (!curr->desc) { return makeGCData(std::move(data), curr->type); } - auto desc = self()->visit(curr->descriptor); + auto desc = self()->visit(curr->desc); if (desc.breaking()) { return desc; } diff --git a/src/wasm.h b/src/wasm.h index e3ca5f47997..55e7fa458da 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1683,7 +1683,7 @@ class StructNew : public SpecificExpression { // case, and binaryen doesn't guarantee roundtripping binaries anyhow. ExpressionList operands; - Expression* descriptor = nullptr; + Expression* desc = nullptr; bool isWithDefault() { return operands.empty(); } diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 2c282684974..b56e32812a7 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -2230,7 +2230,7 @@ Result<> IRBuilder::makeStructNew(HeapType type) { curr.type = Type(type, NonNullable, Exact); curr.operands.resize(type.getStruct().fields.size()); CHECK_ERR(visitStructNew(&curr)); - push(builder.makeStructNew(type, std::move(curr.operands), curr.descriptor)); + push(builder.makeStructNew(type, std::move(curr.operands), curr.desc)); return Ok{}; } @@ -2238,7 +2238,7 @@ Result<> IRBuilder::makeStructNewDefault(HeapType type) { StructNew curr(wasm.allocator); curr.type = Type(type, NonNullable, Exact); CHECK_ERR(visitStructNew(&curr)); - push(builder.makeStructNew(type, {}, curr.descriptor)); + push(builder.makeStructNew(type, {}, curr.desc)); return Ok{}; } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index d36ca80f38c..2fe4ea7d4ef 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -3159,11 +3159,11 @@ void FunctionValidator::visitStructNew(StructNew* curr) { auto descType = curr->type.getHeapType().getDescriptorType(); if (!descType) { - shouldBeFalse(curr->descriptor, + shouldBeFalse(curr->desc, curr, "struct.new of type without descriptor should lack one"); } else { - shouldBeSubType(curr->descriptor->type, + shouldBeSubType(curr->desc->type, Type(*descType, Nullable, Exact), curr, "struct.new descriptor operand should have proper type"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index d2301ac2bf8..dac47857f7d 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1216,7 +1216,7 @@ void StructNew::finalize() { if (handleUnreachableOperands(this)) { return; } - if (descriptor && descriptor->type == Type::unreachable) { + if (desc && desc->type == Type::unreachable) { type = Type::unreachable; } } diff --git a/test/lit/passes/precompute-desc.wast b/test/lit/passes/precompute-desc.wast new file mode 100644 index 00000000000..e0b261cca04 --- /dev/null +++ b/test/lit/passes/precompute-desc.wast @@ -0,0 +1,85 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. + +;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate --fuzz-exec -all -S -o - \ +;; RUN: | filecheck %s + +(module + (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $struct (descriptor $desc (struct))) + (type $struct (descriptor $desc (struct))) + ;; CHECK: (type $desc (describes $struct (struct))) + (type $desc (describes $struct (struct))) + ) + + ;; CHECK: (global $desc (ref (exact $desc)) (struct.new_default $desc)) + (global $desc (ref (exact $desc)) (struct.new $desc)) + ;; CHECK: (global $struct (ref $struct) (struct.new_default $struct + ;; CHECK-NEXT: (global.get $desc) + ;; CHECK-NEXT: )) + (global $struct (ref $struct) (struct.new $struct (global.get $desc))) + + ;; CHECK: (func $eq-descs (type $0) (result i32) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + (func $eq-descs (result i32) + (ref.eq + (ref.get_desc $struct + (struct.new $struct + (global.get $desc) + ) + ) + (global.get $desc) + ) + ) + + ;; CHECK: (func $different-descs (type $0) (result i32) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + (func $different-descs (result i32) + (ref.eq + (ref.get_desc $struct + (struct.new $struct + (struct.new $desc) + ) + ) + (global.get $desc) + ) + ) + + ;; CHECK: (func $br-on-cast-desc (type $0) (result i32) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + (func $br-on-cast-desc (result i32) + (ref.eq + (block $l (result eqref) + (drop + (br_on_cast_desc $l eqref (ref $struct) + (global.get $struct) + (global.get $desc) + ) + ) + (ref.null none) + ) + (global.get $struct) + ) + ) + + ;; CHECK: (func $br-on-cast-desc-fail (type $0) (result i32) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + (func $br-on-cast-desc-fail (result i32) + (ref.eq + (block $l (result eqref) + (drop + (br_on_cast_desc_fail $l eqref (ref $struct) + (global.get $struct) + (global.get $desc) + ) + ) + (ref.null none) + ) + (global.get $struct) + ) + ) +)