summaryrefslogtreecommitdiff
path: root/src/passes/OptimizeInstructions.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-02-14 08:06:52 -0800
committerGitHub <noreply@github.com>2018-02-14 08:06:52 -0800
commite97d485bb1f1818e2c2118d28507d49cb61ea57b (patch)
treee1ef9db3f9b95ba4d279ec6c421e0b1c4f2a3b22 /src/passes/OptimizeInstructions.cpp
parent41faf2409f3e1d8d2dcaf456141f4ce6ac6a3d75 (diff)
downloadbinaryen-e97d485bb1f1818e2c2118d28507d49cb61ea57b.tar.gz
binaryen-e97d485bb1f1818e2c2118d28507d49cb61ea57b.tar.bz2
binaryen-e97d485bb1f1818e2c2118d28507d49cb61ea57b.zip
More simple math opts (#1414)
* optimize more simple math operations: mul of 0, or of 0, and of 0, mul of 1, mul of a power of 2, urem of a power of 2 * fix asm2wasm callImport parsing: the optimizer may get rid of the added offset to a function table * update js builds
Diffstat (limited to 'src/passes/OptimizeInstructions.cpp')
-rw-r--r--src/passes/OptimizeInstructions.cpp47
1 files changed, 45 insertions, 2 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 7bd7aaa51..8fd98cfda 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -567,9 +567,16 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
}
- // some operations have no effect TODO: many more
+ // some math operations have trivial results TODO: many more
if (right->value == Literal(int32_t(0))) {
- if (binary->op == ShlInt32 || binary->op == ShrUInt32 || binary->op == ShrSInt32) {
+ if (binary->op == ShlInt32 || binary->op == ShrUInt32 || binary->op == ShrSInt32 || binary->op == OrInt32) {
+ return binary->left;
+ } else if ((binary->op == MulInt32 || binary->op == AndInt32) &&
+ !EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) {
+ return binary->right;
+ }
+ } else if (right->value == Literal(int32_t(1))) {
+ if (binary->op == MulInt32) {
return binary->left;
}
}
@@ -597,6 +604,17 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
}
}
}
+ // math operations on a constant power of 2 right side can be optimized
+ if (right->type == i32) {
+ uint32_t c = right->value.geti32();
+ if (IsPowerOf2(c)) {
+ if (binary->op == MulInt32) {
+ return optimizePowerOf2Mul(binary, c);
+ } else if (binary->op == RemUInt32) {
+ return optimizePowerOf2URem(binary, c);
+ }
+ }
+ }
}
// bitwise operations
if (binary->op == AndInt32) {
@@ -1024,6 +1042,31 @@ private:
}
}
+ // Optimize a multiply by a power of two on the right, which
+ // can be a shift.
+ // This doesn't shrink code size, and VMs likely optimize it anyhow,
+ // but it's still worth doing since
+ // * Often shifts are more common than muls.
+ // * The constant is smaller.
+ Expression* optimizePowerOf2Mul(Binary* binary, uint32_t c) {
+ uint32_t shifts = CountTrailingZeroes(c);
+ binary->op = ShlInt32;
+ binary->right->cast<Const>()->value = Literal(int32_t(shifts));
+ return binary;
+ }
+
+ // Optimize an unsigned divide by a power of two on the right,
+ // which can be an AND mask
+ // This doesn't shrink code size, and VMs likely optimize it anyhow,
+ // but it's still worth doing since
+ // * Usually ands are more common than urems.
+ // * The constant is slightly smaller.
+ Expression* optimizePowerOf2URem(Binary* binary, uint32_t c) {
+ binary->op = AndInt32;
+ binary->right->cast<Const>()->value = Literal(int32_t(c - 1));
+ return binary;
+ }
+
Expression* makeZeroExt(Expression* curr, int32_t bits) {
Builder builder(*getModule());
return builder.makeBinary(AndInt32, curr, builder.makeConst(Literal(Bits::lowBitMask(bits))));