Skip to content
Merged
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
40 changes: 40 additions & 0 deletions src/passes/OptimizeInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,46 @@ struct OptimizeInstructions
}
}

if (curr->op == ExtendUInt32 || curr->op == ExtendSInt32) {
if (auto* load = curr->value->dynCast<Load>()) {
// i64.extend_i32_s(i32.load(_8|_16)(_u|_s)(x)) =>
// i64.load(_8|_16|_32)(_u|_s)(x)
//
// i64.extend_i32_u(i32.load(_8|_16)(_u|_s)(x)) =>
// i64.load(_8|_16|_32)(_u|_s)(x)
//
// but we can't do this in following cases:
//
// i64.extend_i32_u(i32.load8_s(x))
// i64.extend_i32_u(i32.load16_s(x))
//
// this mixed sign/zero extensions can't represent in single
// signed or unsigned 64-bit load operation. For example if `load8_s(x)`
// return i8(-1) (0xFF) than sign extended result will be
// i32(-1) (0xFFFFFFFF) and with zero extension to i64 we got
// finally 0x00000000FFFFFFFF. However with `i64.load8_s` in this
// situation we got `i64(-1)` (all ones) and with `i64.load8_u` it
// will be 0x00000000000000FF.
//
// Another limitation is atomics which only have unsigned loads.
// So we also avoid this only case:
//
// i64.extend_i32_s(i32.atomic.load(x))

// Special case for i32.load. In this case signedness depends on
// extend operation.
bool willBeSigned = curr->op == ExtendSInt32 && load->bytes == 4;
if (!(curr->op == ExtendUInt32 && load->bytes <= 2 && load->signed_) &&
!(willBeSigned && load->isAtomic)) {
if (willBeSigned) {
load->signed_ = true;
}
load->type = Type::i64;
return replaceCurrent(load);
}
}
}

if (Abstract::hasAnyReinterpret(curr->op)) {
// i32.reinterpret_f32(f32.reinterpret_i32(x)) => x
// i64.reinterpret_f64(f64.reinterpret_i64(x)) => x
Expand Down
44 changes: 44 additions & 0 deletions test/lit/passes/optimize-instructions-atomics.wast
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,48 @@
(drop (f64.reinterpret_i64 (i64.atomic.load (local.get $x)))) ;; skip
(i32.atomic.store (i32.const 8) (i32.reinterpret_f32 (local.get $y))) ;; skip
)

;; CHECK: (func $combine_atomic_load_and_extends (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.atomic.load8_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.atomic.load16_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.atomic.load32_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.atomic.load8_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.atomic.load16_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.extend_i32_s
;; CHECK-NEXT: (i32.atomic.load
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $combine_atomic_load_and_extends (param $x i32)
(drop (i64.extend_i32_u (i32.atomic.load8_u (local.get $x))))
(drop (i64.extend_i32_u (i32.atomic.load16_u (local.get $x))))
(drop (i64.extend_i32_u (i32.atomic.load (local.get $x))))
(drop (i64.extend_i32_s (i32.atomic.load8_u (local.get $x))))
(drop (i64.extend_i32_s (i32.atomic.load16_u (local.get $x))))
;; skips
(drop (i64.extend_i32_s (i32.atomic.load (local.get $x))))
)
)
83 changes: 83 additions & 0 deletions test/lit/passes/optimize-instructions.wast
Original file line number Diff line number Diff line change
Expand Up @@ -13404,4 +13404,87 @@
(drop (f32.reinterpret_i32 (i32.reinterpret_f32 (local.get $z))))
(drop (f64.reinterpret_i64 (i64.reinterpret_f64 (local.get $w))))
)

;; u64(i32.load(_8|_16)(_u|_s)(x)) => i64.load(_8|_16|_32)(_u|_s)(x)
;; except:
;; i64.extend_i32_u(i32.load8_s(x)) and
;; i64.extend_i32_u(i32.load16_s(x))

;; CHECK: (func $combine_load_and_extend_u (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load8_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load16_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load32_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.extend_i32_u
;; CHECK-NEXT: (i32.load8_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.extend_i32_u
;; CHECK-NEXT: (i32.load16_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $combine_load_and_extend_u (param $x i32)
(drop (i64.extend_i32_u (i32.load8_u (local.get $x))))
(drop (i64.extend_i32_u (i32.load16_u (local.get $x))))
(drop (i64.extend_i32_u (i32.load (local.get $x))))

;; skips
(drop (i64.extend_i32_u (i32.load8_s (local.get $x))))
(drop (i64.extend_i32_u (i32.load16_s (local.get $x))))
)

;; i64(i32.load(_8|_16)(_u|_s)(x)) => i64.load(_8|_16|_32)(_u|_s)(x)

;; CHECK: (func $combine_load_and_extend_s (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load8_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load16_u
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load8_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load16_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i64.load32_s
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $combine_load_and_extend_s (param $x i32)
(drop (i64.extend_i32_s (i32.load8_u (local.get $x))))
(drop (i64.extend_i32_s (i32.load16_u (local.get $x))))
(drop (i64.extend_i32_s (i32.load8_s (local.get $x))))
(drop (i64.extend_i32_s (i32.load16_s (local.get $x))))
(drop (i64.extend_i32_s (i32.load (local.get $x))))
)
)