; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f | FileCheck %s --check-prefixes=CHECK,AVX512,AVX512F
; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f,+avx512fp16 | FileCheck %s --check-prefixes=CHECK,AVX512,AVX512FP16
; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512vl | FileCheck %s --check-prefixes=CHECK,AVX512VL,AVX512VLF
; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512vl,+avx512fp16 | FileCheck %s --check-prefixes=CHECK,AVX512VLFP16

define half @test_half(half %x, i32 %exp) nounwind {
; AVX512F-LABEL: test_half:
; AVX512F:       # %bb.0: # %entry
; AVX512F-NEXT:    vcvtsi2ss %edi, %xmm15, %xmm1
; AVX512F-NEXT:    vcvtph2ps %xmm0, %xmm0
; AVX512F-NEXT:    vscalefss %xmm1, %xmm0, %xmm0
; AVX512F-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
; AVX512F-NEXT:    retq
;
; AVX512FP16-LABEL: test_half:
; AVX512FP16:       # %bb.0: # %entry
; AVX512FP16-NEXT:    vcvtsi2sh %edi, %xmm31, %xmm1
; AVX512FP16-NEXT:    vscalefsh %xmm1, %xmm0, %xmm0
; AVX512FP16-NEXT:    retq
;
; AVX512VL-LABEL: test_half:
; AVX512VL:       # %bb.0: # %entry
; AVX512VL-NEXT:    vcvtsi2ss %edi, %xmm15, %xmm1
; AVX512VL-NEXT:    vcvtph2ps %xmm0, %xmm0
; AVX512VL-NEXT:    vscalefss %xmm1, %xmm0, %xmm0
; AVX512VL-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_half:
; AVX512VLFP16:       # %bb.0: # %entry
; AVX512VLFP16-NEXT:    vcvtsi2sh %edi, %xmm31, %xmm1
; AVX512VLFP16-NEXT:    vscalefsh %xmm1, %xmm0, %xmm0
; AVX512VLFP16-NEXT:    retq
entry:
  %r = tail call fast half @llvm.ldexp.f16.i32(half %x, i32 %exp)
  ret half %r
}
declare half @llvm.ldexp.f16.i32(half, i32) memory(none)

define float @test_float(float %x, i32 %exp) nounwind {
; CHECK-LABEL: test_float:
; CHECK:       # %bb.0: # %entry
; CHECK-NEXT:    vcvtsi2ss %edi, %xmm15, %xmm1
; CHECK-NEXT:    vscalefss %xmm1, %xmm0, %xmm0
; CHECK-NEXT:    retq
entry:
  %r = tail call fast float @ldexpf(float %x, i32 %exp)
  ret float %r
}
declare float @ldexpf(float, i32) memory(none)

define double @test_double(double %x, i32 %exp) nounwind {
; CHECK-LABEL: test_double:
; CHECK:       # %bb.0: # %entry
; CHECK-NEXT:    vcvtsi2sd %edi, %xmm15, %xmm1
; CHECK-NEXT:    vscalefsd %xmm1, %xmm0, %xmm0
; CHECK-NEXT:    retq
entry:
  %r = tail call fast double @ldexp(double %x, i32 %exp)
  ret double %r
}
declare double @ldexp(double, i32) memory(none)

define fp128 @testExpl(fp128 %x, i32 %exp) nounwind {
; CHECK-LABEL: testExpl:
; CHECK:       # %bb.0: # %entry
; CHECK-NEXT:    jmp ldexpl@PLT # TAILCALL
entry:
  %r = tail call fast fp128 @ldexpl(fp128 %x, i32 %exp)
  ret fp128 %r
}
declare fp128 @ldexpl(fp128, i32) memory(none)

define <8 x half> @test_ldexp_8xhalf(<8 x half> %x, <8 x i16> %exp) nounwind {
; AVX512F-LABEL: test_ldexp_8xhalf:
; AVX512F:       # %bb.0:
; AVX512F-NEXT:    vpmovsxwd %xmm1, %ymm1
; AVX512F-NEXT:    vcvtph2ps %xmm0, %ymm0
; AVX512F-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512F-NEXT:    vcvtps2ph $4, %ymm0, %xmm0
; AVX512F-NEXT:    vzeroupper
; AVX512F-NEXT:    retq
;
; AVX512FP16-LABEL: test_ldexp_8xhalf:
; AVX512FP16:       # %bb.0:
; AVX512FP16-NEXT:    vxorps %xmm2, %xmm2, %xmm2
; AVX512FP16-NEXT:    vinsertf32x4 $0, %xmm0, %zmm2, %zmm0
; AVX512FP16-NEXT:    vmovaps %xmm1, %xmm1
; AVX512FP16-NEXT:    vscalefph %zmm1, %zmm0, %zmm0
; AVX512FP16-NEXT:    # kill: def $xmm0 killed $xmm0 killed $zmm0
; AVX512FP16-NEXT:    vzeroupper
; AVX512FP16-NEXT:    retq
;
; AVX512VL-LABEL: test_ldexp_8xhalf:
; AVX512VL:       # %bb.0:
; AVX512VL-NEXT:    vpmovsxwd %xmm1, %ymm1
; AVX512VL-NEXT:    vcvtph2ps %xmm0, %ymm0
; AVX512VL-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512VL-NEXT:    vcvtps2ph $4, %ymm0, %xmm0
; AVX512VL-NEXT:    vzeroupper
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_ldexp_8xhalf:
; AVX512VLFP16:       # %bb.0:
; AVX512VLFP16-NEXT:    vcvtw2ph %xmm1, %xmm1
; AVX512VLFP16-NEXT:    vscalefph %xmm1, %xmm0, %xmm0
; AVX512VLFP16-NEXT:    retq
  %r = call <8 x half> @llvm.ldexp.v8f16.v8i16(<8 x half> %x, <8 x i16> %exp)
  ret <8 x half> %r
}
declare <8 x half> @llvm.ldexp.v8f16.v8i16(<8 x half>, <8 x i16>)

define <4 x float> @test_ldexp_4xfloat(<4 x float> %x, <4 x i32> %exp) nounwind {
; AVX512-LABEL: test_ldexp_4xfloat:
; AVX512:       # %bb.0:
; AVX512-NEXT:    vmovaps %xmm1, %xmm1
; AVX512-NEXT:    vmovaps %xmm0, %xmm0
; AVX512-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512-NEXT:    # kill: def $xmm0 killed $xmm0 killed $zmm0
; AVX512-NEXT:    vzeroupper
; AVX512-NEXT:    retq
;
; AVX512VL-LABEL: test_ldexp_4xfloat:
; AVX512VL:       # %bb.0:
; AVX512VL-NEXT:    vcvtdq2ps %xmm1, %xmm1
; AVX512VL-NEXT:    vscalefps %xmm1, %xmm0, %xmm0
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_ldexp_4xfloat:
; AVX512VLFP16:       # %bb.0:
; AVX512VLFP16-NEXT:    vcvtdq2ps %xmm1, %xmm1
; AVX512VLFP16-NEXT:    vscalefps %xmm1, %xmm0, %xmm0
; AVX512VLFP16-NEXT:    retq
  %r = call <4 x float> @llvm.ldexp.v4f32.v4i32(<4 x float> %x, <4 x i32> %exp)
  ret <4 x float> %r
}
declare <4 x float> @llvm.ldexp.v4f32.v4i32(<4 x float>, <4 x i32>)

define <2 x double> @test_ldexp_2xdouble(<2 x double> %x, <2 x i32> %exp) nounwind {
; CHECK-LABEL: test_ldexp_2xdouble:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vcvtdq2pd %xmm1, %xmm2
; CHECK-NEXT:    vscalefsd %xmm2, %xmm0, %xmm2
; CHECK-NEXT:    vshufpd {{.*#+}} xmm0 = xmm0[1,0]
; CHECK-NEXT:    vshufps {{.*#+}} xmm1 = xmm1[1,1,1,1]
; CHECK-NEXT:    vcvtdq2pd %xmm1, %xmm1
; CHECK-NEXT:    vscalefsd %xmm1, %xmm0, %xmm0
; CHECK-NEXT:    vunpcklpd {{.*#+}} xmm0 = xmm2[0],xmm0[0]
; CHECK-NEXT:    retq
  %r = call <2 x double> @llvm.ldexp.v2f64.v2i32(<2 x double> %x, <2 x i32> %exp)
  ret <2 x double> %r
}
declare <2 x double> @llvm.ldexp.v2f64.v2i32(<2 x double>, <2 x i32>)

define <16 x half> @test_ldexp_16xhalf(<16 x half> %x, <16 x i16> %exp) nounwind {
; AVX512F-LABEL: test_ldexp_16xhalf:
; AVX512F:       # %bb.0:
; AVX512F-NEXT:    vpmovsxwd %ymm1, %zmm1
; AVX512F-NEXT:    vcvtph2ps %ymm0, %zmm0
; AVX512F-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512F-NEXT:    vcvtps2ph $4, %zmm0, %ymm0
; AVX512F-NEXT:    retq
;
; AVX512FP16-LABEL: test_ldexp_16xhalf:
; AVX512FP16:       # %bb.0:
; AVX512FP16-NEXT:    vxorps %xmm2, %xmm2, %xmm2
; AVX512FP16-NEXT:    vinsertf64x4 $0, %ymm0, %zmm2, %zmm0
; AVX512FP16-NEXT:    vmovaps %ymm1, %ymm1
; AVX512FP16-NEXT:    vscalefph %zmm1, %zmm0, %zmm0
; AVX512FP16-NEXT:    # kill: def $ymm0 killed $ymm0 killed $zmm0
; AVX512FP16-NEXT:    retq
;
; AVX512VL-LABEL: test_ldexp_16xhalf:
; AVX512VL:       # %bb.0:
; AVX512VL-NEXT:    vpmovsxwd %ymm1, %zmm1
; AVX512VL-NEXT:    vcvtph2ps %ymm0, %zmm0
; AVX512VL-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512VL-NEXT:    vcvtps2ph $4, %zmm0, %ymm0
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_ldexp_16xhalf:
; AVX512VLFP16:       # %bb.0:
; AVX512VLFP16-NEXT:    vcvtw2ph %ymm1, %ymm1
; AVX512VLFP16-NEXT:    vscalefph %ymm1, %ymm0, %ymm0
; AVX512VLFP16-NEXT:    retq
  %r = call <16 x half> @llvm.ldexp.v16f16.v16i16(<16 x half> %x, <16 x i16> %exp)
  ret <16 x half> %r
}
declare <16 x half> @llvm.ldexp.v16f16.v16i16(<16 x half>, <16 x i16>)

define <8 x float> @test_ldexp_8xfloat(<8 x float> %x, <8 x i32> %exp) nounwind {
; AVX512-LABEL: test_ldexp_8xfloat:
; AVX512:       # %bb.0:
; AVX512-NEXT:    vmovaps %ymm1, %ymm1
; AVX512-NEXT:    vmovaps %ymm0, %ymm0
; AVX512-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512-NEXT:    # kill: def $ymm0 killed $ymm0 killed $zmm0
; AVX512-NEXT:    retq
;
; AVX512VL-LABEL: test_ldexp_8xfloat:
; AVX512VL:       # %bb.0:
; AVX512VL-NEXT:    vcvtdq2ps %ymm1, %ymm1
; AVX512VL-NEXT:    vscalefps %ymm1, %ymm0, %ymm0
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_ldexp_8xfloat:
; AVX512VLFP16:       # %bb.0:
; AVX512VLFP16-NEXT:    vcvtdq2ps %ymm1, %ymm1
; AVX512VLFP16-NEXT:    vscalefps %ymm1, %ymm0, %ymm0
; AVX512VLFP16-NEXT:    retq
  %r = call <8 x float> @llvm.ldexp.v8f32.v8i32(<8 x float> %x, <8 x i32> %exp)
  ret <8 x float> %r
}
declare <8 x float> @llvm.ldexp.v8f32.v8i32(<8 x float>, <8 x i32>)

define <4 x double> @test_ldexp_4xdouble(<4 x double> %x, <4 x i32> %exp) nounwind {
; AVX512-LABEL: test_ldexp_4xdouble:
; AVX512:       # %bb.0:
; AVX512-NEXT:    vmovapd %xmm1, %xmm1
; AVX512-NEXT:    vmovapd %ymm0, %ymm0
; AVX512-NEXT:    vscalefpd %zmm1, %zmm0, %zmm0
; AVX512-NEXT:    # kill: def $ymm0 killed $ymm0 killed $zmm0
; AVX512-NEXT:    retq
;
; AVX512VL-LABEL: test_ldexp_4xdouble:
; AVX512VL:       # %bb.0:
; AVX512VL-NEXT:    vcvtdq2pd %xmm1, %ymm1
; AVX512VL-NEXT:    vscalefpd %ymm1, %ymm0, %ymm0
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_ldexp_4xdouble:
; AVX512VLFP16:       # %bb.0:
; AVX512VLFP16-NEXT:    vcvtdq2pd %xmm1, %ymm1
; AVX512VLFP16-NEXT:    vscalefpd %ymm1, %ymm0, %ymm0
; AVX512VLFP16-NEXT:    retq
  %r = call <4 x double> @llvm.ldexp.v4f64.v4i32(<4 x double> %x, <4 x i32> %exp)
  ret <4 x double> %r
}
declare <4 x double> @llvm.ldexp.v4f64.v4i32(<4 x double>, <4 x i32>)

define <32 x half> @test_ldexp_32xhalf(<32 x half> %x, <32 x i16> %exp) nounwind {
; AVX512F-LABEL: test_ldexp_32xhalf:
; AVX512F:       # %bb.0:
; AVX512F-NEXT:    vpmovsxwd %ymm1, %zmm2
; AVX512F-NEXT:    vcvtph2ps %ymm0, %zmm3
; AVX512F-NEXT:    vscalefps %zmm2, %zmm3, %zmm2
; AVX512F-NEXT:    vcvtps2ph $4, %zmm2, %ymm2
; AVX512F-NEXT:    vextracti64x4 $1, %zmm1, %ymm1
; AVX512F-NEXT:    vpmovsxwd %ymm1, %zmm1
; AVX512F-NEXT:    vextractf64x4 $1, %zmm0, %ymm0
; AVX512F-NEXT:    vcvtph2ps %ymm0, %zmm0
; AVX512F-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512F-NEXT:    vcvtps2ph $4, %zmm0, %ymm0
; AVX512F-NEXT:    vinsertf64x4 $1, %ymm0, %zmm2, %zmm0
; AVX512F-NEXT:    retq
;
; AVX512FP16-LABEL: test_ldexp_32xhalf:
; AVX512FP16:       # %bb.0:
; AVX512FP16-NEXT:    vcvtw2ph %zmm1, %zmm1
; AVX512FP16-NEXT:    vscalefph %zmm1, %zmm0, %zmm0
; AVX512FP16-NEXT:    retq
;
; AVX512VL-LABEL: test_ldexp_32xhalf:
; AVX512VL:       # %bb.0:
; AVX512VL-NEXT:    vpmovsxwd %ymm1, %zmm2
; AVX512VL-NEXT:    vcvtph2ps %ymm0, %zmm3
; AVX512VL-NEXT:    vscalefps %zmm2, %zmm3, %zmm2
; AVX512VL-NEXT:    vcvtps2ph $4, %zmm2, %ymm2
; AVX512VL-NEXT:    vextracti64x4 $1, %zmm1, %ymm1
; AVX512VL-NEXT:    vpmovsxwd %ymm1, %zmm1
; AVX512VL-NEXT:    vextractf64x4 $1, %zmm0, %ymm0
; AVX512VL-NEXT:    vcvtph2ps %ymm0, %zmm0
; AVX512VL-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; AVX512VL-NEXT:    vcvtps2ph $4, %zmm0, %ymm0
; AVX512VL-NEXT:    vinsertf64x4 $1, %ymm0, %zmm2, %zmm0
; AVX512VL-NEXT:    retq
;
; AVX512VLFP16-LABEL: test_ldexp_32xhalf:
; AVX512VLFP16:       # %bb.0:
; AVX512VLFP16-NEXT:    vcvtw2ph %zmm1, %zmm1
; AVX512VLFP16-NEXT:    vscalefph %zmm1, %zmm0, %zmm0
; AVX512VLFP16-NEXT:    retq
  %r = call <32 x half> @llvm.ldexp.v32f16.v32i16(<32 x half> %x, <32 x i16> %exp)
  ret <32 x half> %r
}
declare <32 x half> @llvm.ldexp.v32f16.v32i16(<32 x half>, <32 x i16>)

define <16 x float> @test_ldexp_16xfloat(<16 x float> %x, <16 x i32> %exp) nounwind {
; CHECK-LABEL: test_ldexp_16xfloat:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vcvtdq2ps %zmm1, %zmm1
; CHECK-NEXT:    vscalefps %zmm1, %zmm0, %zmm0
; CHECK-NEXT:    retq
  %r = call <16 x float> @llvm.ldexp.v16f32.v16i32(<16 x float> %x, <16 x i32> %exp)
  ret <16 x float> %r
}
declare <16 x float> @llvm.ldexp.v16f32.v16i32(<16 x float>, <16 x i32>)

define <8 x double> @test_ldexp_8xdouble(<8 x double> %x, <8 x i32> %exp) nounwind {
; CHECK-LABEL: test_ldexp_8xdouble:
; CHECK:       # %bb.0:
; CHECK-NEXT:    vcvtdq2pd %ymm1, %zmm1
; CHECK-NEXT:    vscalefpd %zmm1, %zmm0, %zmm0
; CHECK-NEXT:    retq
  %r = call <8 x double> @llvm.ldexp.v8f64.v8i32(<8 x double> %x, <8 x i32> %exp)
  ret <8 x double> %r
}
declare <8 x double> @llvm.ldexp.v8f64.v8i32(<8 x double>, <8 x i32>)

;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; AVX512VLF: {{.*}}
