2 Simplifies the MIR. This file rewrites some of the higher
3 level MIR primitives into simpler expressions so we don't
4 have to worry about them in the backend -- some of the safety
5 checks and whatnot are harder to deal with in backend. Note
6 that this code may be called by the backend itself if they
7 need to run an expression...
10 Copyright (C) 2001 Justin David Smith, Caltech
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
44 module Pos
= MakePos
(struct let name = "Mir_simplify" end)
51 module MirSimplify
(Frame
: BackendSig
) : MirSimplifySig
=
53 module MirUtil
= Mir_util.MirUtil
(Frame
)
54 module MirArity
= Mir_arity.MirArity
(Frame
)
60 string_pos
"Mir_simplify" (exp_pos pos
)
63 (*** Simplification of Atoms ***)
67 These functions transform the complex *atom* expressions into simpler
68 expressions that we can work with in the backend. Note that simplifying
69 atoms may require the addition of new *expression* statements, PRIOR to
70 the use of the atom. Because of this, we have to play a bit of a logic
73 Each of these functions takes a function called e_cont, as well as the
74 atom to be simplified. The code computes the expression and a new,
75 simplified atom expression -- the simplified atom is usually a variable
76 that contains the result. We call e_cont with *this* atom, and e_cont
77 computes the rest of the program with the substituted atom. We then
78 prepend our expression to the result. A new expression (with the
79 substituted atoms) is returned.
83 (* Specifies what operation to perform for *_of_index functions.
84 The *_of_index functions take this operator to determine what
85 type of code they are emitting. *)
87 Safe
(* Pointer is safe, no checks required *)
88 | Unsafe
(* Pointer is unsafe, but no check required *)
89 | UnsafeCheck
(* Pointer is unsafe, please check it *)
93 Returns true if the operation specified is ``safe''. Note: this
94 affects the memory representation only; if no safety checks were
95 enabled, then we'll call everything safe so everything uses the
96 simple representation. *)
97 let is_safe = function
102 not
(Fir_state.safety_enabled
())
106 Returns true if the operation specified wants to ``check''. *)
107 let do_check = function
116 Express a hashed index->pointer operation, assuming the usual
117 safety checks may be required in the code. This uses the pointer
118 table. The op specifies whether this is a safe index->pointer
119 conversion, or an unsafe. The op also specifies whether checks
121 let pointer_of_index arity_tags pos loc ptrty op a_hashed_index e_cont
=
122 let pos = string_pos
"pointer_of_index" pos in
123 let v_index = new_symbol_string
"index" in
124 let v_index_test = new_symbol_string
"index_test" in
125 let v_pointer = new_symbol_string
"pointer" in
126 let v_bit = new_symbol_string
"bit" in
127 let ac_pointer = ACPointer ptrty
in
128 let a_cont = AtomVar
(ac_pointer, v_pointer) in
129 let e_cont = e_cont a_cont in
131 (* Construct the segfault expressions *)
132 let seg_fault_index_expr = (* Index was invalid *)
133 make_exp loc
(TailCall
(ExternalCall
, seg_fault_labels
.(index_fault
),
134 [a_hashed_index
; AtomVar
(ac_native_unsigned
, v_index)]))
136 let seg_fault_pointer_expr = (* Pointer in ptbl was invalid *)
137 make_exp loc
(TailCall
(ExternalCall
, seg_fault_labels
.(pointer_index_fault
),
139 AtomVar
(ac_native_unsigned
, v_index);
140 AtomVar
(ac_pointer, v_pointer)]))
143 (* STEP 1 - Compute index from hash. *)
146 (* Safe pointers do not hash their value, currently *)
147 make_exp loc
(LetAtom
(v_index, ac_native_unsigned
, a_hashed_index
, e
))
149 (* Convert an unsafe hashed index into a real index *)
150 make_exp loc
(LetAtom
(v_index, ac_native_unsigned
,
151 AtomBinop
(AndOp ac_native_unsigned
, AtomRawInt
(Rawint.of_int
Rawint.Int32
false 0xfffffffc),
152 AtomBinop
(XorOp ac_native_unsigned
, a_hashed_index
, hash_native_unsigned
)), e
))
153 in (* end of build_step1 *)
155 (* STEP 2 - Check that the index is valid. *)
158 (* Check that it is a valid index *)
159 make_exp loc
(LetAtom
(v_index_test, ac_native_bool
,
160 AtomBinop
(LtOp ac_native_unsigned
,
161 AtomVar
(ac_native_unsigned
, v_index),
162 AtomVar
(ac_native_unsigned
, pointer_size
)),
163 make_exp loc
(Match
(AtomVar
(ac_native_bool
, v_index_test), ac_native_bool
,
164 [RawIntSet native_false_set
, seg_fault_index_expr;
165 RawIntSet native_true_set
, e
]))))
167 (* No check required. *)
169 in (* end of build_step2 *)
171 (* STEP 3 - Read from pointer table *)
173 (* Read the pointer from the ptbl *)
174 make_exp loc
(LetAtom
(v_pointer, ac_pointer,
175 AtomBinop
(MemOp
(ac_pointer, PtrAggr
), AtomVar
(ac_pointer_base
, pointer_base
),
176 AtomVar
(ac_native_unsigned
, v_index)), e
))
177 in (* end of build_step3 *)
179 (* STEP 4 - Check that the pointer is valid. *)
182 (* Check that the pointer is valid *)
183 make_exp loc
(LetAtom
(v_bit, ac_native_unsigned
,
184 AtomBinop
(AndOp ac_native_unsigned
,
185 AtomUnop
(Int32OfPointerOp ptrty
, AtomVar
(ac_pointer, v_pointer)),
186 AtomRawInt one_pointer
),
187 make_exp loc
(Match
(AtomVar
(ac_native_unsigned
, v_bit), ac_native_unsigned
,
188 [RawIntSet one_pointer_set
, seg_fault_pointer_expr;
189 RawIntSet zero_pointer_set
, e
]))))
191 (* No check required. *)
193 in (* end of build_step2 *)
195 (* Construct the index->pointer operation *)
196 build_step1 (build_step2 (build_step3 (build_step4 e_cont)))
200 Express a hashed index->pointer operation, assuming the usual
201 safety checks are required in the code. This uses the function
202 pointer table. The op specifies whether this is a safe function
203 conversion or unsafe, and also specifies whether checks should
205 let function_of_index arity_tags
pos loc funty op a_hashed_index
e_cont =
206 let pos = string_pos
"function_of_index" pos in
207 let v_index = new_symbol_string
"index" in
208 let v_index_test = new_symbol_string
"index_test" in
209 let v_pointer = new_symbol_string
"pointer" in
210 let ac_pointer = ACFunction funty
in
211 let v_arity_test = new_symbol_string
"arity_test" in
212 let v_arity_tag = new_symbol_string
"arity_tag" in
213 let ac_arity_tag = ac_native_unsigned
in
214 let a_cont = AtomVar
(ac_pointer, v_pointer) in
215 let e_cont = e_cont a_cont in
217 (* Compute the required arity tag for this function pointer. *)
218 let arity_tag, _
= arity_lookup_by_funty arity_tags
pos funty
in
220 (* Construct the segfault expressions *)
221 let seg_fault_index_expr = (* Index was invalid *)
222 make_exp loc
(TailCall
(ExternalCall
, seg_fault_labels
.(fun_index_fault
),
223 [a_hashed_index
; AtomVar
(ac_native_unsigned
, v_index)]))
225 let seg_fault_arity_tag_expr = (* Arity tags not compatible *)
226 make_exp loc
(TailCall
(ExternalCall
, seg_fault_labels
.(fun_arity_tag_fault
),
227 [a_hashed_index
; AtomVar
(ac_native_unsigned
, v_index);
228 AtomVar
(ac_arity_tag, arity_tag); AtomVar
(ac_arity_tag, v_arity_tag)]))
231 (* STEP 1 - Compute index from hash *)
234 (* Safe pointers do not hash their indices, currently *)
235 make_exp loc
(LetAtom
(v_index, ac_native_unsigned
, a_hashed_index
, e
))
237 (* Unhash the unsafe function index *)
238 make_exp loc
(LetAtom
(v_index, ac_native_unsigned
,
239 AtomBinop
(XorOp ac_native_unsigned
, a_hashed_index
, hash_fun_native_unsigned
),
241 in (* end of build_step1 *)
243 (* STEP 2 - Check that the index is valid *)
246 (* Check that it is a valid index *)
247 make_exp loc
(LetAtom
(v_index_test, ac_native_bool
,
248 AtomBinop
(LtOp ac_native_unsigned
,
249 AtomVar
(ac_native_unsigned
, v_index),
250 AtomVar
(ac_native_unsigned
, function_size
)),
251 make_exp loc
(Match
(AtomVar
(ac_native_bool
, v_index_test), ac_native_bool
,
252 [RawIntSet native_false_set
, seg_fault_index_expr;
253 RawIntSet native_true_set
, e
]))))
255 (* No check required. *)
257 in (* end of build_step2 *)
259 (* STEP 3 - Read from function table - pointers in the function
260 table are always valid pointers, since they are in code seg. *)
262 (* Read the pointer from the ptbl *)
263 make_exp loc
(LetAtom
(v_pointer, ac_pointer,
264 AtomBinop
(MemOp
(ac_pointer, PtrAggr
), AtomVar
(ac_pointer_base
, function_base
),
265 AtomVar
(ac_native_unsigned
, v_index)),
267 in (* end of build_step3 *)
269 (* STEP 4 - Check that the arity tag is compatible. *)
271 if Fir_state.safe_functions
() then
272 (* Get arity tag on the function header block. *)
273 make_exp loc
(LetAtom
(v_arity_tag, ac_arity_tag,
274 AtomUnop
(MemFunArityTagOp
(funty
, ac_arity_tag),
275 AtomVar
(ac_pointer, v_pointer)),
276 (* Check the arity tag *)
277 make_exp loc
(LetAtom
(v_arity_test, ac_native_bool
,
278 AtomBinop
(EqOp ac_native_unsigned
,
279 AtomVar
(ac_arity_tag, v_arity_tag),
280 AtomVar
(ac_arity_tag, arity_tag)),
281 make_exp loc
(Match
(AtomVar
(ac_arity_tag, v_arity_tag), ac_arity_tag,
282 [RawIntSet native_false_set
, seg_fault_arity_tag_expr;
283 RawIntSet native_true_set
, e
]))))))
285 (* No arity check required *)
287 in (* end of build_step4 *)
289 (* Construct the final expression. *)
290 build_step1 (build_step2 (build_step3 (build_step4 e_cont)))
294 Converts a pointer into an index. The op specifies whether the
295 conversion is using safe or unsafe representation. *)
296 let index_of_pointer arity_tags
pos loc ptrty op a_pointer
e_cont =
297 let pos = string_pos
"index_of_pointer" pos in
298 let ac_index = ACRawInt
(precision_native_int
, unsigned_int
) in
299 let a_index = AtomUnop
(MemIndexOp
(ptrty
, ac_index), a_pointer
) in
303 e_cont (AtomBinop
(XorOp ac_native_unsigned
, a_index, hash_native_unsigned
))
307 Converts a function pointer into an index. The op specifies
308 whether the conversion is using safe or unsafe representation. *)
309 let index_of_function arity_tags
pos loc funty op a_pointer
e_cont =
310 let pos = string_pos
"index_of_function" pos in
311 let ac_index = ACRawInt
(precision_native_int
, unsigned_int
) in
312 let a_index = AtomUnop
(MemFunIndexOp
(funty
, ac_index), a_pointer
) in
316 e_cont (AtomBinop
(XorOp ac_native_unsigned
, a_index, hash_fun_native_unsigned
))
320 Simplifies the atom given. *)
321 let rec mir_simplify_atom arity_tags
pos loc a
e_cont =
322 let pos = string_pos
"mir_simplify_atom" pos in
330 | AtomUnop
(op
, a
) ->
331 mir_simplify_unop_atom arity_tags
pos loc op a
e_cont
332 | AtomBinop
(op
, a1
, a2
) ->
333 mir_simplify_binop_atom arity_tags
pos loc op a1 a2
e_cont
336 (* mir_simplify_unop_atom
337 Simplifies the unary operator given. *)
338 and mir_simplify_unop_atom arity_tags
pos loc op a
e_cont =
339 let pos = string_pos
"mir_simplify_unop_atom" pos in
340 mir_simplify_atom arity_tags
pos loc a
(fun a
->
342 SafePointerOfIndexOp ptrty
->
343 pointer_of_index arity_tags
pos loc ptrty Safe a
e_cont
344 | UnsafePointerOfIndexOp ptrty
->
345 pointer_of_index arity_tags
pos loc ptrty Unsafe a
e_cont
346 | SafeFunctionOfIndexOp funty
->
347 function_of_index arity_tags
pos loc funty Safe a
e_cont
348 | UnsafeFunctionOfIndexOp funty
->
349 function_of_index arity_tags
pos loc funty Unsafe a
e_cont
350 | SafeIndexOfPointerOp ptrty
->
351 index_of_pointer arity_tags
pos loc ptrty Safe a
e_cont
352 | UnsafeIndexOfPointerOp ptrty
->
353 index_of_pointer arity_tags
pos loc ptrty Unsafe a
e_cont
354 | SafeIndexOfFunctionOp funty
->
355 index_of_function arity_tags
pos loc funty Safe a
e_cont
356 | UnsafeIndexOfFunctionOp funty
->
357 index_of_function arity_tags
pos loc funty Unsafe a
e_cont
359 e_cont (AtomUnop
(op
, a
)))
362 (* mir_simplify_binop_atom
363 Simplifies the binary operator given. *)
364 and mir_simplify_binop_atom arity_tags
pos loc op a1 a2
e_cont =
365 let pos = string_pos
"mir_simplify_binop_atom" pos in
366 mir_simplify_atom arity_tags
pos loc a1
(fun a1
->
367 mir_simplify_atom arity_tags
pos loc a2
(fun a2
->
368 e_cont (AtomBinop
(op
, a1
, a2
))))
371 (* mir_simplify_atom_list
372 Simplifies a list of atoms, in order. *)
373 let mir_simplify_atom_list arity_tags
pos loc atoms
e_cont =
374 let pos = string_pos
"mir_simplify_atom_list" pos in
375 let rec mir_simplify_atom_list arity_tags res
= function
377 mir_simplify_atom arity_tags
pos loc a
(fun a
->
378 mir_simplify_atom_list arity_tags
(a
:: res
) atoms
)
380 e_cont (List.rev res
)
382 mir_simplify_atom_list arity_tags
[] atoms
385 (* mir_simplify_atom_option
386 Simplifies an optional atom. *)
387 let mir_simplify_atom_option arity_tags
pos loc atom
e_cont =
388 let pos = string_pos
"mir_simplify_atom_option" pos in
391 mir_simplify_atom arity_tags
pos loc atom
(fun atom
->
397 (*** Simplification of Expressions ***)
401 Simplifies the expression given. *)
402 let rec mir_simplify_expr arity_tags e
=
403 let pos = string_pos
"mir_simplify_expr" (exp_pos e
) in
404 let loc = loc_of_exp e
in
405 match dest_exp_core e
with
406 LetAtom
(v
, ac
, a
, e
) ->
407 mir_simplify_atom arity_tags
pos loc a
(fun a
->
408 let e = mir_simplify_expr arity_tags
e in
409 make_exp
loc (LetAtom
(v
, ac
, a
, e)))
410 | TailCall
(op
, f
, atoms
) ->
411 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
412 make_exp
loc (TailCall
(op
, f
, atoms
)))
413 | IfThenElse
(op
, a1
, a2
, e1
, e2
) ->
414 mir_simplify_atom arity_tags
pos loc a1
(fun a1
->
415 mir_simplify_atom arity_tags
pos loc a2
(fun a2
->
416 let e1 = mir_simplify_expr arity_tags
e1 in
417 let e2 = mir_simplify_expr arity_tags
e2 in
418 make_exp
loc (IfThenElse
(op
, a1
, a2
, e1, e2))))
419 | IfType
(obj
, names
, name, v
, e1, e2) ->
420 mir_simplify_atom arity_tags
pos loc obj
(fun obj
->
421 mir_simplify_atom arity_tags
pos loc names
(fun names
->
422 mir_simplify_atom arity_tags
pos loc name (fun name ->
423 let e1 = mir_simplify_expr arity_tags
e1 in
424 let e2 = mir_simplify_expr arity_tags
e2 in
425 make_exp
loc (IfType
(obj
, names
, name, v
, e1, e2)))))
426 | Match
(a
, ac
, cases
) ->
427 mir_simplify_atom arity_tags
pos loc a
(fun a
->
428 let process_case (set
, e) = (set
, mir_simplify_expr arity_tags
e) in
429 let cases = List.map
process_case cases in
430 make_exp
loc (Match
(a
, ac
, cases)))
431 | LetExternal
(v
, ac
, f
, atoms
, e) ->
432 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
433 let e = mir_simplify_expr arity_tags
e in
434 make_exp
loc (LetExternal
(v
, ac
, f
, atoms
, e)))
435 | LetExternalReserve
((label
, vars
, mem
, ptr
), v
, ac
, f
, atoms
, e) ->
436 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
437 mir_simplify_atom arity_tags
pos loc mem
(fun mem
->
438 mir_simplify_atom arity_tags
pos loc ptr
(fun ptr
->
439 let e = mir_simplify_expr arity_tags
e in
440 make_exp
loc (LetExternalReserve
((label
, vars
, mem
, ptr
), v
, ac
, f
, atoms
, e)))))
441 | Reserve
((label
, vars
, mem
, ptr
), e) ->
442 mir_simplify_atom arity_tags
pos loc mem
(fun mem
->
443 mir_simplify_atom arity_tags
pos loc ptr
(fun ptr
->
444 let e = mir_simplify_expr arity_tags
e in
445 make_exp
loc (Reserve
((label
, vars
, mem
, ptr
), e))))
446 | LetAlloc
(v
, AllocTuple atoms
, e) ->
447 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
448 let e = mir_simplify_expr arity_tags
e in
449 make_exp
loc (LetAlloc
(v
, AllocTuple atoms
, e)))
450 | LetAlloc
(v
, AllocArray atoms
, e) ->
451 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
452 let e = mir_simplify_expr arity_tags
e in
453 make_exp
loc (LetAlloc
(v
, AllocArray atoms
, e)))
454 | LetAlloc
(v
, AllocMArray
(atoms
, a
), e) ->
455 mir_simplify_atom arity_tags
pos loc a
(fun a
->
456 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
457 let e = mir_simplify_expr arity_tags
e in
458 make_exp
loc (LetAlloc
(v
, AllocMArray
(atoms
, a
), e))))
459 | LetAlloc
(v
, AllocUnion
(tag
, atoms
), e) ->
460 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
461 let e = mir_simplify_expr arity_tags
e in
462 make_exp
loc (LetAlloc
(v
, AllocUnion
(tag
, atoms
), e)))
463 | LetAlloc
(v
, AllocMalloc a
, e) ->
464 mir_simplify_atom arity_tags
pos loc a
(fun a
->
465 let e = mir_simplify_expr arity_tags
e in
466 make_exp
loc (LetAlloc
(v
, AllocMalloc a
, e)))
467 | SetMem
(ac
, op
, a1
, a2
, a3
, e) ->
468 mir_simplify_atom arity_tags
pos loc a1
(fun a1
->
469 mir_simplify_atom arity_tags
pos loc a2
(fun a2
->
470 mir_simplify_atom arity_tags
pos loc a3
(fun a3
->
471 let e = mir_simplify_expr arity_tags
e in
472 make_exp
loc (SetMem
(ac
, op
, a1
, a2
, a3
, e)))))
473 | SetGlobal
(ac
, v
, a
, e) ->
474 mir_simplify_atom arity_tags
pos loc a
(fun a
->
475 let e = mir_simplify_expr arity_tags
e in
476 make_exp
loc (SetGlobal
(ac
, v
, a
, e)))
477 | BoundsCheck
(label
, ptrty
, ptr
, start
, stop
, e) ->
478 mir_simplify_bounds_check arity_tags
pos loc label ptrty ptr start stop
e
479 | LowerBoundsCheck
(label
, ptrty
, ptr
, start
, e) ->
480 mir_simplify_lower_bounds_check arity_tags
pos loc label ptrty ptr start
e
481 | UpperBoundsCheck
(label
, ptrty
, ptr
, stop
, e) ->
482 mir_simplify_upper_bounds_check arity_tags
pos loc label ptrty ptr stop
e
483 | PointerIndexCheck
(label
, ptrty
, v
, ac
, index
, e) ->
484 mir_simplify_atom arity_tags
pos loc index
(fun index
->
485 pointer_of_index arity_tags
pos loc ptrty UnsafeCheck index
(fun a
->
486 let e = mir_simplify_expr arity_tags
e in
487 make_exp
loc (LetAtom
(v
, ac
, a
, e))))
488 | FunctionIndexCheck
(label
, funty
, v
, ac
, index
, e) ->
489 mir_simplify_atom arity_tags
pos loc index
(fun index
->
490 function_of_index arity_tags
pos loc funty UnsafeCheck index
(fun a
->
491 let e = mir_simplify_expr arity_tags
e in
492 make_exp
loc (LetAtom
(v
, ac
, a
, e))))
493 | Memcpy
(op
, a1
, a2
, a3
, a4
, a5
, e) ->
494 mir_simplify_atom arity_tags
pos loc a1
(fun a1
->
495 mir_simplify_atom arity_tags
pos loc a2
(fun a2
->
496 mir_simplify_atom arity_tags
pos loc a3
(fun a3
->
497 mir_simplify_atom arity_tags
pos loc a4
(fun a4
->
498 mir_simplify_atom arity_tags
pos loc a5
(fun a5
->
499 let e = mir_simplify_expr arity_tags
e in
500 make_exp
loc (Memcpy
(op
, a1
, a2
, a3
, a4
, a5
, e)))))))
502 let e = mir_simplify_expr arity_tags
e in
503 make_exp
loc (Debug
(info
, e))
504 | PrintDebug
(v1
, v2
, atoms
, e) ->
505 mir_simplify_atom_list arity_tags
pos loc atoms
(fun atoms
->
506 let e = mir_simplify_expr arity_tags
e in
507 make_exp
loc (PrintDebug
(v1
, v2
, atoms
, e)))
508 | CommentFIR
(fir
, e) ->
509 let e = mir_simplify_expr arity_tags
e in
510 make_exp
loc (CommentFIR
(fir
, e))
511 | SysMigrate
(label
, dst_ptr
, dst_off
, f
, env
) ->
512 mir_simplify_atom arity_tags
pos loc dst_ptr
(fun dst_ptr
->
513 mir_simplify_atom arity_tags
pos loc dst_off
(fun dst_off
->
514 mir_simplify_atom arity_tags
pos loc env
(fun env
->
515 make_exp
loc (SysMigrate
(label
, dst_ptr
, dst_off
, f
, env
)))))
516 | Atomic
(f
, i
, env
) ->
517 mir_simplify_atom arity_tags
pos loc i
(fun i
->
518 mir_simplify_atom arity_tags
pos loc env
(fun env
->
519 make_exp
loc (Atomic
(f
, i
, env
))))
520 | AtomicRollback
(level
, i
) ->
521 mir_simplify_atom arity_tags
pos loc level
(fun level
->
522 mir_simplify_atom arity_tags
pos loc i
(fun i
->
523 make_exp
loc (AtomicRollback
(level
, i
))))
524 | AtomicCommit
(level
, e) ->
525 mir_simplify_atom arity_tags
pos loc level
(fun level
->
526 let e = mir_simplify_expr arity_tags
e in
527 make_exp
loc (AtomicCommit
(level
, e)))
528 | CopyOnWrite
((label
, vars
, mem
, ptr
), copy_ptr
, e) ->
529 mir_simplify_atom arity_tags
pos loc mem
(fun mem
->
530 mir_simplify_atom arity_tags
pos loc ptr
(fun ptr
->
531 mir_simplify_atom arity_tags
pos loc copy_ptr
(fun copy_ptr
->
532 let e = mir_simplify_expr arity_tags
e in
533 make_exp
loc (CopyOnWrite
((label
, vars
, mem
, ptr
), copy_ptr
, e)))))
535 raise
(MirException
(pos, InternalError
"SpecialCall not allowed here"))
538 (* mir_simplify_bounds_check_core
539 Rewrites a *BoundsCheck expression into two bounds checks.
540 both lower and upper bounds must be checked. The <start> and
541 <stop> arguments are atom option fields; a bounds check is
542 done only if the corresponding argument matches Some (atom). *)
543 and mir_simplify_bounds_check_core arity_tags
pos loc label ptrty ptr start stop
e =
544 let pos = string_pos
"mir_simplify_bounds_check_core" pos in
546 (* Setup a bunch of variables that we might need to use... *)
547 let v_lower = new_symbol_string
"lower_offset" in
548 let v_upper = new_symbol_string
"upper_offset" in
549 let v_lower_test = new_symbol_string
"lower_offset_test" in
550 let v_upper_test = new_symbol_string
"upper_offset_test" in
551 let v_size = new_symbol_string
"block_size" in
553 (* Seg fault expression for when something goes wrong. *)
556 match start
, stop
with
557 Some start
, Some stop
->
558 TailCall
(ExternalCall
, seg_fault_labels
.(bounds_fault
),
559 [ptr
; start
; stop
; AtomVar
(ac_native_unsigned
, v_size)])
560 | Some start
, None
->
561 TailCall
(ExternalCall
, seg_fault_labels
.(lower_bounds_fault
),
562 [ptr
; start
; AtomVar
(ac_native_unsigned
, v_size)])
564 TailCall
(ExternalCall
, seg_fault_labels
.(upper_bounds_fault
),
565 [ptr
; stop
; AtomVar
(ac_native_unsigned
, v_size)])
567 raise
(MirException
(pos, InternalError
"Bounds check requested with no bounds specified!"))
572 (* Simplify the atoms and final expression, first *)
573 mir_simplify_atom arity_tags
pos loc ptr
(fun ptr
->
574 mir_simplify_atom_option arity_tags
pos loc start
(fun start
->
575 mir_simplify_atom_option arity_tags
pos loc stop
(fun stop
->
576 let e = mir_simplify_expr arity_tags
e in
578 (* Okay, now we can start rewriting the bounds check. Note
579 that we need to check both the lower and UPPER bounds; if
580 we only check the upper bound, then it's possible to flow
581 into the header (hint: set size = 8, offset = -4). NOTE:
582 In the case where lower and upper bounds are both constants,
583 one of these steps will be redundant. We do UPPER bound
584 FIRST because that check is most exclusive, therefore we
585 can more easily catch the redundant conditional if this
586 conditional appears first! *)
587 (* STEP 1 - Load values into temporary variables *)
592 make_exp
loc (LetAtom
(v_lower, ac_native_unsigned
, start
, e))
599 make_exp
loc (LetAtom
(v_upper, ac_native_unsigned
, stop
, e))
603 let size_ac = ACRawInt
(precision_native_int
, unsigned_int
) in
604 make_exp
loc (LetAtom
(v_size, ac_native_unsigned
,
605 AtomUnop
(MemSizeOp
(ptrty
, size_ac), ptr
),
606 get_lower (get_upper e)))
607 in (* end of step1 *)
609 (* STEP 2 - check against the upper bound *)
613 (* NOTE: values are unsigned, therefore this value must
614 be less than OR EQUAL TO the size of the memory block.
615 If we run over the beginning of the block, then we
616 get a large (unsigned) value, so this check will work. *)
617 make_exp
loc (LetAtom
(v_upper_test, ac_native_bool
,
618 AtomBinop
(LeOp ac_native_unsigned
,
619 AtomVar
(ac_native_unsigned
, v_upper),
620 AtomVar
(ac_native_unsigned
, v_size)),
621 make_exp
loc (Match
(AtomVar
(ac_native_bool
, v_upper_test), ac_native_bool
,
622 [RawIntSet native_false_set
, seg_fault_expr;
623 RawIntSet native_true_set
, e]))))
625 (* No upper bound to check *)
627 in (* end of step2 *)
629 (* STEP 3 - check against the lower bound *)
633 (* NOTE: values are unsigned, therefore this value must be
634 strictly LESS THAN the size of the memory block. *)
635 make_exp
loc (LetAtom
(v_lower_test, ac_native_bool
,
636 AtomBinop
(LtOp ac_native_unsigned
,
637 AtomVar
(ac_native_unsigned
, v_lower),
638 AtomVar
(ac_native_unsigned
, v_size)),
639 make_exp
loc (Match
(AtomVar
(ac_native_bool
, v_lower_test), ac_native_bool
,
640 [RawIntSet native_false_set
, seg_fault_expr;
641 RawIntSet native_true_set
, e]))))
643 (* No lower bound to check *)
645 in (* end of step3 *)
647 (* Construct the bounds check *)
648 build_step1 (build_step2 (build_step3 e)))))
651 (* mir_simplify_bounds_check
652 Checks both lower and upper bounds. *)
653 and mir_simplify_bounds_check arity_tags
pos loc label ptrty ptr start stop
e =
654 let pos = string_pos
"mir_simplify_bounds_check" pos in
655 mir_simplify_bounds_check_core arity_tags
pos loc label ptrty ptr
(Some start
) (Some stop
) e
658 (* mir_simplify_lower_bounds_check
659 Checks the lower bounds only. *)
660 and mir_simplify_lower_bounds_check arity_tags
pos loc label ptrty ptr start
e =
661 let pos = string_pos
"mir_simplify_bounds_check" pos in
662 mir_simplify_bounds_check_core arity_tags
pos loc label ptrty ptr
(Some start
) None
e
665 (* mir_simplify_upper_bounds_check
666 Checks the upper bounds only. *)
667 and mir_simplify_upper_bounds_check arity_tags
pos loc label ptrty ptr stop
e =
668 let pos = string_pos
"mir_simplify_bounds_check" pos in
669 mir_simplify_bounds_check_core arity_tags
pos loc label ptrty ptr None
(Some stop
) e
672 (*** Simplification of Programs ***)
676 Simplifies an entire program. Note: this function currently only
677 simplifies function bodies; it does not simplify atoms that appear
678 in globals, or other locations. *)
679 let simplify_prog prog
=
680 let { prog_funs
= funs
;
681 prog_arity_tags
= arity_tags
;
684 let simplify_fun (funs
, arity_tags
) f
(line
, args
, e) =
685 let e = mir_simplify_expr arity_tags
e in
686 let funs = SymbolTable.add
funs f
(line
, args
, e) in
689 let funs, arity_tags
= SymbolTable.fold
simplify_fun (SymbolTable.empty
, arity_tags
) funs in
690 if debug
Mir_state.debug_print_mir
then
691 Mir_print.debug_prog
"After simplify" prog
;
694 prog_arity_tags
= arity_tags
;
697 let simplify_prog = Fir_state.profile
"Mir_simplify.simplify_prog" simplify_prog
699 let simplify_expr = Fir_state.profile
"Mir_simplify.simplify_expr" mir_simplify_expr