Skip to content

Commit dfcd1d4

Browse files
authored
[ChildTyper] Handle missing type immediates (#9302)
Previously ChildTyper would crash when run on an expression that did not have type immediate information, e.g. a StructGet with a null child. This is fine when IRBuilder uses ChildTyper because it has access to the original type immediates. The other user of ChildTyper, TypeSSA, worked around the problem by checking whether the type immediate information was available before calling ChildTyper. As various type generalization passes become more important, ChildTyper will need to run on arbitrary IR to help do backward type analyses. Fix ChildTyper so it calls noteUnknown() rather than crashing when the information it needs is absent. Remove the check from TypeSSA so we can get full test coverage of the new changes via TypeSSA lit tests.
1 parent c117b0f commit dfcd1d4

5 files changed

Lines changed: 1739 additions & 55 deletions

File tree

‎src/ir/child-typer.h‎

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -867,11 +867,11 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
867867

868868
void visitCallRef(CallRef* curr, std::optional<HeapType> ht = std::nullopt) {
869869
if (!ht) {
870-
if (!curr->target->type.isRef()) {
870+
if (!curr->target->type.isSignature()) {
871871
self().noteUnknown();
872872
return;
873873
}
874-
ht = curr->target->type.getHeapType().getSignature();
874+
ht = curr->target->type.getHeapType();
875875
}
876876
auto params = ht->getSignature().params;
877877
handleCall(curr, params);
@@ -891,19 +891,25 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
891891
}
892892
target = curr->type;
893893
}
894+
std::optional<HeapType> desc;
895+
if (curr->desc) {
896+
desc = target->getHeapType().getDescriptorType();
897+
if (!desc) {
898+
self().noteUnknown();
899+
return;
900+
}
901+
}
894902
auto top = target->getHeapType().getTop();
895903
note(&curr->ref, Type(top, Nullable));
896904
if (curr->desc) {
897-
auto desc = target->getHeapType().getDescriptorType();
898-
assert(desc);
899905
note(&curr->desc, Type(*desc, Nullable, target->getExactness()));
900906
}
901907
}
902908

903909
void visitRefGetDesc(RefGetDesc* curr,
904910
std::optional<HeapType> ht = std::nullopt) {
905911
if (!ht) {
906-
if (!curr->ref->type.isRef()) {
912+
if (!curr->ref->type.isRef() || curr->ref->type.isBottomRef()) {
907913
self().noteUnknown();
908914
return;
909915
}
@@ -936,11 +942,17 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
936942
out = curr->castType;
937943
in = Type(out->getHeapType().getTop(), Nullable);
938944
}
939-
note(&curr->ref, *in);
945+
std::optional<HeapType> desc;
940946
if (curr->op == BrOnCastDescEq || curr->op == BrOnCastDescEqFail) {
941-
auto desc = out->getHeapType().getDescriptorType();
942-
assert(desc);
943-
note(&curr->desc, Type(*desc, Nullable));
947+
desc = out->getHeapType().getDescriptorType();
948+
if (!desc) {
949+
self().noteUnknown();
950+
return;
951+
}
952+
}
953+
note(&curr->ref, *in);
954+
if (desc) {
955+
note(&curr->desc, Type(*desc, Nullable, out->getExactness()));
944956
}
945957
return;
946958
}
@@ -949,7 +961,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
949961
}
950962

951963
void visitStructNew(StructNew* curr) {
952-
if (!curr->type.isRef()) {
964+
if (!curr->type.isStruct()) {
953965
self().noteUnknown();
954966
return;
955967
}
@@ -968,7 +980,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
968980
void visitStructGet(StructGet* curr,
969981
std::optional<HeapType> ht = std::nullopt) {
970982
if (!ht) {
971-
if (!curr->ref->type.isRef()) {
983+
if (!curr->ref->type.isStruct()) {
972984
self().noteUnknown();
973985
return;
974986
}
@@ -980,7 +992,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
980992
void visitStructSet(StructSet* curr,
981993
std::optional<HeapType> ht = std::nullopt) {
982994
if (!ht) {
983-
if (!curr->ref->type.isRef()) {
995+
if (!curr->ref->type.isStruct()) {
984996
self().noteUnknown();
985997
return;
986998
}
@@ -995,7 +1007,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
9951007
void visitStructRMW(StructRMW* curr,
9961008
std::optional<HeapType> ht = std::nullopt) {
9971009
if (!ht) {
998-
if (!curr->ref->type.isRef()) {
1010+
if (!curr->ref->type.isStruct()) {
9991011
self().noteUnknown();
10001012
return;
10011013
}
@@ -1010,7 +1022,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
10101022
void visitStructCmpxchg(StructCmpxchg* curr,
10111023
std::optional<HeapType> ht = std::nullopt) {
10121024
if (!ht) {
1013-
if (!curr->ref->type.isRef()) {
1025+
if (!curr->ref->type.isStruct()) {
10141026
self().noteUnknown();
10151027
return;
10161028
}
@@ -1063,7 +1075,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
10631075

10641076
void visitArrayNew(ArrayNew* curr) {
10651077
if (!curr->isWithDefault()) {
1066-
if (!curr->type.isRef()) {
1078+
if (!curr->type.isArray()) {
10671079
self().noteUnknown();
10681080
return;
10691081
}
@@ -1083,7 +1095,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
10831095
}
10841096

10851097
void visitArrayNewFixed(ArrayNewFixed* curr) {
1086-
if (!curr->type.isRef()) {
1098+
if (!curr->type.isArray()) {
10871099
self().noteUnknown();
10881100
return;
10891101
}
@@ -1096,7 +1108,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
10961108
void visitArrayGet(ArrayGet* curr,
10971109
std::optional<HeapType> ht = std::nullopt) {
10981110
if (!ht) {
1099-
if (!curr->ref->type.isRef()) {
1111+
if (!curr->ref->type.isArray()) {
11001112
self().noteUnknown();
11011113
return;
11021114
}
@@ -1109,7 +1121,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11091121
void visitArraySet(ArraySet* curr,
11101122
std::optional<HeapType> ht = std::nullopt) {
11111123
if (!ht) {
1112-
if (!curr->ref->type.isRef()) {
1124+
if (!curr->ref->type.isArray()) {
11131125
self().noteUnknown();
11141126
return;
11151127
}
@@ -1124,7 +1136,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11241136
void visitArrayLoad(ArrayLoad* curr,
11251137
std::optional<HeapType> ht = std::nullopt) {
11261138
if (!ht) {
1127-
if (!curr->ref->type.isRef()) {
1139+
if (!curr->ref->type.isArray()) {
11281140
self().noteUnknown();
11291141
return;
11301142
}
@@ -1138,7 +1150,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11381150
std::optional<HeapType> ht = std::nullopt,
11391151
std::optional<Type> valueType = std::nullopt) {
11401152
if (!ht) {
1141-
if (!curr->ref->type.isRef()) {
1153+
if (!curr->ref->type.isArray()) {
11421154
self().noteUnknown();
11431155
return;
11441156
}
@@ -1162,14 +1174,14 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11621174
std::optional<HeapType> dest = std::nullopt,
11631175
std::optional<HeapType> src = std::nullopt) {
11641176
if (!dest) {
1165-
if (!curr->destRef->type.isRef()) {
1177+
if (!curr->destRef->type.isArray()) {
11661178
self().noteUnknown();
11671179
return;
11681180
}
11691181
dest = curr->destRef->type.getHeapType();
11701182
}
11711183
if (!src) {
1172-
if (!curr->srcRef->type.isRef()) {
1184+
if (!curr->srcRef->type.isArray()) {
11731185
self().noteUnknown();
11741186
return;
11751187
}
@@ -1185,7 +1197,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
11851197
void visitArrayFill(ArrayFill* curr,
11861198
std::optional<HeapType> ht = std::nullopt) {
11871199
if (!ht) {
1188-
if (!curr->ref->type.isRef()) {
1200+
if (!curr->ref->type.isArray()) {
11891201
self().noteUnknown();
11901202
return;
11911203
}
@@ -1201,7 +1213,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
12011213
void visitArrayInitData(ArrayInitData* curr,
12021214
std::optional<HeapType> ht = std::nullopt) {
12031215
if (!ht) {
1204-
if (!curr->ref->type.isRef()) {
1216+
if (!curr->ref->type.isArray()) {
12051217
self().noteUnknown();
12061218
return;
12071219
}
@@ -1216,7 +1228,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
12161228
void visitArrayInitElem(ArrayInitElem* curr,
12171229
std::optional<HeapType> ht = std::nullopt) {
12181230
if (!ht) {
1219-
if (!curr->ref->type.isRef()) {
1231+
if (!curr->ref->type.isArray()) {
12201232
self().noteUnknown();
12211233
return;
12221234
}
@@ -1231,7 +1243,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
12311243
void visitArrayRMW(ArrayRMW* curr,
12321244
std::optional<HeapType> ht = std::nullopt) {
12331245
if (!ht) {
1234-
if (!curr->ref->type.isRef()) {
1246+
if (!curr->ref->type.isArray()) {
12351247
self().noteUnknown();
12361248
return;
12371249
}
@@ -1246,7 +1258,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
12461258
void visitArrayCmpxchg(ArrayCmpxchg* curr,
12471259
std::optional<HeapType> ht = std::nullopt) {
12481260
if (!ht) {
1249-
if (!curr->ref->type.isRef()) {
1261+
if (!curr->ref->type.isArray()) {
12501262
self().noteUnknown();
12511263
return;
12521264
}
@@ -1350,20 +1362,27 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
13501362
note(&curr->end, Type::i32);
13511363
}
13521364

1353-
void visitContNew(ContNew* curr) { note(&curr->func, curr->type); }
1365+
void visitContNew(ContNew* curr) {
1366+
if (!curr->type.isContinuation()) {
1367+
self().noteUnknown();
1368+
return;
1369+
}
1370+
note(&curr->func,
1371+
Type(curr->type.getHeapType().getContinuation().type, Nullable));
1372+
}
13541373

13551374
void visitContBind(ContBind* curr,
13561375
std::optional<HeapType> src = std::nullopt,
13571376
std::optional<HeapType> dest = std::nullopt) {
13581377
if (!src) {
1359-
if (!curr->cont->type.isRef()) {
1378+
if (!curr->cont->type.isContinuation()) {
13601379
self().noteUnknown();
13611380
return;
13621381
}
13631382
src = curr->cont->type.getHeapType();
13641383
}
13651384
if (!dest) {
1366-
if (!curr->type.isRef()) {
1385+
if (!curr->type.isContinuation()) {
13671386
self().noteUnknown();
13681387
return;
13691388
}
@@ -1390,7 +1409,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
13901409

13911410
void visitResume(Resume* curr, std::optional<HeapType> ct = std::nullopt) {
13921411
if (!ct) {
1393-
if (!curr->cont->type.isRef()) {
1412+
if (!curr->cont->type.isContinuation()) {
13941413
self().noteUnknown();
13951414
return;
13961415
}
@@ -1408,7 +1427,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
14081427
void visitResumeThrow(ResumeThrow* curr,
14091428
std::optional<HeapType> ct = std::nullopt) {
14101429
if (!ct) {
1411-
if (!curr->cont->type.isRef()) {
1430+
if (!curr->cont->type.isContinuation()) {
14121431
self().noteUnknown();
14131432
return;
14141433
}
@@ -1432,7 +1451,7 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
14321451
void visitStackSwitch(StackSwitch* curr,
14331452
std::optional<HeapType> ct = std::nullopt) {
14341453
if (!ct) {
1435-
if (!curr->cont->type.isRef()) {
1454+
if (!curr->cont->type.isContinuation()) {
14361455
self().noteUnknown();
14371456
return;
14381457
}

‎src/passes/TypeSSA.cpp‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "ir/module-utils.h"
5252
#include "ir/names.h"
5353
#include "ir/possible-constant.h"
54+
#include "ir/properties.h"
5455
#include "ir/utils.h"
5556
#include "pass.h"
5657
#include "support/hash.h"
@@ -136,26 +137,26 @@ struct Analyzer
136137
}
137138
}
138139
void visitRefTest(RefTest* curr) { visitCast(curr); }
139-
void visitRefCast(RefCast* curr) { visitCast(curr); }
140+
void visitRefCast(RefCast* curr) {
141+
visitCast(curr);
142+
visitExpression(curr);
143+
}
140144
void visitBrOn(BrOn* curr) {
141-
if (curr->op == BrOnCast || curr->op == BrOnCastFail) {
145+
if (curr->op != BrOnNull && curr->op != BrOnNonNull) {
142146
visitCast(curr);
143147
}
148+
visitExpression(curr);
144149
}
145150

146151
void visitExpression(Expression* curr) {
147152
// Look at the constraints on this expression's operands to see if it
148153
// requires an exact operand. If it does, we cannot optimize allocations of
149154
// that type. As an optimization, do not let control flow structures or
150-
// branches inhibit optimization since they can safely be refinalized to use
155+
// branches inhibit optimization. They can safely be refinalized to use
151156
// new types as long as no other instruction expected the original exact
152-
// type. Also allow optimizing if the instruction that would inhibit
153-
// optimizing will not be written in the final output. Skipping further
154-
// analysis for these instructions also ensures that the ChildTyper below
155-
// sees the type information it expects in the instructions it analyzes.
157+
// type.
156158
if (Properties::isControlFlowStructure(curr) ||
157-
Properties::isBranch(curr) ||
158-
Properties::hasUnwritableTypeImmediate(curr)) {
159+
Properties::isBranch(curr)) {
159160
return;
160161
}
161162

0 commit comments

Comments
 (0)