summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp24
-rw-r--r--test/lit/passes/optimize-instructions.wast116
2 files changed, 140 insertions, 0 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index d3c3f26f6..106bfea19 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1430,6 +1430,7 @@ private:
Expression* optimizeSelect(Select* curr) {
using namespace Match;
+ using namespace Abstract;
Builder builder(*getModule());
curr->condition = optimizeBoolean(curr->condition);
{
@@ -1482,6 +1483,29 @@ private:
}
}
{
+ // Simplify x < 0 ? -1 : 1 or x >= 0 ? 1 : -1 to
+ // i32(x) >> 31 | 1
+ // i64(x) >> 63 | 1
+ Binary* bin;
+ if (matches(
+ curr,
+ select(ival(-1), ival(1), binary(&bin, LtS, any(), ival(0)))) ||
+ matches(
+ curr,
+ select(ival(1), ival(-1), binary(&bin, GeS, any(), ival(0))))) {
+ auto c = bin->right->cast<Const>();
+ auto type = curr->ifTrue->type;
+ if (type == c->type) {
+ bin->type = type;
+ bin->op = Abstract::getBinary(type, ShrS);
+ c->value = Literal::makeFromInt32(type.getByteSize() * 8 - 1, type);
+ curr->ifTrue->cast<Const>()->value = Literal::makeOne(type);
+ return builder.makeBinary(
+ Abstract::getBinary(type, Or), bin, curr->ifTrue);
+ }
+ }
+ }
+ {
// Sides are identical, fold
Expression *ifTrue, *ifFalse, *c;
if (matches(curr, select(any(&ifTrue), any(&ifFalse), any(&c))) &&
diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast
index 728081e9f..e8296e8cc 100644
--- a/test/lit/passes/optimize-instructions.wast
+++ b/test/lit/passes/optimize-instructions.wast
@@ -587,6 +587,122 @@
)
)
)
+ ;; CHECK: (func $select-sign-32-lt (param $x i32) (result i32)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (i32.shr_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 31)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select-sign-32-lt (param $x i32) (result i32)
+ (select
+ (i32.const -1)
+ (i32.const 1)
+ (i32.lt_s
+ (local.get $x)
+ (i32.const 0)
+ )
+ )
+ )
+ ;; CHECK: (func $select-sign-32-ge (param $x i32) (result i32)
+ ;; CHECK-NEXT: (i32.or
+ ;; CHECK-NEXT: (i32.shr_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 31)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select-sign-32-ge (param $x i32) (result i32)
+ (select
+ (i32.const 1)
+ (i32.const -1)
+ (i32.ge_s
+ (local.get $x)
+ (i32.const 0)
+ )
+ )
+ )
+ ;; CHECK: (func $select-sign-64-lt (param $x i64) (result i64)
+ ;; CHECK-NEXT: (i64.or
+ ;; CHECK-NEXT: (i64.shr_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i64.const 63)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select-sign-64-lt (param $x i64) (result i64)
+ (select
+ (i64.const -1)
+ (i64.const 1)
+ (i64.lt_s
+ (local.get $x)
+ (i64.const 0)
+ )
+ )
+ )
+ ;; CHECK: (func $select-sign-64-ge (param $x i64) (result i64)
+ ;; CHECK-NEXT: (i64.or
+ ;; CHECK-NEXT: (i64.shr_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i64.const 63)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select-sign-64-ge (param $x i64) (result i64)
+ (select
+ (i64.const 1)
+ (i64.const -1)
+ (i64.ge_s
+ (local.get $x)
+ (i64.const 0)
+ )
+ )
+ )
+ ;; CHECK: (func $select-sign-lt-skip-1 (param $x i32) (result i64)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i64.const -1)
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: (i32.lt_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select-sign-lt-skip-1 (param $x i32) (result i64)
+ (select
+ (i64.const -1)
+ (i64.const 1)
+ (i32.lt_s
+ (local.get $x)
+ (i32.const 0)
+ )
+ )
+ )
+ ;; CHECK: (func $select-sign-lt-skip-2 (param $x i64) (result i32)
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (i32.const -1)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i64.lt_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i64.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select-sign-lt-skip-2 (param $x i64) (result i32)
+ (select
+ (i32.const -1)
+ (i32.const 1)
+ (i64.lt_s
+ (local.get $x)
+ (i64.const 0)
+ )
+ )
+ )
;; CHECK: (func $load8_s-and-255 (result i32)
;; CHECK-NEXT: (i32.load8_u
;; CHECK-NEXT: (i32.const 0)