summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-08-17 12:09:22 -0700
committerGitHub <noreply@github.com>2023-08-17 19:09:22 +0000
commitc39ca2e1cde95b6fcef6cdfeb9326dadd75e55df (patch)
treeca9a9535fc37e7bbb23c1e9f73a4dbeb38410279 /src/ir
parent7424929782692271a09a19572806e1760beacddc (diff)
downloadbinaryen-c39ca2e1cde95b6fcef6cdfeb9326dadd75e55df.tar.gz
binaryen-c39ca2e1cde95b6fcef6cdfeb9326dadd75e55df.tar.bz2
binaryen-c39ca2e1cde95b6fcef6cdfeb9326dadd75e55df.zip
Improve cast optimizations (#5876)
Simplify the optimization of ref.cast and ref.test in OptimizeInstructions by moving the loop that examines fallthrough values one at a time out to a shared function in properties.h. Also simplify ref.cast optimization by analyzing the cast result in just one place. In addition to simplifying the code, also make the cast optimizations more powerful by analyzing the nullability and heap type of the cast value independently, resulting in a potentially more precise analysis of the cast behavior. Also improve optimization power by considering fallthrough values when optimizing the SuccessOnlyIfNonNull case.
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/properties.h68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/ir/properties.h b/src/ir/properties.h
index d47cf774b..7f247f72f 100644
--- a/src/ir/properties.h
+++ b/src/ir/properties.h
@@ -362,6 +362,74 @@ inline Expression* getFallthrough(
}
}
+// Look at all the intermediate fallthrough expressions and return the most
+// precise type we know this value will have.
+inline Type getFallthroughType(Expression* curr,
+ const PassOptions& passOptions,
+ Module& module) {
+ Type type = curr->type;
+ if (!type.isRef()) {
+ // Only reference types can be improved (excepting improvements to
+ // unreachable, which we leave to refinalization).
+ // TODO: Handle tuples if that ever becomes important.
+ return type;
+ }
+ while (1) {
+ auto* next = getImmediateFallthrough(curr, passOptions, module);
+ if (next == curr) {
+ return type;
+ }
+ type = Type::getGreatestLowerBound(type, next->type);
+ if (type == Type::unreachable) {
+ return type;
+ }
+ curr = next;
+ }
+}
+
+// Find the best fallthrough value ordered by refinement of heaptype, refinement
+// of nullability, and closeness to the current expression. The type of the
+// expression this function returns may be nullable even if `getFallthroughType`
+// is non-nullable, but the heap type will definitely match.
+inline Expression** getMostRefinedFallthrough(Expression** currp,
+ const PassOptions& passOptions,
+ Module& module) {
+ Expression* curr = *currp;
+ if (!curr->type.isRef()) {
+ return currp;
+ }
+ auto bestType = curr->type.getHeapType();
+ auto bestNullability = curr->type.getNullability();
+ auto** bestp = currp;
+ while (1) {
+ curr = *currp;
+ auto** nextp =
+ Properties::getImmediateFallthroughPtr(currp, passOptions, module);
+ auto* next = *nextp;
+ if (next == curr || next->type == Type::unreachable) {
+ return bestp;
+ }
+ assert(next->type.isRef());
+ auto nextType = next->type.getHeapType();
+ auto nextNullability = next->type.getNullability();
+ if (nextType == bestType) {
+ // Heap types match: refine nullability if possible.
+ if (bestNullability == Nullable && nextNullability == NonNullable) {
+ bestp = nextp;
+ bestNullability = NonNullable;
+ }
+ } else {
+ // Refine heap type if possible, resetting nullability.
+ if (HeapType::isSubType(nextType, bestType)) {
+ bestp = nextp;
+ bestNullability = nextNullability;
+ bestType = nextType;
+ }
+ }
+ currp = nextp;
+ }
+}
+
inline Index getNumChildren(Expression* curr) {
Index ret = 0;