(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*         Xavier Leroy, Collège de France and INRIA Paris             *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Neededness analysis for AArch64 operators *)
Definition needs_of_shift (s: shift) (a: amount32) (nv: nval) :=
match s with
| Slsl => shlimm nv a
| Sasr => shrimm nv a
| Slsr => shruimm nv a
| Sror => ror nv a
end.
Definition zero_ext' (s: Z) (nv: nval) :=
if zle 0 s then zero_ext s nv else default nv.
Definition sign_ext' (s: Z) (nv: nval) :=
if zlt 0 s then sign_ext s nv else default nv.
Definition op1 (nv: nval) := nv :: nil.
Definition op2 (nv: nval) := nv :: nv :: nil.
Definition op1shift (s: shift) (a: amount32) (nv: nval) :=
needs_of_shift s a nv :: nil.
Definition op2shift (s: shift) (a: amount32) (nv: nval) :=
nv :: needs_of_shift s a nv :: nil.
Definition needs_of_condition (cond: condition): list nval := nil.
Definition needs_of_operation (op: operation) (nv: nval): list nval :=
match op with
| Omove => nv :: nil
| Ointconst _ => nil
| Olongconst _ => nil
| Ofloatconst _ => nil
| Osingleconst _ => nil
| Oaddrsymbol _ _ => nil
| Oaddrstack _ => nil
| Oshift s a => op1shift s a nv
| Oadd | Osub | Omul => op2 (modarith nv)
| Oaddshift s a | Osubshift s a => op2shift s a (modarith nv)
| Oaddimm _ => op1 (modarith nv)
| Oneg => op1 (modarith nv)
| Onegshift s a => op1shift s a (modarith nv)
| Omuladd | Omulsub =>
let n := modarith nv in n :: n :: n :: nil
| Odiv | Odivu => op2 (default nv)
| Oand | Oor | Oxor => op2 (bitwise nv)
| Oandshift s a | Oorshift s a | Oxorshift s a =>  op2shift s a (bitwise nv)
| Oandimm  n => op1 (andimm nv n)
| Oorimm n => op1 (orimm nv n)
| Oxorimm n => op1 (bitwise nv)
| Onot => op1 (bitwise nv)
| Onotshift s a => needs_of_shift s a (bitwise nv) :: nil
| Obic | Oorn | Oeqv =>
let n := bitwise nv in n :: bitwise n :: nil
| Obicshift s a | Oornshift s a | Oeqvshift s a =>
let n := bitwise nv in n :: needs_of_shift s a (bitwise n) :: nil
| Oshl | Oshr | Oshru => op2 (default nv)
| Oshrximm _ => op1 (default nv)
| Ozext s => op1 (zero_ext' s nv)
| Osext s => op1 (sign_ext' s nv)
| Oshlzext s a => op1 (zero_ext' s (shlimm nv a))
| Oshlsext s a => op1 (sign_ext' s (shlimm nv a))
| Ozextshr a s => op1 (shruimm (zero_ext' s nv) a)
| Osextshr a s => op1 (shrimm (sign_ext' s nv) a)
| Oshiftl _ _ | Oextend _ _ => op1 (default nv)
| Omakelong  | Olowlong  | Ohighlong => op1 (default nv)
| Oaddl | Osubl | Omull => op2 (default nv)
| Oaddlshift _ _ | Oaddlext _ _ | Osublshift _ _ | Osublext _ _ => op2 (default nv)
| Oaddlimm _ => op1 (default nv)
| Onegl => op1 (default nv)
| Oneglshift _ _ => op1 (default nv)
| Omulladd | Omullsub => let n := default nv in n :: n :: n :: nil
| Omullhs | Omullhu | Odivl | Odivlu => op2 (default nv)
| Oandl | Oorl | Oxorl | Obicl | Oornl | Oeqvl => op2 (default nv)
| Oandlshift _ _ | Oorlshift _ _  | Oxorlshift _ _
| Obiclshift _ _ | Oornlshift _ _ | Oeqvlshift _ _ => op2 (default nv)
| Oandlimm _ | Oorlimm _ | Oxorlimm _ => op1 (default nv)
| Onotl => op1 (default nv)
| Onotlshift _ _ => op1 (default nv)
| Oshll | Oshrl | Oshrlu => op2 (default nv)
| Oshrlximm _ => op1 (default nv)
| Ozextl _ | Osextl _
| Oshllzext _ _ | Oshllsext _ _ | Ozextshrl _ _ | Osextshrl _ _ => op1 (default nv)
| Onegf | Oabsf => op1 (default nv)
| Oaddf | Osubf | Omulf | Odivf => op2 (default nv)
| Onegfs | Oabsfs => op1 (default nv)
| Oaddfs | Osubfs | Omulfs | Odivfs => op2 (default nv)
| Ofloatofsingle | Osingleoffloat => op1 (default nv)
| Ointoffloat | Ointuoffloat | Ofloatofint | Ofloatofintu => op1 (default nv)
| Olongoffloat | Olonguoffloat | Ofloatoflong | Ofloatoflongu => op1 (default nv)
| Ointofsingle | Ointuofsingle | Osingleofint | Osingleofintu => op1 (default nv)
| Olongofsingle | Olonguofsingle | Osingleoflong | Osingleoflongu => op1 (default nv)
| Ocmp c => needs_of_condition c
| Osel c ty => nv :: nv :: needs_of_condition c
end.
Definition operation_is_redundant (op: operation) (nv: nval): bool :=
match op with
| Ozext s => zle 0 s && zero_ext_redundant s nv
| Osext s => zlt 0 s && sign_ext_redundant s nv
| Oandimm n => andimm_redundant nv n
| Oorimm n => orimm_redundant nv n
| _ => false
end.
Ltac InvAgree :=
match goal with
| [H: vagree_list nil _ _ |- _ ] => inv H; InvAgree
| [H: vagree_list (_::_) _ _ |- _ ] => inv H; InvAgree
| _ => idtac
end.
Ltac TrivialExists :=
match goal with
| [ |- exists v, Some ?x = Some v /\ _ ] => exists x; split; auto
| _ => idtac
end.

Lemma shift_sound:
forall v w s a x,
vagree v w (needs_of_shift s a x) ->
vagree (eval_shift s v a) (eval_shift s w a) x.