Section SAVE_CALLEE_SAVE.
Variable j: meminj.
Variable cs: list stackframe.
Variable fb: block.
Variable sp: block.
Variable ls: locset.
Hypothesis ls_temp_undef:
forall ty r, In r (destroyed_by_setstack ty) -> ls (R r) = Vundef.
Hypothesis wt_ls: forall r, Val.has_type (ls (R r)) (mreg_type r).
End SAVE_CALLEE_SAVE.
Remark LTL_undef_regs_same:
forall r rl ls, In r rl -> LTL.undef_regs rl ls (R r) = Vundef.
Remark LTL_undef_regs_others:
forall r rl ls, ~In r rl -> LTL.undef_regs rl ls (R r) = ls (R r).
Remark LTL_undef_regs_slot:
forall sl ofs ty rl ls, LTL.undef_regs rl ls (S sl ofs ty) = ls (S sl ofs ty).
Remark undef_regs_type:
forall ty l rl ls,
Val.has_type (ls l) ty -> Val.has_type (LTL.undef_regs rl ls l) ty.

Lemma save_callee_save_correct:
forall j ls ls0 rs sp cs fb k m P,
m |= range sp fe.(fe_ofs_callee_save) (size_callee_save_area b fe.(fe_ofs_callee_save)) ** P ->
(forall r, Val.has_type (ls (R r)) (mreg_type r)) ->
agree_callee_save ls ls0 ->
agree_regs j ls rs ->
let ls1 := LTL.undef_regs destroyed_at_function_entry (LTL.call_regs ls) in
let rs1 := undef_regs destroyed_at_function_entry rs in
exists rs', exists m',
star step tge
(State cs fb (Vptr sp Ptrofs.zero) (save_callee_save fe k) rs1 m)
E0 (State cs fb (Vptr sp Ptrofs.zero) k rs' m')
/\ m' |= contains_callee_saves j sp fe.(fe_ofs_callee_save) b.(used_callee_save) ls0 ** P
/\ (forall ofs k p, Mem.perm m sp ofs k p -> Mem.perm m' sp ofs k p)
/\ agree_regs j ls1 rs'.