diff options
Diffstat (limited to 'src/passes')
-rw-r--r-- | src/passes/Unsubtyping.cpp | 279 |
1 files changed, 20 insertions, 259 deletions
diff --git a/src/passes/Unsubtyping.cpp b/src/passes/Unsubtyping.cpp index e5d9453a8..67a3c4e85 100644 --- a/src/passes/Unsubtyping.cpp +++ b/src/passes/Unsubtyping.cpp @@ -16,7 +16,7 @@ #include <unordered_map> -#include "ir/branch-utils.h" +#include "ir/subtype-exprs.h" #include "ir/subtypes.h" #include "ir/type-updating.h" #include "ir/utils.h" @@ -105,7 +105,8 @@ namespace wasm { namespace { struct Unsubtyping - : WalkerPass<ControlFlowWalker<Unsubtyping, OverriddenVisitor<Unsubtyping>>> { + : WalkerPass< + ControlFlowWalker<Unsubtyping, SubtypingDiscoverer<Unsubtyping>>> { // The new set of supertype relations. std::unordered_map<HeapType, HeapType> supertypes; @@ -181,6 +182,17 @@ struct Unsubtyping noteSubtype(sub.getHeapType(), super.getHeapType()); } + // Note a subtyping where one or both sides are expressions. + void noteSubtype(Expression* sub, Type super) { + noteSubtype(sub->type, super); + } + void noteSubtype(Type sub, Expression* super) { + noteSubtype(sub, super->type); + } + void noteSubtype(Expression* sub, Expression* super) { + noteSubtype(sub->type, super->type); + } + void noteCast(HeapType src, HeapType dest) { if (src == dest || dest.isBottom()) { return; @@ -198,6 +210,12 @@ struct Unsubtyping noteCast(src.getHeapType(), dest.getHeapType()); } + // Note a cast where one or both sides are expressions. + void noteCast(Expression* src, Type dest) { noteCast(src->type, dest); } + void noteCast(Expression* src, Expression* dest) { + noteCast(src->type, dest->type); + } + void analyzePublicTypes(Module& wasm) { // We cannot change supertypes for anything public. for (auto type : ModuleUtils::getPublicHeapTypes(wasm)) { @@ -317,263 +335,6 @@ struct Unsubtyping // Visit the rest of the code that is not in functions. walkModuleCode(wasm); } - - void visitFunction(Function* func) { - if (func->body) { - noteSubtype(func->body->type, func->getResults()); - } - } - void visitGlobal(Global* global) { - if (global->init) { - noteSubtype(global->init->type, global->type); - } - } - void visitElementSegment(ElementSegment* seg) { - if (seg->offset) { - noteSubtype(seg->type, getModule()->getTable(seg->table)->type); - } - for (auto init : seg->data) { - noteSubtype(init->type, seg->type); - } - } - void visitNop(Nop* curr) {} - void visitBlock(Block* curr) { - if (!curr->list.empty()) { - noteSubtype(curr->list.back()->type, curr->type); - } - } - void visitIf(If* curr) { - if (curr->ifFalse) { - noteSubtype(curr->ifTrue->type, curr->type); - noteSubtype(curr->ifFalse->type, curr->type); - } - } - void visitLoop(Loop* curr) { noteSubtype(curr->body->type, curr->type); } - void visitBreak(Break* curr) { - if (curr->value) { - noteSubtype(curr->value->type, findBreakTarget(curr->name)->type); - } - } - void visitSwitch(Switch* curr) { - if (curr->value) { - for (auto name : BranchUtils::getUniqueTargets(curr)) { - noteSubtype(curr->value->type, findBreakTarget(name)->type); - } - } - } - template<typename T> void handleCall(T* curr, Signature sig) { - assert(curr->operands.size() == sig.params.size()); - for (size_t i = 0, size = sig.params.size(); i < size; ++i) { - noteSubtype(curr->operands[i]->type, sig.params[i]); - } - if (curr->isReturn) { - noteSubtype(sig.results, getFunction()->getResults()); - } - } - void visitCall(Call* curr) { - handleCall(curr, getModule()->getFunction(curr->target)->getSig()); - } - void visitCallIndirect(CallIndirect* curr) { - handleCall(curr, curr->heapType.getSignature()); - auto* table = getModule()->getTable(curr->table); - auto tableType = table->type.getHeapType(); - if (HeapType::isSubType(tableType, curr->heapType)) { - // Unlike other casts, where cast targets are always subtypes of cast - // sources, call_indirect target types may be supertypes of their source - // table types. In this case, the cast will always succeed, but only if we - // keep the types related. - noteSubtype(tableType, curr->heapType); - } else if (HeapType::isSubType(curr->heapType, tableType)) { - noteCast(tableType, curr->heapType); - } else { - // The types are unrelated and the cast will fail. We can keep the types - // unrelated. - } - } - void visitLocalGet(LocalGet* curr) {} - void visitLocalSet(LocalSet* curr) { - noteSubtype(curr->value->type, getFunction()->getLocalType(curr->index)); - } - void visitGlobalGet(GlobalGet* curr) {} - void visitGlobalSet(GlobalSet* curr) { - noteSubtype(curr->value->type, getModule()->getGlobal(curr->name)->type); - } - void visitLoad(Load* curr) {} - void visitStore(Store* curr) {} - void visitAtomicRMW(AtomicRMW* curr) {} - void visitAtomicCmpxchg(AtomicCmpxchg* curr) {} - void visitAtomicWait(AtomicWait* curr) {} - void visitAtomicNotify(AtomicNotify* curr) {} - void visitAtomicFence(AtomicFence* curr) {} - void visitSIMDExtract(SIMDExtract* curr) {} - void visitSIMDReplace(SIMDReplace* curr) {} - void visitSIMDShuffle(SIMDShuffle* curr) {} - void visitSIMDTernary(SIMDTernary* curr) {} - void visitSIMDShift(SIMDShift* curr) {} - void visitSIMDLoad(SIMDLoad* curr) {} - void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {} - void visitMemoryInit(MemoryInit* curr) {} - void visitDataDrop(DataDrop* curr) {} - void visitMemoryCopy(MemoryCopy* curr) {} - void visitMemoryFill(MemoryFill* curr) {} - void visitConst(Const* curr) {} - void visitUnary(Unary* curr) {} - void visitBinary(Binary* curr) {} - void visitSelect(Select* curr) { - noteSubtype(curr->ifTrue->type, curr->type); - noteSubtype(curr->ifFalse->type, curr->type); - } - void visitDrop(Drop* curr) {} - void visitReturn(Return* curr) { - if (curr->value) { - noteSubtype(curr->value->type, getFunction()->getResults()); - } - } - void visitMemorySize(MemorySize* curr) {} - void visitMemoryGrow(MemoryGrow* curr) {} - void visitUnreachable(Unreachable* curr) {} - void visitPop(Pop* curr) {} - void visitRefNull(RefNull* curr) {} - void visitRefIsNull(RefIsNull* curr) {} - void visitRefFunc(RefFunc* curr) {} - void visitRefEq(RefEq* curr) {} - void visitTableGet(TableGet* curr) {} - void visitTableSet(TableSet* curr) { - noteSubtype(curr->value->type, getModule()->getTable(curr->table)->type); - } - void visitTableSize(TableSize* curr) {} - void visitTableGrow(TableGrow* curr) {} - void visitTableFill(TableFill* curr) { - noteSubtype(curr->value->type, getModule()->getTable(curr->table)->type); - } - void visitTableCopy(TableCopy* curr) { - noteSubtype(getModule()->getTable(curr->sourceTable)->type, - getModule()->getTable(curr->destTable)->type); - } - void visitTry(Try* curr) { - noteSubtype(curr->body->type, curr->type); - for (auto* body : curr->catchBodies) { - noteSubtype(body->type, curr->type); - } - } - void visitThrow(Throw* curr) { - Type params = getModule()->getTag(curr->tag)->sig.params; - assert(params.size() == curr->operands.size()); - for (size_t i = 0, size = curr->operands.size(); i < size; ++i) { - noteSubtype(curr->operands[i]->type, params[i]); - } - } - void visitRethrow(Rethrow* curr) {} - void visitTupleMake(TupleMake* curr) {} - void visitTupleExtract(TupleExtract* curr) {} - void visitRefI31(RefI31* curr) {} - void visitI31Get(I31Get* curr) {} - void visitCallRef(CallRef* curr) { - if (!curr->target->type.isSignature()) { - return; - } - handleCall(curr, curr->target->type.getHeapType().getSignature()); - } - void visitRefTest(RefTest* curr) { - noteCast(curr->ref->type, curr->castType); - } - void visitRefCast(RefCast* curr) { noteCast(curr->ref->type, curr->type); } - void visitBrOn(BrOn* curr) { - if (curr->op == BrOnCast || curr->op == BrOnCastFail) { - noteCast(curr->ref->type, curr->castType); - } - noteSubtype(curr->getSentType(), findBreakTarget(curr->name)->type); - } - void visitStructNew(StructNew* curr) { - if (!curr->type.isStruct() || curr->isWithDefault()) { - return; - } - const auto& fields = curr->type.getHeapType().getStruct().fields; - assert(fields.size() == curr->operands.size()); - for (size_t i = 0, size = fields.size(); i < size; ++i) { - noteSubtype(curr->operands[i]->type, fields[i].type); - } - } - void visitStructGet(StructGet* curr) {} - void visitStructSet(StructSet* curr) { - if (!curr->ref->type.isStruct()) { - return; - } - const auto& fields = curr->ref->type.getHeapType().getStruct().fields; - noteSubtype(curr->value->type, fields[curr->index].type); - } - void visitArrayNew(ArrayNew* curr) { - if (!curr->type.isArray() || curr->isWithDefault()) { - return; - } - auto array = curr->type.getHeapType().getArray(); - noteSubtype(curr->init->type, array.element.type); - } - void visitArrayNewData(ArrayNewData* curr) {} - void visitArrayNewElem(ArrayNewElem* curr) { - if (!curr->type.isArray()) { - return; - } - auto array = curr->type.getHeapType().getArray(); - auto* seg = getModule()->getElementSegment(curr->segment); - noteSubtype(seg->type, array.element.type); - } - void visitArrayNewFixed(ArrayNewFixed* curr) { - if (!curr->type.isArray()) { - return; - } - auto array = curr->type.getHeapType().getArray(); - for (auto* value : curr->values) { - noteSubtype(value->type, array.element.type); - } - } - void visitArrayGet(ArrayGet* curr) {} - void visitArraySet(ArraySet* curr) { - if (!curr->ref->type.isArray()) { - return; - } - auto array = curr->ref->type.getHeapType().getArray(); - noteSubtype(curr->value->type, array.element.type); - } - void visitArrayLen(ArrayLen* curr) {} - void visitArrayCopy(ArrayCopy* curr) { - if (!curr->srcRef->type.isArray() || !curr->destRef->type.isArray()) { - return; - } - auto src = curr->srcRef->type.getHeapType().getArray(); - auto dest = curr->destRef->type.getHeapType().getArray(); - noteSubtype(src.element.type, dest.element.type); - } - void visitArrayFill(ArrayFill* curr) { - if (!curr->ref->type.isArray()) { - return; - } - auto array = curr->ref->type.getHeapType().getArray(); - noteSubtype(curr->value->type, array.element.type); - } - void visitArrayInitData(ArrayInitData* curr) {} - void visitArrayInitElem(ArrayInitElem* curr) { - if (!curr->ref->type.isArray()) { - return; - } - auto array = curr->ref->type.getHeapType().getArray(); - auto* seg = getModule()->getElementSegment(curr->segment); - noteSubtype(seg->type, array.element.type); - } - void visitRefAs(RefAs* curr) {} - void visitStringNew(StringNew* curr) {} - void visitStringConst(StringConst* curr) {} - void visitStringMeasure(StringMeasure* curr) {} - void visitStringEncode(StringEncode* curr) {} - void visitStringConcat(StringConcat* curr) {} - void visitStringEq(StringEq* curr) {} - void visitStringAs(StringAs* curr) {} - void visitStringWTF8Advance(StringWTF8Advance* curr) {} - void visitStringWTF16Get(StringWTF16Get* curr) {} - void visitStringIterNext(StringIterNext* curr) {} - void visitStringIterMove(StringIterMove* curr) {} - void visitStringSliceWTF(StringSliceWTF* curr) {} - void visitStringSliceIter(StringSliceIter* curr) {} }; } // anonymous namespace |