llvm/llvm/test/CodeGen/X86/llvm.frexp.ll

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck -check-prefixes=X64 %s
; RUN: llc -mtriple=i386-pc-win32 < %s | FileCheck -check-prefix=WIN32 %s

define { half, i32 } @test_frexp_f16_i32(half %a) {
; X64-LABEL: test_frexp_f16_i32:
; X64:       # %bb.0:
; X64-NEXT:    subq $24, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 32
; X64-NEXT:    movaps %xmm0, (%rsp) # 16-byte Spill
; X64-NEXT:    callq __extendhfsf2@PLT
; X64-NEXT:    mulss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
; X64-NEXT:    callq __truncsfhf2@PLT
; X64-NEXT:    pextrw $0, %xmm0, %ecx
; X64-NEXT:    movl %ecx, %eax
; X64-NEXT:    andl $31744, %eax # imm = 0x7C00
; X64-NEXT:    movdqa (%rsp), %xmm0 # 16-byte Reload
; X64-NEXT:    pextrw $0, %xmm0, %edx
; X64-NEXT:    movl %edx, %esi
; X64-NEXT:    andl $32767, %esi # imm = 0x7FFF
; X64-NEXT:    cmpl $1024, %esi # imm = 0x400
; X64-NEXT:    cmovael %edx, %ecx
; X64-NEXT:    cmovael %esi, %eax
; X64-NEXT:    shrl $10, %eax
; X64-NEXT:    leal -12(%rax), %edi
; X64-NEXT:    cmpl $1024, %esi # imm = 0x400
; X64-NEXT:    cmovael %eax, %edi
; X64-NEXT:    addl $-14, %edi
; X64-NEXT:    andl $-31745, %ecx # imm = 0x83FF
; X64-NEXT:    orl $14336, %ecx # imm = 0x3800
; X64-NEXT:    addl $-31744, %esi # imm = 0x8400
; X64-NEXT:    movzwl %si, %esi
; X64-NEXT:    xorl %eax, %eax
; X64-NEXT:    cmpl $33792, %esi # imm = 0x8400
; X64-NEXT:    cmoval %edi, %eax
; X64-NEXT:    cmovbel %edx, %ecx
; X64-NEXT:    pinsrw $0, %ecx, %xmm0
; X64-NEXT:    addq $24, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f16_i32:
; WIN32:       # %bb.0:
; WIN32-NEXT:    pushl %esi
; WIN32-NEXT:    subl $20, %esp
; WIN32-NEXT:    movzwl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, (%esp)
; WIN32-NEXT:    calll ___gnu_h2f_ieee
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstps (%esp)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %esi
; WIN32-NEXT:    calll ___gnu_f2h_ieee
; WIN32-NEXT:    movl %esi, %edx
; WIN32-NEXT:    addl $20, %esp
; WIN32-NEXT:    popl %esi
; WIN32-NEXT:    retl
  %result = call { half, i32 } @llvm.frexp.f16.i32(half %a)
  ret { half, i32 } %result
}

define half @test_frexp_f16_i32_only_use_fract(half %a) {
; X64-LABEL: test_frexp_f16_i32_only_use_fract:
; X64:       # %bb.0:
; X64-NEXT:    subq $24, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 32
; X64-NEXT:    movaps %xmm0, (%rsp) # 16-byte Spill
; X64-NEXT:    callq __extendhfsf2@PLT
; X64-NEXT:    mulss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
; X64-NEXT:    callq __truncsfhf2@PLT
; X64-NEXT:    pextrw $0, %xmm0, %eax
; X64-NEXT:    movdqa (%rsp), %xmm0 # 16-byte Reload
; X64-NEXT:    pextrw $0, %xmm0, %ecx
; X64-NEXT:    movl %ecx, %edx
; X64-NEXT:    andl $32767, %edx # imm = 0x7FFF
; X64-NEXT:    cmpl $1024, %edx # imm = 0x400
; X64-NEXT:    cmovael %ecx, %eax
; X64-NEXT:    andl $-31745, %eax # imm = 0x83FF
; X64-NEXT:    orl $14336, %eax # imm = 0x3800
; X64-NEXT:    addl $-31744, %edx # imm = 0x8400
; X64-NEXT:    movzwl %dx, %edx
; X64-NEXT:    cmpl $33792, %edx # imm = 0x8400
; X64-NEXT:    cmovbel %ecx, %eax
; X64-NEXT:    pinsrw $0, %eax, %xmm0
; X64-NEXT:    addq $24, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f16_i32_only_use_fract:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $20, %esp
; WIN32-NEXT:    movzwl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, (%esp)
; WIN32-NEXT:    calll ___gnu_h2f_ieee
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstps (%esp)
; WIN32-NEXT:    calll ___gnu_f2h_ieee
; WIN32-NEXT:    addl $20, %esp
; WIN32-NEXT:    retl
  %result = call { half, i32 } @llvm.frexp.f16.i32(half %a)
  %result.0 = extractvalue { half, i32 } %result, 0
  ret half %result.0
}

define i32 @test_frexp_f16_i32_only_use_exp(half %a) {
; X64-LABEL: test_frexp_f16_i32_only_use_exp:
; X64:       # %bb.0:
; X64-NEXT:    subq $24, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 32
; X64-NEXT:    movaps %xmm0, (%rsp) # 16-byte Spill
; X64-NEXT:    callq __extendhfsf2@PLT
; X64-NEXT:    mulss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
; X64-NEXT:    callq __truncsfhf2@PLT
; X64-NEXT:    pextrw $0, %xmm0, %eax
; X64-NEXT:    andl $31744, %eax # imm = 0x7C00
; X64-NEXT:    movdqa (%rsp), %xmm0 # 16-byte Reload
; X64-NEXT:    pextrw $0, %xmm0, %ecx
; X64-NEXT:    andl $32767, %ecx # imm = 0x7FFF
; X64-NEXT:    cmpl $1024, %ecx # imm = 0x400
; X64-NEXT:    cmovael %ecx, %eax
; X64-NEXT:    shrl $10, %eax
; X64-NEXT:    leal -12(%rax), %edx
; X64-NEXT:    cmpl $1024, %ecx # imm = 0x400
; X64-NEXT:    cmovael %eax, %edx
; X64-NEXT:    addl $-14, %edx
; X64-NEXT:    addl $-31744, %ecx # imm = 0x8400
; X64-NEXT:    movzwl %cx, %ecx
; X64-NEXT:    xorl %eax, %eax
; X64-NEXT:    cmpl $33792, %ecx # imm = 0x8400
; X64-NEXT:    cmoval %edx, %eax
; X64-NEXT:    addq $24, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f16_i32_only_use_exp:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $16, %esp
; WIN32-NEXT:    movzwl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, (%esp)
; WIN32-NEXT:    calll ___gnu_h2f_ieee
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    addl $16, %esp
; WIN32-NEXT:    retl
  %result = call { half, i32 } @llvm.frexp.f16.i32(half %a)
  %result.0 = extractvalue { half, i32 } %result, 1
  ret i32 %result.0
}

; FIXME
; define { <2 x half>, <2 x i32> } @test_frexp_v2f16_v2i32(<2 x half> %a) {
;   %result = call { <2 x half>, <2 x i32> } @llvm.frexp.v2f16.v2i32(<2 x half> %a)
;   ret { <2 x half>, <2 x i32> } %result
; }

; define <2 x half> @test_frexp_v2f16_v2i32_only_use_fract(<2 x half> %a) {
;   %result = call { <2 x half>, <2 x i32> } @llvm.frexp.v2f16.v2i32(<2 x half> %a)
;   %result.0 = extractvalue { <2 x half>, <2 x i32> } %result, 0
;   ret <2 x half> %result.0
; }

; define <2 x i32> @test_frexp_v2f16_v2i32_only_use_exp(<2 x half> %a) {
;   %result = call { <2 x half>, <2 x i32> } @llvm.frexp.v2f16.v2i32(<2 x half> %a)
;   %result.1 = extractvalue { <2 x half>, <2 x i32> } %result, 1
;   ret <2 x i32> %result.1
; }

define { float, i32 } @test_frexp_f32_i32(float %a) {
; X64-LABEL: test_frexp_f32_i32:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rax
; X64-NEXT:    .cfi_def_cfa_offset 16
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movl {{[0-9]+}}(%rsp), %eax
; X64-NEXT:    popq %rcx
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f32_i32:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $20, %esp
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    addl $20, %esp
; WIN32-NEXT:    retl
  %result = call { float, i32 } @llvm.frexp.f32.i32(float %a)
  ret { float, i32 } %result
}

define float @test_frexp_f32_i32_only_use_fract(float %a) {
; X64-LABEL: test_frexp_f32_i32_only_use_fract:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rax
; X64-NEXT:    .cfi_def_cfa_offset 16
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    popq %rax
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f32_i32_only_use_fract:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $20, %esp
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    addl $20, %esp
; WIN32-NEXT:    retl
  %result = call { float, i32 } @llvm.frexp.f32.i32(float %a)
  %result.0 = extractvalue { float, i32 } %result, 0
  ret float %result.0
}

define i32 @test_frexp_f32_i32_only_use_exp(float %a) {
; X64-LABEL: test_frexp_f32_i32_only_use_exp:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rax
; X64-NEXT:    .cfi_def_cfa_offset 16
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movl {{[0-9]+}}(%rsp), %eax
; X64-NEXT:    popq %rcx
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f32_i32_only_use_exp:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $16, %esp
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    addl $16, %esp
; WIN32-NEXT:    retl
  %result = call { float, i32 } @llvm.frexp.f32.i32(float %a)
  %result.0 = extractvalue { float, i32 } %result, 1
  ret i32 %result.0
}

; FIXME: Widen vector result
; define { <2 x float>, <2 x i32> } @test_frexp_v2f32_v2i32(<2 x float> %a) {
;   %result = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %a)
;   ret { <2 x float>, <2 x i32> } %result
; }

; define <2 x float> @test_frexp_v2f32_v2i32_only_use_fract(<2 x float> %a) {
;   %result = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %a)
;   %result.0 = extractvalue { <2 x float>, <2 x i32> } %result, 0
;   ret <2 x float> %result.0
; }

; define <2 x i32> @test_frexp_v2f32_v2i32_only_use_exp(<2 x float> %a) {
;   %result = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %a)
;   %result.1 = extractvalue { <2 x float>, <2 x i32> } %result, 1
;   ret <2 x i32> %result.1
; }

define { <4 x float>, <4 x i32> } @test_frexp_v4f32_v4i32(<4 x float> %a) {
; X64-LABEL: test_frexp_v4f32_v4i32:
; X64:       # %bb.0:
; X64-NEXT:    subq $72, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 80
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[3,3,3,3]
; X64-NEXT:    movq %rsp, %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    movhlps {{.*#+}} xmm0 = xmm0[1,1]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    unpcklps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Folded Reload
; X64-NEXT:    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[1,1,1,1]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Reload
; X64-NEXT:    unpcklps {{.*#+}} xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
; X64-NEXT:    unpcklpd {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Folded Reload
; X64-NEXT:    # xmm1 = xmm1[0],mem[0]
; X64-NEXT:    movaps %xmm1, %xmm0
; X64-NEXT:    movss {{.*#+}} xmm1 = mem[0],zero,zero,zero
; X64-NEXT:    movss {{.*#+}} xmm2 = mem[0],zero,zero,zero
; X64-NEXT:    unpcklps {{.*#+}} xmm2 = xmm2[0],xmm1[0],xmm2[1],xmm1[1]
; X64-NEXT:    movss {{.*#+}} xmm1 = mem[0],zero,zero,zero
; X64-NEXT:    movss {{.*#+}} xmm3 = mem[0],zero,zero,zero
; X64-NEXT:    unpcklps {{.*#+}} xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
; X64-NEXT:    movlhps {{.*#+}} xmm1 = xmm1[0],xmm2[0]
; X64-NEXT:    addq $72, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_v4f32_v4i32:
; WIN32:       # %bb.0:
; WIN32-NEXT:    pushl %edi
; WIN32-NEXT:    pushl %esi
; WIN32-NEXT:    subl $60, %esp
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %esi
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstpl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Spill
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstpl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Spill
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    fldl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Reload
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    fldl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Reload
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edx
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edi
; WIN32-NEXT:    movl %edi, 28(%esi)
; WIN32-NEXT:    movl %edx, 24(%esi)
; WIN32-NEXT:    movl %ecx, 20(%esi)
; WIN32-NEXT:    movl %eax, 16(%esi)
; WIN32-NEXT:    fstps 12(%esi)
; WIN32-NEXT:    fstps 8(%esi)
; WIN32-NEXT:    fstps 4(%esi)
; WIN32-NEXT:    fstps (%esi)
; WIN32-NEXT:    movl %esi, %eax
; WIN32-NEXT:    addl $60, %esp
; WIN32-NEXT:    popl %esi
; WIN32-NEXT:    popl %edi
; WIN32-NEXT:    retl
  %result = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> %a)
  ret { <4 x float>, <4 x i32> } %result
}

define <4 x float> @test_frexp_v4f32_v4i32_only_use_fract(<4 x float> %a) {
; X64-LABEL: test_frexp_v4f32_v4i32_only_use_fract:
; X64:       # %bb.0:
; X64-NEXT:    subq $72, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 80
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[3,3,3,3]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps %xmm0, (%rsp) # 16-byte Spill
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    movhlps {{.*#+}} xmm0 = xmm0[1,1]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    unpcklps (%rsp), %xmm0 # 16-byte Folded Reload
; X64-NEXT:    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
; X64-NEXT:    movaps %xmm0, (%rsp) # 16-byte Spill
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[1,1,1,1]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Reload
; X64-NEXT:    unpcklps {{.*#+}} xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
; X64-NEXT:    unpcklpd (%rsp), %xmm1 # 16-byte Folded Reload
; X64-NEXT:    # xmm1 = xmm1[0],mem[0]
; X64-NEXT:    movaps %xmm1, %xmm0
; X64-NEXT:    addq $72, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_v4f32_v4i32_only_use_fract:
; WIN32:       # %bb.0:
; WIN32-NEXT:    pushl %esi
; WIN32-NEXT:    subl $60, %esp
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %esi
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstpl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Spill
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstpl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Spill
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    fldl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Reload
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    fldl {{[-0-9]+}}(%e{{[sb]}}p) # 8-byte Folded Reload
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstps {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstps 12(%esi)
; WIN32-NEXT:    fstps 8(%esi)
; WIN32-NEXT:    fstps 4(%esi)
; WIN32-NEXT:    fstps (%esi)
; WIN32-NEXT:    movl %esi, %eax
; WIN32-NEXT:    addl $60, %esp
; WIN32-NEXT:    popl %esi
; WIN32-NEXT:    retl
  %result = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> %a)
  %result.0 = extractvalue { <4 x float>, <4 x i32> } %result, 0
  ret <4 x float> %result.0
}

define <4 x i32> @test_frexp_v4f32_v4i32_only_use_exp(<4 x float> %a) {
; X64-LABEL: test_frexp_v4f32_v4i32_only_use_exp:
; X64:       # %bb.0:
; X64-NEXT:    subq $40, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 48
; X64-NEXT:    movaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[3,3,3,3]
; X64-NEXT:    movq %rsp, %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    movhlps {{.*#+}} xmm0 = xmm0[1,1]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[1,1,1,1]
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexpf@PLT
; X64-NEXT:    movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
; X64-NEXT:    movss {{.*#+}} xmm1 = mem[0],zero,zero,zero
; X64-NEXT:    unpcklps {{.*#+}} xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
; X64-NEXT:    movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
; X64-NEXT:    movss {{.*#+}} xmm2 = mem[0],zero,zero,zero
; X64-NEXT:    unpcklps {{.*#+}} xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
; X64-NEXT:    movlhps {{.*#+}} xmm0 = xmm0[0],xmm1[0]
; X64-NEXT:    addq $40, %rsp
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_v4f32_v4i32_only_use_exp:
; WIN32:       # %bb.0:
; WIN32-NEXT:    pushl %edi
; WIN32-NEXT:    pushl %esi
; WIN32-NEXT:    subl $28, %esp
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %esi
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    flds {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edx
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %edi
; WIN32-NEXT:    movl %edi, 12(%esi)
; WIN32-NEXT:    movl %edx, 8(%esi)
; WIN32-NEXT:    movl %ecx, 4(%esi)
; WIN32-NEXT:    movl %eax, (%esi)
; WIN32-NEXT:    movl %esi, %eax
; WIN32-NEXT:    addl $28, %esp
; WIN32-NEXT:    popl %esi
; WIN32-NEXT:    popl %edi
; WIN32-NEXT:    retl
  %result = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> %a)
  %result.1 = extractvalue { <4 x float>, <4 x i32> } %result, 1
  ret <4 x i32> %result.1
}

define { double, i32 } @test_frexp_f64_i32(double %a) {
; X64-LABEL: test_frexp_f64_i32:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rax
; X64-NEXT:    .cfi_def_cfa_offset 16
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexp@PLT
; X64-NEXT:    movl {{[0-9]+}}(%rsp), %eax
; X64-NEXT:    popq %rcx
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f64_i32:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $16, %esp
; WIN32-NEXT:    fldl {{[0-9]+}}(%esp)
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    addl $16, %esp
; WIN32-NEXT:    retl
  %result = call { double, i32 } @llvm.frexp.f64.i32(double %a)
  ret { double, i32 } %result
}

define double @test_frexp_f64_i32_only_use_fract(double %a) {
; X64-LABEL: test_frexp_f64_i32_only_use_fract:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rax
; X64-NEXT:    .cfi_def_cfa_offset 16
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexp@PLT
; X64-NEXT:    popq %rax
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f64_i32_only_use_fract:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $16, %esp
; WIN32-NEXT:    fldl {{[0-9]+}}(%esp)
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    addl $16, %esp
; WIN32-NEXT:    retl
  %result = call { double, i32 } @llvm.frexp.f64.i32(double %a)
  %result.0 = extractvalue { double, i32 } %result, 0
  ret double %result.0
}

define i32 @test_frexp_f64_i32_only_use_exp(double %a) {
; X64-LABEL: test_frexp_f64_i32_only_use_exp:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rax
; X64-NEXT:    .cfi_def_cfa_offset 16
; X64-NEXT:    leaq {{[0-9]+}}(%rsp), %rdi
; X64-NEXT:    callq frexp@PLT
; X64-NEXT:    movl {{[0-9]+}}(%rsp), %eax
; X64-NEXT:    popq %rcx
; X64-NEXT:    .cfi_def_cfa_offset 8
; X64-NEXT:    retq
;
; WIN32-LABEL: test_frexp_f64_i32_only_use_exp:
; WIN32:       # %bb.0:
; WIN32-NEXT:    subl $16, %esp
; WIN32-NEXT:    fldl {{[0-9]+}}(%esp)
; WIN32-NEXT:    leal {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    movl %eax, {{[0-9]+}}(%esp)
; WIN32-NEXT:    fstpl (%esp)
; WIN32-NEXT:    calll _frexp
; WIN32-NEXT:    fstp %st(0)
; WIN32-NEXT:    movl {{[0-9]+}}(%esp), %eax
; WIN32-NEXT:    addl $16, %esp
; WIN32-NEXT:    retl
  %result = call { double, i32 } @llvm.frexp.f64.i32(double %a)
  %result.0 = extractvalue { double, i32 } %result, 1
  ret i32 %result.0
}

; FIXME: Widen vector result
; define { <2 x double>, <2 x i32> } @test_frexp_v2f64_v2i32(<2 x double> %a) {
;   %result = call { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double> %a)
;   ret { <2 x double>, <2 x i32> } %result
; }

; define <2 x double> @test_frexp_v2f64_v2i32_only_use_fract(<2 x double> %a) {
;   %result = call { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double> %a)
;   %result.0 = extractvalue { <2 x double>, <2 x i32> } %result, 0
;   ret <2 x double> %result.0
; }

; define <2 x i32> @test_frexp_v2f64_v2i32_only_use_exp(<2 x double> %a) {
;   %result = call { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double> %a)
;   %result.1 = extractvalue { <2 x double>, <2 x i32> } %result, 1
;   ret <2 x i32> %result.1
; }

declare { float, i32 } @llvm.frexp.f32.i32(float) #0
declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float>) #0
declare { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float>) #0

declare { half, i32 } @llvm.frexp.f16.i32(half) #0
declare { <2 x half>, <2 x i32> } @llvm.frexp.v2f16.v2i32(<2 x half>) #0

declare { double, i32 } @llvm.frexp.f64.i32(double) #0
declare { <2 x double>, <2 x i32> } @llvm.frexp.v2f64.v2i32(<2 x double>) #0

declare { half, i16 } @llvm.frexp.f16.i16(half) #0
declare { <2 x half>, <2 x i16> } @llvm.frexp.v2f16.v2i16(<2 x half>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }