This commit implements the [wide-arithmetic] proposal which has recently reached phase 2 in the WebAssembly proposals process. The goal here is to implement support in LLVM for emitting these instructions which are gated behind a new feature flag by default. A new `wide-arithmetic` feature flag is introduced which gates these four new instructions from being emitted. Emission of each instruction itself is relatively simple given LLVM's preexisting lowering rules and infrastructure. The main gotcha is that due to the multi-result nature of all of these instructions it needed the lowerings to be implemented in C++ rather than in TableGen. [wide-arithmetic]: https://github.com/WebAssembly/wide-arithmetic
133 lines
3.7 KiB
LLVM
133 lines
3.7 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
|
|
; RUN: llc -mattr=+wide-arithmetic < %s | FileCheck %s
|
|
|
|
target triple = "wasm32-unknown-unknown"
|
|
|
|
define i128 @add_i128(i128 %a, i128 %b) {
|
|
; CHECK-LABEL: add_i128:
|
|
; CHECK: .functype add_i128 (i32, i64, i64, i64, i64) -> ()
|
|
; CHECK-NEXT: # %bb.0:
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: local.get 3
|
|
; CHECK-NEXT: local.get 4
|
|
; CHECK-NEXT: i64.add128
|
|
; CHECK-NEXT: local.set 3
|
|
; CHECK-NEXT: local.set 4
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 3
|
|
; CHECK-NEXT: i64.store 8
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 4
|
|
; CHECK-NEXT: i64.store 0
|
|
; CHECK-NEXT: # fallthrough-return
|
|
%c = add i128 %a, %b
|
|
ret i128 %c
|
|
}
|
|
|
|
define i128 @sub_i128(i128 %a, i128 %b) {
|
|
; CHECK-LABEL: sub_i128:
|
|
; CHECK: .functype sub_i128 (i32, i64, i64, i64, i64) -> ()
|
|
; CHECK-NEXT: # %bb.0:
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: local.get 3
|
|
; CHECK-NEXT: local.get 4
|
|
; CHECK-NEXT: i64.sub128
|
|
; CHECK-NEXT: local.set 3
|
|
; CHECK-NEXT: local.set 4
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 3
|
|
; CHECK-NEXT: i64.store 8
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 4
|
|
; CHECK-NEXT: i64.store 0
|
|
; CHECK-NEXT: # fallthrough-return
|
|
%c = sub i128 %a, %b
|
|
ret i128 %c
|
|
}
|
|
|
|
define i128 @mul_i128(i128 %a, i128 %b) {
|
|
; CHECK-LABEL: mul_i128:
|
|
; CHECK: .functype mul_i128 (i32, i64, i64, i64, i64) -> ()
|
|
; CHECK-NEXT: .local i64
|
|
; CHECK-NEXT: # %bb.0:
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: local.get 3
|
|
; CHECK-NEXT: i64.mul_wide_u
|
|
; CHECK-NEXT: local.set 5
|
|
; CHECK-NEXT: i64.store 0
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 5
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: local.get 4
|
|
; CHECK-NEXT: i64.mul
|
|
; CHECK-NEXT: i64.add
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: local.get 3
|
|
; CHECK-NEXT: i64.mul
|
|
; CHECK-NEXT: i64.add
|
|
; CHECK-NEXT: i64.store 8
|
|
; CHECK-NEXT: # fallthrough-return
|
|
%c = mul i128 %a, %b
|
|
ret i128 %c
|
|
}
|
|
|
|
define i128 @i64_mul_wide_s(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: i64_mul_wide_s:
|
|
; CHECK: .functype i64_mul_wide_s (i32, i64, i64) -> ()
|
|
; CHECK-NEXT: # %bb.0:
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: i64.mul_wide_s
|
|
; CHECK-NEXT: local.set 1
|
|
; CHECK-NEXT: local.set 2
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: i64.store 8
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: i64.store 0
|
|
; CHECK-NEXT: # fallthrough-return
|
|
%a128 = sext i64 %a to i128
|
|
%b128 = sext i64 %b to i128
|
|
%c = mul i128 %a128, %b128
|
|
ret i128 %c
|
|
}
|
|
|
|
define i128 @i64_mul_wide_u(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: i64_mul_wide_u:
|
|
; CHECK: .functype i64_mul_wide_u (i32, i64, i64) -> ()
|
|
; CHECK-NEXT: # %bb.0:
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: i64.mul_wide_u
|
|
; CHECK-NEXT: local.set 1
|
|
; CHECK-NEXT: local.set 2
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: i64.store 8
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: i64.store 0
|
|
; CHECK-NEXT: # fallthrough-return
|
|
%a128 = zext i64 %a to i128
|
|
%b128 = zext i64 %b to i128
|
|
%c = mul i128 %a128, %b128
|
|
ret i128 %c
|
|
}
|
|
|
|
define i64 @mul_i128_only_lo(i128 %a, i128 %b) {
|
|
; CHECK-LABEL: mul_i128_only_lo:
|
|
; CHECK: .functype mul_i128_only_lo (i64, i64, i64, i64) -> (i64)
|
|
; CHECK-NEXT: # %bb.0:
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 2
|
|
; CHECK-NEXT: i64.mul
|
|
; CHECK-NEXT: # fallthrough-return
|
|
%c = mul i128 %a, %b
|
|
%d = trunc i128 %c to i64
|
|
ret i64 %d
|
|
}
|