summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/properties.h33
-rw-r--r--src/ir/struct-utils.h10
2 files changed, 33 insertions, 10 deletions
diff --git a/src/ir/properties.h b/src/ir/properties.h
index 4bd66b1d5..1d2937d81 100644
--- a/src/ir/properties.h
+++ b/src/ir/properties.h
@@ -240,17 +240,29 @@ inline Index getZeroExtBits(Expression* curr) {
// way to the final value falling through, potentially through multiple
// intermediate expressions.
//
+// Behavior wrt tee/br_if is customizable, since in some cases we do not want to
+// look through them (for example, the type of a tee is related to the local,
+// not the value, so if we returned the fallthrough of the tee we'd have a
+// possible difference between the type in the IR and the type of the value,
+// which some cases care about; the same for a br_if, whose type is related to
+// the branch target).
+//
// TODO: Receive a Module instead of FeatureSet, to pass to EffectAnalyzer?
-inline Expression* getImmediateFallthrough(Expression* curr,
- const PassOptions& passOptions,
- Module& module) {
+
+enum class FallthroughBehavior { AllowTeeBrIf, NoTeeBrIf };
+
+inline Expression* getImmediateFallthrough(
+ Expression* curr,
+ const PassOptions& passOptions,
+ Module& module,
+ FallthroughBehavior behavior = FallthroughBehavior::AllowTeeBrIf) {
// If the current node is unreachable, there is no value
// falling through.
if (curr->type == Type::unreachable) {
return curr;
}
if (auto* set = curr->dynCast<LocalSet>()) {
- if (set->isTee()) {
+ if (set->isTee() && behavior == FallthroughBehavior::AllowTeeBrIf) {
return set->value;
}
} else if (auto* block = curr->dynCast<Block>()) {
@@ -270,7 +282,8 @@ inline Expression* getImmediateFallthrough(Expression* curr,
}
}
} else if (auto* br = curr->dynCast<Break>()) {
- if (br->condition && br->value) {
+ if (br->condition && br->value &&
+ behavior == FallthroughBehavior::AllowTeeBrIf) {
return br->value;
}
} else if (auto* tryy = curr->dynCast<Try>()) {
@@ -289,11 +302,13 @@ inline Expression* getImmediateFallthrough(Expression* curr,
// Similar to getImmediateFallthrough, but looks through multiple children to
// find the final value that falls through.
-inline Expression* getFallthrough(Expression* curr,
- const PassOptions& passOptions,
- Module& module) {
+inline Expression* getFallthrough(
+ Expression* curr,
+ const PassOptions& passOptions,
+ Module& module,
+ FallthroughBehavior behavior = FallthroughBehavior::AllowTeeBrIf) {
while (1) {
- auto* next = getImmediateFallthrough(curr, passOptions, module);
+ auto* next = getImmediateFallthrough(curr, passOptions, module, behavior);
if (next == curr) {
return curr;
}
diff --git a/src/ir/struct-utils.h b/src/ir/struct-utils.h
index ba5617de6..9d02bb779 100644
--- a/src/ir/struct-utils.h
+++ b/src/ir/struct-utils.h
@@ -191,7 +191,10 @@ struct StructScanner
// (otherwise, we'd need to consider both the type actually written and the
// type of the fallthrough, somehow).
auto* fallthrough = Properties::getFallthrough(
- expr, this->getPassOptions(), *this->getModule());
+ expr,
+ this->getPassOptions(),
+ *this->getModule(),
+ static_cast<SubType*>(this)->getFallthroughBehavior());
if (fallthrough->type == expr->type) {
expr = fallthrough;
}
@@ -205,6 +208,11 @@ struct StructScanner
static_cast<SubType*>(this)->noteExpression(expr, type, index, info);
}
+ Properties::FallthroughBehavior getFallthroughBehavior() {
+ // By default, look at and use tee&br_if fallthrough values.
+ return Properties::FallthroughBehavior::AllowTeeBrIf;
+ }
+
FunctionStructValuesMap<T>& functionNewInfos;
FunctionStructValuesMap<T>& functionSetGetInfos;
};