Commit 0016d8d9 by Richard Sandiford Committed by Richard Sandiford

[gen/AArch64] Generate helpers for substituting iterator values into pattern names

Given a pattern like:

  (define_insn "aarch64_frecpe<mode>" ...)

the SVE ACLE implementation wants to generate the pattern for a
particular (non-constant) mode.  This patch automatically generates
helpers to do that, specifically:

  // Return CODE_FOR_nothing on failure.
  insn_code maybe_code_for_aarch64_frecpe (machine_mode);

  // Assert that the code exists.
  insn_code code_for_aarch64_frecpe (machine_mode);

  // Return NULL_RTX on failure.
  rtx maybe_gen_aarch64_frecpe (machine_mode, rtx, rtx);

  // Assert that generation succeeds.
  rtx gen_aarch64_frecpe (machine_mode, rtx, rtx);

Many patterns don't have sensible names when all <...>s are removed.
E.g. "<optab><mode>2" would give a base name "2".  The new functions
therefore require explicit opt-in, which should also help to reduce
code bloat.

The (arbitrary) opt-in syntax I went for was to prefix the pattern
name with '@', similarly to the existing '*' marker.

The patch also makes config/aarch64 use the new routines in cases where
they obviously apply.  This was mostly straight-forward, but it seemed
odd that we defined:

   aarch64_reload_movcp<...><P:mode>

but then only used it with DImode, never SImode.  If we should be
using Pmode instead of DImode, then that's a simple change,
but should probably be a separate patch.

2018-08-02  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* doc/md.texi: Expand the documentation of instruction names
	to mention port-local uses.  Document '@' in pattern names.
	* read-md.h (overloaded_instance, overloaded_name): New structs.
	(mapping): Declare.
	(md_reader::handle_overloaded_name): New member function.
	(md_reader::get_overloads): Likewise.
	(md_reader::m_first_overload): New member variable.
	(md_reader::m_next_overload_ptr): Likewise.
	(md_reader::m_overloads_htab): Likewise.
	* read-md.c (md_reader::md_reader): Initialize m_first_overload,
	m_next_overload_ptr and m_overloads_htab.
	* read-rtl.c (iterator_group): Add "type" and "get_c_token" fields.
	(get_mode_token, get_code_token, get_int_token): New functions.
	(map_attr_string): Add an optional argument that passes back
	the associated iterator.
	(overloaded_name_hash, overloaded_name_eq_p, named_rtx_p):
	(md_reader::handle_overloaded_name, add_overload_instance): New
	functions.
	(apply_iterators): Handle '@' names.  Report an error if '@'
	is used without iterators.
	(initialize_iterators): Initialize the new iterator_group fields.
	* genopinit.c (handle_overloaded_code_for)
	(handle_overloaded_gen): New functions.
	(main): Use them to print declarations of maybe_code_for_* and
	maybe_gen_* functions, and inline definitions of code_for_* and gen_*.
	* genemit.c (print_overload_arguments, print_overload_test)
	(handle_overloaded_code_for, handle_overloaded_gen): New functions.
	(main): Use it to print definitions of maybe_code_for_* and
	maybe_gen_* functions.
	* config/aarch64/aarch64.c (aarch64_split_128bit_move): Use
	gen_aarch64_mov{low,high}_di and gen_aarch64_movdi_{low,high}
	instead of explicit mode checks.
	(aarch64_split_simd_combine): Likewise gen_aarch64_simd_combine.
	(aarch64_split_simd_move): Likewise gen_aarch64_split_simd_mov.
	(aarch64_emit_load_exclusive): Likewise gen_aarch64_load_exclusive.
	(aarch64_emit_store_exclusive): Likewise gen_aarch64_store_exclusive.
	(aarch64_expand_compare_and_swap): Likewise
	gen_aarch64_compare_and_swap and gen_aarch64_compare_and_swap_lse
	(aarch64_gen_atomic_cas): Likewise gen_aarch64_atomic_cas.
	(aarch64_emit_atomic_swap): Likewise gen_aarch64_atomic_swp.
	(aarch64_constant_pool_reload_icode): Delete.
	(aarch64_secondary_reload): Use code_for_aarch64_reload_movcp
	instead of aarch64_constant_pool_reload_icode.  Use
	code_for_aarch64_reload_mov instead of explicit mode checks.
	(rsqrte_type, get_rsqrte_type, rsqrts_type, get_rsqrts_type): Delete.
	(aarch64_emit_approx_sqrt): Use gen_aarch64_rsqrte instead of
	get_rsqrte_type and gen_aarch64_rsqrts instead of gen_rqrts_type.
	(recpe_type, get_recpe_type, recps_type, get_recps_type): Delete.
	(aarch64_emit_approx_div): Use gen_aarch64_frecpe instead of
	get_recpe_type and gen_aarch64_frecps instead of get_recps_type.
	(aarch64_atomic_load_op_code): Delete.
	(aarch64_emit_atomic_load_op): Likewise.
	(aarch64_gen_atomic_ldop): Use UNSPECV_ATOMIC_* instead of
	aarch64_atomic_load_op_code.  Use gen_aarch64_atomic_load
	instead of aarch64_emit_atomic_load_op.
	* config/aarch64/aarch64.md (aarch64_reload_movcp<GPF_TF:mode><P:mode>)
	(aarch64_reload_movcp<VALL:mode><P:mode>, aarch64_reload_mov<mode>)
	(aarch64_movdi_<mode>low, aarch64_movdi_<mode>high)
	(aarch64_mov<mode>high_di, aarch64_mov<mode>low_di): Add a '@'
	character before the pattern name.
	* config/aarch64/aarch64-simd.md (aarch64_split_simd_mov<mode>)
	(aarch64_rsqrte<mode>, aarch64_rsqrts<mode>)
	(aarch64_simd_combine<mode>, aarch64_frecpe<mode>)
	(aarch64_frecps<mode>): Likewise.
	* config/aarch64/atomics.md (atomic_compare_and_swap<mode>)
	(aarch64_compare_and_swap<mode>, aarch64_compare_and_swap<mode>_lse)
	(aarch64_load_exclusive<mode>, aarch64_store_exclusive<mode>)
	(aarch64_atomic_swp<mode>, aarch64_atomic_cas<mode>)
	(aarch64_atomic_load<atomic_ldop><mode>): Likewise.

From-SVN: r263251
parent a4518821
2018-08-02 Richard Sandiford <richard.sandiford@arm.com>
* doc/md.texi: Expand the documentation of instruction names
to mention port-local uses. Document '@' in pattern names.
* read-md.h (overloaded_instance, overloaded_name): New structs.
(mapping): Declare.
(md_reader::handle_overloaded_name): New member function.
(md_reader::get_overloads): Likewise.
(md_reader::m_first_overload): New member variable.
(md_reader::m_next_overload_ptr): Likewise.
(md_reader::m_overloads_htab): Likewise.
* read-md.c (md_reader::md_reader): Initialize m_first_overload,
m_next_overload_ptr and m_overloads_htab.
* read-rtl.c (iterator_group): Add "type" and "get_c_token" fields.
(get_mode_token, get_code_token, get_int_token): New functions.
(map_attr_string): Add an optional argument that passes back
the associated iterator.
(overloaded_name_hash, overloaded_name_eq_p, named_rtx_p):
(md_reader::handle_overloaded_name, add_overload_instance): New
functions.
(apply_iterators): Handle '@' names. Report an error if '@'
is used without iterators.
(initialize_iterators): Initialize the new iterator_group fields.
* genopinit.c (handle_overloaded_code_for)
(handle_overloaded_gen): New functions.
(main): Use them to print declarations of maybe_code_for_* and
maybe_gen_* functions, and inline definitions of code_for_* and gen_*.
* genemit.c (print_overload_arguments, print_overload_test)
(handle_overloaded_code_for, handle_overloaded_gen): New functions.
(main): Use it to print definitions of maybe_code_for_* and
maybe_gen_* functions.
* config/aarch64/aarch64.c (aarch64_split_128bit_move): Use
gen_aarch64_mov{low,high}_di and gen_aarch64_movdi_{low,high}
instead of explicit mode checks.
(aarch64_split_simd_combine): Likewise gen_aarch64_simd_combine.
(aarch64_split_simd_move): Likewise gen_aarch64_split_simd_mov.
(aarch64_emit_load_exclusive): Likewise gen_aarch64_load_exclusive.
(aarch64_emit_store_exclusive): Likewise gen_aarch64_store_exclusive.
(aarch64_expand_compare_and_swap): Likewise
gen_aarch64_compare_and_swap and gen_aarch64_compare_and_swap_lse
(aarch64_gen_atomic_cas): Likewise gen_aarch64_atomic_cas.
(aarch64_emit_atomic_swap): Likewise gen_aarch64_atomic_swp.
(aarch64_constant_pool_reload_icode): Delete.
(aarch64_secondary_reload): Use code_for_aarch64_reload_movcp
instead of aarch64_constant_pool_reload_icode. Use
code_for_aarch64_reload_mov instead of explicit mode checks.
(rsqrte_type, get_rsqrte_type, rsqrts_type, get_rsqrts_type): Delete.
(aarch64_emit_approx_sqrt): Use gen_aarch64_rsqrte instead of
get_rsqrte_type and gen_aarch64_rsqrts instead of gen_rqrts_type.
(recpe_type, get_recpe_type, recps_type, get_recps_type): Delete.
(aarch64_emit_approx_div): Use gen_aarch64_frecpe instead of
get_recpe_type and gen_aarch64_frecps instead of get_recps_type.
(aarch64_atomic_load_op_code): Delete.
(aarch64_emit_atomic_load_op): Likewise.
(aarch64_gen_atomic_ldop): Use UNSPECV_ATOMIC_* instead of
aarch64_atomic_load_op_code. Use gen_aarch64_atomic_load
instead of aarch64_emit_atomic_load_op.
* config/aarch64/aarch64.md (aarch64_reload_movcp<GPF_TF:mode><P:mode>)
(aarch64_reload_movcp<VALL:mode><P:mode>, aarch64_reload_mov<mode>)
(aarch64_movdi_<mode>low, aarch64_movdi_<mode>high)
(aarch64_mov<mode>high_di, aarch64_mov<mode>low_di): Add a '@'
character before the pattern name.
* config/aarch64/aarch64-simd.md (aarch64_split_simd_mov<mode>)
(aarch64_rsqrte<mode>, aarch64_rsqrts<mode>)
(aarch64_simd_combine<mode>, aarch64_frecpe<mode>)
(aarch64_frecps<mode>): Likewise.
* config/aarch64/atomics.md (atomic_compare_and_swap<mode>)
(aarch64_compare_and_swap<mode>, aarch64_compare_and_swap<mode>_lse)
(aarch64_load_exclusive<mode>, aarch64_store_exclusive<mode>)
(aarch64_atomic_swp<mode>, aarch64_atomic_cas<mode>)
(aarch64_atomic_load<atomic_ldop><mode>): Likewise.
2018-08-02 Richard Sandiford <richard.sandiford@arm.com>
* config/aarch64/aarch64.c (aarch64_float_const_representable_p):
Allow HFmode constants if TARGET_FP_F16INST.
......
......@@ -257,7 +257,7 @@
DONE;
})
(define_expand "aarch64_split_simd_mov<mode>"
(define_expand "@aarch64_split_simd_mov<mode>"
[(set (match_operand:VQ 0)
(match_operand:VQ 1))]
"TARGET_SIMD"
......@@ -559,7 +559,7 @@
[(set_attr "type" "neon<fp>_mul_<stype>_scalar<q>")]
)
(define_insn "aarch64_rsqrte<mode>"
(define_insn "@aarch64_rsqrte<mode>"
[(set (match_operand:VHSDF_HSDF 0 "register_operand" "=w")
(unspec:VHSDF_HSDF [(match_operand:VHSDF_HSDF 1 "register_operand" "w")]
UNSPEC_RSQRTE))]
......@@ -567,7 +567,7 @@
"frsqrte\\t%<v>0<Vmtype>, %<v>1<Vmtype>"
[(set_attr "type" "neon_fp_rsqrte_<stype><q>")])
(define_insn "aarch64_rsqrts<mode>"
(define_insn "@aarch64_rsqrts<mode>"
[(set (match_operand:VHSDF_HSDF 0 "register_operand" "=w")
(unspec:VHSDF_HSDF [(match_operand:VHSDF_HSDF 1 "register_operand" "w")
(match_operand:VHSDF_HSDF 2 "register_operand" "w")]
......@@ -3145,7 +3145,7 @@
}
)
(define_expand "aarch64_simd_combine<mode>"
(define_expand "@aarch64_simd_combine<mode>"
[(match_operand:<VDBL> 0 "register_operand")
(match_operand:VDC 1 "register_operand")
(match_operand:VDC 2 "register_operand")]
......@@ -5878,7 +5878,7 @@
)
(define_insn "aarch64_frecpe<mode>"
(define_insn "@aarch64_frecpe<mode>"
[(set (match_operand:VHSDF 0 "register_operand" "=w")
(unspec:VHSDF [(match_operand:VHSDF 1 "register_operand" "w")]
UNSPEC_FRECPE))]
......@@ -5896,7 +5896,7 @@
[(set_attr "type" "neon_fp_recp<FRECP:frecp_suffix>_<GPF_F16:stype>")]
)
(define_insn "aarch64_frecps<mode>"
(define_insn "@aarch64_frecps<mode>"
[(set (match_operand:VHSDF_HSDF 0 "register_operand" "=w")
(unspec:VHSDF_HSDF
[(match_operand:VHSDF_HSDF 1 "register_operand" "w")
......
......@@ -5989,7 +5989,7 @@
;; -------------------------------------------------------------------
;; Reload Scalar Floating point modes from constant pool.
;; The AArch64 port doesn't have __int128 constant move support.
(define_expand "aarch64_reload_movcp<GPF_TF:mode><P:mode>"
(define_expand "@aarch64_reload_movcp<GPF_TF:mode><P:mode>"
[(set (match_operand:GPF_TF 0 "register_operand" "=w")
(mem:GPF_TF (match_operand 1 "aarch64_constant_pool_symref" "S")))
(clobber (match_operand:P 2 "register_operand" "=&r"))]
......@@ -6002,7 +6002,7 @@
)
;; Reload Vector modes from constant pool.
(define_expand "aarch64_reload_movcp<VALL:mode><P:mode>"
(define_expand "@aarch64_reload_movcp<VALL:mode><P:mode>"
[(set (match_operand:VALL 0 "register_operand" "=w")
(mem:VALL (match_operand 1 "aarch64_constant_pool_symref" "S")))
(clobber (match_operand:P 2 "register_operand" "=&r"))]
......@@ -6014,7 +6014,7 @@
}
)
(define_expand "aarch64_reload_mov<mode>"
(define_expand "@aarch64_reload_mov<mode>"
[(set (match_operand:TX 0 "register_operand" "=w")
(match_operand:TX 1 "register_operand" "w"))
(clobber (match_operand:DI 2 "register_operand" "=&r"))
......@@ -6034,7 +6034,7 @@
;; after or during reload as we don't want these patterns to start
;; kicking in during the combiner.
(define_insn "aarch64_movdi_<mode>low"
(define_insn "@aarch64_movdi_<mode>low"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:TX 1 "register_operand" "w")
(const_int 64) (const_int 0)))]
......@@ -6044,7 +6044,7 @@
(set_attr "length" "4")
])
(define_insn "aarch64_movdi_<mode>high"
(define_insn "@aarch64_movdi_<mode>high"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:TX 1 "register_operand" "w")
(const_int 64) (const_int 64)))]
......@@ -6054,7 +6054,7 @@
(set_attr "length" "4")
])
(define_insn "aarch64_mov<mode>high_di"
(define_insn "@aarch64_mov<mode>high_di"
[(set (zero_extract:TX (match_operand:TX 0 "register_operand" "+w")
(const_int 64) (const_int 64))
(zero_extend:TX (match_operand:DI 1 "register_operand" "r")))]
......@@ -6064,7 +6064,7 @@
(set_attr "length" "4")
])
(define_insn "aarch64_mov<mode>low_di"
(define_insn "@aarch64_mov<mode>low_di"
[(set (match_operand:TX 0 "register_operand" "=w")
(zero_extend:TX (match_operand:DI 1 "register_operand" "r")))]
"TARGET_FLOAT && (reload_completed || reload_in_progress)"
......
......@@ -20,7 +20,7 @@
;; Instruction patterns.
(define_expand "atomic_compare_and_swap<mode>"
(define_expand "@atomic_compare_and_swap<mode>"
[(match_operand:SI 0 "register_operand" "") ;; bool out
(match_operand:ALLI 1 "register_operand" "") ;; val out
(match_operand:ALLI 2 "aarch64_sync_memory_operand" "") ;; memory
......@@ -36,7 +36,7 @@
}
)
(define_insn_and_split "aarch64_compare_and_swap<mode>"
(define_insn_and_split "@aarch64_compare_and_swap<mode>"
[(set (reg:CC CC_REGNUM) ;; bool out
(unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
(set (match_operand:SI 0 "register_operand" "=&r") ;; val out
......@@ -61,7 +61,7 @@
}
)
(define_insn_and_split "aarch64_compare_and_swap<mode>"
(define_insn_and_split "@aarch64_compare_and_swap<mode>"
[(set (reg:CC CC_REGNUM) ;; bool out
(unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
(set (match_operand:GPI 0 "register_operand" "=&r") ;; val out
......@@ -85,7 +85,7 @@
}
)
(define_insn_and_split "aarch64_compare_and_swap<mode>_lse"
(define_insn_and_split "@aarch64_compare_and_swap<mode>_lse"
[(set (reg:CC CC_REGNUM) ;; bool out
(unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
(set (match_operand:SI 0 "register_operand" "=&r") ;; val out
......@@ -111,7 +111,7 @@
}
)
(define_insn_and_split "aarch64_compare_and_swap<mode>_lse"
(define_insn_and_split "@aarch64_compare_and_swap<mode>_lse"
[(set (reg:CC CC_REGNUM) ;; bool out
(unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
(set (match_operand:GPI 0 "register_operand" "=&r") ;; val out
......@@ -496,7 +496,7 @@
}
)
(define_insn "aarch64_load_exclusive<mode>"
(define_insn "@aarch64_load_exclusive<mode>"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI
(unspec_volatile:SHORT
......@@ -513,7 +513,7 @@
}
)
(define_insn "aarch64_load_exclusive<mode>"
(define_insn "@aarch64_load_exclusive<mode>"
[(set (match_operand:GPI 0 "register_operand" "=r")
(unspec_volatile:GPI
[(match_operand:GPI 1 "aarch64_sync_memory_operand" "Q")
......@@ -529,7 +529,7 @@
}
)
(define_insn "aarch64_store_exclusive<mode>"
(define_insn "@aarch64_store_exclusive<mode>"
[(set (match_operand:SI 0 "register_operand" "=&r")
(unspec_volatile:SI [(const_int 0)] UNSPECV_SX))
(set (match_operand:ALLI 1 "aarch64_sync_memory_operand" "=Q")
......@@ -586,7 +586,7 @@
;; ARMv8.1-A LSE instructions.
;; Atomic swap with memory.
(define_insn "aarch64_atomic_swp<mode>"
(define_insn "@aarch64_atomic_swp<mode>"
[(set (match_operand:ALLI 0 "register_operand" "+&r")
(match_operand:ALLI 1 "aarch64_sync_memory_operand" "+Q"))
(set (match_dup 1)
......@@ -609,7 +609,7 @@
;; Atomic compare-and-swap: HI and smaller modes.
(define_insn "aarch64_atomic_cas<mode>"
(define_insn "@aarch64_atomic_cas<mode>"
[(set (match_operand:SI 0 "register_operand" "+&r") ;; out
(zero_extend:SI
(match_operand:SHORT 1 "aarch64_sync_memory_operand" "+Q"))) ;; memory.
......@@ -634,7 +634,7 @@
;; Atomic compare-and-swap: SI and larger modes.
(define_insn "aarch64_atomic_cas<mode>"
(define_insn "@aarch64_atomic_cas<mode>"
[(set (match_operand:GPI 0 "register_operand" "+&r") ;; out
(match_operand:GPI 1 "aarch64_sync_memory_operand" "+Q")) ;; memory.
(set (match_dup 1)
......@@ -658,7 +658,7 @@
;; Atomic load-op: Load data, operate, store result, keep data.
(define_insn "aarch64_atomic_load<atomic_ldop><mode>"
(define_insn "@aarch64_atomic_load<atomic_ldop><mode>"
[(set (match_operand:ALLI 0 "register_operand" "=r")
(match_operand:ALLI 1 "aarch64_sync_memory_operand" "+Q"))
(set (match_dup 1)
......
......@@ -115,26 +115,37 @@ A @code{define_insn} is an RTL expression containing four or five operands:
@enumerate
@item
An optional name. The presence of a name indicates that this instruction
pattern can perform a certain standard job for the RTL-generation
pass of the compiler. This pass knows certain names and will use
the instruction patterns with those names, if the names are defined
in the machine description.
An optional name @var{n}. When a name is present, the compiler
automically generates a C++ function @samp{gen_@var{n}} that takes
the operands of the instruction as arguments and returns the instruction's
rtx pattern. The compiler also assigns the instruction a unique code
@samp{CODE_FOR_@var{n}}, with all such codes belonging to an enum
called @code{insn_code}.
These names serve one of two purposes. The first is to indicate that the
instruction performs a certain standard job for the RTL-generation
pass of the compiler, such as a move, an addition, or a conditional
jump. The second is to help the target generate certain target-specific
operations, such as when implementing target-specific intrinsic functions.
It is better to prefix target-specific names with the name of the
target, to avoid any clash with current or future standard names.
The absence of a name is indicated by writing an empty string
where the name should go. Nameless instruction patterns are never
used for generating RTL code, but they may permit several simpler insns
to be combined later on.
Names that are not thus known and used in RTL-generation have no
effect; they are equivalent to no name at all.
For the purpose of debugging the compiler, you may also specify a
name beginning with the @samp{*} character. Such a name is used only
for identifying the instruction in RTL dumps; it is equivalent to having
a nameless pattern for all other purposes. Names beginning with the
@samp{*} character are not required to be unique.
The name may also have the form @samp{@@@var{n}}. This has the same
effect as a name @samp{@var{n}}, but in addition tells the compiler to
generate further helper functions; see @xref{Parameterized Names} for details.
@item
The @dfn{RTL template}: This is a vector of incomplete RTL expressions
which describe the semantics of the instruction (@pxref{RTL Template}).
......@@ -10530,6 +10541,7 @@ facilities to make this process easier.
* Code Iterators:: Doing the same for codes.
* Int Iterators:: Doing the same for integers.
* Subst Iterators:: Generating variations of patterns for define_subst.
* Parameterized Names:: Specifying iterator values in C++ code.
@end menu
@node Mode Iterators
......@@ -10925,4 +10937,101 @@ replaced in the first copy of the original RTL-template.
@var{subst-applied-value} is a value with which subst-attribute would be
replaced in the second copy of the original RTL-template.
@node Parameterized Names
@subsection Parameterized Names
@cindex @samp{@@} in instruction pattern names
Ports sometimes need to apply iterators using C++ code, in order to
get the code or RTL pattern for a specific instruction. For example,
suppose we have the @samp{neon_vq<absneg><mode>} pattern given above:
@smallexample
(define_int_iterator QABSNEG [UNSPEC_VQABS UNSPEC_VQNEG])
(define_int_attr absneg [(UNSPEC_VQABS "abs") (UNSPEC_VQNEG "neg")])
(define_insn "neon_vq<absneg><mode>"
[(set (match_operand:VDQIW 0 "s_register_operand" "=w")
(unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w")
(match_operand:SI 2 "immediate_operand" "i")]
QABSNEG))]
@dots{}
)
@end smallexample
A port might need to generate this pattern for a variable
@samp{QABSNEG} value and a variable @samp{VDQIW} mode. There are two
ways of doing this. The first is to build the rtx for the pattern
directly from C++ code; this is a valid technique and avoids any risk
of combinatorial explosion. The second is to prefix the instruction
name with the special character @samp{@@}, which tells GCC to generate
the four additional functions below. In each case, @var{name} is the
name of the instruction without the leading @samp{@@} character,
without the @samp{<@dots{}>} placeholders, and with any underscore
before a @samp{<@dots{}>} placeholder removed if keeping it would
lead to a double or trailing underscore.
@table @samp
@item insn_code maybe_code_for_@var{name} (@var{i1}, @var{i2}, @dots{})
See whether replacing the first @samp{<@dots{}>} placeholder with
iterator value @var{i1}, the second with iterator value @var{i2}, and
so on, gives a valid instruction. Return its code if so, otherwise
return @code{CODE_FOR_nothing}.
@item insn_code code_for_@var{name} (@var{i1}, @var{i2}, @dots{})
Same, but abort the compiler if the requested instruction does not exist.
@item rtx maybe_gen_@var{name} (@var{i1}, @var{i2}, @dots{}, @var{op0}, @var{op1}, @dots{})
Check for a valid instruction in the same way as
@code{maybe_code_for_@var{name}}. If the instruction exists,
generate an instance of it using the operand values given by @var{op0},
@var{op1}, and so on, otherwise return null.
@item rtx gen_@var{name} (@var{i1}, @var{i2}, @dots{}, @var{op0}, @var{op1}, @dots{})
Same, but abort the compiler if the requested instruction does not exist,
or if the instruction generator invoked the @code{FAIL} macro.
@end table
For example, changing the pattern above to:
@smallexample
(define_insn "@@neon_vq<absneg><mode>"
[(set (match_operand:VDQIW 0 "s_register_operand" "=w")
(unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w")
(match_operand:SI 2 "immediate_operand" "i")]
QABSNEG))]
@dots{}
)
@end smallexample
would define the same patterns as before, but in addition would generate
the four functions below:
@smallexample
insn_code maybe_code_for_neon_vq (int, machine_mode);
insn_code code_for_neon_vq (int, machine_mode);
rtx maybe_gen_neon_vq (int, machine_mode, rtx, rtx, rtx);
rtx gen_neon_vq (int, machine_mode, rtx, rtx, rtx);
@end smallexample
Calling @samp{code_for_neon_vq (UNSPEC_VQABS, V8QImode)}
would then give @code{CODE_FOR_neon_vqabsv8qi}.
It is possible to have multiple @samp{@@} patterns with the same
name and same types of iterator. For example:
@smallexample
(define_insn "@@some_arithmetic_op<mode>"
[(set (match_operand:INTEGER_MODES 0 "register_operand") @dots{})]
@dots{}
)
(define_insn "@@some_arithmetic_op<mode>"
[(set (match_operand:FLOAT_MODES 0 "register_operand") @dots{})]
@dots{}
)
@end smallexample
would produce a single set of functions that handles both
@code{INTEGER_MODES} and @code{FLOAT_MODES}.
@end ifset
......@@ -752,6 +752,92 @@ output_peephole2_scratches (rtx split)
}
}
/* Print "arg<N>" parameter declarations for each argument N of ONAME. */
static void
print_overload_arguments (overloaded_name *oname)
{
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
printf ("%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
}
/* Print code to test whether INSTANCE should be chosne, given that
argument N of the overload is available as "arg<N>". */
static void
print_overload_test (overloaded_instance *instance)
{
for (unsigned int i = 0; i < instance->arg_values.length (); ++i)
printf ("%sarg%d == %s", i == 0 ? " if (" : "\n && ",
i, instance->arg_values[i]);
printf (")\n");
}
/* Emit a maybe_code_for_* function for ONAME. */
static void
handle_overloaded_code_for (overloaded_name *oname)
{
/* Print the function prototype. */
printf ("\ninsn_code\nmaybe_code_for_%s (", oname->name);
print_overload_arguments (oname);
printf (")\n{\n");
/* Use a sequence of "if" statements for each instance. */
for (overloaded_instance *instance = oname->first_instance;
instance; instance = instance->next)
{
print_overload_test (instance);
printf (" return CODE_FOR_%s;\n", instance->name);
}
/* Return null if no match was found. */
printf (" return CODE_FOR_nothing;\n}\n");
}
/* Emit a maybe_gen_* function for ONAME. */
static void
handle_overloaded_gen (overloaded_name *oname)
{
/* All patterns must have the same number of operands. */
pattern_stats stats;
get_pattern_stats (&stats, XVEC (oname->first_instance->insn, 1));
for (overloaded_instance *instance = oname->first_instance->next;
instance; instance = instance->next)
{
pattern_stats stats2;
get_pattern_stats (&stats2, XVEC (instance->insn, 1));
if (stats.num_generator_args != stats2.num_generator_args)
fatal_at (get_file_location (instance->insn),
"inconsistent number of operands for '%s'; "
"this instance has %d, but previous instances had %d",
oname->name, stats2.num_generator_args,
stats.num_generator_args);
}
/* Print the function prototype. */
printf ("\nrtx\nmaybe_gen_%s (", oname->name);
print_overload_arguments (oname);
for (int i = 0; i < stats.num_generator_args; ++i)
printf (", rtx x%d", i);
printf (")\n{\n");
/* Use maybe_code_for_*, instead of duplicating the selection logic here. */
printf (" insn_code code = maybe_code_for_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
printf ("%sarg%d", i == 0 ? "" : ", ", i);
printf (");\n"
" if (code != CODE_FOR_nothing)\n"
" return GEN_FCN (code) (");
for (int i = 0; i < stats.num_generator_args; ++i)
printf ("%sx%d", i == 0 ? "" : ", ", i);
printf (");\n"
" else\n"
" return NULL_RTX;\n"
"}\n");
}
int
main (int argc, const char **argv)
{
......@@ -840,6 +926,13 @@ from the machine description file `md'. */\n\n");
output_add_clobbers ();
output_added_clobbers_hard_reg_p ();
for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
oname; oname = oname->next)
{
handle_overloaded_code_for (oname);
handle_overloaded_gen (oname);
}
fflush (stdout);
return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
}
......@@ -104,6 +104,63 @@ open_outfile (const char *file_name)
return f;
}
/* Declare the maybe_code_for_* function for ONAME, and provide
an inline definition of the assserting code_for_* wrapper. */
static void
handle_overloaded_code_for (FILE *file, overloaded_name *oname)
{
fprintf (file, "\nextern insn_code maybe_code_for_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
fprintf (file, ");\n");
fprintf (file, "inline insn_code\ncode_for_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
fprintf (file, ")\n{\n insn_code code = maybe_code_for_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
fprintf (file,
");\n"
" gcc_assert (code != CODE_FOR_nothing);\n"
" return code;\n"
"}\n");
}
/* Declare the maybe_gen_* function for ONAME, and provide
an inline definition of the assserting gen_* wrapper. */
static void
handle_overloaded_gen (FILE *file, overloaded_name *oname)
{
pattern_stats stats;
get_pattern_stats (&stats, XVEC (oname->first_instance->insn, 1));
fprintf (file, "\nextern rtx maybe_gen_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
for (int i = 0; i < stats.num_generator_args; ++i)
fprintf (file, ", rtx");
fprintf (file, ");\n");
fprintf (file, "inline rtx\ngen_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
for (int i = 0; i < stats.num_generator_args; ++i)
fprintf (file, ", rtx x%d", i);
fprintf (file, ")\n{\n rtx res = maybe_gen_%s (", oname->name);
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
for (int i = 0; i < stats.num_generator_args; ++i)
fprintf (file, ", x%d", i);
fprintf (file,
");\n"
" gcc_assert (res);\n"
" return res;\n"
"}\n");
}
int
main (int argc, const char **argv)
{
......@@ -220,7 +277,16 @@ main (int argc, const char **argv)
"optab_to_code (optab op)\n"
"{\n"
" return optab_to_code_[op];\n"
"}\n"
"}\n");
for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
oname; oname = oname->next)
{
handle_overloaded_code_for (h_file, oname);
handle_overloaded_gen (h_file, oname);
}
fprintf (h_file,
"#endif\n"
"\n"
"extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
......
......@@ -1003,7 +1003,10 @@ md_reader::md_reader (bool compact)
m_first_dir_md_include (NULL),
m_last_dir_md_include_ptr (&m_first_dir_md_include),
m_first_line (0),
m_last_line (0)
m_last_line (0),
m_first_overload (NULL),
m_next_overload_ptr (&m_first_overload),
m_overloads_htab (NULL)
{
/* Set the global singleton pointer. */
md_reader_ptr = this;
......
......@@ -91,6 +91,48 @@ struct enum_type {
unsigned int num_values;
};
/* Describes one instance of an overloaded_name. */
struct overloaded_instance {
/* The next instance in the chain, or null if none. */
overloaded_instance *next;
/* The values that the overloaded_name arguments should have for this
instance to be chosen. Each value is a C token. */
vec<const char *> arg_values;
/* The full (non-overloaded) name of the pattern. */
const char *name;
/* The corresponding define_expand or define_insn. */
rtx insn;
};
/* Describes a define_expand or define_insn whose name was preceded by '@'.
Overloads are uniquely determined by their name and the types of their
arguments; it's possible to have overloads with the same name but
different argument types. */
struct overloaded_name {
/* The next overloaded name in the chain. */
overloaded_name *next;
/* The overloaded name (i.e. the name with "@" character and
"<...>" placeholders removed). */
const char *name;
/* The C types of the iterators that determine the underlying pattern,
in the same order as in the pattern name. E.g. "<mode>" in the
pattern name would give a "machine_mode" argument here. */
vec<const char *> arg_types;
/* The first instance associated with this overloaded_name. */
overloaded_instance *first_instance;
/* Where to chain new overloaded_instances. */
overloaded_instance **next_instance_ptr;
};
struct mapping;
/* A class for reading .md files and RTL dump files.
Implemented in read-md.c.
......@@ -165,6 +207,7 @@ class md_reader
rtx x, unsigned int index,
const char *name);
struct mapping *read_mapping (struct iterator_group *group, htab_t table);
overloaded_name *handle_overloaded_name (rtx, vec<mapping *> *);
const char *get_top_level_filename () const { return m_toplevel_fname; }
const char *get_filename () const { return m_read_md_filename; }
......@@ -174,6 +217,8 @@ class md_reader
struct obstack *get_string_obstack () { return &m_string_obstack; }
htab_t get_md_constants () { return m_md_constants; }
overloaded_name *get_overloads () const { return m_first_overload; }
private:
/* A singly-linked list of filenames. */
struct file_name_list {
......@@ -253,6 +298,16 @@ class md_reader
/* If non-zero, filter the input to just this subset of lines. */
int m_first_line;
int m_last_line;
/* The first overloaded_name. */
overloaded_name *m_first_overload;
/* Where to chain further overloaded_names, */
overloaded_name **m_next_overload_ptr;
/* A hash table of overloaded_names, keyed off their name and the types of
their arguments. */
htab_t m_overloads_htab;
};
/* Global singleton; constrast with rtx_reader_ptr below. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment