Computation and correctness proof of global bounds.
Require Import Bool.
Require Import BinPos.
Require Import List.
Require Import TheoryList.
Require Import Arith.
Require Import Coqlib.
Require Import Integers.
Require Import Errors.
Require Import AST.
Require Import RTL.
Require Import Maps.
Require Import Registers.
Require Import Values.
Require Import Memory.
Require Import Events.
Require Import Op.
Require Import RTLPaths.
Require Import CountingSem.
Require Import Scope.
Require Import Counter.
Require Import DLib.
Require Import UtilBase.
Require Import HeaderBounds.
Require Import LocalBounds.
Require Import GlobalBounds.
Local Open Scope nat_scope.
Hint Immediate in_eq.
Hint Immediate in_cons.
Section FUNCTION.
Variable f :
function.
Variable fsc :
Scope.family f.
Variable sp :
val.
Variable ge :
genv.
Variable rs0:
regset.
Variable m0 :
mem.
Notation root :=
f.(
fn_entrypoint).
Notation header := (
Scope.header fsc).
Notation scope := (
Scope.scope fsc).
Notation parent := (
Scope.parent fsc).
Notation elements := (
Scope.elements fsc).
Notation inc_r_counter' := (
inc_r_counter f fsc).
Notation exited_scope' := (
exited_scopes fsc).
Notation pcs := (
map get_pc).
Notation "
a %
pc" := (
get_pc a) (
at level 1).
Notation "
a %
rs" := (
get_rs a) (
at level 1).
Notation "
a %
m" := (
get_mem a) (
at level 1).
Notation "
a %
cs" := (
get_cs a) (
at level 1).
Notation "
a %
rcs" := (
get_rcs a) (
at level 1).
Notation step' := (
cstep ge f fsc sp).
Notation Reach' := (
Reach ge f fsc sp rs0 m0).
Notation Trace' := (
Trace ge f fsc sp rs0 m0).
Lemma Trace_split:
forall n tr,
Trace'
tr ->
exists tr0,
exists trl,
tr =
flatten trl ++
tr0 /\
(
forall s',
In s'
tr0 ->
s'%
pc <>
n) /\
forall tr',
In tr'
trl ->
exists sn,
exists tr'',
tr' =
tr'' ++
sn ::
nil /\
sn%
pc =
n /\
(
forall s',
In s'
tr'' ->
s'%
pc <>
n).
Proof.
induction tr;
intros.
>
inv H.
>
inv H.
set (
s:=
init_st f rs0 m0).
destruct (
peq s%
pc n).
>
exists nil;
exists ((
s::
nil)::
nil);
split;
auto.
split;
intuition.
simpl in H;
intuition.
econstructor;
exists nil;
split;
eauto.
>
exists (
s::
nil);
exists nil;
split;
auto.
simpl;
intuition.
congruence.
>
edestruct IHtr as (
tr &
trl &
S1 &
S2 &
S3);
eauto.
destruct (
peq n a%
pc).
>
exists tr;
exists ((
a::
nil)::
trl);
intuition.
>
simpl;
congruence.
>
simpl in H0;
destruct H0;
eauto.
econstructor;
exists nil;
eauto.
>
destruct trl.
>
simpl in *.
exists (
a::
s::
tr0);
exists nil;
simpl in *;
intuition.
>
simpl;
congruence.
>
eelim S2;
eauto.
subst;
auto.
>
eelim S2;
eauto.
subst;
auto.
>
exists tr;
exists ((
a::
l)::
trl);
split.
>
rewrite S1;
auto.
>
intuition.
simpl in H0;
destruct H0;
eauto.
destruct (
S3 l)
as (
sn &
tr'' &
T1 &
T2 &
T3);
auto.
subst;
econstructor;
exists (
a::
tr'');
split;
eauto.
simpl;
eauto.
split;
auto.
simpl;
destruct 1;
eauto.
subst;
auto.
Qed.
Open Scope nat_scope.
Lemma nil_not_eq_app_cons:
forall A (
x:
A)
l l',
nil <>
l ++
x ::
l'.
Proof.
red;
intros.
assert (
length (
l++
x::
l') = 0).
rewrite <-
H;
auto.
generalize H0.
rewrite app_length.
simpl;
intros.
omega.
Qed.
Section parent.
Variable n :
node.
Variable n_f_In:
f_In n f.
Variable not_root:
header (
scope n) <>
root.
Let is_header (
n:
node) :=
n =
header (
scope n).
Variable n_is_header:
is_header n.
Let p :=
header (
parent (
scope n)).
Hypothesis parent_not_in_scope: ~
p ∈ (
scope n).
Variable M:
nat.
Hypothesis rcs_c_bound_by_M:
forall s tr,
Trace' (
s::
tr) ->
s %
rcs #
n <=
M.
Hypothesis rcs_c_bound_by_M':
forall s tr,
Trace' (
s::
tr) ->
s %
rcs #
n =
M ->
s%
pc <>
n.
Hypothesis M_strict_pos:
M>0.
Lemma rcs_max_prefix'
_out:
forall tr s,
Trace' (
s ::
tr) ->
~
s%
pc ∈ (
scope n) ->
s%
rcs #
n = 0.
Proof.
Lemma succ_not_in_last_exited_scope:
forall n0 n n',
n ∈ (
scope n0) ->
n' ∈ (
scope n0) ->
~
In n0 (
exited_scope'
n n').
Proof.
unfold exited_scopes;
intros.
rewrite in_flat_map.
intros (
sc &
S1 &
S2).
destruct In_dec;
simpl in S2;
try (
intuition;
fail).
destruct In_dec;
simpl in S2;
try (
intuition;
fail).
destruct n2.
eapply Scope.scope_least;
eauto.
Qed.
Hint Resolve step_succ_node Scope.in_scope Scope.scope_in_elements.
Lemma in_scope_after_header:
forall (
tr1:
list cstate) (
a sp:
cstate)
tr2,
~
sp%
pc ∈ (
scope n) ->
Trace' (
a ::
tr1 ++
sp ::
tr2) ->
a %
pc ∈ (
scope n) ->
exists s',
In s' (
a::
tr1) /\
s'%
pc =
n.
Proof.
Lemma In_tr:
forall (
s:
cstate)
tr,
In s tr ->
exists tr1,
exists tr2,
tr =
tr1 ++
s ::
tr2.
Proof.
induction tr;
simpl;
intuition.
subst;
exists nil;
simpl;
eauto.
destruct H as (
tr1 &
tr2 &
T);
exists (
a::
tr1);
subst;
simpl;
eauto.
Qed.
Lemma diff_cs_and_M:
forall (
sp:
cstate) (
tr2:
list cstate),
sp%
pc =
p ->
forall tr1 s,
Trace' (
s::
tr1++
sp::
tr2) ->
(
forall s',
In s'
tr1 ->
s'%
pc <>
p) ->
(
s %
cs #
n =
sp %
cs #
n /\ (
forall s',
In s'
tr1 ->
s'%
pc <>
n) /\
s %
rcs #
n = 0)
\/
(
s %
cs #
n =
s %
rcs #
n +
sp %
cs #
n /\
s%
pc ∈ (
scope n))
\/
(
exists k,
s %
cs #
n =
k +
sp %
cs #
n /\
k <=
M /\
exists sn,
In sn tr1 /\
sn%
pc =
n /\ ~
s%
pc ∈ (
scope n)).
Proof.
induction tr1;
simpl;
intros.
>
left;
intuition.
>
inv H0.
exploit step_cs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_counter;
rewrite PMap.gsspec;
destruct peq.
>
eelim parent_not_in_scope.
rewrite <-
H.
subst;
apply Scope.in_scope;
eauto.
>
reflexivity.
>
inv H0.
exploit step_rcs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_r_counter.
assert (
O:
forall x y,
x <=
y ->
y = 0 ->
x = 0)
by (
intros;
omega).
eapply O.
eapply reset_counters_le.
unfold inc_counter;
rewrite PMap.gsspec;
destruct peq.
>
eelim parent_not_in_scope.
rewrite <-
H;
subst.
apply Scope.in_scope;
eauto.
>
eapply rcs_max_prefix'
_out;
eauto.
rewrite H;
auto.
>
inv H0.
exploit IHtr1;
eauto;
intros IHtr;
clear IHtr1.
exploit step_cs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_counter;
rewrite PMap.gsspec;
destruct peq.
>
right.
destruct IHtr as [
IH | [
IH |
IH]].
>
destruct IH as (
IH1 &
IH2 &
IH3).
subst;
rewrite IH1.
destruct (
In_dec (
s%
pc) (
scope a%
pc)).
>
left;
split;
auto.
replace (
s%
rcs#(
a%
pc))
with 1;
try omega.
exploit step_rcs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_r_counter.
rewrite reset_counters_inv_out.
>
rewrite inc_counter_new;
auto;
omega.
>
apply succ_not_in_last_exited_scope;
auto.
>
right;
exists 1;
split;
try omega.
split;
try omega.
exists a;
auto.
>
destruct IH as (
IH1 &
IH2).
subst;
rewrite IH1.
destruct (
In_dec (
s%
pc) (
scope a%
pc)).
>
left;
split;
auto.
replace (
s%
rcs#(
a%
pc))
with (
a%
rcs#(
a%
pc)+1);
try omega.
exploit step_rcs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_r_counter.
rewrite reset_counters_inv_out.
>
rewrite inc_counter_new;
auto;
omega.
>
apply succ_not_in_last_exited_scope;
auto.
>
assert ((
a %
rcs) # (
a %
pc) <=
M)
by eauto with datatypes.
assert (((
a %
rcs) # (
a %
pc) <
M)\/((
a %
rcs) # (
a %
pc) =
M))
by omega.
destruct H2.
>
right;
exists (
a%
rcs#(
a%
pc)+1);
split;
try omega.
split;
try omega.
eauto.
>
elim rcs_c_bound_by_M'
with (1:=
H4) (
s:=
a);
auto.
>
destruct IH as (
k &
IH1 &
IH2 &
sn &
IH3 &
IH4 &
IH5).
elim IH5;
try congruence.
rewrite <-
e;
apply Scope.in_scope;
eauto.
>
destruct IHtr as [
IH | [
IH |
IH]].
>
destruct IH as (
IH1 &
IH2 &
IH3).
subst;
rewrite IH1.
left;
split;
auto.
split.
>
destruct 1;
auto;
congruence.
>
exploit step_rcs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_r_counter.
assert (
O:
forall x y,
x <=
y ->
y = 0 ->
x = 0)
by (
intros;
omega).
eapply O.
eapply reset_counters_le.
rewrite inc_counter_old;
auto.
>
destruct IH as (
IH1 &
IH2).
subst;
rewrite IH1.
destruct (
In_dec (
s%
pc) (
scope n)).
>
right;
left;
split;
auto.
replace (
s%
rcs#
n)
with (
a%
rcs#
n);
try omega.
exploit step_rcs;
eauto;
intros HS;
rewrite HS;
clear HS.
unfold inc_r_counter.
rewrite reset_counters_inv_out.
>
rewrite inc_counter_old;
auto.
>
apply succ_not_in_last_exited_scope;
auto.
>
assert (
exists sn,
In sn tr1 /\
sn%
pc=
n).
elim in_scope_after_header with (2:=
H4);
eauto.
simpl;
destruct 1.
destruct H0;
subst;
eauto;
intuition.
rewrite H;
auto.
destruct H0 as (
sn &
S1 &
S2).
>
right;
right;
exists (
a%
rcs#
n);
split;
try omega.
split;
try omega.
>
exploit rcs_c_bound_by_M;
eauto.
>
eauto.
>
destruct IH as (
k &
IH1 &
IH2 &
sn &
IH3 &
IH4 &
IH5).
right;
right.
exists k;
split;
auto.
split;
try omega.
exists sn;
split;
auto.
split;
auto.
intro.
assert (
s%
pc =
header (
scope n)).
>
apply enter_in_scope_at_header_only1 with a%
pc;
eauto.
elim In_tr with (1:=
IH3);
intros tr1' (
tr2' &
T);
subst.
assert (
Trace' (
nil ++
s :: (
a::
tr1') ++
sn :: (
tr2' ++
sp0 ::
tr2))).
>
rewrite app_ass in H4;
simpl in *;
econstructor;
eauto.
exploit Trace_split_rev_path;
eauto.
simpl;
rewrite map_app;
simpl.
unfold get_pc';
intros.
assert (
sn%
pc =
s%
pc)
by congruence.
rewrite H7 in *.
edestruct Scope.cycle_at_header with (3:=
H5);
eauto.
congruence.
simpl in H8;
destruct H8.
>
eelim H1;
eauto.
>
rewrite in_app in H8;
destruct H8;
eauto.
>
rewrite in_map_iff in H8.
destruct H8 as (
st &
S1 &
S2).
elim (
H1 st);
eauto with datatypes.
>
simpl in H8;
intuition.
elim (
H1 sn);
eauto with datatypes.
congruence.
Qed.
Lemma diff_cs_and_M_final:
forall (
sp:
cstate)
tr2,
sp%
pc =
p ->
forall tr1 s,
Trace' (
s::
tr1++
sp::
tr2) ->
(
forall s',
In s'
tr1 ->
s'%
pc <>
p) ->
exists k,
s %
cs #
n =
k +
sp %
cs #
n /\
k <=
M.
Proof.
intros;
exploit diff_cs_and_M;
eauto.
destruct 1
as [
I | [
I |
I]].
>
destruct I as (
I1 &
I2).
exists O;
split;
omega.
>
destruct I as (
I1 &
I2).
econstructor;
split;
eauto.
exploit rcs_c_bound_by_M;
eauto.
>
destruct I as (
k &
I1 &
I2 &
sn &
I3 &
I4 &
I5).
exists k;
omega.
Qed.
Lemma Trace_sc_zero:
forall n tr s,
Trace' (
s::
tr) ->
(
forall s',
In s'
tr ->
s'%
pc <>
n) ->
s%
cs #
n = 0.
Proof.
Lemma Trace_sc_same:
forall s0 tr2 n tr1 s,
Trace' (
s::
tr1++
s0::
tr2) ->
(
forall s',
In s'
tr1 ->
s'%
pc <>
n) ->
forall s',
In s'
tr1 ->
s%
cs #
n =
s'%
cs #
n.
Proof.
induction tr1;
simpl;
intros.
>
intuition.
>
inv H.
exploit step_cs;
eauto;
intros R;
rewrite R.
destruct H1.
>
subst.
rewrite inc_counter_old;
auto.
>
rewrite inc_counter_old;
auto.
Qed.
Lemma header_dominates:
forall n tr0 s,
f_In n f ->
Trace' (
s::
tr0) ->
s%
pc ∈ (
scope n) ->
header (
scope n) =
root \/
exists s0,
In s0 (
s::
tr0) /\
header (
scope n) =
s0%
pc.
Proof.
induction tr0;
simpl;
intuition.
>
inv H0.
unfold init_st in *;
simpl in *.
exploit Scope.in_scope_root;
eauto.
>
inv H0.
destruct (
In_dec a%
pc (
scope n0)).
>
exploit IHtr0;
eauto.
destruct 1;
eauto.
destruct H0 as (
s0 &
S1 &
S2);
eauto.
>
right;
exists s;
split;
auto.
symmetry.
apply enter_in_scope_at_header_only1 with a%
pc;
eauto.
Qed.
Lemma header_dominates2:
forall n tr0 s s1,
f_In n f ->
Trace' (
s1::
tr0) ->
In s tr0 ->
s%
pc ∈ (
scope n) ->
header (
scope n) =
root \/
exists s0,
In s0 (
tr0) /\
header (
scope n) =
s0%
pc.
Proof.
induction tr0;
simpl;
intuition.
>
inv H0.
exploit header_dominates;
eauto.
>
inv H0.
exploit IHtr0;
eauto.
destruct 1;
eauto.
destruct H0 as (
s0 &
S1 &
S2);
eauto.
Qed.
Lemma parent_dominates_aux:
forall n tr0 s,
f_In n f ->
Trace' (
s::
tr0) ->
s%
pc ∈ (
scope n) ->
header (
scope n) =
root \/
exists s0,
In s0 tr0 /\
parent (
scope n) =
scope s0%
pc /\
f_In s0%
pc f.
Proof.
Lemma init_st_in_Trace:
forall tr,
Trace'
tr ->
exists s0,
In s0 tr /\
s0%
pc =
root.
Proof.
induction tr; intros.
> inv H.
> inv H.
> econstructor; simpl; split; eauto.
> destruct IHtr as (s1 & S1 & S2); auto.
econstructor; split.
right; eauto.
auto.
Qed.
Lemma parent_dominates:
forall tr0 s,
Trace' (
s::
tr0) ->
(
forall s',
In s'
tr0 ->
s'%
pc <>
p) ->
(
forall s',
In s'
tr0 -> ~
s'%
pc ∈ (
scope n)).
Proof.
induction tr0;
simpl;
intuition.
>
subst.
inv H.
exploit parent_dominates_aux;
eauto.
destruct 1;
auto.
destruct H as (
s0 &
S1 &
S2 &
S3).
exploit (
header_dominates2 s0%
pc);
eauto.
destruct 1.
>
assert (
p=
root)
by (
unfold p in *;
congruence).
elim init_st_in_Trace with (1:=
H4);
intros ss0 (
SS1 &
SS2).
elim H0 with ss0;
auto.
congruence.
>
destruct H as (
s1 &
S5 &
S4).
elim H0 with s1;
eauto.
unfold p in *;
congruence.
>
inv H;
exploit IHtr0;
eauto.
Qed.
Lemma global_bound_almost:
forall tr0 trl s,
Trace' (
s::
flatten trl ++
tr0) ->
(
forall s',
In s'
tr0 ->
s'%
pc <>
p) ->
(
forall tr',
In tr'
trl ->
exists sn,
exists tr'',
tr' =
tr'' ++
sn ::
nil /\
sn%
pc =
p /\
(
forall s',
In s'
tr'' ->
s'%
pc <>
p)) ->
s%
cs #
n <= (
length trl) *
M.
Proof.
induction trl;
simpl;
intros.
>
assert (
forall s',
In s'
tr0 ->
s'%
pc <>
n).
red;
intros.
eelim parent_dominates with (1:=
H);
eauto.
rewrite H3;
auto.
erewrite Trace_sc_zero;
eauto.
>
edestruct (
H1 a)
as (
sn &
tr'' &
T1 &
T2 &
T3);
eauto.
subst a.
assert (
Trace' (
sn::
flatten trl ++
tr0)).
generalize H.
repeat (
rewrite app_ass;
simpl);
intros.
apply Trace_app with (
s::
tr'');
auto.
exploit IHtrl;
eauto;
intros IH;
clear IHtrl H2.
rewrite (
app_ass tr'')
in H.
simpl in H.
rewrite app_ass in H.
simpl in H.
edestruct diff_cs_and_M_final as (
k &
K1 &
K2);
eauto.
omega.
Qed.
Lemma app_cons_case:
forall A (
l:
list A),
l =
nil \/
exists x,
exists q,
l =
q ++
x ::
nil.
Proof.
induction l;
simpl;
auto.
right;
destruct IHl.
>
subst l;
econstructor;
exists nil;
simpl;
eauto.
>
destruct H as (
x &
q &
H1).
exists x;
exists (
a::
q);
simpl;
congruence.
Qed.
Lemma cs_parent_length:
forall tr0 trl s,
Trace' (
s::
flatten trl ++
tr0) ->
(
forall s',
In s'
tr0 ->
s'%
pc <>
p) ->
(
forall tr',
In tr'
trl ->
exists sn,
exists tr'',
tr' =
tr'' ++
sn ::
nil /\
sn%
pc =
p /\
(
forall s',
In s'
tr'' ->
s'%
pc <>
p)) ->
s%
cs #
p =
length trl.
Proof.
induction trl;
simpl;
intros.
>
erewrite Trace_sc_zero;
eauto.
>
edestruct (
H1 a)
as (
sn &
tr'' &
T1 &
T2 &
T3);
eauto.
subst a.
assert (
Trace' (
sn::
flatten trl ++
tr0)).
>
generalize H.
repeat (
rewrite app_ass;
simpl);
intros.
apply Trace_app with (
s::
tr'');
auto.
exploit IHtrl;
eauto;
intros IH;
clear IHtrl H2.
rewrite (
app_ass tr'')
in H.
simpl in H.
rewrite app_ass in H.
simpl in H.
destruct (
app_cons_case _ tr'')
as [
Ha |(
x &
q &
Ha)].
>
subst tr''.
inv H.
rewrite <-
T2.
exploit step_cs;
eauto;
intros R;
rewrite R;
clear R.
rewrite inc_counter_new;
auto.
rewrite T2;
omega.
>
subst tr''.
exploit Trace_sc_same;
eauto with datatypes.
intros HH.
assert (
Trace' (
x ::
sn::
flatten trl ++
tr0)).
>
generalize H.
repeat (
rewrite app_ass;
simpl);
intros.
apply Trace_app with (
s::
q);
auto.
assert (
step'
sn x).
>
inv H2;
auto.
rewrite HH.
exploit step_cs;
eauto;
intros R;
rewrite R;
clear R.
rewrite T2.
rewrite inc_counter_new;
auto.
omega.
Qed.
Lemma 3 in the paper: global_bound.
It relates local and global bounds for a given scope header.
Lemma global_bound:
(* Lemma 3 *)
forall tr s,
Trace' (
s::
tr) ->
s%
cs #
n <=
s %
cs #
p *
M.
Proof.
intros.
inv H.
>
unfold init_st;
simpl.
repeat rewrite init_counters_zero;
omega.
>
exploit (
Trace_split p);
eauto.
intros (
tr &
trl &
T1 &
T2 &
T3).
assert (
Trace' (
s ::
s0 ::
tr0))
by (
econstructor;
eauto).
rewrite T1 in *.
exploit cs_parent_length;
eauto;
intros HL.
exploit global_bound_almost;
eauto.
rewrite <-
HL;
auto.
Qed.
End parent.
End FUNCTION.
Require Import String.
Require Import Maps.
Require Import RTLWfFunction.
Require Import Sliceproof.
Require Import SliceCFG.
Require Import SliceGen.
Require Import WCETSlice.
Open Scope Z_scope.
Section BOUND_CORRECT.
Variable f:
function.
Variable fsc:
Scope.family f.
Variable exit_n :
node.
Variable reg_vint :
reg.
Hypothesis WFF:
check_wf f =
OK (
exit_n,
reg_vint).
Lemma fold_bound_rec_error:
forall A B g l e,
@
fold_left (
res B)
A
(
fun eacc sc' =>
do acc <-
eacc;
g sc'
acc)
l
(
Error e) =
Error e.
Proof.
induction l; simpl; intros; auto.
Qed.
Lemma bound_rec_acc:
forall fuel sc bmap bmap',
bound_rec f fsc exit_n reg_vint fuel sc bmap =
OK bmap' ->
forall n b,
bmap!
n =
Some b ->
bmap'!
n =
Some b.
Proof.
Definition correct_bound (
n:
node) (
b:
Z) :
Prop :=
(
forall ge sp tr rs m s,
f_In n f ->
Reaches_final ge f fsc sp rs m ->
Trace ge f fsc sp rs m (
s::
tr) -> (
Z_of_nat (
get_cs s) #
n) <=
b) /\
b > 0.
Theorem local_bound_pos :
forall f (
fsc:
Scope.family f)
n bound,
local_bound f fsc n =
OK bound ->
bound > 0.
Proof.
Lemma cs_root:
forall ge sp rs m s,
Reach ge f fsc sp rs m s ->
Z_of_nat ((
get_cs s) # (
f.(
fn_entrypoint))) <= 1.
Proof.
Lemma bound_rec_correct:
forall fuel sc bmap bmap',
bound_rec f fsc exit_n reg_vint fuel sc bmap =
OK bmap' ->
In sc (
Scope.elements fsc) ->
(
forall n b,
bmap!
n =
Some b ->
correct_bound n b) ->
(
forall n b,
bmap'!
n =
Some b ->
correct_bound n b).
Proof.
End BOUND_CORRECT.
Theorem 1 in the paper: bound_correct. It states
the correctness of the method with respect to the instrumented RTL
semantics.
Theorem bound_correct:
(* Theorem 1 *)
forall f bmap,
bound f =
OK bmap ->
exists fsc,
forall ge sp rs m,
Reaches_final ge f fsc sp rs m ->
forall s,
Reach ge f fsc sp rs m s ->
forall n,
f_In n f ->
forall b,
bmap n =
Some b ->
(
Z_of_nat (
get_cs s) #
n) <=
b.
Proof.