Skip to content
Merged
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
23 changes: 8 additions & 15 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -891,23 +891,16 @@ struct InfoCollector
handleIndirectCall(curr, curr->target->type);
}

// Creates a location for a root of a particular type, creating a RootLocation
// and marking it as a root.
Location getRootLocation(Type type, PossibleContents rootValue) {
auto location = RootLocation{type};
addRoot(location, rootValue);
Location getTypeLocation(Type type) {
auto location = TypeLocation{type};
addRoot(location, PossibleContents::fromType(type));
return location;
}

// Creates a root location, settings its value by the type.
Location getRootLocation(Type type) {
return getRootLocation(type, PossibleContents::fromType(type));
}

// Makes a root location containing a null.
Location getNullLocation(Type type) {
return getRootLocation(type,
PossibleContents::literal(Literal::makeZero(type)));
auto location = NullLocation{type};
addRoot(location, PossibleContents::literal(Literal::makeZero(type)));
return location;
}

// Iterates over a list of children and adds links from them. The target of
Expand Down Expand Up @@ -1230,7 +1223,7 @@ struct InfoCollector
}

if (curr->catchRefs[tagIndex]) {
auto location = getRootLocation(Type(HeapType::exn, NonNullable));
auto location = getTypeLocation(Type(HeapType::exn, NonNullable));
info.links.push_back(
{location, getBreakTargetLocation(target, exnrefIndex)});
}
Expand Down Expand Up @@ -1317,7 +1310,7 @@ struct InfoCollector
auto targetType = findBreakTarget(target)->type;
assert(targetType.size() >= 1);
auto contType = targetType[targetType.size() - 1];
auto location = getRootLocation(contType);
auto location = getTypeLocation(contType);
info.links.push_back(
{location, getBreakTargetLocation(target, params.size())});
}
Expand Down
38 changes: 25 additions & 13 deletions src/ir/possible-contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -500,17 +500,22 @@ struct TagLocation {
}
};

// A root value. This is used as the location of the default value of a var in a
// function, a null written to a struct field in struct.new_with_default, an
// exnref from a catch etc. - in all these cases, we know
//
// 1. The value (which might be a null, or "anything of this type").
// 2. That the value will never change; we can learn nothing more here.
// 3. That all roots of this type can share the same location.
//
struct RootLocation {
// A null value of a particular type. For example, a nullable local reads from
// the corresponding NullLocation, for its default value.
struct NullLocation {
Type type;
bool operator==(const RootLocation& other) const {
bool operator==(const NullLocation& other) const {
return type == other.type;
}
};

// A location that contains anything of a particular type. This is used as a
// root of the graph, a source of values we will never learn anything about, and
// must assume they can be anything of that type (e.g., the return of a call to
// an import).
struct TypeLocation {
Type type;
bool operator==(const TypeLocation& other) const {
return type == other.type;
}
};
Expand Down Expand Up @@ -552,7 +557,8 @@ using Location = std::variant<ExpressionLocation,
SignatureResultLocation,
DataLocation,
TagLocation,
RootLocation,
NullLocation,
TypeLocation,
ConeReadLocation>;

} // namespace wasm
Expand Down Expand Up @@ -633,8 +639,14 @@ template<> struct hash<wasm::TagLocation> {
}
};

template<> struct hash<wasm::RootLocation> {
size_t operator()(const wasm::RootLocation& loc) const {
template<> struct hash<wasm::NullLocation> {
size_t operator()(const wasm::NullLocation& loc) const {
return std::hash<wasm::Type>{}(loc.type);
}
};

template<> struct hash<wasm::TypeLocation> {
size_t operator()(const wasm::TypeLocation& loc) const {
return std::hash<wasm::Type>{}(loc.type);
}
};
Expand Down
93 changes: 93 additions & 0 deletions test/lit/passes/gufa-eh-null-type.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: foreach %s %t wasm-opt -all --gufa -S -o - | filecheck %s

;; The function here will use a NullLocation for (ref exn) as well as a
;; TypeLocation for that very same type. We should not get confused by that (see
;; below).

(module
;; CHECK: (type $func (func))
(type $func (func))

;; CHECK: (tag $tag (type $func))
(tag $tag (type $func))

;; CHECK: (export "func" (func $func))

;; CHECK: (func $func (type $func)
;; CHECK-NEXT: (local $1 (ref exn))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $block (result (ref exn))
;; CHECK-NEXT: (try_table (catch_all_ref $block)
;; CHECK-NEXT: (throw $tag)
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (try
;; CHECK-NEXT: (do
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: (catch $tag
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $block0 (result (ref noexn))
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br_on_non_null $block0
;; CHECK-NEXT: (ref.null noexn)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $func (export "func")
(local $1 (ref exn))
;; This part ends up generating a TypeLocation for (ref exn).
;;
;; This code should not be mis-optimized. In particular, it should not trap.
(drop
(block $block (result (ref exn))
(try_table (catch_all_ref $block)
(throw $tag)
)
(return)
)
)
(try
(do
(nop)
)
(catch $tag
(drop
(block $block (result (ref exn))
;; This part ends up generating a NullLocation for (ref exn).
;;
;; Due to the unreachable here, we will end up modifying this code to add
;; more unreachables.
(br_on_non_null $block
(local.tee $1
(unreachable)
)
(ref.null noexn)
)
(drop
(local.get $1)
)
)
)
)
)
)
)
Loading