Fixpoint set_params' (vl: list val) (il: list ident) (te: Cminor.env) : Cminor.env :=
  match il, vl with
  | i1 :: is, v1 :: vs => set_params' vs is (PTree.set i1 v1 te)
  | i1 :: is, nil => set_params' nil is (PTree.set i1 Vundef te)
  | _, _ => te
  end.

(* Specifications: *)
Lemma bind_parameters_agree_rec: forall f vars vals tvals le1 le2 te, bind_parameters vars vals le1 = Some le2 -> Val.inject_list f vals tvals -> match_temps f le1 te -> match_temps f le2 (set_params' tvals vars te).
Lemma bind_parameters_agree: forall f params temps vals tvals le, bind_parameters params vals (create_undef_temps temps) = Some le -> Val.inject_list f vals tvals -> list_norepet params -> list_disjoint params temps -> match_temps f le (set_locals temps (set_params tvals params)).
Theorem match_callstack_function_entry: forall fn cenv tf m e m' tm tm' sp f cs args targs le, build_compilenv fn = (cenv, tf.(fn_stackspace)) -> tf.(fn_stackspace) <= Ptrofs.max_unsigned -> list_norepet (map fst (Csharpminor.fn_vars fn)) -> list_norepet (Csharpminor.fn_params fn) -> list_disjoint (Csharpminor.fn_params fn) (Csharpminor.fn_temps fn) -> alloc_variables Csharpminor.empty_env m (Csharpminor.fn_vars fn) e m' -> bind_parameters (Csharpminor.fn_params fn) args (create_undef_temps fn.(fn_temps)) = Some le -> Val.inject_list f args targs -> Mem.alloc tm 0 tf.(fn_stackspace) = (tm', sp) -> match_callstack f m tm cs (Mem.nextblock m) (Mem.nextblock tm) -> Mem.inject f m tm -> let te := set_locals (Csharpminor.fn_temps fn) (set_params targs (Csharpminor.fn_params fn)) in exists f', match_callstack f' m' tm' (Frame cenv tf e le te sp (Mem.nextblock m) (Mem.nextblock m') :: cs) (Mem.nextblock m') (Mem.nextblock tm') /\ Mem.inject f' m' tm'.