aboutsummaryrefslogtreecommitdiff
path: root/src/UnderLets.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/UnderLets.v')
-rw-r--r--src/UnderLets.v206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/UnderLets.v b/src/UnderLets.v
new file mode 100644
index 000000000..522a8c4c7
--- /dev/null
+++ b/src/UnderLets.v
@@ -0,0 +1,206 @@
+Require Import Crypto.Language.
+Require Import Crypto.Util.Notations.
+
+Module Compilers.
+ Export Language.Compilers.
+ Import invert_expr.
+
+ Module SubstVarLike.
+ Section with_ident.
+ Context {base_type : Type}.
+ Local Notation type := (type.type base_type).
+ Context {ident : type -> Type}.
+ Local Notation expr := (@expr.expr base_type ident).
+ Section with_var.
+ Context {var : type -> Type}.
+ Section with_var_like.
+ Context (is_var_like : forall t, @expr var t -> bool).
+ Fixpoint subst_var_like {t} (e : @expr (@expr var) t) : @expr var t
+ := match e with
+ | expr.LetIn tx tC ex eC
+ => let ex' := @subst_var_like tx ex in
+ let eC' := fun v => @subst_var_like tC (eC v) in
+ if is_var_like _ ex'
+ then eC' ex'
+ else expr.LetIn ex' (fun v => eC' ($v))
+ | expr.App s d f x
+ => let f' := @subst_var_like _ f in
+ let x' := @subst_var_like _ x in
+ expr.App f' x'
+ | expr.Abs s d f
+ => expr.Abs (fun v => @subst_var_like _ (f ($v)))
+ | expr.Var t v => v
+ | expr.Ident t idc => expr.Ident idc
+ end%expr.
+ End with_var_like.
+ Section with_ident_like.
+ Context (ident_is_good : forall t, ident t -> bool).
+ Fixpoint is_recursively_var_or_ident {t} (e : @expr var t) : bool
+ := match e with
+ | expr.Ident t idc => ident_is_good _ idc
+ | expr.Var t v => true
+ | expr.Abs s d f => false
+ | expr.App s d f x
+ => andb (@is_recursively_var_or_ident _ f)
+ (@is_recursively_var_or_ident _ x)
+ | expr.LetIn A B x f => false
+ end.
+ End with_ident_like.
+ End with_var.
+
+ Definition SubstVarLike (is_var_like : forall var t, @expr var t -> bool)
+ {t} (e : expr.Expr t) : expr.Expr t
+ := fun var => subst_var_like (is_var_like _) (e _).
+
+ Definition SubstVar {t} (e : expr.Expr t) : expr.Expr t
+ := SubstVarLike (fun _ _ e => match invert_Var e with Some _ => true | None => false end) e.
+
+ Definition SubstVarOrIdent (should_subst_ident : forall t, ident t -> bool)
+ {t} (e : expr.Expr t) : expr.Expr t
+ := SubstVarLike (fun var t => is_recursively_var_or_ident should_subst_ident) e.
+ End with_ident.
+
+ Definition ident_is_var_like {t} (idc : ident t) : bool
+ := match idc with
+ | ident.Literal _ _
+ | ident.nil _
+ | ident.cons _
+ | ident.pair _ _
+ | ident.fst _ _
+ | ident.snd _ _
+ | ident.Z_opp
+ | ident.Z_cast _
+ | ident.Z_cast2 _
+ => true
+ | _ => false
+ end.
+ Definition is_var_fst_snd_pair_opp_cast {var} {t} (e : expr (var:=var) t) : bool
+ := @is_recursively_var_or_ident base.type ident var (@ident_is_var_like) t e.
+ Definition IsVarFstSndPairOppCast {t} (e : expr.Expr t) : bool
+ := @is_var_fst_snd_pair_opp_cast (fun _ => unit) t (e _).
+
+ Definition SubstVarFstSndPairOppCast {t} (e : expr.Expr t) : expr.Expr t
+ := @SubstVarOrIdent base.type ident (@ident_is_var_like) t e.
+ End SubstVarLike.
+
+ Module UnderLets.
+ Section with_var.
+ Context {base_type : Type}.
+ Local Notation type := (type base_type).
+ Context {ident : type -> Type}
+ {var : type -> Type}.
+ Local Notation expr := (@expr base_type ident var).
+
+ Inductive UnderLets {T : Type} :=
+ | Base (v : T)
+ | UnderLet {A} (x : expr A) (f : var A -> UnderLets).
+
+ Fixpoint splice {A B} (x : @UnderLets A) (e : A -> @UnderLets B) : @UnderLets B
+ := match x with
+ | Base v => e v
+ | UnderLet A x f => UnderLet x (fun v => @splice _ _ (f v) e)
+ end.
+
+ Fixpoint splice_list {A B} (ls : list (@UnderLets A)) (e : list A -> @UnderLets B) : @UnderLets B
+ := match ls with
+ | nil => e nil
+ | cons x xs
+ => splice x (fun x => @splice_list A B xs (fun xs => e (cons x xs)))
+ end.
+
+ Fixpoint to_expr {t} (x : @UnderLets (expr t)) : expr t
+ := match x with
+ | Base v => v
+ | UnderLet A x f
+ => expr.LetIn x (fun v => @to_expr _ (f v))
+ end.
+ Fixpoint of_expr {t} (x : expr t) : @UnderLets (expr t)
+ := match x in expr.expr t return @UnderLets (expr t) with
+ | expr.LetIn A B x f
+ => UnderLet x (fun v => @of_expr B (f v))
+ | e => Base e
+ end.
+ End with_var.
+ Module Export Notations.
+ Global Arguments UnderLets : clear implicits.
+ Delimit Scope under_lets_scope with under_lets.
+ Bind Scope under_lets_scope with UnderLets.UnderLets.
+ Notation "x <-- y ; f" := (UnderLets.splice y (fun x => f%under_lets)) : under_lets_scope.
+ Notation "x <---- y ; f" := (UnderLets.splice_list y (fun x => f%under_lets)) : under_lets_scope.
+ End Notations.
+
+ Section reify.
+ Context {var : type.type base.type -> Type}.
+ Local Notation type := (type.type base.type).
+ Local Notation expr := (@expr.expr base.type ident var).
+ Local Notation UnderLets := (@UnderLets.UnderLets base.type ident var).
+ Let type_base (t : base.type) : type := type.base t.
+ Coercion type_base : base.type >-> type.
+
+ Let default_reify_and_let_binds_base_cps {t : base.type} : expr t -> forall T, (expr t -> UnderLets T) -> UnderLets T
+ := fun e T k
+ => match invert_expr.invert_Var e with
+ | Some v => k ($v)%expr
+ | None => if SubstVarLike.is_var_fst_snd_pair_opp_cast e
+ then k e
+ else UnderLets.UnderLet e (fun v => k ($v)%expr)
+ end.
+
+ Fixpoint reify_and_let_binds_base_cps {t : base.type} : expr t -> forall T, (expr t -> UnderLets T) -> UnderLets T
+ := match t return expr t -> forall T, (expr t -> UnderLets T) -> UnderLets T with
+ | base.type.type_base t
+ => fun e T k
+ => match invert_Literal e with
+ | Some v => k (expr.Ident (ident.Literal v))
+ | None => @default_reify_and_let_binds_base_cps _ e T k
+ end
+ | base.type.prod A B
+ => fun e T k
+ => match invert_pair e with
+ | Some (a, b)
+ => @reify_and_let_binds_base_cps
+ A a _
+ (fun ae
+ => @reify_and_let_binds_base_cps
+ B b _
+ (fun be
+ => k (ae, be)%expr))
+ | None => @default_reify_and_let_binds_base_cps _ e T k
+ end
+ | base.type.list A
+ => fun e T k
+ => match reflect_list e with
+ | Some ls
+ => list_rect
+ _
+ (fun k => k []%expr)
+ (fun x _ rec k
+ => @reify_and_let_binds_base_cps
+ A x _
+ (fun xe
+ => rec (fun xse => k (xe :: xse)%expr)))
+ ls
+ k
+ | None => @default_reify_and_let_binds_base_cps _ e T k
+ end
+ end%under_lets.
+
+ Fixpoint let_bind_return {t} : expr t -> expr t
+ := match t return expr t -> expr t with
+ | type.base t
+ => fun e => to_expr (v <-- of_expr e; reify_and_let_binds_base_cps v _ Base)
+ | type.arrow s d
+ => fun e
+ => expr.Abs (fun v => @let_bind_return
+ d
+ match invert_Abs e with
+ | Some f => f v
+ | None => e @ $v
+ end%expr)
+ end.
+ End reify.
+ Definition LetBindReturn {t} (e : expr.Expr t) : expr.Expr t
+ := fun var => let_bind_return (e _).
+ End UnderLets.
+ Export UnderLets.Notations.
+End Compilers.