Commit 75df257b by Richard Sandiford Committed by Richard Sandiford

Accept code attributes as rtx codes in .md files

The recent AArch64 absolute difference patterns had to go through
some hoops to pair max/min rtx codes with the same signedness.
I also need to pair signed/unsigned codes with sign/zero extension
for some SVE ACLE patterns.

This patch therefore supports <...> as rtx codes, like we already
do for modes.

2019-05-12  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* doc/md.texi: Document use of code attributes in rtx patterns.
	* read-md.h (rtx_reader::rtx_alloc_for_name): New member function.
	* read-rtl.c (find_code): Split out search loops into...
	(maybe_find_code): ...this new function.
	(check_code_iterator): Make the error message more informative.
	(check_code_attribute): New function.
	(rtx_reader::rtx_alloc_for_name): Likewise.
	(rtx_reader::read_rtx_code): Use rtx_alloc_for_name.
	* config/aarch64/predicates.md (aarch64_smin, aarch64_umin): Delete.
	* config/aarch64/aarch64-simd.md (*aarch64_<su>abd<mode>_3): Use
	<max_opp> directly as an rtx code instead of via a match_operator.
	* config/aarch64/aarch64-sve.md (aarch64_<su>abd<mode>_3): Likewise.
	(<su>abd<mode>_3): Update accordingly.

From-SVN: r271107
parent 4c016457
2019-05-12 Richard Sandiford <richard.sandiford@arm.com>
* doc/md.texi: Document use of code attributes in rtx patterns.
* read-md.h (rtx_reader::rtx_alloc_for_name): New member function.
* read-rtl.c (find_code): Split out search loops into...
(maybe_find_code): ...this new function.
(check_code_iterator): Make the error message more informative.
(check_code_attribute): New function.
(rtx_reader::rtx_alloc_for_name): Likewise.
(rtx_reader::read_rtx_code): Use rtx_alloc_for_name.
* config/aarch64/predicates.md (aarch64_smin, aarch64_umin): Delete.
* config/aarch64/aarch64-simd.md (*aarch64_<su>abd<mode>_3): Use
<max_opp> directly as an rtx code instead of via a match_operator.
* config/aarch64/aarch64-sve.md (aarch64_<su>abd<mode>_3): Likewise.
(<su>abd<mode>_3): Update accordingly.
2019-05-12 Iain Sandoe <iain@sandoe.co.uk> 2019-05-12 Iain Sandoe <iain@sandoe.co.uk>
* config/rs6000/rs6000.c (debug_stack_info): When -mdebug=stack * config/rs6000/rs6000.c (debug_stack_info): When -mdebug=stack
......
...@@ -716,9 +716,9 @@ ...@@ -716,9 +716,9 @@
(USMAX:VDQ_BHSI (USMAX:VDQ_BHSI
(match_operand:VDQ_BHSI 1 "register_operand" "w") (match_operand:VDQ_BHSI 1 "register_operand" "w")
(match_operand:VDQ_BHSI 2 "register_operand" "w")) (match_operand:VDQ_BHSI 2 "register_operand" "w"))
(match_operator 3 "aarch64_<max_opp>" (<max_opp>:VDQ_BHSI
[(match_dup 1) (match_dup 1)
(match_dup 2)])))] (match_dup 2))))]
"TARGET_SIMD" "TARGET_SIMD"
"<su>abd\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>" "<su>abd\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>"
[(set_attr "type" "neon_abd<q>")] [(set_attr "type" "neon_abd<q>")]
......
...@@ -3149,8 +3149,7 @@ ...@@ -3149,8 +3149,7 @@
[(set_attr "movprfx" "*,yes")] [(set_attr "movprfx" "*,yes")]
) )
;; Helper expander for aarch64_<su>abd<mode>_3 to save the callers ;; Unpredicated integer absolute difference.
;; the hassle of constructing the other arm of the MINUS.
(define_expand "<su>abd<mode>_3" (define_expand "<su>abd<mode>_3"
[(use (match_operand:SVE_I 0 "register_operand")) [(use (match_operand:SVE_I 0 "register_operand"))
(USMAX:SVE_I (match_operand:SVE_I 1 "register_operand") (USMAX:SVE_I (match_operand:SVE_I 1 "register_operand")
...@@ -3158,9 +3157,8 @@ ...@@ -3158,9 +3157,8 @@
"TARGET_SVE" "TARGET_SVE"
{ {
rtx pred = force_reg (<VPRED>mode, CONSTM1_RTX (<VPRED>mode)); rtx pred = force_reg (<VPRED>mode, CONSTM1_RTX (<VPRED>mode));
rtx other_arm = gen_rtx_<MAX_OPP> (<MODE>mode, operands[1], operands[2]);
emit_insn (gen_aarch64_<su>abd<mode>_3 (operands[0], pred, operands[1], emit_insn (gen_aarch64_<su>abd<mode>_3 (operands[0], pred, operands[1],
operands[2], other_arm)); operands[2]));
DONE; DONE;
} }
) )
...@@ -3174,9 +3172,9 @@ ...@@ -3174,9 +3172,9 @@
(USMAX:SVE_I (USMAX:SVE_I
(match_operand:SVE_I 2 "register_operand" "0, w") (match_operand:SVE_I 2 "register_operand" "0, w")
(match_operand:SVE_I 3 "register_operand" "w, w")) (match_operand:SVE_I 3 "register_operand" "w, w"))
(match_operator 4 "aarch64_<max_opp>" (<max_opp>:SVE_I
[(match_dup 2) (match_dup 2)
(match_dup 3)]))] (match_dup 3)))]
UNSPEC_MERGE_PTRUE))] UNSPEC_MERGE_PTRUE))]
"TARGET_SVE" "TARGET_SVE"
"@ "@
......
...@@ -323,12 +323,6 @@ ...@@ -323,12 +323,6 @@
(ior (match_operand 0 "register_operand") (ior (match_operand 0 "register_operand")
(match_operand 0 "const_scalar_int_operand"))) (match_operand 0 "const_scalar_int_operand")))
(define_predicate "aarch64_smin"
(match_code "smin"))
(define_predicate "aarch64_umin"
(match_code "umin"))
;; True for integer comparisons and for FP comparisons other than LTGT or UNEQ. ;; True for integer comparisons and for FP comparisons other than LTGT or UNEQ.
(define_special_predicate "aarch64_comparison_operator" (define_special_predicate "aarch64_comparison_operator"
(match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,unordered, (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,unordered,
......
...@@ -10979,6 +10979,27 @@ Other attributes are defined using: ...@@ -10979,6 +10979,27 @@ Other attributes are defined using:
(define_code_attr @var{name} [(@var{code1} "@var{value1}") @dots{} (@var{coden} "@var{valuen}")]) (define_code_attr @var{name} [(@var{code1} "@var{value1}") @dots{} (@var{coden} "@var{valuen}")])
@end smallexample @end smallexample
Instruction patterns can use code attributes as rtx codes, which can be
useful if two sets of codes act in tandem. For example, the following
@code{define_insn} defines two patterns, one calculating a signed absolute
difference and another calculating an unsigned absolute difference:
@smallexample
(define_code_iterator any_max [smax umax])
(define_code_attr paired_min [(smax "smin") (umax "umin")])
(define_insn @dots{}
[(set (match_operand:SI 0 @dots{})
(minus:SI (any_max:SI (match_operand:SI 1 @dots{})
(match_operand:SI 2 @dots{}))
(<paired_min>:SI (match_dup 1) (match_dup 2))))]
@dots{})
@end smallexample
The signed version of the instruction uses @code{smax} and @code{smin}
while the unsigned version uses @code{umax} and @code{umin}. There
are no versions that pair @code{smax} with @code{umin} or @code{umax}
with @code{smin}.
Here's an example of code iterators in action, taken from the MIPS port: Here's an example of code iterators in action, taken from the MIPS port:
@smallexample @smallexample
......
...@@ -337,6 +337,7 @@ class rtx_reader : public md_reader ...@@ -337,6 +337,7 @@ class rtx_reader : public md_reader
~rtx_reader (); ~rtx_reader ();
bool read_rtx (const char *rtx_name, vec<rtx> *rtxen); bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
rtx rtx_alloc_for_name (const char *);
rtx read_rtx_code (const char *code_name); rtx read_rtx_code (const char *code_name);
virtual rtx read_rtx_operand (rtx return_rtx, int idx); virtual rtx read_rtx_operand (rtx return_rtx, int idx);
rtx read_nested_rtx (); rtx read_nested_rtx ();
......
...@@ -194,22 +194,31 @@ static const compact_insn_name compact_insn_names[] = { ...@@ -194,22 +194,31 @@ static const compact_insn_name compact_insn_names[] = {
{ NOTE, "cnote" } { NOTE, "cnote" }
}; };
/* Implementations of the iterator_group callbacks for codes. */ /* Return the rtx code for NAME, or UNKNOWN if NAME isn't a valid rtx code. */
static int static rtx_code
find_code (const char *name) maybe_find_code (const char *name)
{ {
int i; for (int i = 0; i < NUM_RTX_CODE; i++)
for (i = 0; i < NUM_RTX_CODE; i++)
if (strcmp (GET_RTX_NAME (i), name) == 0) if (strcmp (GET_RTX_NAME (i), name) == 0)
return i; return (rtx_code) i;
for (i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++) for (int i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
if (strcmp (compact_insn_names[i].name, name) == 0) if (strcmp (compact_insn_names[i].name, name) == 0)
return compact_insn_names[i].code; return compact_insn_names[i].code;
fatal_with_file_and_line ("unknown rtx code `%s'", name); return UNKNOWN;
}
/* Implementations of the iterator_group callbacks for codes. */
static int
find_code (const char *name)
{
rtx_code code = maybe_find_code (name);
if (code == UNKNOWN)
fatal_with_file_and_line ("unknown rtx code `%s'", name);
return code;
} }
static void static void
...@@ -1306,7 +1315,37 @@ check_code_iterator (struct mapping *iterator) ...@@ -1306,7 +1315,37 @@ check_code_iterator (struct mapping *iterator)
for (v = iterator->values->next; v != 0; v = v->next) for (v = iterator->values->next; v != 0; v = v->next)
if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0) if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0)
fatal_with_file_and_line ("code iterator `%s' combines " fatal_with_file_and_line ("code iterator `%s' combines "
"different rtx formats", iterator->name); "`%s' and `%s', which have different "
"rtx formats", iterator->name,
GET_RTX_NAME (bellwether),
GET_RTX_NAME (v->number));
}
/* Check that all values of attribute ATTR are rtx codes that have a
consistent format. Return a representative code. */
static rtx_code
check_code_attribute (mapping *attr)
{
rtx_code bellwether = UNKNOWN;
for (map_value *v = attr->values; v != 0; v = v->next)
{
rtx_code code = maybe_find_code (v->string);
if (code == UNKNOWN)
fatal_with_file_and_line ("code attribute `%s' contains "
"unrecognized rtx code `%s'",
attr->name, v->string);
if (bellwether == UNKNOWN)
bellwether = code;
else if (strcmp (GET_RTX_FORMAT (bellwether),
GET_RTX_FORMAT (code)) != 0)
fatal_with_file_and_line ("code attribute `%s' combines "
"`%s' and `%s', which have different "
"rtx formats", attr->name,
GET_RTX_NAME (bellwether),
GET_RTX_NAME (code));
}
return bellwether;
} }
/* Read an rtx-related declaration from the MD file, given that it /* Read an rtx-related declaration from the MD file, given that it
...@@ -1467,6 +1506,54 @@ parse_reg_note_name (const char *string) ...@@ -1467,6 +1506,54 @@ parse_reg_note_name (const char *string)
fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string); fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
} }
/* Allocate an rtx for code NAME. If NAME is a code iterator or code
attribute, record its use for later and use one of its possible
values as an interim rtx code. */
rtx
rtx_reader::rtx_alloc_for_name (const char *name)
{
#ifdef GENERATOR_FILE
size_t len = strlen (name);
if (name[0] == '<' && name[len - 1] == '>')
{
/* Copy the attribute string into permanent storage, without the
angle brackets around it. */
obstack *strings = get_string_obstack ();
obstack_grow0 (strings, name + 1, len - 2);
char *deferred_name = XOBFINISH (strings, char *);
/* Find the name of the attribute. */
const char *attr = strchr (deferred_name, ':');
if (!attr)
attr = deferred_name;
/* Find the attribute itself. */
mapping *m = (mapping *) htab_find (codes.attrs, &attr);
if (!m)
fatal_with_file_and_line ("unknown code attribute `%s'", attr);
/* Pick the first possible code for now, and record the attribute
use for later. */
rtx x = rtx_alloc (check_code_attribute (m));
record_attribute_use (&codes, x, 0, deferred_name);
return x;
}
mapping *iterator = (mapping *) htab_find (codes.iterators, &name);
if (iterator != 0)
{
/* Pick the first possible code for now, and record the iterator
use for later. */
rtx x = rtx_alloc (rtx_code (iterator->values->number));
record_iterator_use (iterator, x, 0);
return x;
}
#endif
return rtx_alloc (rtx_code (codes.find_builtin (name)));
}
/* Subroutine of read_rtx and read_nested_rtx. CODE_NAME is the name of /* Subroutine of read_rtx and read_nested_rtx. CODE_NAME is the name of
either an rtx code or a code iterator. Parse the rest of the rtx and either an rtx code or a code iterator. Parse the rest of the rtx and
return it. */ return it. */
...@@ -1475,7 +1562,6 @@ rtx ...@@ -1475,7 +1562,6 @@ rtx
rtx_reader::read_rtx_code (const char *code_name) rtx_reader::read_rtx_code (const char *code_name)
{ {
RTX_CODE code; RTX_CODE code;
struct mapping *iterator = NULL;
const char *format_ptr; const char *format_ptr;
struct md_name name; struct md_name name;
rtx return_rtx; rtx return_rtx;
...@@ -1509,20 +1595,9 @@ rtx_reader::read_rtx_code (const char *code_name) ...@@ -1509,20 +1595,9 @@ rtx_reader::read_rtx_code (const char *code_name)
return return_rtx; return return_rtx;
} }
/* If this code is an iterator, build the rtx using the iterator's
first value. */
#ifdef GENERATOR_FILE
iterator = (struct mapping *) htab_find (codes.iterators, &code_name);
if (iterator != 0)
code = (enum rtx_code) iterator->values->number;
else
code = (enum rtx_code) codes.find_builtin (code_name);
#else
code = (enum rtx_code) codes.find_builtin (code_name);
#endif
/* If we end up with an insn expression then we free this space below. */ /* If we end up with an insn expression then we free this space below. */
return_rtx = rtx_alloc (code); return_rtx = rtx_alloc_for_name (code_name);
code = GET_CODE (return_rtx);
format_ptr = GET_RTX_FORMAT (code); format_ptr = GET_RTX_FORMAT (code);
memset (return_rtx, 0, RTX_CODE_SIZE (code)); memset (return_rtx, 0, RTX_CODE_SIZE (code));
PUT_CODE (return_rtx, code); PUT_CODE (return_rtx, code);
...@@ -1534,9 +1609,6 @@ rtx_reader::read_rtx_code (const char *code_name) ...@@ -1534,9 +1609,6 @@ rtx_reader::read_rtx_code (const char *code_name)
m_reuse_rtx_by_id[reuse_id] = return_rtx; m_reuse_rtx_by_id[reuse_id] = return_rtx;
} }
if (iterator)
record_iterator_use (iterator, return_rtx, 0);
/* Check for flags. */ /* Check for flags. */
read_flags (return_rtx); read_flags (return_rtx);
......
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