Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/passes/OptimizeInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
22 changes: 22 additions & 0 deletions test/lit/passes/optimize-instructions-tee-get-comparison.wast
Original file line number Diff line number Diff line change
@@ -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))
)
)
Loading