1616#ifndef wasm_ir_child_typer_h
1717#define wasm_ir_child_typer_h
1818
19+ #include " ir/principal-type.h"
1920#include " wasm-traversal.h"
2021#include " wasm.h"
2122
2223namespace wasm {
2324
24- // CRTP visitor for determining constraints on the types of expression children.
25- // For each child of the visited expression, calls a callback with a pointer to
26- // the child and information on how the child is constrained. The possible
27- // callbacks are:
25+ // CRTP visitor for determining constaints on the types of expression children.
26+ // For each child of the visited expression, calls a callback with the VarTypes
27+ // giving the constraint on the child:
2828//
29- // noteSubtype(Expression** childp, Type type) - The child must be a subtype
30- // of `type`, which may be a tuple type. For children that must not produce
31- // values, this may be `Type::none`. This accounts for most type constraints.
29+ // note(Expression** childp, SmallVector<VarType, 1> type)
3230//
33- // noteAnyType(Expression** childp) - The child may have any non-tuple type.
34- // Used for the children of polymorphic instructions like `drop` and `select`.
35- //
36- // noteAnyReferenceType(Expression** childp) - The child may have any
37- // reference type. Used for the children of polymorphic reference instructions
38- // like `ref.is_null`.
39- //
40- // noteAnyTupleType(Expression** childp, size_t arity) - The child may have
41- // any tuple type with the given arity. Used for the children of polymorphic
42- // tuple instructions like `tuple.drop` and `tuple.extract`.
31+ // Multiple VarTypes are provided if and only if the child must be a tuple. In
32+ // that case, each vartype gives the constraint on a single element of the
33+ // tuple.
4334//
4435// Subclasses must additionally implement a callback for getting the type of a
45- // branch target. This callback will only be used when the label type is not
36+ // branch target. This callback will only be used when a the label type is not
4637// passed directly as an argument to the branch visitor method (see below).
4738//
4839// Type getLabelType(Name label)
4940//
50- // Children with type `unreachable` satisfy all constraints.
51- //
5241// Constraints are determined using information that would be present in the
5342// binary, e.g. type annotation immediates. Many of the visitor methods take
5443// optional additional parameter for passing this information directly, and if
@@ -70,33 +59,49 @@ namespace wasm {
7059// information to generate constraints for all the children. Some users may wish
7160// to ignore this situation and others may want to assert that it never occurs.
7261template <typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
62+ using Constraints = SmallVector<VarType, 1 >;
7363 Module& wasm;
7464 Function* func;
7565
7666 ChildTyper (Module& wasm, Function* func) : wasm(wasm), func(func) {}
7767
7868 Subtype& self () { return *static_cast <Subtype*>(this ); }
7969
80- void note (Expression** childp, Type type) {
81- self ().noteSubtype (childp, type);
70+ void note (Expression** childp, VarType type) {
71+ self ().note (childp, Constraints{ type} );
8272 }
8373
84- void notePointer (Expression** ptrp, Name mem) {
85- note (ptrp, wasm.getMemory (mem)->addressType );
74+ void note (Expression** childp, Type type) {
75+ if (type.isTuple ()) {
76+ Constraints tuple;
77+ for (auto t : type.getTuple ()) {
78+ tuple.push_back (t);
79+ }
80+ self ().note (childp, tuple);
81+ } else {
82+ note (childp, VarType{type});
83+ }
8684 }
8785
88- void noteTableIndex (Expression** indexp, Name table) {
89- note (indexp, wasm.getTable (table)->addressType );
86+ // Disambiguate betwween Type and VarType.
87+ void note (Expression** childp, Type::BasicType type) {
88+ note (childp, VarType{Type (type)});
9089 }
9190
92- void noteAny (Expression** childp) { self ().noteAnyType (childp); }
91+ void noteAnyTuple (Expression** childp, size_t n) {
92+ Constraints tuple;
93+ for (; n != 0 ; --n) {
94+ tuple.push_back (VarType{Index (n - 1 )});
95+ }
96+ self ().note (childp, tuple);
97+ }
9398
94- void noteAnyReference (Expression** childp ) {
95- self (). noteAnyReferenceType (childp );
99+ void notePointer (Expression** ptrp, Name mem ) {
100+ note (ptrp, wasm. getMemory (mem)-> addressType );
96101 }
97102
98- void noteAnyTuple (Expression** childp, size_t arity ) {
99- self (). noteAnyTupleType (childp, arity );
103+ void noteTableIndex (Expression** indexp, Name table ) {
104+ note (indexp, wasm. getTable (table)-> addressType );
100105 }
101106
102107 Type getLabelType (Name label) { return self ().getLabelType (label); }
@@ -115,6 +120,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
115120 }
116121
117122 void visitIf (If* curr) {
123+ // TODO: if the condition is unreachable, use a type variable for the arms?
118124 note (&curr->condition , Type::i32 );
119125 note (&curr->ifTrue , curr->type );
120126 if (curr->ifFalse ) {
@@ -200,8 +206,6 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
200206
201207 void visitAtomicCmpxchg (AtomicCmpxchg* curr,
202208 std::optional<Type> type = std::nullopt ) {
203- assert (!type || *type == Type::i32 || *type == Type::i64 );
204- notePointer (&curr->ptr , curr->memory );
205209 if (!type) {
206210 if (curr->expected ->type == Type::i64 ||
207211 curr->replacement ->type == Type::i64 ) {
@@ -210,6 +214,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
210214 type = Type::i32 ;
211215 }
212216 }
217+ assert (*type == Type::i32 || *type == Type::i64 );
218+ notePointer (&curr->ptr , curr->memory );
213219 note (&curr->expected , *type);
214220 note (&curr->replacement , *type);
215221 }
@@ -701,8 +707,10 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
701707 note (&curr->ifTrue , *type);
702708 note (&curr->ifFalse , *type);
703709 } else {
704- noteAny (&curr->ifTrue );
705- noteAny (&curr->ifFalse );
710+ // Polymorphic over types.
711+ // TODO: Model the constraint that this must be a numeric or vector type.
712+ note (&curr->ifTrue , VarType{0u });
713+ note (&curr->ifFalse , VarType{0u });
706714 }
707715 note (&curr->condition , Type::i32 );
708716 }
@@ -711,11 +719,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
711719 if (!arity) {
712720 arity = curr->value ->type .size ();
713721 }
714- if (*arity > 1 ) {
715- noteAnyTuple (&curr->value , *arity);
716- } else {
717- noteAny (&curr->value );
718- }
722+ assert (*arity > 0 );
723+ // Might not actually be a tuple, but works either way.
724+ noteAnyTuple (&curr->value , *arity);
719725 }
720726
721727 void visitReturn (Return* curr) {
@@ -738,14 +744,19 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
738744
739745 void visitRefNull (RefNull* curr) {}
740746
741- void visitRefIsNull (RefIsNull* curr) { noteAnyReference (&curr->value ); }
747+ void visitRefIsNull (RefIsNull* curr) {
748+ // Polymorphic over heap types.
749+ note (&curr->value , VarRef{Nullable, VarHeapType{0u }});
750+ }
742751
743752 void visitRefFunc (RefFunc* curr) {}
744753
745754 void visitRefEq (RefEq* curr) {
746- Type eqref (HeapType::eq, Nullable);
747- note (&curr->left , eqref);
748- note (&curr->right , eqref);
755+ // Polymorphic over sharedness.
756+ VarRef maybeShareEqref{Nullable,
757+ VarAbsHeapType{VarSharedness{0u }, HeapType::eq}};
758+ note (&curr->left , maybeShareEqref);
759+ note (&curr->right , maybeShareEqref);
749760 }
750761
751762 void visitTableGet (TableGet* curr) {
@@ -815,8 +826,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
815826 }
816827
817828 void visitTupleMake (TupleMake* curr) {
818- for (auto & expr : curr->operands ) {
819- noteAny (&expr );
829+ for (Index i = 0 ; i < curr->operands . size (); ++i ) {
830+ note (&curr-> operands [i], VarType{ Index (curr-> operands . size () - i - 1 )} );
820831 }
821832 }
822833
@@ -848,10 +859,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
848859 ht = curr->target ->type .getHeapType ().getSignature ();
849860 }
850861 auto params = ht->getSignature ().params ;
851- assert (curr->operands .size () == params.size ());
852- for (size_t i = 0 ; i < params.size (); ++i) {
853- note (&curr->operands [i], params[i]);
854- }
862+ handleCall (curr, params);
855863 note (&curr->target , Type (*ht, Nullable));
856864 }
857865
@@ -886,7 +894,9 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
886894 }
887895 ht = curr->ref ->type .getHeapType ();
888896 }
889- note (&curr->ref , Type (*ht, Nullable));
897+ // Polymorphic over exactness.
898+ assert (!ht->isBasic ());
899+ note (&curr->ref , VarRef{Nullable, VarDefHeapType{VarExactness{0u }, *ht}});
890900 }
891901
892902 void visitBrOn (BrOn* curr, std::optional<Type> target = std::nullopt ) {
@@ -896,7 +906,8 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
896906 // br_on(_non)_null is polymorphic over reference types and does not
897907 // take a type immediate.
898908 assert (!target);
899- noteAnyReference (&curr->ref );
909+ // Polymorphic over heap types.
910+ note (&curr->ref , VarRef{Nullable, VarHeapType{0u }});
900911 return ;
901912 case BrOnCast:
902913 case BrOnCastFail:
@@ -931,8 +942,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
931942 note (&curr->operands [i], fields[i].type );
932943 }
933944 }
934- auto desc = curr->type .getHeapType ().getDescriptorType ();
935- if (desc) {
945+ if (auto desc = curr->type .getHeapType ().getDescriptorType ()) {
936946 note (&curr->desc , Type (*desc, NonNullable, Exact));
937947 }
938948 }
@@ -992,6 +1002,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
9921002 assert (curr->index < fields.size ());
9931003 note (&curr->ref , Type (*ht, Nullable));
9941004 auto type = fields[curr->index ].type ;
1005+ // TODO: (shared eq) as appropriate.
9951006 note (&curr->expected , type.isRef () ? Type (HeapType::eq, Nullable) : type);
9961007 note (&curr->replacement , type);
9971008 }
@@ -1154,17 +1165,19 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11541165 }
11551166 ht = curr->ref ->type .getHeapType ();
11561167 }
1157- auto type = ht->getArray ().element .type ;
1168+ Type type = ht->getArray ().element .type ;
11581169 note (&curr->ref , Type (*ht, Nullable));
11591170 note (&curr->index , Type::i32 );
1171+ // TODO: (shared eq) as appropriate.
11601172 note (&curr->expected , type.isRef () ? Type (HeapType::eq, Nullable) : type);
11611173 note (&curr->replacement , type);
11621174 }
11631175
11641176 void visitRefAs (RefAs* curr) {
11651177 switch (curr->op ) {
11661178 case RefAsNonNull:
1167- noteAnyReference (&curr->value );
1179+ // Polymorphic over heap types.
1180+ note (&curr->value , VarRef{Nullable, VarHeapType{0u }});
11681181 return ;
11691182 case AnyConvertExtern:
11701183 note (&curr->value , Type (HeapType::ext, Nullable));
@@ -1200,6 +1213,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
12001213 void visitStringConst (StringConst* curr) {}
12011214
12021215 void visitStringMeasure (StringMeasure* curr) {
1216+ // TODO: extern instead of string? For other ops as well.
12031217 note (&curr->ref , Type (HeapType::string, Nullable));
12041218 }
12051219
0 commit comments