[WebAssembly] Optimize convert_iKxN_u into convert_iKxN_s (#149609)
convert_iKxN_s is canonicalized into convert_iKxN_u when the argument is known to have sign bit 0. This results in emitting Wasm opcodes that, on some targets (like x86_64), are dramatically slower than signed versions on major engines. Similarly to X86, we now fix this up in isel when the instruction has nonneg flag from canonicalization or if we know the source has zero sign bit. Fixes #149457.
This commit is contained in:
parent
8366dc207a
commit
5b98992fb9
3 changed files with 55 additions and 5 deletions
|
|
@ -2938,6 +2938,25 @@ performVectorExtendToFPCombine(SDNode *N,
|
|||
return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv);
|
||||
}
|
||||
|
||||
static SDValue
|
||||
performVectorNonNegToFPCombine(SDNode *N,
|
||||
TargetLowering::DAGCombinerInfo &DCI) {
|
||||
auto &DAG = DCI.DAG;
|
||||
|
||||
SDNodeFlags Flags = N->getFlags();
|
||||
SDValue Op0 = N->getOperand(0);
|
||||
EVT VT = N->getValueType(0);
|
||||
|
||||
// Optimize uitofp to sitofp when the sign bit is known to be zero.
|
||||
// Depending on the target (runtime) backend, this might be performance
|
||||
// neutral (e.g. AArch64) or a significant improvement (e.g. x86_64).
|
||||
if (VT.isVector() && (Flags.hasNonNeg() || DAG.SignBitIsZero(Op0))) {
|
||||
return DAG.getNode(ISD::SINT_TO_FP, SDLoc(N), VT, Op0);
|
||||
}
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
static SDValue
|
||||
performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
|
||||
auto &DAG = DCI.DAG;
|
||||
|
|
@ -3519,6 +3538,9 @@ WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
|
|||
case ISD::ZERO_EXTEND:
|
||||
return performVectorExtendCombine(N, DCI);
|
||||
case ISD::UINT_TO_FP:
|
||||
if (auto ExtCombine = performVectorExtendToFPCombine(N, DCI))
|
||||
return ExtCombine;
|
||||
return performVectorNonNegToFPCombine(N, DCI);
|
||||
case ISD::SINT_TO_FP:
|
||||
return performVectorExtendToFPCombine(N, DCI);
|
||||
case ISD::FP_TO_SINT_SAT:
|
||||
|
|
|
|||
|
|
@ -441,3 +441,31 @@ define <2 x double> @promote_mixed_v2f64(<4 x float> %x, <4 x float> %y) {
|
|||
%a = fpext <2 x float> %v to <2 x double>
|
||||
ret <2 x double> %a
|
||||
}
|
||||
|
||||
define <4 x float> @convert_u_v4f32_maybeneg(<4 x i32> %x) {
|
||||
; CHECK-LABEL: convert_u_v4f32_maybeneg:
|
||||
; CHECK: .functype convert_u_v4f32_maybeneg (v128) -> (v128)
|
||||
; CHECK-NEXT: # %bb.0:
|
||||
; CHECK-NEXT: local.get 0
|
||||
; CHECK-NEXT: i32.const 1
|
||||
; CHECK-NEXT: i32x4.shr_s
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_u
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%a = ashr <4 x i32> %x, <i32 1, i32 1, i32 1, i32 1>
|
||||
%b = uitofp <4 x i32> %a to <4 x float>
|
||||
ret <4 x float> %b
|
||||
}
|
||||
|
||||
define <4 x float> @convert_u_v4f32_nonneg(<4 x i32> %x) {
|
||||
; CHECK-LABEL: convert_u_v4f32_nonneg:
|
||||
; CHECK: .functype convert_u_v4f32_nonneg (v128) -> (v128)
|
||||
; CHECK-NEXT: # %bb.0:
|
||||
; CHECK-NEXT: local.get 0
|
||||
; CHECK-NEXT: i32.const 1
|
||||
; CHECK-NEXT: i32x4.shr_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_s
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%a = lshr <4 x i32> %x, <i32 1, i32 1, i32 1, i32 1>
|
||||
%b = uitofp <4 x i32> %a to <4 x float>
|
||||
ret <4 x float> %b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ define <4 x float> @extend_to_float_low_i16x8_u(<8 x i16> %x) {
|
|||
; CHECK-NEXT: # %bb.0:
|
||||
; CHECK-NEXT: local.get 0
|
||||
; CHECK-NEXT: i32x4.extend_low_i16x8_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_s
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%low = shufflevector <8 x i16> %x, <8 x i16> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%extended = uitofp <4 x i16> %low to <4 x float>
|
||||
|
|
@ -25,7 +25,7 @@ define <4 x float> @extend_to_float_high_i16x8_u(<8 x i16> %x) {
|
|||
; CHECK-NEXT: # %bb.0:
|
||||
; CHECK-NEXT: local.get 0
|
||||
; CHECK-NEXT: i32x4.extend_high_i16x8_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_s
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%high = shufflevector <8 x i16> %x, <8 x i16> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
|
||||
%extended = uitofp <4 x i16> %high to <4 x float>
|
||||
|
|
@ -39,7 +39,7 @@ define <4 x float> @extend_to_float_low_i8x16_u(<8 x i8> %x) {
|
|||
; CHECK-NEXT: local.get 0
|
||||
; CHECK-NEXT: i16x8.extend_low_i8x16_u
|
||||
; CHECK-NEXT: i32x4.extend_low_i16x8_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_s
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%low = shufflevector <8 x i8> %x, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%extended = uitofp <4 x i8> %low to <4 x float>
|
||||
|
|
@ -55,7 +55,7 @@ define <4 x float> @extend_to_float_high_i8x16_u(<8 x i8> %x) {
|
|||
; CHECK-NEXT: i8x16.shuffle 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
; CHECK-NEXT: i16x8.extend_low_i8x16_u
|
||||
; CHECK-NEXT: i32x4.extend_low_i16x8_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_u
|
||||
; CHECK-NEXT: f32x4.convert_i32x4_s
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%high = shufflevector <8 x i8> %x, <8 x i8> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
|
||||
%extended = uitofp <4 x i8> %high to <4 x float>
|
||||
|
|
@ -136,7 +136,7 @@ define <2 x double> @extend_to_double_low_i16x4_u(<4 x i16> %x) {
|
|||
; CHECK-NEXT: # %bb.0:
|
||||
; CHECK-NEXT: local.get 0
|
||||
; CHECK-NEXT: i32x4.extend_low_i16x8_u
|
||||
; CHECK-NEXT: f64x2.convert_low_i32x4_u
|
||||
; CHECK-NEXT: f64x2.convert_low_i32x4_s
|
||||
; CHECK-NEXT: # fallthrough-return
|
||||
%low = shufflevector <4 x i16> %x, <4 x i16> undef, <2 x i32> <i32 0, i32 1>
|
||||
%extended = uitofp <2 x i16> %low to <2 x double>
|
||||
|
|
|
|||
Loading…
Reference in a new issue