diff --git a/_CoqProject b/_CoqProject index cd6ca145b88ab6ad97b83d19aaaa1f530e3f288e..acf17cdb922c3150dc58ad290989d26c0990fff6 100644 --- a/_CoqProject +++ b/_CoqProject @@ -1,5 +1,5 @@ -R src/ StoreBuffer -src/definitions.v src/utils.v -src/store_buffer.v -src/correct_store_buffer.v +src/modular_definitions.v +src/fivestage.v +src/modular_store_buffer.v diff --git a/src/definitions.v b/src/definitions.v index 69261dfdd96f094fb165e5c44601c7de295fdbbf..122ca502c4af00283ee818cec3951597ee369f9d 100644 --- a/src/definitions.v +++ b/src/definitions.v @@ -3,6 +3,7 @@ (* They may or may not be useful… *) Require Import Bool List Nat PeanoNat. +From Coq.Arith Require Import Plus. Import ListNotations. (* Basic definitions: opcodes, stages, store buffer state. *) @@ -12,18 +13,6 @@ Variant opcode := Scheme Equality for opcode. -Definition is_load opc := - match opc with - | Load _ => True - | Store => False - end. - -Definition is_store opc := - match opc with - | Load _ => False - | Store => True - end. - Variant stage := | Sp | Lsu @@ -46,17 +35,7 @@ Definition nstg s opc := | _, _ => Sn end. -(* Specification for stage comparison. Sp < Lsu < (Lu, Su) < Sn. *) -Inductive le : stage -> stage -> Prop := -| le_refl : forall x, le x x -| le_trans : forall x y z, le x y -> le y z -> le x z -| le_Sp_Lsu : le Sp Lsu -| le_Lsu_Lu : le Lsu Lu -| le_Lsu_Su : le Lsu Su -| le_Lu_Sn : le Lu Sn -| le_Su_Sn : le Su Sn. - -(* Should be the same, but with booleans this time. *) +(* Boolean stage comparison. Sp < Lsu < (Lu, Su) < Sn. *) Definition leb x y := match x, y with | Sp, _ => true @@ -70,51 +49,6 @@ Definition leb x y := | Su, _ => false end. -Ltac destruct_stages := - repeat match goal with - | [ x : stage |- _ ] => destruct x - end. - -(* Prove that le and leb are the same. *) -Theorem le_iff_leb : forall x y, le x y <-> leb x y = true. -Proof. - intros x y. - split; - intro H. - - (* le implies leb *) - - induction H; - destruct_stages; - (reflexivity || discriminate). - - (* leb implies le *) - - destruct_stages; - try discriminate; - eauto using le. -Qed. - -Theorem le_antisym : forall x y, le x y -> le y x -> x = y. -Proof. - intros x y H1 H2. - rewrite le_iff_leb in H1, H2. - destruct x, y; - reflexivity || discriminate. -Qed. - -(* nstg yields a better stage. *) -Theorem nstg_is_leb : forall s o, leb s (nstg s o) = true. -Proof. - intros s o. - - (* Enumerate all stages *) - destruct s eqn:Hs; - match goal with - (* Trivial for all cases, except Lsu: depends on the opcode *) - | [ _ : s = Lsu |- _ ] => destruct o; reflexivity - | _ => reflexivity - end. -Qed. - Variant sbStateT := | Empty | NotEmpty @@ -168,205 +102,117 @@ Definition compare_two (e1 e2 : option instr_kind) := Lemma compare_two_eq_true : forall e, e <> None -> compare_two e e = true. Proof. intros e Hn. - destruct e. - - destruct i. + destruct e as [i |]. + - (* e = Some i *) + destruct i as [o s]. simpl. + (* state_leb s s = true, we have a lemma for this. *) now rewrite state_leb_eq_true. - - contradiction. -Qed. - -Definition get_opc (trace : trace_kind) := - fst (List.split trace). - -Definition get_stg (trace : trace_kind) := - fst (List.split (snd (List.split trace))). - -Definition get_cyc (trace : trace_kind) := - snd (List.split (snd (List.split trace))). - -Lemma opc_length : forall t, List.length (get_opc t) = List.length t. -Proof. - intro t. - unfold get_opc. - apply List.split_length_l. -Qed. - -Lemma stg_length : forall t, List.length (get_stg t) = List.length t. -Proof. - intro t. - unfold get_stg. - rewrite List.split_length_l. - apply List.split_length_r. -Qed. - -Lemma cyc_length : forall t, List.length (get_cyc t) = List.length t. -Proof. - intro t. - unfold get_cyc. - rewrite List.split_length_r. - apply List.split_length_r. -Qed. - -Lemma kind_is_valid : - forall t i, i < List.length t -> List.nth_error (get_opc t) i <> None. -Proof. - intros t i Hl. - assert (Hl' := Hl). - now rewrite <- opc_length, <- (nth_error_Some (get_opc t) i) in Hl. -Qed. - -Lemma stage_is_valid : - forall t i, i < List.length t -> List.nth_error (get_stg t) i <> None. -Proof. - intros t i Hl. - assert (Hl' := Hl). - now rewrite <- stg_length, <- (nth_error_Some (get_stg t) i) in Hl. -Qed. - -Lemma cycle_is_valid : - forall t i, i < List.length t -> List.nth_error (get_cyc t) i <> None. -Proof. - intros t i Hl. - assert (Hl' := Hl). - now rewrite <- cyc_length, <- (nth_error_Some (get_cyc t) i) in Hl. -Qed. - -Lemma not_some_0_is_some_n : - forall i t, i < List.length t -> - List.nth_error (get_cyc t) i <> Some 0 -> - exists n, List.nth_error (get_cyc t) i = Some n. -Proof. - intros i t Hi Hzero. - - assert (nth_error (get_cyc t) i <> None) as Hnone. - - now apply cycle_is_valid. - - - destruct nth_error. - + exists n. - reflexivity. - + contradiction. + - (* None <> None. *) + contradiction. Qed. (* Pipeline comparison. *) +Definition instrs_leb (instrs : (instr_kind * instr_kind)) := + match instrs with + | ((_, st1), (_, st2)) => state_leb st1 st2 + (* | ((o1, st1), (o2, st2)) => opcode_beq o1 o2 && state_leb st1 st2 *) + end. + Definition pipeline_leb p1 p2 := let comb := List.combine p1 p2 in - Nat.eqb (List.length p1) (List.length p2) - && List.forallb (fun instrs => - match instrs with - | ((o1, st1), (o2, st2)) => opcode_beq o1 o2 && state_leb st1 st2 - end) comb. - -(* Pipeline validity. *) -Definition single_in_stage trace st := - List.count_occ stage_eq_dec (get_stg trace) st <=? 1. - -Definition check_latencies trace := - List.forallb (fun (elt : instr_kind) => - match elt with - | (_, (_, 0)) - | (_, (Lu, S _)) => true - | (_, (_, S _)) => false - end) trace. - -Definition check_loads_and_stores trace := - List.forallb (fun (elt : instr_kind) => - match elt with - | (Load _, (Su, _)) - | (Store, (Lu, _)) => false - | _ => true - end) trace. - -Lemma check_latencies_is_correct_v0 : - forall t t1 t2, t = t1 ++ t2 -> - check_latencies t = (check_latencies t1 && check_latencies t2). -Proof. - intros t t1 t2 Ht. - unfold check_latencies. - rewrite Ht. - apply forallb_app. -Qed. - -Lemma check_loads_and_stores_is_correct_v0 : - forall t t1 t2, t = t1 ++ t2 -> - check_loads_and_stores t = (check_loads_and_stores t1 && check_loads_and_stores t2). -Proof. - intros t t1 t2 Ht. - unfold check_loads_and_stores. - rewrite Ht. - apply forallb_app. -Qed. - -Section check_correctness. - Variable t t1 t2 tstep : trace_kind. - Variable e : instr_kind. - Variable opc : opcode. - Variable lat : nat. - - Hypothesis Ht : t = t1 ++ e :: t2. - Hypothesis Htstep : tstep = e :: t2. - - Lemma check_latencies_is_correct_v1 : - e = (opc, (Lu, lat)) -> check_latencies t = (check_latencies t1 && check_latencies t2). - Proof. - intro He. - - rewrite <- Htstep in Ht. - rewrite (check_latencies_is_correct_v0 _ t1 tstep). - - rewrite (check_latencies_is_correct_v0 tstep [e] t2). - + rewrite He. - now destruct lat. - + exact Htstep. - - exact Ht. + Nat.eqb (List.length p1) (List.length p2) && List.forallb instrs_leb comb. + +Section pipeline_comparison. + Variable t t' : trace_kind. + Variable i : nat. + Variable d : instr_kind. + + Hypothesis Hct : compare_two (List.nth_error t i) (List.nth_error t' i) = true. + + Lemma compare_two_true_means_exists : + (exists e, List.nth_error t i = Some e) + /\ (exists e, List.nth_error t' i = Some e). + split. + - (* First case. *) + destruct (nth_error t _). + + now exists i0. (* Some i0 = Some e -> i0 = e. *) + + discriminate. (* compare_two None ... = true is a contradiction. *) + + - (* Second case. *) + destruct (nth_error t' _). + + now exists i0. (* Some i0 = Some e -> i0 = e. *) + + (* compare_two ... None = true is a contradiction, with extra steps. *) + destruct (nth_error t _). + * simpl in Hct. + destruct i0. + discriminate. + * discriminate. Qed. - Lemma check_latencies_is_correct_v2 : - forall stage n, stage <> Lu -> e = (opc, (stage, S n)) -> check_latencies t = false. + Lemma compare_two_true_means_instrs_leb : + instrs_leb (List.nth i t d, List.nth i t' d) = true. Proof. - intros stage n Hs He. - - rewrite <- Htstep in Ht. - rewrite (check_latencies_is_correct_v0 _ t1 tstep). - - rewrite (check_latencies_is_correct_v0 tstep [e] t2). - + rewrite He. - destruct stage; - contradiction || (rewrite andb_comm; apply andb_false_l). - + exact Htstep. - - exact Ht. - Qed. + destruct compare_two_true_means_exists as [Hec Hec']. + destruct Hec as [ec Hnth], Hec' as [ec' Hnth']. + rewrite Hnth, Hnth' in Hct. - Lemma check_loads_and_stores_is_correct_v1 : - forall n, e = (Load n, (Su, lat)) -> check_loads_and_stores t = false. - Proof. - intros n He. - - rewrite <- Htstep in Ht. - rewrite (check_loads_and_stores_is_correct_v0 t t1 tstep). - - rewrite (check_loads_and_stores_is_correct_v0 tstep [e] t2). - + now rewrite He, andb_comm. - + exact Htstep. - - exact Ht. + now rewrite (nth_error_nth t i d Hnth), (nth_error_nth t' i d Hnth'). Qed. - - Lemma check_loads_and_stores_is_correct_v2 : - e = (Store, (Lu, lat)) -> check_loads_and_stores t = false. - Proof. - intro He. - - rewrite <- Htstep in Ht. - rewrite (check_loads_and_stores_is_correct_v0 t t1 tstep). - - rewrite (check_loads_and_stores_is_correct_v0 tstep [e] t2). - + now rewrite He, andb_comm. - + exact Htstep. - - exact Ht. - Qed. -End check_correctness. - -Definition valid trace := - single_in_stage trace Lsu - && single_in_stage trace Lu - && single_in_stage trace Su - && check_latencies trace - && check_loads_and_stores trace. +End pipeline_comparison. + +Lemma combine_app : + forall (A B : Type) (l1 l2 : list A) (l1' l2' : list B), + length l1 = length l1' -> + combine (l1 ++ l2) (l1' ++ l2') = combine l1 l1' ++ combine l2 l2'. +Proof. + intros A B l1 l2. + + induction l1 as [| a l1 IHl1]; + destruct l1'. + - reflexivity. + - discriminate. + - discriminate. + - simpl. + intros l2' Hlength. + rewrite IHl1. + + reflexivity. + + now apply eq_add_S. +Qed. + +Lemma pipeline_sub_is_leb : + forall (t t' tpre tpre' tpost tpost' : trace_kind) (e e' : instr_kind), + List.length t = List.length t' -> List.length tpre = List.length tpre' -> + t = tpre ++ e :: tpost -> t' = tpre' ++ e' :: tpost' -> + pipeline_leb t t' = true -> + pipeline_leb tpre tpre' = true /\ pipeline_leb tpost tpost' = true /\ + (let (_, st1) := e in let (_, st2) := e' in state_leb st1 st2) = true. +Proof. + intros t t' tpre tpre' tpost tpost' e e' Hlength Hlength' Ht Ht' Hleb. + + unfold pipeline_leb in Hleb |- *. + rewrite andb_true_iff, Nat.eqb_eq in Hleb |- *. + destruct Hleb as [_ Hforall]. + rewrite Ht, Ht', combine_app, forallb_app, andb_true_iff in Hforall; + [| exact Hlength']. + + destruct Hforall as [Hfpre Hfpost]. + simpl in Hfpost. + rewrite andb_true_iff in Hfpost. + destruct Hfpost as [He Hfpost]. + + split. + - now split. + - rewrite andb_true_iff, Nat.eqb_eq. + split; + try split; + try assumption. + + rewrite Ht, Ht', app_length, app_length, Hlength' in Hlength. + apply plus_reg_l in Hlength. + simpl in Hlength. + auto. +Qed. (* Helper functions, may be useful to all implementations. *) (* Check if an instruction is in a stage. *) @@ -376,8 +222,6 @@ Definition is_in_stage st (instr : instr_kind) := end. (* Ready-to-use functions. *) -Definition is_in_lsu := is_in_stage Lsu. -Definition is_in_lu := is_in_stage Lu. Definition is_in_su := is_in_stage Su. Definition get_instr_in_stage trace st := List.find (is_in_stage st) trace. diff --git a/src/fivestage.v b/src/fivestage.v new file mode 100644 index 0000000000000000000000000000000000000000..5926e9f6cc7e73ed41caf1bc2a9801bef72234fb --- /dev/null +++ b/src/fivestage.v @@ -0,0 +1,423 @@ +Require Import Bool Lia List Nat PeanoNat. +From StoreBuffer Require Import utils modular_definitions. +Import ListNotations. + +Module FiveStageSig <: Sig. + Variant opcode_fs := + | Load (dlat : nat) (id : nat) + | Store (id : nat) + | Other (id : nat). + + Variant stage_fs := + | Pre + | Ex + | Mem + | Wb + | Post. + + Definition first_stage := Pre. + + Scheme Equality for opcode_fs. + Definition opcode := opcode_fs. + Definition opcode_beq := opcode_fs_beq. + Definition opcode_eq_dec := opcode_fs_eq_dec. + + Scheme Equality for stage_fs. + Definition stage := stage_fs. + Definition stage_beq := stage_fs_beq. + Definition stage_eq_dec := stage_fs_eq_dec. + + Lemma stage_beq_eq_true : forall s, stage_beq s s = true. + Proof. + now destruct s. + Qed. + + (* Boolean stage comparison. Pre < Ex < Mem < Wb < Post. *) + Definition leb x y := + match x, y with + | Pre, _ => true + | Ex, Pre => false + | Ex, _ => true + | Mem, Pre => false + | Mem, Ex => false + | Mem, _ => true + | Wb, Wb => true + | Wb, Post => true + | Wb, _ => false + | Post, Post => true + | Post, _ => false + end. +End FiveStageSig. + +Module FiveStage := Pipeline FiveStageSig. +Export FiveStage. + +Definition nstg s := + match s with + | Pre => Ex + | Ex => Mem + | Mem => Wb + | _ => Post + end. + +Definition busFree := sbStateT_beq Empty. + +(* ready, free, and cycle functions. *) +Definition ready next_id sbState (elt : instr_kind) := + match elt with + | (_, (_, S _)) => false + | (Store _, (Mem, 0)) => negb (sbStateT_beq Full sbState) + | (Load _ _, (Ex, 0)) => busFree sbState + | (opc, (Pre, 0)) => idx opc =? next_id + | _ => true + end. + +Definition memFree next_id sbState trace := + let instr := get_instr_in_stage trace Mem in + match instr with + | Some elt => ready next_id sbState elt + | None => true + end. + +Definition exFree next_id sbState trace := + let instr := get_instr_in_stage trace Ex in + match instr with + | Some elt => ready next_id sbState elt && memFree next_id sbState trace + | None => true + end. + +Definition free next_id sbState trace (elt : instr_kind) := + let (opc, state) := elt in + let (st, _) := state in + match nstg st with + | Mem => memFree next_id sbState trace + | Ex => exFree next_id sbState trace + | _ => true + end. + +Definition get_latency opc st := + match opc, st with + | Load n _, Mem => n + | _, _ => 0 + end. + +Definition cycle_elt next_id sbState trace elt := + match elt with + | (opc, (st, S n)) => (opc, (st, n)) + | (opc, (st, 0)) => + if ready next_id sbState elt && free next_id sbState trace elt then + let nstg := nstg st in + (opc, (nstg, get_latency opc nstg)) + else + elt + end. + +Definition cycle sbState trace := + List.map (cycle_elt (next_id trace) sbState trace) trace. + +Definition legal_sb_transitions st sbState sbState' := + match st, sbState with + | Mem, NotEmpty => sbState' = NotEmpty \/ sbState' = Empty + | Mem, Empty => sbState' = Empty + | _, _ => sbState' = Full \/ sbState' = NotEmpty \/ sbState' = Empty + end. + +Lemma next_stage_is_higher : forall opc st st', + st' = nstg st -> + compare_two (Some (opc, (st, 0))) + (Some (opc, (st', get_latency opc st'))) = true. +Proof. + intros opc st st' Hst'. + rewrite Hst'. + now destruct st; + [..| destruct opc]. +Qed. + +Lemma opc_match_case_identical : forall (A : Type) (a : A) opc, + match opc with | Load _ _ | _ => a end = a. +Proof. + intros A a opc. + now destruct opc. +Qed. + +Section monotonicity. + Variable opc : opcode. + Variable d : instr_kind. + Variable st st' : stage. + Variable t tpre tpost t' tpre' tpost' tc tc' : trace_kind. + Variable sbState sbState' : sbStateT. + + Hypothesis Hleb : pipeline_leb t t' = true. + Hypothesis Hl : pipeline_leb tpre tpre' = true. + Hypothesis Hl' : pipeline_leb tpost tpost' = true. + Hypothesis Htc : tc = cycle sbState t. + Hypothesis Htc' : tc' = cycle sbState' t'. + Hypothesis Hlsbt : legal_sb_transitions st sbState sbState'. + Hypothesis HnId : next_id t <= next_id t'. + + Hypothesis HnIdLow : forall t (e : instr_kind), + match e with + | (opc, (st, _)) => idx opc < next_id t <-> st <> Pre + end. + Hypothesis HnIdHigh : forall t (e : instr_kind), + match e with + | (opc, (st, _)) => idx opc >= next_id t <-> st = Pre + end. + + Hypothesis HfreePersists : + forall (st : stage), free (next_id t) sbState t (opc, (st, 0)) = true -> + free (next_id t') sbState' t' (opc, (st, 0)) = true. + + Hypothesis HbusFree : + forall st, st = Ex -> busFree sbState = true -> busFree sbState' = true. + + Hypothesis HvalidLat : forall (e : instr_kind), + match e with + | (_, (st, 0)) => True + | (Load dlat _, (st, n)) => st = Mem /\ n <= dlat + | (_, (st, S _)) => False + end. + + Section simple_monotonicity. + Variable e e' : instr_kind. + Variable i : nat. + + Hypothesis Ht : t = tpre ++ e :: tpost. + Hypothesis Ht' : t' = tpre' ++ e' :: tpost'. + Hypothesis Hi : i = List.length tpre. + Hypothesis Hi' : i = List.length tpre'. + + Ltac work_on_e He' := + rewrite Htc, Htc', Ht; + match type of He' with + | e = e' => + rewrite Ht', <- He' in HfreePersists, HnId |- * + | e <> e' => + rewrite Ht' + end; + unfold cycle; + rewrite (map_in_the_middle _ _ e d _ _ tpre tpost _ eq_refl Hi), + (map_in_the_middle _ _ _ d _ _ tpre' tpost' _ eq_refl Hi'); + unfold cycle_elt; + rewrite <- Ht; + match type of He' with + | e = e' => + subst e + | e <> e' => + rewrite <- Ht'; + subst e; + subst e' + end. + + Lemma unmoved_no_lat_can_advance : + e = (opc, (st, 0)) -> e = e' -> forall n, + List.nth_error tc i = Some (opc, (nstg st, n)) -> + List.nth_error tc' i = Some (opc, (nstg st, n)). + Proof. + intros He He' n. + specialize (HfreePersists st). + specialize (HbusFree st). + specialize (HnIdLow t' e'). + specialize (HnIdHigh t' e'). + + rewrite Ht', <- He' in HnIdLow, HnIdHigh. + + (* Delve onto e, then handle stages on a case-by-case basis. *) + work_on_e He'. + destruct st; + (* Solve Wb and Post automatically. *) + [..| auto | auto]. + + (* Pre. *) + - destruct free. + + destruct free; + [| now discriminate HfreePersists]. + + simpl. + repeat rewrite opc_match_case_identical. + + destruct (_ =? _) eqn:Hidx. + * rewrite Nat.eqb_eq in Hidx. + rewrite <- Hidx in HnId. + destruct HnIdHigh as [_ HnIdHigh']. + pose proof (n_le_he_eq _ _ HnId (HnIdHigh' eq_refl)) as HnIdEq. + rewrite <- Nat.eqb_eq in HnIdEq. + now rewrite HnIdEq. + * discriminate. + + (* + (* Ex is free in t. *) *) + (* now destruct (free _ _ _) in HfreePersists |- *; *) + (* [| discriminate HfreePersists]. *) + + rewrite andb_false_r. + discriminate. + + (* Ex. *) + - destruct free. + + (* Case where e can progress in t. *) + rewrite (HfreePersists eq_refl). + destruct opc; + (* Stores and others are trivial. *) + [| auto..]. + + (* Loads *) + unfold ready. + destruct busFree. + * now rewrite HbusFree. + * discriminate. + + + (* Case where e cannot progress in t. *) + (* This is irrelevant, eliminate it. *) + rewrite andb_false_r. + discriminate. + + (* Mem. *) + - now destruct opc; [ + (* Loads and stores are trivial; stores are trickier. *) + | destruct sbState, sbState', Hlsbt; + try discriminate |]. + Qed. + + Lemma unmoved_is_monotonic : + forall n, e = (opc, (st, n)) -> e = e' -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros n He He'. + + (* Extract e. *) + pose proof unmoved_no_lat_can_advance as Huca. + revert Huca. + work_on_e He'. + intro Huca. + + destruct n. + - (* Case where an instruction has a latency of 0. *) + destruct (_ && _). + + (* If e (in t) can progress. *) + (* e' (in t') can progress to. We have a lemma for this. *) + rewrite (Huca eq_refl eq_refl (get_latency opc (nstg st)) eq_refl). + now apply compare_two_eq_true. + + + (* If e (in t) cannot progress. *) + destruct (_ && _). + * now apply next_stage_is_higher. + * now apply compare_two_eq_true. + + - (* Case where an instruction has a latency higher than 0. *) + (* cycle_elt ... e = cycle_elt ... e'. Then, compare_two ... = true. *) + now apply compare_two_eq_true. + Qed. + + Lemma moved_no_lat_is_monotonic : + e = (opc, (st, 0)) -> e' = (opc, (st', 0)) -> e <> e' -> + state_leb (st, 0) (st', 0) = true -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros He He' Hed Hsl. + clear HfreePersists Hlsbt. + + (* Goal transformation: show exactly how e and e' are modified by the + * cycle function. *) + work_on_e Hed. + + destruct st, st'; + try contradiction; + try discriminate; + destruct (_ && _); + match goal with + | [|- context[if ?X then _ else _]] => + now destruct X + | [|- context[get_latency ?opc _]] => + now destruct opc + | _ => + reflexivity + end. + Qed. + + Lemma moved_lat_is_monotonic : + forall n n', e = (opc, (st, n)) -> e' = (opc, (st', n')) -> e <> e' -> + state_leb (st, n) (st', n') = true -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros n n' He He' Hed Hsl. + clear HfreePersists Hlsbt. + + pose proof (HvalidLat e') as HvalidLat'. + specialize (HvalidLat e). + + rewrite He in HvalidLat. + rewrite He' in HvalidLat'. + + destruct n, n'; [ + now apply moved_no_lat_is_monotonic | + work_on_e Hed; + destruct opc; + [| contradiction..].. + ]. + + (* From there, opc = Load. *) + - (* n = 0 and n' <> 0. *) + destruct HvalidLat' as [Hst' Hn']. + rewrite Hst' in Hsl, Hed |- *. + destruct st; + try discriminate. + + now destruct (_ && _). + + destruct (_ && _). + * simpl. + rewrite Nat.leb_le. + lia. + * reflexivity. + + - (* n <> 0 and n' = 0. *) + destruct HvalidLat as [Hst _]. + rewrite Hst in Hsl, Hed |- *. + destruct st'; + discriminate || reflexivity. + + - (* n and n' <> 0. *) + exact Hsl. + Qed. + + Theorem is_monotonic : + forall n n', e = (opc, (st, n)) -> e' = (opc, (st', n')) -> + state_leb (st, n) (st', n') = true -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros n n' He He' Hsl. + pose proof (instr_kind_is_comparable e e') as Heqd. + + (* e = e' or e <> e'. *) + destruct Heqd as [Heq | Hdiff]. + - (* If e = e', we have a lemma for this. *) + now apply (unmoved_is_monotonic n). + - (* If e <> e', we have a lemma for this. *) + now apply (moved_lat_is_monotonic n n'). + Qed. + End simple_monotonicity. + + Let tc_and_tc' := + tc_tc'_length_eq (cycle_elt (next_id t) sbState t) (cycle_elt (next_id t') sbState' t') + t t' tc tc' Hleb Htc Htc'. + + Variable e e' : instr_kind. + Variable n n' : nat. + + Hypothesis Ht : t = tpre ++ e :: tpost. + Hypothesis Ht' : t' = tpre' ++ e' :: tpost'. + Hypothesis Hi : forall i, i = List.length tpre. + Hypothesis Hi' : forall i, i = List.length tpre'. + + Hypothesis He : e = (opc, (st, n)). + Hypothesis He' : e' = (opc, (st', n')). + Hypothesis Hsl : state_leb (st, n) (st', n') = true. + + Let is_monotonic' ni := + is_monotonic e e' ni Ht Ht' (Hi ni) (Hi' ni) n n' He He' Hsl. + + Let cycled_instrs_are_leb' := + cycled_instrs_are_leb d tc tc' is_monotonic' tc_and_tc'. + + Theorem is_fully_monotonic : pipeline_leb tc tc' = true. + Proof. + now apply is_pipeline_fully_monotonic. + Qed. +End monotonicity. diff --git a/src/modular_definitions.v b/src/modular_definitions.v new file mode 100644 index 0000000000000000000000000000000000000000..bbe116a6ecaffca4e20f9dc461828ddc5097a373 --- /dev/null +++ b/src/modular_definitions.v @@ -0,0 +1,204 @@ +Require Import Bool List Nat PeanoNat. +Import ListNotations. + +Module Type Sig. + Parameter opcode : Set. + Axiom opcode_beq : opcode -> opcode -> bool. + Axiom opcode_eq_dec : forall (o o' : opcode), {o = o'} + {o <> o'}. + + Parameter stage : Set. + Axiom first_stage : stage. + Axiom stage_beq : stage -> stage -> bool. + Axiom stage_eq_dec : forall (s s' : stage), {s = s'} + {s <> s'}. + Axiom stage_beq_eq_true : forall s, stage_beq s s = true. + + Axiom leb : stage -> stage -> bool. + Axiom idx : opcode -> nat. +End Sig. + +Module Pipeline (Def : Sig). + Import Def. + Export Def. + + Definition state := (stage * nat)%type. + Definition instr_kind := (opcode * state)%type. + Definition trace_kind := list instr_kind. + + Definition is_in_stage st (instr : instr_kind) := + match instr with + | (_, (st', _)) => stage_beq st st' + end. + + Definition get_instr_in_stage trace st := List.find (is_in_stage st) trace. + + Definition state_leb st1 st2 := + match st1, st2 with + | (s1, n1), (s2, n2) => + if stage_beq s1 s2 then + Nat.leb n2 n1 + else + leb s1 s2 + end. + + Definition next_id (trace : trace_kind) := + match trace with + | [] => 0 + | (opc, _) :: r => + let id := idx opc in + List.fold_left (fun cid (elt : instr_kind) => + let (opc, st) := elt in + let (s, _) := st in + if stage_beq s first_stage then + Nat.min cid (idx opc) + else + cid) r id + end. + + Lemma state_leb_eq_true : forall st, state_leb st st = true. + Proof. + intro st. + destruct st. + simpl. + now rewrite stage_beq_eq_true, Nat.leb_le. + Qed. + + Lemma instr_kind_is_comparable : forall (e e' : instr_kind), {e = e'} + {e <> e'}. + Proof. + repeat decide equality. + - apply stage_eq_dec. + - apply opcode_eq_dec. + Qed. + + Definition compare_two (e1 e2 : option instr_kind) := + match e1, e2 with + | None, _ + | _, None => false + | Some (_, st1), Some (_, st2) => state_leb st1 st2 + end. + + Lemma compare_two_eq_true : forall e, e <> None -> compare_two e e = true. + Proof. + intros e Hn. + destruct e as [[o s] |]. + - (* e = Some (o, s) *) + simpl. + now rewrite state_leb_eq_true. + - (* None <> None *) + contradiction. + Qed. + + Definition instrs_leb (instrs : (instr_kind * instr_kind)) := + match instrs with + | ((_, st1), (_, st2)) => state_leb st1 st2 + end. + + Definition pipeline_leb p1 p2 := + let comb := List.combine p1 p2 in + Nat.eqb (List.length p1) (List.length p2) && List.forallb instrs_leb comb. + + Section comparison. + Variable t t' : trace_kind. + Variable i : nat. + Variable d : instr_kind. + + Hypothesis Hct : compare_two (List.nth_error t i) (List.nth_error t' i) = true. + + Lemma compare_two_true_means_exists : + (exists e, List.nth_error t i = Some e) + /\ (exists e, List.nth_error t' i = Some e). + split. + - (* First case. *) + destruct (nth_error t _). + + now exists i0. (* Some i0 = Some e -> i0 = e. *) + + discriminate. (* compare_two None ... = true is a contradiction. *) + + - (* Second case. *) + destruct (nth_error t' _). + + now exists i0. (* Some i0 = Some e -> i0 = e. *) + + (* compare_two ... None = true is a contradiction, with extra steps. *) + destruct (nth_error t _). + * simpl in Hct. + destruct i0. + discriminate. + * discriminate. + Qed. + + Lemma compare_two_true_means_instrs_leb : + instrs_leb (List.nth i t d, List.nth i t' d) = true. + Proof. + destruct compare_two_true_means_exists as [Hec Hec']. + destruct Hec as [ec Hnth], Hec' as [ec' Hnth']. + rewrite Hnth, Hnth' in Hct. + + now rewrite (nth_error_nth t i d Hnth), (nth_error_nth t' i d Hnth'). + Qed. + End comparison. + + Lemma tc_tc'_length_eq : + forall (f f' : instr_kind -> instr_kind) (t t' tc tc' : trace_kind), + pipeline_leb t t' = true -> + tc = map f t -> tc' = map f' t' -> length tc = length tc'. + Proof. + intros f f' t t' tc tc' Hleb Htc Htc'. + + (* length t = length t'. *) + (* length (map ... t) = length t. *) + rewrite Htc, Htc'. + repeat rewrite map_length. + unfold pipeline_leb in Hleb. + now rewrite andb_true_iff, Nat.eqb_eq in Hleb. + Qed. + + Lemma cycled_instrs_are_leb : + forall (d : instr_kind) (tc tc' : trace_kind), + (forall i, compare_two (nth_error tc i) (nth_error tc' i) = true) -> + List.length tc = List.length tc' -> + forall instrs, In instrs (combine tc tc') -> instrs_leb instrs = true. + Proof. + (* Since instrs is in (combine tc tc'), there is a + * i' < length (combine tc tc') and + * nth i' (combine tc tc') (d, d)) = instrs. *) + intros d tc tc' Hct Hlength instrs HIn. + destruct (In_nth (combine tc tc') instrs (d, d) HIn) as [i [Hil HInth]]. + + (* since nth i (combine tc tc') = instrs, + * instrs = (nth i tc d, nth i tc' d). *) + rewrite combine_nth in HInth. + - (* instrs_leb instrs = true means + * compare_two (nth_error tc i) (nth_error tc' i) = true. + * We have a lemma for this. *) + (* Then, compare_two (nth_error tc i) (nth_error tc' i) = true. + * We have a theorem for this. *) + rewrite <- HInth. + apply (compare_two_true_means_instrs_leb tc tc' i d), (Hct i). + - exact Hlength. + Qed. + + Lemma is_pipeline_fully_monotonic : + forall (tc tc' : trace_kind), + List.length tc = List.length tc' -> + (forall instrs, In instrs (combine tc tc') -> instrs_leb instrs = true) -> + pipeline_leb tc tc' = true. + Proof. + intros tc tc' Hlength Hleb. + + unfold pipeline_leb. + rewrite andb_true_iff. + now split; [ + (* First, length tc = length tc'. We have a hypothesis for this. *) + rewrite Nat.eqb_eq | + (* Now, forallb instrs_leb (combine tc tc') = true. *) + (* Transform the goal into + * forall instrs, In instrs (combine ...) -> instrs_leb instrs = true. + * Directly apply Hleb. *) + rewrite forallb_forall + ]. + Qed. +End Pipeline. + +Variant sbStateT := + | Empty + | NotEmpty + | Full. + +Scheme Equality for sbStateT. diff --git a/src/modular_store_buffer.v b/src/modular_store_buffer.v new file mode 100644 index 0000000000000000000000000000000000000000..6fe24efa33dd5b90b5bd28bab0af2108266f9b6f --- /dev/null +++ b/src/modular_store_buffer.v @@ -0,0 +1,512 @@ +Require Import Bool Lia List Nat PeanoNat. +From StoreBuffer Require Import modular_definitions utils. +Import ListNotations. + +Module StoreBufferSig <: Sig. + Variant opcode_sb := + | Load (dlat : nat) (id : nat) + | Store (id : nat). + + Variant stage_sb := + | Sp + | Lsu + | Lu + | Su + | Sn. + + Definition first_stage := Sp. + + Scheme Equality for opcode_sb. + Definition opcode := opcode_sb. + Definition opcode_beq := opcode_sb_beq. + Definition opcode_eq_dec := opcode_sb_eq_dec. + + Scheme Equality for stage_sb. + Definition stage := stage_sb. + Definition stage_beq := stage_sb_beq. + Definition stage_eq_dec := stage_sb_eq_dec. + + Lemma stage_beq_eq_true : forall s, stage_beq s s = true. + Proof. + now destruct s. + Qed. + + (* Boolean stage comparison. Sp < Lsu < (Lu, Su) < Sn. *) + Definition leb x y := + match x, y with + | Sp, _ => true + | _, Sn => true + | Sn, _ => false + | Lsu, Sp => false + | Lsu, _ => true + | Lu, Lu => true + | Lu, _ => false + | Su, Su => true + | Su, _ => false + end. + + Definition idx opc := + match opc with + | Load _ id | Store id => id + end. +End StoreBufferSig. + +Module StoreBuffer := Pipeline StoreBufferSig. +Export StoreBuffer. + +Definition nstg s opc := + match s, opc with + | Sp, _ => Lsu + | Lsu, Load _ _ => Lu + | Lsu, Store _ => Su + | _, _ => Sn + end. + +Definition sbEmpty := sbStateT_beq Empty. + +(* ready, free and cycle functions. *) +Definition ready next_id sbState (elt : instr_kind) := + match elt with + | (Load _ _, (Lsu, _)) => sbEmpty sbState + | (_, (Su, _)) => negb (sbStateT_beq sbState Full) + | (_, (Lu, S _)) => false + | (opc, (Sp, 0)) => idx opc =? next_id + | _ => true + end. + +Definition luFree next_id sbState trace := + let instr := get_instr_in_stage trace Lu in + match instr with + | Some elt => ready next_id sbState elt (* Sn is always free *) + | None => true + end. + +Definition suFree next_id sbState trace := + let instr := get_instr_in_stage trace Su in + match instr with + | Some elt => ready next_id sbState elt (* Sn is always free *) + | None => true + end. + +Definition lsuFree next_id sbState trace := + let instr := get_instr_in_stage trace Lsu in + match instr with + | Some (opcode, (stg, lat)) => ready next_id sbState (opcode, (stg, lat)) && + if stage_beq (nstg stg opcode) Lu then + luFree next_id sbState trace + else + suFree next_id sbState trace + | None => true + end. + +Definition free next_id sbState trace (elt : instr_kind) := + let (opc, state) := elt in + let (st, _) := state in + match nstg st opc with + | Lu => luFree next_id sbState trace + | Su => suFree next_id sbState trace + | Lsu => lsuFree next_id sbState trace + | _ => true + end. + +Definition get_latency opc st := + match opc, st with + | Load n _, Lu => n + | _, _ => 0 + end. + +Definition cycle_elt next_id (busTaken : bool) sbState trace elt := + match elt with + | (opc, (st, S n)) => + if busTaken then + (opc, (st, n)) + else + elt + | (opc, (st, 0)) => + if ready next_id sbState elt && free next_id sbState trace elt then + let nstg := nstg st opc in + (opc, (nstg, get_latency opc nstg)) + else + elt + end. + +Definition cycle sbState busTaken trace := + List.map (cycle_elt (next_id trace) busTaken sbState trace) trace. + +Definition legal_sb_transitions st sbState sbState' := + match st, sbState with + | Su, Empty => sbState' = Empty + | Su, NotEmpty => sbState' = NotEmpty \/ sbState' = Empty + | _, _ => sbState' = Full \/ sbState' = NotEmpty \/ sbState' = Empty + end. + +Lemma next_stage_is_higher : + forall opc st st', st' = nstg st opc -> + compare_two (Some (opc, (st, 0))) + (Some (opc, (st', get_latency opc st'))) = true. +Proof. + intros opc st st' Hst'. + rewrite Hst'. + destruct st; + try reflexivity; + now destruct opc. +Qed. + +Lemma opc_match_case_identical : forall (A : Type) (a : A) opc, + match opc with | Load _ _ | _ => a end = a. +Proof. + intros A a opc. + now destruct opc. +Qed. + +Section monotonicity. + Variable opc : opcode. + Variable d : instr_kind. + Variable st st' : stage. + Variable t tpre tpost t' tpre' tpost' tc tc' : trace_kind. + Variable busTaken busTaken' : bool. + Variable sbState sbState' : sbStateT. + + Hypothesis Hleb : pipeline_leb t t' = true. + Hypothesis Hl : pipeline_leb tpre tpre' = true. + Hypothesis Hl' : pipeline_leb tpost tpost' = true. + Hypothesis Htc : tc = cycle sbState busTaken t. + Hypothesis Htc' : tc' = cycle sbState' busTaken' t'. + Hypothesis Hlsbt : legal_sb_transitions st sbState sbState'. + Hypothesis HnId : next_id t <= next_id t'. + + Hypothesis HnIdLow : forall t (e : instr_kind), + match e with + | (opc, (st, _)) => idx opc < next_id t <-> st <> Sp + end. + + Hypothesis HnIdHigh : forall t (e : instr_kind), + match e with + | (opc, (st, _)) => idx opc >= next_id t <-> st = Sp + end. + + Hypothesis Hlu : forall st opc n, st = Lu -> exists id, opc = Load n id. + Hypothesis Hsu : forall st opc, st = Su -> exists id, opc = Store id. + + (* Long hypotheses related to stage occupation. *) + Hypothesis HfreeLsuPersists : + free (next_id t) sbState t (opc, (Sp, 0)) = true -> + free (next_id t') sbState' t' (opc, (Sp, 0)) = true. + + Hypothesis HfreeFromLsuPersists : + free (next_id t) sbState t (opc, (Lsu, 0)) = true -> + free (next_id t') sbState' t' (opc, (Lsu, 0)) = true. + + Hypothesis HbusTakenPersists : busTaken = true -> busTaken' = true. + + Hypothesis HsbRemainsEmpty : + forall st, st = Lsu -> sbEmpty sbState = true -> sbEmpty sbState' = true. + + Hypothesis HvalidLat : forall (e : instr_kind) (busTaken : bool), + match e with + | (_, (st, 0)) => True + | (Load dlat _, (st, n)) => st = Lu /\ n <= dlat /\ (busTaken = false -> n = dlat) + | (_, (st, S _)) => False + end. + + Section simple_monotonicity. + Variable e e' : instr_kind. + Variable i : nat. + + Hypothesis Ht : t = tpre ++ e :: tpost. + Hypothesis Ht' : t' = tpre' ++ e' :: tpost'. + Hypothesis Hi : i = List.length tpre. + Hypothesis Hi' : i = List.length tpre'. + + Ltac work_on_e He' := + rewrite Htc, Htc', Ht; + match type of He' with + | e = e' => + rewrite Ht', <- He' in HfreeLsuPersists, HfreeFromLsuPersists, HnId |- * + | e <> e' => + rewrite Ht' + end; + unfold cycle; + rewrite (map_in_the_middle _ _ e d _ _ tpre tpost _ eq_refl Hi), + (map_in_the_middle _ _ _ d _ _ tpre' tpost' _ eq_refl Hi'); + unfold cycle_elt; + rewrite <- Ht; + match type of He' with + | e = e' => + subst e + | e <> e' => + rewrite <- Ht'; + subst e; + subst e' + end. + + Ltac stage_opc Hyp := + destruct (Hyp eq_refl) as [sopc_internal_id sopc_internal_Hopc]; + (discriminate sopc_internal_Hopc || + rewrite sopc_internal_Hopc; + auto). + + Lemma unmoved_no_lat_can_advance : + e = (opc, (st, 0)) -> e = e' -> forall n, + List.nth_error tc i = Some (opc, (nstg st opc, n)) -> + List.nth_error tc' i = Some (opc, (nstg st opc, n)). + Proof. + intros He He' n. + specialize (Hlu st opc). + specialize (Hsu st opc). + specialize (HsbRemainsEmpty st). + specialize (HnIdLow t' e'). + specialize (HnIdHigh t' e'). + + rewrite Ht', <- He' in HnIdLow, HnIdHigh. + + (* Delve onto e, then handle stages on a case-by-case basis. *) + work_on_e He'. + destruct st. + + (* Sp. The proof does not rely on the kind of instruction. *) + - destruct free in HfreeLsuPersists |- *. + + (* LSU is free in t. *) + setoid_rewrite (HfreeLsuPersists eq_refl). + unfold ready. + repeat rewrite opc_match_case_identical. + + destruct (_ =? _) eqn:Hidx. + * rewrite Nat.eqb_eq in Hidx. + rewrite <- Hidx in HnId. + destruct HnIdHigh as [_ HnIdHigh']. + pose proof (n_le_he_eq _ _ HnId (HnIdHigh' eq_refl)) as HnIdEq. + rewrite <- Nat.eqb_eq in HnIdEq. + now rewrite HnIdEq. + * discriminate. + + + (* LSU is not free in t: this is irrelevant. *) + rewrite andb_false_r. + discriminate. + + (* Lsu *) + - destruct free, opc. + (* Cases where e progressed in t. *) + + (* Loads *) + unfold ready. + destruct sbEmpty. + * simpl in HfreeFromLsuPersists |- *. + now rewrite HsbRemainsEmpty, HfreeFromLsuPersists. + * discriminate. + + (* Stores *) + simpl in HfreeFromLsuPersists |- *. + now rewrite HfreeFromLsuPersists. + + (* Cases where e did not progress in t. *) + (* Irrelevant, exclude them. *) + + rewrite andb_false_r. + discriminate. + + discriminate. + + (* Lu: instructions without latency (this is the case here) move to Sn. *) + - stage_opc (Hlu n). + + (* Su: if there is space in the store buffer, move to Sn, otherwise, remain + in Su. Eliminate cases where sbState/sbState' are inconsistent. *) + - stage_opc Hsu. + now destruct sbState, sbState', Hlsbt; + try discriminate. + + (* Sn: instructions remains in Sn. *) + - auto. + Qed. + + Lemma unmoved_is_monotonic : + forall n, e = (opc, (st, n)) -> e = e' -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros n He He'. + + (* Extract e. *) + pose proof unmoved_no_lat_can_advance as Huca. + revert Huca. + work_on_e He'. + intro Huca. + + destruct n. + - (* Case where an instruction has a latency of 0. *) + destruct (_ && _). + + (* If e (in t) can progress. *) + (* e' (in t') can progress to. We have a lemma for this. *) + rewrite (Huca eq_refl eq_refl (get_latency _ _) eq_refl). + now apply compare_two_eq_true. + + (* If e (in t) cannot progress. *) + destruct (_ && _). + * (* If e (in t') can progress. cycle_elt e t' > cycle_elt e t. This + * is trivial, but each case must be analysed separately. *) + now apply next_stage_is_higher. + * (* If e (in t') cannot progress. cycle_elt e t' = cycle e t. This + * is also trivial. *) + now apply compare_two_eq_true. + + - (* Case where an instruction has a latency higher than 0. *) + (* cycle_elt ... e = cycle_elt ... e'. Then, compare_two ... = true. *) + destruct busTaken. + + rewrite (HbusTakenPersists eq_refl). + now apply compare_two_eq_true. + + destruct busTaken'. + * simpl. + + rewrite stage_beq_eq_true, Nat.leb_le. + auto. + * now apply compare_two_eq_true. + Qed. + + Lemma moved_no_lat_is_monotonic : + e = (opc, (st, 0)) -> e' = (opc, (st', 0)) -> e <> e' -> + state_leb (st, 0) (st', 0) = true -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros He He' Hed Hsl. + clear HfreeFromLsuPersists HfreeLsuPersists Hlsbt. + specialize (Hlu st opc 0). + pose proof (Hsu st' opc) as Hsu'. + specialize (Hsu st opc). + + (* Goal transformation: show exactly how e and e' are modified by the + * cycle function. *) + work_on_e Hed. + + (* Case-by-case analysis *) + destruct st, st'; + try contradiction; + try discriminate. + + (* st = Sp, st' = Lsu, Lu, Su, Sn *) + - now destruct (_ && _), (_ && _), opc. + - now destruct (_ && _), opc. + - now destruct (_ && _), (_ && _). + - now destruct (_ && _), opc. + + (* st = Lsu, st' = Lu, Su, Sn *) + - now destruct (_ && _), opc. + - destruct (_ && _), (_ && _); + try reflexivity; + stage_opc Hsu'. + - now destruct (_ && _), opc. + + (* st = Lu, st' = Sn *) + - (* Trivial when opc = Load, eliminate the case where opc = Store. *) + stage_opc Hlu. + + (* st = Su, st' = Sn *) + - (* Eliminate the case where opc = Load. *) + stage_opc Hsu. + (* Either the instruction remains in Su, or it progresses in Sn. *) + (* Both cases are trivial. *) + now destruct (_ && _). + Qed. + + Lemma moved_lat_is_monotonic : + forall n n', e = (opc, (st, n)) -> e' = (opc, (st', n')) -> e <> e' -> + state_leb (st, n) (st', n') = true -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros n n' He He' Hed Hsl. + clear HfreeFromLsuPersists HfreeLsuPersists Hlsbt. + pose proof (HvalidLat e' busTaken') as HvalidLat'. + specialize (HvalidLat e busTaken). + + destruct n, n'; [ + (* n and n' are = 0. We have a lemma for that. *) + now apply moved_no_lat_is_monotonic | + (* Other cases: rewrite the goal to make cycle appear. *) + work_on_e Hed; + (* Since n or n' is not equal to 0, opc is a load. Remove other cases. *) + destruct opc; + [| contradiction] .. + ]. + + (* From there, opc = Load. *) + (* n = 0 and n' <> 0. *) + - (* st' = Lu. *) + destruct HvalidLat' as [Hst' [Hlat' _]]. + rewrite Hst' in Hsl, Hed |- *. + destruct st; + try discriminate. + + (* st = Sp. In this case, the next stage is either Sp or Lsu, which are + * both lower than Lu. *) + now destruct (_ && _), busTaken'. + + (* st = Lsu. In this case, the next stage is either Lsu or Lu. *) + destruct (_ && _). + * simpl. + destruct busTaken'; + rewrite Nat.leb_le; + lia. + * now destruct busTaken'. + + (* n <> 0 and n' = 0. *) + - (* st = Lu. *) + destruct HvalidLat as [Hst Hlat]. + rewrite Hst in Hsl, Hed |- *. + destruct st'; + (* Sp, Lsu: impossible since e' would be lower than e. *) + (* Su: impossible since loads cannot be in Su. *) + discriminate + (* Lu: since n' = 0, e' will be in Sn in the next cycle, e will still be *) + (* in Lu. *) + (* Sn: e' will remain in Sn, e will still be in Lu. *) + || now destruct busTaken. + + (* n and n' <> 0. *) + - destruct busTaken. + + now rewrite HbusTakenPersists. + + destruct HvalidLat as [Hst [_ Hdlat]], HvalidLat' as [Hst' [Hlat' Hdlat']]. + rewrite (Hdlat eq_refl), Hst, Hst' in Hed |- *. + destruct busTaken'. + * simpl. + rewrite Nat.leb_le. + lia. + * now rewrite Hdlat' in Hed |- *. + Qed. + + Theorem is_monotonic : + forall n n', e = (opc, (st, n)) -> e' = (opc, (st', n')) -> + state_leb (st, n) (st', n') = true -> + compare_two (List.nth_error tc i) (List.nth_error tc' i) = true. + Proof. + intros n n' He He' Hsl. + pose proof (instr_kind_is_comparable e e') as Heqd. + + (* e = e' or e <> e'. *) + destruct Heqd as [Heq | Hdiff]. + - (* If e = e', we have a lemma for this. *) + now apply (unmoved_is_monotonic n). + - (* If e <> e', we have a lemma for this. *) + now apply (moved_lat_is_monotonic n n'). + Qed. + End simple_monotonicity. + + Let tc_and_tc' := + tc_tc'_length_eq (cycle_elt (next_id t) busTaken sbState t) + (cycle_elt (next_id t') busTaken' sbState' t') + t t' tc tc' Hleb Htc Htc'. + + Variable e e' : instr_kind. + Variable n n' : nat. + + Hypothesis Ht : t = tpre ++ e :: tpost. + Hypothesis Ht' : t' = tpre' ++ e' :: tpost'. + Hypothesis Hi : forall i, i = List.length tpre. + Hypothesis Hi' : forall i, i = List.length tpre'. + + Hypothesis He : e = (opc, (st, n)). + Hypothesis He' : e' = (opc, (st', n')). + Hypothesis Hsl : state_leb (st, n) (st', n') = true. + + Let is_monotonic' ni := + is_monotonic e e' ni Ht Ht' (Hi ni) (Hi' ni) n n' He He' Hsl. + + Let cycled_instrs_are_leb' := + cycled_instrs_are_leb d tc tc' is_monotonic' tc_and_tc'. + + Theorem is_fully_monotonic : pipeline_leb tc tc' = true. + Proof. + now apply is_pipeline_fully_monotonic. + Qed. +End monotonicity. diff --git a/src/utils.v b/src/utils.v index f8244f17f168b773a6b850b9c6441601c0874af3..19d6b321b3303958c444f063f1a75561b5e4ab9e 100644 --- a/src/utils.v +++ b/src/utils.v @@ -1,54 +1,85 @@ Require Import Lia List Nat. Import ListNotations. -Lemma not_existsb_means_cannot_find : - forall (T : Type) (f : T -> bool) (l : list T), - List.existsb f l = false -> List.find f l = None. +Scheme Equality for list. + +Lemma list_elt_exists : + forall (A : Type) (l : list A) (d : A) i, + i < List.length l -> (exists a, List.nth_error l i = Some a). Proof. - intros T f l. - induction l. - - reflexivity. - - simpl. - now destruct f. + intros A l d i Hi. + destruct nth_error eqn:Hnth. + - now exists a. + - pose proof (nth_error_nth' l d Hi) as Hnth'. + rewrite Hnth in Hnth'. + discriminate. Qed. -Lemma nth_error_on_composed_list : - forall (T : Type) (a d : T) (l lpre lpost : list T) i, - l = lpre ++ a :: lpost -> i = List.length lpre -> - List.nth_error l i = Some a. -Proof. - intros T a d l lpre lpost i Hl Hi. +Section list_utils. + Variable A B : Type. + Variable a d : A. + Variable f : A -> B. + Variable l lpre lpost : list A. + Variable i : nat. + + Hypothesis Hl : l = lpre ++ a :: lpost. + Hypothesis Hi : i = List.length lpre. - assert (i < List.length l) as Hlength. - - rewrite Hl, app_length, Hi. + Lemma i_lt_length_l : i < List.length l. + Proof. + rewrite Hl, app_length, Hi. simpl. lia. + Qed. - - now rewrite (nth_error_nth' _ d Hlength), Hl, Hi, nth_middle. -Qed. + Lemma nth_error_on_composed_list : List.nth_error l i = Some a. + Proof. + now rewrite (nth_error_nth' _ d i_lt_length_l), Hl, Hi, nth_middle. + Qed. + + Lemma map_in_the_middle : List.nth_error (List.map f l) i = Some (f a). + Proof. + apply map_nth_error, nth_error_on_composed_list. + Qed. + + Lemma list_is_composed : + forall (l' : list A), List.length l = List.length l' -> + (exists a' lpre' lpost', l' = lpre' ++ a' :: lpost' /\ i = List.length lpre'). + Proof. + intros l' Hlength. -Lemma map_in_the_middle : - forall (A B : Type) (a d : A) (f : A -> B) l lpre lpost i, - l = lpre ++ a :: lpost -> i = List.length lpre -> - List.nth_error (List.map f l) i = Some (f a). + pose proof i_lt_length_l as Hlength'. + rewrite Hlength in Hlength'. + + pose proof (list_elt_exists A l' d i Hlength') as Hle. + destruct Hle as [a' Hle]. + + pose proof (nth_error_split l' i Hle) as Hnes. + destruct Hnes as [lpre' [lpost' [Hnes Hi']]]. + exists a', lpre', lpost'. + split. + - exact Hnes. + - now apply eq_sym in Hi'. + Qed. +End list_utils. + +Lemma list_is_empty_or_composed : + forall (A : Type) (l : list A), + l = [] \/ (exists (a : A) (lpre lpost : list A) (i : nat), l = lpre ++ a :: lpost /\ i = List.length lpre). Proof. - intros A B a d f l lpre lpost i Hl Hi. - now apply map_nth_error, (nth_error_on_composed_list _ _ d _ lpre lpost). + intros A l. + + induction l. + - now left. + - right. + destruct IHl as [IHl | IHl]. + + exists a, [], [], 0. + now rewrite IHl. + + destruct IHl as [a0 [lpre [lpost IHl]]]. + now exists a, [], l, 0. Qed. -Section ListCustomBool. - Variable A : Type. - Variable f : A -> bool. - - Definition nth_at := - let fix aux i (l : list A) {struct l} := - match l with - | [] => None - | x :: tl => - if f x then - Some i - else - aux (S i) tl - end in - aux 0. -End ListCustomBool. +Lemma n_le_he_eq : forall (n m : nat), n <= m -> n >= m -> n = m. +Proof. + lia. +Qed.