summaryrefslogtreecommitdiff
path: root/src/passes/OptimizeInstructions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/OptimizeInstructions.cpp')
-rw-r--r--src/passes/OptimizeInstructions.cpp35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index c54960079..59a38eeaa 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -350,6 +350,41 @@ struct OptimizeInstructions
return inner;
}
}
+ {
+ // x <<>> (C & (31 | 63)) ==> x <<>> C'
+ // x <<>> (y & (31 | 63)) ==> x <<>> y
+ // where '<<>>':
+ // '<<', '>>', '>>>'. 'rotl' or 'rotr'
+ BinaryOp op;
+ Const* c;
+ Expression *x, *y;
+
+ // x <<>> C
+ if (matches(curr, binary(&op, any(&x), ival(&c))) &&
+ Abstract::hasAnyShift(op)) {
+ // truncate RHS constant to effective size as:
+ // i32(x) <<>> const(C & 31))
+ // i64(x) <<>> const(C & 63))
+ c->value = c->value.and_(
+ Literal::makeFromInt32(c->type.getByteSize() * 8 - 1, c->type));
+ // x <<>> 0 ==> x
+ if (c->value.isZero()) {
+ return x;
+ }
+ }
+ if (matches(
+ curr,
+ binary(&op, any(&x), binary(Abstract::And, any(&y), ival(&c)))) &&
+ Abstract::hasAnyShift(op)) {
+ // i32(x) <<>> (y & 31) ==> x <<>> y
+ // i64(x) <<>> (y & 63) ==> x <<>> y
+ if ((c->type == Type::i32 && (c->value.geti32() & 31) == 31) ||
+ (c->type == Type::i64 && (c->value.geti64() & 63LL) == 63LL)) {
+ curr->cast<Binary>()->right = y;
+ return curr;
+ }
+ }
+ }
}
if (auto* select = curr->dynCast<Select>()) {