Reorganize switch handling
parent
f5573b0f6b
commit
6ee86d523d
|
@ -187,6 +187,10 @@ let approx_for_allocated_const (const : Allocated_const.t) =
|
|||
A.value_immutable_float_array
|
||||
(Array.map A.value_float (Array.of_list a))
|
||||
|
||||
type filtered_switch_branches =
|
||||
| Must_be_taken of Flambda.t
|
||||
| Can_be_taken of (int * Flambda.t) list
|
||||
|
||||
(* Determine whether a given closure ID corresponds directly to a variable
|
||||
(bound to a closure) in the given environment. This happens when the body
|
||||
of a [let rec]-bound function refers to another in the same set of closures.
|
||||
|
@ -1256,7 +1260,34 @@ and simplify env r (tree : Flambda.t) : Flambda.t * R.t =
|
|||
[Switch]. (This should also make the [Let] that binds [arg] redundant,
|
||||
meaning that it too can be eliminated.) *)
|
||||
simplify_free_variable env arg ~f:(fun env arg arg_approx ->
|
||||
let get_failaction () : Flambda.t =
|
||||
let rec filter_branches filter branches compatible_branches =
|
||||
match branches with
|
||||
| [] -> Can_be_taken compatible_branches
|
||||
| (c, lam) as branch :: branches ->
|
||||
match filter arg_approx c with
|
||||
| A.Cannot_be_taken ->
|
||||
filter_branches filter branches compatible_branches
|
||||
| A.Can_be_taken ->
|
||||
filter_branches filter branches (branch :: compatible_branches)
|
||||
| A.Must_be_taken ->
|
||||
Must_be_taken lam
|
||||
in
|
||||
let filtered_consts =
|
||||
filter_branches A.potentially_taken_const_switch_branch sw.consts []
|
||||
in
|
||||
let filtered_blocks =
|
||||
filter_branches A.potentially_taken_block_switch_branch sw.blocks []
|
||||
in
|
||||
begin match filtered_consts, filtered_blocks with
|
||||
| Must_be_taken _, Must_be_taken _ ->
|
||||
assert false
|
||||
| Must_be_taken branch, _
|
||||
| _, Must_be_taken branch ->
|
||||
let lam, r = simplify env r branch in
|
||||
lam, R.map_benefit r B.remove_branch
|
||||
| Can_be_taken consts, Can_be_taken blocks ->
|
||||
match consts, blocks, sw.failaction with
|
||||
| [], [], None ->
|
||||
(* If the switch is applied to a statically-known value that does not
|
||||
match any case:
|
||||
* if there is a default action take that case;
|
||||
|
@ -1269,40 +1300,6 @@ and simplify env r (tree : Flambda.t) : Flambda.t * R.t =
|
|||
match v with <-- This match is unreachable
|
||||
| Float f -> ...]
|
||||
*)
|
||||
match sw.failaction with
|
||||
| None -> Proved_unreachable
|
||||
| Some f -> f
|
||||
in
|
||||
let consts =
|
||||
List.filter
|
||||
(fun (c, _) -> A.potentially_taken_const_switch_branch arg_approx c)
|
||||
sw.consts
|
||||
in
|
||||
let blocks =
|
||||
List.filter
|
||||
(fun (c, _) -> A.potentially_taken_block_switch_branch arg_approx c)
|
||||
sw.blocks
|
||||
in
|
||||
begin match arg_approx.descr with
|
||||
| Value_int i
|
||||
| Value_constptr i ->
|
||||
let lam =
|
||||
try List.assoc i consts
|
||||
with Not_found -> get_failaction ()
|
||||
in
|
||||
let lam, r = simplify env r lam in
|
||||
lam, R.map_benefit r B.remove_branch
|
||||
| Value_block (tag, _) ->
|
||||
let tag = Tag.to_int tag in
|
||||
let lam =
|
||||
try List.assoc tag blocks
|
||||
with Not_found -> get_failaction ()
|
||||
in
|
||||
let lam, r = simplify env r lam in
|
||||
lam, R.map_benefit r B.remove_branch
|
||||
| _ ->
|
||||
match consts, blocks, sw.failaction with
|
||||
| [], [], None ->
|
||||
Proved_unreachable, ret r A.value_bottom
|
||||
| [_, branch], [], None
|
||||
| [], [_, branch], None
|
||||
|
|
|
@ -795,25 +795,30 @@ let check_approx_for_string t : string option =
|
|||
| Value_extern _ | Value_boxed_int _ | Value_symbol _ ->
|
||||
None
|
||||
|
||||
type switch_branch_selection =
|
||||
| Cannot_be_taken
|
||||
| Can_be_taken
|
||||
| Must_be_taken
|
||||
|
||||
let potentially_taken_const_switch_branch t branch =
|
||||
match t.descr with
|
||||
| (Value_unresolved _
|
||||
| Value_unknown _
|
||||
| Value_extern _
|
||||
| Value_symbol _) ->
|
||||
| Value_unresolved _
|
||||
| Value_unknown _
|
||||
| Value_extern _
|
||||
| Value_symbol _ ->
|
||||
(* In theory symbol cannot contain integers but this shouldn't
|
||||
matter as this will always be an imported approximation *)
|
||||
true
|
||||
|
||||
| (Value_constptr i | Value_int i) ->
|
||||
i = branch
|
||||
| Value_char c ->
|
||||
Char.code c = branch
|
||||
|
||||
| ( Value_block _ | Value_float _ | Value_float_array _
|
||||
| Value_string _ | Value_closure _ | Value_set_of_closures _
|
||||
| Value_boxed_int _ | Value_bottom ) ->
|
||||
false
|
||||
Can_be_taken
|
||||
| Value_constptr i | Value_int i when i = branch ->
|
||||
Must_be_taken
|
||||
| Value_char c when Char.code c = branch ->
|
||||
Must_be_taken
|
||||
| Value_constptr _ | Value_int _ | Value_char _ ->
|
||||
Cannot_be_taken
|
||||
| Value_block _ | Value_float _ | Value_float_array _
|
||||
| Value_string _ | Value_closure _ | Value_set_of_closures _
|
||||
| Value_boxed_int _ | Value_bottom ->
|
||||
Cannot_be_taken
|
||||
|
||||
let potentially_taken_block_switch_branch t tag =
|
||||
match t.descr with
|
||||
|
@ -821,28 +826,25 @@ let potentially_taken_block_switch_branch t tag =
|
|||
| Value_unknown _
|
||||
| Value_extern _
|
||||
| Value_symbol _) ->
|
||||
true
|
||||
|
||||
Can_be_taken
|
||||
| (Value_constptr _ | Value_int _| Value_char _) ->
|
||||
false
|
||||
|
||||
| Value_block (block_tag, _) ->
|
||||
Tag.to_int block_tag = tag
|
||||
|
||||
| Value_float _ ->
|
||||
tag = Obj.double_tag
|
||||
|
||||
| Value_float_array _ ->
|
||||
tag = Obj.double_array_tag
|
||||
|
||||
| Value_string _ ->
|
||||
tag = Obj.string_tag
|
||||
|
||||
| (Value_closure _ | Value_set_of_closures _) ->
|
||||
tag = Obj.closure_tag || tag = Obj.infix_tag
|
||||
|
||||
| Value_boxed_int _ ->
|
||||
tag = Obj.custom_tag
|
||||
|
||||
Cannot_be_taken
|
||||
| Value_block (block_tag, _) when Tag.to_int block_tag = tag ->
|
||||
Must_be_taken
|
||||
| Value_float _ when tag = Obj.double_tag ->
|
||||
Must_be_taken
|
||||
| Value_float_array _ when tag = Obj.double_array_tag ->
|
||||
Must_be_taken
|
||||
| Value_string _ when tag = Obj.string_tag ->
|
||||
Must_be_taken
|
||||
| (Value_closure _ | Value_set_of_closures _)
|
||||
when tag = Obj.closure_tag || tag = Obj.infix_tag ->
|
||||
Can_be_taken
|
||||
| Value_boxed_int _ when tag = Obj.custom_tag ->
|
||||
Must_be_taken
|
||||
| Value_block _ | Value_float _ | Value_set_of_closures _ | Value_closure _
|
||||
| Value_string _ | Value_float_array _ | Value_boxed_int _ ->
|
||||
Cannot_be_taken
|
||||
| Value_bottom ->
|
||||
false
|
||||
Cannot_be_taken
|
||||
|
||||
|
|
|
@ -413,6 +413,11 @@ val float_array_as_constant : value_float_array -> float list option
|
|||
(** Returns the value if it can be proved to be a constant string *)
|
||||
val check_approx_for_string : t -> string option
|
||||
|
||||
type switch_branch_selection =
|
||||
| Cannot_be_taken
|
||||
| Can_be_taken
|
||||
| Must_be_taken
|
||||
|
||||
(** Check that the branch is compatible with the approximation *)
|
||||
val potentially_taken_const_switch_branch : t -> int -> bool
|
||||
val potentially_taken_block_switch_branch : t -> int -> bool
|
||||
val potentially_taken_const_switch_branch : t -> int -> switch_branch_selection
|
||||
val potentially_taken_block_switch_branch : t -> int -> switch_branch_selection
|
||||
|
|
Loading…
Reference in New Issue