diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index b862dd9e45c..bb65db00e27 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -4990,6 +4990,47 @@ struct OptimizeInstructions using namespace Match; auto type = curr->right->type; + + // (rel (local.tee $n X) (local.get $n)) compares X against itself, so + // the result is a constant. Evaluate X once for its side effects, + // discard the tee's value, and return the constant. Do not duplicate X: + // it may trap or write (the reproduction is a chain of loads). + if (areMatchingTeeAndGet(curr->left, curr->right)) { + bool isTrue; + switch (curr->op) { + case GtSInt32: + case GtUInt32: + case LtSInt32: + case LtUInt32: + case GtSInt64: + case GtUInt64: + case LtSInt64: + case LtUInt64: + case NeInt32: + case NeInt64: + isTrue = false; + break; + case GeSInt32: + case GeUInt32: + case LeSInt32: + case LeUInt32: + case GeSInt64: + case GeUInt64: + case LeSInt64: + case LeUInt64: + case EqInt32: + case EqInt64: + isTrue = true; + break; + default: + WASM_UNREACHABLE("unexpected relational op"); + } + Builder builder(*getModule()); + return builder.makeSequence( + builder.makeDrop(curr->left), + builder.makeConst(Literal::makeFromInt32(isTrue, Type::i32))); + } + if (curr->left->type.isInteger()) { if (curr->op == Abstract::getBinary(type, Abstract::Eq) || curr->op == Abstract::getBinary(type, Abstract::Ne)) { diff --git a/test/lit/passes/optimize-instructions-tee-get-comparison.wast b/test/lit/passes/optimize-instructions-tee-get-comparison.wast new file mode 100644 index 00000000000..4b1f6ad1dd4 --- /dev/null +++ b/test/lit/passes/optimize-instructions-tee-get-comparison.wast @@ -0,0 +1,22 @@ +;; RUN: wasm-opt -all --optimize-instructions %s -S -o - | filecheck %s + +;; (i32.gt_s (local.tee $0 X) (local.get $0)) is X compared with itself, +;; always 0. The tee and its load are preserved for trap behavior; the +;; comparison folds to a constant. +;; CHECK: (drop +;; CHECK-NEXT: (local.tee $0 +;; CHECK-NEXT: (i32.load +;; CHECK-NEXT: (i32.const 0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (i32.const 0) +;; NOT: i32.gt_s +(module + (memory 1) + (func $f (result i32) (local $0 i32) + (i32.gt_s + (local.tee $0 (i32.load (i32.const 0))) + (local.get $0)) + ) +) \ No newline at end of file