~james/span

ref: 868a68649c220302cb07a07563b4111f1fb392d9 span/src/Encoding.thy -rw-r--r-- 5.7 KiB
868a6864 — james Merge pull request #1 from ecstasygg/improvements 10 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
theory Encoding
  imports Relax
begin

datatype operation = Idle | Raise | Lower | Finish | Branch bool bool int

fun bytesize :: "operation \<Rightarrow> nat" where
  "bytesize (Branch c wide d) = (if wide then 3 else 2)"
| "bytesize _ = 1"

fun encodable :: "operation \<Rightarrow> bool" where
  "encodable (Branch c wide d) = (if wide then -32768 \<le> d \<and> d < 32768 else -128 \<le> d \<and> d < 128)"
| "encodable _ = True"

fun encode :: "operation \<Rightarrow> nat list" where
  "encode Idle = [0]"
| "encode Raise = [1]"
| "encode Lower = [2]"
| "encode Finish = [3]"
| "encode (Branch c False d) = [if c then 17 else 16, nat (d + 128)]"
| "encode (Branch c True d) = [if c then 19 else 18, nat (d + 32768) mod 256, nat (d + 32768) div 256]"

fun decode :: "nat list \<Rightarrow> (operation \<times> nat list) option" where
  "decode [] = None"
| "decode (b # bs) =
    (if b = 0 then Some (Idle, bs)
     else if b = 1 then Some (Raise, bs)
     else if b = 2 then Some (Lower, bs)
     else if b = 3 then Some (Finish, bs)
     else if b = 16 \<or> b = 17 then
       (case bs of [] \<Rightarrow> None | x # xs \<Rightarrow>
         if x < 256 then Some (Branch (b = 17) False (int x - 128), xs) else None)
     else if b = 18 \<or> b = 19 then
       (case bs of x # y # xs \<Rightarrow>
         if x < 256 \<and> y < 256 then Some (Branch (b = 19) True (int (y * 256 + x) - 32768), xs) else None
        | _ \<Rightarrow> None)
     else None)"

lemma encode_length [simp]: "length (encode op) = bytesize op"
  by (cases op) (auto split: bool.splits)

lemma byte_join: "n div 256 * 256 + n mod 256 = (n :: nat)"
  by (simp add: div_mult_mod_eq)

lemma encode_bytes:
  "encodable op \<Longrightarrow> set (encode op) \<subseteq> {..<256}"
  by (cases op) (auto simp: nat_less_iff div_less_iff_less_mult split: bool.splits if_splits)

theorem decode_encode:
  assumes "encodable op"
  shows "decode (encode op @ tail) = Some (op, tail)"
  using assms
  by (cases op)
    (auto simp: byte_join nat_less_iff div_less_iff_less_mult split: bool.splits if_splits)

theorem decode_canonical:
  "decode bs = Some (op, rest) \<Longrightarrow> encodable op \<and> bs = encode op @ rest"
  by (cases bs)
    (auto simp: nat_less_iff div_less_iff_less_mult mod_less div_eq_0_iff
      nat_add_distrib nat_mult_distrib
      split: if_splits list.splits)

corollary decode_progress:
  "decode bs = Some (op, rest) \<Longrightarrow> length rest < length bs"
  using decode_canonical[of bs op rest]
  by (cases op) (auto split: bool.splits)

theorem encode_injective:
  "encodable a \<Longrightarrow> encodable b \<Longrightarrow> encode a = encode b \<longleftrightarrow> a = b"
  using decode_encode[of a "[]"] decode_encode[of b "[]"]
  by (metis append_Nil option.inject prod.inject)

fun lower :: "nat instruction list \<Rightarrow> nat set \<Rightarrow> nat \<Rightarrow> nat instruction \<Rightarrow> operation" where
  "lower p W i Nop = Idle"
| "lower p W i Inc = Raise"
| "lower p W i Dec = Lower"
| "lower p W i Stop = Finish"
| "lower p W i (Jump t) = Branch False (i \<in> W) (displacement p W i)"
| "lower p W i (Zero t) = Branch True (i \<in> W) (displacement p W i)"

definition chunks :: "nat instruction list \<Rightarrow> nat set \<Rightarrow> nat list list" where
  "chunks p W = map (\<lambda>i. encode (lower p W i (p ! i))) [0..<length p]"

definition bytecode :: "nat instruction list \<Rightarrow> nat set \<Rightarrow> nat list" where
  "bytecode p W = concat (chunks p W)"

lemma chunks_code [code]:
  "chunks p W = map (\<lambda>(i,op). encode (lower p W i op)) (zip [0..<length p] p)"
  unfolding chunks_def by (rule nth_equalityI) auto

lemma lower_size:
  "i < length p \<Longrightarrow> bytesize (lower p W i (p ! i)) = width p W i"
  unfolding width_def branches_def by (cases "p ! i") auto

lemma lower_encodable:
  "valid p W \<Longrightarrow> i < length p \<Longrightarrow> encodable (lower p W i (p ! i))"
  unfolding valid_def fits_signed branches_def
  by (cases "p ! i") (auto split: if_splits)

lemma chunks_length [simp]: "length (chunks p W) = length p"
  by (simp add: chunks_def)

lemma chunks_nth:
  "i < length p \<Longrightarrow> chunks p W ! i = encode (lower p W i (p ! i))"
  by (simp add: chunks_def)

lemma prefix_length:
  "i \<le> length p \<Longrightarrow> length (concat (take i (chunks p W))) = address p W i"
proof (induction i)
  case 0
  then show ?case by simp
next
  case (Suc i)
  then have idx: "i < length p" by simp
  show ?case using Suc.IH Suc.prems
    by (simp add: take_Suc_conv_app_nth chunks_nth[OF idx] lower_size[OF idx])
qed

lemma bytecode_length: "length (bytecode p W) = address p W (length p)"
  using prefix_length[of "length p" p W] by (simp add: bytecode_def)

lemma bytecode_bytes:
  assumes valid: "valid p W"
  shows "set (bytecode p W) \<subseteq> {..<256}"
proof -
  have each: "\<And>i. i < length p \<Longrightarrow> set (encode (lower p W i (p ! i))) \<subseteq> {..<256}"
    by (rule encode_bytes, rule lower_encodable[OF valid]) assumption
  show ?thesis unfolding bytecode_def chunks_def
    by (auto dest: each[THEN subsetD])
qed

lemma fetch_instruction:
  assumes "valid p W" "i < length p"
  shows "map_option fst (decode (drop (address p W i) (bytecode p W))) = Some (lower p W i (p ! i))"
proof -
  have prefix: "bytecode p W = concat (take i (chunks p W)) @ concat (drop i (chunks p W))"
    by (simp add: bytecode_def flip: concat_append)
  have suffix: "drop i (chunks p W) = chunks p W ! i # drop (Suc i) (chunks p W)"
    using assms(2) by (simp add: Cons_nth_drop_Suc)
  show ?thesis
    using prefix_length[OF less_imp_le[OF assms(2)], of W]
    by (subst prefix, subst suffix)
      (simp add: chunks_nth[OF assms(2)] decode_encode[OF lower_encodable[OF assms]])
qed

end