Theory LLVM_Float_Types

theory LLVM_Float_Types
imports "IEEE_FP_Extensions/IEEE_Float_Extend_Integer"
begin

subsection Double

typedef double = "UNIV::(11, 52) float set"
  morphisms float_of_double double_of_float  
  ..
  
setup_lifting type_definition_double

text Operations with default round-to-nearest

instantiation double :: "{uminus,plus,times,minus,zero,one,abs,ord,inverse,finite}" begin
  lift_definition uminus_double::"double  double" is uminus .
  lift_definition plus_double::"double  double  double" is plus .
  lift_definition times_double::"double  double  double" is times .
  lift_definition divide_double::"double  double  double" is divide .
  lift_definition inverse_double::"double  double" is inverse .
  lift_definition minus_double::"double  double  double" is minus .
  lift_definition zero_double::"double" is "0::float64" .
  lift_definition one_double::"double" is "1::float64" .
  lift_definition less_eq_double::"double  double  bool" is "(≤)" .
  lift_definition less_double::"double  double  bool" is "(<)" .
  instance proof
    have [simp]: "(UNIV :: double set) = double_of_float`(UNIV::float64 set)"
      apply auto
      by (metis double_of_float_cases range_eqI)
    show "finite (UNIV :: double set)" by (simp)
  qed
end

text Operations with explicit rounding mode

lift_definition dradd :: "roundmode  double  double  double" is fadd .
lift_definition drsub :: "roundmode  double  double  double" is fsub .
lift_definition drmul :: "roundmode  double  double  double" is fmul .
lift_definition drdiv :: "roundmode  double  double  double" is fdiv .
lift_definition drrem :: "roundmode  double  double  double" is frem .
lift_definition drsqrt :: "roundmode  double  double" is fsqrt .
lift_definition drfmadd :: "roundmode  double  double  double  double" is fmul_add .

definition "drem  drrem To_nearest"
definition "dsqrt  drsqrt To_nearest"

lift_definition eq_double::"doubledoublebool" is float_eq .

lift_definition sqrt_double::"doubledouble" is float_sqrt .

lift_definition infinity_double::"double" is plus_infinity .

lift_definition is_normal_double::"double  bool" is IEEE.is_normal .
lift_definition is_zero_double::"double  bool" is IEEE.is_zero .
lift_definition is_finite_double::"double  bool" is IEEE.is_finite .
lift_definition is_nan_double::"double  bool" is IEEE.is_nan .


lift_definition double_of_word :: "64 word  double" is float_of_fp64 .
lift_definition word_of_double :: "double  64 word" is fp64_of_float .

lemma double_of_word_inv[simp]:
  "double_of_word (word_of_double d) = d"
  "word_of_double (double_of_word w) = w"
  by (determ transfer, simp)+
  
lemma double_of_word_zero[simp]: "double_of_word 0 = 0"
  by transfer' simp
  
lemma word_of_double_zero[simp]: "word_of_double 0 = 0"  
  by transfer' simp
  

lift_definition real_of_double :: "double  real" is IEEE.valof .

lift_definition round_double :: "roundmode  real  double" is round .

abbreviation round_double_nearest where "round_double_nearest  round_double To_nearest"
abbreviation round_double_zero where "round_double_zero  round_double float_To_zero"
abbreviation round_double_up where "round_double_up  round_double To_pinfinity"
abbreviation round_double_down where "round_double_down  round_double To_ninfinity"

subsection Single
typedef single = "UNIV::float32 set" 
  morphisms float_of_single single_of_float  
  ..


setup_lifting type_definition_single

text Operations with default round-to-nearest

instantiation single :: "{uminus,plus,times,minus,zero,one,abs,ord,inverse,finite}" begin
  lift_definition uminus_single::"single  single" is uminus .
  lift_definition plus_single::"single  single  single" is plus .
  lift_definition times_single::"single  single  single" is times .
  lift_definition divide_single::"single  single  single" is divide .
  lift_definition inverse_single::"single  single" is inverse .
  lift_definition minus_single::"single  single  single" is minus .
  lift_definition zero_single::"single" is "0::float32" .
  lift_definition one_single::"single" is "1::float32" .
  lift_definition less_eq_single::"single  single  bool" is "(≤)" .
  lift_definition less_single::"single  single  bool" is "(<)" .
  instance proof
    have [simp]: "(UNIV :: single set) = single_of_float`(UNIV::float32 set)"
      apply auto
      by (metis single_of_float_cases range_eqI)
    show "finite (UNIV :: single set)" by (simp)
  qed
end

text Operations with explicit rounding mode

lift_definition sradd :: "roundmode  single  single  single" is fadd .
lift_definition srsub :: "roundmode  single  single  single" is fsub .
lift_definition srmul :: "roundmode  single  single  single" is fmul .
lift_definition srdiv :: "roundmode  single  single  single" is fdiv .
lift_definition srrem :: "roundmode  single  single  single" is frem .
lift_definition srsqrt :: "roundmode  single  single" is fsqrt .
lift_definition srfmadd :: "roundmode  single  single  single  single" is fmul_add .

definition "srem  srrem To_nearest"
definition "ssqrt  srsqrt To_nearest"

lift_definition eq_single::"singlesinglebool" is float_eq .

lift_definition sqrt_single::"singlesingle" is float_sqrt .

lift_definition infinity_single::"single" is plus_infinity .

lift_definition is_normal_single::"single  bool" is IEEE.is_normal .
lift_definition is_zero_single::"single  bool" is IEEE.is_zero .
lift_definition is_finite_single::"single  bool" is IEEE.is_finite .
lift_definition is_nan_single::"single  bool" is IEEE.is_nan .


lift_definition single_of_word :: "32 word  single" is float_of_fp32 .
lift_definition word_of_single :: "single  32 word" is fp32_of_float .

lemma single_of_word_inv[simp]:
  "single_of_word (word_of_single d) = d"
  "word_of_single (single_of_word w) = w"
  by (determ transfer, simp)+
    
lemma single_of_word_zero[simp]: "single_of_word 0 = 0"
  by transfer' simp
  
lemma word_of_single_zero[simp]: "word_of_single 0 = 0"  
  by transfer' simp
  

lift_definition real_of_single :: "single  real" is IEEE.valof .

lift_definition round_single :: "roundmode  real  single" is round .

abbreviation round_single_nearest where "round_single_nearest  round_single To_nearest"
abbreviation round_single_zero where "round_single_zero  round_single float_To_zero"
abbreviation round_single_up where "round_single_up  round_single To_pinfinity"
abbreviation round_single_down where "round_single_down  round_single To_ninfinity"


subsection Extension Correctness Theorem

text Version for single and double: 
theorem fext_int_single_double_correct:
  fixes i32 :: "integer"
  defines "i64  fext_int_32_64 i32"
  defines "f32  single_of_word (word_of_integer i32)"
  defines "f64  double_of_word (word_of_integer i64)"
  shows "correct_extension (float_of_single f32) (float_of_double f64)"
  using double_of_word.rep_eq f32_def f64_def fext_int_32_64_correct i64_def single_of_word.rep_eq 
  by presburger

end