Module FPExtra

Require Import Coqlib.
Require Import Compopts.
Require Import AST Integers Floats.
Require Import Op CminorSel.
Require Import OpHelpers.
Require Import SelectOp SplitLong.
Require Import Values ExtValues.
Require Import DecBoolOps.

Local Open Scope cminorsel_scope.
Local Open Scope string_scope.

Definition e_andl a b := Eop Oandl (a ::: b ::: Enil).
Definition e_addl a b := Eop Oaddl (a ::: b ::: Enil).
Definition e_orl a b := Eop Oorl (a ::: b ::: Enil).
Definition e_constl n := Eop (Olongconst (Int64.repr n)) Enil.
Definition e_float_of_longu a := Eop Ofloatoflongu (a ::: Enil).
Definition e_float_of_long a := Eop Ofloatoflong (a ::: Enil).
Definition e_single_of_float a := Eop Osingleoffloat (a ::: Enil).
Definition e_ite ty c vc v1 v2 := Eop (Osel c ty) (v1 ::: v2 ::: vc ::: Enil).
Definition e_cmpluimm c v n := Eop (Ocmp (Ccompluimm c n)) (v ::: Enil).
Definition e_absl a := Eop (Oabsdifflimm Int64.zero) (a ::: Enil).

Definition a_var := Eletvar 0%nat.

Definition e_single_of_longu a :=
  Elet a (e_single_of_float (e_float_of_longu
    (e_ite Tlong (Ccompu0 Cne) (e_cmpluimm Cle a_var (Int64.repr (2^53))) a_var
           (e_andl (e_orl a_var (e_addl (e_andl a_var (e_constl 2047))
                                        (e_constl 2047)))
                   (e_constl (-2048))))))%Z.

Theorem e_single_of_longu_correct :
  forall (ge : genv) (sp: val) cmenv memenv
         (le : letenv) (expr_a : expr) (va : val)
         (EVAL_a : eval_expr ge sp cmenv memenv le expr_a va),
  eval_expr ge sp cmenv memenv le (e_single_of_longu expr_a)
            (Val.maketotal (Val.singleoflongu va)).
Proof.
  intros.
  unfold e_single_of_longu.
  repeat econstructor. eassumption.
  cbn.
  destruct va; cbn.
  all: try reflexivity.
  f_equal.
  unfold Int64.ltu.
  change (Int64.unsigned (Int64.repr 9007199254740992))%Z with 9007199254740992%Z.
  destruct zlt as [LT | GE]; cbn.
  { change (Int.eq Int.zero Int.zero) with true. cbn.
    f_equal.
    symmetry.
    apply Float32.of_longu_double_2.
    lia.
  }
  change (Int.eq Int.one Int.zero) with false. cbn.
  f_equal.
  symmetry.
  apply Float32.of_longu_double_1.
  lia.
Qed.

Definition e_single_of_long a :=
  Elet a (e_single_of_float (e_float_of_long
    (e_ite Tlong (Ccompu0 Cne) (e_cmpluimm Cle (e_absl a_var) (Int64.repr (2^53))) a_var
           (e_andl (e_orl a_var (e_addl (e_andl a_var (e_constl 2047))
                                        (e_constl 2047)))
                   (e_constl (-2048))))))%Z.

Theorem e_single_of_long_correct :
  forall (ge : genv) (sp: val) cmenv memenv
         (le : letenv) (expr_a : expr) (va : val)
         (EVAL_a : eval_expr ge sp cmenv memenv le expr_a va),
  eval_expr ge sp cmenv memenv le (e_single_of_long expr_a)
            (Val.maketotal (Val.singleoflong va)).
Proof.
  intros.
  unfold e_single_of_long.
  repeat econstructor. eassumption.
  cbn.
  destruct va; cbn.
  all: try reflexivity.
  f_equal.
  unfold Int64.ltu.
  change (Int64.unsigned (Int64.repr 9007199254740992))%Z with 9007199254740992%Z.
  destruct zlt as [LT | GE]; cbn.
  { change (Int.eq Int.zero Int.zero) with true. cbn.
    f_equal.
    symmetry.
    apply Float32.of_long_double_2.
    unfold long_absdiff, Z_abs_diff in LT.
    change (Int64.signed Int64.zero) with 0%Z in LT.
    rewrite Z.sub_0_r in LT.
    rewrite Int64.unsigned_repr in LT.
    lia.
    pose proof (Int64.signed_range i).
    change Int64.min_signed with (-9223372036854775808)%Z in *.
    change Int64.max_signed with (9223372036854775807)%Z in *.
    change Int64.max_unsigned with (18446744073709551615)%Z.
    lia.
  }
  change (Int.eq Int.one Int.zero) with false. cbn.
  f_equal.
  symmetry.
  apply Float32.of_long_double_1.
  unfold long_absdiff, Z_abs_diff in GE.
  change (Int64.signed Int64.zero) with 0%Z in GE.
  rewrite Z.sub_0_r in GE.
  rewrite Int64.unsigned_repr in GE.
  lia.
  pose proof (Int64.signed_range i).
  change Int64.min_signed with (-9223372036854775808)%Z in *.
  change Int64.max_signed with (9223372036854775807)%Z in *.
  change Int64.max_unsigned with (18446744073709551615)%Z.
  lia.
Qed.