2019-03-18 01:52:34 -07:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* OCaml *)
|
|
|
|
(* *)
|
|
|
|
(* Mark Shinwell, Jane Street Europe *)
|
|
|
|
(* *)
|
|
|
|
(* Copyright 2014--2019 Jane Street Group LLC *)
|
|
|
|
(* *)
|
|
|
|
(* All rights reserved. This file is distributed under the terms of *)
|
|
|
|
(* the GNU Lesser General Public License version 2.1, with the *)
|
|
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
|
|
|
|
|
|
|
[@@@ocaml.warning "+a-4-30-40-41-42"]
|
|
|
|
|
|
|
|
(** This file defines types that are used to specify the interface of
|
|
|
|
[Compute_ranges]. The description of [Compute_ranges] is:
|
|
|
|
|
|
|
|
"Coalescing of per-instruction information into possibly-discontiguous
|
|
|
|
regions of code delimited by labels. This is used for collating register
|
|
|
|
availability and lexical block scoping information into a concise form."
|
|
|
|
|
|
|
|
[Compute_ranges] defines a functor, whose argument has type [S_functor], and
|
|
|
|
whose result has type [S]. Both [S_functor] and [S] are defined here.
|
|
|
|
|
|
|
|
It is suggested that those unfamiliar with this module start by reading
|
|
|
|
the documentation on module type [S], below.
|
|
|
|
*)
|
|
|
|
|
2019-08-13 04:11:13 -07:00
|
|
|
module L = Linear
|
2019-03-18 01:52:34 -07:00
|
|
|
|
|
|
|
(** The type of caller-defined contextual state associated with subranges.
|
|
|
|
This may be used to track information throughout the range-computing
|
|
|
|
process. *)
|
|
|
|
module type S_subrange_state = sig
|
|
|
|
type t
|
|
|
|
|
|
|
|
val create : unit -> t
|
|
|
|
val advance_over_instruction : t -> L.instruction -> t
|
|
|
|
end
|
|
|
|
|
|
|
|
(** The type of caller-defined information associated with subranges. *)
|
|
|
|
module type S_subrange_info = sig
|
|
|
|
type t
|
|
|
|
type key
|
|
|
|
type subrange_state
|
|
|
|
|
|
|
|
val create : key -> subrange_state -> t
|
|
|
|
end
|
|
|
|
|
|
|
|
(** The type of caller-defined information associated with ranges. *)
|
|
|
|
module type S_range_info = sig
|
|
|
|
type t
|
|
|
|
type key
|
|
|
|
type index
|
|
|
|
|
|
|
|
val create
|
|
|
|
: L.fundecl
|
|
|
|
-> key
|
|
|
|
-> start_insn:L.instruction
|
|
|
|
-> (index * t) option
|
|
|
|
end
|
|
|
|
|
|
|
|
(** This module type specifies what the caller has to provide in order to
|
|
|
|
instantiate a module to compute ranges. *)
|
|
|
|
module type S_functor = sig
|
|
|
|
(** The module [Index] is used to filter and group the generated subranges.
|
|
|
|
Inclusion of a computed subrange in the result is conditional upon the
|
|
|
|
existence of an index that can be associated to it. To give a concrete
|
|
|
|
example, the keys associated to ranges might be pseudoregisters, and the
|
|
|
|
indexes variable names (c.f. [Available_ranges_vars]). Every register that
|
|
|
|
is not known to hold the value of some variable is dropped from the
|
|
|
|
result.
|
|
|
|
|
|
|
|
As the name suggests, values of type [Index.t] also serve as indices for
|
|
|
|
accessing ranges in the result. The result may actually contain no
|
|
|
|
reference to keys (only [Subrange_info.t] may reliably contain it), and
|
|
|
|
subranges with different keys will be coalesced into a single range if all
|
|
|
|
their keys are associated to the same index. *)
|
|
|
|
module Index : Identifiable.S
|
|
|
|
|
|
|
|
(** The module [Key] corresponds to the identifiers that define the ranges in
|
2019-08-13 04:11:13 -07:00
|
|
|
[Linear] instructions. Each instruction should have two sets of keys,
|
2019-03-18 01:52:34 -07:00
|
|
|
[available_before] and [available_across], with accessor functions of
|
|
|
|
these names being provided to retrieve them. The notion of "availability"
|
|
|
|
is not prescribed. The availability sets are used to compute subranges
|
|
|
|
associated to each key. *)
|
|
|
|
module Key : sig
|
|
|
|
(** The type of identifiers that define ranges. *)
|
|
|
|
type t
|
|
|
|
|
|
|
|
module Set : sig
|
|
|
|
include Set.S with type elt = t
|
|
|
|
val print : Format.formatter -> t -> unit
|
|
|
|
end
|
|
|
|
|
|
|
|
module Map : Map.S with type key = t
|
|
|
|
|
|
|
|
(** Print a representation (typically sexp) of the given key to the given
|
|
|
|
formatter. *)
|
|
|
|
val print : Format.formatter -> t -> unit
|
|
|
|
|
|
|
|
(** In some situations, for performance reasons, an "available" set may only
|
|
|
|
contain a subset of all keys that need to be tracked. For example, when
|
|
|
|
using a notion of availability that describes which lexical block a
|
|
|
|
given instruction lies in, using a standard notion of nested lexical
|
|
|
|
blocks, the innermost lexical block uniquely determines the chain of its
|
|
|
|
parents. (This is exploited in [Lexical_block_ranges].) The
|
|
|
|
[all_parents] function must return, given an "available" [key], all
|
|
|
|
those other keys that are also available and uniquely determined by
|
|
|
|
[key]. *)
|
|
|
|
val all_parents : t -> t list
|
|
|
|
end
|
|
|
|
|
|
|
|
(** The module [Range_info] is used to store additional information on a range
|
|
|
|
that is associated to a range at its creation and can be retrieved from
|
|
|
|
the result. The association between keys and indices is also done here:
|
|
|
|
[Range_info.create] serves both as a map between keys and indices; and
|
|
|
|
also as the creator of the [Range_info.t] structure. When several
|
|
|
|
subranges are contained in a single range, the associated [Range_info.t]
|
|
|
|
will correspond to the first closed subrange. *)
|
|
|
|
module Range_info : S_range_info
|
|
|
|
with type key := Key.t
|
|
|
|
with type index := Index.t
|
|
|
|
|
|
|
|
(** The module [Subrange_state] describes information that needs to be
|
|
|
|
propagated and passed to [Subrange_info.create]. The state that will be
|
|
|
|
used for subrange creation is the state at the end of the subrange, not at
|
|
|
|
the beginning. *)
|
|
|
|
module Subrange_state : S_subrange_state
|
|
|
|
|
|
|
|
(** The module [Subrange_info] has a similar purpose to [Range_info], but for
|
|
|
|
subranges. Its distinguishing property is that it can store information
|
|
|
|
about its context using the additional [subrange_state] parameter of its
|
|
|
|
[create] function. *)
|
|
|
|
module Subrange_info : S_subrange_info
|
|
|
|
with type key := Key.t
|
|
|
|
with type subrange_state := Subrange_state.t
|
|
|
|
|
|
|
|
(** How to retrieve from an instruction those keys that are available
|
|
|
|
immediately before the instruction starts executing. *)
|
|
|
|
val available_before : L.instruction -> Key.Set.t
|
|
|
|
|
|
|
|
(** How to retrieve from an instruction those keys that are available
|
|
|
|
between the points at which the instruction reads its arguments and
|
|
|
|
writes its results. *)
|
|
|
|
val available_across : L.instruction -> Key.Set.t
|
|
|
|
|
|
|
|
(** This [must_restart_ranges_upon_any_change] boolean exists because some
|
|
|
|
consumers of the range information may require that two subranges are
|
|
|
|
disjoint rather than including one in another. When this function returns
|
|
|
|
[true], whenever a subrange is opened or closed, all other overlapping
|
|
|
|
subranges will be split in two at the same point. *)
|
|
|
|
val must_restart_ranges_upon_any_change : unit -> bool
|
|
|
|
end
|
|
|
|
|
|
|
|
(** This module type is the result type of the [Compute_ranges.Make] functor.
|
|
|
|
|
|
|
|
The _ranges_ being computed are composed of contiguous _subranges_ delimited
|
2019-08-13 04:11:13 -07:00
|
|
|
by two labels (of type [Linear.label]). These labels will be added by
|
2019-03-18 01:52:34 -07:00
|
|
|
this pass to the code being inspected, which is why the [create] function in
|
|
|
|
the result of the functor returns not only the ranges but also the updated
|
|
|
|
function with the labels added. The [start_pos_offset] and [end_pos_offset]
|
|
|
|
components of the subranges are there to allow a distinction between ranges
|
|
|
|
starting (or ending) right at the start of the corresponding instruction
|
|
|
|
(offset of zero), and ranges starting or ending one byte after the actual
|
|
|
|
instruction (offset of one). *)
|
|
|
|
module type S = sig
|
|
|
|
(** Corresponds to [Index] in the [S_functor] module type. *)
|
|
|
|
module Index : Identifiable.S
|
|
|
|
|
|
|
|
(** Corresponds to [Key] in the [S_functor] module type. *)
|
|
|
|
module Key : sig
|
|
|
|
type t
|
|
|
|
module Set : Set.S with type elt = t
|
|
|
|
module Map : Map.S with type key = t
|
|
|
|
end
|
|
|
|
|
|
|
|
(** Corresponds to [Subrange_state] in the [S_functor] module type. *)
|
|
|
|
module Subrange_state : S_subrange_state
|
|
|
|
|
|
|
|
(** Corresponds to [Subrange_info] in the [S_functor] module type. *)
|
|
|
|
module Subrange_info : S_subrange_info
|
|
|
|
with type key := Key.t
|
|
|
|
with type subrange_state := Subrange_state.t
|
|
|
|
|
|
|
|
(** Corresponds to [Range_info] in the [S_functor] module type. *)
|
|
|
|
module Range_info : S_range_info
|
|
|
|
with type key := Key.t
|
|
|
|
with type index := Index.t
|
|
|
|
|
|
|
|
module Subrange : sig
|
|
|
|
(** The type of subranges. Each subrange is a contiguous region of
|
|
|
|
code delimited by labels. *)
|
|
|
|
type t
|
|
|
|
|
|
|
|
(** The caller's information about the subrange. *)
|
|
|
|
val info : t -> Subrange_info.t
|
|
|
|
|
|
|
|
(** The label at the start of the range. *)
|
2019-08-13 04:11:13 -07:00
|
|
|
val start_pos : t -> Linear.label
|
2019-03-18 01:52:34 -07:00
|
|
|
|
|
|
|
(** How many bytes from the label at [start_pos] the range actually
|
|
|
|
commences. If this value is zero, then the first byte of the range
|
|
|
|
has the address of the label given by [start_pos]. *)
|
|
|
|
val start_pos_offset : t -> int
|
|
|
|
|
|
|
|
(** The label at the end of the range. *)
|
2019-08-13 04:11:13 -07:00
|
|
|
val end_pos : t -> Linear.label
|
2019-03-18 01:52:34 -07:00
|
|
|
|
|
|
|
(** Like [start_pos_offset], but analogously for the end of the range. (The
|
|
|
|
sense is not inverted; a positive [end_pos_offset] means the range ends
|
|
|
|
at an address higher than the address of the [end_pos], just like a
|
|
|
|
positive [start_pos_offset] means the range starts at an address higher
|
|
|
|
than the [start_pos]. *)
|
|
|
|
val end_pos_offset : t -> int
|
|
|
|
end
|
|
|
|
|
|
|
|
module Range : sig
|
|
|
|
(** The type of ranges. Each range is a list of subranges, so a
|
|
|
|
possibly-discontiguous region of code. *)
|
|
|
|
type t
|
|
|
|
|
|
|
|
(** The caller's information about the range. *)
|
|
|
|
val info : t -> Range_info.t
|
|
|
|
|
|
|
|
(** Estimate the pair of ([start_pos], [start_pos_offset]) (c.f. [Subrange],
|
|
|
|
above) found amongst the given ranges that yields the lowest machine
|
|
|
|
address. The assumption is made that no [start_pos_offset] or
|
|
|
|
[end_pos_offset] will cause the corresponding extremity of a range to
|
|
|
|
cross an extremity of any other range. (This should be satisfied in
|
|
|
|
typical uses because the offsets are typically zero or one.) If there
|
|
|
|
are no ranges supplied then [None] is returned. *)
|
2019-08-13 04:11:13 -07:00
|
|
|
val estimate_lowest_address : t -> (Linear.label * int) option
|
2019-03-18 01:52:34 -07:00
|
|
|
|
|
|
|
(** Fold over all subranges within the given range. *)
|
|
|
|
val fold
|
|
|
|
: t
|
|
|
|
-> init:'a
|
|
|
|
-> f:('a -> Subrange.t -> 'a)
|
|
|
|
-> 'a
|
|
|
|
end
|
|
|
|
|
|
|
|
(** The type holding information on computed ranges. *)
|
|
|
|
type t
|
|
|
|
|
|
|
|
(** A value of type [t] that holds no range information. *)
|
|
|
|
val empty : t
|
|
|
|
|
|
|
|
(** Compute ranges for the code in the given linearized function
|
|
|
|
declaration, returning the ranges as a value of type [t] and the
|
|
|
|
rewritten code that must go forward for emission. *)
|
2019-08-13 04:11:13 -07:00
|
|
|
val create : Linear.fundecl -> t * Linear.fundecl
|
2019-03-18 01:52:34 -07:00
|
|
|
|
|
|
|
(** Iterate through ranges. Each range is associated with an index. *)
|
|
|
|
val iter : t -> f:(Index.t -> Range.t -> unit) -> unit
|
|
|
|
|
|
|
|
(** Like [iter], but a fold. *)
|
|
|
|
val fold : t -> init:'a -> f:('a -> Index.t -> Range.t -> 'a) -> 'a
|
|
|
|
|
|
|
|
(** Find the range for the given index, or raise an exception. *)
|
|
|
|
val find : t -> Index.t -> Range.t
|
|
|
|
|
|
|
|
(** All indexes for which the given value of type [t] contains ranges. *)
|
|
|
|
val all_indexes : t -> Index.Set.t
|
|
|
|
|
|
|
|
(** An internal function used by [Coalesce_labels].
|
|
|
|
The [env] should come from [Coalesce_labels.fundecl]. *)
|
|
|
|
val rewrite_labels_and_remove_empty_subranges_and_ranges
|
|
|
|
: t
|
|
|
|
-> env:int Numbers.Int.Map.t
|
|
|
|
-> t
|
|
|
|
end
|