llvm/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=instsimplify < %s | FileCheck %s

; Test cases for denormal handling mode when constant folding floating point
; operations. Input and output modes are checked separately.

; ============================================================================ ;
; fadd tests
; Denormal operand added to normal operand produces denormal result.
; If denormal outputs should be flushed to zero, the result should be zero.
; If denormal inputs should be treated as zero, the result should be the
; normal operand (a number plus zero is the same number).
; ============================================================================ ;

define float @test_float_fadd_ieee() #0 {
; CHECK-LABEL: @test_float_fadd_ieee(
; CHECK-NEXT:    ret float 0xB800000000000000
;
; default ieee mode leaves result as a denormal
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_pzero_out() #1 {
; CHECK-LABEL: @test_float_fadd_pzero_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_psign_out() #2 {
; CHECK-LABEL: @test_float_fadd_psign_out(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_pzero_in() #3 {
; CHECK-LABEL: @test_float_fadd_pzero_in(
; CHECK-NEXT:    ret float 0xB810000000000000
;
; denormal operand is treated as zero
; normal operand added to zero results in the same operand as a result
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_psign_in() #4 {
; CHECK-LABEL: @test_float_fadd_psign_in(
; CHECK-NEXT:    ret float 0xB810000000000000
;
; denormal operand is treated as zero
; normal operand added to zero results in the same operand as a result
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_pzero_f32_out() #5 {
; CHECK-LABEL: @test_float_fadd_pzero_f32_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; f32 only attribute should flush float output
; default ieee mode leaves result as a denormal
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define double @test_double_fadd_ieee() #0 {
; CHECK-LABEL: @test_double_fadd_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; default ieee mode leaves result as a denormal
  %result = fadd double 0x8010000000000000, 0x0008000000000000
  ret double %result
}

define double @test_double_fadd_pzero_out() #1 {
; CHECK-LABEL: @test_double_fadd_pzero_out(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fadd double 0x8010000000000000, 0x0008000000000000
  ret double %result
}

define double @test_double_fadd_psign_out() #2 {
; CHECK-LABEL: @test_double_fadd_psign_out(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fadd double 0x8010000000000000, 0x0008000000000000
  ret double %result
}

define double @test_double_fadd_pzero_in() #3 {
; CHECK-LABEL: @test_double_fadd_pzero_in(
; CHECK-NEXT:    ret double 0x8010000000000000
;
; denormal operand is treated as zero
; normal operand added to zero results in the same operand as a result
  %result = fadd double 0x8010000000000000, 0x0008000000000000
  ret double %result
}

define double @test_double_fadd_psign_in() #4 {
; CHECK-LABEL: @test_double_fadd_psign_in(
; CHECK-NEXT:    ret double 0x8010000000000000
;
; denormal operand is treated as zero
; normal operand added to zero results in the same operand as a result
  %result = fadd double 0x8010000000000000, 0x0008000000000000
  ret double %result
}

define double @test_double_fadd_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fadd_f32_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
  %result = fadd double 0x8010000000000000, 0x0008000000000000
  ret double %result
}

; ============================================================================ ;
; fsub tests
; Normal operand subtracted from denormal operand produces denormal result
; If denormal outputs should be flushed to zero, the result should be zero.
; If denormal inputs should be treated as zero, the result should be the
; negated normal operand (zero minus the original operand).
; ============================================================================ ;

define float @test_float_fsub_ieee() #0 {
; CHECK-LABEL: @test_float_fsub_ieee(
; CHECK-NEXT:    ret float 0xB800000000000000
;
; default ieee mode leaves result as a denormal
  %result = fsub float 0x3800000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_fsub_pzero_out() #1 {
; CHECK-LABEL: @test_float_fsub_pzero_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fsub float 0x3800000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_fsub_psign_out() #2 {
; CHECK-LABEL: @test_float_fsub_psign_out(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fsub float 0x3800000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_fsub_pzero_in() #3 {
; CHECK-LABEL: @test_float_fsub_pzero_in(
; CHECK-NEXT:    ret float 0xB810000000000000
;
; denormal operand is treated as zero
; normal operand subtracted from zero produces the same operand, negated
  %result = fsub float 0x3800000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_fsub_psign_in() #4 {
; CHECK-LABEL: @test_float_fsub_psign_in(
; CHECK-NEXT:    ret float 0xB810000000000000
;
; denormal operand is treated as zero
; normal operand subtracted from zero produces the same operand, negated
  %result = fsub float 0x3800000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_fsub_pzero_f32_out() #5 {
; CHECK-LABEL: @test_float_fsub_pzero_f32_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; f32 only attribute should flush float output
; same as pzero_out above
  %result = fsub float 0x3800000000000000, 0x3810000000000000
  ret float %result
}

define double @test_double_fsub_ieee() #0 {
; CHECK-LABEL: @test_double_fsub_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; default ieee mode leaves result as a denormal
  %result = fsub double 0x0008000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_fsub_pzero_out() #1 {
; CHECK-LABEL: @test_double_fsub_pzero_out(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fsub double 0x0008000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_fsub_psign_out() #2 {
; CHECK-LABEL: @test_double_fsub_psign_out(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fsub double 0x0008000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_fsub_pzero_in() #3 {
; CHECK-LABEL: @test_double_fsub_pzero_in(
; CHECK-NEXT:    ret double 0x8010000000000000
;
; denormal operand is treated as zero
; normal operand subtracted from zero produces the same operand, negated
  %result = fsub double 0x0008000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_fsub_psign_in() #4 {
; CHECK-LABEL: @test_double_fsub_psign_in(
; CHECK-NEXT:    ret double 0x8010000000000000
;
; denormal operand is treated as zero
; normal operand subtracted from zero produces the same operand, negated
  %result = fsub double 0x0008000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_fsub_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fsub_f32_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
  %result = fsub double 0x0008000000000000, 0x0010000000000000
  ret double %result
}

; ============================================================================ ;
; fmul tests
; Output modes are tested by multiplying the smallest normal number by 0.5,
; producing a denormal result. If denormal outputs should be flushed to zero,
; the result should be zero.
; Input modes are tested by the reverse operation: taking the denormal and
; multiplying by 2 to produce a normal number. If denormal inputs should be
; treated as zero, the result should also be zero.
; ============================================================================ ;

define float @test_float_fmul_ieee() #0 {
; CHECK-LABEL: @test_float_fmul_ieee(
; CHECK-NEXT:    ret float 0xB800000000000000
;
; default ieee mode leaves result as a denormal
  %result = fmul float 0x3810000000000000, -5.000000e-01
  ret float %result
}

define float @test_float_fmul_pzero_out() #1 {
; CHECK-LABEL: @test_float_fmul_pzero_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fmul float 0x3810000000000000, -5.000000e-01
  ret float %result
}

define float @test_float_fmul_psign_out() #2 {
; CHECK-LABEL: @test_float_fmul_psign_out(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fmul float 0x3810000000000000, -5.000000e-01
  ret float %result
}

define float @test_float_fmul_pzero_in() #3 {
; CHECK-LABEL: @test_float_fmul_pzero_in(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal operand is treated as positive zero
; anything multiplied by zero gives a zero result
  %result = fmul float 0xB800000000000000, 2.000000e-00
  ret float %result
}

define float @test_float_fmul_psign_in() #4 {
; CHECK-LABEL: @test_float_fmul_psign_in(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal operand is treated as signed zero
; anything multiplied by zero gives a zero result
  %result = fmul float 0xB800000000000000, 2.000000e-00
  ret float %result
}

define float @test_float_fmul_pzero_f32_out() #1 {
; CHECK-LABEL: @test_float_fmul_pzero_f32_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; f32 only attribute should flush float output
; same as pzero_out above
  %result = fmul float 0x3810000000000000, -5.000000e-01
  ret float %result
}

define double @test_double_fmul_ieee() #0 {
; CHECK-LABEL: @test_double_fmul_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; default ieee mode leaves result as a denormal
  %result = fmul double 0x00010000000000000, -5.000000e-01
  ret double %result
}

define double @test_double_fmul_pzero_out() #1 {
; CHECK-LABEL: @test_double_fmul_pzero_out(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fmul double 0x00010000000000000, -5.000000e-01
  ret double %result
}

define double @test_double_fmul_psign_out() #2 {
; CHECK-LABEL: @test_double_fmul_psign_out(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fmul double 0x0010000000000000, -5.000000e-01
  ret double %result
}

define double @test_double_fmul_pzero_in() #3 {
; CHECK-LABEL: @test_double_fmul_pzero_in(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal operand is treated as positive zero
; anything multiplied by zero gives a zero result
  %result = fmul double 0x8008000000000000, 2.000000e-00
  ret double %result
}

define double @test_double_fmul_psign_in() #4 {
; CHECK-LABEL: @test_double_fmul_psign_in(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal operand is treated as signed zero
; anything multiplied by zero gives a zero result
  %result = fmul double 0x8008000000000000, 2.000000e-00
  ret double %result
}

define double @test_double_fmul_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fmul_f32_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
  %result = fmul double 0x0010000000000000, -5.000000e-01
  ret double %result
}

; ============================================================================ ;
; fdiv tests
; Output modes are tested by dividing the smallest normal number by 2,
; producing a denormal result. If denormal outputs should be flushed to zero,
; the result should be zero.
; Input modes are tested by the reverse operation: taking the denormal and
; dividing by 0.5 to produce a normal number. If denormal inputs should be
; treated as zero, the result should also be zero.
; ============================================================================ ;

define float @test_float_fdiv_ieee() #0 {
; CHECK-LABEL: @test_float_fdiv_ieee(
; CHECK-NEXT:    ret float 0xB800000000000000
;
; default ieee mode leaves result as a denormal
  %result = fdiv float 0x3810000000000000, -2.000000e-00
  ret float %result
}

define float @test_float_fdiv_pzero_out() #1 {
; CHECK-LABEL: @test_float_fdiv_pzero_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fdiv float 0x3810000000000000, -2.000000e-00
  ret float %result
}

define float @test_float_fdiv_psign_out() #2 {
; CHECK-LABEL: @test_float_fdiv_psign_out(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fdiv float 0x3810000000000000, -2.000000e-00
  ret float %result
}

define float @test_float_fdiv_pzero_in() #3 {
; CHECK-LABEL: @test_float_fdiv_pzero_in(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal operand is treated as zero
; zero divided by anything gives a zero result
  %result = fdiv float 0xB800000000000000, 5.000000e-01
  ret float %result
}

define float @test_float_fdiv_psign_in() #4 {
; CHECK-LABEL: @test_float_fdiv_psign_in(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal operand is treated as zero
; zero divided by anything gives a zero result
  %result = fmul float 0xB800000000000000, 5.000000e-01
  ret float %result
}

define float @test_float_fdiv_pzero_f32_out() #1 {
; CHECK-LABEL: @test_float_fdiv_pzero_f32_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; f32 only attribute should flush float output
; same as pzero_out above
  %result = fdiv float 0x3810000000000000, -2.000000e-00
  ret float %result
}

define double @test_double_fdiv_ieee() #0 {
; CHECK-LABEL: @test_double_fdiv_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; default ieee mode leaves result as a denormal
  %result = fdiv double 0x0010000000000000, -2.000000e-00
  ret double %result
}

define double @test_double_fdiv_pzero_out() #1 {
; CHECK-LABEL: @test_double_fdiv_pzero_out(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = fdiv double 0x0010000000000000, -2.000000e-00
  ret double %result
}

define double @test_double_fdiv_psign_out() #2 {
; CHECK-LABEL: @test_double_fdiv_psign_out(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = fdiv double 0x0010000000000000, -2.000000e-00
  ret double %result
}

define double @test_double_fdiv_pzero_in() #3 {
; CHECK-LABEL: @test_double_fdiv_pzero_in(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal operand is treated as zero
; zero divided by anything gives a zero result
  %result = fdiv double 0x8008000000000000, 5.000000e-01
  ret double %result
}

define double @test_double_fdiv_psign_in() #4 {
; CHECK-LABEL: @test_double_fdiv_psign_in(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal operand is treated as zero
; zero divided by anything gives a zero result
  %result = fdiv double 0x8008000000000000, 5.000000e-01
  ret double %result
}

define double @test_double_fdiv_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fdiv_f32_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
  %result = fdiv double 0x0010000000000000, -2.000000e-00
  ret double %result
}

; ============================================================================ ;
; frem tests
; Output modes are tested by using two small normal numbers to produce a
; denormal result. If denormal outputs should be flushed to zero, the result
; should be zero.
; Input modes are tested by calculating the remainder of a denormal number
; and a larger normal number. If denormal inputs should be treated as zero
; the result also becomes zero.
; ============================================================================ ;

define float @test_float_frem_ieee_out() #0 {
; CHECK-LABEL: @test_float_frem_ieee_out(
; CHECK-NEXT:    ret float 0xB800000000000000
;
; default ieee mode leaves result as a denormal
  %result = frem float 0xB818000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_frem_pzero_out() #1 {
; CHECK-LABEL: @test_float_frem_pzero_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = frem float 0xB818000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_frem_psign_out() #2 {
; CHECK-LABEL: @test_float_frem_psign_out(
; CHECK-NEXT:    ret float -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = frem float 0xB818000000000000, 0x3810000000000000
  ret float %result
}

define float @test_float_frem_ieee_in() #0 {
; CHECK-LABEL: @test_float_frem_ieee_in(
; CHECK-NEXT:    ret float 0x3800000000000000
;
; default ieee mode leaves result same as input
  %result = frem float 0x3800000000000000, 2.000000e+00
  ret float %result
}

define float @test_float_frem_pzero_in() #3 {
; CHECK-LABEL: @test_float_frem_pzero_in(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal operand is treated as zero
; remainder is now zero
  %result = frem float 0x3800000000000000, 2.000000e+00
  ret float %result
}

define float @test_float_frem_psign_in() #4 {
; CHECK-LABEL: @test_float_frem_psign_in(
; CHECK-NEXT:    ret float 0.000000e+00
;
; denormal operand is treated as zero
; remainder is now zero
  %result = frem float 0x3800000000000000, 2.000000e+00
  ret float %result
}

define float @test_float_frem_pzero_f32_out() #1 {
; CHECK-LABEL: @test_float_frem_pzero_f32_out(
; CHECK-NEXT:    ret float 0.000000e+00
;
; f32 only attribute should flush float output
; same as pzero_out above
  %result = frem float 0xB818000000000000, 0x3810000000000000
  ret float %result
}

define double @test_double_frem_ieee_out() #0 {
; CHECK-LABEL: @test_double_frem_ieee_out(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; default ieee mode leaves result as a denormal
  %result = frem double 0x8018000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_frem_pzero_out() #1 {
; CHECK-LABEL: @test_double_frem_pzero_out(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal result is flushed to positive zero
  %result = frem double 0x8018000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_frem_psign_out() #2 {
; CHECK-LABEL: @test_double_frem_psign_out(
; CHECK-NEXT:    ret double -0.000000e+00
;
; denormal result is flushed to sign preserved zero
  %result = frem double 0x8018000000000000, 0x0010000000000000
  ret double %result
}

define double @test_double_frem_ieee_in() #0 {
; CHECK-LABEL: @test_double_frem_ieee_in(
; CHECK-NEXT:    ret double 0x8000000000000
;
; default ieee mode leaves result same as input
  %result = frem double 0x0008000000000000, 2.000000e+00
  ret double %result
}

define double @test_double_frem_pzero_in() #3 {
; CHECK-LABEL: @test_double_frem_pzero_in(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal operand is treated as zero
; remainder is now zero
  %result = frem double 0x0008000000000000, 2.000000e+00
  ret double %result
}

define double @test_double_frem_psign_in() #4 {
; CHECK-LABEL: @test_double_frem_psign_in(
; CHECK-NEXT:    ret double 0.000000e+00
;
; denormal operand is treated as zero
; remainder is now zero
  %result = frem double 0x0008000000000000, 2.000000e+00
  ret double %result
}

define double @test_double_frem_f32_ieee() #5 {
; CHECK-LABEL: @test_double_frem_f32_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
  %result = frem double 0x8018000000000000, 0x0010000000000000
  ret double %result
}

; ============================================================================ ;
; fneg tests
; fneg should NOT be affected by denormal handling mode
; these tests confirm fneg results are unchanged
; ============================================================================ ;

define float @test_float_fneg_ieee() #0 {
; CHECK-LABEL: @test_float_fneg_ieee(
; CHECK-NEXT:    ret float 0xB800000000000000
;
  %result = fneg float 0x3800000000000000
  ret float %result
}

define float @test_float_fneg_pzero_out() #0 {
; CHECK-LABEL: @test_float_fneg_pzero_out(
; CHECK-NEXT:    ret float 0xB800000000000000
;
  %result = fneg float 0x3800000000000000
  ret float %result
}

define float @test_float_fneg_psign_out() #0 {
; CHECK-LABEL: @test_float_fneg_psign_out(
; CHECK-NEXT:    ret float 0xB800000000000000
;
  %result = fneg float 0x3800000000000000
  ret float %result
}

define float @test_float_fneg_pzero_in() #0 {
; CHECK-LABEL: @test_float_fneg_pzero_in(
; CHECK-NEXT:    ret float 0xB800000000000000
;
  %result = fneg float 0x3800000000000000
  ret float %result
}

define float @test_float_fneg_psign_in() #0 {
; CHECK-LABEL: @test_float_fneg_psign_in(
; CHECK-NEXT:    ret float 0xB800000000000000
;
  %result = fneg float 0x3800000000000000
  ret float %result
}

define float @test_float_fneg_pzero_f32_out() #5 {
; CHECK-LABEL: @test_float_fneg_pzero_f32_out(
; CHECK-NEXT:    ret float 0xB800000000000000
;
  %result = fneg float 0x3800000000000000
  ret float %result
}

define double @test_double_fneg_ieee() #0 {
; CHECK-LABEL: @test_double_fneg_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
  %result = fneg double 0x0008000000000000
  ret double %result
}

define double @test_double_fneg_pzero_out() #1 {
; CHECK-LABEL: @test_double_fneg_pzero_out(
; CHECK-NEXT:    ret double 0x8008000000000000
;
  %result = fneg double 0x0008000000000000
  ret double %result
}

define double @test_double_fneg_psign_out() #2 {
; CHECK-LABEL: @test_double_fneg_psign_out(
; CHECK-NEXT:    ret double 0x8008000000000000
;
  %result = fneg double 0x0008000000000000
  ret double %result
}

define double @test_double_fneg_pzero_in() #3 {
; CHECK-LABEL: @test_double_fneg_pzero_in(
; CHECK-NEXT:    ret double 0x8008000000000000
;
  %result = fneg double 0x0008000000000000
  ret double %result
}

define double @test_double_fneg_psign_in() #4 {
; CHECK-LABEL: @test_double_fneg_psign_in(
; CHECK-NEXT:    ret double 0x8008000000000000
;
  %result = fneg double 0x0008000000000000
  ret double %result
}

define double @test_double_fneg_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fneg_f32_ieee(
; CHECK-NEXT:    ret double 0x8008000000000000
;
  %result = fneg double 0x0008000000000000
  ret double %result
}

define i1 @fcmp_double_ieee_in_ieee_out() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_float_ieee_in_ieee_out() #0 {
; CHECK-LABEL: @fcmp_float_ieee_in_ieee_out(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp une float 0x3800000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out() #6 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_float_pz_in_pz_out() #6 {
; CHECK-LABEL: @fcmp_float_pz_in_pz_out(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une float 0x3800000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out() #7 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_float_ps_in_ps_out() #7 {
; CHECK-LABEL: @fcmp_float_ps_in_ps_out(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une float 0x3800000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_pz_out_ieee_in() #1 {
; CHECK-LABEL: @fcmp_double_pz_out_ieee_in(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ps_out_ieee_in() #2 {
; CHECK-LABEL: @fcmp_double_ps_out_ieee_in(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_out_pz_in() #3 {
; CHECK-LABEL: @fcmp_double_ieee_out_pz_in(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_out_ps_in() #4 {
; CHECK-LABEL: @fcmp_double_ieee_out_ps_in(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_f32_pz_in() #8 {
; CHECK-LABEL: @fcmp_double_f32_pz_in(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_two_denormal_ins() #6 {
; CHECK-LABEL: @fcmp_double_two_denormal_ins(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp une double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out_false() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_false(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp false double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_false() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_false(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp false double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out_true() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_true(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp true double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_true() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_true(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp true double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out_oeq() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_oeq(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp oeq double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_oeq() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_oeq(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp oeq double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out_one() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_one(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp one double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_one() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_one(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp one double 0x0008100000000000, 0x0008000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out_ord1() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_ord1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ord double 0x0008000000000000, 0x7ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_ord1() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_ord1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ord double 0x0008000000000000, 0x7ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ps_in_ps_out_ord2() #6 {
; CHECK-LABEL: @fcmp_double_ps_in_ps_out_ord2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp ord double 0x0008000000000000, 0x1ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_ord2() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_ord2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp ord double 0x0008000000000000, 0x1ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out_ugt() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_ugt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ugt double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_ugt() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_ugt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp ugt double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out_ult() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_ult(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ult double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_ult() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_ult(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ult double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out_uge() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_uge(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp uge double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_uge() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_uge(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp uge double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out_ule() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_ule(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp ule double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_ule() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_ule(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp ule double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out_uno() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_uno(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp uno double 0x0008000000000000, 0x7ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_uno() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_uno(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = fcmp uno double 0x0008000000000000, 0x7ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_pz_in_pz_out_uno2() #7 {
; CHECK-LABEL: @fcmp_double_pz_in_pz_out_uno2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp uno double 0x0008000000000000, 0x1ff1000000000000
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_in_ieee_out_uno2() #0 {
; CHECK-LABEL: @fcmp_double_ieee_in_ieee_out_uno2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = fcmp uno double 0x0008000000000000, 0x1ff1000000000000
  ret i1 %cmp
}

; ============================================================================ ;
; dynamic mode tests
; ============================================================================ ;

define float @test_float_fadd_dynamic_ieee() #9 {
; CHECK-LABEL: @test_float_fadd_dynamic_ieee(
; CHECK-NEXT:    [[RESULT:%.*]] = fadd float 0xB810000000000000, 0x3800000000000000
; CHECK-NEXT:    ret float [[RESULT]]
;
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_ieee_dynamic() #10 {
; CHECK-LABEL: @test_float_fadd_ieee_dynamic(
; CHECK-NEXT:    [[RESULT:%.*]] = fadd float 0xB810000000000000, 0x3800000000000000
; CHECK-NEXT:    ret float [[RESULT]]
;
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

define float @test_float_fadd_dynamic_dynamic() #11 {
; CHECK-LABEL: @test_float_fadd_dynamic_dynamic(
; CHECK-NEXT:    [[RESULT:%.*]] = fadd float 0xB810000000000000, 0x3800000000000000
; CHECK-NEXT:    ret float [[RESULT]]
;
  %result = fadd float 0xB810000000000000, 0x3800000000000000
  ret float %result
}

; Check for failed to fold on each operand
define float @test_float_fadd_dynamic_dynamic_commute() #11 {
; CHECK-LABEL: @test_float_fadd_dynamic_dynamic_commute(
; CHECK-NEXT:    [[RESULT:%.*]] = fadd float 0x3800000000000000, 0xB810000000000000
; CHECK-NEXT:    ret float [[RESULT]]
;
  %result = fadd float 0x3800000000000000, 0xB810000000000000
  ret float %result
}

define i1 @fcmp_double_dynamic_ieee() #9 {
; CHECK-LABEL: @fcmp_double_dynamic_ieee(
; CHECK-NEXT:    ret i1 true
;
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_ieee_dynamic() #10 {
; CHECK-LABEL: @fcmp_double_ieee_dynamic(
; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double 0x8000000000000, 0.000000e+00
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_dynamic_dynamic() #11 {
; CHECK-LABEL: @fcmp_double_dynamic_dynamic(
; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double 0x8000000000000, 0.000000e+00
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

define i1 @fcmp_double_dynamic_dynamic_commute() #11 {
; CHECK-LABEL: @fcmp_double_dynamic_dynamic_commute(
; CHECK-NEXT:    [[CMP:%.*]] = fcmp une double 0.000000e+00, 0x8000000000000
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %cmp = fcmp une double 0x0, 0x0008000000000000
  ret i1 %cmp
}

; Output doesn't matter.
define i1 @fcmp_double_dynamic_psz() #12 {
; CHECK-LABEL: @fcmp_double_dynamic_psz(
; CHECK-NEXT:    ret i1 false
;
  %cmp = fcmp une double 0x0008000000000000, 0x0
  ret i1 %cmp
}

; Non-denormal values should fold
define float @test_float_fadd_dynamic_dynamic_normals() #11 {
; CHECK-LABEL: @test_float_fadd_dynamic_dynamic_normals(
; CHECK-NEXT:    ret float 3.000000e+00
;
  %result = fadd float 1.0, 2.0
  ret float %result
}

; Non-denormal values should fold
define i1 @fcmp_double_dynamic_dynamic_normals() #11 {
; CHECK-LABEL: @fcmp_double_dynamic_dynamic_normals(
; CHECK-NEXT:    ret i1 true
;
  %cmp = fcmp une double 1.0, 2.0
  ret i1 %cmp
}

attributes #0 = { nounwind "denormal-fp-math"="ieee,ieee" }
attributes #1 = { nounwind "denormal-fp-math"="positive-zero,ieee" }
attributes #2 = { nounwind "denormal-fp-math"="preserve-sign,ieee" }
attributes #3 = { nounwind "denormal-fp-math"="ieee,positive-zero" }
attributes #4 = { nounwind "denormal-fp-math"="ieee,preserve-sign" }
attributes #5 = { nounwind "denormal-fp-math"="ieee,ieee" "denormal-fp-math-f32"="positive-zero,ieee" }
attributes #6 = { nounwind "denormal-fp-math"="positive-zero,positive-zero" }
attributes #7 = { nounwind "denormal-fp-math"="preserve-sign,preserve-sign" }
attributes #8 = { nounwind "denormal-fp-math"="ieee,ieee" "denormal-fp-math-f32"="positive-zero,positive-zero" }
attributes #9 = { nounwind "denormal-fp-math"="dynamic,ieee" }
attributes #10 = { nounwind "denormal-fp-math"="ieee,dynamic" }
attributes #11 = { nounwind "denormal-fp-math"="dynamic,dynamic" }
attributes #12 = { nounwind "denormal-fp-math"="dynamic,preserve-sign" }