From 623ad09035fc1945bac272b0e6ccb135fa90c85e Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Fri, 11 Oct 2024 22:38:11 +0400 Subject: [PATCH] Add optimization from `x < 0 || x > POSITIVE_CONST` to `x > POSITIVE_CONST` with unsigned comparison Fixes #6685 --- src/passes/OptimizeInstructions.cpp | 27 +++ .../passes/optimize-instructions-cmps.wast | 162 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 test/lit/passes/optimize-instructions-cmps.wast diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index fff18b925c4..1301fb5a056 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -395,6 +395,25 @@ struct OptimizeInstructions return replaceCurrent(un); } } + { + // x < 0 || x > POSITIVE_CONST ==> x > POSITIVE_CONST (unsigned + // comparison) + Binary* bin; + Expression *x_left, *x_right; + Const* y; + // TODO: check if x_left === x_right + if (matches(curr, + binary(&bin, + OrInt32, + binary(LtSInt32, pure(&x_left), i32(0)), + binary(GtSInt32, pure(&x_right), constant(&y)))) && + y->type == Type::i32 && y->value.geti32() > 0) { + bin->op = GtUInt32; + bin->left = x_left; + bin->right = y; + return; + } + } { // x <<>> (C & (31 | 63)) ==> x <<>> C' // x <<>> (y & (31 | 63)) ==> x <<>> y @@ -679,6 +698,14 @@ struct OptimizeInstructions if (auto* ret = optimizeAddedConstants(curr)) { return replaceCurrent(ret); } + } else if (curr->op == SubInt32 || curr->op == SubInt64 || + curr->op == AddVecI8x16 || curr->op == AddVecI16x8 || + curr->op == SubVecI8x16 || curr->op == SubVecI16x8 || + curr->op == AddVecI32x4 || curr->op == AddVecI64x2 || + curr->op == SubVecI32x4 || curr->op == SubVecI64x2) { + if (auto* ret = optimizeAddedConstants(curr)) { + return replaceCurrent(ret); + } } else if (curr->op == MulFloat32 || curr->op == MulFloat64 || curr->op == DivFloat32 || curr->op == DivFloat64) { if (curr->left->type == curr->right->type) { diff --git a/test/lit/passes/optimize-instructions-cmps.wast b/test/lit/passes/optimize-instructions-cmps.wast new file mode 100644 index 00000000000..dea9b60b018 --- /dev/null +++ b/test/lit/passes/optimize-instructions-cmps.wast @@ -0,0 +1,162 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --optimize-instructions -S -o - | filecheck %s + +;; Tests for "x < 0 || x > POSITIVE_CONST ==> x > POSITIVE_CONST (unsigned comparison)" optimization + +(module + ;; CHECK: (global $g (mut i32) (i32.const 0)) + (global $g (mut i32) (i32.const 0)) + + ;; CHECK: (func $cmp (param $0 i32) (result i32) + ;; CHECK-NEXT: (i32.gt_u + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 255) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cmp (param $0 i32) (result i32) + (i32.or + (i32.lt_s + (local.get $0) + (i32.const 0) + ) + (i32.gt_s + (local.get $0) + (i32.const 255) + ) + ) + ) + + ;; CHECK: (func $cmp2 (param $0 i32) (result i32) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.gt_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const -255) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cmp2 (param $0 i32) (result i32) + (i32.or + (i32.lt_s + (local.get $0) + (i32.const 0) + ) + (i32.gt_s + (local.get $0) + (i32.const -255) ;; negative number + ) + ) + ) + + ;; CHECK: (func $cmp3 (param $0 i32) (result i32) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.gt_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 255) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cmp3 (param $0 i32) (result i32) + (i32.or + (i32.lt_s + (local.get $0) + (i32.const 10) ;; note this + ) + (i32.gt_s + (local.get $0) + (i32.const 255) + ) + ) + ) + + ;; CHECK: (func $set_global_and_return (param $x i32) (result i32) + ;; CHECK-NEXT: (global.set $g + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + (func $set_global_and_return (param $x i32) (result i32) + (global.set $g (local.get $x)) ;; side-effect + (local.get $x) + ) + + ;; CHECK: (func $cmp4 (result i32) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (call $set_global_and_return + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.gt_s + ;; CHECK-NEXT: (call $set_global_and_return + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 255) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cmp4 (result i32) + (i32.or + (i32.lt_s + (call $set_global_and_return (i32.const 10)) ;; x with side-effect + (i32.const 0) + ) + (i32.gt_s + (call $set_global_and_return (i32.const 10)) + (i32.const 255) + ) + ) + ) + + ;; CHECK: (func $cmp5 (param $0 i32) (param $1 i32) (result i32) + ;; CHECK-NEXT: (i32.gt_u + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 255) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cmp5 (param $0 i32) (param $1 i32) (result i32) + (i32.or + (i32.lt_s + (local.get $0) + (i32.const 0) + ) + (i32.gt_s + (local.get $1) ;; note this + (i32.const 255) + ) + ) + ) + + ;; CHECK: (func $cmp6 (param $0 i32) (param $1 i32) (result i32) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.gt_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cmp6 (param $0 i32) (param $1 i32) (result i32) + (i32.or + (i32.lt_s + (local.get $0) + (i32.const 0) + ) + (i32.gt_s + (local.get $0) + (local.get $1) ;; non-constant + ) + ) + ) +)