Skip to content
Open
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
3 changes: 3 additions & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ struct InfoCollector
info.links.push_back({SignatureResultLocation{subType, i},
ResultLocation{getFunction(), i}});
}
return true;
});
}
}
Expand Down Expand Up @@ -3282,6 +3283,7 @@ void Flower::readFromData(Type declaredType,
[&](HeapType type, Index depth) {
connectDuringFlow(DataLocation{type, fieldIndex},
coneReadLocation);
return true;
});

// TODO: we can end up with redundant links here if we see one cone first
Expand Down Expand Up @@ -3351,6 +3353,7 @@ void Flower::writeToData(Expression* ref,
cone.type.getHeapType(), normalizedDepth, [&](HeapType type, Index depth) {
auto heapLoc = DataLocation{type, fieldIndex};
updateContents(heapLoc, valueContents);
return true;
});
}

Expand Down
11 changes: 8 additions & 3 deletions src/ir/subtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,14 @@ struct SubTypes {

// Efficiently iterate on subtypes of a type, up to a particular depth (depth
// 0 means not to traverse subtypes, etc.). The callback function receives
// (type, depth).
// (type, depth) and returns whether to continue the scan (i.e. if it returns
// false, we stop).
template<typename F>
void iterSubTypes(HeapType type, Index depth, F func) const {
// Start by traversing the type itself.
func(type, 0);
if (!func(type, 0)) {
return;
}

if (depth == 0) {
// Nothing else to scan.
Expand Down Expand Up @@ -201,7 +204,9 @@ struct SubTypes {
auto& currVec = *item.vec;
assert(currDepth <= depth);
for (auto type : currVec) {
func(type, currDepth);
if (!func(type, currDepth)) {
return;
}
auto* subVec = &getImmediateSubTypes(type);
if (currDepth + 1 <= depth && !subVec->empty()) {
work.push_back({subVec, currDepth + 1});
Expand Down
17 changes: 8 additions & 9 deletions src/passes/ConstantFieldPropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,27 +332,23 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> {
// as having failed.
auto fail = false;
auto handleType = [&](HeapType type, Index depth) {
if (fail) {
// TODO: Add a mechanism to halt |iterSubTypes| in the middle, as once
// we fail there is no point to further iterating.
return;
}
assert(!fail);

auto iter = refTestInfos.find({type, Exact});
if (iter == refTestInfos.end()) {
// This type has no allocations, so we can ignore it: it is abstract.
return;
return true;
}

auto value = iter->second[index];
if (!value.hasNoted()) {
// Also abstract and ignorable.
return;
return true;
}
if (!value.isConstant()) {
// The value here is not constant, so give up entirely.
fail = true;
return;
return false;
}

// Consider the constant value compared to previous ones.
Expand All @@ -376,9 +372,11 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> {
// the last, we've failed to find only two values.
if (i == 1) {
fail = true;
return;
return false;
}
}

return true;
};
subTypes.iterSubTypes(refHeapType, handleType);

Expand Down Expand Up @@ -677,6 +675,7 @@ struct ConstantFieldPropagation : public Pass {
if (readable[{sub, Exact}][dst.index].combine(val)) {
applyCopiesFrom(sub, Exact, dst.index, val);
}
return true;
});
} else {
// The copy destination is exact, so there are no subtypes to
Expand Down
1 change: 1 addition & 0 deletions src/passes/RemoveUnusedModuleElements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ struct Analyzer {
}
}
unreadStructFieldExprMap.erase(subStructField);
return true;
});
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/tools/fuzzing/heap-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1000,8 +1000,10 @@ void Inhabitator::markNullable(FieldPos field) {
// this extra `index` variable once we have C++20. It's a workaround for
// lambdas being unable to capture structured bindings.
const size_t index = idx;
subtypes.iterSubTypes(
curr, [&](HeapType type, Index) { nullables.insert({type, index}); });
subtypes.iterSubTypes(curr, [&](HeapType type, Index) {
nullables.insert({type, index});
return true;
});
break;
}
}
Expand Down
19 changes: 19 additions & 0 deletions test/gtest/type-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,7 @@ TEST_F(TypeTest, TestIterSubTypes) {
HeapType A, B, C, D;
{
TypeBuilder builder(4);
builder.createRecGroup(0, 4);
builder[0].setOpen() = Struct();
builder[1].setOpen().subTypeOf(builder[0]) = Struct();
builder[2].setOpen().subTypeOf(builder[0]) = Struct();
Expand All @@ -1717,6 +1718,7 @@ TEST_F(TypeTest, TestIterSubTypes) {
TypeDepths ret;
subTypes.iterSubTypes(type, depth, [&](HeapType subType, Index depth) {
ret.insert({subType, depth});
return true;
});
return ret;
};
Expand All @@ -1729,6 +1731,23 @@ TEST_F(TypeTest, TestIterSubTypes) {
EXPECT_EQ(getSubTypes(C, 0), TypeDepths({{C, 0}}));
EXPECT_EQ(getSubTypes(C, 1), TypeDepths({{C, 0}, {D, 1}}));
EXPECT_EQ(getSubTypes(C, 2), TypeDepths({{C, 0}, {D, 1}}));

// When the iteration function returns |false|, we stop.
int count = 0;
subTypes.iterSubTypes(A, 3, [&](HeapType subType, Index depth) {
count++;
// Stop after the second increment.
return count != 2;
});
EXPECT_EQ(count, 2);

// If we return true, we iterate through all four.
count = 0;
subTypes.iterSubTypes(A, 3, [&](HeapType subType, Index depth) {
count++;
return true;
});
EXPECT_EQ(count, 4);
}

// Test supertypes
Expand Down
Loading