heap_lang.v 11.7 KB
Newer Older
1
Require Export Autosubst.Autosubst.
2
Require Export program_logic.language.
3
Require Import prelude.gmap.
4

5 6
Module heap_lang.
(** Expressions and vals. *)
7
Definition loc := positive. (* Really, any countable type. *)
Ralf Jung's avatar
Ralf Jung committed
8

9 10 11 12 13 14 15
Inductive base_lit : Set :=
  | LitNat (n : nat) | LitBool (b : bool) | LitUnit.
Inductive un_op : Set :=
  | NegOp.
Inductive bin_op : Set :=
  | PlusOp | MinusOp | LeOp | LtOp | EqOp.

Ralf Jung's avatar
Ralf Jung committed
16
Inductive expr :=
17 18 19 20 21
  (* Base lambda calculus *)
  | Var (x : var)
  | Rec (e : {bind 2 of expr}) (* These are recursive lambdas.
                                  The *inner* binder is the recursive call! *)
  | App (e1 e2 : expr)
22 23 24 25 26
  (* Base types and their operations *)
  | Lit (l : base_lit)
  | UnOp (op : un_op) (e : expr)
  | BinOp (op : bin_op) (e1 e2 : expr)
  | If (e0 e1 e2 : expr)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
  (* Products *)
  | Pair (e1 e2 : expr)
  | Fst (e : expr)
  | Snd (e : expr)
  (* Sums *)
  | InjL (e : expr)
  | InjR (e : expr)
  | Case (e0 : expr) (e1 : {bind expr}) (e2 : {bind expr})
  (* Concurrency *)
  | Fork (e : expr)
  (* Heap *)
  | Loc (l : loc)
  | Alloc (e : expr)
  | Load (e : expr)
  | Store (e1 : expr) (e2 : expr)
  | Cas (e0 : expr) (e1 : expr) (e2 : expr).
Ralf Jung's avatar
Ralf Jung committed
43 44 45 46 47 48

Instance Ids_expr : Ids expr. derive. Defined.
Instance Rename_expr : Rename expr. derive. Defined.
Instance Subst_expr : Subst expr. derive. Defined.
Instance SubstLemmas_expr : SubstLemmas expr. derive. Qed.

49 50 51
Inductive val :=
  | RecV (e : {bind 2 of expr}) (* These are recursive lambdas.
                                   The *inner* binder is the recursive call! *)
52
  | LitV (l : base_lit)
53 54 55 56
  | PairV (v1 v2 : val)
  | InjLV (v : val)
  | InjRV (v : val)
  | LocV (l : loc).
Ralf Jung's avatar
Ralf Jung committed
57

58
Fixpoint of_val (v : val) : expr :=
Ralf Jung's avatar
Ralf Jung committed
59
  match v with
60
  | RecV e => Rec e
61
  | LitV l => Lit l
62 63 64
  | PairV v1 v2 => Pair (of_val v1) (of_val v2)
  | InjLV v => InjL (of_val v)
  | InjRV v => InjR (of_val v)
65
  | LocV l => Loc l
Ralf Jung's avatar
Ralf Jung committed
66
  end.
67
Fixpoint to_val (e : expr) : option val :=
68
  match e with
Ralf Jung's avatar
Ralf Jung committed
69
  | Rec e => Some (RecV e)
70
  | Lit l => Some (LitV l)
71 72 73
  | Pair e1 e2 => v1  to_val e1; v2  to_val e2; Some (PairV v1 v2)
  | InjL e => InjLV <$> to_val e
  | InjR e => InjRV <$> to_val e
74
  | Loc l => Some (LocV l)
Ralf Jung's avatar
Ralf Jung committed
75
  | _ => None
76 77
  end.

78 79
(** The state: heaps of vals. *)
Definition state := gmap loc val.
Ralf Jung's avatar
Ralf Jung committed
80

81
(** Evaluation contexts *)
82 83 84
Inductive ectx_item :=
  | AppLCtx (e2 : expr)
  | AppRCtx (v1 : val)
85 86 87 88
  | UnOpCtx (op : un_op)
  | BinOpLCtx (op : bin_op) (e2 : expr)
  | BinOpRCtx (op : bin_op) (v1 : val)
  | IfCtx (e1 e2 : expr)
89 90 91 92 93 94 95 96 97 98 99 100 101 102
  | PairLCtx (e2 : expr)
  | PairRCtx (v1 : val)
  | FstCtx
  | SndCtx
  | InjLCtx
  | InjRCtx
  | CaseCtx (e1 : {bind expr}) (e2 : {bind expr})
  | AllocCtx
  | LoadCtx
  | StoreLCtx (e2 : expr)
  | StoreRCtx (v1 : val)
  | CasLCtx (e1 : expr)  (e2 : expr)
  | CasMCtx (v0 : val) (e2 : expr)
  | CasRCtx (v0 : val) (v1 : val).
103

104
Notation ectx := (list ectx_item).
105

106
Definition fill_item (Ki : ectx_item) (e : expr) : expr :=
107 108 109
  match Ki with
  | AppLCtx e2 => App e e2
  | AppRCtx v1 => App (of_val v1) e
110 111 112 113
  | UnOpCtx op => UnOp op e
  | BinOpLCtx op e2 => BinOp op e e2
  | BinOpRCtx op v1 => BinOp op (of_val v1) e
  | IfCtx e1 e2 => If e e1 e2
114 115 116 117 118 119 120 121 122 123 124 125 126 127
  | PairLCtx e2 => Pair e e2
  | PairRCtx v1 => Pair (of_val v1) e
  | FstCtx => Fst e
  | SndCtx => Snd e
  | InjLCtx => InjL e
  | InjRCtx => InjR e
  | CaseCtx e1 e2 => Case e e1 e2
  | AllocCtx => Alloc e
  | LoadCtx => Load e
  | StoreLCtx e2 => Store e e2
  | StoreRCtx v1 => Store (of_val v1) e
  | CasLCtx e1 e2 => Cas e e1 e2
  | CasMCtx v0 e2 => Cas (of_val v0) e e2
  | CasRCtx v0 v1 => Cas (of_val v0) (of_val v1) e
Ralf Jung's avatar
Ralf Jung committed
128
  end.
129
Definition fill (K : ectx) (e : expr) : expr := fold_right fill_item e K.
Ralf Jung's avatar
Ralf Jung committed
130

131
(** The stepping relation *)
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
Definition un_op_eval (op : un_op) (l : base_lit) : option base_lit :=
  match op, l with
  | NegOp, LitBool b => Some $ LitBool (negb b)
  | _, _ => None
  end.

(* FIXME RJ I am *sure* this already exists somewhere... but I can't find it. *)
Definition sum2bool {A B} (x : { A } + { B }) : bool :=
  match x with
  | left _ => true
  | right _ => false
  end.

Definition bin_op_eval (op : bin_op) (l1 l2 : base_lit) : option base_lit :=
  match op, l1, l2 with
  | PlusOp, LitNat n1, LitNat n2 => Some $ LitNat (n1 + n2)
  | MinusOp, LitNat n1, LitNat n2 => Some $ LitNat (n1 - n2)
  | LeOp, LitNat n1, LitNat n2 => Some $ LitBool $ sum2bool $ decide (n1  n2)
  | LtOp, LitNat n1, LitNat n2 => Some $ LitBool $ sum2bool $ decide (n1 < n2)
  | EqOp, LitNat n1, LitNat n2 => Some $ LitBool $ sum2bool $ decide (n1 = n2)
  | _, _, _ => None
  end.

155 156 157 158
Inductive head_step : expr -> state -> expr -> state -> option expr -> Prop :=
  | BetaS e1 e2 v2 σ :
     to_val e2 = Some v2 
     head_step (App (Rec e1) e2) σ e1.[(Rec e1),e2/] σ None
159 160 161 162 163 164 165 166 167 168
  | UnOpS op l l' σ: 
     un_op_eval op l = Some l'  
     head_step (UnOp op (Lit l)) σ (Lit l') σ None
  | BinOpS op l1 l2 l' σ: 
     bin_op_eval op l1 l2 = Some l'  
     head_step (BinOp op (Lit l1) (Lit l2)) σ (Lit l') σ None
  | IfTrueS e1 e2 σ :
     head_step (If (Lit $ LitBool true) e1 e2) σ e1 σ None
  | IfFalseS e1 e2 σ :
     head_step (If (Lit $ LitBool false) e1 e2) σ e2 σ None
169 170 171 172 173 174 175 176 177 178 179 180 181
  | FstS e1 v1 e2 v2 σ :
     to_val e1 = Some v1  to_val e2 = Some v2 
     head_step (Fst (Pair e1 e2)) σ e1 σ None
  | SndS e1 v1 e2 v2 σ :
     to_val e1 = Some v1  to_val e2 = Some v2 
     head_step (Snd (Pair e1 e2)) σ e2 σ None
  | CaseLS e0 v0 e1 e2 σ :
     to_val e0 = Some v0 
     head_step (Case (InjL e0) e1 e2) σ e1.[e0/] σ None
  | CaseRS e0 v0 e1 e2 σ :
     to_val e0 = Some v0 
     head_step (Case (InjR e0) e1 e2) σ e2.[e0/] σ None
  | ForkS e σ:
182
     head_step (Fork e) σ (Lit LitUnit) σ (Some e)
183 184 185 186 187 188 189 190
  | AllocS e v σ l :
     to_val e = Some v  σ !! l = None 
     head_step (Alloc e) σ (Loc l) (<[l:=v]>σ) None
  | LoadS l v σ :
     σ !! l = Some v 
     head_step (Load (Loc l)) σ (of_val v) σ None
  | StoreS l e v σ :
     to_val e = Some v  is_Some (σ !! l) 
191
     head_step (Store (Loc l) e) σ (Lit LitUnit) (<[l:=v]>σ) None
192 193 194
  | CasFailS l e1 v1 e2 v2 vl σ :
     to_val e1 = Some v1  to_val e2 = Some v2 
     σ !! l = Some vl  vl  v1 
195
     head_step (Cas (Loc l) e1 e2) σ (Lit $ LitBool false)  σ None
196 197 198
  | CasSucS l e1 v1 e2 v2 σ :
     to_val e1 = Some v1  to_val e2 = Some v2 
     σ !! l = Some v1 
199
     head_step (Cas (Loc l) e1 e2) σ (Lit $ LitBool true) (<[l:=v2]>σ) None.
Ralf Jung's avatar
Ralf Jung committed
200

201 202 203 204 205 206 207 208 209
(** Atomic expressions *)
Definition atomic (e: expr) :=
  match e with
  | Alloc e => is_Some (to_val e)
  | Load e => is_Some (to_val e)
  | Store e1 e2 => is_Some (to_val e1)  is_Some (to_val e2)
  | Cas e0 e1 e2 => is_Some (to_val e0)  is_Some (to_val e1)  is_Some (to_val e2)
  | _ => False
  end.
210

211 212 213 214
(** Close reduction under evaluation contexts.
We could potentially make this a generic construction. *)
Inductive prim_step
    (e1 : expr) (σ1 : state) (e2 : expr) (σ2: state) (ef: option expr) : Prop :=
215
  Ectx_step K e1' e2' :
216 217 218 219 220 221
    e1 = fill K e1'  e2 = fill K e2' 
    head_step e1' σ1 e2' σ2 ef  prim_step e1 σ1 e2 σ2 ef.

(** Basic properties about the language *)
Lemma to_of_val v : to_val (of_val v) = Some v.
Proof. by induction v; simplify_option_equality. Qed.
222

223
Lemma of_to_val e v : to_val e = Some v  of_val v = e.
224
Proof.
225
  revert v; induction e; intros; simplify_option_equality; auto with f_equal.
226
Qed.
227

228 229
Instance: Injective (=) (=) of_val.
Proof. by intros ?? Hv; apply (injective Some); rewrite -!to_of_val Hv. Qed.
230

231
Instance fill_item_inj Ki : Injective (=) (=) (fill_item Ki).
232
Proof. destruct Ki; intros ???; simplify_equality'; auto with f_equal. Qed.
233

234 235
Instance ectx_fill_inj K : Injective (=) (=) (fill K).
Proof. red; induction K as [|Ki K IH]; naive_solver. Qed.
236

237 238
Lemma fill_app K1 K2 e : fill (K1 ++ K2) e = fill K1 (fill K2 e).
Proof. revert e; induction K1; simpl; auto with f_equal. Qed.
239

240
Lemma fill_val K e : is_Some (to_val (fill K e))  is_Some (to_val e).
241
Proof.
242 243
  intros [v' Hv']; revert v' Hv'.
  induction K as [|[]]; intros; simplify_option_equality; eauto.
244
Qed.
245

246 247
Lemma fill_not_val K e : to_val e = None  to_val (fill K e) = None.
Proof. rewrite !eq_None_not_Some; eauto using fill_val. Qed.
248

249 250 251
Lemma values_head_stuck e1 σ1 e2 σ2 ef :
  head_step e1 σ1 e2 σ2 ef  to_val e1 = None.
Proof. destruct 1; naive_solver. Qed.
252

253 254
Lemma values_stuck e1 σ1 e2 σ2 ef : prim_step e1 σ1 e2 σ2 ef  to_val e1 = None.
Proof. intros [??? -> -> ?]; eauto using fill_not_val, values_head_stuck. Qed.
255

256 257
Lemma atomic_not_val e : atomic e  to_val e = None.
Proof. destruct e; naive_solver. Qed.
258

259
Lemma atomic_fill K e : atomic (fill K e)  to_val e = None  K = [].
260
Proof.
261 262
  rewrite eq_None_not_Some.
  destruct K as [|[]]; naive_solver eauto using fill_val.
263
Qed.
264

265 266 267
Lemma atomic_head_step e1 σ1 e2 σ2 ef :
  atomic e1  head_step e1 σ1 e2 σ2 ef  is_Some (to_val e2).
Proof. destruct 2; simpl; rewrite ?to_of_val; naive_solver. Qed.
268

269 270
Lemma atomic_step e1 σ1 e2 σ2 ef :
  atomic e1  prim_step e1 σ1 e2 σ2 ef  is_Some (to_val e2).
271
Proof.
272 273 274
  intros Hatomic [K e1' e2' -> -> Hstep].
  assert (K = []) as -> by eauto 10 using atomic_fill, values_head_stuck.
  naive_solver eauto using atomic_head_step.
Ralf Jung's avatar
Ralf Jung committed
275
Qed.
276

277
Lemma head_ctx_step_val Ki e σ1 e2 σ2 ef :
278
  head_step (fill_item Ki e) σ1 e2 σ2 ef  is_Some (to_val e).
279
Proof. destruct Ki; inversion_clear 1; simplify_option_equality; eauto. Qed.
280

281
Lemma fill_item_no_val_inj Ki1 Ki2 e1 e2 :
282
  to_val e1 = None  to_val e2 = None 
283
  fill_item Ki1 e1 = fill_item Ki2 e2  Ki1 = Ki2.
284
Proof.
285
  destruct Ki1, Ki2; intros; try discriminate; simplify_equality';
286
    repeat match goal with
287 288
    | H : to_val (of_val _) = None |- _ => by rewrite to_of_val in H
    end; auto.
Ralf Jung's avatar
Ralf Jung committed
289
Qed.
290

291 292 293 294 295 296
(* When something does a step, and another decomposition of the same expression
has a non-val [e] in the hole, then [K] is a left sub-context of [K'] - in
other words, [e] also contains the reducible expression *)
Lemma step_by_val K K' e1 e1' σ1 e2 σ2 ef :
  fill K e1 = fill K' e1'  to_val e1 = None  head_step e1' σ1 e2 σ2 ef 
  K `prefix_of` K'.
297
Proof.
298 299 300
  intros Hfill Hred Hnval; revert K' Hfill.
  induction K as [|Ki K IH]; simpl; intros K' Hfill; auto using prefix_of_nil.
  destruct K' as [|Ki' K']; simplify_equality'.
Ralf Jung's avatar
Ralf Jung committed
301
  { exfalso; apply (eq_None_not_Some (to_val (fill K e1)));
302 303
      eauto using fill_not_val, head_ctx_step_val. }
  cut (Ki = Ki'); [naive_solver eauto using prefix_of_cons|].
304
  eauto using fill_item_no_val_inj, values_head_stuck, fill_not_val.
305
Qed.
306

307 308 309
Lemma alloc_fresh e v σ :
  let l := fresh (dom _ σ) in
  to_val e = Some v  head_step (Alloc e) σ (Loc l) (<[l:=v]>σ) None.
310
Proof. by intros; apply AllocS, (not_elem_of_dom (D:=gset _)), is_fresh. Qed.
311

312 313 314 315 316 317 318 319 320 321
End heap_lang.

(** Language *)
Program Canonical Structure heap_lang : language := {|
  expr := heap_lang.expr; val := heap_lang.val; state := heap_lang.state;
  of_val := heap_lang.of_val; to_val := heap_lang.to_val;
  atomic := heap_lang.atomic; prim_step := heap_lang.prim_step;
|}.
Solve Obligations with eauto using heap_lang.to_of_val, heap_lang.of_to_val,
  heap_lang.values_stuck, heap_lang.atomic_not_val, heap_lang.atomic_step.
322

323
Global Instance heap_lang_ctx K : LanguageCtx heap_lang (heap_lang.fill K).
324
Proof.
325 326
  split.
  * eauto using heap_lang.fill_not_val.
327
  * intros ????? [K' e1' e2' Heq1 Heq2 Hstep].
328
    by exists (K ++ K') e1' e2'; rewrite ?heap_lang.fill_app ?Heq1 ?Heq2.
329
  * intros e1 σ1 e2 σ2 ? Hnval [K'' e1'' e2'' Heq1 -> Hstep].
330 331 332
    destruct (heap_lang.step_by_val
      K K'' e1 e1'' σ1 e2'' σ2 ef) as [K' ->]; eauto.
    rewrite heap_lang.fill_app in Heq1; apply (injective _) in Heq1.
Ralf Jung's avatar
Ralf Jung committed
333
    exists (heap_lang.fill K' e2''); rewrite heap_lang.fill_app; split; auto.
334
    econstructor; eauto.
335
Qed.
336 337 338 339 340 341 342

Global Instance heap_lang_ctx_item Ki :
  LanguageCtx heap_lang (heap_lang.fill_item Ki).
Proof.
  change (LanguageCtx heap_lang (heap_lang.fill [Ki])).
  by apply _.
Qed.