diff options
Diffstat (limited to 'backend/Ifconv.v')
-rw-r--r-- | backend/Ifconv.v | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/backend/Ifconv.v b/backend/Ifconv.v new file mode 100644 index 00000000..0c9c5b5c --- /dev/null +++ b/backend/Ifconv.v @@ -0,0 +1,129 @@ +(* *********************************************************************) +(* *) +(* 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 GNU General Public License as published by *) +(* the Free Software Foundation, either version 2 of the License, or *) +(* (at your option) any later version. This file is also distributed *) +(* under the terms of the INRIA Non-Commercial License Agreement. *) +(* *) +(* *********************************************************************) + +Require Import Coqlib Maps Errors. +Require Import AST Events Cminor. +Require Import Cminortyping. + +Definition tyenv := ident -> typ. +Definition known_idents := PTree.t unit. + +Definition is_known (ki: known_idents) (id: ident) := + match ki!id with Some _ => true | None => false end. + +Definition safe_unop (op: unary_operation) : bool := + match op with + | Ointoffloat | Ointuoffloat | Ofloatofint | Ofloatofintu => false + | Ointofsingle | Ointuofsingle | Osingleofint | Osingleofintu => false + | Olongoffloat | Olonguoffloat | Ofloatoflong | Ofloatoflongu => false + | Olongofsingle | Olonguofsingle | Osingleoflong | Osingleoflongu => false + | _ => true + end. + +Definition safe_binop (op: binary_operation) : bool := + match op with + | Odiv | Odivu | Omod | Omodu => false + | Odivl | Odivlu | Omodl | Omodlu => false + | Ocmpl _ | Ocmplu _ => false + | _ => true + end. + +Fixpoint safe_expr (ki: known_idents) (a: expr) : bool := + match a with + | Evar v => is_known ki v + | Econst c => true + | Eunop op e1 => safe_unop op && safe_expr ki e1 + | Ebinop op e1 e2 => safe_binop op && safe_expr ki e1 && safe_expr ki e2 + | Eload chunk e => false + end. + +Definition Sselection (id: ident) (ty: typ) (cond ifso ifnot: expr) : stmt := + Sbuiltin (Some id) (EF_select ty) (cond :: ifso :: ifnot :: nil). + +Inductive stmt_class : Type := + | SCskip + | SCassign (id: ident) (a: expr) + | SCother. + +Function classify_stmt (s: stmt) : stmt_class := + match s with + | Sskip => SCskip + | Sassign id a => SCassign id a + | Sseq Sskip s => classify_stmt s + | Sseq s Sskip => classify_stmt s + | _ => SCother + end. + +Definition if_conversion_base + (ki: known_idents) (env: tyenv) + (cond: expr) (id: ident) (ifso ifnot: expr) : option stmt := + if is_known ki id && safe_expr ki ifso && safe_expr ki ifnot + then Some (Sselection id (env id) cond ifso ifnot) + else None. + +Definition if_conversion + (ki: known_idents) (env: tyenv) + (cond: expr) (ifso ifnot: stmt) : option stmt := + match classify_stmt ifso, classify_stmt ifnot with + | SCskip, SCassign id a => + if_conversion_base ki env cond id (Evar id) a + | SCassign id a, SCskip => + if_conversion_base ki env cond id a (Evar id) + | SCassign id1 a1, SCassign id2 a2 => + if ident_eq id1 id2 then if_conversion_base ki env cond id1 a1 a2 else None + | _, _ => None + end. + +Fixpoint transf_stmt (ki: known_idents) (env: tyenv) (s: stmt) : stmt := + match s with + | Sskip => s + | Sassign _ _ => s + | Sstore _ _ _ => s + | Scall _ _ _ _ => s + | Stailcall _ _ _ => s + | Sbuiltin _ _ _ => s + | Sseq s1 s2 => Sseq (transf_stmt ki env s1) (transf_stmt ki env s2) + | Sifthenelse e s1 s2 => + match if_conversion ki env e s1 s2 with + | Some s => s + | None => Sifthenelse e (transf_stmt ki env s1) (transf_stmt ki env s2) + end + | Sloop s1 => Sloop (transf_stmt ki env s1) + | Sblock s1 => Sblock (transf_stmt ki env s1) + | Sexit _ => s + | Sswitch _ _ _ _ => s + | Sreturn _ => s + | Slabel lbl s1 => Slabel lbl (transf_stmt ki env s1) + | Sgoto _ => s + end. + +Definition known_id (f: function) : known_idents := + let add (ki: known_idents) (id: ident) := PTree.set id tt ki in + List.fold_left add f.(fn_vars) + (List.fold_left add f.(fn_params) (PTree.empty unit)). + +Local Open Scope error_monad_scope. + +Definition transf_function (f: function) : res function := + let ki := known_id f in + do env <- type_function f; + OK (mkfunction f.(fn_sig) f.(fn_params) f.(fn_vars) f.(fn_stackspace) + (transf_stmt ki env f.(fn_body))). + +Definition transf_fundef (fd: fundef) : res fundef := + transf_partial_fundef transf_function fd. + +Definition transf_program (p: program) : res program := + transform_partial_program transf_fundef p. |