Node:Automaton pipeline description, Next:Comparison of the two descriptions, Previous:Old pipeline description, Up:Processor pipeline description
This section describes constructions of the automaton based processor pipeline description. The order of all mentioned below constructions in the machine description file is not important.
The following optional construction describes names of automata generated and used for the pipeline hazards recognition. Sometimes the generated finite state automaton used by the pipeline hazard recognizer is large. If we use more than one automaton and bind functional units to the automata, the summary size of the automata usually is less than the size of the single automaton. If there is no one such construction, only one finite state automaton is generated.
(define_automaton automata-names)
automata-names is a string giving names of the automata. The
names are separated by commas. All the automata should have unique names.
The automaton name is used in construction define_cpu_unit
and
define_query_cpu_unit
.
Each processor functional unit used in description of instruction reservations should be described by the following construction.
(define_cpu_unit unit-names [automaton-name])
unit-names is a string giving the names of the functional units
separated by commas. Don't use name nothing
, it is reserved
for other goals.
automaton-name is a string giving the name of the automaton with
which the unit is bound. The automaton should be described in
construction define_automaton
. You should give
automaton-name, if there is a defined automaton.
The following construction describes CPU functional units analogously
to define_cpu_unit
. If we use automata without their
minimization, the reservation of such units can be queried for an
automaton state. The instruction scheduler never queries reservation
of functional units for given automaton state. So as a rule, you
don't need this construction. This construction could be used for
future code generation goals (e.g. to generate VLIW insn
templates).
(define_query_cpu_unit unit-names [automaton-name])
unit-names is a string giving names of the functional units separated by commas.
automaton-name is a string giving the name of the automaton with which the unit is bound.
The following construction is the major one to describe pipeline characteristics of an instruction.
(define_insn_reservation insn-name default_latency condition regexp)
default_latency is a number giving latency time of the
instruction. There is an important difference between the old
description and the automaton based pipeline description. The latency
time is used for all dependencies when we use the old description. In
the automaton based pipeline description, the given latency time is only
used for true dependencies. The cost of anti-dependencies is always
zero and the cost of output dependencies is the difference between
latency times of the producing and consuming insns (if the difference
is negative, the cost is considered to be zero). You can always
change the default costs for any description by using the target hook
TARGET_SCHED_ADJUST_COST
(see Scheduling).
insn-names is a string giving the internal name of the insn. The
internal names are used in constructions define_bypass
and in
the automaton description file generated for debugging. The internal
name has nothing in common with the names in define_insn
. It is a
good practice to use insn classes described in the processor manual.
condition defines what RTL insns are described by this
construction. You should remember that you will be in trouble if
condition for two or more different
define_insn_reservation
constructions is TRUE for an insn. In
this case what reservation will be used for the insn is not defined.
Such cases are not checked during generation of the pipeline hazards
recognizer because in general recognizing that two conditions may have
the same value is quite difficult (especially if the conditions
contain symbol_ref
). It is also not checked during the
pipeline hazard recognizer work because it would slow down the
recognizer considerably.
regexp is a string describing the reservation of the cpu's functional units by the instruction. The reservations are described by a regular expression according to the following syntax:
regexp = regexp "," oneof | oneof oneof = oneof "|" allof | allof allof = allof "+" repeat | repeat repeat = element "*" number | element element = cpu_function_unit_name | reservation_name | result_name | "nothing" | "(" regexp ")"
,
is used for describing the start of the next cycle in
the reservation.
|
is used for describing a reservation described by the first
regular expression or a reservation described by the second
regular expression or etc.
+
is used for describing a reservation described by the first
regular expression and a reservation described by the
second regular expression and etc.
*
is used for convenience and simply means a sequence in which
the regular expression are repeated number times with cycle
advancing (see ,
).
cpu_function_unit_name
denotes reservation of the named
functional unit.
reservation_name
-- see description of construction
define_reservation
.
nothing
denotes no unit reservations.
Sometimes unit reservations for different insns contain common parts. In such case, you can simplify the pipeline description by describing the common part by the following construction
(define_reservation reservation-name regexp)
reservation-name is a string giving name of regexp.
Functional unit names and reservation names are in the same name
space. So the reservation names should be different from the
functional unit names and can not be reserved name nothing
.
The following construction is used to describe exceptions in the latency time for given instruction pair. This is so called bypasses.
(define_bypass number out_insn_names in_insn_names [guard])
number defines when the result generated by the instructions given in string out_insn_names will be ready for the instructions given in string in_insn_names. The instructions in the string are separated by commas.
guard is an optional string giving the name of a C function which
defines an additional guard for the bypass. The function will get the
two insns as parameters. If the function returns zero the bypass will
be ignored for this case. The additional guard is necessary to
recognize complicated bypasses, e.g. when the consumer is only an address
of insn store
(not a stored value).
Usually the following three constructions are used to describe VLIW processors (more correctly to describe a placement of small insns into VLIW insn slots). Although they can be used for RISC processors too.
(exclusion_set unit-names unit-names) (presence_set unit-names unit-names) (absence_set unit-names unit-names)
unit-names is a string giving names of functional units separated by commas.
The first construction (exclusion_set
) means that each
functional unit in the first string can not be reserved simultaneously
with a unit whose name is in the second string and vice versa. For
example, the construction is useful for describing processors
(e.g. some SPARC processors) with a fully pipelined floating point
functional unit which can execute simultaneously only single floating
point insns or only double floating point insns.
The second construction (presence_set
) means that each
functional unit in the first string can not be reserved unless at
least one of units whose names are in the second string is reserved.
This is an asymmetric relation. For example, it is useful for
description that VLIW slot1
is reserved after
slot0
reservation.
The third construction (absence_set
) means that each functional
unit in the first string can be reserved only if each unit whose name
is in the second string is not reserved. This is an asymmetric
relation (actually exclusion_set
is analogous to this one but
it is symmetric). For example, it is useful for description that
VLIW slot0
can not be reserved after slot1
or
slot2
reservation.
All functional units mentioned in a set should belong to the same automaton.
You can control the generator of the pipeline hazard recognizer with the following construction.
(automata_option options)
options is a string giving options which affect the generated code. Currently there are the following options:
.dfa
and can be used for the description
verification and debugging.
|
in the regular expressions. The
usual treatment of the operator is to try the first alternative and,
if the reservation is not possible, the second alternative. The
nondeterministic treatment means trying all alternatives, some of them
may be rejected by reservations in the subsequent insns. You can not
query functional unit reservations in nondeterministic automaton
states.
As an example, consider a superscalar RISC machine which can issue three insns (two integer insns and one floating point insn) on the cycle but can finish only two insns. To describe this, we define the following functional units.
(define_cpu_unit "i0_pipeline, i1_pipeline, f_pipeline") (define_cpu_unit "port0, port1")
All simple integer insns can be executed in any integer pipeline and their result is ready in two cycles. The simple integer insns are issued into the first pipeline unless it is reserved, otherwise they are issued into the second pipeline. Integer division and multiplication insns can be executed only in the second integer pipeline and their results are ready correspondingly in 8 and 4 cycles. The integer division is not pipelined, i.e. the subsequent integer division insn can not be issued until the current division insn finished. Floating point insns are fully pipelined and their results are ready in 3 cycles. Where the result of a floating point insn is used by an integer insn, an additional delay of one cycle is incurred. To describe all of this we could specify
(define_cpu_unit "div") (define_insn_reservation "simple" 2 (eq_attr "cpu" "int") "(i0_pipeline | i1_pipeline), (port0 | port1)") (define_insn_reservation "mult" 4 (eq_attr "cpu" "mult") "i1_pipeline, nothing*2, (port0 | port1)") (define_insn_reservation "div" 8 (eq_attr "cpu" "div") "i1_pipeline, div*7, div + (port0 | port1)") (define_insn_reservation "float" 3 (eq_attr "cpu" "float") "f_pipeline, nothing, (port0 | port1)) (define_bypass 4 "float" "simple,mult,div")
To simplify the description we could describe the following reservation
(define_reservation "finish" "port0|port1")
and use it in all define_insn_reservation
as in the following
construction
(define_insn_reservation "simple" 2 (eq_attr "cpu" "int") "(i0_pipeline | i1_pipeline), finish")