diff options
author | Alon Zakai <azakai@google.com> | 2021-09-13 11:33:00 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-13 11:33:00 -0700 |
commit | ec2c5df877c479855bd13d280b98220e50bb99f9 (patch) | |
tree | 27ea5e95fa15846cb7773552a78b95c3f476cf04 /src/passes/OptimizeInstructions.cpp | |
parent | 5b90e0332253ee879d16fbc29d391ad75734ecf5 (diff) | |
download | binaryen-ec2c5df877c479855bd13d280b98220e50bb99f9.tar.gz binaryen-ec2c5df877c479855bd13d280b98220e50bb99f9.tar.bz2 binaryen-ec2c5df877c479855bd13d280b98220e50bb99f9.zip |
OptimizeInstructions: Optimize boolean selects (#4147)
If all a select's inputs are boolean, we can sometimes turn the select
into an AND or an OR operation,
x ? y : 0 => x & y
x ? 1 : y => x | y
I believe LLVM aggressively canonicalizes to this form. It makes sense
to do here too as it is smaller (save the constant 0 or 1). It also allows
further optimizations (which is why LLVM does it) but I don't think we
have those yet.
Diffstat (limited to 'src/passes/OptimizeInstructions.cpp')
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 357f172d9..768ea5702 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1819,6 +1819,25 @@ private: } } } + if (curr->type == Type::i32 && + Bits::getMaxBits(curr->condition, this) <= 1 && + Bits::getMaxBits(curr->ifTrue, this) <= 1 && + Bits::getMaxBits(curr->ifFalse, this) <= 1) { + // The condition and both arms are i32 booleans, which allows us to do + // boolean optimizations. + Expression* x; + Expression* y; + + // x ? y : 0 ==> x & y + if (matches(curr, select(any(&y), ival(0), any(&x)))) { + return builder.makeBinary(AndInt32, y, x); + } + + // x ? 1 : y ==> x | y + if (matches(curr, select(ival(1), any(&y), any(&x)))) { + return builder.makeBinary(OrInt32, y, x); + } + } { // Sides are identical, fold Expression *ifTrue, *ifFalse, *c; |