annotate lab4/tgen.ml @ 1:b5139af1a420 tip basis

Fixed permissions on compile scripts
author Mike Spivey <mike@cs.ox.ac.uk>
date Fri, 13 Oct 2017 17:27:58 +0100
parents bfdcc3820b32
children
rev   line source
0
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
1 (* lab4/tgen.ml *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
2 (* Copyright (c) 2017 J. M. Spivey *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
3
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
4 open Dict
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
5 open Tree
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
6 open Mach
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
7 open Optree
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
8 open Lexer
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
9 open Print
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
10
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
11 let boundchk = ref false
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
12 let optlevel = ref 0
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
13 let debug = ref 0
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
14
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
15 (* |level| -- nesting level of current procedure *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
16 let level = ref 0
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
17
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
18 (* |retlab| -- label to return from current procedure *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
19 let retlab = ref nolab
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
20
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
21 (* |size_of| -- calculate size of type *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
22 let size_of t = t.t_rep.r_size
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
23
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
24 (* |get_value| -- get constant value or fail *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
25 let get_value e =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
26 match e.e_value with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
27 Some v -> v
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
28 | None -> failwith "get_value"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
29
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
30 (* |line_number| -- compute line number of variable for bound check *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
31 let rec line_number v =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
32 match v.e_guts with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
33 Variable x -> x.x_line
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
34 | Sub (a, i) -> line_number a
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
35 | Select (r, x) -> x.x_line
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
36 | Deref p -> line_number p
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
37 | _ -> failwith "line_number"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
38
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
39 (* |addr_size| -- size of address *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
40 let addr_size = addr_rep.r_size
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
41
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
42 (* |schain| -- code to follow N links of static chain *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
43 let rec schain n =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
44 if n = 0 then
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
45 <LOCAL 0>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
46 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
47 <LOADW, <OFFSET, schain (n-1), <CONST stat_link>>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
48
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
49 (* |address| -- code to push address of an object *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
50 let address d =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
51 match d.d_addr with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
52 Global g ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
53 <GLOBAL g>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
54 | Local off ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
55 <OFFSET, schain (!level - d.d_level), <CONST off>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
56 | Register i ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
57 <REGVAR i>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
58 | Nowhere ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
59 failwith (sprintf "address $" [fId d.d_tag])
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
60
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
61 (* |gen_closure| -- two trees for a (code, envt) pair *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
62 let gen_closure d =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
63 match d.d_kind with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
64 ProcDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
65 (address d,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
66 if d.d_level = 0 then <CONST 0> else schain (!level - d.d_level))
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
67 | PParamDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
68 (<LOADW, address d>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
69 <LOADW, <OFFSET, address d, <CONST addr_size>>>)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
70 | _ -> failwith "missing closure"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
71
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
72 let rec numargs i =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
73 function
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
74 [] -> []
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
75 | (x::xs) -> <ARG i, x> :: numargs (i+1) xs
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
76
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
77 (* |libcall| -- code for library call *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
78 let libcall lab args rtype =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
79 let n = List.length args in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
80 <PCALL n, @(<GLOBAL lab> :: numargs 0 args)>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
81
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
82 (* |gen_copy| -- generate code to copy a fixed-size chunk *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
83 let gen_copy dst src n =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
84 libcall "memcpy" [dst; src; <CONST n>] voidtype
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
85
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
86 (* |gen_addr| -- code for the address of a variable *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
87 let rec gen_addr v =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
88 match v.e_guts with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
89 Variable x ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
90 let d = get_def x in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
91 begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
92 match d.d_kind with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
93 VarDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
94 address d
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
95 | VParamDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
96 <LOADW, address d>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
97 | CParamDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
98 if scalar d.d_type || is_pointer d.d_type then
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
99 address d
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
100 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
101 <LOADW, address d>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
102 | StringDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
103 address d
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
104 | _ ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
105 failwith "load_addr"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
106 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
107 | Sub (a, i) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
108 let bound_check t =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
109 if not !boundchk then t else <BOUND, t, <CONST (bound a.e_type)>> in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
110 <OFFSET,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
111 gen_addr a,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
112 <BINOP Times, bound_check (gen_expr i), <CONST (size_of v.e_type)>>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
113 | Select (r, x) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
114 let d = get_def x in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
115 <OFFSET, gen_addr r, <CONST (offset_of d)>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
116 | Deref p ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
117 let null_check t =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
118 if not !boundchk then t else <NCHECK, t> in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
119 null_check (gen_expr p)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
120 | String (lab, n) -> <GLOBAL lab>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
121 | _ -> failwith "gen_addr"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
122
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
123 (* |gen_expr| -- tree for the value of an expression *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
124 and gen_expr e =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
125 match e.e_value with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
126 Some v ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
127 <CONST v>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
128 | None ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
129 begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
130 match e.e_guts with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
131 Variable _ | Sub _ | Select _ | Deref _ ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
132 let ld = if size_of e.e_type = 1 then LOADC else LOADW in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
133 <ld, gen_addr e>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
134 | Monop (w, e1) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
135 <MONOP w, gen_expr e1>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
136 | Binop (Div, e1, e2) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
137 libcall "int_div" [gen_expr e1; gen_expr e2] integer
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
138 | Binop (Mod, e1, e2) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
139 libcall "int_mod" [gen_expr e1; gen_expr e2] integer
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
140 | Binop (w, e1, e2) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
141 <BINOP w, gen_expr e1, gen_expr e2>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
142 | FuncCall (p, args) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
143 gen_call p args
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
144 | _ -> failwith "gen_expr"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
145 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
146
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
147 (* |gen_call| -- generate code to call a procedure *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
148 and gen_call x args =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
149 let d = get_def x in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
150 match d.d_kind with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
151 LibDef q ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
152 gen_libcall q args
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
153 | _ ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
154 let p = get_proc d.d_type in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
155 let (fn, sl) = gen_closure d in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
156 let args = List.concat (List.map2 gen_arg p.p_fparams args) in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
157 <PCALL p.p_pcount, @(fn :: <SLINK, sl> :: numargs 0 args)>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
158
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
159 (* |gen_arg| -- generate code for a procedure argument *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
160 and gen_arg f a =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
161 match f.d_kind with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
162 CParamDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
163 if scalar f.d_type || is_pointer f.d_type then
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
164 [gen_expr a]
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
165 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
166 [gen_addr a]
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
167 | VParamDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
168 [gen_addr a]
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
169 | PParamDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
170 begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
171 match a.e_guts with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
172 Variable x ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
173 let (fn, sl) = gen_closure (get_def x) in [fn; sl]
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
174 | _ ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
175 failwith "bad funarg"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
176 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
177 | _ -> failwith "bad arg"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
178
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
179 (* |gen_libcall| -- generate code to call a built-in procedure *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
180 and gen_libcall q args =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
181 match (q.q_id, args) with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
182 (ChrFun, [e]) -> gen_expr e
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
183 | (OrdFun, [e]) -> gen_expr e
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
184 | (PrintString, [e]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
185 libcall "print_string" [gen_addr e; <CONST (bound e.e_type)>] voidtype
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
186 | (ReadChar, [e]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
187 libcall "read_char" [gen_addr e] voidtype
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
188 | (NewProc, [e]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
189 let size = size_of (base_type e.e_type) in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
190 <STOREW, libcall "new" [<CONST size>] addrtype, gen_addr e>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
191 | (ArgcFun, []) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
192 libcall "argc" [] integer
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
193 | (ArgvProc, [e1; e2]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
194 libcall "argv" [gen_expr e1; gen_addr e2] voidtype
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
195 | (OpenIn, [e]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
196 libcall "open_in" [gen_addr e] voidtype
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
197 | (Operator op, [e1]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
198 <MONOP op, gen_expr e1>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
199 | (Operator op, [e1; e2]) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
200 <BINOP op, gen_expr e1, gen_expr e2>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
201 | (_, _) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
202 let proc = sprintf "$" [fLibId q.q_id] in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
203 libcall proc (List.map gen_expr args) voidtype
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
204
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
205 (* |gen_cond| -- generate code to branch on a condition *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
206 let rec gen_cond test tlab flab =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
207 match test.e_value with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
208 Some v ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
209 if v <> 0 then <JUMP tlab> else <JUMP flab>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
210 | None ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
211 begin match test.e_guts with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
212 Monop (Not, e) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
213 gen_cond e flab tlab
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
214 | Binop (Or, e1, e2) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
215 let l1 = label () in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
216 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
217 gen_cond e1 tlab l1,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
218 <LABEL l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
219 gen_cond e2 tlab flab>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
220 | Binop (And, e1, e2) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
221 let l1 = label () in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
222 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
223 gen_cond e1 l1 flab,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
224 <LABEL l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
225 gen_cond e2 tlab flab>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
226 | Binop ((Eq | Neq | Lt | Leq | Gt | Geq) as w, e1, e2) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
227 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
228 <JUMPC (w, tlab), gen_expr e1, gen_expr e2>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
229 <JUMP flab>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
230 | _ ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
231 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
232 <JUMPC (Neq, tlab), gen_expr test, <CONST 0>>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
233 <JUMP flab>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
234 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
235
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
236 (* |gen_jtable| -- lay out jump table for case statement *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
237 let gen_jtable sel table0 deflab =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
238 if table0 = [] then
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
239 <JUMP deflab>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
240 else begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
241 let table = List.sort (fun (v1, l1) (v2, l2) -> compare v1 v2) table0 in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
242 let lobound = fst (List.hd table) in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
243 let rec tab u qs =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
244 match qs with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
245 [] -> []
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
246 | (v, l) :: rs ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
247 if u = v then l :: tab (v+1) rs else deflab :: tab (u+1) qs in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
248 <JCASE (tab lobound table, deflab),
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
249 <BINOP Minus, sel, <CONST lobound>>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
250 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
251
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
252 (* |gen_stmt| -- generate code for a statement *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
253 let rec gen_stmt s =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
254 let code =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
255 match s.s_guts with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
256 Skip -> <NOP>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
257
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
258 | Seq ss -> <SEQ, @(List.map gen_stmt ss)>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
259
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
260 | Assign (v, e) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
261 if scalar v.e_type || is_pointer v.e_type then begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
262 let st = if size_of v.e_type = 1 then STOREC else STOREW in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
263 <st, gen_expr e, gen_addr v>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
264 end else begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
265 gen_copy (gen_addr v) (gen_addr e) (size_of v.e_type)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
266 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
267
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
268 | ProcCall (p, args) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
269 gen_call p args
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
270
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
271 | Return res ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
272 begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
273 match res with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
274 Some e -> <SEQ, <RESULTW, gen_expr e>, <JUMP !retlab>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
275 | None -> <JUMP !retlab>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
276 end
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
277
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
278 | IfStmt (test, thenpt, elsept) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
279 let l1 = label () and l2 = label () and l3 = label() in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
280 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
281 gen_cond test l1 l2,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
282 <LABEL l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
283 gen_stmt thenpt,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
284 <JUMP l3>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
285 <LABEL l2>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
286 gen_stmt elsept,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
287 <LABEL l3>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
288
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
289 | WhileStmt (test, body) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
290 let l1 = label () and l2 = label () and l3 = label() in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
291 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
292 <LABEL l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
293 gen_cond test l2 l3,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
294 <LABEL l2>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
295 gen_stmt body,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
296 <JUMP l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
297 <LABEL l3>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
298
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
299 | RepeatStmt (body, test) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
300 let l1 = label () and l2 = label () in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
301 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
302 <LABEL l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
303 gen_stmt body,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
304 gen_cond test l2 l1,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
305 <LABEL l2>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
306
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
307 | ForStmt (var, lo, hi, body, upb) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
308 (* Use previously allocated temp variable to store upper bound.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
309 We could avoid this if the upper bound is constant. *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
310 let tmp = match !upb with Some d -> d | _ -> failwith "for" in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
311 let l1 = label () and l2 = label () in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
312 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
313 <STOREW, gen_expr lo, gen_addr var>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
314 <STOREW, gen_expr hi, address tmp>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
315 <LABEL l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
316 <JUMPC (Gt, l2), gen_expr var, <LOADW, address tmp>>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
317 gen_stmt body,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
318 <STOREW, <BINOP Plus, gen_expr var, <CONST 1>>, gen_addr var>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
319 <JUMP l1>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
320 <LABEL l2>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
321
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
322 | CaseStmt (sel, arms, deflt) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
323 (* Use one jump table, and hope it is reasonably compact *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
324 let deflab = label () and donelab = label () in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
325 let labs = List.map (function x -> label ()) arms in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
326 let get_val (v, body) = get_value v in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
327 let table = List.combine (List.map get_val arms) labs in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
328 let gen_case lab (v, body) =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
329 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
330 <LABEL lab>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
331 gen_stmt body,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
332 <JUMP donelab>> in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
333 <SEQ,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
334 gen_jtable (gen_expr sel) table deflab,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
335 <SEQ, @(List.map2 gen_case labs arms)>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
336 <LABEL deflab>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
337 gen_stmt deflt,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
338 <LABEL donelab>> in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
339
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
340 (* Label the code with a line number *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
341 <SEQ, <LINE s.s_line>, code>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
342
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
343 (* unnest -- move procedure calls to top level *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
344 let unnest code =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
345 let rec do_tree =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
346 function
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
347 <PCALL n, @args> ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
348 let t = Regs.new_temp 1 in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
349 <AFTER,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
350 <DEFTMP t, <PCALL n, @(List.map do_tree args)>>,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
351 <TEMP t>>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
352 | <w, @args> ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
353 <w, @(List.map do_tree args)> in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
354 let do_root =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
355 function <op, @args> -> <op, @(List.map do_tree args)> in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
356 Optree.canon <SEQ, @(List.map do_root code)>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
357
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
358 let show label code =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
359 if !debug > 0 then begin
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
360 printf "$$:\n" [fStr Mach.comment; fStr label];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
361 List.iter (Optree.print_optree Mach.comment) code;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
362 printf "\n" []
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
363 end;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
364 code
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
365
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
366 (* |do_proc| -- generate code for a procedure and pass to the back end *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
367 let do_proc lab lev nargs (Block (_, body, fsize, nregv)) =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
368 level := lev+1;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
369 retlab := label ();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
370 let code0 =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
371 show "Initial code" (Optree.canon <SEQ, gen_stmt body, <LABEL !retlab>>) in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
372 Regs.init ();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
373 let code1 = if !optlevel < 1 then code0 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
374 show "After simplification" (Jumpopt.optimise (Simp.optimise code0)) in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
375 let code2 = if !optlevel < 2 then
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
376 show "After unnesting" (unnest code1)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
377 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
378 show "After sharing" (Share.traverse code1) in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
379 Tran.translate lab nargs !fsize !nregv (flatten code2)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
380
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
381 (* |get_label| -- extract label for global definition *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
382 let get_label d =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
383 match d.d_addr with Global lab -> lab | _ -> failwith "get_label"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
384
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
385 let get_decls (Block (decls, _, _, _)) = decls
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
386
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
387 (* |gen_proc| -- translate a procedure, ignore other declarations *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
388 let rec gen_proc =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
389 function
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
390 ProcDecl (Heading (x, _, _), block) ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
391 let d = get_def x in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
392 let p = get_proc d.d_type in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
393 let line = Source.get_line x.x_line in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
394 printf "$$\n" [fStr Mach.comment; fStr line];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
395 do_proc (get_label d) d.d_level p.p_pcount block;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
396 gen_procs (get_decls block)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
397 | _ -> ()
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
398
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
399 (* |gen_procs| -- generate code for the procedures in a block *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
400 and gen_procs ds = List.iter gen_proc ds
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
401
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
402 (* |gen_global| -- generate declaration for global variable *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
403 let gen_global d =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
404 match d.d_kind with
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
405 VarDef ->
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
406 Target.emit_global (get_label d) (size_of d.d_type)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
407 | _ -> ()
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
408
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
409 (* |translate| -- generate code for the whole program *)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
410 let translate (Prog (block, glodefs)) =
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
411 Target.preamble ();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
412 gen_procs (get_decls block);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
413 do_proc "pmain" 0 0 block;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
414 List.iter gen_global !glodefs;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
415 List.iter (fun (lab, s) -> Target.emit_string lab s) (string_table ());
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
416 Target.postamble ()
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
417