* [PATCH 2/9] (approved) Introduce rtl_data::init_stack_alignment
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
@ 2016-11-11 20:43 ` David Malcolm
2016-11-23 20:09 ` Jeff Law
2016-11-11 20:43 ` [PATCH 3/9] Introduce emit_status::ensure_regno_capacity David Malcolm
` (7 subsequent siblings)
8 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:43 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
(approved by Bernd)
Move this part of "expand"'s initialization of crtl into its own
method so that it can used by the RTL frontend when postprocessing
RTL dumps.
gcc/ChangeLog:
* cfgexpand.c (pass_expand::execute): Move stack initializations
to rtl_data::init_stack_alignment and call it.
* emit-rtl.c (rtl_data::init_stack_alignment): New method.
* emit-rtl.h (rtl_data::init_stack_alignment): New method.
---
gcc/cfgexpand.c | 5 +----
gcc/emit-rtl.c | 12 ++++++++++++
gcc/emit-rtl.h | 2 ++
3 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 5145583..6bc6d29 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -6214,10 +6214,7 @@ pass_expand::execute (function *fun)
discover_nonconstant_array_refs ();
targetm.expand_to_rtl_hook ();
- crtl->stack_alignment_needed = STACK_BOUNDARY;
- crtl->max_used_stack_slot_alignment = STACK_BOUNDARY;
- crtl->stack_alignment_estimated = 0;
- crtl->preferred_stack_boundary = STACK_BOUNDARY;
+ crtl->init_stack_alignment ();
fun->cfg->max_jumptable_ents = 0;
/* Resovle the function section. Some targets, like ARM EABI rely on knowledge
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 9ea0c8f..e995899 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -6287,5 +6287,17 @@ need_atomic_barrier_p (enum memmodel model, bool pre)
gcc_unreachable ();
}
}
+
+/* Initialize fields of rtl_data related to stack alignment. */
+
+void
+rtl_data::init_stack_alignment ()
+{
+ stack_alignment_needed = STACK_BOUNDARY;
+ max_used_stack_slot_alignment = STACK_BOUNDARY;
+ stack_alignment_estimated = 0;
+ preferred_stack_boundary = STACK_BOUNDARY;
+}
+
\f
#include "gt-emit-rtl.h"
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 0a242b1..21c180b 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -55,6 +55,8 @@ struct GTY(()) incoming_args {
/* Datastructures maintained for currently processed function in RTL form. */
struct GTY(()) rtl_data {
+ void init_stack_alignment ();
+
struct expr_status expr;
struct emit_status emit;
struct varasm_status varasm;
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 2/9] (approved) Introduce rtl_data::init_stack_alignment
2016-11-11 20:43 ` [PATCH 2/9] (approved) Introduce rtl_data::init_stack_alignment David Malcolm
@ 2016-11-23 20:09 ` Jeff Law
0 siblings, 0 replies; 78+ messages in thread
From: Jeff Law @ 2016-11-23 20:09 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/11/2016 02:15 PM, David Malcolm wrote:
> (approved by Bernd)
And me too :-0
>
> Move this part of "expand"'s initialization of crtl into its own
> method so that it can used by the RTL frontend when postprocessing
> RTL dumps.
>
> gcc/ChangeLog:
> * cfgexpand.c (pass_expand::execute): Move stack initializations
> to rtl_data::init_stack_alignment and call it.
> * emit-rtl.c (rtl_data::init_stack_alignment): New method.
> * emit-rtl.h (rtl_data::init_stack_alignment): New method.
OK.
jeff
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 3/9] Introduce emit_status::ensure_regno_capacity
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
2016-11-11 20:43 ` [PATCH 2/9] (approved) Introduce rtl_data::init_stack_alignment David Malcolm
@ 2016-11-11 20:43 ` David Malcolm
2016-11-14 14:17 ` Bernd Schmidt
2016-11-23 20:12 ` Jeff Law
2016-11-11 20:44 ` [PATCH 7/9] Add RTL-error-handling to host David Malcolm
` (6 subsequent siblings)
8 siblings, 2 replies; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:43 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Link to earlier version of the patch:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00278.html
gcc/ChangeLog:
* emit-rtl.c (gen_reg_rtx): Move regno_pointer_align and
regno_reg_rtx resizing logic to...
(emit_status::ensure_regno_capacity): ...this new method.
(init_emit): Allocate regno_reg_rtx using ggc_cleared_vec_alloc
rather than ggc_vec_alloc.
* function.h (emit_status::ensure_regno_capacity): New method.
---
gcc/emit-rtl.c | 45 ++++++++++++++++++++++++++-------------------
gcc/function.h | 2 ++
2 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index e995899..50cd388 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1057,29 +1057,35 @@ gen_reg_rtx (machine_mode mode)
/* Do not call gen_reg_rtx with uninitialized crtl. */
gcc_assert (crtl->emit.regno_pointer_align_length);
- /* Make sure regno_pointer_align, and regno_reg_rtx are large
- enough to have an element for this pseudo reg number. */
+ int cur_size = crtl->emit.regno_pointer_align_length;
+ if (reg_rtx_no == cur_size)
+ crtl->emit.ensure_regno_capacity (cur_size * 2);
- if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
- {
- int old_size = crtl->emit.regno_pointer_align_length;
- char *tmp;
- rtx *new1;
+ val = gen_raw_REG (mode, reg_rtx_no);
+ regno_reg_rtx[reg_rtx_no++] = val;
+ return val;
+}
+
+/* Make sure m_regno_pointer_align, and regno_reg_rtx are large
+ enough to have elements in the range 0 <= idx < NEW_SIZE. */
+
+void
+emit_status::ensure_regno_capacity (int new_size)
+{
+ if (new_size < regno_pointer_align_length)
+ return;
- tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
- memset (tmp + old_size, 0, old_size);
- crtl->emit.regno_pointer_align = (unsigned char *) tmp;
+ int old_size = regno_pointer_align_length;
- new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
- memset (new1 + old_size, 0, old_size * sizeof (rtx));
- regno_reg_rtx = new1;
+ char *tmp = XRESIZEVEC (char, regno_pointer_align, new_size);
+ memset (tmp + old_size, 0, new_size - old_size);
+ regno_pointer_align = (unsigned char *) tmp;
- crtl->emit.regno_pointer_align_length = old_size * 2;
- }
+ rtx *new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, new_size);
+ memset (new1 + old_size, 0, (new_size - old_size) * sizeof (rtx));
+ regno_reg_rtx = new1;
- val = gen_raw_REG (mode, reg_rtx_no);
- regno_reg_rtx[reg_rtx_no++] = val;
- return val;
+ crtl->emit.regno_pointer_align_length = new_size;
}
/* Return TRUE if REG is a PARM_DECL, FALSE otherwise. */
@@ -5667,7 +5673,8 @@ init_emit (void)
crtl->emit.regno_pointer_align
= XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
- regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
+ regno_reg_rtx =
+ ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
/* Put copies of all the hard registers into regno_reg_rtx. */
memcpy (regno_reg_rtx,
diff --git a/gcc/function.h b/gcc/function.h
index e854c7f..9fe479c 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -34,6 +34,8 @@ struct GTY(()) sequence_stack {
};
\f
struct GTY(()) emit_status {
+ void ensure_regno_capacity (int new_size);
+
/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
After rtl generation, it is 1 plus the largest register number used. */
int x_reg_rtx_no;
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 7/9] Add RTL-error-handling to host
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
2016-11-11 20:43 ` [PATCH 2/9] (approved) Introduce rtl_data::init_stack_alignment David Malcolm
2016-11-11 20:43 ` [PATCH 3/9] Introduce emit_status::ensure_regno_capacity David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-11-22 21:29 ` Richard Sandiford
2016-11-28 13:47 ` Bernd Schmidt
2016-11-11 20:44 ` [PATCH 9/9] Add "__RTL" to cc1 (v4) David Malcolm
` (5 subsequent siblings)
8 siblings, 2 replies; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Link to previous discussion:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00648.html
On Mon, 2016-10-10 at 19:53 +0100, Richard Sandiford wrote:
> David Malcolm <dmalcolm@redhat.com> writes:
> > On Wed, 2016-10-05 at 18:00 +0200, Bernd Schmidt wrote:
> > > On 10/05/2016 06:15 PM, David Malcolm wrote:
> > > > * errors.c: Use consistent pattern for bconfig.h vs
> > > > config.h
> > > > includes.
> > > > (progname): Wrap with #ifdef GENERATOR_FILE.
> > > > (error): Likewise. Add "error: " to message.
> > > > (fatal): Likewise.
> > > > (internal_error): Likewise.
> > > > (trim_filename): Likewise.
> > > > (fancy_abort): Likewise.
> > > > * errors.h (struct file_location): Move here from read
> > > > -md.h.
> > > > (file_location::file_location): Likewise.
> > > > (error_at): New decl.
> > >
> > > Can you split these out into a separate patch as well? I'll
> > > require
> > > more
> > > explanation for them and they seem largely independent.
> >
> > [CCing Richard Sandiford]
> >
> > The gen* tools have their own diagnostics system, in errors.c:
> >
> > /* warning, error, and fatal. These definitions are suitable for
> > use
> > in the generator programs; the compiler has a more elaborate
> > suite
> > of diagnostic printers, found in diagnostic.c. */
> >
> > with file locations tracked using read-md.h's struct file_location,
> > rather than location_t (aka libcpp's source_location).
> >
> > Implementing an RTL frontend by using the RTL reader from read
> > -rtl.c
> > means that we now need a diagnostics subsystem on the *host* for
> > handling errors in RTL files, rather than just on the build
> > machine.
> >
> > There seem to be two ways to do this:
> >
> > (A) build the "light" diagnostics system (errors.c) for the host
> > as
> > well as build machine, and link it with the RTL reader there, so
> > there
> > are two parallel diagnostics subsystems.
> >
> > (B) build the "real" diagnostics system (diagnostics*) for the
> > *build* machine as well as the host, and use it from the gen*
> > tools,
> > eliminating the "light" system, and porting the gen* tools to use
> > libcpp for location tracking.
> >
> > Approach (A) seems to be simpler, which is what this part of the
> > patch
> > does.
> >
> > I've experimented with approach (B). I think it's doable, but it's
> > much more invasive (perhaps needing a libdiagnostics.a and a
> > build/libdiagnostics.a in gcc/Makefile.in), so I hope this can be
> > followup work.
> >
> > I can split the relevant parts out into a separate patch, but I was
> > wondering if either of you had a strong opinion on (A) vs (B)
> > before I
> > do so?
>
> (A) sounds fine to me FWIW. And sorry for the slow reply.
>
> Thanks,
> Richard
This patch implements approach (A).
It updates the error messages to contain "error: " so that they can
be handled by DejaGnu.
It also adds an "error_at" function to the "light" API. Doing so requires
moving the decl of struct file_location to errors.h.
gcc/ChangeLog:
* Makefile.in (OBJS): Add errors.o.
* errors.c: Use consistent pattern for bconfig.h vs config.h
includes.
(progname): Wrap with #ifdef GENERATOR_FILE.
(error): Likewise. Add "error: " to message.
(fatal): Likewise.
(internal_error): Likewise.
(trim_filename): Likewise.
(fancy_abort): Likewise.
* errors.h (struct file_location): Move here from read-md.h.
(file_location::file_location): Likewise.
(error_at): New decl.
* read-md.h (struct file_location): Move to errors.h.
(file_location::file_location): Likewise.
Include errors.h.
---
gcc/Makefile.in | 1 +
gcc/errors.c | 23 +++++++++++++++++------
gcc/errors.h | 14 ++++++++++++++
gcc/read-md.h | 14 +-------------
4 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fa54215..c265893 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1266,6 +1266,7 @@ OBJS = \
dwarf2cfi.o \
dwarf2out.o \
emit-rtl.o \
+ errors.o \
et-forest.o \
except.o \
explow.o \
diff --git a/gcc/errors.c b/gcc/errors.c
index 468384c..8df94ab 100644
--- a/gcc/errors.c
+++ b/gcc/errors.c
@@ -21,18 +21,21 @@ along with GCC; see the file COPYING3. If not see
in the generator programs; the compiler has a more elaborate suite
of diagnostic printers, found in diagnostic.c. */
-#ifdef HOST_GENERATOR_FILE
-#include "config.h"
-#define GENERATOR_FILE 1
-#else
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
#endif
#include "system.h"
#include "errors.h"
/* Set this to argv[0] at the beginning of main. */
+#ifdef GENERATOR_FILE
const char *progname;
+#endif /* #ifdef GENERATOR_FILE */
/* Starts out 0, set to 1 if error is called. */
@@ -55,13 +58,15 @@ warning (const char *format, ...)
/* Print an error message - we keep going but the output is unusable. */
+#ifdef GENERATOR_FILE
+
void
error (const char *format, ...)
{
va_list ap;
va_start (ap, format);
- fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, "%s: error: ", progname);
vfprintf (stderr, format, ap);
va_end (ap);
fputc ('\n', stderr);
@@ -69,6 +74,7 @@ error (const char *format, ...)
have_error = 1;
}
+#endif /* #ifdef GENERATOR_FILE */
/* Fatal error - terminate execution immediately. Does not return. */
@@ -78,7 +84,7 @@ fatal (const char *format, ...)
va_list ap;
va_start (ap, format);
- fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, "%s: error: ", progname);
vfprintf (stderr, format, ap);
va_end (ap);
fputc ('\n', stderr);
@@ -87,6 +93,8 @@ fatal (const char *format, ...)
/* Similar, but say we got an internal error. */
+#ifdef GENERATOR_FILE
+
void
internal_error (const char *format, ...)
{
@@ -127,8 +135,11 @@ trim_filename (const char *name)
/* "Fancy" abort. Reports where in the compiler someone gave up.
This file is used only by build programs, so we're not as polite as
the version in diagnostic.c. */
+
void
fancy_abort (const char *file, int line, const char *func)
{
internal_error ("abort in %s, at %s:%d", func, trim_filename (file), line);
}
+
+#endif /* #ifdef GENERATOR_FILE */
diff --git a/gcc/errors.h b/gcc/errors.h
index a6973f3..ebafa77 100644
--- a/gcc/errors.h
+++ b/gcc/errors.h
@@ -28,8 +28,22 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ERRORS_H
#define GCC_ERRORS_H
+/* Records a position in the file. */
+struct file_location {
+ file_location () {}
+ file_location (const char *, int, int);
+
+ const char *filename;
+ int lineno;
+ int colno;
+};
+
+inline file_location::file_location (const char *filename_in, int lineno_in, int colno_in)
+: filename (filename_in), lineno (lineno_in), colno (colno_in) {}
+
extern void warning (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
extern void error (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
+extern void error_at (file_location, const char *, ...) ATTRIBUTE_PRINTF_2 ATTRIBUTE_COLD;
extern void fatal (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
extern void internal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
extern const char *trim_filename (const char *);
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 27fc9c2..8910b75 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -21,19 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_READ_MD_H
#include "obstack.h"
-
-/* Records a position in the file. */
-struct file_location {
- file_location () {}
- file_location (const char *, int, int);
-
- const char *filename;
- int lineno;
- int colno;
-};
-
-inline file_location::file_location (const char *filename_in, int lineno_in, int colno_in)
-: filename (filename_in), lineno (lineno_in), colno (colno_in) {}
+#include "errors.h"
/* Holds one symbol or number in the .md file. */
struct md_name {
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-11 20:44 ` [PATCH 7/9] Add RTL-error-handling to host David Malcolm
@ 2016-11-22 21:29 ` Richard Sandiford
2016-11-28 13:47 ` Bernd Schmidt
1 sibling, 0 replies; 78+ messages in thread
From: Richard Sandiford @ 2016-11-22 21:29 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches
David Malcolm <dmalcolm@redhat.com> writes:
> +inline file_location::file_location (const char *filename_in, int lineno_in, int colno_in)
> +: filename (filename_in), lineno (lineno_in), colno (colno_in) {}
> +
Long line (a pre-existing problem, since you're just moving the code).
I'm happy with this FWIW, but it'd be a stretch to say the whole thing
comes under the gen* umbrella.
Thanks,
Richard
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-11 20:44 ` [PATCH 7/9] Add RTL-error-handling to host David Malcolm
2016-11-22 21:29 ` Richard Sandiford
@ 2016-11-28 13:47 ` Bernd Schmidt
2016-11-29 17:20 ` David Malcolm
1 sibling, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-11-28 13:47 UTC (permalink / raw)
To: David Malcolm, gcc-patches
Been looking at this off and on, and I'm still not sure I entirely get
it - sorry.
On 11/11/2016 10:15 PM, David Malcolm wrote:
>>> Implementing an RTL frontend by using the RTL reader from read
>>> -rtl.c
>>> means that we now need a diagnostics subsystem on the *host* for
>>> handling errors in RTL files, rather than just on the build
>>> machine.
So, there are two things that bother me about this patch description:
- The host already has the full diagnostic subsystem. The fact that
you're commenting out some of the functions in errors.c suggests
that errors.c is conflicting with the full one.
- We already compile errors.c for both build and host.
Is there a problem with using both the full and the light errors system
for read-rtl, as available? Mismatches in function signatures or
something like this?
> -#ifdef HOST_GENERATOR_FILE
> -#include "config.h"
> -#define GENERATOR_FILE 1
> -#else
> +/* This file is compiled twice: once for the generator programs
> + once for the compiler. */
> +#ifdef GENERATOR_FILE
> #include "bconfig.h"
> +#else
> +#include "config.h"
> #endif
> #include "system.h"
> #include "errors.h"
The Makefile still has a HOST_GENERATOR_FILE definition for errors.c
after this.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-28 13:47 ` Bernd Schmidt
@ 2016-11-29 17:20 ` David Malcolm
2016-11-29 17:23 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-29 17:20 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches
On Mon, 2016-11-28 at 14:47 +0100, Bernd Schmidt wrote:
> Been looking at this off and on, and I'm still not sure I entirely
> get
> it - sorry.
>
> On 11/11/2016 10:15 PM, David Malcolm wrote:
> > > > Implementing an RTL frontend by using the RTL reader from read
> > > > -rtl.c
> > > > means that we now need a diagnostics subsystem on the *host*
> > > > for
> > > > handling errors in RTL files, rather than just on the build
> > > > machine.
>
> So, there are two things that bother me about this patch description:
> - The host already has the full diagnostic subsystem.
Maybe I worded this poorly.
I meant to say:
"we now need
((a diagnostics subsystem for handling errors in RTL files)
on the *host*),
rather than just on the build machine."
rather than:
"we now need a
((diagnostics subsystem on the *host*)
for handling
errors in RTL files),
rather than just on the build machine."
if that distinction makes sense. Clearly we already have a diagnostics
subsystem on the host; what this patch is adding is the separate, rtl-s
pecific diagnostic subsystem to cc1 on the host.
> The fact that
> you're commenting out some of the functions in errors.c suggests
> that errors.c is conflicting with the full one.
It doesn't conflict: C++ overloading allows both to co-exist. However
I wanted to make sure that we don't accidentally use the RTL-specific
error-handling within other parts of the compiler.
> - We already compile errors.c for both build and host.
Aha, yes, we do, it's linked into gengtype on the host to allow plugins
to support GTY. The patch adds it to OBJS so that it is available
within cc1.
> Is there a problem with using both the full and the light errors
> system
> for read-rtl, as available? Mismatches in function signatures or
> something like this?
As noted above, C++ overloading allows this.
> > -#ifdef HOST_GENERATOR_FILE
> > -#include "config.h"
> > -#define GENERATOR_FILE 1
> > -#else
> > +/* This file is compiled twice: once for the generator programs
> > + once for the compiler. */
> > +#ifdef GENERATOR_FILE
> > #include "bconfig.h"
> > +#else
> > +#include "config.h"
> > #endif
> > #include "system.h"
> > #include "errors.h"
>
> The Makefile still has a HOST_GENERATOR_FILE definition for errors.c
> after this.
Will remove.
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-29 17:20 ` David Malcolm
@ 2016-11-29 17:23 ` Bernd Schmidt
2016-11-29 18:53 ` David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-11-29 17:23 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/29/2016 06:20 PM, David Malcolm wrote:
>
> if that distinction makes sense. Clearly we already have a diagnostics
> subsystem on the host; what this patch is adding is the separate, rtl-s
> pecific diagnostic subsystem to cc1 on the host.
So that still seems odd to me. Why not use the normal diagnostics
subsystem, and add whatever you need from it to errors.c for use from
the generator programs? What exactly makes it "rtl-specific"?
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-29 17:23 ` Bernd Schmidt
@ 2016-11-29 18:53 ` David Malcolm
2016-11-29 21:13 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-29 18:53 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches
On Tue, 2016-11-29 at 18:23 +0100, Bernd Schmidt wrote:
> On 11/29/2016 06:20 PM, David Malcolm wrote:
> >
> > if that distinction makes sense. Clearly we already have a
> > diagnostics
> > subsystem on the host; what this patch is adding is the separate,
> > rtl-s
> > pecific diagnostic subsystem to cc1 on the host.
>
> So that still seems odd to me. Why not use the normal diagnostics
> subsystem, and add whatever you need from it to errors.c for use from
> the generator programs? What exactly makes it "rtl-specific"?
The main issue is that the normal diagnostics subsystem tracks
locations using location_t (aka libcpp's source_location), rather than
read-md.h's struct file_location, so we'd need to start using libcpp
from the generator programs, porting the location tracking to using
libcpp (e.g. creating linemaps for the files).
There would also be various Makefile.in tweaking to build various files
twice; hopefully that wouldn't lead to any unexpected issues.
Quoting from:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00648.html
> There seem to be two ways to do this:
>
> (A) build the "light" diagnostics system (errors.c) for the host as
> well as build machine, and link it with the RTL reader there, so
there
> are two parallel diagnostics subsystems.
>
> (B) build the "real" diagnostics system (diagnostics*) for the
> *build* machine as well as the host, and use it from the gen* tools,
> eliminating the "light" system, and porting the gen* tools to use
> libcpp for location tracking.
>
> Approach (A) seems to be simpler, which is what this part of the
patch
> does.
>
> I've experimented with approach (B). I think it's doable, but it's
> much more invasive (perhaps needing a libdiagnostics.a and a
> build/libdiagnostics.a in gcc/Makefile.in), so I hope this can be
> followup work.
>
> I can split the relevant parts out into a separate patch, but I was
> wondering if either of you had a strong opinion on (A) vs (B) before
I
> do so?
This patch implements approach (A).
Would you prefer that I went with approach (B), or is approach (A)
acceptable?
Thanks
Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-29 18:53 ` David Malcolm
@ 2016-11-29 21:13 ` Bernd Schmidt
2016-11-30 16:18 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-11-29 21:13 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/29/2016 07:53 PM, David Malcolm wrote:
> Would you prefer that I went with approach (B), or is approach (A)
> acceptable?
Well, I was hoping there'd be an approach (C) where the read-rtl code
uses whatever diagnostics framework that is available. Maybe it'll turn
out that's too hard. Somehow the current patch looked strange to me, but
if there's no easy alternative maybe we'll have to go with it.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] Add RTL-error-handling to host
2016-11-29 21:13 ` Bernd Schmidt
@ 2016-11-30 16:18 ` Bernd Schmidt
2016-11-30 19:51 ` [PATCH] Minimal reimplementation of errors.c within read-md.c David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-11-30 16:18 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/29/2016 10:13 PM, Bernd Schmidt wrote:
> On 11/29/2016 07:53 PM, David Malcolm wrote:
>
>> Would you prefer that I went with approach (B), or is approach (A)
>> acceptable?
>
> Well, I was hoping there'd be an approach (C) where the read-rtl code
> uses whatever diagnostics framework that is available. Maybe it'll turn
> out that's too hard. Somehow the current patch looked strange to me, but
> if there's no easy alternative maybe we'll have to go with it.
So, I've tried to build patches 1-6 + 8, without #7. It looks like the
differences are as follows:
- A lack of seen_error in errors.[ch], could be easily added, and
basically a spelling mismatch between have_error and errorcount.
- A lack of fatal in diagnostics.c. Could maybe be added to just call
fatal_error?
All this seems simpler and cleaner to fix than linking two different
error handling frameworks into one binary. Do you see any other
difficulties?
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Minimal reimplementation of errors.c within read-md.c
2016-11-30 16:18 ` Bernd Schmidt
@ 2016-11-30 19:51 ` David Malcolm
2016-12-01 12:40 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-30 19:51 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
On Wed, 2016-11-30 at 17:18 +0100, Bernd Schmidt wrote:
> On 11/29/2016 10:13 PM, Bernd Schmidt wrote:
> > On 11/29/2016 07:53 PM, David Malcolm wrote:
> >
> > > Would you prefer that I went with approach (B), or is approach
> > > (A)
> > > acceptable?
> >
> > Well, I was hoping there'd be an approach (C) where the read-rtl
> > code
> > uses whatever diagnostics framework that is available. Maybe it'll
> > turn
> > out that's too hard. Somehow the current patch looked strange to
> > me, but
> > if there's no easy alternative maybe we'll have to go with it.
>
> So, I've tried to build patches 1-6 + 8, without #7. It looks like
> the
> differences are as follows:
>
> - A lack of seen_error in errors.[ch], could be easily added, and
> basically a spelling mismatch between have_error and errorcount.
> - A lack of fatal in diagnostics.c. Could maybe be added to just call
> fatal_error?
>
> All this seems simpler and cleaner to fix than linking two different
> error handling frameworks into one binary. Do you see any other
> difficulties?
>
>
> Bernd
Thanks. Here's an implementation of that idea.
Given that fatal_error doesn't expose a way to accept va_args, it
seemed simplest to just copy the implementation from errors.c,
and conditionalize it with #ifndef GENERATOR_FILE.
Only lightly tested so far, but it builds (stage 1) and passes the
new rtl.exp test suite from patch 9 (which includes an error-handling
test).
Is this OK, assuming it passes regular testing?
gcc/ChangeLog:
* read-md.c (have_error): New global, copied from errors.c.
(fatal): New function, copied from errors.c.
* selftest-rtl.c: Include "diagnostic-core.h".
---
gcc/read-md.c | 25 +++++++++++++++++++++++++
gcc/selftest-rtl.c | 1 +
2 files changed, 26 insertions(+)
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 25bc3c4..ce99473 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -31,6 +31,31 @@ along with GCC; see the file COPYING3. If not see
#include "vec.h"
#include "read-md.h"
+#ifndef GENERATOR_FILE
+
+/* Minimal reimplementation of errors.c for use by RTL frontend
+ within cc1. */
+
+int have_error = 0;
+
+/* Fatal error - terminate execution immediately. Does not return. */
+
+void
+fatal (const char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ fprintf (stderr, "%s: ", progname);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+ fputc ('\n', stderr);
+ exit (FATAL_EXIT_CODE);
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+
/* Associates PTR (which can be a string, etc.) with the file location
specified by FILENAME and LINENO. */
struct ptr_loc {
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
index 8f3c976..c5ab216 100644
--- a/gcc/selftest-rtl.c
+++ b/gcc/selftest-rtl.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "memmodel.h"
#include "emit-rtl.h"
#include "selftest-rtl.h"
+#include "diagnostic-core.h"
#if CHECKING_P
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Minimal reimplementation of errors.c within read-md.c
2016-11-30 19:51 ` [PATCH] Minimal reimplementation of errors.c within read-md.c David Malcolm
@ 2016-12-01 12:40 ` Bernd Schmidt
2016-12-02 22:34 ` [PATCH] Even more minimal " David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-01 12:40 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/30/2016 09:24 PM, David Malcolm wrote:
> gcc/ChangeLog:
> * read-md.c (have_error): New global, copied from errors.c.
> (fatal): New function, copied from errors.c.
I would have expected the function to go into diagnostic.c, but actually
there are already various functions of this sort in read-md. I'd request
you place it near fatal_at, and maybe add this to errors.h:
inline bool seen_error ()
{
return have_error;
}
and replace explicit uses of have_error with that to unify things a bit.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Even more minimal reimplementation of errors.c within read-md.c
2016-12-01 12:40 ` Bernd Schmidt
@ 2016-12-02 22:34 ` David Malcolm
2016-12-06 12:11 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-02 22:34 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
On Thu, 2016-12-01 at 13:40 +0100, Bernd Schmidt wrote:
> On 11/30/2016 09:24 PM, David Malcolm wrote:
>
> > gcc/ChangeLog:
> > * read-md.c (have_error): New global, copied from errors.c.
> > (fatal): New function, copied from errors.c.
>
> I would have expected the function to go into diagnostic.c, but
> actually
> there are already various functions of this sort in read-md.
In a way, there are three diagnostic systems in the codebase:
- the functions in errors.h/errors.c (warning, error, fatal, etc)
- the functions in read-md.c (error_at, fatal_at) which share the
"have_error" global with errors.c.
- the "real" diagnostics subsystem (diagnostics.c etc)
It turns out that the only thing using "fatal" within read-md.c is
md_reader::read_md_files. The interface this provides is overly
complicated for the RTL FE's purposes, so the following patch avoids
using it in favor of a simpler, new method: md_reader::read_file.
With that, the only thing needed in read-md.c from errors.c on the host
is just the "have_error" global; the patch verifies that by
conditionalizing the include of errors.h on #ifdef GENERATOR_FILE
(and similarly conditionalizing md_reader::read_md_files, since
"fatal" isn't implemented on the host).
> I'd request
> you place it near fatal_at, and maybe add this to errors.h:
>
> inline bool seen_error ()
> {
> return have_error;
> }
>
> and replace explicit uses of have_error with that to unify things a
> bit.
>
>
> Bernd
seen_error is already implemented in the "real" diagnostic subsystem,
and would be a clash: we want a way to determine if read-md.c's
implementation of error_at was called. Hence it seems simplest to
conditionally add a copy of the "have_error" global to read-md.c.
Thoughts?
gcc/ChangeLog:
* read-md.c: Wrap include of errors.h with #ifdef GENERATOR_FILE.
(have_error): New global, copied from errors.c.
(md_reader::read_md_files): Wrap with #ifdef GENERATOR_FILE.
(md_reader::read_file): New method.
* read-md.h (md_reader::read_file): New method.
* read-rtl-function.c (read_rtl_function_body): Reimplement in
terms of md_reader::read_file.
---
gcc/read-md.c | 31 +++++++++++++++++++++++++++++++
gcc/read-md.h | 1 +
gcc/read-rtl-function.c | 6 +-----
3 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 25bc3c4..e581326 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -26,11 +26,23 @@ along with GCC; see the file COPYING3. If not see
#endif
#include "system.h"
#include "coretypes.h"
+#ifdef GENERATOR_FILE
#include "errors.h"
+#endif /* #ifdef GENERATOR_FILE */
#include "statistics.h"
#include "vec.h"
#include "read-md.h"
+#ifndef GENERATOR_FILE
+
+/* Minimal reimplementation of errors.c for use by RTL frontend
+ within cc1. */
+
+int have_error = 0;
+
+#endif /* #ifndef GENERATOR_FILE */
+
+
/* Associates PTR (which can be a string, etc.) with the file location
specified by FILENAME and LINENO. */
struct ptr_loc {
@@ -1190,6 +1202,8 @@ md_reader::add_include_path (const char *arg)
m_last_dir_md_include_ptr = &dirtmp->next;
}
+#ifdef GENERATOR_FILE
+
/* The main routine for reading .md files. Try to process all the .md
files specified on the command line and return true if no error occurred.
@@ -1296,6 +1310,23 @@ md_reader::read_md_files (int argc, const char **argv,
return !have_error;
}
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Read FILENAME. */
+
+bool
+md_reader::read_file (const char *filename)
+{
+ m_read_md_filename = filename;
+ m_read_md_file = fopen (m_read_md_filename, "r");
+ if (m_read_md_file == 0)
+ {
+ perror (m_read_md_filename);
+ return false;
+ }
+ handle_toplevel_file ();
+ return !have_error;
+}
/* Read FILENAME, filtering to just the given lines. */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 6a73b00..5fc7605 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -110,6 +110,7 @@ class md_reader
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
+ bool read_file (const char *filename);
bool read_file_fragment (const char *filename,
int first_line,
int last_line);
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index ddea836..5188b86 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -1590,12 +1590,8 @@ read_rtl_function_body (const char *path)
init_emit ();
init_varasm_status ();
- auto_vec<const char *> argv (2);
- argv.safe_push (progname);
- argv.safe_push (path);
-
function_reader reader;
- if (!reader.read_md_files (argv.length (), argv.address (), NULL))
+ if (!reader.read_file (path))
return false;
return true;
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Even more minimal reimplementation of errors.c within read-md.c
2016-12-02 22:34 ` [PATCH] Even more minimal " David Malcolm
@ 2016-12-06 12:11 ` Bernd Schmidt
0 siblings, 0 replies; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-06 12:11 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/03/2016 12:07 AM, David Malcolm wrote:
> seen_error is already implemented in the "real" diagnostic subsystem,
> and would be a clash: we want a way to determine if read-md.c's
> implementation of error_at was called. Hence it seems simplest to
> conditionally add a copy of the "have_error" global to read-md.c.
>
> Thoughts?
Yeah, ok. I think this area could be cleaned up but with this minimal
patch it's become somewhat of an orthogonal problem.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 9/9] Add "__RTL" to cc1 (v4)
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
` (2 preceding siblings ...)
2016-11-11 20:44 ` [PATCH 7/9] Add RTL-error-handling to host David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-11-14 15:14 ` Richard Biener
2016-11-11 20:44 ` [PATCH 4/9] (approved) Add some functions for use by the RTL frontend David Malcolm
` (4 subsequent siblings)
8 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Changed in this version:
* Rather than running just one pass, run *all* passes, but start at
the given pass; support for "dg-do run" tests that execute the
resulting code.
* Updated test cases to new "compact" dump format; more test cases;
use "dg-do run" in various places.
* Lots of bugfixing
Links to previous versions:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00263.html
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00500.html
gcc/ChangeLog:
* Makefile.in (OBJS): Add run-rtl-passes.o.
gcc/c-family/ChangeLog:
* c-common.c (c_common_reswords): Add "__RTL".
* c-common.h (enum rid): Add RID_RTL.
gcc/c/ChangeLog:
* c-parser.c: Include "read-rtl-function.h" and
"run-rtl-passes.h".
(c_parser_declaration_or_fndef): In the "GNU extensions" part of
the leading comment, add an alternate production for
"function-definition", along with new "rtl-body-specifier" and
"rtl-body-pass-specifier" productions. Handle "__RTL" by calling
c_parser_parse_rtl_body. Convert a timevar_push/pop pair
to an auto_timevar, to cope with early exit.
(c_parser_parse_rtl_body): New function.
gcc/ChangeLog:
* cfg.c (free_original_copy_tables): Remove assertion
on original_copy_bb_pool.
* cgraph.h (symtab_node::native_rtl_p): New decl.
* cgraphunit.c (symtab_node::native_rtl_p): New function.
(symtab_node::needed_p): Don't assert for early assembly output
for __RTL functions.
(cgraph_node::finalize_function): Set "force_output" for __RTL
functions.
(cgraph_node::analyze): Bail out early for __RTL functions.
(analyze_functions): Update assertion to support __RTL functions.
(cgraph_node::expand): Bail out early for __RTL functions.
* emit-rtl.c (unshare_all_rtl_again): Wrap set_used_decls call
in check for DECL_INITIAL.
* final.c (rest_of_clean_state): Don't call delete_tree_ssa for
_RTL functions.
* function.h (struct function): Add field "native_RTL".
* gimple-expr.c (gimple_has_body_p): Return false for __RTL
functions.
* pass_manager.h (gcc::pass_manager::get_rest_of_compilation): New
accessor.
(gcc::pass_manager::get_clean_slate): New accessor.
* passes.c: Include "insn-addr.h".
(execute_one_pass): Implement skipping of passes for functions
with pass_startwith set.
* read-md.c (md_reader::read_char): Support filtering
the input to a subset of line numbers.
(md_reader::md_reader): Initialize fields
m_first_line and m_last_line.
(md_reader::read_file_fragment): New function.
* read-md.h (md_reader::read_file_fragment): New decl.
(md_reader::m_first_line): New field.
(md_reader::int m_last_line): New field.
* read-rtl-function.c (function_reader::create_function): Only create
cfun if it doesn't already exist. Set "native_RTL" on cfun. Set
DECL_INITIAL.
(read_rtl_function_body_from_file_range): New function.
* read-rtl-function.h (read_rtl_function_body_from_file_range):
New decl.
* run-rtl-passes.c: New file.
* run-rtl-passes.h: New file.
gcc/testsuite/ChangeLog:
* gcc.dg/rtl/aarch64/asr_div1.c: New file.
* gcc.dg/rtl/aarch64/pr71779.c: New file.
* gcc.dg/rtl/rtl.exp: New file.
* gcc.dg/rtl/test.c: New file.
* gcc.dg/rtl/unknown-rtx-code.c: New file.
* gcc.dg/rtl/x86_64/dfinit.c: New file.
* gcc.dg/rtl/x86_64/different-structs.c: New file.
* gcc.dg/rtl/x86_64/final.c: New file.
* gcc.dg/rtl/x86_64/into-cfglayout.c: New file.
* gcc.dg/rtl/x86_64/ira.c: New file.
* gcc.dg/rtl/x86_64/pro_and_epilogue.c: New file.
* gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c: New file.
* gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c: New file.
* gcc.dg/rtl/x86_64/test-rtl.c: New file.
* gcc.dg/rtl/x86_64/test_1.h: New file.
* gcc.dg/rtl/x86_64/times-two.c.after-expand.c: New file.
* gcc.dg/rtl/x86_64/times-two.c.before-df.c: New file.
* gcc.dg/rtl/x86_64/vregs.c: New file.
---
gcc/Makefile.in | 1 +
gcc/c-family/c-common.c | 1 +
gcc/c-family/c-common.h | 3 +
gcc/c/c-parser.c | 122 ++++++++++++++++++-
gcc/cfg.c | 1 -
gcc/cgraph.h | 4 +
gcc/cgraphunit.c | 41 ++++++-
gcc/emit-rtl.c | 3 +-
gcc/final.c | 3 +-
gcc/function.h | 9 ++
gcc/gimple-expr.c | 2 +-
gcc/pass_manager.h | 6 +
gcc/passes.c | 47 ++++++++
gcc/read-md.c | 35 +++++-
gcc/read-md.h | 7 ++
gcc/read-rtl-function.c | 83 ++++++++++---
gcc/read-rtl-function.h | 3 +
gcc/run-rtl-passes.c | 85 +++++++++++++
gcc/run-rtl-passes.h | 25 ++++
gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c | 41 +++++++
gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c | 50 ++++++++
gcc/testsuite/gcc.dg/rtl/rtl.exp | 41 +++++++
gcc/testsuite/gcc.dg/rtl/test.c | 31 +++++
gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c | 8 ++
gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c | 116 ++++++++++++++++++
.../gcc.dg/rtl/x86_64/different-structs.c | 81 +++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/final.c | 133 +++++++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c | 117 ++++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/ira.c | 111 +++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c | 110 +++++++++++++++++
.../rtl/x86_64/test-return-const.c.after-expand.c | 39 ++++++
.../rtl/x86_64/test-return-const.c.before-fwprop.c | 42 +++++++
gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c | 101 ++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h | 16 +++
.../gcc.dg/rtl/x86_64/times-two.c.after-expand.c | 70 +++++++++++
.../gcc.dg/rtl/x86_64/times-two.c.before-df.c | 54 +++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c | 112 +++++++++++++++++
37 files changed, 1727 insertions(+), 27 deletions(-)
create mode 100644 gcc/run-rtl-passes.c
create mode 100644 gcc/run-rtl-passes.h
create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/rtl.exp
create mode 100644 gcc/testsuite/gcc.dg/rtl/test.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/final.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 73d12dc..14ffb96 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1429,6 +1429,7 @@ OBJS = \
rtlhash.o \
rtlanal.o \
rtlhooks.o \
+ run-rtl-passes.o \
sbitmap.o \
sched-deps.o \
sched-ebb.o \
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 307862b..573ca7a 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -435,6 +435,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
+ { "__RTL", RID_RTL, 0 },
{ "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "asm", RID_ASM, D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 547bab2..5e6882e 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -118,6 +118,9 @@ enum rid
RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
+ /* "__RTL", for the RTL-parsing extension to the C frontend. */
+ RID_RTL,
+
/* C11 */
RID_ALIGNAS, RID_GENERIC,
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6bc42da..e6e86ec 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -59,6 +59,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-expr.h"
#include "context.h"
#include "gcc-rich-location.h"
+#include "read-rtl-function.h"
+#include "run-rtl-passes.h"
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
@@ -1421,6 +1423,9 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
static void c_parser_cilk_grainsize (c_parser *, bool *);
+static void c_parser_parse_rtl_body (c_parser *parser,
+ const char *start_with_pass);
+
/* Parse a translation unit (C90 6.7, C99 6.9).
translation-unit:
@@ -1624,6 +1629,16 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
declaration-specifiers declarator declaration-list[opt]
compound-statement
+ function-definition:
+ declaration-specifiers rtl-body-specifier declarator declaration-list[opt]
+ compound-statement
+
+ rtl-body-specifier:
+ __RTL rtl-body-pass-specifier[opt]
+
+ rtl-body-pass-specifier:
+ ( string )
+
attribute ;
Objective-C:
@@ -1668,6 +1683,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
tree all_prefix_attrs;
bool diagnosed_no_specs = false;
location_t here = c_parser_peek_token (parser)->location;
+ bool rtl_body_p = false;
+ const char *start_with_pass = NULL;
if (static_assert_ok
&& c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -1752,6 +1769,33 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
+
+ /* Handle GNU extension rtl-body-specifier by detecting "__RTL". */
+ if (c_parser_next_token_is_keyword (parser, RID_RTL))
+ {
+ rtl_body_p = true;
+ c_parser_consume_token (parser);
+
+ /* Handle the optional rtl-body-pass-specifier: parens wrapping
+ a string, giving a pass name. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser);
+ c_token *tok = c_parser_peek_token (parser);
+ if (tok->type != CPP_STRING)
+ {
+ c_parser_error (parser, "expected string");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ gcc_assert (TREE_CODE (tok->value) == STRING_CST);
+ start_with_pass = TREE_STRING_POINTER (tok->value);
+ c_parser_consume_token (parser);
+
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ }
+
finish_declspecs (specs);
bool auto_type_p = specs->typespec_word == cts_auto_type;
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -2146,7 +2190,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
tv = TV_PARSE_INLINE;
else
tv = TV_PARSE_FUNC;
- timevar_push (tv);
+ auto_timevar at (g_timer, tv);
/* Parse old-style parameter declarations. ??? Attributes are
not allowed to start declaration specifiers here because of a
@@ -2173,6 +2217,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= c_parser_peek_token (parser)->location;
+
+ /* If we had an rtl-body-specifier, use the RTL parser now,
+ consuming the function body. */
+ if (rtl_body_p)
+ {
+ c_parser_parse_rtl_body (parser, start_with_pass);
+
+ /* Normally, store_parm_decls sets next_is_function_body,
+ anticipating a function body. We need a push_scope/pop_scope
+ pair to flush out this state, or subsequent function parsing
+ will go wrong. */
+ push_scope ();
+ pop_scope ();
+
+ finish_function ();
+ return;
+ }
+
fnbody = c_parser_compound_statement (parser);
if (flag_cilkplus && contains_array_notation_expr (fnbody))
fnbody = expand_array_notation_exprs (fnbody);
@@ -2195,7 +2257,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
finish_function ();
}
- timevar_pop (tv);
break;
}
}
@@ -18313,4 +18374,61 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
return value_tree;
}
+/* Parse the body of a function declaration marked with "__RTL".
+
+ The RTL parser works on the level of characters read from a
+ FILE *, whereas c_parser works at the level of tokens.
+ Square this circle by consuming all of the tokens up to and
+ including the closing brace, recording the start/end of the RTL
+ fragment, and reopening the file and re-reading the relevant
+ lines within the RTL parser.
+
+ This requires the opening and closing braces of the C function
+ to be on separate lines from the RTL they wrap. */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, const char *start_with_pass)
+{
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ return;
+
+ location_t start_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume all tokens, up to the closing brace, handling
+ matching pairs of braces in the rtl dump. */
+ int num_open_braces = 1;
+ while (1)
+ {
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_BRACE:
+ num_open_braces++;
+ break;
+ case CPP_CLOSE_BRACE:
+ if (--num_open_braces == 0)
+ goto found_closing_brace;
+ break;
+ default:
+ break;
+ }
+ c_parser_consume_token (parser);
+ }
+
+ found_closing_brace:
+ /* At the closing brace; record its location. */
+ location_t end_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume the closing brace. */
+ c_parser_consume_token (parser);
+
+ /* Invoke the RTL parser. */
+ if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+ return;
+
+ /* If a pass name was provided for START_WITH_PASS, run the backend
+ accordingly now, on the cfun created above. */
+ if (start_with_pass)
+ run_rtl_passes (start_with_pass);
+}
+
#include "gt-c-c-parser.h"
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 6604b02..26a68c1 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -1083,7 +1083,6 @@ reset_original_copy_tables (void)
void
free_original_copy_tables (void)
{
- gcc_assert (original_copy_bb_pool);
delete bb_copy;
bb_copy = NULL;
delete bb_original;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cc730d2..79e33da 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -328,6 +328,10 @@ public:
configury. This function is used just during symbol creation. */
bool needed_p (void);
+ /* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+ bool native_rtl_p () const;
+
/* Return true when there are references to the node. */
bool referred_to_p (bool include_self = true);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index e315a77..956562e 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -217,6 +217,19 @@ static void handle_alias_pairs (void);
/* Used for vtable lookup in thunk adjusting. */
static GTY (()) tree vtable_entry_type;
+/* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+
+bool
+symtab_node::native_rtl_p () const
+{
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ return false;
+ if (!DECL_STRUCT_FUNCTION (decl))
+ return false;
+ return DECL_STRUCT_FUNCTION (decl)->native_RTL;
+}
+
/* Determine if symbol declaration is needed. That is, visible to something
either outside this translation unit, something magic in the system
configury */
@@ -225,8 +238,10 @@ symtab_node::needed_p (void)
{
/* Double check that no one output the function into assembly file
early. */
- gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)
- || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
+ if (!native_rtl_p ())
+ gcc_checking_assert
+ (!DECL_ASSEMBLER_NAME_SET_P (decl)
+ || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
if (!definition)
return false;
@@ -435,6 +450,14 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
&& !DECL_DISREGARD_INLINE_LIMITS (decl))
node->force_output = 1;
+ /* __RTL functions were already output as soon as they were parsed (due
+ to the large amount of global state in the backend).
+ Mark such functions as "force_output" to reflect the fact that they
+ will be in the asm file when considering the symbols they reference.
+ The attempt to output them later on will bail out immediately. */
+ if (node->native_rtl_p ())
+ node->force_output = 1;
+
/* When not optimizing, also output the static functions. (see
PR24561), but don't do so for always_inline functions, functions
declared inline and nested functions. These were optimized out
@@ -568,6 +591,12 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
void
cgraph_node::analyze (void)
{
+ if (native_rtl_p ())
+ {
+ analyzed = true;
+ return;
+ }
+
tree decl = this->decl;
location_t saved_loc = input_location;
input_location = DECL_SOURCE_LOCATION (decl);
@@ -1226,7 +1255,8 @@ analyze_functions (bool first_time)
gcc_assert (!cnode->definition || cnode->thunk.thunk_p
|| cnode->alias
- || gimple_has_body_p (decl));
+ || gimple_has_body_p (decl)
+ || cnode->native_rtl_p ());
gcc_assert (cnode->analyzed == cnode->definition);
}
node->aux = NULL;
@@ -1965,6 +1995,11 @@ cgraph_node::expand (void)
/* We ought to not compile any inline clones. */
gcc_assert (!global.inlined_to);
+ /* __RTL functions are compiled as soon as they are parsed, so don't
+ do it again. */
+ if (native_rtl_p ())
+ return;
+
announce_function (decl);
process = 0;
gcc_assert (lowered);
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 179a91f..8039742 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -2672,7 +2672,8 @@ unshare_all_rtl_again (rtx_insn *insn)
}
/* Make sure that virtual stack slots are not shared. */
- set_used_decls (DECL_INITIAL (cfun->decl));
+ if (DECL_INITIAL (cfun->decl))
+ set_used_decls (DECL_INITIAL (cfun->decl));
/* Make sure that virtual parameters are not shared. */
for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = DECL_CHAIN (decl))
diff --git a/gcc/final.c b/gcc/final.c
index 5709d0e..97e2e1a 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4701,7 +4701,8 @@ rest_of_clean_state (void)
free_bb_for_insn ();
- delete_tree_ssa (cfun);
+ if (!cfun->native_RTL)
+ delete_tree_ssa (cfun);
/* We can reduce stack alignment on call site only when we are sure that
the function body just produced will be actually used in the final
diff --git a/gcc/function.h b/gcc/function.h
index 9fe479c..2263f30 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -236,6 +236,9 @@ struct GTY(()) function {
/* The loops in this function. */
struct loops *x_current_loops;
+ /* Filled by the GIMPLE FE, pass to start compilation with. */
+ const char *pass_startwith;
+
/* The stack usage of this function. */
struct stack_usage *su;
@@ -384,6 +387,12 @@ struct GTY(()) function {
/* Set when the tail call has been identified. */
unsigned int tail_call_marked : 1;
+
+ /* Nonzero if the the current function was specified in RTL form using the
+ C frontend's "__RTL" syntax. This initializes global RTL state, and so
+ such functions must be compiled immediately, rather than under the
+ control of the callgraph. */
+ unsigned int native_RTL : 1;
};
/* Add the decl D to the local_decls list of FUN. */
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index de5cce1..3a06888 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -323,7 +323,7 @@ bool
gimple_has_body_p (tree fndecl)
{
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
- return (gimple_body (fndecl) || (fn && fn->cfg));
+ return (gimple_body (fndecl) || (fn && fn->cfg && !fn->native_RTL));
}
/* Return a printable name for symbol DECL. */
diff --git a/gcc/pass_manager.h b/gcc/pass_manager.h
index 464e25f..7278d97 100644
--- a/gcc/pass_manager.h
+++ b/gcc/pass_manager.h
@@ -82,6 +82,12 @@ public:
opt_pass *get_pass_by_name (const char *name);
+ opt_pass *get_rest_of_compilation () const
+ {
+ return pass_rest_of_compilation_1;
+ }
+ opt_pass *get_clean_slate () const { return pass_clean_state_1; }
+
public:
/* The root of the compilation pass tree, once constructed. */
opt_pass *all_passes;
diff --git a/gcc/passes.c b/gcc/passes.c
index e78f9ed..54029f5 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgrtl.h"
#include "tree-ssa-live.h" /* For remove_unused_locals. */
#include "tree-cfgcleanup.h"
+#include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC. */
using namespace gcc;
@@ -2313,6 +2314,52 @@ execute_one_pass (opt_pass *pass)
return false;
}
+ /* For skipping passes until startwith pass */
+ if (cfun
+ && cfun->pass_startwith)
+ {
+ if (strcmp (pass->name, cfun->pass_startwith) == 0)
+ {
+ if (!quiet_flag)
+ fprintf (stderr, "found starting pass: %s\n", cfun->pass_startwith);
+ cfun->pass_startwith = NULL;
+ }
+ else
+ {
+ /* Don't skip df init; later passes need it. */
+ if (strstr (pass->name, "dfinit") == NULL)
+ {
+ if (!quiet_flag)
+ fprintf (stderr, "skipping pass: %s\n", pass->name);
+
+ /* Pass "reload" sets the global "reload_completed", and many
+ things depend on this (e.g. instructions in .md files). */
+ if (strcmp (pass->name, "reload") == 0)
+ reload_completed = 1;
+
+ /* The INSN_ADDRESSES vec is normally set up by
+ shorten_branches; set it up for the benefit of passes that
+ run after this. */
+ if (strcmp (pass->name, "shorten") == 0)
+ INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+ /* Update the cfg hooks as appropriate. */
+ if (strcmp (pass->name, "into_cfglayout") == 0)
+ {
+ cfg_layout_rtl_register_cfg_hooks ();
+ cfun->curr_properties |= PROP_cfglayout;
+ }
+ if (strcmp (pass->name, "outof_cfglayout") == 0)
+ {
+ rtl_register_cfg_hooks ();
+ cfun->curr_properties &= ~PROP_cfglayout;
+ }
+
+ return true;
+ }
+ }
+ }
+
/* Pass execution event trigger: useful to identify passes being
executed. */
invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
diff --git a/gcc/read-md.c b/gcc/read-md.c
index a8462a6..25bc3c4 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -399,6 +399,16 @@ md_reader::read_char (void)
else
m_read_md_colno++;
+ /* If we're filtering lines, treat everything before the range of
+ interest as a space, and as EOF for everything after. */
+ if (m_first_line && m_last_line)
+ {
+ if (m_read_md_lineno < m_first_line)
+ return ' ';
+ if (m_read_md_lineno > m_last_line)
+ return EOF;
+ }
+
return ch;
}
@@ -981,7 +991,9 @@ md_reader::md_reader (bool compact)
m_read_md_lineno (0),
m_read_md_colno (0),
m_first_dir_md_include (NULL),
- m_last_dir_md_include_ptr (&m_first_dir_md_include)
+ m_last_dir_md_include_ptr (&m_first_dir_md_include),
+ m_first_line (0),
+ m_last_line (0)
{
/* Set the global singleton pointer. */
md_reader_ptr = this;
@@ -1284,6 +1296,27 @@ md_reader::read_md_files (int argc, const char **argv,
return !have_error;
}
+
+/* Read FILENAME, filtering to just the given lines. */
+
+bool
+md_reader::read_file_fragment (const char *filename,
+ int first_line,
+ int last_line)
+{
+ m_read_md_filename = filename;
+ m_read_md_file = fopen (m_read_md_filename, "r");
+ if (m_read_md_file == 0)
+ {
+ perror (m_read_md_filename);
+ return false;
+ }
+ m_first_line = first_line;
+ m_last_line = last_line;
+ handle_toplevel_file ();
+ return !have_error;
+}
+
/* class noop_reader : public md_reader */
/* A dummy implementation which skips unknown directives. */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 1be0f5a..06be3ec 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -98,6 +98,9 @@ class md_reader
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
+ bool read_file_fragment (const char *filename,
+ int first_line,
+ int last_line);
/* A hook that handles a single .md-file directive, up to but not
including the closing ')'. It takes two arguments: the file position
@@ -232,6 +235,10 @@ class md_reader
/* A table of enum_type structures, hashed by name. */
htab_t m_enum_types;
+
+ /* If non-zero, filter the input to just this subset of lines. */
+ int m_first_line;
+ int m_last_line;
};
/* Global singleton; constrast with rtx_reader_ptr below. */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index ff6c808..6c4b282 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -489,23 +489,38 @@ function_reader::create_function ()
else
rtl_register_cfg_hooks ();
- /* Create cfun. */
- tree fn_name = get_identifier (m_name ? m_name : "test_1");
- tree int_type = integer_type_node;
- tree return_type = int_type;
- tree arg_types[3] = {int_type, int_type, int_type};
- tree fn_type = build_function_type_array (return_type, 3, arg_types);
- tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
- fn_type);
- tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
- return_type);
- DECL_ARTIFICIAL (resdecl) = 1;
- DECL_IGNORED_P (resdecl) = 1;
- DECL_RESULT (fndecl) = resdecl;
- allocate_struct_function (fndecl, false);
- /* This sets cfun. */
-
- current_function_decl = fndecl;
+ /* When run from selftests or "rtl1", cfun is NULL.
+ When run from "cc1" for a C function tagged with __RTL, cfun is the
+ tagged function. */
+ if (!cfun)
+ {
+ tree fn_name = get_identifier (m_name ? m_name : "test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+ current_function_decl = fndecl;
+ }
+
+ gcc_assert (cfun);
+ gcc_assert (current_function_decl);
+ tree fndecl = current_function_decl;
+
+ /* Mark this function as being specified as __RTL. */
+ cfun->native_RTL = 1;
+
+ /* cc1 normally inits DECL_INITIAL (fndecl) to be error_mark_node.
+ Ensure it is NULL_TREE. */
+ DECL_INITIAL (fndecl) = NULL_TREE;
cfun->curr_properties = (PROP_cfg | PROP_rtl);
@@ -1615,6 +1630,40 @@ read_rtl_function_body (int argc, const char **argv,
return true;
}
+/* Run the RTL dump parser on the range of lines between START_LOC and
+ END_LOC (including those lines). */
+
+bool
+read_rtl_function_body_from_file_range (location_t start_loc,
+ location_t end_loc)
+{
+ expanded_location exploc_start = expand_location (start_loc);
+ expanded_location exploc_end = expand_location (end_loc);
+
+ if (exploc_start.file != exploc_end.file)
+ {
+ error_at (end_loc, "start/end of RTL fragment are in different files");
+ return false;
+ }
+ if (exploc_start.line >= exploc_end.line)
+ {
+ error_at (end_loc,
+ "start of RTL fragment must be on an earlier line than end");
+ return false;
+ }
+
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ function_reader reader (NULL);
+ if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
+ exploc_end.line - 1))
+ return false;
+
+ return true;
+}
+
#if CHECKING_P
namespace selftest {
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index 036fcce..d5d12ab 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -33,4 +33,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
bool (*parse_opt) (const char *),
function_reader_policy *policy);
+extern bool read_rtl_function_body_from_file_range (location_t start_loc,
+ location_t end_loc);
+
#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/run-rtl-passes.c b/gcc/run-rtl-passes.c
new file mode 100644
index 0000000..2bca929
--- /dev/null
+++ b/gcc/run-rtl-passes.c
@@ -0,0 +1,85 @@
+/* run-rtl-passes.c - Run just one RTL pass
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "insn-attr-common.h" /* for INSN_SCHEDULING. */
+#include "insn-attr.h" /* for init_sched_attrs. */
+#include "run-rtl-passes.h"
+
+/* Run the backend passes, starting at the given pass. */
+
+void
+run_rtl_passes (const char *initial_pass_name)
+{
+ cfun->pass_startwith = initial_pass_name;
+ max_regno = max_reg_num ();
+
+ /* Pass "expand" noemally sets this up. */
+#ifdef INSN_SCHEDULING
+ init_sched_attrs ();
+#endif
+
+ bitmap_obstack_initialize (NULL);
+ bitmap_obstack_initialize (®_obstack);
+
+ opt_pass *rest_of_compilation
+ = g->get_passes ()->get_rest_of_compilation ();
+ gcc_assert (rest_of_compilation);
+ execute_pass_list (cfun, rest_of_compilation);
+
+ opt_pass *clean_slate = g->get_passes ()->get_clean_slate ();
+ gcc_assert (clean_slate);
+ execute_pass_list (cfun, clean_slate);
+
+ bitmap_obstack_release (®_obstack);
+}
diff --git a/gcc/run-rtl-passes.h b/gcc/run-rtl-passes.h
new file mode 100644
index 0000000..14ea8ea
--- /dev/null
+++ b/gcc/run-rtl-passes.h
@@ -0,0 +1,25 @@
+/* run-rtl-passes.h - Run a subset of the RTL passes
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_RUN_RTL_PASSES_H
+#define GCC_RUN_RTL_PASSES_H
+
+extern void run_rtl_passes (const char *initial_pass_name);
+
+#endif /* GCC_RUN_RTL_PASSES_H */
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
new file mode 100644
index 0000000..9123651
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
@@ -0,0 +1,41 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-mtune=cortex-a53 -fdump-rtl-combine -O2" } */
+
+/* Taken from
+ gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+ for aarch64, hand editing to the new format. */
+
+int __RTL("combine") f1 (int n)
+{
+(function "f1"
+ (param "n"
+ (DECL_RTL (reg/v:SI %1 [ n ]))
+ (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
+ ) ;; param "n"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 8 (set (reg:DI %2)
+ (lshiftrt:DI (reg:DI %0)
+ (const_int 32)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %0)))
+ (cinsn 9 (set (reg:SI %1)
+ (ashiftrt:SI (subreg:SI (reg:DI %2) 0)
+ (const_int 3)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %2)))
+
+ ;; Extra insn, to avoid all of the above from being deleted by DCE
+ (insn 10 (use (reg/i:SI %1)))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
+}
+
+/* Verify that insns 8 and 9 get combined into a shift of 35 (0x23) */
+/* { dg-final { scan-rtl-dump "allowing combination of insns 8 and 9" "combine" } } */
+/* { dg-final { scan-rtl-dump "modifying insn i3 9: r\[0-9\]+:SI#0=r\[0-9\]+:DI>>0x23" "combine" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
new file mode 100644
index 0000000..d318339
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
@@ -0,0 +1,50 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-fdump-rtl-cse1" } */
+
+/* Dump taken from comment 2 of PR 71779, of
+ "...the relevant memory access coming out of expand"
+ hand-edited to the compact dump format. */
+
+int __RTL("cse1") test (int n)
+{
+(function "fragment"
+ (param "n"
+ (DECL_RTL (reg/v:SI %1 [ n ]))
+ (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
+ ) ;; param "n"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+
+;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
+(insn 1045 (set (reg:SI %480)
+ (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ y.c:12702)
+(insn 1046 (set (reg/f:SI %479)
+ (lo_sum:SI (reg:SI %480)
+ (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ y.c:12702
+ (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+(insn 1047 (set (reg:DI %481)
+ (subreg:DI (reg/f:SI %479) 0)) y.c:12702)
+(insn 1048 (set (zero_extract:DI (reg/v:DI %191 [ obj1D.17368 ])
+ (const_int 32)
+ (const_int 0))
+ (reg:DI %481)) y.c:12702)
+;; Extra insn, to avoid all of the above from being deleted by DCE
+(insn 1049 (set (mem:DI (reg:DI %191) [1 i+0 S4 A32])
+ (const_int 1)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
+}
+
+/* TODO: scan the dump. */
diff --git a/gcc/testsuite/gcc.dg/rtl/rtl.exp b/gcc/testsuite/gcc.dg/rtl/rtl.exp
new file mode 100644
index 0000000..3c6648b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/rtl.exp
@@ -0,0 +1,41 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+ set DEFAULT_RTLFLAGS ""
+ # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.c]]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/rtl/test.c b/gcc/testsuite/gcc.dg/rtl/test.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/test.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+}
+
+/* Example showing:
+ - data structure
+ - loop
+ - call to "abort". */
+
+struct foo
+{
+ int count;
+ float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+ float result = 0.0f;
+
+ if (lhs->count != rhs->count)
+ __builtin_abort ();
+
+ for (int i = 0; i < lhs->count; i++)
+ result += lhs->data[i] * rhs->data[i];
+
+ return result;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
new file mode 100644
index 0000000..dd252f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
@@ -0,0 +1,8 @@
+void __RTL test (void)
+{
+ (function "test"
+ (insn-chain
+ (not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
+ ) ;; insn-chain
+ ) ;; function
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
new file mode 100644
index 0000000..f7b3e77
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
@@ -0,0 +1,116 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+#include "test_1.h"
+
+/* Lightly-modified dump of test.c.261r.split1 for x86_64. */
+
+int __RTL("no-opt dfinit") test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that the dataflow information matches what cc1 would normally
+ have generated. In particular, in earlier versions of the RTL
+ frontend, the exit block use of reg 0 (ax) wasn't picked up
+ on, due to not setting up crtl->return_rtx based on
+ DECL_RESULT (fndecl). */
+/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
new file mode 100644
index 0000000..8db1161
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
@@ -0,0 +1,81 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+extern double sqrt(double x);
+
+struct foo
+{
+ double x;
+ double y;
+};
+
+struct bar
+{
+ double x;
+ double y;
+};
+
+double __RTL test (struct foo *f, const struct bar *b)
+{
+#if 0
+ /* Result of "expand" on this C code, compiled for x86_64 with -Os. */
+ f->x += b->x;
+ f->y += b->y;
+ return sqrt (f->x * f->x + f->y * f->y);
+#endif
+(function "test"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 5 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (reg/v/f:DI %10 [ f ])
+ (reg:DI di [ f ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
+ (cinsn 3 (set (reg/v/f:DI %11 [ b ])
+ (reg:DI si [ b ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
+ (cnote 4 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 7 (set (reg:DF %12)
+ (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 8 (set (reg:DF %2 [ _3 ])
+ (plus:DF (reg:DF %12)
+ (mem:DF (reg/v/f:DI %11 [ b ]) [2 b_12(D)->x+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 9 (set (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])
+ (reg:DF %2 [ _3 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 10 (set (reg:DF %13)
+ (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
+ (const_int 8)) [2 f_11(D)->y+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 11 (set (reg:DF %5 [ _6 ])
+ (plus:DF (reg:DF %13)
+ (mem:DF (plus:DI (reg/v/f:DI %11 [ b ])
+ (const_int 8)) [2 b_12(D)->y+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 12 (set (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
+ (const_int 8)) [2 f_11(D)->y+0 S8 A64])
+ (reg:DF %5 [ _6 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 13 (set (reg:DF %14)
+ (mult:DF (reg:DF %2 [ _3 ])
+ (reg:DF %2 [ _3 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 14 (set (reg:DF %15)
+ (mult:DF (reg:DF %5 [ _6 ])
+ (reg:DF %5 [ _6 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 15 (set (reg:DF %16)
+ (plus:DF (reg:DF %14)
+ (reg:DF %15))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 16 (set (reg:DF xmm0)
+ (reg:DF %16)) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (ccall_insn/j 17 (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)))
+ (expr_list:DF (use (reg:DF xmm0))))
+ (edge-to exit (flags "ABNORMAL | SIBCALL"))
+ ) ;; block 2
+ (cbarrier 18)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:DF xmm0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test"
+
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/final.c b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
new file mode 100644
index 0000000..d10deb0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
@@ -0,0 +1,133 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.304r.dwarf2 for x86_64 target,
+ with various NOTE_INSN_CFI deleted by hand for now. */
+
+int __RTL("final") test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn/f 32 (set (mem:DI (pre_dec:DI (reg/f:DI sp)) [0 S8 A8])
+ (reg/f:DI bp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn/f 33 (set (reg/f:DI bp)
+ (reg/f:DI sp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 34 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 35 NOTE_INSN_PROLOGUE_END)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI ax [90])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (plus:SI (reg:SI ax [90])
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI ax [91])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (neg:SI (reg:SI ax [91])))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cnote 36 NOTE_INSN_EPILOGUE_BEG)
+ (cinsn 37 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn/f 38 (set (reg/f:DI bp)
+ (mem:DI (post_inc:DI (reg/f:DI sp)) [0 S8 A8])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7
+ (expr_list:REG_CFA_DEF_CFA (plus:DI (reg/f:DI sp)
+ (const_int 8))))
+ (cjump_insn 39 (simple_return) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit)
+ ) ;; block 5
+ (cbarrier 40)
+ (cnote 31 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that asm was emitted. */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+ FIXME: this assumes i386.md. */
+/* { dg-final { scan-assembler "ret" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
new file mode 100644
index 0000000..d080956
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
@@ -0,0 +1,117 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-into_cfglayout" } */
+
+/* Lightly-modified dump of test.c.226r.vregs for x86_64. */
+
+#include "test_1.h"
+
+int __RTL("into_cfglayout") test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* The conversion to cfglayout should eliminate unconditional jump
+ instructions... */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "barrier" "into_cfglayout" } } */
+
+/* ...but conditional jumps should be preserved. */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
new file mode 100644
index 0000000..3f729cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
@@ -0,0 +1,111 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.265r.asmcons for x86_64. */
+
+#include "test_1.h"
+
+int __RTL ("ira") test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that IRA was run. */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
new file mode 100644
index 0000000..712faf0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
@@ -0,0 +1,110 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.274r.split2 for x86_64. */
+
+int __RTL("pro_and_epilogue") test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI ax [90])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (plus:SI (reg:SI ax [90])
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI ax [91])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (neg:SI (reg:SI ax [91])))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ (cnote 31 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that the prologue and epilogue were added. */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } } */
+
+/* We expect a jump_insn to "simple_return". */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } } */
+
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
new file mode 100644
index 0000000..bb431ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
@@ -0,0 +1,39 @@
+/* { dg-do run { target x86_64-*-* } } */
+
+extern void abort (void);
+
+int __RTL("vregs") test_returning_constant (void)
+{
+ /* C code:
+ return 42; */
+(function "test_returning_constant"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_returning_constant"
+}
+
+int main (void)
+{
+ if (test_returning_constant () != 42)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
new file mode 100644
index 0000000..4ae5418
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
@@ -0,0 +1,42 @@
+/* { dg-do run { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-fwprop1 -O2" } */
+
+extern void abort (void);
+
+int __RTL ("fwprop1") test_returning_constant (void)
+{
+ /* C code:
+ return 42; */
+(function "test_returning_constant"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ <retval> ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 9 (set (reg/i:SI ax)
+ (const_int 42)) "../../src/test-return-const.c":4
+ (expr_list:REG_DEAD (reg:SI %0 [ <retval> ])))
+ (cinsn 10 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_returning_constant"
+}
+
+/* Verify that insn 5 is eliminated. */
+/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
+/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
+
+int main (void)
+{
+ if (test_returning_constant () != 42)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
new file mode 100644
index 0000000..b4d1e6d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
@@ -0,0 +1,101 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+ This is a dump of test.c from immediately after "expand", for x86_64. */
+
+int __RTL test_1 (int i, int j, int k)
+{
+ /*
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+ */
+(function "test_1"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
new file mode 100644
index 0000000..a783ea8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
@@ -0,0 +1,16 @@
+/* Shared test code for the various __RTL tests of test_1 that
+ start at different passes. */
+
+extern void abort (void);
+extern int test_1 (int i, int j, int k);
+
+int main (void)
+{
+ if (test_1 (0, 0, 3) != -3)
+ abort ();
+
+ if (test_1 (0, 1, 3) != 7)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
new file mode 100644
index 0000000..f6bd45f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
@@ -0,0 +1,70 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+
+extern void abort (void);
+
+int __RTL ("vregs") times_two (int i)
+{
+ /* C function:
+ return i * 2; */
+(function "times_two"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ]))
+ ) ;; param "i"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
+}
+
+int main (void)
+{
+ if (times_two (0) != 0)
+ abort ();
+
+ if (times_two (1) != 2)
+ abort ();
+
+ if (times_two (100) != 200)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
new file mode 100644
index 0000000..5cb4a71
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
@@ -0,0 +1,54 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+int __RTL ("rtl-dfinit") times_two (int i)
+{
+ /* C function:
+ return i * 2; */
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2)
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3)
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3)
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4)
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
+}
+
+/* Verify that the dataflow information matches what cc1 would have
+ generated. In particular, in earlier versions of the RTL
+ frontend, the exit block use of reg 0 (ax) wasn't picked up
+ on, due to not setting up crtl->return_rtx based on
+ DECL_RESULT (fndecl). */
+
+/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+
+/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
new file mode 100644
index 0000000..24d141f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
@@ -0,0 +1,112 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-vregs" } */
+
+/* Lightly-modified dump of test.c.225r.expand for x86_64. */
+
+#include "test_1.h"
+
+int __RTL("vregs") test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame". */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } } */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } } */
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 9/9] Add "__RTL" to cc1 (v4)
2016-11-11 20:44 ` [PATCH 9/9] Add "__RTL" to cc1 (v4) David Malcolm
@ 2016-11-14 15:14 ` Richard Biener
2016-11-15 21:07 ` David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Richard Biener @ 2016-11-14 15:14 UTC (permalink / raw)
To: David Malcolm; +Cc: GCC Patches
On Fri, Nov 11, 2016 at 10:15 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> Changed in this version:
>
> * Rather than running just one pass, run *all* passes, but start at
> the given pass; support for "dg-do run" tests that execute the
> resulting code.
> * Updated test cases to new "compact" dump format; more test cases;
> use "dg-do run" in various places.
> * Lots of bugfixing
>
> Links to previous versions:
> https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00263.html
> https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00500.html
Does running the RTL passes right from the parser work with -fsyntax-only?
Doing it like __GIMPLE has the advantage of not exposing
"rest_of_compilation", etc..
I'm now handling __GIMPLE from within declspecs (the GIMPLE FE stuff
has been committed), it would be nice to match the __RTL piece here.
> gcc/ChangeLog:
> * Makefile.in (OBJS): Add run-rtl-passes.o.
>
> gcc/c-family/ChangeLog:
> * c-common.c (c_common_reswords): Add "__RTL".
> * c-common.h (enum rid): Add RID_RTL.
>
> gcc/c/ChangeLog:
> * c-parser.c: Include "read-rtl-function.h" and
> "run-rtl-passes.h".
> (c_parser_declaration_or_fndef): In the "GNU extensions" part of
> the leading comment, add an alternate production for
> "function-definition", along with new "rtl-body-specifier" and
> "rtl-body-pass-specifier" productions. Handle "__RTL" by calling
> c_parser_parse_rtl_body. Convert a timevar_push/pop pair
> to an auto_timevar, to cope with early exit.
> (c_parser_parse_rtl_body): New function.
>
> gcc/ChangeLog:
> * cfg.c (free_original_copy_tables): Remove assertion
> on original_copy_bb_pool.
How can that trigger?
> * cgraph.h (symtab_node::native_rtl_p): New decl.
> * cgraphunit.c (symtab_node::native_rtl_p): New function.
> (symtab_node::needed_p): Don't assert for early assembly output
> for __RTL functions.
> (cgraph_node::finalize_function): Set "force_output" for __RTL
> functions.
> (cgraph_node::analyze): Bail out early for __RTL functions.
> (analyze_functions): Update assertion to support __RTL functions.
> (cgraph_node::expand): Bail out early for __RTL functions.
> * emit-rtl.c (unshare_all_rtl_again): Wrap set_used_decls call
> in check for DECL_INITIAL.
You should simply set DECL_INITIAL of your function decl (make_node (BLOCK);).
There's too much code assuming that is not NULL (and I've fixed quite a bit of
code during stage1 not doing that).
> * final.c (rest_of_clean_state): Don't call delete_tree_ssa for
> _RTL functions.
> * function.h (struct function): Add field "native_RTL".
I wonder if you could simply use ->curr_properties & PROP_rtl? (and set that
property during parsing, of course)
> * gimple-expr.c (gimple_has_body_p): Return false for __RTL
> functions.
> * pass_manager.h (gcc::pass_manager::get_rest_of_compilation): New
> accessor.
> (gcc::pass_manager::get_clean_slate): New accessor.
> * passes.c: Include "insn-addr.h".
> (execute_one_pass): Implement skipping of passes for functions
> with pass_startwith set.
> * read-md.c (md_reader::read_char): Support filtering
> the input to a subset of line numbers.
> (md_reader::md_reader): Initialize fields
> m_first_line and m_last_line.
> (md_reader::read_file_fragment): New function.
> * read-md.h (md_reader::read_file_fragment): New decl.
> (md_reader::m_first_line): New field.
> (md_reader::int m_last_line): New field.
> * read-rtl-function.c (function_reader::create_function): Only create
> cfun if it doesn't already exist. Set "native_RTL" on cfun. Set
> DECL_INITIAL.
> (read_rtl_function_body_from_file_range): New function.
> * read-rtl-function.h (read_rtl_function_body_from_file_range):
> New decl.
> * run-rtl-passes.c: New file.
> * run-rtl-passes.h: New file.
>
> gcc/testsuite/ChangeLog:
> * gcc.dg/rtl/aarch64/asr_div1.c: New file.
> * gcc.dg/rtl/aarch64/pr71779.c: New file.
> * gcc.dg/rtl/rtl.exp: New file.
> * gcc.dg/rtl/test.c: New file.
> * gcc.dg/rtl/unknown-rtx-code.c: New file.
> * gcc.dg/rtl/x86_64/dfinit.c: New file.
> * gcc.dg/rtl/x86_64/different-structs.c: New file.
> * gcc.dg/rtl/x86_64/final.c: New file.
> * gcc.dg/rtl/x86_64/into-cfglayout.c: New file.
> * gcc.dg/rtl/x86_64/ira.c: New file.
> * gcc.dg/rtl/x86_64/pro_and_epilogue.c: New file.
> * gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c: New file.
> * gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c: New file.
> * gcc.dg/rtl/x86_64/test-rtl.c: New file.
> * gcc.dg/rtl/x86_64/test_1.h: New file.
> * gcc.dg/rtl/x86_64/times-two.c.after-expand.c: New file.
> * gcc.dg/rtl/x86_64/times-two.c.before-df.c: New file.
> * gcc.dg/rtl/x86_64/vregs.c: New file.
> ---
> gcc/Makefile.in | 1 +
> gcc/c-family/c-common.c | 1 +
> gcc/c-family/c-common.h | 3 +
> gcc/c/c-parser.c | 122 ++++++++++++++++++-
> gcc/cfg.c | 1 -
> gcc/cgraph.h | 4 +
> gcc/cgraphunit.c | 41 ++++++-
> gcc/emit-rtl.c | 3 +-
> gcc/final.c | 3 +-
> gcc/function.h | 9 ++
> gcc/gimple-expr.c | 2 +-
> gcc/pass_manager.h | 6 +
> gcc/passes.c | 47 ++++++++
> gcc/read-md.c | 35 +++++-
> gcc/read-md.h | 7 ++
> gcc/read-rtl-function.c | 83 ++++++++++---
> gcc/read-rtl-function.h | 3 +
> gcc/run-rtl-passes.c | 85 +++++++++++++
> gcc/run-rtl-passes.h | 25 ++++
> gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c | 41 +++++++
> gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c | 50 ++++++++
> gcc/testsuite/gcc.dg/rtl/rtl.exp | 41 +++++++
> gcc/testsuite/gcc.dg/rtl/test.c | 31 +++++
> gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c | 8 ++
> gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c | 116 ++++++++++++++++++
> .../gcc.dg/rtl/x86_64/different-structs.c | 81 +++++++++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/final.c | 133 +++++++++++++++++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c | 117 ++++++++++++++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/ira.c | 111 +++++++++++++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c | 110 +++++++++++++++++
> .../rtl/x86_64/test-return-const.c.after-expand.c | 39 ++++++
> .../rtl/x86_64/test-return-const.c.before-fwprop.c | 42 +++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c | 101 ++++++++++++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h | 16 +++
> .../gcc.dg/rtl/x86_64/times-two.c.after-expand.c | 70 +++++++++++
> .../gcc.dg/rtl/x86_64/times-two.c.before-df.c | 54 +++++++++
> gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c | 112 +++++++++++++++++
> 37 files changed, 1727 insertions(+), 27 deletions(-)
> create mode 100644 gcc/run-rtl-passes.c
> create mode 100644 gcc/run-rtl-passes.h
> create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/rtl.exp
> create mode 100644 gcc/testsuite/gcc.dg/rtl/test.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/final.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
> create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 73d12dc..14ffb96 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1429,6 +1429,7 @@ OBJS = \
> rtlhash.o \
> rtlanal.o \
> rtlhooks.o \
> + run-rtl-passes.o \
> sbitmap.o \
> sched-deps.o \
> sched-ebb.o \
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 307862b..573ca7a 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -435,6 +435,7 @@ const struct c_common_resword c_common_reswords[] =
> { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
> { "__volatile", RID_VOLATILE, 0 },
> { "__volatile__", RID_VOLATILE, 0 },
> + { "__RTL", RID_RTL, 0 },
> { "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN },
> { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN },
> { "asm", RID_ASM, D_ASM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 547bab2..5e6882e 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -118,6 +118,9 @@ enum rid
>
> RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
>
> + /* "__RTL", for the RTL-parsing extension to the C frontend. */
> + RID_RTL,
> +
> /* C11 */
> RID_ALIGNAS, RID_GENERIC,
>
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 6bc42da..e6e86ec 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -59,6 +59,8 @@ along with GCC; see the file COPYING3. If not see
> #include "gimple-expr.h"
> #include "context.h"
> #include "gcc-rich-location.h"
> +#include "read-rtl-function.h"
> +#include "run-rtl-passes.h"
>
> /* We need to walk over decls with incomplete struct/union/enum types
> after parsing the whole translation unit.
> @@ -1421,6 +1423,9 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
> static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
> static void c_parser_cilk_grainsize (c_parser *, bool *);
>
> +static void c_parser_parse_rtl_body (c_parser *parser,
> + const char *start_with_pass);
> +
> /* Parse a translation unit (C90 6.7, C99 6.9).
>
> translation-unit:
> @@ -1624,6 +1629,16 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
> declaration-specifiers declarator declaration-list[opt]
> compound-statement
>
> + function-definition:
> + declaration-specifiers rtl-body-specifier declarator declaration-list[opt]
> + compound-statement
> +
> + rtl-body-specifier:
> + __RTL rtl-body-pass-specifier[opt]
> +
> + rtl-body-pass-specifier:
> + ( string )
> +
> attribute ;
>
> Objective-C:
> @@ -1668,6 +1683,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
> tree all_prefix_attrs;
> bool diagnosed_no_specs = false;
> location_t here = c_parser_peek_token (parser)->location;
> + bool rtl_body_p = false;
> + const char *start_with_pass = NULL;
>
> if (static_assert_ok
> && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
> @@ -1752,6 +1769,33 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
> c_parser_skip_to_end_of_block_or_statement (parser);
> return;
> }
> +
> + /* Handle GNU extension rtl-body-specifier by detecting "__RTL". */
> + if (c_parser_next_token_is_keyword (parser, RID_RTL))
> + {
> + rtl_body_p = true;
> + c_parser_consume_token (parser);
> +
> + /* Handle the optional rtl-body-pass-specifier: parens wrapping
> + a string, giving a pass name. */
> + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
> + {
> + c_parser_consume_token (parser);
> + c_token *tok = c_parser_peek_token (parser);
> + if (tok->type != CPP_STRING)
> + {
> + c_parser_error (parser, "expected string");
> + c_parser_skip_to_end_of_block_or_statement (parser);
> + return;
> + }
> + gcc_assert (TREE_CODE (tok->value) == STRING_CST);
> + start_with_pass = TREE_STRING_POINTER (tok->value);
> + c_parser_consume_token (parser);
> +
> + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
> + }
> + }
> +
> finish_declspecs (specs);
> bool auto_type_p = specs->typespec_word == cts_auto_type;
> if (c_parser_next_token_is (parser, CPP_SEMICOLON))
> @@ -2146,7 +2190,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
> tv = TV_PARSE_INLINE;
> else
> tv = TV_PARSE_FUNC;
> - timevar_push (tv);
> + auto_timevar at (g_timer, tv);
>
> /* Parse old-style parameter declarations. ??? Attributes are
> not allowed to start declaration specifiers here because of a
> @@ -2173,6 +2217,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
> c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
> DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
> = c_parser_peek_token (parser)->location;
> +
> + /* If we had an rtl-body-specifier, use the RTL parser now,
> + consuming the function body. */
> + if (rtl_body_p)
> + {
> + c_parser_parse_rtl_body (parser, start_with_pass);
> +
> + /* Normally, store_parm_decls sets next_is_function_body,
> + anticipating a function body. We need a push_scope/pop_scope
> + pair to flush out this state, or subsequent function parsing
> + will go wrong. */
> + push_scope ();
> + pop_scope ();
> +
> + finish_function ();
> + return;
> + }
> +
> fnbody = c_parser_compound_statement (parser);
> if (flag_cilkplus && contains_array_notation_expr (fnbody))
> fnbody = expand_array_notation_exprs (fnbody);
> @@ -2195,7 +2257,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
> finish_function ();
> }
>
> - timevar_pop (tv);
> break;
> }
> }
> @@ -18313,4 +18374,61 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
> return value_tree;
> }
>
> +/* Parse the body of a function declaration marked with "__RTL".
> +
> + The RTL parser works on the level of characters read from a
> + FILE *, whereas c_parser works at the level of tokens.
> + Square this circle by consuming all of the tokens up to and
> + including the closing brace, recording the start/end of the RTL
> + fragment, and reopening the file and re-reading the relevant
> + lines within the RTL parser.
> +
> + This requires the opening and closing braces of the C function
> + to be on separate lines from the RTL they wrap. */
> +
> +void
> +c_parser_parse_rtl_body (c_parser *parser, const char *start_with_pass)
> +{
> + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
> + return;
> +
> + location_t start_loc = c_parser_peek_token (parser)->location;
> +
> + /* Consume all tokens, up to the closing brace, handling
> + matching pairs of braces in the rtl dump. */
> + int num_open_braces = 1;
> + while (1)
> + {
> + switch (c_parser_peek_token (parser)->type)
> + {
> + case CPP_OPEN_BRACE:
> + num_open_braces++;
> + break;
> + case CPP_CLOSE_BRACE:
> + if (--num_open_braces == 0)
> + goto found_closing_brace;
> + break;
> + default:
> + break;
> + }
> + c_parser_consume_token (parser);
> + }
> +
> + found_closing_brace:
> + /* At the closing brace; record its location. */
> + location_t end_loc = c_parser_peek_token (parser)->location;
> +
> + /* Consume the closing brace. */
> + c_parser_consume_token (parser);
> +
> + /* Invoke the RTL parser. */
> + if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
> + return;
> +
> + /* If a pass name was provided for START_WITH_PASS, run the backend
> + accordingly now, on the cfun created above. */
> + if (start_with_pass)
> + run_rtl_passes (start_with_pass);
> +}
> +
> #include "gt-c-c-parser.h"
> diff --git a/gcc/cfg.c b/gcc/cfg.c
> index 6604b02..26a68c1 100644
> --- a/gcc/cfg.c
> +++ b/gcc/cfg.c
> @@ -1083,7 +1083,6 @@ reset_original_copy_tables (void)
> void
> free_original_copy_tables (void)
> {
> - gcc_assert (original_copy_bb_pool);
> delete bb_copy;
> bb_copy = NULL;
> delete bb_original;
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index cc730d2..79e33da 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -328,6 +328,10 @@ public:
> configury. This function is used just during symbol creation. */
> bool needed_p (void);
>
> + /* Return true if this symbol is a function from the C frontend specified
> + directly in RTL form (with "__RTL"). */
> + bool native_rtl_p () const;
> +
> /* Return true when there are references to the node. */
> bool referred_to_p (bool include_self = true);
>
> diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
> index e315a77..956562e 100644
> --- a/gcc/cgraphunit.c
> +++ b/gcc/cgraphunit.c
> @@ -217,6 +217,19 @@ static void handle_alias_pairs (void);
> /* Used for vtable lookup in thunk adjusting. */
> static GTY (()) tree vtable_entry_type;
>
> +/* Return true if this symbol is a function from the C frontend specified
> + directly in RTL form (with "__RTL"). */
> +
> +bool
> +symtab_node::native_rtl_p () const
> +{
> + if (TREE_CODE (decl) != FUNCTION_DECL)
> + return false;
> + if (!DECL_STRUCT_FUNCTION (decl))
> + return false;
> + return DECL_STRUCT_FUNCTION (decl)->native_RTL;
> +}
> +
> /* Determine if symbol declaration is needed. That is, visible to something
> either outside this translation unit, something magic in the system
> configury */
> @@ -225,8 +238,10 @@ symtab_node::needed_p (void)
> {
> /* Double check that no one output the function into assembly file
> early. */
> - gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)
> - || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
> + if (!native_rtl_p ())
> + gcc_checking_assert
> + (!DECL_ASSEMBLER_NAME_SET_P (decl)
> + || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
>
> if (!definition)
> return false;
> @@ -435,6 +450,14 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
> && !DECL_DISREGARD_INLINE_LIMITS (decl))
> node->force_output = 1;
>
> + /* __RTL functions were already output as soon as they were parsed (due
> + to the large amount of global state in the backend).
> + Mark such functions as "force_output" to reflect the fact that they
> + will be in the asm file when considering the symbols they reference.
> + The attempt to output them later on will bail out immediately. */
> + if (node->native_rtl_p ())
> + node->force_output = 1;
> +
> /* When not optimizing, also output the static functions. (see
> PR24561), but don't do so for always_inline functions, functions
> declared inline and nested functions. These were optimized out
> @@ -568,6 +591,12 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
> void
> cgraph_node::analyze (void)
> {
> + if (native_rtl_p ())
> + {
> + analyzed = true;
> + return;
> + }
> +
> tree decl = this->decl;
> location_t saved_loc = input_location;
> input_location = DECL_SOURCE_LOCATION (decl);
> @@ -1226,7 +1255,8 @@ analyze_functions (bool first_time)
>
> gcc_assert (!cnode->definition || cnode->thunk.thunk_p
> || cnode->alias
> - || gimple_has_body_p (decl));
> + || gimple_has_body_p (decl)
> + || cnode->native_rtl_p ());
> gcc_assert (cnode->analyzed == cnode->definition);
> }
> node->aux = NULL;
> @@ -1965,6 +1995,11 @@ cgraph_node::expand (void)
> /* We ought to not compile any inline clones. */
> gcc_assert (!global.inlined_to);
>
> + /* __RTL functions are compiled as soon as they are parsed, so don't
> + do it again. */
> + if (native_rtl_p ())
> + return;
> +
> announce_function (decl);
> process = 0;
> gcc_assert (lowered);
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index 179a91f..8039742 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -2672,7 +2672,8 @@ unshare_all_rtl_again (rtx_insn *insn)
> }
>
> /* Make sure that virtual stack slots are not shared. */
> - set_used_decls (DECL_INITIAL (cfun->decl));
> + if (DECL_INITIAL (cfun->decl))
> + set_used_decls (DECL_INITIAL (cfun->decl));
>
> /* Make sure that virtual parameters are not shared. */
> for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = DECL_CHAIN (decl))
> diff --git a/gcc/final.c b/gcc/final.c
> index 5709d0e..97e2e1a 100644
> --- a/gcc/final.c
> +++ b/gcc/final.c
> @@ -4701,7 +4701,8 @@ rest_of_clean_state (void)
>
> free_bb_for_insn ();
>
> - delete_tree_ssa (cfun);
> + if (!cfun->native_RTL)
> + delete_tree_ssa (cfun);
>
> /* We can reduce stack alignment on call site only when we are sure that
> the function body just produced will be actually used in the final
> diff --git a/gcc/function.h b/gcc/function.h
> index 9fe479c..2263f30 100644
> --- a/gcc/function.h
> +++ b/gcc/function.h
> @@ -236,6 +236,9 @@ struct GTY(()) function {
> /* The loops in this function. */
> struct loops *x_current_loops;
>
> + /* Filled by the GIMPLE FE, pass to start compilation with. */
> + const char *pass_startwith;
> +
> /* The stack usage of this function. */
> struct stack_usage *su;
>
> @@ -384,6 +387,12 @@ struct GTY(()) function {
>
> /* Set when the tail call has been identified. */
> unsigned int tail_call_marked : 1;
> +
> + /* Nonzero if the the current function was specified in RTL form using the
> + C frontend's "__RTL" syntax. This initializes global RTL state, and so
> + such functions must be compiled immediately, rather than under the
> + control of the callgraph. */
> + unsigned int native_RTL : 1;
> };
>
> /* Add the decl D to the local_decls list of FUN. */
> diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
> index de5cce1..3a06888 100644
> --- a/gcc/gimple-expr.c
> +++ b/gcc/gimple-expr.c
> @@ -323,7 +323,7 @@ bool
> gimple_has_body_p (tree fndecl)
> {
> struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
> - return (gimple_body (fndecl) || (fn && fn->cfg));
> + return (gimple_body (fndecl) || (fn && fn->cfg && !fn->native_RTL));
> }
>
> /* Return a printable name for symbol DECL. */
> diff --git a/gcc/pass_manager.h b/gcc/pass_manager.h
> index 464e25f..7278d97 100644
> --- a/gcc/pass_manager.h
> +++ b/gcc/pass_manager.h
> @@ -82,6 +82,12 @@ public:
>
> opt_pass *get_pass_by_name (const char *name);
>
> + opt_pass *get_rest_of_compilation () const
> + {
> + return pass_rest_of_compilation_1;
> + }
> + opt_pass *get_clean_slate () const { return pass_clean_state_1; }
> +
> public:
> /* The root of the compilation pass tree, once constructed. */
> opt_pass *all_passes;
> diff --git a/gcc/passes.c b/gcc/passes.c
> index e78f9ed..54029f5 100644
> --- a/gcc/passes.c
> +++ b/gcc/passes.c
> @@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see
> #include "cfgrtl.h"
> #include "tree-ssa-live.h" /* For remove_unused_locals. */
> #include "tree-cfgcleanup.h"
> +#include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC. */
>
> using namespace gcc;
>
> @@ -2313,6 +2314,52 @@ execute_one_pass (opt_pass *pass)
> return false;
> }
>
> + /* For skipping passes until startwith pass */
> + if (cfun
> + && cfun->pass_startwith)
> + {
> + if (strcmp (pass->name, cfun->pass_startwith) == 0)
> + {
> + if (!quiet_flag)
> + fprintf (stderr, "found starting pass: %s\n", cfun->pass_startwith);
> + cfun->pass_startwith = NULL;
> + }
> + else
> + {
> + /* Don't skip df init; later passes need it. */
> + if (strstr (pass->name, "dfinit") == NULL)
> + {
> + if (!quiet_flag)
> + fprintf (stderr, "skipping pass: %s\n", pass->name);
> +
> + /* Pass "reload" sets the global "reload_completed", and many
> + things depend on this (e.g. instructions in .md files). */
> + if (strcmp (pass->name, "reload") == 0)
> + reload_completed = 1;
> +
> + /* The INSN_ADDRESSES vec is normally set up by
> + shorten_branches; set it up for the benefit of passes that
> + run after this. */
> + if (strcmp (pass->name, "shorten") == 0)
> + INSN_ADDRESSES_ALLOC (get_max_uid ());
> +
> + /* Update the cfg hooks as appropriate. */
> + if (strcmp (pass->name, "into_cfglayout") == 0)
> + {
> + cfg_layout_rtl_register_cfg_hooks ();
> + cfun->curr_properties |= PROP_cfglayout;
> + }
> + if (strcmp (pass->name, "outof_cfglayout") == 0)
> + {
> + rtl_register_cfg_hooks ();
> + cfun->curr_properties &= ~PROP_cfglayout;
> + }
> +
> + return true;
> + }
> + }
> + }
> +
> /* Pass execution event trigger: useful to identify passes being
> executed. */
> invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
> diff --git a/gcc/read-md.c b/gcc/read-md.c
> index a8462a6..25bc3c4 100644
> --- a/gcc/read-md.c
> +++ b/gcc/read-md.c
> @@ -399,6 +399,16 @@ md_reader::read_char (void)
> else
> m_read_md_colno++;
>
> + /* If we're filtering lines, treat everything before the range of
> + interest as a space, and as EOF for everything after. */
> + if (m_first_line && m_last_line)
> + {
> + if (m_read_md_lineno < m_first_line)
> + return ' ';
> + if (m_read_md_lineno > m_last_line)
> + return EOF;
> + }
> +
> return ch;
> }
>
> @@ -981,7 +991,9 @@ md_reader::md_reader (bool compact)
> m_read_md_lineno (0),
> m_read_md_colno (0),
> m_first_dir_md_include (NULL),
> - m_last_dir_md_include_ptr (&m_first_dir_md_include)
> + m_last_dir_md_include_ptr (&m_first_dir_md_include),
> + m_first_line (0),
> + m_last_line (0)
> {
> /* Set the global singleton pointer. */
> md_reader_ptr = this;
> @@ -1284,6 +1296,27 @@ md_reader::read_md_files (int argc, const char **argv,
> return !have_error;
> }
>
> +
> +/* Read FILENAME, filtering to just the given lines. */
> +
> +bool
> +md_reader::read_file_fragment (const char *filename,
> + int first_line,
> + int last_line)
> +{
> + m_read_md_filename = filename;
> + m_read_md_file = fopen (m_read_md_filename, "r");
> + if (m_read_md_file == 0)
> + {
> + perror (m_read_md_filename);
> + return false;
> + }
> + m_first_line = first_line;
> + m_last_line = last_line;
> + handle_toplevel_file ();
> + return !have_error;
> +}
> +
> /* class noop_reader : public md_reader */
>
> /* A dummy implementation which skips unknown directives. */
> diff --git a/gcc/read-md.h b/gcc/read-md.h
> index 1be0f5a..06be3ec 100644
> --- a/gcc/read-md.h
> +++ b/gcc/read-md.h
> @@ -98,6 +98,9 @@ class md_reader
> virtual ~md_reader ();
>
> bool read_md_files (int, const char **, bool (*) (const char *));
> + bool read_file_fragment (const char *filename,
> + int first_line,
> + int last_line);
>
> /* A hook that handles a single .md-file directive, up to but not
> including the closing ')'. It takes two arguments: the file position
> @@ -232,6 +235,10 @@ class md_reader
>
> /* A table of enum_type structures, hashed by name. */
> htab_t m_enum_types;
> +
> + /* If non-zero, filter the input to just this subset of lines. */
> + int m_first_line;
> + int m_last_line;
> };
>
> /* Global singleton; constrast with rtx_reader_ptr below. */
> diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
> index ff6c808..6c4b282 100644
> --- a/gcc/read-rtl-function.c
> +++ b/gcc/read-rtl-function.c
> @@ -489,23 +489,38 @@ function_reader::create_function ()
> else
> rtl_register_cfg_hooks ();
>
> - /* Create cfun. */
> - tree fn_name = get_identifier (m_name ? m_name : "test_1");
> - tree int_type = integer_type_node;
> - tree return_type = int_type;
> - tree arg_types[3] = {int_type, int_type, int_type};
> - tree fn_type = build_function_type_array (return_type, 3, arg_types);
> - tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
> - fn_type);
> - tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
> - return_type);
> - DECL_ARTIFICIAL (resdecl) = 1;
> - DECL_IGNORED_P (resdecl) = 1;
> - DECL_RESULT (fndecl) = resdecl;
> - allocate_struct_function (fndecl, false);
> - /* This sets cfun. */
> -
> - current_function_decl = fndecl;
> + /* When run from selftests or "rtl1", cfun is NULL.
> + When run from "cc1" for a C function tagged with __RTL, cfun is the
> + tagged function. */
> + if (!cfun)
> + {
> + tree fn_name = get_identifier (m_name ? m_name : "test_1");
> + tree int_type = integer_type_node;
> + tree return_type = int_type;
> + tree arg_types[3] = {int_type, int_type, int_type};
> + tree fn_type = build_function_type_array (return_type, 3, arg_types);
> + tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
> + fn_type);
> + tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
> + return_type);
> + DECL_ARTIFICIAL (resdecl) = 1;
> + DECL_IGNORED_P (resdecl) = 1;
> + DECL_RESULT (fndecl) = resdecl;
> + allocate_struct_function (fndecl, false);
> + /* This sets cfun. */
> + current_function_decl = fndecl;
> + }
> +
> + gcc_assert (cfun);
> + gcc_assert (current_function_decl);
> + tree fndecl = current_function_decl;
> +
> + /* Mark this function as being specified as __RTL. */
> + cfun->native_RTL = 1;
> +
> + /* cc1 normally inits DECL_INITIAL (fndecl) to be error_mark_node.
> + Ensure it is NULL_TREE. */
> + DECL_INITIAL (fndecl) = NULL_TREE;
>
> cfun->curr_properties = (PROP_cfg | PROP_rtl);
>
> @@ -1615,6 +1630,40 @@ read_rtl_function_body (int argc, const char **argv,
> return true;
> }
>
> +/* Run the RTL dump parser on the range of lines between START_LOC and
> + END_LOC (including those lines). */
> +
> +bool
> +read_rtl_function_body_from_file_range (location_t start_loc,
> + location_t end_loc)
> +{
> + expanded_location exploc_start = expand_location (start_loc);
> + expanded_location exploc_end = expand_location (end_loc);
> +
> + if (exploc_start.file != exploc_end.file)
> + {
> + error_at (end_loc, "start/end of RTL fragment are in different files");
> + return false;
> + }
> + if (exploc_start.line >= exploc_end.line)
> + {
> + error_at (end_loc,
> + "start of RTL fragment must be on an earlier line than end");
> + return false;
> + }
> +
> + initialize_rtl ();
> + init_emit ();
> + init_varasm_status ();
> +
> + function_reader reader (NULL);
> + if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
> + exploc_end.line - 1))
> + return false;
> +
> + return true;
> +}
> +
> #if CHECKING_P
>
> namespace selftest {
> diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
> index 036fcce..d5d12ab 100644
> --- a/gcc/read-rtl-function.h
> +++ b/gcc/read-rtl-function.h
> @@ -33,4 +33,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
> bool (*parse_opt) (const char *),
> function_reader_policy *policy);
>
> +extern bool read_rtl_function_body_from_file_range (location_t start_loc,
> + location_t end_loc);
> +
> #endif /* GCC_READ_RTL_FUNCTION_H */
> diff --git a/gcc/run-rtl-passes.c b/gcc/run-rtl-passes.c
> new file mode 100644
> index 0000000..2bca929
> --- /dev/null
> +++ b/gcc/run-rtl-passes.c
> @@ -0,0 +1,85 @@
> +/* run-rtl-passes.c - Run just one RTL pass
> + Copyright (C) 2016 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "target.h"
> +#include "tree.h"
> +#include "gimple-expr.h"
> +#include "diagnostic.h"
> +#include "opts.h"
> +#include "fold-const.h"
> +#include "gimplify.h"
> +#include "stor-layout.h"
> +#include "debug.h"
> +#include "convert.h"
> +#include "langhooks.h"
> +#include "langhooks-def.h"
> +#include "common/common-target.h"
> +#include "read-md.h"
> +#include <mpfr.h>
> +#include "rtl.h"
> +#include "cfghooks.h"
> +#include "stringpool.h"
> +#include "function.h"
> +#include "tree-cfg.h"
> +#include "cfg.h"
> +#include "basic-block.h"
> +#include "cfgrtl.h"
> +#include "memmodel.h"
> +#include "emit-rtl.h"
> +#include "cgraph.h"
> +#include "tree-pass.h"
> +#include "context.h"
> +#include "pass_manager.h"
> +#include "bitmap.h"
> +#include "df.h"
> +#include "regs.h"
> +#include "insn-attr-common.h" /* for INSN_SCHEDULING. */
> +#include "insn-attr.h" /* for init_sched_attrs. */
> +#include "run-rtl-passes.h"
> +
> +/* Run the backend passes, starting at the given pass. */
> +
> +void
> +run_rtl_passes (const char *initial_pass_name)
> +{
> + cfun->pass_startwith = initial_pass_name;
> + max_regno = max_reg_num ();
> +
> + /* Pass "expand" noemally sets this up. */
> +#ifdef INSN_SCHEDULING
> + init_sched_attrs ();
> +#endif
> +
> + bitmap_obstack_initialize (NULL);
> + bitmap_obstack_initialize (®_obstack);
> +
> + opt_pass *rest_of_compilation
> + = g->get_passes ()->get_rest_of_compilation ();
> + gcc_assert (rest_of_compilation);
> + execute_pass_list (cfun, rest_of_compilation);
> +
> + opt_pass *clean_slate = g->get_passes ()->get_clean_slate ();
> + gcc_assert (clean_slate);
> + execute_pass_list (cfun, clean_slate);
> +
> + bitmap_obstack_release (®_obstack);
> +}
> diff --git a/gcc/run-rtl-passes.h b/gcc/run-rtl-passes.h
> new file mode 100644
> index 0000000..14ea8ea
> --- /dev/null
> +++ b/gcc/run-rtl-passes.h
> @@ -0,0 +1,25 @@
> +/* run-rtl-passes.h - Run a subset of the RTL passes
> + Copyright (C) 2016 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +
> +#ifndef GCC_RUN_RTL_PASSES_H
> +#define GCC_RUN_RTL_PASSES_H
> +
> +extern void run_rtl_passes (const char *initial_pass_name);
> +
> +#endif /* GCC_RUN_RTL_PASSES_H */
> diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
> new file mode 100644
> index 0000000..9123651
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile { target aarch64-*-* } } */
> +/* { dg-options "-mtune=cortex-a53 -fdump-rtl-combine -O2" } */
> +
> +/* Taken from
> + gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
> + for aarch64, hand editing to the new format. */
> +
> +int __RTL("combine") f1 (int n)
> +{
> +(function "f1"
> + (param "n"
> + (DECL_RTL (reg/v:SI %1 [ n ]))
> + (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
> + ) ;; param "n"
> + (insn-chain
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 8 (set (reg:DI %2)
> + (lshiftrt:DI (reg:DI %0)
> + (const_int 32)))
> + "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
> + (expr_list:REG_DEAD (reg:DI %0)))
> + (cinsn 9 (set (reg:SI %1)
> + (ashiftrt:SI (subreg:SI (reg:DI %2) 0)
> + (const_int 3)))
> + "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
> + (expr_list:REG_DEAD (reg:DI %2)))
> +
> + ;; Extra insn, to avoid all of the above from being deleted by DCE
> + (insn 10 (use (reg/i:SI %1)))
> +
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> +) ;; function
> +}
> +
> +/* Verify that insns 8 and 9 get combined into a shift of 35 (0x23) */
> +/* { dg-final { scan-rtl-dump "allowing combination of insns 8 and 9" "combine" } } */
> +/* { dg-final { scan-rtl-dump "modifying insn i3 9: r\[0-9\]+:SI#0=r\[0-9\]+:DI>>0x23" "combine" } } */
> diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
> new file mode 100644
> index 0000000..d318339
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
> @@ -0,0 +1,50 @@
> +/* { dg-do compile { target aarch64-*-* } } */
> +/* { dg-options "-fdump-rtl-cse1" } */
> +
> +/* Dump taken from comment 2 of PR 71779, of
> + "...the relevant memory access coming out of expand"
> + hand-edited to the compact dump format. */
> +
> +int __RTL("cse1") test (int n)
> +{
> +(function "fragment"
> + (param "n"
> + (DECL_RTL (reg/v:SI %1 [ n ]))
> + (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
> + ) ;; param "n"
> + (insn-chain
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +
> +;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
> +(insn 1045 (set (reg:SI %480)
> + (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
> + [flags 0xc0]
> + <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> + y.c:12702)
> +(insn 1046 (set (reg/f:SI %479)
> + (lo_sum:SI (reg:SI %480)
> + (symbol_ref:SI ("isl_obj_map_vtable")
> + [flags 0xc0]
> + <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> + y.c:12702
> + (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
> + [flags 0xc0]
> + <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
> +(insn 1047 (set (reg:DI %481)
> + (subreg:DI (reg/f:SI %479) 0)) y.c:12702)
> +(insn 1048 (set (zero_extract:DI (reg/v:DI %191 [ obj1D.17368 ])
> + (const_int 32)
> + (const_int 0))
> + (reg:DI %481)) y.c:12702)
> +;; Extra insn, to avoid all of the above from being deleted by DCE
> +(insn 1049 (set (mem:DI (reg:DI %191) [1 i+0 S4 A32])
> + (const_int 1)))
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> +) ;; function
> +}
> +
> +/* TODO: scan the dump. */
> diff --git a/gcc/testsuite/gcc.dg/rtl/rtl.exp b/gcc/testsuite/gcc.dg/rtl/rtl.exp
> new file mode 100644
> index 0000000..3c6648b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/rtl.exp
> @@ -0,0 +1,41 @@
> +# Copyright (C) 2016 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3. If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# GCC testsuite that uses the `dg.exp' driver.
> +
> +# Load support procs.
> +load_lib gcc-dg.exp
> +
> +# If a testcase doesn't have special options, use these.
> +global DEFAULT_RTLFLAGS
> +if ![info exists DEFAULT_RTLFLAGS] then {
> + set DEFAULT_RTLFLAGS ""
> + # -fdump-tree-rtl-raw
> +}
> +
> +# Initialize `dg'.
> +dg-init
> +
> +# Gather a list of all tests.
> +set tests [lsort [find $srcdir/$subdir *.c]]
> +
> +verbose "rtl.exp tests: $tests" 1
> +
> +# Main loop.
> +dg-runtest $tests "" $DEFAULT_RTLFLAGS
> +
> +# All done.
> +dg-finish
> diff --git a/gcc/testsuite/gcc.dg/rtl/test.c b/gcc/testsuite/gcc.dg/rtl/test.c
> new file mode 100644
> index 0000000..ebb8aef
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/test.c
> @@ -0,0 +1,31 @@
> +int test_1 (int i, int j, int k)
> +{
> + if (i < j)
> + return k + 4;
> + else
> + return -k;
> +}
> +
> +/* Example showing:
> + - data structure
> + - loop
> + - call to "abort". */
> +
> +struct foo
> +{
> + int count;
> + float *data;
> +};
> +
> +float test_2 (struct foo *lhs, struct foo *rhs)
> +{
> + float result = 0.0f;
> +
> + if (lhs->count != rhs->count)
> + __builtin_abort ();
> +
> + for (int i = 0; i < lhs->count; i++)
> + result += lhs->data[i] * rhs->data[i];
> +
> + return result;
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
> new file mode 100644
> index 0000000..dd252f1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
> @@ -0,0 +1,8 @@
> +void __RTL test (void)
> +{
> + (function "test"
> + (insn-chain
> + (not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
> + ) ;; insn-chain
> + ) ;; function
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
> new file mode 100644
> index 0000000..f7b3e77
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
> @@ -0,0 +1,116 @@
> +/* { dg-do run { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-dfinit" } */
> +
> +#include "test_1.h"
> +
> +/* Lightly-modified dump of test.c.261r.split1 for x86_64. */
> +
> +int __RTL("no-opt dfinit") test_1 (int i, int j, int k)
> +{
> +(function "test_1"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ])))
> + (param "j"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI si [ j ])))
> + (param "k"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI dx [ k ])))
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 3 (flags "FALLTHRU"))
> + (edge-to 4)
> + ) ;; block 2
> + (block 3
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI %3)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (plus:SI (reg:SI %3)
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 29 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 5)
> + ) ;; block 3
> + (cbarrier 30)
> + (block 4
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI %4)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (neg:SI (reg:SI %4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 5 (flags "FALLTHRU"))
> + ) ;; block 4
> + (block 5
> + (edge-from 4 (flags "FALLTHRU"))
> + (edge-from 3)
> + (clabel 20 3)
> + (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 22 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _1 ])))
> + (cinsn 26 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 5
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> +
> +/* Verify that the dataflow information matches what cc1 would normally
> + have generated. In particular, in earlier versions of the RTL
> + frontend, the exit block use of reg 0 (ax) wasn't picked up
> + on, due to not setting up crtl->return_rtx based on
> + DECL_RESULT (fndecl). */
> +/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
> +/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
> new file mode 100644
> index 0000000..8db1161
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
> @@ -0,0 +1,81 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +
> +extern double sqrt(double x);
> +
> +struct foo
> +{
> + double x;
> + double y;
> +};
> +
> +struct bar
> +{
> + double x;
> + double y;
> +};
> +
> +double __RTL test (struct foo *f, const struct bar *b)
> +{
> +#if 0
> + /* Result of "expand" on this C code, compiled for x86_64 with -Os. */
> + f->x += b->x;
> + f->y += b->y;
> + return sqrt (f->x * f->x + f->y * f->y);
> +#endif
> +(function "test"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 5 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (reg/v/f:DI %10 [ f ])
> + (reg:DI di [ f ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
> + (cinsn 3 (set (reg/v/f:DI %11 [ b ])
> + (reg:DI si [ b ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
> + (cnote 4 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 7 (set (reg:DF %12)
> + (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
> + (cinsn 8 (set (reg:DF %2 [ _3 ])
> + (plus:DF (reg:DF %12)
> + (mem:DF (reg/v/f:DI %11 [ b ]) [2 b_12(D)->x+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
> + (cinsn 9 (set (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])
> + (reg:DF %2 [ _3 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
> + (cinsn 10 (set (reg:DF %13)
> + (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
> + (const_int 8)) [2 f_11(D)->y+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
> + (cinsn 11 (set (reg:DF %5 [ _6 ])
> + (plus:DF (reg:DF %13)
> + (mem:DF (plus:DI (reg/v/f:DI %11 [ b ])
> + (const_int 8)) [2 b_12(D)->y+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
> + (cinsn 12 (set (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
> + (const_int 8)) [2 f_11(D)->y+0 S8 A64])
> + (reg:DF %5 [ _6 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
> + (cinsn 13 (set (reg:DF %14)
> + (mult:DF (reg:DF %2 [ _3 ])
> + (reg:DF %2 [ _3 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
> + (cinsn 14 (set (reg:DF %15)
> + (mult:DF (reg:DF %5 [ _6 ])
> + (reg:DF %5 [ _6 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
> + (cinsn 15 (set (reg:DF %16)
> + (plus:DF (reg:DF %14)
> + (reg:DF %15))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
> + (cinsn 16 (set (reg:DF xmm0)
> + (reg:DF %16)) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
> + (ccall_insn/j 17 (set (reg:DF xmm0)
> + (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>) [0 __builtin_sqrt S1 A8])
> + (const_int 0))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23
> + (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>)
> + (expr_list:REG_EH_REGION (const_int 0)))
> + (expr_list:DF (use (reg:DF xmm0))))
> + (edge-to exit (flags "ABNORMAL | SIBCALL"))
> + ) ;; block 2
> + (cbarrier 18)
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:DF xmm0)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test"
> +
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/final.c b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
> new file mode 100644
> index 0000000..d10deb0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
> @@ -0,0 +1,133 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-final" } */
> +
> +/* Lightly-modified dump of test.c.304r.dwarf2 for x86_64 target,
> + with various NOTE_INSN_CFI deleted by hand for now. */
> +
> +int __RTL("final") test_1 (int i, int j, int k)
> +{
> +(function "test_1"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ])))
> + (param "j"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI si [ j ])))
> + (param "k"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI dx [ k ])))
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn/f 32 (set (mem:DI (pre_dec:DI (reg/f:DI sp)) [0 S8 A8])
> + (reg/f:DI bp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn/f 33 (set (reg/f:DI bp)
> + (reg/f:DI sp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 34 (set (mem/v:BLK (0|scratch:DI) [0 A8])
> + (unspec:BLK [
> + (mem/v:BLK (reuse_rtx 0) [0 A8])
> + ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 35 NOTE_INSN_PROLOGUE_END)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI ax [89])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI ax [89])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 3 (flags "FALLTHRU"))
> + (edge-to 4)
> + ) ;; block 2
> + (block 3
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI ax [90])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI ax [orig:87 _1 ] [87])
> + (plus:SI (reg:SI ax [90])
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 29 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 5)
> + ) ;; block 3
> + (cbarrier 30)
> + (block 4
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI ax [91])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI ax [orig:87 _1 ] [87])
> + (neg:SI (reg:SI ax [91])))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 5 (flags "FALLTHRU"))
> + ) ;; block 4
> + (block 5
> + (edge-from 4 (flags "FALLTHRU"))
> + (edge-from 3)
> + (clabel 20 3)
> + (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cnote 36 NOTE_INSN_EPILOGUE_BEG)
> + (cinsn 37 (set (mem/v:BLK (1|scratch:DI) [0 A8])
> + (unspec:BLK [
> + (mem/v:BLK (reuse_rtx 1) [0 A8])
> + ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cinsn/f 38 (set (reg/f:DI bp)
> + (mem:DI (post_inc:DI (reg/f:DI sp)) [0 S8 A8])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7
> + (expr_list:REG_CFA_DEF_CFA (plus:DI (reg/f:DI sp)
> + (const_int 8))))
> + (cjump_insn 39 (simple_return) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit)
> + ) ;; block 5
> + (cbarrier 40)
> + (cnote 31 NOTE_INSN_DELETED)
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> +
> +/* Verify that asm was emitted. */
> +/* { dg-final { scan-assembler "test_1:" } } */
> +/* { dg-final { scan-assembler ".cfi_startproc" } } */
> +/* { dg-final { scan-assembler ".cfi_endproc" } } */
> +
> +/* Verify that the "simple_return" was recognized.
> + FIXME: this assumes i386.md. */
> +/* { dg-final { scan-assembler "ret" } } */
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
> new file mode 100644
> index 0000000..d080956
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
> @@ -0,0 +1,117 @@
> +/* { dg-do run { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-into_cfglayout" } */
> +
> +/* Lightly-modified dump of test.c.226r.vregs for x86_64. */
> +
> +#include "test_1.h"
> +
> +int __RTL("into_cfglayout") test_1 (int i, int j, int k)
> +{
> +(function "test_1"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ])))
> + (param "j"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI si [ j ])))
> + (param "k"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI dx [ k ])))
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 4 (flags "FALLTHRU"))
> + (edge-to 5)
> + ) ;; block 2
> + (block 4
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI %3)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (plus:SI (reg:SI %3)
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 14 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 6)
> + ) ;; block 4
> + (cbarrier 15)
> + (block 5
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI %4)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (neg:SI (reg:SI %4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 6 (flags "FALLTHRU"))
> + ) ;; block 5
> + (block 6
> + (edge-from 4)
> + (edge-from 5 (flags "FALLTHRU"))
> + (clabel 20 3)
> + (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 22 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _1 ])))
> + (cinsn 26 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 6
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> +
> +/* The conversion to cfglayout should eliminate unconditional jump
> + instructions... */
> +/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } } */
> +/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } } */
> +/* { dg-final { scan-rtl-dump-not "barrier" "into_cfglayout" } } */
> +
> +/* ...but conditional jumps should be preserved. */
> +/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } } */
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
> new file mode 100644
> index 0000000..3f729cd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
> @@ -0,0 +1,111 @@
> +/* { dg-do run { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-ira" } */
> +
> +/* Lightly-modified dump of test.c.265r.asmcons for x86_64. */
> +
> +#include "test_1.h"
> +
> +int __RTL ("ira") test_1 (int i, int j, int k)
> +{
> +(function "test_1"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ])))
> + (param "j"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI si [ j ])))
> + (param "k"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI dx [ k ])))
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 3 (flags "FALLTHRU"))
> + (edge-to 4)
> + ) ;; block 2
> + (block 3
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI %3)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (plus:SI (reg:SI %3)
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 29 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 5)
> + ) ;; block 3
> + (cbarrier 30)
> + (block 4
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI %4)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (neg:SI (reg:SI %4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 5 (flags "FALLTHRU"))
> + ) ;; block 4
> + (block 5
> + (edge-from 4 (flags "FALLTHRU"))
> + (edge-from 3)
> + (clabel 20 3)
> + (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 22 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _1 ])))
> + (cinsn 26 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 5
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> +
> +/* Verify that IRA was run. */
> +/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
> new file mode 100644
> index 0000000..712faf0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
> @@ -0,0 +1,110 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-pro_and_epilogue" } */
> +
> +/* Lightly-modified dump of test.c.274r.split2 for x86_64. */
> +
> +int __RTL("pro_and_epilogue") test_1 (int i, int j, int k)
> +{
> +(function "test_1"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ])))
> + (param "j"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI si [ j ])))
> + (param "k"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI dx [ k ])))
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI ax [89])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI ax [89])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 3 (flags "FALLTHRU"))
> + (edge-to 4)
> + ) ;; block 2
> + (block 3
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI ax [90])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI ax [orig:87 _1 ] [87])
> + (plus:SI (reg:SI ax [90])
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 29 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 5)
> + ) ;; block 3
> + (cbarrier 30)
> + (block 4
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI ax [91])
> + (mem/c:SI (plus:DI (reg/f:DI bp)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI ax [orig:87 _1 ] [87])
> + (neg:SI (reg:SI ax [91])))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 5 (flags "FALLTHRU"))
> + ) ;; block 4
> + (block 5
> + (edge-from 4 (flags "FALLTHRU"))
> + (edge-from 3)
> + (clabel 20 3)
> + (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 5
> + (cnote 31 NOTE_INSN_DELETED)
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> +
> +/* Verify that the prologue and epilogue were added. */
> +/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } } */
> +
> +/* We expect a jump_insn to "simple_return". */
> +/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } } */
> +
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
> new file mode 100644
> index 0000000..bb431ee
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
> @@ -0,0 +1,39 @@
> +/* { dg-do run { target x86_64-*-* } } */
> +
> +extern void abort (void);
> +
> +int __RTL("vregs") test_returning_constant (void)
> +{
> + /* C code:
> + return 42; */
> +(function "test_returning_constant"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cnote 2 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 5 (set (reg:SI %0 [ _1 ])
> + (const_int 42)) "../../src/test-return-const.c":3)
> + (cinsn 8 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
> + (cinsn 12 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
> + (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_returning_constant"
> +}
> +
> +int main (void)
> +{
> + if (test_returning_constant () != 42)
> + abort ();
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
> new file mode 100644
> index 0000000..4ae5418
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
> @@ -0,0 +1,42 @@
> +/* { dg-do run { target x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-fwprop1 -O2" } */
> +
> +extern void abort (void);
> +
> +int __RTL ("fwprop1") test_returning_constant (void)
> +{
> + /* C code:
> + return 42; */
> +(function "test_returning_constant"
> + (insn-chain
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cnote 2 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 5 (set (reg:SI %0 [ <retval> ])
> + (const_int 42)) "../../src/test-return-const.c":3)
> + (cinsn 9 (set (reg/i:SI ax)
> + (const_int 42)) "../../src/test-return-const.c":4
> + (expr_list:REG_DEAD (reg:SI %0 [ <retval> ])))
> + (cinsn 10 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_returning_constant"
> +}
> +
> +/* Verify that insn 5 is eliminated. */
> +/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
> +/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
> +
> +int main (void)
> +{
> + if (test_returning_constant () != 42)
> + abort ();
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
> new file mode 100644
> index 0000000..b4d1e6d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
> @@ -0,0 +1,101 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +
> +/* Test of embedding RTL dump in a C function, tagged with "__RTL".
> +
> + This is a dump of test.c from immediately after "expand", for x86_64. */
> +
> +int __RTL test_1 (int i, int j, int k)
> +{
> + /*
> + if (i < j)
> + return k + 4;
> + else
> + return -k;
> + */
> +(function "test_1"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 4 (flags "FALLTHRU"))
> + (edge-to 5)
> + ) ;; block 2
> + (block 4
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI %3)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (plus:SI (reg:SI %3)
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 14 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 6)
> + ) ;; block 4
> + (cbarrier 15)
> + (block 5
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI %4)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (neg:SI (reg:SI %4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 6 (flags "FALLTHRU"))
> + ) ;; block 5
> + (block 6
> + (edge-from 4)
> + (edge-from 5 (flags "FALLTHRU"))
> + (clabel 20 3)
> + (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 22 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _1 ])))
> + (cinsn 26 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 6
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
> new file mode 100644
> index 0000000..a783ea8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
> @@ -0,0 +1,16 @@
> +/* Shared test code for the various __RTL tests of test_1 that
> + start at different passes. */
> +
> +extern void abort (void);
> +extern int test_1 (int i, int j, int k);
> +
> +int main (void)
> +{
> + if (test_1 (0, 0, 3) != -3)
> + abort ();
> +
> + if (test_1 (0, 1, 3) != 7)
> + abort ();
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
> new file mode 100644
> index 0000000..f6bd45f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
> @@ -0,0 +1,70 @@
> +/* { dg-do run { target i?86-*-* x86_64-*-* } } */
> +
> +extern void abort (void);
> +
> +int __RTL ("vregs") times_two (int i)
> +{
> + /* C function:
> + return i * 2; */
> +(function "times_two"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ]))
> + ) ;; param "i"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/times-two.c":2
> + (nil))
> + (cnote 3 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 6 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
> + (nil))
> + (cinsn 7 (parallel [
> + (set (reg:SI %0 [ _2 ])
> + (ashift:SI (reg:SI %2)
> + (const_int 1)))
> + (clobber (reg:CC flags))
> + ]) "../../src/times-two.c":3
> + (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (const_int 1))
> + (nil)))
> + (cinsn 10 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
> + (nil))
> + (cinsn 14 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
> + (nil))
> + (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
> + (nil))
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "times_two"
> +}
> +
> +int main (void)
> +{
> + if (times_two (0) != 0)
> + abort ();
> +
> + if (times_two (1) != 2)
> + abort ();
> +
> + if (times_two (100) != 200)
> + abort ();
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
> new file mode 100644
> index 0000000..5cb4a71
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
> @@ -0,0 +1,54 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-dfinit" } */
> +
> +int __RTL ("rtl-dfinit") times_two (int i)
> +{
> + /* C function:
> + return i * 2; */
> +(function "times_two"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/times-two.c":2)
> + (cnote 3 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 6 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3)
> + (cinsn 7 (parallel [
> + (set (reg:SI %0 [ _2 ])
> + (ashift:SI (reg:SI %2)
> + (const_int 1)))
> + (clobber (reg:CC flags))
> + ]) "../../src/times-two.c":3
> + (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32])
> + (const_int 1))))
> + (cinsn 10 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _2 ])) "../../src/times-two.c":3)
> + (cinsn 14 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4)
> + (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "times_two"
> +}
> +
> +/* Verify that the dataflow information matches what cc1 would have
> + generated. In particular, in earlier versions of the RTL
> + frontend, the exit block use of reg 0 (ax) wasn't picked up
> + on, due to not setting up crtl->return_rtx based on
> + DECL_RESULT (fndecl). */
> +
> +/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
> +
> +/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
> diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
> new file mode 100644
> index 0000000..24d141f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
> @@ -0,0 +1,112 @@
> +/* { dg-do run { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-vregs" } */
> +
> +/* Lightly-modified dump of test.c.225r.expand for x86_64. */
> +
> +#include "test_1.h"
> +
> +int __RTL("vregs") test_1 (int i, int j, int k)
> +{
> +(function "test_1"
> + (param "i"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -4)) [1 i+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI di [ i ])))
> + (param "j"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -8)) [1 j+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI si [ j ])))
> + (param "k"
> + (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
> + (const_int -12)) [1 k+0 S4 A32]))
> + (DECL_RTL_INCOMING (reg:SI dx [ k ])))
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -8)) [1 j+0 S4 A32])
> + (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])
> + (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
> + (cnote 5 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 8 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cinsn 9 (set (reg:CCGC flags)
> + (compare:CCGC (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (cjump_insn 10 (set (pc)
> + (if_then_else (ge (reg:CCGC flags)
> + (const_int 0))
> + (label_ref 16)
> + (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
> + (edge-to 4 (flags "FALLTHRU"))
> + (edge-to 5)
> + ) ;; block 2
> + (block 4
> + (edge-from 2 (flags "FALLTHRU"))
> + (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 12 (set (reg:SI %3)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (cinsn 13 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (plus:SI (reg:SI %3)
> + (const_int 4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
> + (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])
> + (const_int 4))))
> + (cjump_insn 14 (set (pc)
> + (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
> + (edge-to 6)
> + ) ;; block 4
> + (cbarrier 15)
> + (block 5
> + (edge-from 2)
> + (clabel 16 2)
> + (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 18 (set (reg:SI %4)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
> + (cinsn 19 (parallel [
> + (set (reg:SI %0 [ _1 ])
> + (neg:SI (reg:SI %4)))
> + (clobber (reg:CC flags))
> + ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
> + (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -12)) [1 k+0 S4 A32]))))
> + (edge-to 6 (flags "FALLTHRU"))
> + ) ;; block 5
> + (block 6
> + (edge-from 4)
> + (edge-from 5 (flags "FALLTHRU"))
> + (clabel 20 3)
> + (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 22 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _1 ])))
> + (cinsn 26 (set (reg/i:SI ax)
> + (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 6
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "test_1"
> +}
> +
> +/* The 9 instances of "virtual-stack-vars" should now all be "frame". */
> +/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } } */
> +/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } } */
> --
> 1.8.5.3
>
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 9/9] Add "__RTL" to cc1 (v4)
2016-11-14 15:14 ` Richard Biener
@ 2016-11-15 21:07 ` David Malcolm
2016-11-16 13:24 ` Richard Biener
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-15 21:07 UTC (permalink / raw)
To: Richard Biener; +Cc: GCC Patches
On Mon, 2016-11-14 at 16:14 +0100, Richard Biener wrote:
> On Fri, Nov 11, 2016 at 10:15 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > Changed in this version:
> >
> > * Rather than running just one pass, run *all* passes, but start at
> > the given pass; support for "dg-do run" tests that execute the
> > resulting code.
> > * Updated test cases to new "compact" dump format; more test cases;
> > use "dg-do run" in various places.
> > * Lots of bugfixing
> >
> > Links to previous versions:
> > https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00263.html
> > https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00500.html
> Does running the RTL passes right from the parser work with -fsyntax
> -only?
It depends what you mean by "work". If I run it with -fsyntax-only,
then pass_rest_of_compilation::gate returns false, and none of the RTL
passes are run. Is this behavior correct?
> Doing it like __GIMPLE has the advantage of not exposing
> "rest_of_compilation", etc..
The gimple part of the compiler supports having multiple functions in
memory at once, and then compiling them in arbitrary order based on
decisions made by the callgraph.
By contrast, the RTL part of the compiler is full of singleton state:
things like crtl (aka x_rtl), the state of emit-rtl.c,
"reload_completed", etc etc.
To try to limit the scope of the project, for the RTL frontend work I'm
merely attempting to restore the singleton RTL state from a dump,
rather than to support having per function stashes of RTL state.
Hence the rest of compilation gets invoked directly from the frontend
for the __RTL case, since it will get overwritten if there's a second
__RTL function in the source file (which sounds like an idea for a test
case; I'll attempt such a test case).
I hope this is a reasonable approach. If not, I suppose I can attempt
to bundle it up into some kind of RTL function state, but that seems
like significant scope creep.
> I'm now handling __GIMPLE from within declspecs (the GIMPLE FE stuff
> has been committed), it would be nice to match the __RTL piece here.
(Congratulations on getting the GIMPLE FE stuff in)
I'm not sure I understand you here - do you want me to rewrite the
__RTL parsing to match the __GIMPLE piece, or the other way around?
If the former, presumably I should reuse (and rename)
c_parser_gimple_pass_list?
> > gcc/ChangeLog:
> > * Makefile.in (OBJS): Add run-rtl-passes.o.
> >
> > gcc/c-family/ChangeLog:
> > * c-common.c (c_common_reswords): Add "__RTL".
> > * c-common.h (enum rid): Add RID_RTL.
> >
> > gcc/c/ChangeLog:
> > * c-parser.c: Include "read-rtl-function.h" and
> > "run-rtl-passes.h".
> > (c_parser_declaration_or_fndef): In the "GNU extensions"
> > part of
> > the leading comment, add an alternate production for
> > "function-definition", along with new "rtl-body-specifier"
> > and
> > "rtl-body-pass-specifier" productions. Handle "__RTL" by
> > calling
> > c_parser_parse_rtl_body. Convert a timevar_push/pop pair
> > to an auto_timevar, to cope with early exit.
> > (c_parser_parse_rtl_body): New function.
> >
> > gcc/ChangeLog:
> > * cfg.c (free_original_copy_tables): Remove assertion
> > on original_copy_bb_pool.
>
> How can that trigger?
It happens when running pass_outof_cfg_layout_mode::execute; seen with
gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c.
The input file is a dump taken in cfg_layout mode (although in this
case it's a trivial 3-basic-block CFG, but ideally there would be cases
with non-trivial control flow); it has "fwprop1" as its starting pass.
Running without -quiet shows:
skipping pass: *rest_of_compilation
skipping pass: vregs
skipping pass: into_cfglayout
skipping pass: jump
skipping pass: subreg1
skipping pass: cse1
found starting pass: fwprop1
i.e. it skips the into_cfglayout (amongst others), to start with
fwprop1.
In theory skipping a pass ought to be a no-op, assuming that we're
faithfully reconstructing all RTL state. However, RTL state management
is fiddly, so the patch introduces some logic in passes.c to do some
things when skipping a pass; in particular, it has:
/* Update the cfg hooks as appropriate. */
if (strcmp (pass->name, "into_cfglayout") == 0)
{
cfg_layout_rtl_register_cfg_hooks ();
cfun->curr_properties |= PROP_cfglayout;
}
if (strcmp (pass->name, "outof_cfglayout") == 0)
{
rtl_register_cfg_hooks ();
cfun->curr_properties &= ~PROP_cfglayout;
}
so that even when skipping "into_cfglayout", the CFG hooks are at least
correct.
The assertion fires when running outof_cfglayout later on (rather than
skipping it); the assertion:
gcc_assert (original_copy_bb_pool);
assumes that into_cfglayout was actually run, rather than just the
simple "skipping" version of it.
> > * cgraph.h (symtab_node::native_rtl_p): New decl.
> > * cgraphunit.c (symtab_node::native_rtl_p): New function.
> > (symtab_node::needed_p): Don't assert for early assembly
> > output
> > for __RTL functions.
> > (cgraph_node::finalize_function): Set "force_output" for
> > __RTL
> > functions.
> > (cgraph_node::analyze): Bail out early for __RTL functions.
> > (analyze_functions): Update assertion to support __RTL
> > functions.
> > (cgraph_node::expand): Bail out early for __RTL functions.
> > * emit-rtl.c (unshare_all_rtl_again): Wrap set_used_decls
> > call
> > in check for DECL_INITIAL.
>
> You should simply set DECL_INITIAL of your function decl (make_node
> (BLOCK);).
> There's too much code assuming that is not NULL (and I've fixed quite
> a bit of
> code during stage1 not doing that).
Thanks; fixed.
> > * final.c (rest_of_clean_state): Don't call delete_tree_ssa
> > for
> > _RTL functions.
> > * function.h (struct function): Add field "native_RTL".
>
> I wonder if you could simply use ->curr_properties & PROP_rtl? (and
> set that
> property during parsing, of course)
I tried to doing that; it mostly works, but this assertion fails:
237 symtab_node::needed_p (void)
238 {
239 /* Double check that no one output the function into assembly file
240 early. */
241 if (!native_rtl_p ())
242 gcc_checking_assert
243 (!DECL_ASSEMBLER_NAME_SET_P (decl)
244 || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
[I added the "if (!native_rtl_p ())" guard in the patch]
The issue here is that when this is run, the __RTL function has been
compiled and cleaned up, and the curr_properties & PROP_rtl has been
cleared:
(gdb) p decl->function_decl->f->curr_properties
$7 = 0
I could set the flag again after running the passes; on doing so, the
test suite successfully runs.
Would you prefer I use curr_properties & PROP_rtl for this?
[...snip...]
Thanks
Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 9/9] Add "__RTL" to cc1 (v4)
2016-11-15 21:07 ` David Malcolm
@ 2016-11-16 13:24 ` Richard Biener
2016-11-18 21:02 ` [PATCH] Add "__RTL" to cc1 (v5) David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Richard Biener @ 2016-11-16 13:24 UTC (permalink / raw)
To: David Malcolm, Jan Hubicka; +Cc: GCC Patches
On Tue, Nov 15, 2016 at 10:07 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Mon, 2016-11-14 at 16:14 +0100, Richard Biener wrote:
>> On Fri, Nov 11, 2016 at 10:15 PM, David Malcolm <dmalcolm@redhat.com>
>> wrote:
>> > Changed in this version:
>> >
>> > * Rather than running just one pass, run *all* passes, but start at
>> > the given pass; support for "dg-do run" tests that execute the
>> > resulting code.
>> > * Updated test cases to new "compact" dump format; more test cases;
>> > use "dg-do run" in various places.
>> > * Lots of bugfixing
>> >
>> > Links to previous versions:
>> > https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00263.html
>> > https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00500.html
>
>> Does running the RTL passes right from the parser work with -fsyntax
>> -only?
>
> It depends what you mean by "work". If I run it with -fsyntax-only,
> then pass_rest_of_compilation::gate returns false, and none of the RTL
> passes are run. Is this behavior correct?
Yes.
>> Doing it like __GIMPLE has the advantage of not exposing
>> "rest_of_compilation", etc..
>
> The gimple part of the compiler supports having multiple functions in
> memory at once, and then compiling them in arbitrary order based on
> decisions made by the callgraph.
>
> By contrast, the RTL part of the compiler is full of singleton state:
> things like crtl (aka x_rtl), the state of emit-rtl.c,
> "reload_completed", etc etc.
Ah, of course - I forgot that...
> To try to limit the scope of the project, for the RTL frontend work I'm
> merely attempting to restore the singleton RTL state from a dump,
> rather than to support having per function stashes of RTL state.
>
> Hence the rest of compilation gets invoked directly from the frontend
> for the __RTL case, since it will get overwritten if there's a second
> __RTL function in the source file (which sounds like an idea for a test
> case; I'll attempt such a test case).
>
> I hope this is a reasonable approach. If not, I suppose I can attempt
> to bundle it up into some kind of RTL function state, but that seems
> like significant scope creep.
Yeah, I think it's a good approach for now.
>> I'm now handling __GIMPLE from within declspecs (the GIMPLE FE stuff
>> has been committed), it would be nice to match the __RTL piece here.
>
> (Congratulations on getting the GIMPLE FE stuff in)
>
> I'm not sure I understand you here - do you want me to rewrite the
> __RTL parsing to match the __GIMPLE piece, or the other way around?
> If the former, presumably I should reuse (and rename)
> c_parser_gimple_pass_list?
Handle __RTL like __GIMPLE, thus as declspec. Of course ultimatively
Joseph has the last word here.
>
>> > gcc/ChangeLog:
>> > * Makefile.in (OBJS): Add run-rtl-passes.o.
>> >
>> > gcc/c-family/ChangeLog:
>> > * c-common.c (c_common_reswords): Add "__RTL".
>> > * c-common.h (enum rid): Add RID_RTL.
>> >
>> > gcc/c/ChangeLog:
>> > * c-parser.c: Include "read-rtl-function.h" and
>> > "run-rtl-passes.h".
>> > (c_parser_declaration_or_fndef): In the "GNU extensions"
>> > part of
>> > the leading comment, add an alternate production for
>> > "function-definition", along with new "rtl-body-specifier"
>> > and
>> > "rtl-body-pass-specifier" productions. Handle "__RTL" by
>> > calling
>> > c_parser_parse_rtl_body. Convert a timevar_push/pop pair
>> > to an auto_timevar, to cope with early exit.
>> > (c_parser_parse_rtl_body): New function.
>> >
>> > gcc/ChangeLog:
>> > * cfg.c (free_original_copy_tables): Remove assertion
>> > on original_copy_bb_pool.
>>
>> How can that trigger?
>
> It happens when running pass_outof_cfg_layout_mode::execute; seen with
> gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c.
>
> The input file is a dump taken in cfg_layout mode (although in this
> case it's a trivial 3-basic-block CFG, but ideally there would be cases
> with non-trivial control flow); it has "fwprop1" as its starting pass.
>
> Running without -quiet shows:
>
> skipping pass: *rest_of_compilation
> skipping pass: vregs
> skipping pass: into_cfglayout
> skipping pass: jump
> skipping pass: subreg1
> skipping pass: cse1
> found starting pass: fwprop1
>
> i.e. it skips the into_cfglayout (amongst others), to start with
> fwprop1.
>
> In theory skipping a pass ought to be a no-op, assuming that we're
> faithfully reconstructing all RTL state. However, RTL state management
> is fiddly, so the patch introduces some logic in passes.c to do some
> things when skipping a pass; in particular, it has:
>
> /* Update the cfg hooks as appropriate. */
> if (strcmp (pass->name, "into_cfglayout") == 0)
> {
> cfg_layout_rtl_register_cfg_hooks ();
> cfun->curr_properties |= PROP_cfglayout;
> }
> if (strcmp (pass->name, "outof_cfglayout") == 0)
> {
> rtl_register_cfg_hooks ();
> cfun->curr_properties &= ~PROP_cfglayout;
> }
>
> so that even when skipping "into_cfglayout", the CFG hooks are at least
> correct.
I suppose the pass manager could handle the hook switching based on
a (RTL) pass setting/clearing PROP_cfglayout. Or all passes needing
cfglayout would need to set prop_required accordingly and thus
the into/outouf cfglayout passes would be implicit.
> The assertion fires when running outof_cfglayout later on (rather than
> skipping it); the assertion:
>
> gcc_assert (original_copy_bb_pool);
>
> assumes that into_cfglayout was actually run, rather than just the
> simple "skipping" version of it.
Ah, I see cfg_layout_initialize calls initialize_original_copy_tables ()
for whatever reason and they are kept initialized until out-of-cfglayout...
GIMPLE passes do init/free them all the time. I think a better
fix would be to add a original_copy_tables_initialized () function
and guard the free_original_copy_tables call with that (keeping
the assertion that they run in pairs).
>> > * cgraph.h (symtab_node::native_rtl_p): New decl.
>> > * cgraphunit.c (symtab_node::native_rtl_p): New function.
>> > (symtab_node::needed_p): Don't assert for early assembly
>> > output
>> > for __RTL functions.
>> > (cgraph_node::finalize_function): Set "force_output" for
>> > __RTL
>> > functions.
>> > (cgraph_node::analyze): Bail out early for __RTL functions.
>> > (analyze_functions): Update assertion to support __RTL
>> > functions.
>> > (cgraph_node::expand): Bail out early for __RTL functions.
>> > * emit-rtl.c (unshare_all_rtl_again): Wrap set_used_decls
>> > call
>> > in check for DECL_INITIAL.
>>
>> You should simply set DECL_INITIAL of your function decl (make_node
>> (BLOCK);).
>> There's too much code assuming that is not NULL (and I've fixed quite
>> a bit of
>> code during stage1 not doing that).
>
> Thanks; fixed.
>
>> > * final.c (rest_of_clean_state): Don't call delete_tree_ssa
>> > for
>> > _RTL functions.
>> > * function.h (struct function): Add field "native_RTL".
>>
>> I wonder if you could simply use ->curr_properties & PROP_rtl? (and
>> set that
>> property during parsing, of course)
>
> I tried to doing that; it mostly works, but this assertion fails:
>
> 237 symtab_node::needed_p (void)
> 238 {
> 239 /* Double check that no one output the function into assembly file
> 240 early. */
> 241 if (!native_rtl_p ())
> 242 gcc_checking_assert
> 243 (!DECL_ASSEMBLER_NAME_SET_P (decl)
> 244 || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
>
> [I added the "if (!native_rtl_p ())" guard in the patch]
>
> The issue here is that when this is run, the __RTL function has been
> compiled and cleaned up, and the curr_properties & PROP_rtl has been
> cleared:
>
> (gdb) p decl->function_decl->f->curr_properties
> $7 = 0
>
> I could set the flag again after running the passes; on doing so, the
> test suite successfully runs.
Hmm, so if you are finished with the function you should set
symtab_node->analyzed
to false I think (it signals it's now merely an "extern" symbol and no
longer has a body).
Or set body_removed. Maybe just ask Honza what to do ...
Richard.
> Would you prefer I use curr_properties & PROP_rtl for this?
> [...snip...]
>
> Thanks
> Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Add "__RTL" to cc1 (v5)
2016-11-16 13:24 ` Richard Biener
@ 2016-11-18 21:02 ` David Malcolm
2016-11-18 22:14 ` Joseph Myers
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-18 21:02 UTC (permalink / raw)
To: Richard Biener, Jan Hubicka; +Cc: GCC Patches, David Malcolm
On Wed, 2016-11-16 at 14:24 +0100, Richard Biener wrote:
> On Tue, Nov 15, 2016 at 10:07 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > On Mon, 2016-11-14 at 16:14 +0100, Richard Biener wrote:
> > > On Fri, Nov 11, 2016 at 10:15 PM, David Malcolm <
> > > dmalcolm@redhat.com>
> > > wrote:
> > > > Changed in this version:
> > > >
> > > > * Rather than running just one pass, run *all* passes, but
> > > > start at
> > > > the given pass; support for "dg-do run" tests that execute
> > > > the
> > > > resulting code.
> > > > * Updated test cases to new "compact" dump format; more test
> > > > cases;
> > > > use "dg-do run" in various places.
> > > > * Lots of bugfixing
> > > >
> > > > Links to previous versions:
> > > > https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00263.html
> > > > https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00500.html
> >
> > > Does running the RTL passes right from the parser work with
> > > -fsyntax
> > > -only?
> >
> > It depends what you mean by "work". If I run it with -fsyntax
> > -only,
> > then pass_rest_of_compilation::gate returns false, and none of the
> > RTL
> > passes are run. Is this behavior correct?
>
> Yes.
Thanks.
> > > Doing it like __GIMPLE has the advantage of not exposing
> > > "rest_of_compilation", etc..
> >
> > The gimple part of the compiler supports having multiple functions
> > in
> > memory at once, and then compiling them in arbitrary order based on
> > decisions made by the callgraph.
> >
> > By contrast, the RTL part of the compiler is full of singleton
> > state:
> > things like crtl (aka x_rtl), the state of emit-rtl.c,
> > "reload_completed", etc etc.
>
> Ah, of course - I forgot that...
>
> > To try to limit the scope of the project, for the RTL frontend work
> > I'm
> > merely attempting to restore the singleton RTL state from a dump,
> > rather than to support having per function stashes of RTL state.
> >
> > Hence the rest of compilation gets invoked directly from the
> > frontend
> > for the __RTL case, since it will get overwritten if there's a
> > second
> > __RTL function in the source file (which sounds like an idea for a
> > test
> > case; I'll attempt such a test case).
> >
> > I hope this is a reasonable approach. If not, I suppose I can
> > attempt
> > to bundle it up into some kind of RTL function state, but that
> > seems
> > like significant scope creep.
>
> Yeah, I think it's a good approach for now.
OK.
> > > I'm now handling __GIMPLE from within declspecs (the GIMPLE FE
> > > stuff
> > > has been committed), it would be nice to match the __RTL piece
> > > here.
> >
> > (Congratulations on getting the GIMPLE FE stuff in)
> >
> > I'm not sure I understand you here - do you want me to rewrite the
> > __RTL parsing to match the __GIMPLE piece, or the other way around?
> > If the former, presumably I should reuse (and rename)
> > c_parser_gimple_pass_list?
>
> Handle __RTL like __GIMPLE, thus as declspec. Of course ultimatively
> Joseph has the last word here.
I've updated the patch to do so.
> >
> > > > gcc/ChangeLog:
> > > > * Makefile.in (OBJS): Add run-rtl-passes.o.
> > > >
> > > > gcc/c-family/ChangeLog:
> > > > * c-common.c (c_common_reswords): Add "__RTL".
> > > > * c-common.h (enum rid): Add RID_RTL.
> > > >
> > > > gcc/c/ChangeLog:
> > > > * c-parser.c: Include "read-rtl-function.h" and
> > > > "run-rtl-passes.h".
> > > > (c_parser_declaration_or_fndef): In the "GNU
> > > > extensions"
> > > > part of
> > > > the leading comment, add an alternate production for
> > > > "function-definition", along with new "rtl-body
> > > > -specifier"
> > > > and
> > > > "rtl-body-pass-specifier" productions. Handle "__RTL"
> > > > by
> > > > calling
> > > > c_parser_parse_rtl_body. Convert a timevar_push/pop
> > > > pair
> > > > to an auto_timevar, to cope with early exit.
> > > > (c_parser_parse_rtl_body): New function.
> > > >
> > > > gcc/ChangeLog:
> > > > * cfg.c (free_original_copy_tables): Remove assertion
> > > > on original_copy_bb_pool.
> > >
> > > How can that trigger?
> >
> > It happens when running pass_outof_cfg_layout_mode::execute; seen
> > with
> > gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c.
> >
> > The input file is a dump taken in cfg_layout mode (although in this
> > case it's a trivial 3-basic-block CFG, but ideally there would be
> > cases
> > with non-trivial control flow); it has "fwprop1" as its starting
> > pass.
> >
> > Running without -quiet shows:
> >
> > skipping pass: *rest_of_compilation
> > skipping pass: vregs
> > skipping pass: into_cfglayout
> > skipping pass: jump
> > skipping pass: subreg1
> > skipping pass: cse1
> > found starting pass: fwprop1
> >
> > i.e. it skips the into_cfglayout (amongst others), to start with
> > fwprop1.
> >
> > In theory skipping a pass ought to be a no-op, assuming that we're
> > faithfully reconstructing all RTL state. However, RTL state
> > management
> > is fiddly, so the patch introduces some logic in passes.c to do
> > some
> > things when skipping a pass; in particular, it has:
> >
> > /* Update the cfg hooks as appropriate. */
> > if (strcmp (pass->name, "into_cfglayout") == 0)
> > {
> > cfg_layout_rtl_register_cfg_hooks ();
> > cfun->curr_properties |= PROP_cfglayout;
> > }
> > if (strcmp (pass->name, "outof_cfglayout") == 0)
> > {
> > rtl_register_cfg_hooks ();
> > cfun->curr_properties &= ~PROP_cfglayout;
> > }
> >
> > so that even when skipping "into_cfglayout", the CFG hooks are at
> > least
> > correct.
>
> I suppose the pass manager could handle the hook switching based on
> a (RTL) pass setting/clearing PROP_cfglayout. Or all passes needing
> cfglayout would need to set prop_required accordingly and thus
> the into/outouf cfglayout passes would be implicit.
(I haven't attempted to touch the pass properties in this version of
the patch).
> > The assertion fires when running outof_cfglayout later on (rather
> > than
> > skipping it); the assertion:
> >
> > gcc_assert (original_copy_bb_pool);
> >
> > assumes that into_cfglayout was actually run, rather than just the
> > simple "skipping" version of it.
>
> Ah, I see cfg_layout_initialize calls initialize_original_copy_tables
> ()
> for whatever reason and they are kept initialized until out-of
> -cfglayout...
>
> GIMPLE passes do init/free them all the time. I think a better
> fix would be to add a original_copy_tables_initialized () function
> and guard the free_original_copy_tables call with that (keeping
> the assertion that they run in pairs).
Done.
> > > > * cgraph.h (symtab_node::native_rtl_p): New decl.
> > > > * cgraphunit.c (symtab_node::native_rtl_p): New
> > > > function.
> > > > (symtab_node::needed_p): Don't assert for early
> > > > assembly
> > > > output
> > > > for __RTL functions.
> > > > (cgraph_node::finalize_function): Set "force_output"
> > > > for
> > > > __RTL
> > > > functions.
> > > > (cgraph_node::analyze): Bail out early for __RTL
> > > > functions.
> > > > (analyze_functions): Update assertion to support __RTL
> > > > functions.
> > > > (cgraph_node::expand): Bail out early for __RTL
> > > > functions.
> > > > * emit-rtl.c (unshare_all_rtl_again): Wrap
> > > > set_used_decls
> > > > call
> > > > in check for DECL_INITIAL.
> > >
> > > You should simply set DECL_INITIAL of your function decl
> > > (make_node
> > > (BLOCK);).
> > > There's too much code assuming that is not NULL (and I've fixed
> > > quite
> > > a bit of
> > > code during stage1 not doing that).
> >
> > Thanks; fixed.
> >
> > > > * final.c (rest_of_clean_state): Don't call
> > > > delete_tree_ssa
> > > > for
> > > > _RTL functions.
> > > > * function.h (struct function): Add field "native_RTL".
> > >
> > > I wonder if you could simply use ->curr_properties & PROP_rtl?
> > > (and
> > > set that
> > > property during parsing, of course)
> >
> > I tried to doing that; it mostly works, but this assertion fails:
> >
> > 237 symtab_node::needed_p (void)
> > 238 {
> > 239 /* Double check that no one output the function into
> > assembly file
> > 240 early. */
> > 241 if (!native_rtl_p ())
> > 242 gcc_checking_assert
> > 243 (!DECL_ASSEMBLER_NAME_SET_P (decl)
> > 244 || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME
> > (decl)));
> >
> > [I added the "if (!native_rtl_p ())" guard in the patch]
> >
> > The issue here is that when this is run, the __RTL function has
> > been
> > compiled and cleaned up, and the curr_properties & PROP_rtl has
> > been
> > cleared:
> >
> > (gdb) p decl->function_decl->f->curr_properties
> > $7 = 0
> >
> > I could set the flag again after running the passes; on doing so,
> > the
> > test suite successfully runs.
>
> Hmm, so if you are finished with the function you should set
> symtab_node->analyzed
> to false I think (it signals it's now merely an "extern" symbol and
> no
> longer has a body).
> Or set body_removed. Maybe just ask Honza what to do ...
I looked at these fields, but I think I prefer the approach of
simply setting the PROP_rtl flag again; the other fields seem to
have specific meanings that don't apply here.
> Richard.
>
> > Would you prefer I use curr_properties & PROP_rtl for this?
>
> > [...snip...]
> >
> > Thanks
> > Dave
Updated patch follows.
Changed in v5:
- rebased from r242065 to r242392. In particular, this
brings in the gimple FE. I rewrote the "startwith" pass-skipping
mechanism to work with both __GIMPLE and __RTL.
- rewrote the "__RTL" parser so that it shares code with the
"__GIMPLE" parser, within c_parser_declspecs.
Updated all the test cases to use the 'startwith' syntax.
The gimple FE has a "flag_gimple" to enable __GIMPLE; should
I add an equivalent for __RTL?
- eliminated the new "native_RTL" field, instead just using
curr_properties & PROP_rtl.
- added original_copy_tables_initialized_p and reinstate:
gcc_assert (original_copy_bb_pool);
within free_original_copy_tables.
- added a test of multiple __RTL-marked functions within one test
case.
Successfully bootstrapped®rtested on x86_64-pc-linux-gnu as
part of the patch kit.
OK for trunk? (most of the rest of the kit also still needs
review, fwiw).
gcc/ChangeLog:
* Makefile.in (OBJS): Add run-rtl-passes.o.
gcc/c-family/ChangeLog:
* c-common.c (c_common_reswords): Add "__RTL".
* c-common.h (enum rid): Add RID_RTL.
gcc/c/ChangeLog:
* c-parser.c: Include "read-rtl-function.h" and
"run-rtl-passes.h".
(c_parser_declaration_or_fndef): Rename "gimple-pass-list" in
grammar to gimple-or-rtl-pass-list. Add rtl-function-definition
production. Update for renaming of field "gimple_pass" to
"gimple_or_rtl_pass". If __RTL was seen, call
c_parser_parse_rtl_body. Convert a timevar_push/pop pair
to an auto_timevar, to cope with early exit.
(c_parser_declspecs): Update RID_GIMPLE handling for renaming of
field "gimple_pass" to "gimple_or_rtl_pass", and for renaming of
c_parser_gimple_pass_list to c_parser_gimple_or_rtl_pass_list.
Handle RID_RTL.
(c_parser_parse_rtl_body): New function.
* c-tree.h (enum c_declspec_word): Add cdw_rtl.
(struct c_declspecs): Rename field "gimple_pass" to
"gimple_or_rtl_pass". Add field "rtl_p".
* gimple-parser.c (c_parser_gimple_pass_list): Rename to...
(c_parser_gimple_or_rtl_pass_list): ...this, updating accordingly.
* gimple-parser.h (c_parser_gimple_pass_list): Rename to...
(c_parser_gimple_or_rtl_pass_list): ...this.
gcc/ChangeLog:
* cfg.c (original_copy_tables_initialized_p): New function.
* cfg.h (original_copy_tables_initialized_p): New decl.
* cfgrtl.c (relink_block_chain): Guard the call to
free_original_copy_tables with a call to
original_copy_tables_initialized_p.
* cgraph.h (symtab_node::native_rtl_p): New decl.
* cgraphunit.c (symtab_node::native_rtl_p): New function.
(symtab_node::needed_p): Don't assert for early assembly output
for __RTL functions.
(cgraph_node::finalize_function): Set "force_output" for __RTL
functions.
(cgraph_node::analyze): Bail out early for __RTL functions.
(analyze_functions): Update assertion to support __RTL functions.
(cgraph_node::expand): Bail out early for __RTL functions.
* final.c (rest_of_clean_state): Don't call delete_tree_ssa for
_RTL functions.
* gimple-expr.c: Include "tree-pass.h".
(gimple_has_body_p): Return false for __RTL functions.
* pass_manager.h (gcc::pass_manager::get_rest_of_compilation): New
accessor.
(gcc::pass_manager::get_clean_slate): New accessor.
* passes.c: Include "insn-addr.h".
(execute_one_pass): Split out logic for skipping passes into...
(determine_pass_name_match): ...this new function, ...
(should_skip_pass_p): ...and this new function, adding logging
and special-casing dfinit.
(skip_pass): New function.
* read-md.c (md_reader::read_char): Support filtering
the input to a subset of line numbers.
(md_reader::md_reader): Initialize fields
m_first_line and m_last_line.
(md_reader::read_file_fragment): New function.
* read-md.h (md_reader::read_file_fragment): New decl.
(md_reader::m_first_line): New field.
(md_reader::int m_last_line): New field.
* read-rtl-function.c (function_reader::create_function): Only
create cfun if it doesn't already exist. Set PROP_rtl on cfun's
curr_properties. Set DECL_INITIAL to a dummy block.
(read_rtl_function_body_from_file_range): New function.
* read-rtl-function.h (read_rtl_function_body_from_file_range):
New decl.
* run-rtl-passes.c: New file.
* run-rtl-passes.h: New file.
gcc/testsuite/ChangeLog:
* gcc.dg/rtl/aarch64/asr_div1.c: New file.
* gcc.dg/rtl/aarch64/pr71779.c: New file.
* gcc.dg/rtl/rtl.exp: New file.
* gcc.dg/rtl/test.c: New file.
* gcc.dg/rtl/unknown-rtx-code.c: New file.
* gcc.dg/rtl/x86_64/dfinit.c: New file.
* gcc.dg/rtl/x86_64/different-structs.c: New file.
* gcc.dg/rtl/x86_64/final.c: New file.
* gcc.dg/rtl/x86_64/into-cfglayout.c: New file.
* gcc.dg/rtl/x86_64/ira.c: New file.
* gcc.dg/rtl/x86_64/pro_and_epilogue.c: New file.
* gcc.dg/rtl/x86_64/test-multiple-fns.c: New file.
* gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c: New file.
* gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c: New file.
* gcc.dg/rtl/x86_64/test-rtl.c: New file.
* gcc.dg/rtl/x86_64/test_1.h: New file.
* gcc.dg/rtl/x86_64/times-two.c.after-expand.c: New file.
* gcc.dg/rtl/x86_64/times-two.c.before-df.c: New file.
* gcc.dg/rtl/x86_64/vregs.c: New file.
---
gcc/Makefile.in | 1 +
gcc/c-family/c-common.c | 1 +
gcc/c-family/c-common.h | 3 +
gcc/c/c-parser.c | 105 +++++++++++++++-
gcc/c/c-tree.h | 7 +-
gcc/c/gimple-parser.c | 8 +-
gcc/c/gimple-parser.h | 2 +-
gcc/cfg.c | 9 ++
gcc/cfg.h | 1 +
gcc/cfgrtl.c | 3 +-
gcc/cgraph.h | 4 +
gcc/cgraphunit.c | 41 ++++++-
gcc/final.c | 3 +-
gcc/function.h | 2 +-
gcc/gimple-expr.c | 3 +-
gcc/pass_manager.h | 6 +
gcc/passes.c | 130 ++++++++++++++++----
gcc/read-md.c | 35 +++++-
gcc/read-md.h | 7 ++
gcc/read-rtl-function.c | 83 ++++++++++---
gcc/read-rtl-function.h | 3 +
gcc/run-rtl-passes.c | 88 ++++++++++++++
gcc/run-rtl-passes.h | 25 ++++
gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c | 41 +++++++
gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c | 50 ++++++++
gcc/testsuite/gcc.dg/rtl/rtl.exp | 41 +++++++
gcc/testsuite/gcc.dg/rtl/test.c | 31 +++++
gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c | 8 ++
gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c | 116 ++++++++++++++++++
.../gcc.dg/rtl/x86_64/different-structs.c | 81 +++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/final.c | 133 +++++++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c | 117 ++++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/ira.c | 111 +++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c | 110 +++++++++++++++++
.../gcc.dg/rtl/x86_64/test-multiple-fns.c | 105 ++++++++++++++++
.../rtl/x86_64/test-return-const.c.after-expand.c | 39 ++++++
.../rtl/x86_64/test-return-const.c.before-fwprop.c | 42 +++++++
gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c | 101 ++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h | 16 +++
.../gcc.dg/rtl/x86_64/times-two.c.after-expand.c | 70 +++++++++++
.../gcc.dg/rtl/x86_64/times-two.c.before-df.c | 54 +++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c | 112 +++++++++++++++++
42 files changed, 1885 insertions(+), 63 deletions(-)
create mode 100644 gcc/run-rtl-passes.c
create mode 100644 gcc/run-rtl-passes.h
create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/rtl.exp
create mode 100644 gcc/testsuite/gcc.dg/rtl/test.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/final.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 73d12dc..14ffb96 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1429,6 +1429,7 @@ OBJS = \
rtlhash.o \
rtlanal.o \
rtlhooks.o \
+ run-rtl-passes.o \
sbitmap.o \
sched-deps.o \
sched-ebb.o \
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 2997c83..7ba3539 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -437,6 +437,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__volatile__", RID_VOLATILE, 0 },
{ "__GIMPLE", RID_GIMPLE, D_CONLY },
{ "__PHI", RID_PHI, D_CONLY },
+ { "__RTL", RID_RTL, D_CONLY },
{ "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "asm", RID_ASM, D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 241b345..89a5f6f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -124,6 +124,9 @@ enum rid
/* "__PHI", for parsing PHI function in GIMPLE FE. */
RID_PHI,
+ /* "__RTL", for the RTL-parsing extension to the C frontend. */
+ RID_RTL,
+
/* C11 */
RID_ALIGNAS, RID_GENERIC,
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 00fe731..d645d29 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3. If not see
#include "gcc-rich-location.h"
#include "c-parser.h"
#include "gimple-parser.h"
+#include "read-rtl-function.h"
+#include "run-rtl-passes.h"
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
@@ -1310,6 +1312,8 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
static void c_parser_cilk_grainsize (c_parser *, bool *);
+static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass);
+
/* Parse a translation unit (C90 6.7, C99 6.9).
translation-unit:
@@ -1546,7 +1550,11 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
GIMPLE:
gimple-function-definition:
- declaration-specifiers[opt] __GIMPLE (gimple-pass-list) declarator
+ declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator
+ declaration-list[opt] compound-statement
+
+ rtl-function-definition:
+ declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator
declaration-list[opt] compound-statement */
static void
@@ -2042,7 +2050,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
tv = TV_PARSE_INLINE;
else
tv = TV_PARSE_FUNC;
- timevar_push (tv);
+ auto_timevar at (g_timer, tv);
/* Parse old-style parameter declarations. ??? Attributes are
not allowed to start declaration specifiers here because of a
@@ -2074,12 +2082,28 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
function body as GIMPLE. */
if (specs->gimple_p)
{
- cfun->pass_startwith = specs->gimple_pass;
+ cfun->pass_startwith = specs->gimple_or_rtl_pass;
bool saved = in_late_binary_op;
in_late_binary_op = true;
c_parser_parse_gimple_body (parser);
in_late_binary_op = saved;
}
+ /* Similarly, if it was marked with __RTL, use the RTL parser now,
+ consuming the function body. */
+ else if (specs->rtl_p)
+ {
+ c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
+
+ /* Normally, store_parm_decls sets next_is_function_body,
+ anticipating a function body. We need a push_scope/pop_scope
+ pair to flush out this state, or subsequent function parsing
+ will go wrong. */
+ push_scope ();
+ pop_scope ();
+
+ finish_function ();
+ return;
+ }
else
{
fnbody = c_parser_compound_statement (parser);
@@ -2110,7 +2134,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (specs->gimple_p)
DECL_SAVED_TREE (fndecl) = NULL_TREE;
- timevar_pop (tv);
break;
}
}
@@ -2602,7 +2625,13 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
c_parser_consume_token (parser);
specs->gimple_p = true;
specs->locations[cdw_gimple] = loc;
- specs->gimple_pass = c_parser_gimple_pass_list (parser);
+ specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+ break;
+ case RID_RTL:
+ c_parser_consume_token (parser);
+ specs->rtl_p = true;
+ specs->locations[cdw_rtl] = loc;
+ specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
break;
default:
goto out;
@@ -18258,4 +18287,70 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
return value_tree;
}
+/* Parse the body of a function declaration marked with "__RTL".
+
+ The RTL parser works on the level of characters read from a
+ FILE *, whereas c_parser works at the level of tokens.
+ Square this circle by consuming all of the tokens up to and
+ including the closing brace, recording the start/end of the RTL
+ fragment, and reopening the file and re-reading the relevant
+ lines within the RTL parser.
+
+ This requires the opening and closing braces of the C function
+ to be on separate lines from the RTL they wrap.
+
+ Take ownership of START_WITH_PASS, if non-NULL. */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
+{
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ free (start_with_pass);
+ return;
+ }
+
+ location_t start_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume all tokens, up to the closing brace, handling
+ matching pairs of braces in the rtl dump. */
+ int num_open_braces = 1;
+ while (1)
+ {
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_BRACE:
+ num_open_braces++;
+ break;
+ case CPP_CLOSE_BRACE:
+ if (--num_open_braces == 0)
+ goto found_closing_brace;
+ break;
+ default:
+ break;
+ }
+ c_parser_consume_token (parser);
+ }
+
+ found_closing_brace:
+ /* At the closing brace; record its location. */
+ location_t end_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume the closing brace. */
+ c_parser_consume_token (parser);
+
+ /* Invoke the RTL parser. */
+ if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+ {
+ free (start_with_pass);
+ return;
+ }
+
+ /* If a pass name was provided for START_WITH_PASS, run the backend
+ accordingly now, on the cfun created above, transferring
+ ownership of START_WITH_PASS. */
+ if (start_with_pass)
+ run_rtl_passes (start_with_pass);
+}
+
#include "gt-c-c-parser.h"
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a8cf353..94821d8 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -268,6 +268,7 @@ enum c_declspec_word {
cdw_alignas,
cdw_address_space,
cdw_gimple,
+ cdw_rtl,
cdw_number_of_elements /* This one must always be the last
enumerator. */
};
@@ -291,8 +292,8 @@ struct c_declspecs {
NULL; attributes (possibly from multiple lists) will be passed
separately. */
tree attrs;
- /* The pass to start compiling a __GIMPLE function with. */
- char *gimple_pass;
+ /* The pass to start compiling a __GIMPLE or __RTL function with. */
+ char *gimple_or_rtl_pass;
/* The base-2 log of the greatest alignment required by an _Alignas
specifier, in bytes, or -1 if no such specifiers with nonzero
alignment. */
@@ -367,6 +368,8 @@ struct c_declspecs {
BOOL_BITFIELD alignas_p : 1;
/* Whether any __GIMPLE specifier was specified. */
BOOL_BITFIELD gimple_p : 1;
+ /* Whether any __RTL specifier was specified. */
+ BOOL_BITFIELD rtl_p : 1;
/* The address space that the declaration belongs to. */
addr_space_t address_space;
};
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
index 9b6af13..f5b2c44 100644
--- a/gcc/c/gimple-parser.c
+++ b/gcc/c/gimple-parser.c
@@ -1000,18 +1000,18 @@ c_parser_gimple_label (c_parser *parser, gimple_seq *seq)
return;
}
-/* Parse gimple pass list.
+/* Parse gimple/RTL pass list.
- gimple-pass-list:
+ gimple-or-rtl-pass-list:
startwith("pass-name")
*/
char *
-c_parser_gimple_pass_list (c_parser *parser)
+c_parser_gimple_or_rtl_pass_list (c_parser *parser)
{
char *pass = NULL;
- /* Accept __GIMPLE. */
+ /* Accept __GIMPLE/__RTL. */
if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
return NULL;
c_parser_consume_token (parser);
diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
index f72b626..e3ab019 100644
--- a/gcc/c/gimple-parser.h
+++ b/gcc/c/gimple-parser.h
@@ -22,6 +22,6 @@ along with GCC; see the file COPYING3. If not see
/* Gimple parsing functions. */
extern void c_parser_parse_gimple_body (c_parser *);
-extern char *c_parser_gimple_pass_list (c_parser *);
+extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
#endif
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 6604b02..1ca6592 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -1094,6 +1094,15 @@ free_original_copy_tables (void)
original_copy_bb_pool = NULL;
}
+/* Return true iff we have had a call to initialize_original_copy_tables
+ without a corresponding call to free_original_copy_tables. */
+
+bool
+original_copy_tables_initialized_p (void)
+{
+ return original_copy_bb_pool != NULL;
+}
+
/* Removes the value associated with OBJ from table TAB. */
static void
diff --git a/gcc/cfg.h b/gcc/cfg.h
index ad935e3..df1480f 100644
--- a/gcc/cfg.h
+++ b/gcc/cfg.h
@@ -110,6 +110,7 @@ extern void scale_bbs_frequencies_gcov_type (basic_block *, int, gcov_type,
extern void initialize_original_copy_tables (void);
extern void reset_original_copy_tables (void);
extern void free_original_copy_tables (void);
+extern bool original_copy_tables_initialized_p (void);
extern void set_bb_original (basic_block, basic_block);
extern basic_block get_bb_original (basic_block);
extern void set_bb_copy (basic_block, basic_block);
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index d2719db..de53295 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -3647,7 +3647,8 @@ relink_block_chain (bool stay_in_cfglayout_mode)
/* Maybe reset the original copy tables, they are not valid anymore
when we renumber the basic blocks in compact_blocks. If we are
are going out of cfglayout mode, don't re-allocate the tables. */
- free_original_copy_tables ();
+ if (original_copy_tables_initialized_p ())
+ free_original_copy_tables ();
if (stay_in_cfglayout_mode)
initialize_original_copy_tables ();
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cc730d2..79e33da 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -328,6 +328,10 @@ public:
configury. This function is used just during symbol creation. */
bool needed_p (void);
+ /* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+ bool native_rtl_p () const;
+
/* Return true when there are references to the node. */
bool referred_to_p (bool include_self = true);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index e315a77..aae7b2a 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -217,6 +217,19 @@ static void handle_alias_pairs (void);
/* Used for vtable lookup in thunk adjusting. */
static GTY (()) tree vtable_entry_type;
+/* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+
+bool
+symtab_node::native_rtl_p () const
+{
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ return false;
+ if (!DECL_STRUCT_FUNCTION (decl))
+ return false;
+ return DECL_STRUCT_FUNCTION (decl)->curr_properties & PROP_rtl;
+}
+
/* Determine if symbol declaration is needed. That is, visible to something
either outside this translation unit, something magic in the system
configury */
@@ -225,8 +238,10 @@ symtab_node::needed_p (void)
{
/* Double check that no one output the function into assembly file
early. */
- gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)
- || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
+ if (!native_rtl_p ())
+ gcc_checking_assert
+ (!DECL_ASSEMBLER_NAME_SET_P (decl)
+ || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
if (!definition)
return false;
@@ -435,6 +450,14 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
&& !DECL_DISREGARD_INLINE_LIMITS (decl))
node->force_output = 1;
+ /* __RTL functions were already output as soon as they were parsed (due
+ to the large amount of global state in the backend).
+ Mark such functions as "force_output" to reflect the fact that they
+ will be in the asm file when considering the symbols they reference.
+ The attempt to output them later on will bail out immediately. */
+ if (node->native_rtl_p ())
+ node->force_output = 1;
+
/* When not optimizing, also output the static functions. (see
PR24561), but don't do so for always_inline functions, functions
declared inline and nested functions. These were optimized out
@@ -568,6 +591,12 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
void
cgraph_node::analyze (void)
{
+ if (native_rtl_p ())
+ {
+ analyzed = true;
+ return;
+ }
+
tree decl = this->decl;
location_t saved_loc = input_location;
input_location = DECL_SOURCE_LOCATION (decl);
@@ -1226,7 +1255,8 @@ analyze_functions (bool first_time)
gcc_assert (!cnode->definition || cnode->thunk.thunk_p
|| cnode->alias
- || gimple_has_body_p (decl));
+ || gimple_has_body_p (decl)
+ || cnode->native_rtl_p ());
gcc_assert (cnode->analyzed == cnode->definition);
}
node->aux = NULL;
@@ -1965,6 +1995,11 @@ cgraph_node::expand (void)
/* We ought to not compile any inline clones. */
gcc_assert (!global.inlined_to);
+ /* __RTL functions are compiled as soon as they are parsed, so don't
+ do it again. */
+ if (native_rtl_p ())
+ return;
+
announce_function (decl);
process = 0;
gcc_assert (lowered);
diff --git a/gcc/final.c b/gcc/final.c
index 5709d0e..c1afc57 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4701,7 +4701,8 @@ rest_of_clean_state (void)
free_bb_for_insn ();
- delete_tree_ssa (cfun);
+ if (cfun->gimple_df)
+ delete_tree_ssa (cfun);
/* We can reduce stack alignment on call site only when we are sure that
the function body just produced will be actually used in the final
diff --git a/gcc/function.h b/gcc/function.h
index cabffb9..19c26c8 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -236,7 +236,7 @@ struct GTY(()) function {
/* The loops in this function. */
struct loops *x_current_loops;
- /* Filled by the GIMPLE FE, pass to start compilation with. */
+ /* Filled by the GIMPLE and RTL FEs, pass to start compilation with. */
char *pass_startwith;
/* The stack usage of this function. */
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index de5cce1..e60c607 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "demangle.h"
#include "hash-set.h"
#include "rtl.h"
+#include "tree-pass.h"
/* ----- Type related ----- */
@@ -323,7 +324,7 @@ bool
gimple_has_body_p (tree fndecl)
{
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
- return (gimple_body (fndecl) || (fn && fn->cfg));
+ return (gimple_body (fndecl) || (fn && fn->cfg && !(fn->curr_properties & PROP_rtl)));
}
/* Return a printable name for symbol DECL. */
diff --git a/gcc/pass_manager.h b/gcc/pass_manager.h
index 464e25f..7278d97 100644
--- a/gcc/pass_manager.h
+++ b/gcc/pass_manager.h
@@ -82,6 +82,12 @@ public:
opt_pass *get_pass_by_name (const char *name);
+ opt_pass *get_rest_of_compilation () const
+ {
+ return pass_rest_of_compilation_1;
+ }
+ opt_pass *get_clean_slate () const { return pass_clean_state_1; }
+
public:
/* The root of the compilation pass tree, once constructed. */
opt_pass *all_passes;
diff --git a/gcc/passes.c b/gcc/passes.c
index 51d0d84..5086868 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgrtl.h"
#include "tree-ssa-live.h" /* For remove_unused_locals. */
#include "tree-cfgcleanup.h"
+#include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC. */
using namespace gcc;
@@ -2273,6 +2274,106 @@ override_gate_status (opt_pass *pass, tree func, bool gate_status)
return gate_status;
}
+/* Determine if PASS_NAME matches CRITERION.
+ Not a pure predicate, since it can update CRITERION, to support
+ matching the Nth invocation of a pass.
+ Subroutine of should_skip_pass_p. */
+
+static bool
+determine_pass_name_match (const char *pass_name, char *criterion)
+{
+ size_t namelen = strlen (pass_name);
+ if (!strncmp (pass_name, criterion, namelen))
+ {
+ /* The following supports starting with the Nth invocation
+ of a pass (where N does not necessarily is equal to the
+ dump file suffix). */
+ if (criterion[namelen] == '\0'
+ || (criterion[namelen] == '1'
+ && criterion[namelen + 1] == '\0'))
+ return true;
+ else
+ {
+ if (criterion[namelen + 1] == '\0')
+ --criterion[namelen];
+ return false;
+ }
+ }
+ else
+ return false;
+}
+
+/* For skipping passes until "startwith" pass.
+ Return true iff PASS should be skipped.
+ Clear cfun->pass_startwith when encountering the "startwith" pass,
+ so that all subsequent passes are run. */
+
+static bool
+should_skip_pass_p (opt_pass *pass)
+{
+ if (!cfun)
+ return false;
+ if (!cfun->pass_startwith)
+ return false;
+
+ /* We can't skip the lowering phase yet -- ideally we'd
+ drive that phase fully via properties. */
+ if (pass->type == GIMPLE_PASS
+ && !(cfun->curr_properties & PROP_ssa))
+ {
+ if (!quiet_flag)
+ fprintf (stderr, "running pass anyway: %s\n", pass->name);
+ return false;
+ }
+
+ if (determine_pass_name_match (pass->name, cfun->pass_startwith))
+ {
+ if (!quiet_flag)
+ fprintf (stderr, "found starting pass: %s\n", pass->name);
+ cfun->pass_startwith = NULL;
+ return false;
+ }
+
+ /* Don't skip df init; later RTL passes need it. */
+ if (strstr (pass->name, "dfinit") != NULL)
+ return false;
+
+ if (!quiet_flag)
+ fprintf (stderr, "skipping pass: %s\n", pass->name);
+ return true;
+}
+
+/* Skip the given pass, for handling passes before "startwith"
+ in __GIMPLE and__RTL-marked functions.
+ In theory, this ought to be a no-op, but some of the RTL passes
+ need additional processing here. */
+
+static void
+skip_pass (opt_pass *pass)
+{
+ /* Pass "reload" sets the global "reload_completed", and many
+ things depend on this (e.g. instructions in .md files). */
+ if (strcmp (pass->name, "reload") == 0)
+ reload_completed = 1;
+
+ /* The INSN_ADDRESSES vec is normally set up by
+ shorten_branches; set it up for the benefit of passes that
+ run after this. */
+ if (strcmp (pass->name, "shorten") == 0)
+ INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+ /* Update the cfg hooks as appropriate. */
+ if (strcmp (pass->name, "into_cfglayout") == 0)
+ {
+ cfg_layout_rtl_register_cfg_hooks ();
+ cfun->curr_properties |= PROP_cfglayout;
+ }
+ if (strcmp (pass->name, "outof_cfglayout") == 0)
+ {
+ rtl_register_cfg_hooks ();
+ cfun->curr_properties &= ~PROP_cfglayout;
+ }
+}
/* Execute PASS. */
@@ -2313,33 +2414,10 @@ execute_one_pass (opt_pass *pass)
return false;
}
- /* For skipping passes until startwith pass */
- if (cfun
- && cfun->pass_startwith
- /* But we can't skip the lowering phase yet -- ideally we'd
- drive that phase fully via properties. */
- && (cfun->curr_properties & PROP_ssa))
+ if (should_skip_pass_p (pass))
{
- size_t namelen = strlen (pass->name);
- if (! strncmp (pass->name, cfun->pass_startwith, namelen))
- {
- /* The following supports starting with the Nth invocation
- of a pass (where N does not necessarily is equal to the
- dump file suffix). */
- if (cfun->pass_startwith[namelen] == '\0'
- || (cfun->pass_startwith[namelen] == '1'
- && cfun->pass_startwith[namelen + 1] == '\0'))
- cfun->pass_startwith = NULL;
- else
- {
- if (cfun->pass_startwith[namelen + 1] != '\0')
- return true;
- --cfun->pass_startwith[namelen];
- return true;
- }
- }
- else
- return true;
+ skip_pass (pass);
+ return true;
}
/* Pass execution event trigger: useful to identify passes being
diff --git a/gcc/read-md.c b/gcc/read-md.c
index a8462a6..25bc3c4 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -399,6 +399,16 @@ md_reader::read_char (void)
else
m_read_md_colno++;
+ /* If we're filtering lines, treat everything before the range of
+ interest as a space, and as EOF for everything after. */
+ if (m_first_line && m_last_line)
+ {
+ if (m_read_md_lineno < m_first_line)
+ return ' ';
+ if (m_read_md_lineno > m_last_line)
+ return EOF;
+ }
+
return ch;
}
@@ -981,7 +991,9 @@ md_reader::md_reader (bool compact)
m_read_md_lineno (0),
m_read_md_colno (0),
m_first_dir_md_include (NULL),
- m_last_dir_md_include_ptr (&m_first_dir_md_include)
+ m_last_dir_md_include_ptr (&m_first_dir_md_include),
+ m_first_line (0),
+ m_last_line (0)
{
/* Set the global singleton pointer. */
md_reader_ptr = this;
@@ -1284,6 +1296,27 @@ md_reader::read_md_files (int argc, const char **argv,
return !have_error;
}
+
+/* Read FILENAME, filtering to just the given lines. */
+
+bool
+md_reader::read_file_fragment (const char *filename,
+ int first_line,
+ int last_line)
+{
+ m_read_md_filename = filename;
+ m_read_md_file = fopen (m_read_md_filename, "r");
+ if (m_read_md_file == 0)
+ {
+ perror (m_read_md_filename);
+ return false;
+ }
+ m_first_line = first_line;
+ m_last_line = last_line;
+ handle_toplevel_file ();
+ return !have_error;
+}
+
/* class noop_reader : public md_reader */
/* A dummy implementation which skips unknown directives. */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 1be0f5a..06be3ec 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -98,6 +98,9 @@ class md_reader
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
+ bool read_file_fragment (const char *filename,
+ int first_line,
+ int last_line);
/* A hook that handles a single .md-file directive, up to but not
including the closing ')'. It takes two arguments: the file position
@@ -232,6 +235,10 @@ class md_reader
/* A table of enum_type structures, hashed by name. */
htab_t m_enum_types;
+
+ /* If non-zero, filter the input to just this subset of lines. */
+ int m_first_line;
+ int m_last_line;
};
/* Global singleton; constrast with rtx_reader_ptr below. */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 3e19433..d051506 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -489,23 +489,38 @@ function_reader::create_function ()
else
rtl_register_cfg_hooks ();
- /* Create cfun. */
- tree fn_name = get_identifier (m_name ? m_name : "test_1");
- tree int_type = integer_type_node;
- tree return_type = int_type;
- tree arg_types[3] = {int_type, int_type, int_type};
- tree fn_type = build_function_type_array (return_type, 3, arg_types);
- tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
- fn_type);
- tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
- return_type);
- DECL_ARTIFICIAL (resdecl) = 1;
- DECL_IGNORED_P (resdecl) = 1;
- DECL_RESULT (fndecl) = resdecl;
- allocate_struct_function (fndecl, false);
- /* This sets cfun. */
-
- current_function_decl = fndecl;
+ /* When run from selftests or "rtl1", cfun is NULL.
+ When run from "cc1" for a C function tagged with __RTL, cfun is the
+ tagged function. */
+ if (!cfun)
+ {
+ tree fn_name = get_identifier (m_name ? m_name : "test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+ current_function_decl = fndecl;
+ }
+
+ gcc_assert (cfun);
+ gcc_assert (current_function_decl);
+ tree fndecl = current_function_decl;
+
+ /* Mark this function as being specified as __RTL. */
+ cfun->curr_properties |= PROP_rtl;
+
+ /* cc1 normally inits DECL_INITIAL (fndecl) to be error_mark_node.
+ Create a dummy block for it. */
+ DECL_INITIAL (fndecl) = make_node (BLOCK);
cfun->curr_properties = (PROP_cfg | PROP_rtl);
@@ -1615,6 +1630,40 @@ read_rtl_function_body (int argc, const char **argv,
return true;
}
+/* Run the RTL dump parser on the range of lines between START_LOC and
+ END_LOC (including those lines). */
+
+bool
+read_rtl_function_body_from_file_range (location_t start_loc,
+ location_t end_loc)
+{
+ expanded_location exploc_start = expand_location (start_loc);
+ expanded_location exploc_end = expand_location (end_loc);
+
+ if (exploc_start.file != exploc_end.file)
+ {
+ error_at (end_loc, "start/end of RTL fragment are in different files");
+ return false;
+ }
+ if (exploc_start.line >= exploc_end.line)
+ {
+ error_at (end_loc,
+ "start of RTL fragment must be on an earlier line than end");
+ return false;
+ }
+
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ function_reader reader (NULL);
+ if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
+ exploc_end.line - 1))
+ return false;
+
+ return true;
+}
+
#if CHECKING_P
namespace selftest {
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index 036fcce..d5d12ab 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -33,4 +33,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
bool (*parse_opt) (const char *),
function_reader_policy *policy);
+extern bool read_rtl_function_body_from_file_range (location_t start_loc,
+ location_t end_loc);
+
#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/run-rtl-passes.c b/gcc/run-rtl-passes.c
new file mode 100644
index 0000000..eefbad4
--- /dev/null
+++ b/gcc/run-rtl-passes.c
@@ -0,0 +1,88 @@
+/* run-rtl-passes.c - Run just one RTL pass
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "insn-attr-common.h" /* for INSN_SCHEDULING. */
+#include "insn-attr.h" /* for init_sched_attrs. */
+#include "run-rtl-passes.h"
+
+/* Run the backend passes, starting at the given pass.
+ Take ownership of INITIAL_PASS_NAME. */
+
+void
+run_rtl_passes (char *initial_pass_name)
+{
+ cfun->pass_startwith = initial_pass_name;
+ max_regno = max_reg_num ();
+
+ /* Pass "expand" normally sets this up. */
+#ifdef INSN_SCHEDULING
+ init_sched_attrs ();
+#endif
+
+ bitmap_obstack_initialize (NULL);
+ bitmap_obstack_initialize (®_obstack);
+
+ opt_pass *rest_of_compilation
+ = g->get_passes ()->get_rest_of_compilation ();
+ gcc_assert (rest_of_compilation);
+ execute_pass_list (cfun, rest_of_compilation);
+
+ opt_pass *clean_slate = g->get_passes ()->get_clean_slate ();
+ gcc_assert (clean_slate);
+ execute_pass_list (cfun, clean_slate);
+
+ bitmap_obstack_release (®_obstack);
+
+ cfun->curr_properties |= PROP_rtl;
+}
diff --git a/gcc/run-rtl-passes.h b/gcc/run-rtl-passes.h
new file mode 100644
index 0000000..aa035c5
--- /dev/null
+++ b/gcc/run-rtl-passes.h
@@ -0,0 +1,25 @@
+/* run-rtl-passes.h - Run a subset of the RTL passes
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_RUN_RTL_PASSES_H
+#define GCC_RUN_RTL_PASSES_H
+
+extern void run_rtl_passes (char *initial_pass_name);
+
+#endif /* GCC_RUN_RTL_PASSES_H */
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
new file mode 100644
index 0000000..bc39a70
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
@@ -0,0 +1,41 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-mtune=cortex-a53 -fdump-rtl-combine -O2" } */
+
+/* Taken from
+ gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+ for aarch64, hand editing to the new format. */
+
+int __RTL (startwith ("combine")) f1 (int n)
+{
+(function "f1"
+ (param "n"
+ (DECL_RTL (reg/v:SI %1 [ n ]))
+ (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
+ ) ;; param "n"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 8 (set (reg:DI %2)
+ (lshiftrt:DI (reg:DI %0)
+ (const_int 32)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %0)))
+ (cinsn 9 (set (reg:SI %1)
+ (ashiftrt:SI (subreg:SI (reg:DI %2) 0)
+ (const_int 3)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %2)))
+
+ ;; Extra insn, to avoid all of the above from being deleted by DCE
+ (insn 10 (use (reg/i:SI %1)))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
+}
+
+/* Verify that insns 8 and 9 get combined into a shift of 35 (0x23) */
+/* { dg-final { scan-rtl-dump "allowing combination of insns 8 and 9" "combine" } } */
+/* { dg-final { scan-rtl-dump "modifying insn i3 9: r\[0-9\]+:SI#0=r\[0-9\]+:DI>>0x23" "combine" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
new file mode 100644
index 0000000..91ae937
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
@@ -0,0 +1,50 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-fdump-rtl-cse1" } */
+
+/* Dump taken from comment 2 of PR 71779, of
+ "...the relevant memory access coming out of expand"
+ hand-edited to the compact dump format. */
+
+int __RTL (startwith ("cse1")) test (int n)
+{
+(function "fragment"
+ (param "n"
+ (DECL_RTL (reg/v:SI %1 [ n ]))
+ (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
+ ) ;; param "n"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+
+;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
+(insn 1045 (set (reg:SI %480)
+ (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ y.c:12702)
+(insn 1046 (set (reg/f:SI %479)
+ (lo_sum:SI (reg:SI %480)
+ (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ y.c:12702
+ (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+(insn 1047 (set (reg:DI %481)
+ (subreg:DI (reg/f:SI %479) 0)) y.c:12702)
+(insn 1048 (set (zero_extract:DI (reg/v:DI %191 [ obj1D.17368 ])
+ (const_int 32)
+ (const_int 0))
+ (reg:DI %481)) y.c:12702)
+;; Extra insn, to avoid all of the above from being deleted by DCE
+(insn 1049 (set (mem:DI (reg:DI %191) [1 i+0 S4 A32])
+ (const_int 1)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
+}
+
+/* TODO: scan the dump. */
diff --git a/gcc/testsuite/gcc.dg/rtl/rtl.exp b/gcc/testsuite/gcc.dg/rtl/rtl.exp
new file mode 100644
index 0000000..3c6648b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/rtl.exp
@@ -0,0 +1,41 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+ set DEFAULT_RTLFLAGS ""
+ # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.c]]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/rtl/test.c b/gcc/testsuite/gcc.dg/rtl/test.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/test.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+}
+
+/* Example showing:
+ - data structure
+ - loop
+ - call to "abort". */
+
+struct foo
+{
+ int count;
+ float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+ float result = 0.0f;
+
+ if (lhs->count != rhs->count)
+ __builtin_abort ();
+
+ for (int i = 0; i < lhs->count; i++)
+ result += lhs->data[i] * rhs->data[i];
+
+ return result;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
new file mode 100644
index 0000000..dd252f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
@@ -0,0 +1,8 @@
+void __RTL test (void)
+{
+ (function "test"
+ (insn-chain
+ (not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
+ ) ;; insn-chain
+ ) ;; function
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
new file mode 100644
index 0000000..8701c1d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
@@ -0,0 +1,116 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+#include "test_1.h"
+
+/* Lightly-modified dump of test.c.261r.split1 for x86_64. */
+
+int __RTL (startwith ("no-opt dfinit")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that the dataflow information matches what cc1 would normally
+ have generated. In particular, in earlier versions of the RTL
+ frontend, the exit block use of reg 0 (ax) wasn't picked up
+ on, due to not setting up crtl->return_rtx based on
+ DECL_RESULT (fndecl). */
+/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
new file mode 100644
index 0000000..8db1161
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
@@ -0,0 +1,81 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+extern double sqrt(double x);
+
+struct foo
+{
+ double x;
+ double y;
+};
+
+struct bar
+{
+ double x;
+ double y;
+};
+
+double __RTL test (struct foo *f, const struct bar *b)
+{
+#if 0
+ /* Result of "expand" on this C code, compiled for x86_64 with -Os. */
+ f->x += b->x;
+ f->y += b->y;
+ return sqrt (f->x * f->x + f->y * f->y);
+#endif
+(function "test"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 5 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (reg/v/f:DI %10 [ f ])
+ (reg:DI di [ f ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
+ (cinsn 3 (set (reg/v/f:DI %11 [ b ])
+ (reg:DI si [ b ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
+ (cnote 4 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 7 (set (reg:DF %12)
+ (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 8 (set (reg:DF %2 [ _3 ])
+ (plus:DF (reg:DF %12)
+ (mem:DF (reg/v/f:DI %11 [ b ]) [2 b_12(D)->x+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 9 (set (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])
+ (reg:DF %2 [ _3 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 10 (set (reg:DF %13)
+ (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
+ (const_int 8)) [2 f_11(D)->y+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 11 (set (reg:DF %5 [ _6 ])
+ (plus:DF (reg:DF %13)
+ (mem:DF (plus:DI (reg/v/f:DI %11 [ b ])
+ (const_int 8)) [2 b_12(D)->y+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 12 (set (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
+ (const_int 8)) [2 f_11(D)->y+0 S8 A64])
+ (reg:DF %5 [ _6 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 13 (set (reg:DF %14)
+ (mult:DF (reg:DF %2 [ _3 ])
+ (reg:DF %2 [ _3 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 14 (set (reg:DF %15)
+ (mult:DF (reg:DF %5 [ _6 ])
+ (reg:DF %5 [ _6 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 15 (set (reg:DF %16)
+ (plus:DF (reg:DF %14)
+ (reg:DF %15))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 16 (set (reg:DF xmm0)
+ (reg:DF %16)) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (ccall_insn/j 17 (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)))
+ (expr_list:DF (use (reg:DF xmm0))))
+ (edge-to exit (flags "ABNORMAL | SIBCALL"))
+ ) ;; block 2
+ (cbarrier 18)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:DF xmm0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test"
+
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/final.c b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
new file mode 100644
index 0000000..1b8ea09
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
@@ -0,0 +1,133 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.304r.dwarf2 for x86_64 target,
+ with various NOTE_INSN_CFI deleted by hand for now. */
+
+int __RTL (startwith ("final")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn/f 32 (set (mem:DI (pre_dec:DI (reg/f:DI sp)) [0 S8 A8])
+ (reg/f:DI bp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn/f 33 (set (reg/f:DI bp)
+ (reg/f:DI sp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 34 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 35 NOTE_INSN_PROLOGUE_END)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI ax [90])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (plus:SI (reg:SI ax [90])
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI ax [91])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (neg:SI (reg:SI ax [91])))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cnote 36 NOTE_INSN_EPILOGUE_BEG)
+ (cinsn 37 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn/f 38 (set (reg/f:DI bp)
+ (mem:DI (post_inc:DI (reg/f:DI sp)) [0 S8 A8])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7
+ (expr_list:REG_CFA_DEF_CFA (plus:DI (reg/f:DI sp)
+ (const_int 8))))
+ (cjump_insn 39 (simple_return) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit)
+ ) ;; block 5
+ (cbarrier 40)
+ (cnote 31 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that asm was emitted. */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+ FIXME: this assumes i386.md. */
+/* { dg-final { scan-assembler "ret" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
new file mode 100644
index 0000000..ab92004
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
@@ -0,0 +1,117 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-into_cfglayout" } */
+
+/* Lightly-modified dump of test.c.226r.vregs for x86_64. */
+
+#include "test_1.h"
+
+int __RTL (startwith ("into_cfglayout")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* The conversion to cfglayout should eliminate unconditional jump
+ instructions... */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "barrier" "into_cfglayout" } } */
+
+/* ...but conditional jumps should be preserved. */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
new file mode 100644
index 0000000..d23cca4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
@@ -0,0 +1,111 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.265r.asmcons for x86_64. */
+
+#include "test_1.h"
+
+int __RTL (startwith ("ira")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that IRA was run. */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
new file mode 100644
index 0000000..4ba3d6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
@@ -0,0 +1,110 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.274r.split2 for x86_64. */
+
+int __RTL (startwith ("pro_and_epilogue")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI ax [90])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (plus:SI (reg:SI ax [90])
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI ax [91])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (neg:SI (reg:SI ax [91])))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ (cnote 31 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that the prologue and epilogue were added. */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } } */
+
+/* We expect a jump_insn to "simple_return". */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } } */
+
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c
new file mode 100644
index 0000000..ac0ebe4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c
@@ -0,0 +1,105 @@
+/* { dg-do run { target x86_64-*-* } } */
+
+/* Verify that we can have multiple __RTL functions in one test case.
+ Each of these __RTL functions returns a const, dumped immediately after
+ expand. */
+
+extern void abort (void);
+
+int __RTL (startwith ("vregs")) test_return_42 (void)
+{
+ /* C code:
+ return 42; */
+(function "test_return_42"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_return_42"
+}
+
+int __RTL (startwith ("vregs")) test_return_43 (void)
+{
+ /* C code:
+ return 43; */
+(function "test_return_43"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 43)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_return_43"
+}
+
+int __RTL (startwith ("vregs")) test_return_44 (void)
+{
+ /* C code:
+ return 44; */
+(function "test_return_44"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 44)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_return_44"
+}
+
+int main (void)
+{
+ if (test_return_42 () != 42)
+ abort ();
+ if (test_return_43 () != 43)
+ abort ();
+ if (test_return_44 () != 44)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
new file mode 100644
index 0000000..8753809
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
@@ -0,0 +1,39 @@
+/* { dg-do run { target x86_64-*-* } } */
+
+extern void abort (void);
+
+int __RTL (startwith ("vregs")) test_returning_constant (void)
+{
+ /* C code:
+ return 42; */
+(function "test_returning_constant"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_returning_constant"
+}
+
+int main (void)
+{
+ if (test_returning_constant () != 42)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
new file mode 100644
index 0000000..603caa3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
@@ -0,0 +1,42 @@
+/* { dg-do run { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-fwprop1 -O2" } */
+
+extern void abort (void);
+
+int __RTL (startwith ("fwprop1")) test_returning_constant (void)
+{
+ /* C code:
+ return 42; */
+(function "test_returning_constant"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ <retval> ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 9 (set (reg/i:SI ax)
+ (const_int 42)) "../../src/test-return-const.c":4
+ (expr_list:REG_DEAD (reg:SI %0 [ <retval> ])))
+ (cinsn 10 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_returning_constant"
+}
+
+/* Verify that insn 5 is eliminated. */
+/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
+/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
+
+int main (void)
+{
+ if (test_returning_constant () != 42)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
new file mode 100644
index 0000000..b4d1e6d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
@@ -0,0 +1,101 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+ This is a dump of test.c from immediately after "expand", for x86_64. */
+
+int __RTL test_1 (int i, int j, int k)
+{
+ /*
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+ */
+(function "test_1"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
new file mode 100644
index 0000000..a783ea8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
@@ -0,0 +1,16 @@
+/* Shared test code for the various __RTL tests of test_1 that
+ start at different passes. */
+
+extern void abort (void);
+extern int test_1 (int i, int j, int k);
+
+int main (void)
+{
+ if (test_1 (0, 0, 3) != -3)
+ abort ();
+
+ if (test_1 (0, 1, 3) != 7)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
new file mode 100644
index 0000000..f6eb1c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
@@ -0,0 +1,70 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+
+extern void abort (void);
+
+int __RTL (startwith ("vregs")) times_two (int i)
+{
+ /* C function:
+ return i * 2; */
+(function "times_two"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ]))
+ ) ;; param "i"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
+}
+
+int main (void)
+{
+ if (times_two (0) != 0)
+ abort ();
+
+ if (times_two (1) != 2)
+ abort ();
+
+ if (times_two (100) != 200)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
new file mode 100644
index 0000000..1321eaf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
@@ -0,0 +1,54 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+int __RTL (startwith ("rtl-dfinit")) times_two (int i)
+{
+ /* C function:
+ return i * 2; */
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2)
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3)
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3)
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4)
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
+}
+
+/* Verify that the dataflow information matches what cc1 would have
+ generated. In particular, in earlier versions of the RTL
+ frontend, the exit block use of reg 0 (ax) wasn't picked up
+ on, due to not setting up crtl->return_rtx based on
+ DECL_RESULT (fndecl). */
+
+/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+
+/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
new file mode 100644
index 0000000..50d90dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
@@ -0,0 +1,112 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-vregs" } */
+
+/* Lightly-modified dump of test.c.225r.expand for x86_64. */
+
+#include "test_1.h"
+
+int __RTL (startwith ("vregs")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame". */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } } */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } } */
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Add "__RTL" to cc1 (v5)
2016-11-18 21:02 ` [PATCH] Add "__RTL" to cc1 (v5) David Malcolm
@ 2016-11-18 22:14 ` Joseph Myers
2016-11-18 22:46 ` [PATCH] Handle EOF in c_parser_parse_rtl_body David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Joseph Myers @ 2016-11-18 22:14 UTC (permalink / raw)
To: David Malcolm; +Cc: Richard Biener, Jan Hubicka, GCC Patches
On Fri, 18 Nov 2016, David Malcolm wrote:
> + /* Consume all tokens, up to the closing brace, handling
> + matching pairs of braces in the rtl dump. */
> + int num_open_braces = 1;
> + while (1)
> + {
> + switch (c_parser_peek_token (parser)->type)
> + {
> + case CPP_OPEN_BRACE:
> + num_open_braces++;
> + break;
> + case CPP_CLOSE_BRACE:
> + if (--num_open_braces == 0)
> + goto found_closing_brace;
> + break;
> + default:
> + break;
> + }
> + c_parser_consume_token (parser);
> + }
What if you have an EOF without the close brace being found? I'd expect
you to hit the
gcc_assert (parser->tokens[0].type != CPP_EOF);
in c_parser_consume_token.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Handle EOF in c_parser_parse_rtl_body
2016-11-18 22:14 ` Joseph Myers
@ 2016-11-18 22:46 ` David Malcolm
0 siblings, 0 replies; 78+ messages in thread
From: David Malcolm @ 2016-11-18 22:46 UTC (permalink / raw)
To: Joseph Myers; +Cc: Richard Biener, Jan Hubicka, GCC Patches, David Malcolm
On Fri, 2016-11-18 at 22:13 +0000, Joseph Myers wrote:
> On Fri, 18 Nov 2016, David Malcolm wrote:
>
> > + /* Consume all tokens, up to the closing brace, handling
> > + matching pairs of braces in the rtl dump. */
> > + int num_open_braces = 1;
> > + while (1)
> > + {
> > + switch (c_parser_peek_token (parser)->type)
> > + {
> > + case CPP_OPEN_BRACE:
> > + num_open_braces++;
> > + break;
> > + case CPP_CLOSE_BRACE:
> > + if (--num_open_braces == 0)
> > + goto found_closing_brace;
> > + break;
> > + default:
> > + break;
> > + }
> > + c_parser_consume_token (parser);
> > + }
>
> What if you have an EOF without the close brace being found? I'd
> expect
> you to hit the
>
> gcc_assert (parser->tokens[0].type != CPP_EOF);
>
> in c_parser_consume_token.
Oops; thanks. Here's a patch on top of v5 that (I hope) addresses that.
gcc/c/ChangeLog:
* c-parser.c (c_parser_parse_rtl_body): Handle CPP_EOF.
gcc/testsuite/ChangeLog:
* gcc.dg/rtl/truncated-rtl-file.c: New test case.
---
gcc/c/c-parser.c | 4 ++++
gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c | 2 ++
2 files changed, 6 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index d645d29..fef882a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -18326,6 +18326,10 @@ c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
if (--num_open_braces == 0)
goto found_closing_brace;
break;
+ case CPP_EOF:
+ error_at (start_loc, "no closing brace");
+ free (start_with_pass);
+ return;
default:
break;
}
diff --git a/gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c b/gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c
new file mode 100644
index 0000000..4dd8214
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c
@@ -0,0 +1,2 @@
+void __RTL test (void)
+{ /* { dg-error "no closing brace" } */
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] (approved) Add some functions for use by the RTL frontend.
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
` (3 preceding siblings ...)
2016-11-11 20:44 ` [PATCH 9/9] Add "__RTL" to cc1 (v4) David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-11-23 20:11 ` Jeff Law
2016-11-11 20:44 ` [PATCH 8/9] Introduce class function_reader (v4) David Malcolm
` (3 subsequent siblings)
8 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
An earlier version of this was approved by Bernd as:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00280.html
and the changes since then probably fall under the "obvious" rule.
gcc/ChangeLog:
* read-md.c (rtx_reader::require_char): New method.
(require_char_ws): Convert from function to...
(rtx_reader::require_char_ws): ...method.
(rtx_reader::require_word_ws): New method.
* read-md.h (rtx_reader::require_char): New method decl.
(require_char_ws): Remove global decl in favor of...
(rtx_reader::require_char_ws): ...new method decl.
(rtx_reader::require_word_ws): New method decl.
(rtx_reader::peek_char): New method decl.
---
gcc/read-md.c | 35 ++++++++++++++++++++++++++++++++++-
gcc/read-md.h | 5 ++++-
2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 6fe2600..095075f 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -340,17 +340,40 @@ read_skip_spaces (void)
}
}
+/* Consume the next character, issuing a fatal error if it is not
+ EXPECTED. */
+
+void
+rtx_reader::require_char (char expected)
+{
+ int ch = read_char ();
+ if (ch != expected)
+ fatal_expected_char (expected, ch);
+}
+
/* Consume any whitespace, then consume the next non-whitespace
character, issuing a fatal error if it is not EXPECTED. */
void
-require_char_ws (char expected)
+rtx_reader::require_char_ws (char expected)
{
int ch = read_skip_spaces ();
if (ch != expected)
fatal_expected_char (expected, ch);
}
+/* Consume any whitespace, then consume the next word (as per read_name),
+ issuing a fatal error if it is not EXPECTED. */
+
+void
+rtx_reader::require_word_ws (const char *expected)
+{
+ struct md_name name;
+ read_name (&name);
+ if (strcmp (name.string, expected))
+ fatal_with_file_and_line ("missing '%s'", expected);
+}
+
/* Read the next character from the file. */
int
@@ -386,6 +409,16 @@ rtx_reader::unread_char (int ch)
ungetc (ch, m_read_md_file);
}
+/* Peek at the next character from the file without consuming it. */
+
+int
+rtx_reader::peek_char (void)
+{
+ int ch = read_char ();
+ unread_char (ch);
+ return ch;
+}
+
/* Read an rtx code name into NAME. It is terminated by any of the
punctuation chars of rtx printed syntax. */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 996b514..06b89b4 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -116,6 +116,10 @@ class rtx_reader
char *read_braced_string ();
char *read_string (int star_if_braced);
void read_skip_construct (int depth, file_location loc);
+ void require_char (char expected);
+ void require_char_ws (char expected);
+ void require_word_ws (const char *expected);
+ int peek_char (void);
void set_md_ptr_loc (const void *ptr, const char *filename, int lineno);
const struct ptr_loc *get_md_ptr_loc (const void *ptr);
@@ -269,7 +273,6 @@ extern void fatal_with_file_and_line (const char *, ...)
ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
extern void fatal_expected_char (int, int) ATTRIBUTE_NORETURN;
extern int read_skip_spaces (void);
-extern void require_char_ws (char expected);
extern int n_comma_elts (const char *);
extern const char *scan_comma_elt (const char **);
extern void upcase_string (char *);
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8/9] Introduce class function_reader (v4)
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
` (4 preceding siblings ...)
2016-11-11 20:44 ` [PATCH 4/9] (approved) Add some functions for use by the RTL frontend David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-11-23 20:15 ` Bernd Schmidt
2016-12-01 14:40 ` Bernd Schmidt
2016-11-11 20:44 ` [PATCH 1/9] print_rtx: implement support for reuse IDs (v2) David Malcolm
` (2 subsequent siblings)
8 siblings, 2 replies; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Changed in v4:
- error-handling changes split out into a separate patch
- rewritten the loader to use the new "compact" dump format
- support for reuse_rtx in loader
- handling of params, DECL_RTL and DECL_RTL_INCOMING
- moved target-dependent selftests to target-specific code
(aarch64.c and i386.c)
Link to earlier version of the patch:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00267.html
gcc/ChangeLog:
* Makefile.in (OBJS): Add read-md.o, read-rtl.o,
read-rtl-function.o, and selftest-rtl.o.
* config/aarch64/aarch64.c: Include selftest.h and
selftest-rtl.h.
(selftest::aarch64_test_loading_full_dump): New function.
(selftest::aarch64_run_selftests): New function.
(TARGET_RUN_TARGET_SELFTESTS): Wire it up to
selftest::aarch64_run_selftests.
* config/i386/i386.c
(selftest::ix86_test_loading_dump_fragment_1): New function.
(selftest::ix86_test_loading_call_insn): New function.
(selftest::ix86_test_loading_full_dump): New function.
(selftest::ix86_test_loading_unspec): New function.
(selftest::ix86_run_selftests): Call the new functions.
* emit-rtl.c (maybe_set_max_label_num): New function.
* emit-rtl.h (maybe_set_max_label_num): New decl.
* function-tests.c (selftest::verify_three_block_rtl_cfg): Remove
"static".
* function.c (instantiate_decls): Guard call to
instantiate_decls_1 with if (DECL_INITIAL (fndecl)).
* gensupport.c (gen_reader::gen_reader): Pass "false"
for new "compact" param of rtx_reader.
* print-rtl.c (rtx_writer::print_rtx_operand): Print "(nil)"
rather than an empty string for NULL strings.
* read-md.c: Potentially include config.h rather than bconfig.h.
(md_reader::read_name): Rename to...
(md_reader::read_name_1): ...this, adding "out_loc" param,
and converting "missing name or number" to returning false, rather
than failing.
(md_reader::read_name): Reimplement in terms of read_name_1.
(md_reader::read_name_or_nil): New function.
(md_reader::read_string): Handle "(nil)" by returning NULL.
(md_reader::md_reader): Add new param "compact".
* read-md.h (md_reader::md_reader): Add new param "compact".
(md_reader::is_compact): New accessor.
(md_reader::read_name): Convert return type from void to
file_location.
(md_reader::read_name_or_nil): New decl.
(md_reader::read_name_1): New decl.
(md_reader::m_compact): New field.
(noop_reader::noop_reader): Pass "false" for new "compact" param
of rtx_reader.
(rtx_reader::rtx_reader): Add new "compact" param.
(rtx_reader::read_rtx_operand): Make virtual and convert return
type from void to rtx.
(rtx_reader::read_until): New decl.
(rtx_reader::handle_any_trailing_information): New virtual
function.
(rtx_reader::postprocess): New virtual function.
(rtx_reader::m_in_call_function_usage): New field.
(rtx_reader::m_reuse_rtx_by_id): New field.
* read-rtl-function.c: New file.
* read-rtl-function.h: New file.
* read-rtl.c: Potentially include config.h rather than bconfig.h.
For host, include function.h, memmodel.h, and emit-rtl.h.
(one_time_initialization): New function.
(find_code): Handle insn codes in compact dumps.
(apply_subst_iterator): Wrap with #ifdef GENERATOR_FILE.
(bind_subst_iter_and_attr): Likewise.
(add_condition_to_string): Likewise.
(add_condition_to_rtx): Likewise.
(apply_attribute_uses): Likewise.
(add_current_iterators): Likewise.
(apply_iterators): Likewise.
(initialize_iterators): Guard usage of apply_subst_iterator with
#ifdef GENERATOR_FILE.
(read_conditions): Wrap with #ifdef GENERATOR_FILE.
(md_reader::read_mapping): Likewise.
(add_define_attr_for_define_subst): Likewise.
(add_define_subst_attr): Likewise.
(read_subst_mapping): Likewise.
(check_code_iterator): Likewise.
(rtx_reader::read_rtx): Likewise. Move one-time initialization
logic to...
(one_time_initialization): New function.
(rtx_reader::read_until): New method.
(read_flags): New function.
(parse_reg_note_name): New function.
(rtx_reader::read_rtx_code): Initialize "iterator" to NULL.
Call one_time_initialization. Handle reuse_rtx ids.
Wrap iterator lookup within #ifdef GENERATOR_FILE.
Add parsing support for RTL dumps, mirroring the special-cases in
print_rtx, by calling read_flags, reading REG_NOTE names, INSN_UID
values, and calling handle_any_trailing_information.
(rtx_reader::read_rtx_operand): Convert return type from void
to rtx, returning return_rtx. Handle case 'e'. When on host,
reallocate XSTR and XTMPL fields in the GC-managed heap.
(rtx_reader::read_nested_rtx): Handle dumps in which trailing
"(nil)" values were omitted. Call the postprocess vfunc on the
return_rtx.
(rtx_reader::rtx_reader): Add new "compact" param and pass to base
class ctor. Initialize m_in_call_function_usage.
* rtl-tests.c (selftest::test_uncond_jump): Call
set_new_first_and_last_insn.
* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
* selftest-rtl.c: New file.
* selftest-rtl.h (class selftest::rtl_dump_test): New class.
(selftest::get_insn_by_uid): New decl.
(selftest::verify_three_block_rtl_cfg): New decl.
* selftest-run-tests.c (selftest::run_tests): Call
read_rtl_function_c_tests.
* selftest.h (selftest::read_rtl_function_c_tests): New decl.
* tree-dfa.c (ssa_default_def): Return NULL_TREE for rtl function
dumps.
gcc/testsuite/ChangeLog:
* selftests/aarch64: New subdirectory.
* selftests/aarch64/times-two.rtl: New file.
* selftests/asr_div1.rtl: New file.
* selftests/bb-index.rtl: New file.
* selftests/cfg-test.rtl: New file.
* selftests/const-int.rtl: New file.
* selftests/example-labels.rtl: New file.
* selftests/insn-with-mode.rtl: New file.
* selftests/jump-to-label-ref.rtl: New file.
* selftests/jump-to-return.rtl: New file.
* selftests/jump-to-simple-return.rtl: New file.
* selftests/note-insn-deleted.rtl: New file.
* selftests/note_insn_basic_block.rtl: New file.
* selftests/simple-cse.rtl: New file.
* selftests/symbol-ref.rtl: New file.
* selftests/x86_64: New subdirectory.
* selftests/x86_64/call-insn.rtl: New file.
* selftests/x86_64/copy-hard-reg-into-frame.rtl: New file.
* selftests/x86_64/times-two.rtl: New file.
* selftests/x86_64/unspec.rtl: New file.
---
gcc/Makefile.in | 4 +
gcc/config/aarch64/aarch64.c | 49 +
gcc/config/i386/i386.c | 207 ++
gcc/emit-rtl.c | 13 +
gcc/emit-rtl.h | 2 +
gcc/function-tests.c | 2 +-
gcc/function.c | 3 +-
gcc/gensupport.c | 2 +-
gcc/print-rtl.c | 2 +-
gcc/read-md.c | 59 +-
gcc/read-md.h | 29 +-
gcc/read-rtl-function.c | 2124 ++++++++++++++++++++
gcc/read-rtl-function.h | 36 +
gcc/read-rtl.c | 263 ++-
gcc/rtl-tests.c | 1 +
gcc/rtl.h | 2 +
gcc/selftest-rtl.c | 82 +
gcc/selftest-rtl.h | 19 +
gcc/selftest-run-tests.c | 1 +
gcc/selftest.h | 1 +
gcc/testsuite/selftests/aarch64/times-two.rtl | 36 +
gcc/testsuite/selftests/asr_div1.rtl | 24 +
gcc/testsuite/selftests/bb-index.rtl | 8 +
gcc/testsuite/selftests/cfg-test.rtl | 37 +
gcc/testsuite/selftests/const-int.rtl | 20 +
gcc/testsuite/selftests/example-labels.rtl | 8 +
gcc/testsuite/selftests/insn-with-mode.rtl | 7 +
gcc/testsuite/selftests/jump-to-label-ref.rtl | 17 +
gcc/testsuite/selftests/jump-to-return.rtl | 11 +
gcc/testsuite/selftests/jump-to-simple-return.rtl | 11 +
gcc/testsuite/selftests/note-insn-deleted.rtl | 5 +
gcc/testsuite/selftests/note_insn_basic_block.rtl | 9 +
gcc/testsuite/selftests/simple-cse.rtl | 16 +
gcc/testsuite/selftests/symbol-ref.rtl | 13 +
gcc/testsuite/selftests/x86_64/call-insn.rtl | 17 +
.../selftests/x86_64/copy-hard-reg-into-frame.rtl | 15 +
gcc/testsuite/selftests/x86_64/times-two.rtl | 51 +
gcc/testsuite/selftests/x86_64/unspec.rtl | 20 +
gcc/tree-dfa.c | 5 +
39 files changed, 3200 insertions(+), 31 deletions(-)
create mode 100644 gcc/read-rtl-function.c
create mode 100644 gcc/read-rtl-function.h
create mode 100644 gcc/selftest-rtl.c
create mode 100644 gcc/testsuite/selftests/aarch64/times-two.rtl
create mode 100644 gcc/testsuite/selftests/asr_div1.rtl
create mode 100644 gcc/testsuite/selftests/bb-index.rtl
create mode 100644 gcc/testsuite/selftests/cfg-test.rtl
create mode 100644 gcc/testsuite/selftests/const-int.rtl
create mode 100644 gcc/testsuite/selftests/example-labels.rtl
create mode 100644 gcc/testsuite/selftests/insn-with-mode.rtl
create mode 100644 gcc/testsuite/selftests/jump-to-label-ref.rtl
create mode 100644 gcc/testsuite/selftests/jump-to-return.rtl
create mode 100644 gcc/testsuite/selftests/jump-to-simple-return.rtl
create mode 100644 gcc/testsuite/selftests/note-insn-deleted.rtl
create mode 100644 gcc/testsuite/selftests/note_insn_basic_block.rtl
create mode 100644 gcc/testsuite/selftests/simple-cse.rtl
create mode 100644 gcc/testsuite/selftests/symbol-ref.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/unspec.rtl
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c265893..73d12dc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1407,6 +1407,9 @@ OBJS = \
print-rtl-function.o \
print-tree.o \
profile.o \
+ read-md.o \
+ read-rtl.o \
+ read-rtl-function.o \
real.o \
realmpfr.o \
recog.o \
@@ -1434,6 +1437,7 @@ OBJS = \
sel-sched-ir.o \
sel-sched-dump.o \
sel-sched.o \
+ selftest-rtl.o \
selftest-run-tests.o \
sese.o \
shrink-wrap.o \
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b7d4640..e1ab83b 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -64,6 +64,8 @@
#include "sched-int.h"
#include "target-globals.h"
#include "common/common-target.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
/* This file should be included last. */
#include "target-def.h"
@@ -14168,6 +14170,48 @@ aarch64_optab_supported_p (int op, machine_mode mode1, machine_mode,
}
}
+/* Target-specific selftests. */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that the RTL loader copes a dump from print_rtx_function.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+aarch64_test_loading_full_dump ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times-two.rtl"));
+
+ ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+ rtx_insn *insn_15 = get_insn_by_uid (15);
+ ASSERT_EQ (INSN, GET_CODE (insn_15));
+ ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+ /* Verify crtl->return_rtx. */
+ ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+ ASSERT_EQ (0, REGNO (crtl->return_rtx));
+ ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Run all target-specific selftests. */
+
+static void
+aarch64_run_selftests (void)
+{
+ aarch64_test_loading_full_dump ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST aarch64_address_cost
@@ -14502,6 +14546,11 @@ aarch64_optab_supported_p (int op, machine_mode mode1, machine_mode,
#undef TARGET_OMIT_STRUCT_RETURN_REG
#define TARGET_OMIT_STRUCT_RETURN_REG true
+#if CHECKING_P
+#undef TARGET_RUN_TARGET_SELFTESTS
+#define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
+#endif /* #if CHECKING_P */
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-aarch64.h"
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 6c608e0..0dda786 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -50672,6 +50672,206 @@ ix86_test_dumping_memory_blockage ()
" ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
}
+/* Verify loading an RTL dump; specifically a dump of copying
+ a param on x86_64 from a hard reg into the frame.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_dump_fragment_1 ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("x86_64/copy-hard-reg-into-frame.rtl"));
+
+ rtx_insn *insn = get_insn_by_uid (1);
+
+ /* The block structure and indentation here is purely for
+ readability; it mirrors the structure of the rtx. */
+ tree mem_expr;
+ {
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (SET, GET_CODE (pat));
+ {
+ rtx dest = SET_DEST (pat);
+ ASSERT_EQ (MEM, GET_CODE (dest));
+ /* Verify the "/c" was parsed. */
+ ASSERT_TRUE (RTX_FLAG (dest, call));
+ ASSERT_EQ (SImode, GET_MODE (dest));
+ {
+ rtx addr = XEXP (dest, 0);
+ ASSERT_EQ (PLUS, GET_CODE (addr));
+ ASSERT_EQ (DImode, GET_MODE (addr));
+ {
+ rtx lhs = XEXP (addr, 0);
+ ASSERT_EQ (REG, GET_CODE (lhs));
+ /* Verify the "/f" was parsed. */
+ ASSERT_TRUE (RTX_FLAG (lhs, frame_related));
+ ASSERT_EQ (DImode, GET_MODE (lhs));
+ }
+ {
+ rtx rhs = XEXP (addr, 1);
+ ASSERT_EQ (CONST_INT, GET_CODE (rhs));
+ ASSERT_EQ (-4, INTVAL (rhs));
+ }
+ }
+ /* Verify the "[1 i+0 S4 A32]" was parsed. */
+ ASSERT_EQ (1, MEM_ALIAS_SET (dest));
+ /* "i" should have been handled by synthesizing a global int
+ variable named "i". */
+ mem_expr = MEM_EXPR (dest);
+ ASSERT_NE (mem_expr, NULL);
+ ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
+ ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
+ ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
+ ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
+ /* "+0". */
+ ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
+ ASSERT_EQ (0, MEM_OFFSET (dest));
+ /* "S4". */
+ ASSERT_EQ (4, MEM_SIZE (dest));
+ /* "A32. */
+ ASSERT_EQ (32, MEM_ALIGN (dest));
+ }
+ {
+ rtx src = SET_SRC (pat);
+ ASSERT_EQ (REG, GET_CODE (src));
+ ASSERT_EQ (SImode, GET_MODE (src));
+ ASSERT_EQ (5, REGNO (src));
+ tree reg_expr = REG_EXPR (src);
+ /* "i" here should point to the same var as for the MEM_EXPR. */
+ ASSERT_EQ (reg_expr, mem_expr);
+ }
+ }
+}
+
+/* Verify that the RTL loader copes with a call_insn dump.
+ This test is target-specific since the dump contains a target-specific
+ hard reg name. */
+
+static void
+ix86_test_loading_call_insn ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call-insn.rtl"));
+
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (CALL_INSN, GET_CODE (insn));
+
+ /* "/j". */
+ ASSERT_TRUE (RTX_FLAG (insn, jump));
+
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
+
+ /* Verify REG_NOTES. */
+ {
+ /* "(expr_list:REG_CALL_DECL". */
+ ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn)));
+ rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES (insn));
+ ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
+
+ /* "(expr_list:REG_EH_REGION (const_int 0 [0])". */
+ rtx_expr_list *note1 = note0->next ();
+ ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
+
+ ASSERT_EQ (NULL, note1->next ());
+ }
+
+ /* Verify CALL_INSN_FUNCTION_USAGE. */
+ {
+ /* "(expr_list:DF (use (reg:DF 21 xmm0))". */
+ rtx_expr_list *usage
+ = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn));
+ ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
+ ASSERT_EQ (DFmode, GET_MODE (usage));
+ ASSERT_EQ (USE, GET_CODE (usage->element ()));
+ ASSERT_EQ (NULL, usage->next ());
+ }
+}
+
+/* Verify that the RTL loader copes a dump from print_rtx_function.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_full_dump ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times-two.rtl"));
+
+ ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+ rtx_insn *insn_7 = get_insn_by_uid (7);
+ ASSERT_EQ (INSN, GET_CODE (insn_7));
+ ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
+
+ rtx_insn *insn_15 = get_insn_by_uid (15);
+ ASSERT_EQ (INSN, GET_CODE (insn_15));
+ ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+ /* Verify crtl->return_rtx. */
+ ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+ ASSERT_EQ (0, REGNO (crtl->return_rtx));
+ ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Verify that the RTL loader copes with UNSPEC and UNSPEC_VOLATILE insns.
+ In particular, verify that it correctly loads the 2nd operand.
+ This test is target-specific since these are machine-specific
+ operands (and enums). */
+
+static void
+ix86_test_loading_unspec ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/unspec.rtl"));
+
+ ASSERT_STREQ ("test_unspec", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ /* Test of an UNSPEC. */
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (INSN, GET_CODE (insn));
+ rtx set = single_set (insn);
+ ASSERT_NE (NULL, set);
+ rtx dst = SET_DEST (set);
+ ASSERT_EQ (MEM, GET_CODE (dst));
+ rtx src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC, GET_CODE (src));
+ ASSERT_EQ (BLKmode, GET_MODE (src));
+ ASSERT_EQ (UNSPEC_MEMORY_BLOCKAGE, XINT (src, 1));
+
+ rtx v0 = XVECEXP (src, 0, 0);
+
+ /* Verify that the two uses of the first SCRATCH have pointer
+ equality. */
+ rtx scratch_a = XEXP (dst, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_a));
+
+ rtx scratch_b = XEXP (v0, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_b));
+
+ ASSERT_EQ (scratch_a, scratch_b);
+
+ /* Verify that the two mems are thus treated as equal. */
+ ASSERT_TRUE (rtx_equal_p (dst, v0));
+
+ /* Verify the the insn is recognized. */
+ ASSERT_NE(-1, recog_memoized (insn));
+
+ /* Test of an UNSPEC_VOLATILE, which has its own enum values. */
+ insn = NEXT_INSN (insn);
+ ASSERT_EQ (INSN, GET_CODE (insn));
+
+ set = single_set (insn);
+ ASSERT_NE (NULL, set);
+
+ src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC_VOLATILE, GET_CODE (src));
+ ASSERT_EQ (UNSPECV_RDTSCP, XINT (src, 1));
+}
+
/* Run all target-specific selftests. */
static void
@@ -50679,6 +50879,13 @@ ix86_run_selftests (void)
{
ix86_test_dumping_hard_regs ();
ix86_test_dumping_memory_blockage ();
+
+ /* Various tests of loading RTL dumps, here because they contain
+ ix86-isms (e.g. names of hard regs). */
+ ix86_test_loading_dump_fragment_1 ();
+ ix86_test_loading_call_insn ();
+ ix86_test_loading_full_dump ();
+ ix86_test_loading_unspec ();
}
} // namespace selftest
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 50cd388..179a91f 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1371,6 +1371,19 @@ maybe_set_first_label_num (rtx_code_label *x)
if (CODE_LABEL_NUMBER (x) < first_label_num)
first_label_num = CODE_LABEL_NUMBER (x);
}
+
+/* For use by the RTL function loader, when mingling with normal
+ functions.
+ Ensure that label_num is greater than the label num of X, to avoid
+ duplicate labels in the generated assembler. */
+
+void
+maybe_set_max_label_num (rtx_code_label *x)
+{
+ if (CODE_LABEL_NUMBER (x) >= label_num)
+ label_num = CODE_LABEL_NUMBER (x) + 1;
+}
+
\f
/* Return a value representing some low-order bits of X, where the number
of low-order bits is given by MODE. Note that no conversion is done
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 21c180b..01f16a7 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -507,4 +507,6 @@ extern int get_mem_align_offset (rtx, unsigned int);
MODE and adjusted by OFFSET. */
extern rtx widen_memory_access (rtx, machine_mode, HOST_WIDE_INT);
+extern void maybe_set_max_label_num (rtx_code_label *x);
+
#endif /* GCC_EMIT_RTL_H */
diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index b0c44cf..90fec6d 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -421,7 +421,7 @@ verify_three_block_gimple_cfg (function *fun)
/* As above, but additionally verify the RTL insns are sane. */
-static void
+void
verify_three_block_rtl_cfg (function *fun)
{
verify_three_block_cfg (fun);
diff --git a/gcc/function.c b/gcc/function.c
index 0b1d168..2674321 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -1901,7 +1901,8 @@ instantiate_decls (tree fndecl)
instantiate_decl_rtl (DECL_RTL (DECL_VALUE_EXPR (decl)));
/* Now process all variables defined in the function or its subblocks. */
- instantiate_decls_1 (DECL_INITIAL (fndecl));
+ if (DECL_INITIAL (fndecl))
+ instantiate_decls_1 (DECL_INITIAL (fndecl));
FOR_EACH_LOCAL_DECL (cfun, ix, decl)
if (DECL_RTL_SET_P (decl))
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index c49ad6f..64378e3 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2233,7 +2233,7 @@ process_define_subst (void)
class gen_reader : public rtx_reader
{
public:
- gen_reader () : rtx_reader () {}
+ gen_reader () : rtx_reader (false) {}
void handle_unknown_directive (file_location, const char *);
};
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 3bbd395..77e6b05 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -577,7 +577,7 @@ rtx_writer::print_rtx_operand (const_rtx in_rtx, int idx)
string:
if (str == 0)
- fputs (" \"\"", m_outfile);
+ fputs (" (nil)", m_outfile);
else
fprintf (m_outfile, " (\"%s\")", str);
m_sawclose = 1;
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 6d9a1bd..a8462a6 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
#include "system.h"
#include "coretypes.h"
#include "errors.h"
@@ -424,8 +430,8 @@ md_reader::peek_char (void)
/* Read an rtx code name into NAME. It is terminated by any of the
punctuation chars of rtx printed syntax. */
-void
-md_reader::read_name (struct md_name *name)
+bool
+md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
{
int c;
size_t i;
@@ -463,8 +469,12 @@ md_reader::read_name (struct md_name *name)
c = read_char ();
}
+ unread_char (c);
+ *out_loc = get_current_location ();
+ read_char ();
+
if (i == 0)
- fatal_with_file_and_line ("missing name or number");
+ return false;
name->buffer[i] = 0;
name->string = name->buffer;
@@ -485,6 +495,36 @@ md_reader::read_name (struct md_name *name)
}
while (def);
}
+
+ return true;
+}
+
+/* Read an rtx code name into NAME. It is terminated by any of the
+ punctuation chars of rtx printed syntax. */
+
+file_location
+md_reader::read_name (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ fatal_with_file_and_line ("missing name or number");
+ return loc;
+}
+
+file_location
+md_reader::read_name_or_nil (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ {
+ file_location loc = get_current_location ();
+ read_skip_construct (0, loc);
+ /* Skip the ')'. */
+ read_char ();
+ name->buffer[0] = 0;
+ name->string = name->buffer;
+ }
+ return loc;
}
/* Subroutine of the string readers. Handles backslash escapes.
@@ -630,6 +670,14 @@ md_reader::read_string (int star_if_braced)
obstack_1grow (&m_string_obstack, '*');
stringbuf = read_braced_string ();
}
+ else if (saw_paren && c == 'n')
+ {
+ /* Handle (nil) by returning NULL. */
+ require_char ('i');
+ require_char ('l');
+ require_char_ws (')');
+ return NULL;
+ }
else
fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
@@ -924,8 +972,9 @@ md_reader::traverse_enum_types (htab_trav callback, void *info)
/* Constructor for md_reader. */
-md_reader::md_reader ()
-: m_toplevel_fname (NULL),
+md_reader::md_reader (bool compact)
+: m_compact (compact),
+ m_toplevel_fname (NULL),
m_base_dir (NULL),
m_read_md_file (NULL),
m_read_md_filename (NULL),
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 8910b75..1be0f5a 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -94,7 +94,7 @@ struct enum_type {
class md_reader
{
public:
- md_reader ();
+ md_reader (bool compact);
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
@@ -107,10 +107,13 @@ class md_reader
file_location get_current_location () const;
+ bool is_compact () const { return m_compact; }
+
/* Defined in read-md.c. */
int read_char (void);
void unread_char (int ch);
- void read_name (struct md_name *name);
+ file_location read_name (struct md_name *name);
+ file_location read_name_or_nil (struct md_name *);
void read_escape ();
char *read_quoted_string ();
char *read_braced_string ();
@@ -167,7 +170,12 @@ class md_reader
void handle_include (file_location loc);
void add_include_path (const char *arg);
+ bool read_name_1 (struct md_name *name, file_location *out_loc);
+
private:
+ /* Are we reading a compact dump? */
+ bool m_compact;
+
/* The name of the toplevel file that indirectly included
m_read_md_file. */
const char *m_toplevel_fname;
@@ -235,7 +243,7 @@ extern md_reader *md_reader_ptr;
class noop_reader : public md_reader
{
public:
- noop_reader () : md_reader () {}
+ noop_reader () : md_reader (false) {}
/* A dummy implementation which skips unknown directives. */
void handle_unknown_directive (file_location, const char *);
@@ -249,14 +257,25 @@ class noop_reader : public md_reader
class rtx_reader : public md_reader
{
public:
- rtx_reader ();
+ rtx_reader (bool compact);
~rtx_reader ();
bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
rtx read_rtx_code (const char *code_name);
- void read_rtx_operand (rtx return_rtx, int idx);
+ virtual rtx read_rtx_operand (rtx return_rtx, int idx);
rtx read_nested_rtx ();
rtx read_rtx_variadic (rtx form);
+ char *read_until (const char *terminator_chars, bool consume_terminator);
+
+ virtual void handle_any_trailing_information (rtx) {}
+ virtual rtx postprocess (rtx x) { return x; }
+
+ protected:
+ /* Analogous to rtx_writer's m_in_call_function_usage. */
+ bool m_in_call_function_usage;
+
+ /* Support for "reuse_rtx" directives. */
+ auto_vec<rtx> m_reuse_rtx_by_id;
};
/* Global singleton; constrast with md_reader_ptr above. */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
new file mode 100644
index 0000000..ff6c808
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,2124 @@
+/* read-rtl-function.c - Reader for RTL function dumps
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "toplev.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "varasm.h"
+#include "insn-addr.h"
+#include "read-rtl-function.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
+#include "insn-config.h"
+#include "recog.h"
+
+/* Forward decls. */
+class function_reader;
+class fixup;
+
+/* Edges are recorded when parsing the "insn-chain" directive,
+ and created at the end when all the blocks ought to exist.
+ This struct records an "edge-from" or "edge-to" directive seen
+ at LOC, which will be turned into an actual CFG edge once
+ the "insn-chain" is fully parsed. */
+
+struct deferred_edge
+{
+ deferred_edge (file_location loc, int src_bb_idx, int dest_bb_idx, int flags)
+ : m_loc (loc), m_src_bb_idx (src_bb_idx), m_dest_bb_idx (dest_bb_idx),
+ m_flags (flags)
+ {}
+
+ file_location m_loc;
+ int m_src_bb_idx;
+ int m_dest_bb_idx;
+ int m_flags;
+};
+
+/* Subclass of rtx_reader for reading function dumps. */
+
+class function_reader : public rtx_reader
+{
+ public:
+ function_reader (function_reader_policy *policy);
+ ~function_reader ();
+
+ /* Overridden vfuncs of class md_reader. */
+ void handle_unknown_directive (file_location, const char *) FINAL OVERRIDE;
+
+ /* Overridden vfuncs of class rtx_reader. */
+ rtx read_rtx_operand (rtx return_rtx, int idx) FINAL OVERRIDE;
+ void handle_any_trailing_information (rtx return_rtx) FINAL OVERRIDE;
+ rtx postprocess (rtx) FINAL OVERRIDE;
+
+ rtx_insn **get_insn_by_uid (int uid);
+ tree parse_mem_expr (const char *desc);
+
+ private:
+ void parse_function ();
+ void create_function ();
+ void parse_param ();
+ void parse_insn_chain ();
+ void parse_block ();
+ int parse_bb_idx ();
+ void parse_edge (basic_block block, bool from);
+ rtx_insn *parse_insn (file_location loc, const char *name);
+ void parse_cfg (file_location loc);
+ void parse_crtl (file_location loc);
+ void create_edges ();
+
+ int parse_enum_value (int num_values, const char *const *strings);
+
+ void read_rtx_operand_u (rtx return_rtx, int idx);
+ void read_rtx_operand_i_or_n (rtx return_rtx, int idx, char format_char);
+ rtx read_rtx_operand_r (rtx return_rtx);
+ rtx extra_parsing_for_operand_code_0 (rtx return_rtx, int idx);
+
+ void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid);
+
+ void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx);
+
+ void add_fixup_source_location (file_location loc, rtx insn,
+ int operand_idx,
+ const char *filename, int lineno);
+
+ void add_fixup_expr (file_location loc, rtx x,
+ const char *desc);
+
+ rtx consolidate_singletons (rtx x);
+ rtx parse_rtx ();
+ void maybe_read_location (int operand_idx, rtx insn);
+
+ void handle_insn_uids ();
+ void apply_fixups ();
+
+ private:
+ function_reader_policy *m_policy;
+ struct uid_hash : int_hash <int, -1, -2> {};
+ hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+ auto_vec<fixup *> m_fixups;
+ rtx_insn *m_first_insn;
+ auto_vec<tree> m_fake_scope;
+ char *m_name;
+ bool m_have_crtl_directive;
+ basic_block m_bb_to_insert_after;
+ auto_vec <deferred_edge> m_deferred_edges;
+ int m_highest_bb_idx;
+};
+
+/* Abstract base class for recording post-processing steps that must be
+ done after reading a .rtl file. */
+
+class fixup
+{
+ public:
+ fixup (file_location loc, rtx x)
+ : m_loc (loc), m_rtx (x)
+ {}
+ virtual ~fixup () {}
+
+ virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+ file_location m_loc;
+ rtx m_rtx;
+};
+
+/* An abstract subclass of fixup for post-processing steps that
+ act on a specific operand of a specific instruction. */
+
+class operand_fixup : public fixup
+{
+ public:
+ operand_fixup (file_location loc, rtx insn, int operand_idx)
+ : fixup (loc, insn), m_operand_idx (operand_idx)
+ {}
+
+ protected:
+ int m_operand_idx;
+};
+
+/* A concrete subclass of operand_fixup: fixup an rtx_insn *
+ field (NEXT_INSN/PREV_INSN) based on an integer UID. */
+
+class fixup_insn_uid : public operand_fixup
+{
+ public:
+ fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
+ : operand_fixup (loc, insn, operand_idx),
+ m_insn_uid (insn_uid)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_insn_uid;
+};
+
+/* A concrete subclass of operand_fixup: fix up a
+ NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+class fixup_note_insn_basic_block : public operand_fixup
+{
+ public:
+ fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
+ int bb_idx)
+ : operand_fixup (loc, insn, operand_idx),
+ m_bb_idx (bb_idx)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_bb_idx;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+ the expr of an rtx (REG or MEM) based on a textual dump. */
+
+class fixup_expr : public fixup
+{
+ public:
+ fixup_expr (file_location loc, rtx x, const char *desc)
+ : fixup (loc, x),
+ m_desc (xstrdup (desc))
+ {}
+
+ ~fixup_expr () { free (m_desc); }
+
+ void apply (function_reader *reader) const;
+
+ private:
+ char *m_desc;
+};
+
+/* Return a textual description of the given operand of the given rtx. */
+
+static const char *
+get_operand_name (rtx insn, int operand_idx)
+{
+ gcc_assert (is_a <rtx_insn *> (insn));
+ switch (operand_idx)
+ {
+ case 0:
+ return "PREV_INSN";
+ case 1:
+ return "NEXT_INSN";
+ default:
+ return NULL;
+ }
+}
+
+/* Fixup an rtx_insn * field (NEXT_INSN/PREV_INSN) based on an integer
+ UID. */
+
+void
+fixup_insn_uid::apply (function_reader *reader) const
+{
+ rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
+ if (insn_from_uid)
+ XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
+ else
+ {
+ const char *op_name = get_operand_name (m_rtx, m_operand_idx);
+ if (op_name)
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i (`%s') of insn %i",
+ m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
+ else
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i of insn %i",
+ m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
+ }
+}
+
+/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+void
+fixup_note_insn_basic_block::apply (function_reader */*reader*/) const
+{
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+ gcc_assert (bb);
+ NOTE_BASIC_BLOCK (m_rtx) = bb;
+}
+
+/* Fix up the expr of an rtx (REG or MEM) based on a textual dump. */
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+ tree expr = reader->parse_mem_expr (m_desc);
+ switch (GET_CODE (m_rtx))
+ {
+ case REG:
+ set_reg_attrs_for_decl_rtl (expr, m_rtx);
+ break;
+ case MEM:
+ set_mem_expr (m_rtx, expr);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Strip trailing whitespace from DESC. */
+
+static void
+strip_trailing_whitespace (char *desc)
+{
+ char *terminator = desc + strlen (desc);
+ while (desc < terminator)
+ {
+ terminator--;
+ if (ISSPACE (*terminator))
+ *terminator = '\0';
+ else
+ break;
+ }
+}
+
+/* Return the numeric value n for GET_NOTE_INSN_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+static int
+parse_note_insn_name (const char *string)
+{
+ for (int i = 0; i < NOTE_INSN_MAX; i++)
+ if (0 == strcmp (string, GET_NOTE_INSN_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
+}
+
+/* Return the register number for NAME, or return -1 if it isn't
+ recognized. */
+
+static int
+lookup_reg_by_dump_name (const char *name)
+{
+ for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (reg_names[i][0]
+ && ! strcmp (name, reg_names[i]))
+ return i;
+
+ /* Also lookup virtuals. */
+ if (!strcmp (name, "virtual-incoming-args"))
+ return VIRTUAL_INCOMING_ARGS_REGNUM;
+ if (!strcmp (name, "virtual-stack-vars"))
+ return VIRTUAL_STACK_VARS_REGNUM;
+ if (!strcmp (name, "virtual-stack-dynamic"))
+ return VIRTUAL_STACK_DYNAMIC_REGNUM;
+ if (!strcmp (name, "virtual-outgoing-args"))
+ return VIRTUAL_OUTGOING_ARGS_REGNUM;
+ if (!strcmp (name, "virtual-cfa"))
+ return VIRTUAL_CFA_REGNUM;
+ if (!strcmp (name, "virtual-preferred-stack-boundary"))
+ return VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM;
+ /* TODO: handle "virtual-reg-%d". */
+
+ /* In compact mode, pseudos are printed with a '%' sigil following
+ by the regno, offset by (LAST_VIRTUAL_REGISTER + 1), so that the
+ first non-virtual pseudo is dumped as "%0". */
+ if (name[0] == '%')
+ {
+ int dump_num = atoi (name + 1);
+ return dump_num + LAST_VIRTUAL_REGISTER + 1;
+ }
+
+ /* Not found. */
+ return -1;
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor. */
+
+function_reader::function_reader (function_reader_policy *policy)
+: rtx_reader (true),
+ m_policy (policy),
+ m_first_insn (NULL),
+ m_name (NULL),
+ m_have_crtl_directive (false),
+ m_bb_to_insert_after (NULL),
+ m_highest_bb_idx (EXIT_BLOCK)
+{
+}
+
+/* function_reader's destructor. */
+
+function_reader::~function_reader ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ delete f;
+
+ free (m_name);
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+
+ Require a top-level "function" elements, as emitted by
+ print_rtx_function, and parse it. */
+
+void
+function_reader::handle_unknown_directive (file_location start_loc,
+ const char *name)
+{
+ if (strcmp (name, "function"))
+ fatal_at (start_loc, "expected 'function'");
+
+ parse_function ();
+}
+
+/* Parse the output of print_rtx_function (or hand-written data in the
+ same format), having already parsed the "(function" heading, and
+ finishing immediately before the final ")".
+
+ The "param" and "crtl" clauses are optional. */
+
+void
+function_reader::parse_function ()
+{
+ m_name = xstrdup (read_string (0));
+
+ create_function ();
+
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ if (c == ')')
+ {
+ unread_char (c);
+ break;
+ }
+ unread_char (c);
+ require_char ('(');
+ file_location loc = get_current_location ();
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "param") == 0)
+ parse_param ();
+ else if (strcmp (directive.string, "insn-chain") == 0)
+ parse_insn_chain ();
+ else if (strcmp (directive.string, "crtl") == 0)
+ parse_crtl (loc);
+ else
+ fatal_with_file_and_line ("unrecognized directive: %s",
+ directive.string);
+ }
+
+ handle_insn_uids ();
+
+ apply_fixups ();
+
+ /* Rebuild the JUMP_LABEL field of any JUMP_INSNs in the chain, and the
+ LABEL_NUSES of any CODE_LABELs.
+
+ This has to happen after apply_fixups, since only after then do
+ LABEL_REFs have their label_ref_label set up. */
+ rebuild_jump_labels (get_insns ());
+
+ crtl->init_stack_alignment ();
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+ Create "cfun" and a decl for the function.
+ By default, every function decl is hardcoded as
+ int test_1 (int i, int j, int k);
+ Set up various other state:
+ - the cfg and basic blocks (edges are created later, *after* fixups
+ are applied).
+ - add the function to the callgraph. */
+
+void
+function_reader::create_function ()
+{
+ /* Currently we assume cfgrtl mode, rather than cfglayout mode. */
+ if (0)
+ cfg_layout_rtl_register_cfg_hooks ();
+ else
+ rtl_register_cfg_hooks ();
+
+ /* Create cfun. */
+ tree fn_name = get_identifier (m_name ? m_name : "test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+
+ current_function_decl = fndecl;
+
+ cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+ /* Do we need this to force cgraphunit.c to output the function? */
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_PRESERVE_P (fndecl) = 1;
+
+ /* Add to cgraph. */
+ {
+ /* cgraph_node::add_new_function does additional processing
+ based on symtab->state. We need to avoid it attempting to gimplify
+ things. Temporarily putting it in the PARSING state appears to
+ achieve this. */
+ enum symtab_state old_state = symtab->state;
+ symtab->state = PARSING;
+ cgraph_node::add_new_function (fndecl, true /*lowered*/);
+ /* Reset the state. */
+ symtab->state = old_state;
+ }
+
+ /* Create bare-bones cfg. This creates the entry and exit blocks. */
+ init_empty_tree_cfg_for_function (cfun);
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+ EXIT_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+ init_rtl_bb_info (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ init_rtl_bb_info (EXIT_BLOCK_PTR_FOR_FN (cfun));
+ m_bb_to_insert_after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+
+}
+
+/* Parse the content of a "param" directive, having already parsed the
+ "(param". Consume the trailing ')'. */
+
+void
+function_reader::parse_param ()
+{
+ require_char_ws ('"');
+ char *name = read_quoted_string ();
+
+ /* Lookup param by name. */
+ tree t_param = parse_mem_expr (name);
+ // TODO: what if not found?
+
+ /* Parse DECL_RTL. */
+ {
+ require_char_ws ('(');
+ require_word_ws ("DECL_RTL");
+ DECL_WRTL_CHECK (t_param)->decl_with_rtl.rtl = parse_rtx ();
+ require_char_ws (')');
+ }
+
+ /* Parse DECL_RTL_INCOMING. */
+ {
+ require_char_ws ('(');
+ require_word_ws ("DECL_RTL_INCOMING");
+ DECL_INCOMING_RTL (t_param) = parse_rtx ();
+ require_char_ws (')');
+ }
+
+ require_char_ws (')');
+}
+
+/* Parse zero or more child insn elements within an
+ "insn-chain" element. Consume the trailing ')'. */
+
+void
+function_reader::parse_insn_chain ()
+{
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ file_location loc = get_current_location ();
+ if (c == ')')
+ break;
+ else if (c == '(')
+ {
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "block") == 0)
+ parse_block ();
+ else
+ parse_insn (loc, directive.string);
+ }
+ else
+ fatal_at (loc, "expected '(' or ')'");
+ }
+
+ create_edges ();
+}
+
+/* Parse zero or more child directives (edges and insns) within a
+ "block" directive, having already parsed the "(block " heading.
+ Consume the trailing ')'. */
+
+void
+function_reader::parse_block ()
+{
+ /* Parse the index value from the dump. This will be an integer;
+ we don't support "entry" or "exit" here (unlike for edges). */
+ struct md_name name;
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+
+ /* The term "index" has two meanings for basic blocks in a CFG:
+ (a) the "index" field within struct basic_block_def.
+ (b) the index of a basic_block within the cfg's x_basic_block_info
+ vector, as accessed via BASIC_BLOCK_FOR_FN.
+
+ These can get out-of-sync when basic blocks are optimized away.
+ They get back in sync by "compact_blocks".
+ We reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
+ values in it for any missing basic blocks, so that (a) == (b) for
+ all of the blocks we create. The doubly-linked list of basic
+ blocks (next_bb/prev_bb) skips over these "holes". */
+
+ if (m_highest_bb_idx < bb_idx)
+ m_highest_bb_idx = bb_idx;
+
+ size_t new_size = m_highest_bb_idx + 1;
+ if (basic_block_info_for_fn (cfun)->length () < new_size)
+ vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
+
+ last_basic_block_for_fn (cfun) = new_size;
+
+ /* Create the basic block.
+
+ We can't call create_basic_block and use the regular RTL block-creation
+ hooks, since this creates NOTE_INSN_BASIC_BLOCK instances. We don't
+ want to do that; we want to use the notes we were provided with. */
+ basic_block bb = alloc_block ();
+ init_rtl_bb_info (bb);
+ bb->index = bb_idx;
+ bb->flags = BB_NEW | BB_RTL;
+ link_block (bb, m_bb_to_insert_after);
+ m_bb_to_insert_after = bb;
+
+ n_basic_blocks_for_fn (cfun)++;
+ SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
+ BB_SET_PARTITION (bb, BB_UNPARTITIONED);
+
+ /* Handle insns, edge-from and edge-to directives. */
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ file_location loc = get_current_location ();
+ if (c == ')')
+ break;
+ else if (c == '(')
+ {
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "edge-from") == 0)
+ parse_edge (bb, true);
+ else if (strcmp (directive.string, "edge-to") == 0)
+ parse_edge (bb, false);
+ else
+ {
+ rtx_insn *insn = parse_insn (loc, directive.string);
+ set_block_for_insn (insn, bb);
+ if (!BB_HEAD (bb))
+ BB_HEAD (bb) = insn;
+ BB_END (bb) = insn;
+ }
+ }
+ else
+ fatal_at (loc, "expected '(' or ')'");
+ }
+}
+
+/* Subroutine of function_reader::parse_edge.
+ Parse a basic block index, handling "entry" and "exit". */
+
+int
+function_reader::parse_bb_idx ()
+{
+ struct md_name name;
+ read_name (&name);
+ if (strcmp (name.string, "entry") == 0)
+ return ENTRY_BLOCK;
+ if (strcmp (name.string, "exit") == 0)
+ return EXIT_BLOCK;
+ return atoi (name.string);
+}
+
+/* Subroutine of parse_edge_flags.
+ Parse a token such as "FALLTHRU", converting to the flag value.
+ Issue an error if the token is unrecognized. */
+
+static int
+parse_edge_flag_token (const char *tok)
+{
+#define DEF_EDGE_FLAG(NAME,IDX) \
+ do { \
+ if (strcmp (tok, #NAME) == 0) \
+ return EDGE_##NAME; \
+ } while (0);
+#include "cfg-flags.def"
+#undef DEF_EDGE_FLAG
+ error ("unrecognized edge flag: '%s'", tok);
+ return 0;
+}
+
+/* Subroutine of function_reader::parse_edge.
+ Parse STR and convert to a flag value (or issue an error).
+ The parser uses strtok and hence modifiers STR in-place. */
+
+static int
+parse_edge_flags (char *str)
+{
+ int result = 0;
+
+ char *tok = strtok (str, "| ");
+ while (tok)
+ {
+ result |= parse_edge_flag_token (tok);
+ tok = strtok (NULL, "| ");
+ }
+
+ return result;
+}
+
+/* Parse an "edge-from" or "edge-to" directive within the "block"
+ directive for BLOCK, having already parsed the "(edge" heading.
+ Consume the final ")". Record the edge within m_deferred_edges. */
+
+void
+function_reader::parse_edge (basic_block block, bool from)
+{
+ gcc_assert (block);
+ int this_bb_idx = block->index;
+ file_location loc = get_current_location ();
+ int other_bb_idx = parse_bb_idx ();
+
+ /* "(edge-from 2)" means src = 2, dest = this_bb_idx, whereas
+ "(edge-to 3)" means src = this_bb_idx, dest = 3. */
+ int src_idx = from ? other_bb_idx : this_bb_idx;
+ int dest_idx = from ? this_bb_idx : other_bb_idx;
+
+ /* Optional "(flags)". */
+ int flags = 0;
+ int c = read_skip_spaces ();
+ if (c == '(')
+ {
+ require_word_ws ("flags");
+ require_char_ws ('"');
+ char *str = read_quoted_string ();
+ flags = parse_edge_flags (str);
+ require_char_ws (')');
+ }
+ else
+ unread_char (c);
+
+ require_char_ws (')');
+
+ if (0)
+ fprintf (stderr, "parse_edge: %i flags 0x%x \n",
+ other_bb_idx, flags);
+
+ /* This BB already exists, but the other BB might not yet.
+ For now, save the edges, and create them at the end of insn-chain
+ processing. */
+ /* For now, only process the (edge-from) to this BB, and (edge-to)
+ that go to the exit block; we don't yet verify that the edge-from
+ and edge-to directives are consistent. */
+ if (from || dest_idx == EXIT_BLOCK)
+ m_deferred_edges.safe_push (deferred_edge (loc, src_idx, dest_idx, flags));
+}
+
+/* Parse rtx instructions by calling read_rtx_code, calling
+ set_first_insn and set_last_insn as appropriate, and
+ adding the insn to the insn chain.
+ Consume the trailing ')'. */
+
+rtx_insn *
+function_reader::parse_insn (file_location start_loc, const char *name)
+{
+ rtx x = read_rtx_code (name);
+ if (!x)
+ fatal_at (start_loc, "expected insn type; got '%s'", name);
+ rtx_insn *insn = dyn_cast <rtx_insn *> (x);
+ if (!insn)
+ fatal_at (start_loc, "expected insn type; got '%s'", name);
+
+ /* Consume the trailing ')'. */
+ require_char_ws (')');
+
+ rtx_insn *last_insn = get_last_insn ();
+
+ /* Add "insn" to the insn chain. */
+ if (last_insn)
+ {
+ gcc_assert (NEXT_INSN (last_insn) == NULL);
+ SET_NEXT_INSN (last_insn) = insn;
+ }
+ SET_PREV_INSN (insn) = last_insn;
+
+ /* Add it to the sequence. */
+ set_last_insn (insn);
+ if (!m_first_insn)
+ {
+ m_first_insn = insn;
+ set_first_insn (insn);
+ }
+
+ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
+ maybe_set_max_label_num (label);
+
+ return insn;
+}
+
+/* Postprocessing subroutine for parse_insn_chain: all the basic blocks
+ should have been created by now; create the edges that were seen. */
+
+void
+function_reader::create_edges ()
+{
+ int i;
+ deferred_edge *de;
+ FOR_EACH_VEC_ELT (m_deferred_edges, i, de)
+ {
+ /* The BBs should already have been created by parse_block. */
+ basic_block src = BASIC_BLOCK_FOR_FN (cfun, de->m_src_bb_idx);
+ if (!src)
+ fatal_at (de->m_loc, "error: block index %i not found",
+ de->m_src_bb_idx);
+ basic_block dst = BASIC_BLOCK_FOR_FN (cfun, de->m_dest_bb_idx);
+ if (!dst)
+ fatal_at (de->m_loc, "error: block with index %i not found",
+ de->m_dest_bb_idx);
+ unchecked_make_edge (src, dst, de->m_flags);
+ }
+}
+
+/* Parse a "crtl" directive, having already parsed the "(crtl" heading.
+ Consume the final ")". */
+
+void
+function_reader::parse_crtl (file_location loc)
+{
+ if (m_have_crtl_directive)
+ error_at (loc, "more than one 'crtl' directive");
+ m_have_crtl_directive = true;
+
+ /* return_rtx. */
+ require_char_ws ('(');
+ require_word_ws ("return_rtx");
+ crtl->return_rtx = parse_rtx ();
+ require_char_ws (')');
+
+ require_char_ws (')');
+}
+
+/* Overridden implementation of rtx_reader::read_rtx_operand for
+ function_reader, handling various extra data printed by print_rtx,
+ and sometimes calling the base class implementation. */
+
+rtx
+function_reader::read_rtx_operand (rtx return_rtx, int idx)
+{
+ RTX_CODE code = GET_CODE (return_rtx);
+ const char *format_ptr = GET_RTX_FORMAT (code);
+ const char format_char = format_ptr[idx];
+ struct md_name name;
+
+ /* Override the regular parser for some format codes. */
+ switch (format_char)
+ {
+ case 'e':
+ {
+ if (idx == 7 && CALL_P (return_rtx))
+ {
+ m_in_call_function_usage = true;
+ return rtx_reader::read_rtx_operand (return_rtx, idx);
+ m_in_call_function_usage = false;
+ }
+ else
+ return rtx_reader::read_rtx_operand (return_rtx, idx);
+ }
+ break;
+
+ case 'u':
+ read_rtx_operand_u (return_rtx, idx);
+ /* Don't run regular parser for 'u'. */
+ return return_rtx;
+
+ case 'i':
+ case 'n':
+ read_rtx_operand_i_or_n (return_rtx, idx, format_char);
+ /* Don't run regular parser for these codes. */
+ return return_rtx;
+
+ case 'B':
+ {
+ gcc_assert (is_compact ());
+ /* Compact mode doesn't store BBs. */
+ /* Don't run regular parser. */
+ return return_rtx;
+ }
+ break;
+
+ case 'r':
+ /* Don't run regular parser for 'r'. */
+ return read_rtx_operand_r (return_rtx);
+
+ default:
+ break;
+ }
+
+ /* Call base class implementation. */
+ return_rtx = rtx_reader::read_rtx_operand (return_rtx, idx);
+
+ /* Handle any additional parsing needed to handle what the dump
+ could contain. */
+ switch (format_char)
+ {
+ case '0':
+ return extra_parsing_for_operand_code_0 (return_rtx, idx);
+
+ case 'w':
+ {
+ if (!is_compact ())
+ {
+ /* Strip away the redundant hex dump of the value. */
+ require_char_ws ('[');
+ read_name (&name);
+ require_char_ws (']');
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return return_rtx;
+}
+
+/* Special-cased handling of code 'u' for reading function dumps.
+
+ The RTL file recorded the ID of an insn (or 0 for NULL); we
+ must store this as a pointer, but the insn might not have
+ been loaded yet. Store the ID away for now, via a fixup. */
+
+void
+function_reader::read_rtx_operand_u (rtx return_rtx, int idx)
+{
+ /* In compact mode, the PREV/NEXT insn uids are not dumped, so skip
+ the "uu" when reading. */
+ if (is_compact () && GET_CODE (return_rtx) != LABEL_REF)
+ return;
+
+ struct md_name name;
+ file_location loc = read_name (&name);
+ int insn_id = atoi (name.string);
+ if (insn_id)
+ add_fixup_insn_uid (loc, return_rtx, idx, insn_id);
+}
+
+/* Read a name, looking for a match against a string found in array
+ STRINGS of size NUM_VALUES.
+ Return the index of the the matched string, or emit an error. */
+
+int
+function_reader::parse_enum_value (int num_values, const char *const *strings)
+{
+ struct md_name name;
+ read_name (&name);
+ for (int i = 0; i < num_values; i++)
+ {
+ if (strcmp (name.string, strings[i]) == 0)
+ return i;
+ }
+ error ("unrecognized enum value: '%s'", name.string);
+ return 0;
+}
+
+/* Special-cased handling of codes 'i' and 'n' for reading function
+ dumps. */
+
+void
+function_reader::read_rtx_operand_i_or_n (rtx return_rtx, int idx,
+ char format_char)
+{
+ /* Handle some of the extra information that print_rtx
+ can write out for these cases. */
+ /* print_rtx only writes out operand 5 for notes
+ for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+ and NOTE_INSN_DELETED_DEBUG_LABEL. */
+ if (idx == 5 && NOTE_P (return_rtx))
+ return;
+
+ if (idx == 4 && INSN_P (return_rtx))
+ {
+ maybe_read_location (idx, return_rtx);
+ return;
+ }
+
+ /* INSN_CODEs aren't printed in compact mode, so don't attempt to
+ parse them. */
+ if (is_compact ()
+ && INSN_P (return_rtx)
+ && &INSN_CODE (return_rtx) == &XINT (return_rtx, idx))
+ {
+ INSN_CODE (return_rtx) = -1;
+ return;
+ }
+
+ /* Handle UNSPEC and UNSPEC_VOLATILE's operand 1. */
+#if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0
+ if (idx == 1
+ && GET_CODE (return_rtx) == UNSPEC_VOLATILE)
+ {
+ XINT (return_rtx, 1)
+ = parse_enum_value (NUM_UNSPECV_VALUES, unspecv_strings);
+ return;
+ }
+#endif
+#if !defined(GENERATOR_FILE) && NUM_UNSPEC_VALUES > 0
+ if (idx == 1
+ && (GET_CODE (return_rtx) == UNSPEC
+ || GET_CODE (return_rtx) == UNSPEC_VOLATILE))
+ {
+ XINT (return_rtx, 1)
+ = parse_enum_value (NUM_UNSPEC_VALUES, unspec_strings);
+ return;
+ }
+#endif
+
+ struct md_name name;
+ read_name (&name);
+ int value;
+ if (format_char == 'n')
+ value = parse_note_insn_name (name.string);
+ else
+ value = atoi (name.string);
+ XINT (return_rtx, idx) = value;
+}
+
+/* Special-cased handling of code 'r' for reading function dumps. */
+
+rtx
+function_reader::read_rtx_operand_r (rtx return_rtx)
+{
+ struct md_name name;
+ file_location loc = read_name (&name);
+ int regno = lookup_reg_by_dump_name (name.string);
+ if (regno == -1)
+ fatal_at (loc, "unrecognized register: '%s'", name.string);
+
+ set_regno_raw (return_rtx, regno, 1);
+
+ /* Consolidate singletons. */
+ return_rtx = consolidate_singletons (return_rtx);
+
+ ORIGINAL_REGNO (return_rtx) = regno;
+
+ /* Parse extra stuff at end of 'r'.
+ We may have zero, one, or two sections marked by square
+ brackets. */
+ int ch = read_skip_spaces ();
+ bool expect_original_regno = false;
+ if (ch == '[')
+ {
+ file_location loc = get_current_location ();
+ char *desc = read_until ("]", true);
+ strip_trailing_whitespace (desc);
+ const char *desc_start = desc;
+ /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+ "orig:%i", ORIGINAL_REGNO (rtx).
+ Consume it, we don't set ORIGINAL_REGNO, since we can
+ get that from the 2nd copy later. */
+ if (0 == strncmp (desc, "orig:", 5))
+ {
+ expect_original_regno = true;
+ desc_start += 5;
+ /* Skip to any whitespace following the integer. */
+ const char *space = strchr (desc_start, ' ');
+ if (space)
+ desc_start = space + 1;
+ }
+ /* Any remaining text may be the REG_EXPR. Alternatively we have
+ no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
+ if (ISDIGIT (*desc_start))
+ {
+ /* Assume we have ORIGINAL_REGNO. */
+ ORIGINAL_REGNO (return_rtx) = atoi (desc_start);
+ }
+ else
+ {
+ /* Assume we have REG_EXPR. */
+ add_fixup_expr (loc, return_rtx, desc_start);
+ }
+ free (desc);
+ }
+ else
+ unread_char (ch);
+ if (expect_original_regno)
+ {
+ require_char_ws ('[');
+ char *desc = read_until ("]", true);
+ ORIGINAL_REGNO (return_rtx) = atoi (desc);
+ free (desc);
+ }
+
+ return return_rtx;
+}
+
+/* Additional parsing for format code '0' in dumps, handling a variety
+ of special-cases in print_rtx. */
+
+rtx
+function_reader::extra_parsing_for_operand_code_0 (rtx return_rtx, int idx)
+{
+ RTX_CODE code = GET_CODE (return_rtx);
+ int c;
+ struct md_name name;
+
+ if (idx == 1 && code == SYMBOL_REF)
+ {
+ /* Possibly wrote " [flags %#x]", SYMBOL_REF_FLAGS (in_rtx). */
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ file_location loc = read_name (&name);
+ if (strcmp (name.string, "flags"))
+ error_at (loc, "was expecting `%s'", "flags");
+ read_name (&name);
+ SYMBOL_REF_FLAGS (return_rtx) = strtol (name.string, NULL, 16);
+
+ /* We can't reconstruct SYMBOL_REF_BLOCK; set it to NULL. */
+ if (SYMBOL_REF_HAS_BLOCK_INFO_P (return_rtx))
+ SYMBOL_REF_BLOCK (return_rtx) = NULL;
+
+ require_char (']');
+ }
+ else
+ unread_char (c);
+
+ /* Possibly wrote:
+ print_node_brief (outfile, "", SYMBOL_REF_DECL (in_rtx),
+ dump_flags); */
+ c = read_skip_spaces ();
+ if (c == '<')
+ {
+ /* Skip the content for now. */
+ while (1)
+ {
+ char ch = read_char ();
+ if (ch == '>')
+ break;
+ }
+ }
+ else
+ unread_char (c);
+ }
+ else if (idx == 3 && code == NOTE)
+ {
+ /* Note-specific data appears for operand 3, which annoyingly
+ is before the enum specifying which kind of note we have
+ (operand 4). */
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ /* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+ [bb %d]. */
+ file_location bb_loc = read_name (&name);
+ if (strcmp (name.string, "bb"))
+ error_at (bb_loc, "was expecting `%s'", "bb");
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+ add_fixup_note_insn_basic_block (bb_loc, return_rtx, idx,
+ bb_idx);
+ require_char_ws (']');
+ }
+ else
+ unread_char (c);
+ }
+
+ return return_rtx;
+}
+
+/* Implementation of rtx_reader::handle_any_trailing_information.
+ Handle the various additional information that print-rtl.c can
+ write after the regular fields. */
+
+void
+function_reader::handle_any_trailing_information (rtx return_rtx)
+{
+ struct md_name name;
+
+ switch (GET_CODE (return_rtx))
+ {
+ case MEM:
+ {
+ int ch;
+ require_char_ws ('[');
+ read_name (&name);
+ MEM_ALIAS_SET (return_rtx) = atoi (name.string);
+ /* We have either a MEM_EXPR, or a space. */
+ if (peek_char () != ' ')
+ {
+ file_location loc = get_current_location ();
+ char *desc = read_until (" +", false);
+ add_fixup_expr (loc, consolidate_singletons (return_rtx), desc);
+ free (desc);
+ }
+ else
+ read_char ();
+
+ /* We may optionally have '+' for MEM_OFFSET_KNOWN_P. */
+ ch = read_skip_spaces ();
+ if (ch == '+')
+ {
+ read_name (&name);
+ MEM_OFFSET_KNOWN_P (return_rtx) = 1;
+ MEM_OFFSET (return_rtx) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " S" for MEM_SIZE. */
+ ch = read_skip_spaces ();
+ if (ch == 'S')
+ {
+ read_name (&name);
+ MEM_SIZE (return_rtx) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " A" for MEM_ALIGN. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () != 'S')
+ {
+ read_name (&name);
+ MEM_ALIGN (return_rtx) = atoi (name.string);
+ }
+
+ /* Handle optional " AS" for MEM_ADDR_SPACE. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () == 'S')
+ {
+ read_char ();
+ read_name (&name);
+ MEM_ADDR_SPACE (return_rtx) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ require_char (']');
+ }
+ break;
+
+ case CODE_LABEL:
+ {
+ /* Assume that LABEL_NUSES was not dumped. */
+ /* TODO: parse LABEL_KIND. */
+ /* For now, skip until closing ')'. */
+ do
+ {
+ char ch = read_char ();
+ if (ch == ')')
+ {
+ unread_char (ch);
+ break;
+ }
+ }
+ while (1);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Parse a tree dump for MEM_EXPR and turn it back into a tree.
+ We handle "<retval>", but for anything else we "cheat" by building a
+ global VAR_DECL of type "int" with that name (returning the same global
+ for a name if we see the same name more than once). */
+
+tree
+function_reader::parse_mem_expr (const char *desc)
+{
+ tree fndecl = cfun->decl;
+
+ if (0 == strcmp (desc, "<retval>"))
+ {
+ return DECL_RESULT (fndecl);
+ }
+
+ /* Search within function parms. */
+ for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
+ {
+ if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (arg))) == 0)
+ return arg;
+ }
+
+ /* Search within decls we already created.
+ FIXME: use a hash rather than linear search. */
+ int i;
+ tree t;
+ FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+ if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))) == 0)
+ return t;
+
+ /* Not found? Create it.
+ This allows mimicing of real data but avoids having to specify
+ e.g. names of locals, params etc.
+ Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
+ and we don't know the types. Fake it by making everything be
+ a VAR_DECL of "int" type. */
+ t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (desc),
+ integer_type_node);
+ m_fake_scope.safe_push (t);
+ return t;
+}
+
+/* Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid)
+{
+ m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx)
+{
+ m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+ bb_idx));
+}
+
+/* Record the information for later post-processing. */
+void
+function_reader::add_fixup_source_location (file_location, rtx,
+ int, const char *, int)
+{
+ /* Empty for now. */
+}
+
+/* Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+ const char *desc)
+{
+ gcc_assert (desc);
+ /* Fail early if the RTL reader erroneously hands us an int. */
+ gcc_assert (!ISDIGIT (desc[0]));
+
+ m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Helper function for consolidate_reg. */
+
+static rtx
+lookup_global_register (int regno)
+{
+ /* We can't use a switch here, as some of the REGNUMs might not be constants
+ for some targets. */
+ if (regno == STACK_POINTER_REGNUM)
+ return stack_pointer_rtx;
+ else if (regno == FRAME_POINTER_REGNUM)
+ return frame_pointer_rtx;
+ else if (regno == HARD_FRAME_POINTER_REGNUM)
+ return hard_frame_pointer_rtx;
+ else if (regno == ARG_POINTER_REGNUM)
+ return arg_pointer_rtx;
+ else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
+ return virtual_incoming_args_rtx;
+ else if (regno == VIRTUAL_STACK_VARS_REGNUM)
+ return virtual_stack_vars_rtx;
+ else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
+ return virtual_stack_dynamic_rtx;
+ else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
+ return virtual_outgoing_args_rtx;
+ else if (regno == VIRTUAL_CFA_REGNUM)
+ return virtual_cfa_rtx;
+ else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
+ return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+ else if (regno == RETURN_ADDRESS_POINTER_REGNUM)
+ return return_address_pointer_rtx;
+#endif
+
+ return NULL;
+}
+
+/* Normally REG instances are created by gen_reg_rtx which updates
+ regno_reg_rtx, growing it as necessary.
+ The REG instances created from the dumpfile weren't created this
+ way, so we need to manually update regno_reg_rtx. */
+
+static void
+ensure_regno (int regno)
+{
+ crtl->emit.ensure_regno_capacity (regno + 1);
+ gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+
+ if (reg_rtx_no < regno + 1)
+ reg_rtx_no = regno + 1;
+}
+
+/* Helper function for consolidate_singletons, for handling REG instances. */
+
+static rtx
+consolidate_reg (rtx x)
+{
+ gcc_assert (GET_CODE (x) == REG);
+
+ unsigned int regno = REGNO (x);
+
+ ensure_regno (regno);
+
+ /* Some register numbers have their rtx created in init_emit_regs
+ e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
+ Consolidate on this. */
+ rtx global_reg = lookup_global_register (regno);
+ if (global_reg)
+ return global_reg;
+
+ /* Populate regno_reg_rtx if necessary. */
+ if (regno_reg_rtx[regno] == NULL)
+ regno_reg_rtx[regno] = x;
+ /* Use it. */
+ gcc_assert (GET_CODE (regno_reg_rtx[regno]) == REG);
+ gcc_assert (REGNO (regno_reg_rtx[regno]) == regno);
+ if (GET_MODE (x) == GET_MODE (regno_reg_rtx[regno]))
+ return regno_reg_rtx[regno];
+
+ return x;
+}
+
+/* When reading RTL function dumps, we must consolidate some
+ rtx so that we use singletons where singletons are expected
+ (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
+ these are tested via pointer equality against const0_rtx. */
+
+rtx
+function_reader::consolidate_singletons (rtx x)
+{
+ if (!x)
+ return x;
+
+ switch (GET_CODE (x))
+ {
+ /* FIXME: do we need to check for VOIDmode for these? */
+ case PC: return pc_rtx;
+ case RETURN: return ret_rtx;
+ case SIMPLE_RETURN: return simple_return_rtx;
+ case CC0: return cc0_rtx;
+
+ case REG:
+ return consolidate_reg (x);
+
+ case CONST_INT:
+ return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+/* Parse an rtx directive, including both the opening/closing parentheses,
+ and the name. */
+
+rtx
+function_reader::parse_rtx ()
+{
+ require_char_ws ('(');
+ struct md_name directive;
+ read_name (&directive);
+ rtx result
+ = consolidate_singletons (read_rtx_code (directive.string));
+ require_char_ws (')');
+
+ return result;
+}
+
+/* Implementation of rtx_reader::postprocess for reading function dumps. */
+
+rtx
+function_reader::postprocess (rtx x)
+{
+ return consolidate_singletons (x);
+}
+
+/* Handle the optional location information written by print_rtx for
+ instructions. Specifically, operand 4 of instructions (of type "i')
+ is printed thus:
+
+ if (INSN_HAS_LOCATION (in_insn))
+ {
+ expanded_location xloc = insn_location (in_insn);
+ fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+ }
+
+ Hence we need to speculatively read a location of the form
+ " %s:%i", and unread the content if there wasn't one.
+
+ Assume that filenames can't contain whitespace, and can't
+ contain ':'. */
+
+void
+function_reader::maybe_read_location (int operand_idx, rtx insn)
+{
+ file_location loc = get_current_location ();
+
+ /* Skip to first non-whitespace. */
+ int ch = read_skip_spaces ();
+ auto_vec<char> buf;
+ buf.safe_push (ch);
+ while (1)
+ {
+ int ch = read_char ();
+ /* If we see a ':', assume we have a filename. */
+ if (ch == ':')
+ {
+ buf.safe_push ('\0');
+ break;
+ }
+ buf.safe_push (ch);
+
+ /* If we see a space before ':', assume we don't have a
+ filename. */
+ if (ISSPACE (ch))
+ {
+ while (!buf.is_empty ())
+ unread_char (buf.pop ());
+ return;
+ }
+ }
+ char *filename = buf.address ();
+ struct md_name name;
+ read_name (&name);
+
+ add_fixup_source_location (loc, insn, operand_idx,
+ filename, atoi(name.string));
+}
+
+/* Postprocessing subroutine of function_reader::parse_function.
+ Populate m_insns_by_uid. */
+
+void
+function_reader::handle_insn_uids ()
+{
+ /* Locate the currently assigned INSN_UID values, storing
+ them in m_insns_by_uid. */
+ int max_uid = 0;
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (m_insns_by_uid.get (INSN_UID (insn)))
+ error ("duplicate insn UID: %i", INSN_UID (insn));
+ m_insns_by_uid.put (INSN_UID (insn), insn);
+ if (INSN_UID (insn) > max_uid)
+ max_uid = INSN_UID (insn);
+ }
+
+ /* Ensure x_cur_insn_uid is 1 more than the biggest insn UID seen.
+ This is normally updated by the various make_*insn_raw functions. */
+ crtl->emit.x_cur_insn_uid = max_uid + 1;
+}
+
+/* Apply all of the recorded fixups. */
+
+void
+function_reader::apply_fixups ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ f->apply (this);
+}
+
+/* Given a UID value, try to locate a pointer to the corresponding
+ rtx_insn *, or NULL if if can't be found. */
+
+rtx_insn **
+function_reader::get_insn_by_uid (int uid)
+{
+ return m_insns_by_uid.get (uid);
+}
+
+/* Run the RTL dump parser. */
+
+bool
+read_rtl_function_body (int argc, const char **argv,
+ bool (*parse_opt) (const char *),
+ function_reader_policy *policy)
+{
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ function_reader reader (policy);
+ if (!reader.read_md_files (argc, argv, parse_opt))
+ return false;
+
+ return true;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that parse_edge_flags works. */
+
+static void
+test_edge_flags ()
+{
+ /* parse_edge_flags modifies its input (due to strtok), so we must make
+ a copy of the literals. */
+#define ASSERT_PARSE_EDGE_FLAGS(EXPECTED, STR) \
+ do { \
+ char *str = xstrdup (STR); \
+ ASSERT_EQ (EXPECTED, parse_edge_flags (str)); \
+ free (str); \
+ } while (0)
+
+ ASSERT_PARSE_EDGE_FLAGS (0, "");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_FALLTHRU, "FALLTHRU");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL_CALL, "ABNORMAL_CALL");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL,
+ "ABNORMAL | ABNORMAL_CALL");
+
+#undef ASSERT_PARSE_EDGE_FLAGS
+}
+
+/* Verify that lookup_reg_by_dump_name works. */
+
+static void
+test_parsing_regnos ()
+{
+ ASSERT_EQ (-1, lookup_reg_by_dump_name ("this is not a register"));
+
+ /* Verify lookup of hard registers. */
+#ifdef GCC_AARCH64_H
+ ASSERT_EQ (0, lookup_reg_by_dump_name ("x0"));
+ ASSERT_EQ (1, lookup_reg_by_dump_name ("x1"));
+#endif
+#ifdef I386_OPTS_H
+ ASSERT_EQ (0, lookup_reg_by_dump_name ("ax"));
+ ASSERT_EQ (1, lookup_reg_by_dump_name ("dx"));
+#endif
+
+ /* Verify lookup of virtual registers. */
+ ASSERT_EQ (VIRTUAL_INCOMING_ARGS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-incoming-args"));
+ ASSERT_EQ (VIRTUAL_STACK_VARS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-stack-vars"));
+ ASSERT_EQ (VIRTUAL_STACK_DYNAMIC_REGNUM,
+ lookup_reg_by_dump_name ("virtual-stack-dynamic"));
+ ASSERT_EQ (VIRTUAL_OUTGOING_ARGS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-outgoing-args"));
+ ASSERT_EQ (VIRTUAL_CFA_REGNUM,
+ lookup_reg_by_dump_name ("virtual-cfa"));
+ ASSERT_EQ (VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM,
+ lookup_reg_by_dump_name ("virtual-preferred-stack-boundary"));
+
+ /* Verify lookup of non-virtual pseudos. */
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, lookup_reg_by_dump_name ("%0"));
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 2, lookup_reg_by_dump_name ("%1"));
+}
+
+/* Verify that the src and dest indices and flags of edge E are as
+ expected, using LOC as the effective location when reporting
+ failures. */
+
+static void
+assert_edge_at (const location &loc, edge e, int expected_src_idx,
+ int expected_dest_idx, int expected_flags)
+{
+ ASSERT_EQ_AT (loc, expected_src_idx, e->src->index);
+ ASSERT_EQ_AT (loc, expected_dest_idx, e->dest->index);
+ ASSERT_EQ_AT (loc, expected_flags, e->flags);
+}
+
+/* Verify that the src and dest indices and flags of EDGE are as
+ expected. */
+
+#define ASSERT_EDGE(EDGE, EXPECTED_SRC_IDX, EXPECTED_DEST_IDX, \
+ EXPECTED_FLAGS) \
+ assert_edge_at (SELFTEST_LOCATION, EDGE, EXPECTED_SRC_IDX, \
+ EXPECTED_DEST_IDX, EXPECTED_FLAGS)
+
+/* Verify that we can load RTL dumps. */
+
+static void
+test_loading_dump_fragment_1 ()
+{
+ // TODO: filter on target?
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"));
+
+ /* Verify that the insns were loaded correctly. */
+ rtx_insn *insn_1 = get_insns ();
+ ASSERT_TRUE (insn_1);
+ ASSERT_EQ (1, INSN_UID (insn_1));
+ ASSERT_EQ (INSN, GET_CODE (insn_1));
+ ASSERT_EQ (SET, GET_CODE (PATTERN (insn_1)));
+ ASSERT_EQ (NULL, PREV_INSN (insn_1));
+
+ rtx_insn *insn_2 = NEXT_INSN (insn_1);
+ ASSERT_TRUE (insn_2);
+ ASSERT_EQ (2, INSN_UID (insn_2));
+ ASSERT_EQ (INSN, GET_CODE (insn_2));
+ ASSERT_EQ (insn_1, PREV_INSN (insn_2));
+ ASSERT_EQ (NULL, NEXT_INSN (insn_2));
+
+ /* Verify that registers were loaded correctly. */
+ rtx insn_1_dest = SET_DEST (PATTERN (insn_1));
+ ASSERT_EQ (REG, GET_CODE (insn_1_dest));
+ ASSERT_EQ ((LAST_VIRTUAL_REGISTER + 1) + 2, REGNO (insn_1_dest));
+ rtx insn_1_src = SET_SRC (PATTERN (insn_1));
+ ASSERT_EQ (LSHIFTRT, GET_CODE (insn_1_src));
+ rtx reg = XEXP (insn_1_src, 0);
+ ASSERT_EQ (REG, GET_CODE (reg));
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, REGNO (reg));
+
+ /* Verify that get_insn_by_uid works. */
+ ASSERT_EQ (insn_1, get_insn_by_uid (1));
+ ASSERT_EQ (insn_2, get_insn_by_uid (2));
+
+ /* Verify that basic blocks were created. */
+ ASSERT_EQ (2, BLOCK_FOR_INSN (insn_1)->index);
+ ASSERT_EQ (2, BLOCK_FOR_INSN (insn_2)->index);
+
+ /* Verify that the CFG was recreated. */
+ ASSERT_TRUE (cfun);
+ verify_three_block_rtl_cfg (cfun);
+ basic_block bb2 = BASIC_BLOCK_FOR_FN (cfun, 2);
+ ASSERT_TRUE (bb2 != NULL);
+ ASSERT_EQ (BB_RTL, bb2->flags & BB_RTL);
+ ASSERT_EQ (2, bb2->index);
+ ASSERT_EQ (insn_1, BB_HEAD (bb2));
+ ASSERT_EQ (insn_2, BB_END (bb2));
+}
+
+/* Verify loading another RTL dump. */
+
+static void
+test_loading_dump_fragment_2 ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("simple-cse.rtl"));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ rtx_insn *insn_2 = get_insn_by_uid (2);
+ rtx_insn *insn_3 = get_insn_by_uid (3);
+
+ rtx set1 = single_set (insn_1);
+ ASSERT_NE (NULL, set1);
+ rtx set2 = single_set (insn_2);
+ ASSERT_NE (NULL, set2);
+ rtx set3 = single_set (insn_3);
+ ASSERT_NE (NULL, set3);
+
+ rtx src1 = SET_SRC (set1);
+ ASSERT_EQ (PLUS, GET_CODE (src1));
+
+ rtx src2 = SET_SRC (set2);
+ ASSERT_EQ (PLUS, GET_CODE (src2));
+
+ /* Both src1 and src2 refer to "(reg:SI %0)".
+ Verify that we have pointer equality. */
+ rtx lhs1 = XEXP (src1, 0);
+ rtx lhs2 = XEXP (src2, 0);
+ ASSERT_EQ (lhs1, lhs2);
+
+ /* Verify that the CFG was recreated. */
+ ASSERT_TRUE (cfun);
+ verify_three_block_rtl_cfg (cfun);
+}
+
+/* Verify that CODE_LABEL insns are loaded correctly. */
+
+static void
+test_loading_labels ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("example-labels.rtl"));
+
+ rtx_insn *insn_100 = get_insn_by_uid (100);
+ ASSERT_EQ (CODE_LABEL, GET_CODE (insn_100));
+ ASSERT_EQ (100, INSN_UID (insn_100));
+ ASSERT_EQ (NULL, LABEL_NAME (insn_100));
+ ASSERT_EQ (0, LABEL_NUSES (insn_100));
+ ASSERT_EQ (30, CODE_LABEL_NUMBER (insn_100));
+
+ rtx_insn *insn_200 = get_insn_by_uid (200);
+ ASSERT_EQ (CODE_LABEL, GET_CODE (insn_200));
+ ASSERT_EQ (200, INSN_UID (insn_200));
+ ASSERT_STREQ ("some_label_name", LABEL_NAME (insn_200));
+ ASSERT_EQ (0, LABEL_NUSES (insn_200));
+ ASSERT_EQ (40, CODE_LABEL_NUMBER (insn_200));
+
+ /* Ensure that the presence of CODE_LABEL_NUMBER == 40
+ means that the next label num to be handed out will be 41. */
+ ASSERT_EQ (41, max_label_num ());
+
+ /* Ensure that label names read from a dump are GC-managed
+ and are found through the insn. */
+ forcibly_ggc_collect ();
+ ASSERT_TRUE (ggc_marked_p (insn_200));
+ ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_200)));
+}
+
+/* Verify that the loader copes with an insn with a mode. */
+
+static void
+test_loading_insn_with_mode ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("insn-with-mode.rtl"));
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (INSN, GET_CODE (insn));
+
+ /* Verify that the "TI" mode was set from "insn:TI". */
+ ASSERT_EQ (TImode, GET_MODE (insn));
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref. */
+
+static void
+test_loading_jump_to_label_ref ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-label-ref.rtl"));
+
+ rtx_insn *jump_insn = get_insn_by_uid (1);
+ ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+
+ rtx_insn *barrier = get_insn_by_uid (2);
+ ASSERT_EQ (BARRIER, GET_CODE (barrier));
+
+ rtx_insn *code_label = get_insn_by_uid (100);
+ ASSERT_EQ (CODE_LABEL, GET_CODE (code_label));
+
+ /* Verify the jump_insn. */
+ ASSERT_EQ (4, BLOCK_FOR_INSN (jump_insn)->index);
+ ASSERT_EQ (SET, GET_CODE (PATTERN (jump_insn)));
+ /* Ensure that the "(pc)" is using the global singleton. */
+ ASSERT_EQ (pc_rtx, SET_DEST (PATTERN (jump_insn)));
+ // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+ rtx label_ref = SET_SRC (PATTERN (jump_insn));
+ ASSERT_EQ (LABEL_REF, GET_CODE (label_ref));
+ ASSERT_EQ (code_label, label_ref_label (label_ref));
+ ASSERT_EQ (code_label, JUMP_LABEL (jump_insn));
+
+ /* Verify the code_label. */
+ ASSERT_EQ (5, BLOCK_FOR_INSN (code_label)->index);
+ ASSERT_EQ (NULL, LABEL_NAME (code_label));
+ ASSERT_EQ (1, LABEL_NUSES (code_label));
+
+ /* Verify the generated CFG. */
+
+ /* Locate blocks. */
+ basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (entry != NULL);
+ ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+ basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (exit != NULL);
+ ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+ basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
+ basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
+ ASSERT_EQ (4, bb4->index);
+ ASSERT_EQ (5, bb5->index);
+
+ /* Entry block. */
+ ASSERT_EQ (NULL, entry->preds);
+ ASSERT_EQ (1, entry->succs->length ());
+ ASSERT_EDGE ((*entry->succs)[0], 0, 4, EDGE_FALLTHRU);
+
+ /* bb4. */
+ ASSERT_EQ (1, bb4->preds->length ());
+ ASSERT_EDGE ((*bb4->preds)[0], 0, 4, EDGE_FALLTHRU);
+ ASSERT_EQ (1, bb4->succs->length ());
+ ASSERT_EDGE ((*bb4->succs)[0], 4, 5, 0x0);
+
+ /* bb5. */
+ ASSERT_EQ (1, bb5->preds->length ());
+ ASSERT_EDGE ((*bb5->preds)[0], 4, 5, 0x0);
+ ASSERT_EQ (1, bb5->succs->length ());
+ ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
+
+ /* Exit block. */
+ ASSERT_EQ (1, exit->preds->length ());
+ ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
+ ASSERT_EQ (NULL, exit->succs);
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+ marked "return". */
+
+static void
+test_loading_jump_to_return ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-return.rtl"));
+
+ rtx_insn *jump_insn = get_insn_by_uid (1);
+ ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+ ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
+ // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+ marked "simple_return". */
+
+static void
+test_loading_jump_to_simple_return ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("jump-to-simple-return.rtl"));
+
+ rtx_insn *jump_insn = get_insn_by_uid (1);
+ ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+ ASSERT_EQ (simple_return_rtx, JUMP_LABEL (jump_insn));
+ // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a NOTE_INSN_BASIC_BLOCK. */
+
+static void
+test_loading_note_insn_basic_block ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("note_insn_basic_block.rtl"));
+
+ rtx_insn *note = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (note));
+ ASSERT_EQ (2, BLOCK_FOR_INSN (note)->index);
+
+ ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (note));
+ ASSERT_EQ (2, NOTE_BASIC_BLOCK (note)->index);
+ ASSERT_EQ (BASIC_BLOCK_FOR_FN (cfun, 2), NOTE_BASIC_BLOCK (note));
+}
+
+/* Verify that the loader copes with a NOTE_INSN_DELETED. */
+
+static void
+test_loading_note_insn_deleted ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("note-insn-deleted.rtl"));
+
+ rtx_insn *note = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (note));
+ ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (note));
+}
+
+/* Verify that the const_int values are consolidated, since
+ pointer equality corresponds to value equality.
+ TODO: do this for all in CASE_CONST_UNIQUE. */
+
+static void
+test_loading_const_int ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("const-int.rtl"));
+
+ /* Verify that const_int values below MAX_SAVED_CONST_INT use
+ the global values. */
+ ASSERT_EQ (const0_rtx, SET_SRC (PATTERN (get_insn_by_uid (1))));
+ ASSERT_EQ (const1_rtx, SET_SRC (PATTERN (get_insn_by_uid (2))));
+ ASSERT_EQ (constm1_rtx, SET_SRC (PATTERN (get_insn_by_uid (3))));
+
+ /* Verify that other const_int values are consolidated. */
+ rtx int256 = gen_rtx_CONST_INT (SImode, 256);
+ ASSERT_EQ (int256, SET_SRC (PATTERN (get_insn_by_uid (4))));
+}
+
+/* Verify that the loader copes with a SYMBOL_REF. */
+
+static void
+test_loading_symbol_ref ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("symbol-ref.rtl"));
+
+ rtx_insn *insn = get_insns ();
+
+ rtx high = SET_SRC (PATTERN (insn));
+ ASSERT_EQ (HIGH, GET_CODE (high));
+
+ rtx symbol_ref = XEXP (high, 0);
+ ASSERT_EQ (SYMBOL_REF, GET_CODE (symbol_ref));
+
+ /* Verify that "[flags 0xc0]" was parsed. */
+ ASSERT_EQ (0xc0, SYMBOL_REF_FLAGS (symbol_ref));
+ /* TODO: we don't yet load SYMBOL_REF_DECL. */
+}
+
+/* Verify that the loader can rebuild a CFG. */
+
+static void
+test_loading_cfg ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("cfg-test.rtl"));
+
+ ASSERT_STREQ ("cfg_test", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ ASSERT_TRUE (cfun->cfg != NULL);
+ ASSERT_EQ (6, n_basic_blocks_for_fn (cfun));
+ ASSERT_EQ (6, n_edges_for_fn (cfun));
+
+ /* The "fake" basic blocks. */
+ basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (entry != NULL);
+ ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+ basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (exit != NULL);
+ ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+ /* The "real" basic blocks. */
+ basic_block bb2 = (*cfun->cfg->x_basic_block_info)[2];
+ basic_block bb3 = (*cfun->cfg->x_basic_block_info)[3];
+ basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
+ basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
+
+ ASSERT_EQ (2, bb2->index);
+ ASSERT_EQ (3, bb3->index);
+ ASSERT_EQ (4, bb4->index);
+ ASSERT_EQ (5, bb5->index);
+
+ /* Verify connectivity. */
+
+ /* Entry block. */
+ ASSERT_EQ (NULL, entry->preds);
+ ASSERT_EQ (1, entry->succs->length ());
+ ASSERT_EDGE ((*entry->succs)[0], 0, 2, EDGE_FALLTHRU);
+
+ /* bb2. */
+ ASSERT_EQ (1, bb2->preds->length ());
+ ASSERT_EDGE ((*bb2->preds)[0], 0, 2, EDGE_FALLTHRU);
+ ASSERT_EQ (2, bb2->succs->length ());
+ ASSERT_EDGE ((*bb2->succs)[0], 2, 3, EDGE_TRUE_VALUE);
+ ASSERT_EDGE ((*bb2->succs)[1], 2, 4, EDGE_FALSE_VALUE);
+
+ /* bb3. */
+ ASSERT_EQ (1, bb3->preds->length ());
+ ASSERT_EDGE ((*bb3->preds)[0], 2, 3, EDGE_TRUE_VALUE);
+ ASSERT_EQ (1, bb3->succs->length ());
+ ASSERT_EDGE ((*bb3->succs)[0], 3, 5, EDGE_FALLTHRU);
+
+ /* bb4. */
+ ASSERT_EQ (1, bb4->preds->length ());
+ ASSERT_EDGE ((*bb4->preds)[0], 2, 4, EDGE_FALSE_VALUE);
+ ASSERT_EQ (1, bb4->succs->length ());
+ ASSERT_EDGE ((*bb4->succs)[0], 4, 5, EDGE_FALLTHRU);
+
+ /* bb5. */
+ ASSERT_EQ (2, bb5->preds->length ());
+ ASSERT_EDGE ((*bb5->preds)[0], 3, 5, EDGE_FALLTHRU);
+ ASSERT_EDGE ((*bb5->preds)[1], 4, 5, EDGE_FALLTHRU);
+ ASSERT_EQ (1, bb5->succs->length ());
+ ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
+
+ /* Exit block. */
+ ASSERT_EQ (1, exit->preds->length ());
+ ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
+ ASSERT_EQ (NULL, exit->succs);
+}
+
+/* Verify that the loader copes with sparse block indices.
+ This testcase loads a file with a "(block 42)". */
+
+static void
+test_loading_bb_index ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("bb-index.rtl"));
+
+ ASSERT_STREQ ("test_bb_index", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ ASSERT_TRUE (cfun->cfg != NULL);
+ ASSERT_EQ (3, n_basic_blocks_for_fn (cfun));
+ ASSERT_EQ (43, basic_block_info_for_fn (cfun)->length ());
+ ASSERT_EQ (2, n_edges_for_fn (cfun));
+
+ ASSERT_EQ (NULL, (*cfun->cfg->x_basic_block_info)[41]);
+ basic_block bb42 = (*cfun->cfg->x_basic_block_info)[42];
+ ASSERT_NE (NULL, bb42);
+ ASSERT_EQ (42, bb42->index);
+}
+
+/* Run all of the selftests within this file. */
+
+void
+read_rtl_function_c_tests ()
+{
+ test_edge_flags ();
+ test_parsing_regnos ();
+ test_loading_dump_fragment_1 ();
+ test_loading_dump_fragment_2 ();
+ test_loading_labels ();
+ test_loading_insn_with_mode ();
+ test_loading_jump_to_label_ref ();
+ test_loading_jump_to_return ();
+ test_loading_jump_to_simple_return ();
+ test_loading_note_insn_basic_block ();
+ test_loading_note_insn_deleted ();
+ test_loading_const_int ();
+ test_loading_symbol_ref ();
+ test_loading_cfg ();
+ test_loading_bb_index ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
new file mode 100644
index 0000000..036fcce
--- /dev/null
+++ b/gcc/read-rtl-function.h
@@ -0,0 +1,36 @@
+/* read-rtl-function.h - Reader for RTL function dumps
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_READ_RTL_FUNCTION_H
+#define GCC_READ_RTL_FUNCTION_H
+
+/* An optional policy class for class function_reader. */
+
+struct function_reader_policy
+{
+ function_reader_policy ()
+ {
+ }
+};
+
+extern bool read_rtl_function_body (int argc, const char **argv,
+ bool (*parse_opt) (const char *),
+ function_reader_policy *policy);
+
+#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index f74c875..8ef6eec 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
/* Disable rtl checking; it conflicts with the iterator handling. */
#undef ENABLE_RTL_CHECKING
@@ -30,6 +36,12 @@ along with GCC; see the file COPYING3. If not see
#include "read-md.h"
#include "gensupport.h"
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#endif
+
/* One element in a singly-linked list of (integer, string) pairs. */
struct map_value {
struct map_value *next;
@@ -106,6 +118,7 @@ htab_t subst_attr_to_iter_map = NULL;
const char *current_iterator_name;
static void validate_const_int (const char *);
+static void one_time_initialization (void);
/* Global singleton. */
rtx_reader *rtx_reader_ptr = NULL;
@@ -153,6 +166,18 @@ find_code (const char *name)
if (strcmp (GET_RTX_NAME (i), name) == 0)
return i;
+ /* Handle insn codes in compact dumps. In such dumps, the code of insns
+ is prefixed with "c", giving "cinsn", "cnote" etc, and CODE_LABEL is
+ special-cased as "clabel". */
+ if (name[0] == 'c')
+ {
+ for (i = 0; i < NUM_RTX_CODE; i++)
+ if (strcmp (GET_RTX_NAME (i), name + 1) == 0)
+ return i;
+ if (strcmp ("clabel", name) == 0)
+ return CODE_LABEL;
+ }
+
fatal_with_file_and_line ("unknown rtx code `%s'", name);
}
@@ -181,6 +206,8 @@ apply_int_iterator (void *loc, int value)
*(int *)loc = value;
}
+#ifdef GENERATOR_FILE
+
/* This routine adds attribute or does nothing depending on VALUE. When
VALUE is 1, it does nothing - the first duplicate of original
template is kept untouched when it's subjected to a define_subst.
@@ -252,6 +279,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
*slot = value;
}
+#endif /* #ifdef GENERATOR_FILE */
+
/* Return name of a subst-iterator, corresponding to subst-attribute ATTR. */
static char*
@@ -418,6 +447,8 @@ md_reader::copy_rtx_for_iterators (rtx original)
return x;
}
+#ifdef GENERATOR_FILE
+
/* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL
has the form "&& ..." (as used in define_insn_and_splits), assume that
EXTRA is already satisfied. Empty strings are treated like "true". */
@@ -581,6 +612,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
}
}
}
+#endif /* #ifdef GENERATOR_FILE */
/* Add a new "mapping" structure to hashtable TABLE. NAME is the name
of the mapping and GROUP is the group to which it belongs. */
@@ -655,7 +687,9 @@ initialize_iterators (void)
substs.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
substs.find_builtin = find_int; /* We don't use it, anyway. */
+#ifdef GENERATOR_FILE
substs.apply_iterator = apply_subst_iterator;
+#endif
lower = add_mapping (&modes, modes.attrs, "mode");
upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -724,6 +758,8 @@ atoll (const char *p)
}
#endif
\f
+
+#ifdef GENERATOR_FILE
/* Process a define_conditions directive, starting with the optional
space after the "define_conditions". The directive looks like this:
@@ -765,6 +801,7 @@ md_reader::read_conditions ()
add_c_test (expr, value);
}
}
+#endif /* #ifdef GENERATOR_FILE */
static void
validate_const_int (const char *string)
@@ -861,6 +898,8 @@ md_reader::record_potential_iterator_use (struct iterator_group *group,
}
}
+#ifdef GENERATOR_FILE
+
/* Finish reading a declaration of the form:
(define... <name> [<value1> ... <valuen>])
@@ -1020,14 +1059,7 @@ check_code_iterator (struct mapping *iterator)
bool
rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
{
- static bool initialized = false;
-
- /* Do one-time initialization. */
- if (!initialized)
- {
- initialize_iterators ();
- initialized = true;
- }
+ one_time_initialization ();
/* Handle various rtx-related declarations that aren't themselves
encoded as rtxes. */
@@ -1082,6 +1114,103 @@ rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
return true;
}
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization. */
+
+static void
+one_time_initialization (void)
+{
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ initialize_iterators ();
+ initialized = true;
+ }
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+ consuming the terminator character if CONSUME_TERMINATOR is true.
+ Return all characters before the terminator as an allocated buffer. */
+
+char *
+rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
+{
+ int ch = read_skip_spaces ();
+ unread_char (ch);
+ auto_vec<char> buf;
+ while (1)
+ {
+ ch = read_char ();
+ if (strchr (terminator_chars, ch))
+ {
+ if (!consume_terminator)
+ unread_char (ch);
+ break;
+ }
+ buf.safe_push (ch);
+ }
+ buf.safe_push ('\0');
+ return xstrdup (buf.address ());
+}
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags. */
+
+static void
+read_flags (rtx return_rtx)
+{
+ while (1)
+ {
+ int ch = read_char ();
+ if (ch != '/')
+ {
+ unread_char (ch);
+ break;
+ }
+
+ int flag_char = read_char ();
+ switch (flag_char)
+ {
+ case 's':
+ RTX_FLAG (return_rtx, in_struct) = 1;
+ break;
+ case 'v':
+ RTX_FLAG (return_rtx, volatil) = 1;
+ break;
+ case 'u':
+ RTX_FLAG (return_rtx, unchanging) = 1;
+ break;
+ case 'f':
+ RTX_FLAG (return_rtx, frame_related) = 1;
+ break;
+ case 'j':
+ RTX_FLAG (return_rtx, jump) = 1;
+ break;
+ case 'c':
+ RTX_FLAG (return_rtx, call) = 1;
+ break;
+ case 'i':
+ RTX_FLAG (return_rtx, return_val) = 1;
+ break;
+ default:
+ fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+ }
+ }
+}
+
+/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+static int
+parse_reg_note_name (const char *string)
+{
+ for (int i = 0; i < REG_NOTE_MAX; i++)
+ if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
/* 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
return it. */
@@ -1090,11 +1219,12 @@ rtx
rtx_reader::read_rtx_code (const char *code_name)
{
RTX_CODE code;
- struct mapping *iterator;
+ struct mapping *iterator = NULL;
const char *format_ptr;
struct md_name name;
rtx return_rtx;
int c;
+ long reuse_id = -1;
/* Linked list structure for making RTXs: */
struct rtx_list
@@ -1103,13 +1233,39 @@ rtx_reader::read_rtx_code (const char *code_name)
rtx value; /* Value of this node. */
};
+ one_time_initialization ();
+
+ /* Handle reuse_rtx ids e.g. "(0|scratch:DI)". */
+ if (ISDIGIT (code_name[0]))
+ {
+ reuse_id = atoi (code_name);
+ while (char ch = *code_name++)
+ if (ch == '|')
+ break;
+ }
+
+ /* Handle "reuse_rtx". */
+ if (strcmp (code_name, "reuse_rtx") == 0)
+ {
+ read_name (&name);
+ long idx = atoi (name.string);
+ /* Look it up by ID. */
+ gcc_assert (idx < m_reuse_rtx_by_id.length ());
+ return_rtx = m_reuse_rtx_by_id[idx];
+ 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. */
return_rtx = rtx_alloc (code);
@@ -1117,9 +1273,36 @@ rtx_reader::read_rtx_code (const char *code_name)
memset (return_rtx, 0, RTX_CODE_SIZE (code));
PUT_CODE (return_rtx, code);
+ if (reuse_id != -1)
+ {
+ /* Store away for later reuse. */
+ m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1);
+ m_reuse_rtx_by_id[reuse_id] = return_rtx;
+ }
+
if (iterator)
record_iterator_use (iterator, return_rtx);
+ /* Check for flags. */
+ read_flags (return_rtx);
+
+ /* Read REG_NOTE names for EXPR_LIST and INSN_LIST. */
+ if ((GET_CODE (return_rtx) == EXPR_LIST
+ || GET_CODE (return_rtx) == INSN_LIST
+ || GET_CODE (return_rtx) == INT_LIST)
+ && !m_in_call_function_usage)
+ {
+ char ch = read_char ();
+ if (ch == ':')
+ {
+ read_name (&name);
+ PUT_MODE_RAW (return_rtx,
+ (machine_mode)parse_reg_note_name (name.string));
+ }
+ else
+ unread_char (ch);
+ }
+
/* If what follows is `: mode ', read it and
store the mode in the rtx. */
@@ -1132,8 +1315,24 @@ rtx_reader::read_rtx_code (const char *code_name)
else
unread_char (c);
+ if (INSN_CHAIN_CODE_P (code))
+ {
+ read_name (&name);
+ INSN_UID (return_rtx) = atoi (name.string);
+ }
+
+ /* Use the format_ptr to parse the various operands of this rtx.
+ read_rtx_operand is a vfunc, allowing the parser to vary between
+ parsing .md files and parsing .rtl dumps; the function_reader subclass
+ overrides the defaults when loading RTL dumps, to handle the
+ various extra attributes emitted by print_rtx. */
for (int idx = 0; format_ptr[idx] != 0; idx++)
- read_rtx_operand (return_rtx, idx);
+ return_rtx = read_rtx_operand (return_rtx, idx);
+
+ /* Call a vfunc to handle the various additional information that
+ print-rtl.c can write after the regular fields; does nothing when
+ parsing .md files. */
+ handle_any_trailing_information (return_rtx);
if (CONST_WIDE_INT_P (return_rtx))
{
@@ -1197,9 +1396,11 @@ rtx_reader::read_rtx_code (const char *code_name)
/* Subroutine of read_rtx_code. Parse operand IDX within RETURN_RTX,
based on the corresponding format character within GET_RTX_FORMAT
- for the GET_CODE (RETURN_RTX). */
+ for the GET_CODE (RETURN_RTX), and return RETURN_RTX.
+ This is a virtual function, so that function_reader can override
+ some parsing, and potentially return a different rtx. */
-void
+rtx
rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
RTX_CODE code = GET_CODE (return_rtx);
@@ -1217,6 +1418,9 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
break;
case 'e':
+ XEXP (return_rtx, idx) = read_nested_rtx ();
+ break;
+
case 'u':
XEXP (return_rtx, idx) = read_nested_rtx ();
break;
@@ -1273,7 +1477,6 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
char *stringbuf;
int star_if_braced;
- struct obstack *string_obstack = get_string_obstack ();
c = read_skip_spaces ();
unread_char (c);
@@ -1293,7 +1496,10 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
star_if_braced = (format_ptr[idx] == 'T');
stringbuf = read_string (star_if_braced);
+ if (!stringbuf)
+ break;
+#ifdef GENERATOR_FILE
/* For insn patterns, we want to provide a default name
based on the file and line, like "*foo.md:12", if the
given name is blank. These are only for define_insn and
@@ -1303,6 +1509,7 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
&& (GET_CODE (return_rtx) == DEFINE_INSN
|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
{
+ struct obstack *string_obstack = get_string_obstack ();
char line_name[20];
const char *read_md_filename = get_filename ();
const char *fn = (read_md_filename ? read_md_filename : "rtx");
@@ -1348,11 +1555,23 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
if (m != 0)
record_iterator_use (m, return_rtx);
}
+#endif /* #ifdef GENERATOR_FILE */
+
+ /* "stringbuf" was allocated within string_obstack and thus has
+ the its lifetime restricted to that of the rtx_reader. This is
+ OK for the generator programs, but for non-generator programs,
+ XSTR and XTMPL fields are meant to be allocated in the GC-managed
+ heap. Hence we need to allocate a copy in the GC-managed heap
+ for the non-generator case. */
+ const char *string_ptr = stringbuf;
+#ifndef GENERATOR_FILE
+ string_ptr = ggc_strdup (stringbuf);
+#endif /* #ifndef GENERATOR_FILE */
if (star_if_braced)
- XTMPL (return_rtx, idx) = stringbuf;
+ XTMPL (return_rtx, idx) = string_ptr;
else
- XSTR (return_rtx, idx) = stringbuf;
+ XSTR (return_rtx, idx) = string_ptr;
}
break;
@@ -1398,6 +1617,8 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
default:
gcc_unreachable ();
}
+
+ return return_rtx;
}
/* Read a nested rtx construct from the MD file and return it. */
@@ -1408,6 +1629,11 @@ rtx_reader::read_nested_rtx ()
struct md_name name;
rtx return_rtx;
+ /* In compact dumps, trailing "(nil)" values can be omitted.
+ Handle such dumps. */
+ if (peek_char () == ')')
+ return NULL_RTX;
+
require_char_ws ('(');
read_name (&name);
@@ -1418,6 +1644,8 @@ rtx_reader::read_nested_rtx ()
require_char_ws (')');
+ return_rtx = postprocess (return_rtx);
+
return return_rtx;
}
@@ -1454,8 +1682,9 @@ rtx_reader::read_rtx_variadic (rtx form)
/* Constructor for class rtx_reader. */
-rtx_reader::rtx_reader ()
-: md_reader ()
+rtx_reader::rtx_reader (bool compact)
+: md_reader (compact),
+ m_in_call_function_usage (false)
{
/* Set the global singleton pointer. */
rtx_reader_ptr = this;
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
index 8edddfb..bd918a7 100644
--- a/gcc/rtl-tests.c
+++ b/gcc/rtl-tests.c
@@ -200,6 +200,7 @@ test_single_set ()
static void
test_uncond_jump ()
{
+ set_new_first_and_last_insn (NULL, NULL);
rtx_insn *label = gen_label_rtx ();
rtx jump_pat = gen_rtx_SET (pc_rtx,
gen_rtx_LABEL_REF (VOIDmode,
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 7a44e3b..a9a63dc 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3665,7 +3665,9 @@ extern void init_varasm_once (void);
extern rtx make_debug_expr_from_rtl (const_rtx);
/* In read-rtl.c */
+#ifdef GENERATOR_FILE
extern bool read_rtx (const char *, vec<rtx> *);
+#endif
/* In alias.c */
extern rtx canon_rtx (rtx);
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
new file mode 100644
index 0000000..8f3c976
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,82 @@
+/* Selftest support for RTL.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "read-rtl-function.h"
+#include "read-md.h"
+#include "tree-core.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "selftest-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Constructor for selftest::rtl_dump_test.
+ Read a dumped RTL function from PATH.
+ Takes ownership of PATH, freeing in dtor.
+ Use LOC as the effective location when reporting failures. */
+
+rtl_dump_test::rtl_dump_test (const location &loc, char *path)
+ : m_path (path)
+{
+ /* Parse the tempfile. */
+ auto_vec<const char *> argv (2);
+ argv.safe_push (progname);
+ argv.safe_push (path);
+ bool read_ok
+ = read_rtl_function_body (argv.length (), argv.address (), NULL, NULL);
+ ASSERT_TRUE_AT (loc, read_ok);
+}
+
+/* Destructor for selftest::rtl_dump_test.
+ Cleanup global state relating to the function, and free the path. */
+
+selftest::rtl_dump_test::~rtl_dump_test ()
+{
+ /* Cleanups. */
+ current_function_decl = NULL;
+ free_after_compilation (cfun);
+ set_cfun (NULL);
+ free (m_path);
+}
+
+/* Get the insn with the given uid, or NULL if not found. */
+
+rtx_insn *
+get_insn_by_uid (int uid)
+{
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_UID (insn) == uid)
+ return insn;
+
+ /* Not found. */
+ return NULL;
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
index f505018..35d6437 100644
--- a/gcc/selftest-rtl.h
+++ b/gcc/selftest-rtl.h
@@ -47,6 +47,25 @@ assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x,
assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX), \
(REUSE_MANAGER))
+/* A class for testing RTL function dumps. */
+
+class rtl_dump_test
+{
+ public:
+ /* Takes ownership of PATH. */
+ rtl_dump_test (const location &loc, char *path);
+ ~rtl_dump_test ();
+
+ private:
+ char *m_path;
+};
+
+/* Get the insn with the given uid, or NULL if not found. */
+
+extern rtx_insn *get_insn_by_uid (int uid);
+
+extern void verify_three_block_rtl_cfg (function *fun);
+
} /* end of namespace selftest. */
#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index c1cd97e..bf2b84a 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -72,6 +72,7 @@ selftest::run_tests ()
tree_c_tests ();
gimple_c_tests ();
rtl_tests_c_tests ();
+ read_rtl_function_c_tests ();
/* Higher-level tests, or for components that other selftests don't
rely on. */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index c390873..d5afa6d 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -184,6 +184,7 @@ extern void hash_map_tests_c_tests ();
extern void hash_set_tests_c_tests ();
extern void input_c_tests ();
extern void pretty_print_c_tests ();
+extern void read_rtl_function_c_tests ();
extern void rtl_tests_c_tests ();
extern void selftest_c_tests ();
extern void spellcheck_c_tests ();
diff --git a/gcc/testsuite/selftests/aarch64/times-two.rtl b/gcc/testsuite/selftests/aarch64/times-two.rtl
new file mode 100644
index 0000000..dbce67e
--- /dev/null
+++ b/gcc/testsuite/selftests/aarch64/times-two.rtl
@@ -0,0 +1,36 @@
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI x0 [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1))) "../../src/times-two.c":3
+ (nil))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI x0)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI x0)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI x0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
diff --git a/gcc/testsuite/selftests/asr_div1.rtl b/gcc/testsuite/selftests/asr_div1.rtl
new file mode 100644
index 0000000..1507893
--- /dev/null
+++ b/gcc/testsuite/selftests/asr_div1.rtl
@@ -0,0 +1,24 @@
+;; Taken from
+;; gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+;; for aarch64, hand editing to the new format.
+
+(function "f1"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (reg:DI %2)
+ (lshiftrt:DI (reg:DI %0)
+ (const_int 32)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %0)
+ (nil)))
+ (cinsn 2 (set (reg:SI %1)
+ (ashiftrt:SI (subreg:SI (reg:DI %2) 0)
+ (const_int 3)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %2)
+ (nil)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/bb-index.rtl b/gcc/testsuite/selftests/bb-index.rtl
new file mode 100644
index 0000000..7c66f22
--- /dev/null
+++ b/gcc/testsuite/selftests/bb-index.rtl
@@ -0,0 +1,8 @@
+(function "test_bb_index"
+ (insn-chain
+ (block 42
+ (edge-from entry (flags "FALLTHRU"))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 42
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/cfg-test.rtl b/gcc/testsuite/selftests/cfg-test.rtl
new file mode 100644
index 0000000..08a0e22
--- /dev/null
+++ b/gcc/testsuite/selftests/cfg-test.rtl
@@ -0,0 +1,37 @@
+/* Example of a loading a CFG like this:
+ 0 (entry)
+ |
+ 2
+ / \
+ 3 4
+ \ /
+ 5
+ |
+ 1 (exit). */
+
+(function "cfg_test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (edge-to 3 (flags "TRUE_VALUE"))
+ (edge-to 4 (flags "FALSE_VALUE"))
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "TRUE_VALUE"))
+ (cnote 2 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 3
+ (block 4
+ (edge-from 2 (flags "FALSE_VALUE"))
+ (cnote 3 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 3 (flags "FALLTHRU"))
+ (edge-from 4 (flags "FALLTHRU"))
+ (cnote 4 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/const-int.rtl b/gcc/testsuite/selftests/const-int.rtl
new file mode 100644
index 0000000..e50dd88
--- /dev/null
+++ b/gcc/testsuite/selftests/const-int.rtl
@@ -0,0 +1,20 @@
+(function "const_int_examples"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1
+ (set (reg:SI %0) (const_int 0))
+ "test.c":2 (nil))
+ (cinsn 2
+ (set (reg:SI %1) (const_int 1))
+ "test.c":2 (nil))
+ (cinsn 3
+ (set (reg:SI %2) (const_int -1))
+ "test.c":2 (nil))
+ (cinsn 4
+ (set (reg:SI %3) (const_int 256))
+ "test.c":2 (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/example-labels.rtl b/gcc/testsuite/selftests/example-labels.rtl
new file mode 100644
index 0000000..ec33bfd
--- /dev/null
+++ b/gcc/testsuite/selftests/example-labels.rtl
@@ -0,0 +1,8 @@
+(function "example_labels"
+ (insn-chain
+ (block 6
+ (clabel 100 30 (nil))
+ (clabel 200 40 ("some_label_name"))
+ ) ;; block 6
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/insn-with-mode.rtl b/gcc/testsuite/selftests/insn-with-mode.rtl
new file mode 100644
index 0000000..8c4609b
--- /dev/null
+++ b/gcc/testsuite/selftests/insn-with-mode.rtl
@@ -0,0 +1,7 @@
+(function "insn_with_mode"
+ (insn-chain
+ (block 2
+ (insn:TI 1 (set (reg:SI %0) (reg:SI %1)) (nil))
+ ) ;; block
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/jump-to-label-ref.rtl b/gcc/testsuite/selftests/jump-to-label-ref.rtl
new file mode 100644
index 0000000..29184bf
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-label-ref.rtl
@@ -0,0 +1,17 @@
+(function "jump_to_label_ref"
+ (insn-chain
+ (block 4
+ (edge-from entry (flags "FALLTHRU"))
+ (cjump_insn 1 (set (pc) (label_ref 100))
+ "../../src/gcc/testsuite/rtl.dg/test.c":4)
+ (edge-to 5)
+ ) ;; block 4
+ (cbarrier 2)
+ (block 5
+ (edge-from 4)
+ (clabel 100 2 (nil) [1 uses])
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+) ;; function
+
diff --git a/gcc/testsuite/selftests/jump-to-return.rtl b/gcc/testsuite/selftests/jump-to-return.rtl
new file mode 100644
index 0000000..9da89ef
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-return.rtl
@@ -0,0 +1,11 @@
+(function "jump_to_return"
+ (insn-chain
+ (block 4
+ (edge-from entry (flags "FALLTHRU"))
+ (cjump_insn 1 (return)
+ "../../src/gcc/testsuite/rtl.dg/test.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 4
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/jump-to-simple-return.rtl b/gcc/testsuite/selftests/jump-to-simple-return.rtl
new file mode 100644
index 0000000..5a9c1d5
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-simple-return.rtl
@@ -0,0 +1,11 @@
+(function "jump_to_simple_return"
+ (insn-chain
+ (block 4
+ (edge-from entry (flags "FALLTHRU"))
+ (cjump_insn 1 (simple_return)
+ "../../src/gcc/testsuite/rtl.dg/test.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 4
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/note-insn-deleted.rtl b/gcc/testsuite/selftests/note-insn-deleted.rtl
new file mode 100644
index 0000000..a388acd
--- /dev/null
+++ b/gcc/testsuite/selftests/note-insn-deleted.rtl
@@ -0,0 +1,5 @@
+(function "example_note"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/note_insn_basic_block.rtl b/gcc/testsuite/selftests/note_insn_basic_block.rtl
new file mode 100644
index 0000000..e792d98
--- /dev/null
+++ b/gcc/testsuite/selftests/note_insn_basic_block.rtl
@@ -0,0 +1,9 @@
+(function "example_of_note"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/simple-cse.rtl b/gcc/testsuite/selftests/simple-cse.rtl
new file mode 100644
index 0000000..5fe745d
--- /dev/null
+++ b/gcc/testsuite/selftests/simple-cse.rtl
@@ -0,0 +1,16 @@
+(function "test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (reg:SI %1)
+ (plus:SI (reg:SI %0)
+ (const_int 1))) (nil))
+ (cinsn 2 (set (reg:SI %2)
+ (plus:SI (reg:SI %0)
+ (const_int 1))) (nil))
+ (cinsn 3 (set (mem:SI (reg:SI %3) [1 i+0 S4 A32])
+ (mult:SI (reg:SI %1) (reg:SI %2))) (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/symbol-ref.rtl b/gcc/testsuite/selftests/symbol-ref.rtl
new file mode 100644
index 0000000..8339eca
--- /dev/null
+++ b/gcc/testsuite/selftests/symbol-ref.rtl
@@ -0,0 +1,13 @@
+(function "example_of_symbol_ref"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1
+ (set (reg:SI %0)
+ (high:SI (symbol_ref:SI ("isl_obj_map_vtable") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ "y.c":12702
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl b/gcc/testsuite/selftests/x86_64/call-insn.rtl
new file mode 100644
index 0000000..8f3a781
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
@@ -0,0 +1,17 @@
+(function "test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (ccall_insn/j 1
+ (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "test.c":19
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)
+ (nil)))
+ (expr_list:DF (use (reg:DF xmm0))
+ (nil)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function "test"
diff --git a/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
new file mode 100644
index 0000000..4598a1c
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
@@ -0,0 +1,15 @@
+(function "copy_hard_reg_into_frame"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/c:SI
+ (plus:DI
+ (reg/f:DI frame)
+ (const_int -4))
+ [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "test.c":2
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl b/gcc/testsuite/selftests/x86_64/times-two.rtl
new file mode 100644
index 0000000..a26d888
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
@@ -0,0 +1,51 @@
+;; Dump of this C function:
+;;
+;; int times_two (int i)
+;; {
+;; return i * 2;
+;; }
+;;
+;; after expand for target==x86_64
+
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
diff --git a/gcc/testsuite/selftests/x86_64/unspec.rtl b/gcc/testsuite/selftests/x86_64/unspec.rtl
new file mode 100644
index 0000000..ac822ac
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/unspec.rtl
@@ -0,0 +1,20 @@
+(function "test_unspec"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (cinsn 2 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec_volatile:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPECV_RDTSCP)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0396feb..7ec62db 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -305,6 +305,11 @@ ssa_default_def (struct function *fn, tree var)
gcc_assert (VAR_P (var)
|| TREE_CODE (var) == PARM_DECL
|| TREE_CODE (var) == RESULT_DECL);
+
+ /* Always NULL_TREE for rtl function dumps. */
+ if (!fn->gimple_df)
+ return NULL_TREE;
+
in.var = (tree)&ind;
ind.uid = DECL_UID (var);
return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8/9] Introduce class function_reader (v4)
2016-11-11 20:44 ` [PATCH 8/9] Introduce class function_reader (v4) David Malcolm
@ 2016-11-23 20:15 ` Bernd Schmidt
2016-11-23 20:46 ` David Malcolm
2016-12-01 14:40 ` Bernd Schmidt
1 sibling, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-11-23 20:15 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/11/2016 10:15 PM, David Malcolm wrote:
> +static void
> +aarch64_test_loading_full_dump ()
> +{
> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times-two.rtl"));
> +
> + ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
> +
> + rtx_insn *insn_1 = get_insn_by_uid (1);
> + ASSERT_EQ (NOTE, GET_CODE (insn_1));
> +
> + rtx_insn *insn_15 = get_insn_by_uid (15);
> + ASSERT_EQ (INSN, GET_CODE (insn_15));
> + ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
> +
> + /* Verify crtl->return_rtx. */
> + ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
> + ASSERT_EQ (0, REGNO (crtl->return_rtx));
> + ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
> +}
The problem I'm having with this patch, and why I've not really
commented on the latter parts of the series, is that I was hoping the
tests would be more self-contained. For transformations I had mentioned
the idea of having both before and after dumps.
Having a few test files with C code to verify them is probably not a big
deal, but I wonder whether this is going to be the norm rather than the
exception, and whether there are better ways of doing it. Maybe there
needs to be a way of annotating the input RTL to tell the compiler what
kinds of tests to run on it.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8/9] Introduce class function_reader (v4)
2016-11-23 20:15 ` Bernd Schmidt
@ 2016-11-23 20:46 ` David Malcolm
0 siblings, 0 replies; 78+ messages in thread
From: David Malcolm @ 2016-11-23 20:46 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches
On Wed, 2016-11-23 at 21:15 +0100, Bernd Schmidt wrote:
> On 11/11/2016 10:15 PM, David Malcolm wrote:
>
> > +static void
> > +aarch64_test_loading_full_dump ()
> > +{
> > + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times
> > -two.rtl"));
> > +
> > + ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun
> > ->decl)));
> > +
> > + rtx_insn *insn_1 = get_insn_by_uid (1);
> > + ASSERT_EQ (NOTE, GET_CODE (insn_1));
> > +
> > + rtx_insn *insn_15 = get_insn_by_uid (15);
> > + ASSERT_EQ (INSN, GET_CODE (insn_15));
> > + ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
> > +
> > + /* Verify crtl->return_rtx. */
> > + ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
> > + ASSERT_EQ (0, REGNO (crtl->return_rtx));
> > + ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
> > +}
>
> The problem I'm having with this patch, and why I've not really
> commented on the latter parts of the series, is that I was hoping the
> tests would be more self-contained.
The tests in this patch (8/9) are more about verifying that the loader
is sane: they load a dump, and then assert various properties of it, to
ensure that we're loading things correctly. I moved the example dumps
out of the .c files (using locate_file) to avoid having to embed them
in the .c file and escape things (which people objected to in an
earlier version of the kit).
> For transformations I had mentioned
> the idea of having both before and after dumps.
>
> Having a few test files with C code to verify them is probably not a
> big
> deal, but I wonder whether this is going to be the norm rather than
> the
> exception, and whether there are better ways of doing it.
These will be the exception; they're really just about verifying that
the loader is working correctly.
In a previous version of the kit there were indeed selftests that
loaded a dump and attempted to run parts of a pass on it. I've deleted
all of those style of selftest.
> Maybe there
> needs to be a way of annotating the input RTL to tell the compiler
> what
> kinds of tests to run on it.
The "real" tests are in patch 9 of 9, and use DejaGnu directives
(scanning dumps, and "dg-do run" to actually run the generated code).
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8/9] Introduce class function_reader (v4)
2016-11-11 20:44 ` [PATCH 8/9] Introduce class function_reader (v4) David Malcolm
2016-11-23 20:15 ` Bernd Schmidt
@ 2016-12-01 14:40 ` Bernd Schmidt
2016-12-01 21:43 ` David Malcolm
1 sibling, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-01 14:40 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/11/2016 10:15 PM, David Malcolm wrote:
> #include "gt-aarch64.h"
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index 6c608e0..0dda786 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
I think we should separate out the target specific tests so as to give
port maintainers a chance to comment on them separately.
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index 50cd388..179a91f 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -1371,6 +1371,19 @@ maybe_set_first_label_num (rtx_code_label *x)
> if (CODE_LABEL_NUMBER (x) < first_label_num)
> first_label_num = CODE_LABEL_NUMBER (x);
> }
> +
> +/* For use by the RTL function loader, when mingling with normal
> + functions.
Not sure what this means.
> if (str == 0)
> - fputs (" \"\"", m_outfile);
> + fputs (" (nil)", m_outfile);
> else
> fprintf (m_outfile, " (\"%s\")", str);
> m_sawclose = 1;
What does this affect?
> /* Global singleton; constrast with md_reader_ptr above. */
> diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
> new file mode 100644
> index 0000000..ff6c808
> --- /dev/null
> +++ b/gcc/read-rtl-function.c
> @@ -0,0 +1,2124 @@
> +/* read-rtl-function.c - Reader for RTL function dumps
> + Copyright (C) 2016 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +#include <mpfr.h>
Please double-check all these includes whether they are necessary.
> +
> +/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
> +
> +void
> +fixup_note_insn_basic_block::apply (function_reader */*reader*/) const
Lose the /*reader*/, probably.
> +
> +/* Implementation of rtx_reader::handle_unknown_directive.
> +
> + Require a top-level "function" elements, as emitted by
> + print_rtx_function, and parse it. */
"element"?
> +void
> +function_reader::create_function ()
> +{
> + /* Currently we assume cfgrtl mode, rather than cfglayout mode. */
> + if (0)
> + cfg_layout_rtl_register_cfg_hooks ();
> + else
> + rtl_register_cfg_hooks ();
Do we expect to change this? I'd just get rid of the if (0), at least
for now.
> + /* cgraph_node::add_new_function does additional processing
> + based on symtab->state. We need to avoid it attempting to gimplify
> + things. Temporarily putting it in the PARSING state appears to
> + achieve this. */
> + enum symtab_state old_state = symtab->state;
> + symtab->state = PARSING;
> + cgraph_node::add_new_function (fndecl, true /*lowered*/);
> + /* Reset the state. */
> + symtab->state = old_state;
> + }
Does it do anything beside call finalize_function in that state? If
that's all you need, just call it directly.
> +
> + /* Parse DECL_RTL. */
> + {
> + require_char_ws ('(');
> + require_word_ws ("DECL_RTL");
> + DECL_WRTL_CHECK (t_param)->decl_with_rtl.rtl = parse_rtx ();
> + require_char_ws (')');
> + }
Spurious { } blocks.
> + if (0)
> + fprintf (stderr, "parse_edge: %i flags 0x%x \n",
> + other_bb_idx, flags);
Remove this.
> + /* For now, only process the (edge-from) to this BB, and (edge-to)
> + that go to the exit block; we don't yet verify that the edge-from
> + and edge-to directives are consistent. */
That's probably worth a FIXME.
> + if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
> + maybe_set_max_label_num (label);
I keep forgetting why dyn_cast instead of as_a?
> + case 'e':
> + {
> + if (idx == 7 && CALL_P (return_rtx))
> + {
> + m_in_call_function_usage = true;
> + return rtx_reader::read_rtx_operand (return_rtx, idx);
> + m_in_call_function_usage = false;
> + }
> + else
> + return rtx_reader::read_rtx_operand (return_rtx, idx);
> + }
> + break;
Unnecessary { } blocks in several places.
> +
> + case 'w':
> + {
> + if (!is_compact ())
> + {
> + /* Strip away the redundant hex dump of the value. */
> + require_char_ws ('[');
> + read_name (&name);
> + require_char_ws (']');
> + }
> + }
> + break;
Here too.
> +
> +/* Special-cased handling of codes 'i' and 'n' for reading function
> + dumps. */
> +
> +void
> +function_reader::read_rtx_operand_i_or_n (rtx return_rtx, int idx,
> + char format_char)
Document arguments (everywhere). I think return_rtx (throughout these
functions) is a poor name that can cause confusion because it seems to
imply a (return).
> +
> + /* Possibly wrote:
> + print_node_brief (outfile, "", SYMBOL_REF_DECL (in_rtx),
> + dump_flags); */
???
> + /* Skip the content for now. */
Does this relate to the above? Please clarify the comments.
> + case CODE_LABEL:
> + {
> + /* Assume that LABEL_NUSES was not dumped. */
> + /* TODO: parse LABEL_KIND. */
Unnecessary { }.
> + if (0 == strcmp (desc, "<retval>"))
> + {
> + return DECL_RESULT (fndecl);
> + }
> +
> + /* Search within function parms. */
> + for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
> + {
> + if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (arg))) == 0)
> + return arg;
> + }
No { } around single statements, both cases.
> + /* Not found? Create it.
> + This allows mimicing of real data but avoids having to specify
"mimicking".
> +rtx
> +function_reader::consolidate_singletons (rtx x)
> +{
> + if (!x)
> + return x;
> +
> + switch (GET_CODE (x))
Formatting.
> + {
> + /* FIXME: do we need to check for VOIDmode for these? */
Don't see why we would.
> + case CONST_INT:
> + return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
Ugh, really? Can't this be done earlier?
> +
> + add_fixup_source_location (loc, insn, operand_idx,
> + filename, atoi(name.string));
Space before open paren.
> + /* Verify lookup of hard registers. */
> +#ifdef GCC_AARCH64_H
> + ASSERT_EQ (0, lookup_reg_by_dump_name ("x0"));
> + ASSERT_EQ (1, lookup_reg_by_dump_name ("x1"));
> +#endif
> +#ifdef I386_OPTS_H
> + ASSERT_EQ (0, lookup_reg_by_dump_name ("ax"));
> + ASSERT_EQ (1, lookup_reg_by_dump_name ("dx"));
> +#endif
Same as before, please don't do this here.
> +/* Verify that the src and dest indices and flags of edge E are as
> + expected, using LOC as the effective location when reporting
> + failures. */
Again, please document all args (everywhere).
> +
> +static void
> +test_loading_dump_fragment_1 ()
> +{
> + // TODO: filter on target?
> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"));
This is in a generic file, isn't it? Yeah, I don't think we want to load
any RTL from here. Split out such selftests into a separate patch so we
can figure out what to do with them.
> +
> + rtx_insn *jump_insn = get_insn_by_uid (1);
> + ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
> + ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
> + // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
Why is this a fixme and not just done that way (several instances)?
> +
> +/* An optional policy class for class function_reader. */
> +
> +struct function_reader_policy
> +{
> + function_reader_policy ()
> + {
> + }
> +};
> +
> +extern bool read_rtl_function_body (int argc, const char **argv,
> + bool (*parse_opt) (const char *),
> + function_reader_policy *policy);
The policy seems completely unused, please remove. Also, can't this
single declaration go into an existing header?
> + /* Handle insn codes in compact dumps. In such dumps, the code of insns
> + is prefixed with "c", giving "cinsn", "cnote" etc, and CODE_LABEL is
> + special-cased as "clabel". */
> + if (name[0] == 'c')
> + {
> + for (i = 0; i < NUM_RTX_CODE; i++)
> + if (strcmp (GET_RTX_NAME (i), name + 1) == 0)
> + return i;
I'd rather check specifically for the ones we expect, to avoid surprises.
> +#ifdef GENERATOR_FILE
There's a lot of this. Is there a clean split where stuff could be moved
into a separate file instead?
> @@ -1103,13 +1233,39 @@ rtx_reader::read_rtx_code (const char *code_name)
> rtx value; /* Value of this node. */
> };
>
> + one_time_initialization ();
Isn't there a better place to call this?
> +
> + /* Use the format_ptr to parse the various operands of this rtx.
> + read_rtx_operand is a vfunc, allowing the parser to vary between
> + parsing .md files and parsing .rtl dumps; the function_reader subclass
> + overrides the defaults when loading RTL dumps, to handle the
> + various extra attributes emitted by print_rtx. */
Not sure that documentation is really necessary at this point. If
someone is looking for the definition of read_rtx_operand they'll figure
out it's a virtual function anyway.
> for (int idx = 0; format_ptr[idx] != 0; idx++)
> - read_rtx_operand (return_rtx, idx);
> + return_rtx = read_rtx_operand (return_rtx, idx);
> +
> + /* Call a vfunc to handle the various additional information that
> + print-rtl.c can write after the regular fields; does nothing when
> + parsing .md files. */
> + handle_any_trailing_information (return_rtx);
Same here really.
> +
> + /* "stringbuf" was allocated within string_obstack and thus has
> + the its lifetime restricted to that of the rtx_reader. This is
> + OK for the generator programs, but for non-generator programs,
> + XSTR and XTMPL fields are meant to be allocated in the GC-managed
> + heap. Hence we need to allocate a copy in the GC-managed heap
> + for the non-generator case. */
> + const char *string_ptr = stringbuf;
> +#ifndef GENERATOR_FILE
> + string_ptr = ggc_strdup (stringbuf);
> +#endif /* #ifndef GENERATOR_FILE */
Encapsulate in a virtual finalize_string perhaps?
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8/9] Introduce class function_reader (v4)
2016-12-01 14:40 ` Bernd Schmidt
@ 2016-12-01 21:43 ` David Malcolm
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
2016-12-02 15:28 ` [PATCH 8/9] Introduce class function_reader (v4) Bernd Schmidt
0 siblings, 2 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-01 21:43 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches
On Thu, 2016-12-01 at 15:40 +0100, Bernd Schmidt wrote:
Thanks for looking at this.
> On 11/11/2016 10:15 PM, David Malcolm wrote:
> > #include "gt-aarch64.h"
> > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> > index 6c608e0..0dda786 100644
> > --- a/gcc/config/i386/i386.c
> > +++ b/gcc/config/i386/i386.c
>
> I think we should separate out the target specific tests so as to
> give
> port maintainers a chance to comment on them separately.
Done.
> > diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> > index 50cd388..179a91f 100644
> > --- a/gcc/emit-rtl.c
> > +++ b/gcc/emit-rtl.c
> > @@ -1371,6 +1371,19 @@ maybe_set_first_label_num (rtx_code_label
> > *x)
> > if (CODE_LABEL_NUMBER (x) < first_label_num)
> > first_label_num = CODE_LABEL_NUMBER (x);
> > }
> > +
> > +/* For use by the RTL function loader, when mingling with normal
> > + functions.
>
> Not sure what this means.
This is for patch 9 which adds __RTL support to cc1, so that we can
have testcases in which some function bodies are in RTL form, and
others are in normal C form.
The issue is that the CODE_LABEL_NUMBER values in the RTL dump make it
into the generated assembler, and must be unique within the .s file.
Hence we need to update first_label_num so that any new labels created
(e.g. when expanding pure C functions) don't clash with the ones from
the dump.
I can simply drop that first sentence; the followup probably is
sufficient:
/* Ensure that label_num is greater than the label num of X, to
avoid duplicate labels in the generated assembler. */
>
> > if (str == 0)
> > - fputs (" \"\"", m_outfile);
> > + fputs (" (nil)", m_outfile);
> > else
> > fprintf (m_outfile, " (\"%s\")", str);
> > m_sawclose = 1;
>
> What does this affect?
This affects things like the LABEL_NAME of CODE_LABEL instances.
The hunk means that we preserve NULL string values as NULL, rather than
them becoming the empty string on a round trip.
> > /* Global singleton; constrast with md_reader_ptr above. */
> > diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
> > new file mode 100644
> > index 0000000..ff6c808
> > --- /dev/null
> > +++ b/gcc/read-rtl-function.c
> > @@ -0,0 +1,2124 @@
> > +/* read-rtl-function.c - Reader for RTL function dumps
> > + Copyright (C) 2016 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it
> > under
> > +the terms of the GNU General Public License as published by the
> > Free
> > +#include <mpfr.h>
>
> Please double-check all these includes whether they are necessary.
Thanks; yes, quite a few were unnecessary. Fixed.
> > +
> > +/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID.
> > */
> > +
> > +void
> > +fixup_note_insn_basic_block::apply (function_reader */*reader*/)
> > const
>
> Lose the /*reader*/, probably.
Done.
> > +
> > +/* Implementation of rtx_reader::handle_unknown_directive.
> > +
> > + Require a top-level "function" elements, as emitted by
> > + print_rtx_function, and parse it. */
>
> "element"?
Converted to "directive" (I've been trying to use "directive" rather
than "element" throughout).
> > +void
> > +function_reader::create_function ()
> > +{
> > + /* Currently we assume cfgrtl mode, rather than cfglayout mode.
> > */
> > + if (0)
> > + cfg_layout_rtl_register_cfg_hooks ();
> > + else
> > + rtl_register_cfg_hooks ();
>
> Do we expect to change this? I'd just get rid of the if (0), at least
> for now.
Patch 9 adds some logic for switching the hooks as we go through the
various passes, so that "startwith" works properly, but here we just
need it to reflect the state of the hooks coming out of "expand", so
I've changed it to:
/* We start in cfgrtl mode, rather than cfglayout mode. */
rtl_register_cfg_hooks ();
> > + /* cgraph_node::add_new_function does additional processing
> > + based on symtab->state. We need to avoid it attempting to
> > gimplify
> > + things. Temporarily putting it in the PARSING state
> > appears to
> > + achieve this. */
> > + enum symtab_state old_state = symtab->state;
> > + symtab->state = PARSING;
> > + cgraph_node::add_new_function (fndecl, true /*lowered*/);
> > + /* Reset the state. */
> > + symtab->state = old_state;
> > + }
>
> Does it do anything beside call finalize_function in that state? If
> that's all you need, just call it directly.
There's some logic after the switch on state for calling
lang_hooks.eh_personality and setting DECL_FUNCTION_PERSONALITY, but I
think if we want to support that, we'd add it as additional dumped
data.
I've updated things to call finalize_function directly, removing the
messing about with the symtab state.
> > +
> > + /* Parse DECL_RTL. */
> > + {
> > + require_char_ws ('(');
> > + require_word_ws ("DECL_RTL");
> > + DECL_WRTL_CHECK (t_param)->decl_with_rtl.rtl = parse_rtx ();
> > + require_char_ws (')');
> > + }
>
> Spurious { } blocks.
Removed.
> > + if (0)
> > + fprintf (stderr, "parse_edge: %i flags 0x%x \n",
> > + other_bb_idx, flags);
>
> Remove this.
Removed.
> > + /* For now, only process the (edge-from) to this BB, and (edge
> > -to)
> > + that go to the exit block; we don't yet verify that the edge
> > -from
> > + and edge-to directives are consistent. */
>
> That's probably worth a FIXME.
Added.
> > + if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
> > + maybe_set_max_label_num (label);
>
> I keep forgetting why dyn_cast instead of as_a?
as_a requires that the cast be valid; dyn_cast, determines if the cast
is valid, and returns NULL if it isn't valid, allowing uses within a
conditional like the one here.
> > + case 'e':
> > + {
> > + if (idx == 7 && CALL_P (return_rtx))
> > + {
> > + m_in_call_function_usage = true;
> > + return rtx_reader::read_rtx_operand (return_rtx, idx);
> > + m_in_call_function_usage = false;
> > + }
> > + else
> > + return rtx_reader::read_rtx_operand (return_rtx, idx);
> > + }
> > + break;
>
> Unnecessary { } blocks in several places.
Fixed.
> > +
> > + case 'w':
> > + {
> > + if (!is_compact ())
> > + {
> > + /* Strip away the redundant hex dump of the value. */
> > + require_char_ws ('[');
> > + read_name (&name);
> > + require_char_ws (']');
> > + }
> > + }
> > + break;
>
> Here too.
Fixed.
> > +
> > +/* Special-cased handling of codes 'i' and 'n' for reading
> > function
> > + dumps. */
> > +
> > +void
> > +function_reader::read_rtx_operand_i_or_n (rtx return_rtx, int idx,
> > + char format_char)
>
> Document arguments (everywhere). I think return_rtx (throughout these
> functions) is a poor name that can cause confusion because it seems
> to
> imply a (return).
I've renamed it to "x" throughout. I've gone through and documented
arguments and return values throughout (I hope). In doing so, I found
extra_parsing_for_operand_code_0's return value to be redundant, so I
made it "void".
> > +
> > + /* Possibly wrote:
> > + print_node_brief (outfile, "", SYMBOL_REF_DECL (in_rtx),
> > + dump_flags); */
>
> ???
I've rewritten the comment to read:
/* If X had a non-NULL SYMBOL_REF_DECL,
rtx_writer::print_rtx_operand_code_0 would have dumped it
using print_node_brief.
Skip the content for now. */
Hopefully that's clearer.
> > + /* Skip the content for now. */
>
> Does this relate to the above? Please clarify the comments.
Indeed; I've merged it into the above comment.
>
> > + case CODE_LABEL:
> > + {
> > + /* Assume that LABEL_NUSES was not dumped. */
> > + /* TODO: parse LABEL_KIND. */
>
> Unnecessary { }.
Fixed.
> > + if (0 == strcmp (desc, "<retval>"))
> > + {
> > + return DECL_RESULT (fndecl);
> > + }
> > +
> > + /* Search within function parms. */
> > + for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN
> > (arg))
> > + {
> > + if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (arg))) ==
> > 0)
> > + return arg;
> > + }
>
> No { } around single statements, both cases.
Fixed.
> > + /* Not found? Create it.
> > + This allows mimicing of real data but avoids having to
> > specify
>
> "mimicking".
Fixed.
> > +rtx
> > +function_reader::consolidate_singletons (rtx x)
> > +{
> > + if (!x)
> > + return x;
> > +
> > + switch (GET_CODE (x))
>
> Formatting.
Fixed.
> > + {
> > + /* FIXME: do we need to check for VOIDmode for these? */
>
> Don't see why we would.
Thanks; removed.
> > + case CONST_INT:
> > + return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
>
> Ugh, really? Can't this be done earlier?
rtx_reader::read_rtx_code reads the name "const_int" from the FILE *
turns it into a RTX_CODE, and allocates a fresh instance via:
rtx_alloc (code)
I guess we could special-case it at that point, but it would mean
special-casing reading the operands etc also.
By doing it here, we consolidate all of the singleton-consolidation
into one place.
> > +
> > + add_fixup_source_location (loc, insn, operand_idx,
> > + filename, atoi(name.string));
>
> Space before open paren.
Fixed.
> > + /* Verify lookup of hard registers. */
> > +#ifdef GCC_AARCH64_H
> > + ASSERT_EQ (0, lookup_reg_by_dump_name ("x0"));
> > + ASSERT_EQ (1, lookup_reg_by_dump_name ("x1"));
> > +#endif
> > +#ifdef I386_OPTS_H
> > + ASSERT_EQ (0, lookup_reg_by_dump_name ("ax"));
> > + ASSERT_EQ (1, lookup_reg_by_dump_name ("dx"));
> > +#endif
>
> Same as before, please don't do this here.
lookup_reg_by_dump_name is static within read-rtl-function.c. I could
expose it within e.g. rtl.h, and then do the selftests within a target
-specific selftest hook.
Alternatively, I could add the verification of loading hard-reg regnos
to the "loading a dump" selftests I've just split out into separate
patches.
Do you have a preference?
> > +/* Verify that the src and dest indices and flags of edge E are as
> > + expected, using LOC as the effective location when reporting
> > + failures. */
>
> Again, please document all args (everywhere).
Fixed.
> > +
> > +static void
> > +test_loading_dump_fragment_1 ()
> > +{
> > + // TODO: filter on target?
> > + rtl_dump_test t (SELFTEST_LOCATION, locate_file
> > ("asr_div1.rtl"));
>
> This is in a generic file, isn't it? Yeah, I don't think we want to
> load
> any RTL from here. Split out such selftests into a separate patch so
> we
> can figure out what to do with them.
Yes: this is a target-independent dump (I *think*; works with both
x86_64 and aarch64).
I've split out all of them into another patch.
> > +
> > + rtx_insn *jump_insn = get_insn_by_uid (1);
> > + ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
> > + ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
> > + // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
>
> Why is this a fixme and not just done that way (several instances)?
ASSERT_RTX_PTR_EQ doesn't exist yet; there was some discussion about it
in earlier versions of the patch, but I haven't written it. It would
be equivalent to ASSERT_EQ, checking pointer equality, but would dump
the mismatching expected vs actual rtx on failure.
Should I convert this to a TODO, or go ahead and implement
ASSERT_RTX_PTR_EQ?
> > +
> > +/* An optional policy class for class function_reader. */
> > +
> > +struct function_reader_policy
> > +{
> > + function_reader_policy ()
> > + {
> > + }
> > +};
> > +
> > +extern bool read_rtl_function_body (int argc, const char **argv,
> > + bool (*parse_opt) (const char
> > *),
> > + function_reader_policy
> > *policy);
>
> The policy seems completely unused, please remove.
Oops, yes; it's a vestige from an older version of pseudo handling.
Removed.
> Also, can't this
> single declaration go into an existing header?
Probably, but I'm not sure where.
I tried rtl.h, but patch 9 adds read_rtl_function_body_from_file_range.
This needs to be callable from the C frontend, and rtl.h is poisoned
within frontends. Hence the new header file.
> > + /* Handle insn codes in compact dumps. In such dumps, the code
> > of insns
> > + is prefixed with "c", giving "cinsn", "cnote" etc, and
> > CODE_LABEL is
> > + special-cased as "clabel". */
> > + if (name[0] == 'c')
> > + {
> > + for (i = 0; i < NUM_RTX_CODE; i++)
> > + if (strcmp (GET_RTX_NAME (i), name + 1) == 0)
> > + return i;
>
> I'd rather check specifically for the ones we expect, to avoid
> surprises.
I've converted it to a table of known values.
> > +#ifdef GENERATOR_FILE
>
> There's a lot of this. Is there a clean split where stuff could be
> moved
> into a separate file instead?
Currently we have:
- read-md.c: base .md reading, with base-bones directive-handling
- read-rtl.c: adds the ability to handle hierarchical rtx
- read-rtl-function.c: (new in patch kit): adds the ability to read RTL
function dumps.
So maybe "read-rtl-md.c", for the things that relate to hierarchical
rtx, but which are .md-specific?
Or I could try to move the things to read-md.c, but not sure if that's
going to work.
> > @@ -1103,13 +1233,39 @@ rtx_reader::read_rtx_code (const char
> > *code_name)
> > rtx value; /* Value of this node. */
> > };
> >
> > + one_time_initialization ();
>
> Isn't there a better place to call this?
Maybe rename to "ensure_initialized"? This replaces the code:
- static bool initialized = false;
-
- /* Do one-time initialization. */
- if (!initialized)
- {
- initialize_iterators ();
- initialized = true;
- }
in rtx_reader::read_rtx, since now not all rtx-reading goes through
that path.
> > +
> > + /* Use the format_ptr to parse the various operands of this rtx.
> > + read_rtx_operand is a vfunc, allowing the parser to vary
> > between
> > + parsing .md files and parsing .rtl dumps; the function_reader
> > subclass
> > + overrides the defaults when loading RTL dumps, to handle the
> > + various extra attributes emitted by print_rtx. */
>
> Not sure that documentation is really necessary at this point. If
> someone is looking for the definition of read_rtx_operand they'll
> figure
> out it's a virtual function anyway.
Given that we rarely use vfuncs, is calling it out more acceptable?
Shall I just drop it, or word it as "Default implementation of..."?
> > for (int idx = 0; format_ptr[idx] != 0; idx++)
> > - read_rtx_operand (return_rtx, idx);
> > + return_rtx = read_rtx_operand (return_rtx, idx);
> > +
> > + /* Call a vfunc to handle the various additional information
> > that
> > + print-rtl.c can write after the regular fields; does nothing
> > when
> > + parsing .md files. */
> > + handle_any_trailing_information (return_rtx);
>
> Same here really.
Maybe reword to:
"Give subclasses a chance to handle any additional information that
may be present after the regular fields (e.g. in a function dump)"
or somesuch.
> > +
> > + /* "stringbuf" was allocated within string_obstack and
> > thus has
> > + the its lifetime restricted to that of the rtx_reader.
> > This is
> > + OK for the generator programs, but for non-generator
> > programs,
> > + XSTR and XTMPL fields are meant to be allocated in the
> > GC-managed
> > + heap. Hence we need to allocate a copy in the GC
> > -managed heap
> > + for the non-generator case. */
> > + const char *string_ptr = stringbuf;
> > +#ifndef GENERATOR_FILE
> > + string_ptr = ggc_strdup (stringbuf);
> > +#endif /* #ifndef GENERATOR_FILE */
>
> Encapsulate in a virtual finalize_string perhaps?
Done.
I'm preparing updated patches (for the issues covered so far...)
Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8a/9] Introduce class function_reader (v6)
2016-12-01 21:43 ` David Malcolm
@ 2016-12-02 1:27 ` David Malcolm
2016-12-02 1:27 ` [PATCH 8b/9] Add target-independent selftests of RTL function reader David Malcolm
` (4 more replies)
2016-12-02 15:28 ` [PATCH 8/9] Introduce class function_reader (v4) Bernd Schmidt
1 sibling, 5 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-02 1:27 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
Changed in v6:
- split out dump-reading selftests into followup patches
(target-independent, and target-specific)
- removes unneeded headers from read-rtl-function.c
- numerous other cleanups identified in review
Changed in v5:
- updated for change to emit_status::ensure_regno_capacity
Changed in v4:
- error-handling changes split out into a separate patch
- rewritten the loader to use the new "compact" dump format
- support for reuse_rtx in loader
- handling of params, DECL_RTL and DECL_RTL_INCOMING
- moved target-dependent selftests to target-specific code
(aarch64.c and i386.c)
Link to earlier version of the patch:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00267.html
gcc/ChangeLog:
* Makefile.in (OBJS): Add read-md.o, read-rtl.o,
read-rtl-function.o, and selftest-rtl.o.
* emit-rtl.c (maybe_set_max_label_num): New function.
* emit-rtl.h (maybe_set_max_label_num): New decl.
* function.c (instantiate_decls): Guard call to
instantiate_decls_1 with if (DECL_INITIAL (fndecl)).
* gensupport.c (gen_reader::gen_reader): Pass "false"
for new "compact" param of rtx_reader.
* print-rtl.c (rtx_writer::print_rtx_operand): Print "(nil)"
rather than an empty string for NULL strings.
* read-md.c: Potentially include config.h rather than bconfig.h.
(md_reader::read_name): Rename to...
(md_reader::read_name_1): ...this, adding "out_loc" param,
and converting "missing name or number" to returning false, rather
than failing.
(md_reader::read_name): Reimplement in terms of read_name_1.
(md_reader::read_name_or_nil): New function.
(md_reader::read_string): Handle "(nil)" by returning NULL.
(md_reader::md_reader): Add new param "compact".
* read-md.h (md_reader::md_reader): Add new param "compact".
(md_reader::is_compact): New accessor.
(md_reader::read_name): Convert return type from void to
file_location.
(md_reader::read_name_or_nil): New decl.
(md_reader::read_name_1): New decl.
(md_reader::m_compact): New field.
(noop_reader::noop_reader): Pass "false" for new "compact" param
of rtx_reader.
(rtx_reader::rtx_reader): Add new "compact" param.
(rtx_reader::read_rtx_operand): Make virtual and convert return
type from void to rtx.
(rtx_reader::read_until): New decl.
(rtx_reader::handle_any_trailing_information): New virtual
function.
(rtx_reader::postprocess): New virtual function.
(rtx_reader::finalize_string): New virtual function.
(rtx_reader::m_in_call_function_usage): New field.
(rtx_reader::m_reuse_rtx_by_id): New field.
* read-rtl-function.c: New file.
* read-rtl-function.h: New file.
* read-rtl.c: Potentially include config.h rather than bconfig.h.
For host, include function.h, memmodel.h, and emit-rtl.h.
(one_time_initialization): New function.
(struct compact_insn_name): New struct.
(compact_insn_names): New array.
(find_code): Handle insn codes in compact dumps.
(apply_subst_iterator): Wrap with #ifdef GENERATOR_FILE.
(bind_subst_iter_and_attr): Likewise.
(add_condition_to_string): Likewise.
(add_condition_to_rtx): Likewise.
(apply_attribute_uses): Likewise.
(add_current_iterators): Likewise.
(apply_iterators): Likewise.
(initialize_iterators): Guard usage of apply_subst_iterator with
#ifdef GENERATOR_FILE.
(read_conditions): Wrap with #ifdef GENERATOR_FILE.
(md_reader::read_mapping): Likewise.
(add_define_attr_for_define_subst): Likewise.
(add_define_subst_attr): Likewise.
(read_subst_mapping): Likewise.
(check_code_iterator): Likewise.
(rtx_reader::read_rtx): Likewise. Move one-time initialization
logic to...
(one_time_initialization): New function.
(rtx_reader::read_until): New method.
(read_flags): New function.
(parse_reg_note_name): New function.
(rtx_reader::read_rtx_code): Initialize "iterator" to NULL.
Call one_time_initialization. Handle reuse_rtx ids.
Wrap iterator lookup within #ifdef GENERATOR_FILE.
Add parsing support for RTL dumps, mirroring the special-cases in
print_rtx, by calling read_flags, reading REG_NOTE names, INSN_UID
values, and calling handle_any_trailing_information.
(rtx_reader::read_rtx_operand): Convert return type from void
to rtx, returning return_rtx. Handle case 'e'. Call
finalize_string on XSTR and XTMPL fields.
(rtx_reader::read_nested_rtx): Handle dumps in which trailing
"(nil)" values were omitted. Call the postprocess vfunc on the
return_rtx.
(rtx_reader::rtx_reader): Add new "compact" param and pass to base
class ctor. Initialize m_in_call_function_usage.
* rtl-tests.c (selftest::test_uncond_jump): Call
set_new_first_and_last_insn.
* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
* selftest-rtl.c: New file.
* selftest-rtl.h (class selftest::rtl_dump_test): New class.
(selftest::get_insn_by_uid): New decl.
* selftest-run-tests.c (selftest::run_tests): Call
read_rtl_function_c_tests.
* selftest.h (selftest::read_rtl_function_c_tests): New decl.
* tree-dfa.c (ssa_default_def): Return NULL_TREE for rtl function
dumps.
---
gcc/Makefile.in | 4 +
gcc/emit-rtl.c | 13 +
gcc/emit-rtl.h | 2 +
gcc/function.c | 3 +-
gcc/gensupport.c | 2 +-
gcc/print-rtl.c | 2 +-
gcc/read-md.c | 59 +-
gcc/read-md.h | 30 +-
gcc/read-rtl-function.c | 1657 ++++++++++++++++++++++++++++++++++++++++++++++
gcc/read-rtl-function.h | 26 +
gcc/read-rtl.c | 271 +++++++-
gcc/rtl-tests.c | 1 +
gcc/rtl.h | 2 +
gcc/selftest-rtl.c | 82 +++
gcc/selftest-rtl.h | 17 +
gcc/selftest-run-tests.c | 1 +
gcc/selftest.h | 1 +
gcc/tree-dfa.c | 5 +
18 files changed, 2148 insertions(+), 30 deletions(-)
create mode 100644 gcc/read-rtl-function.c
create mode 100644 gcc/read-rtl-function.h
create mode 100644 gcc/selftest-rtl.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c265893..73d12dc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1407,6 +1407,9 @@ OBJS = \
print-rtl-function.o \
print-tree.o \
profile.o \
+ read-md.o \
+ read-rtl.o \
+ read-rtl-function.o \
real.o \
realmpfr.o \
recog.o \
@@ -1434,6 +1437,7 @@ OBJS = \
sel-sched-ir.o \
sel-sched-dump.o \
sel-sched.o \
+ selftest-rtl.o \
selftest-run-tests.o \
sese.o \
shrink-wrap.o \
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index b2b5fde..6d64ad6 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1374,6 +1374,19 @@ maybe_set_first_label_num (rtx_code_label *x)
if (CODE_LABEL_NUMBER (x) < first_label_num)
first_label_num = CODE_LABEL_NUMBER (x);
}
+
+/* For use by the RTL function loader, when mingling with normal
+ functions.
+ Ensure that label_num is greater than the label num of X, to avoid
+ duplicate labels in the generated assembler. */
+
+void
+maybe_set_max_label_num (rtx_code_label *x)
+{
+ if (CODE_LABEL_NUMBER (x) >= label_num)
+ label_num = CODE_LABEL_NUMBER (x) + 1;
+}
+
\f
/* Return a value representing some low-order bits of X, where the number
of low-order bits is given by MODE. Note that no conversion is done
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 21c180b..01f16a7 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -507,4 +507,6 @@ extern int get_mem_align_offset (rtx, unsigned int);
MODE and adjusted by OFFSET. */
extern rtx widen_memory_access (rtx, machine_mode, HOST_WIDE_INT);
+extern void maybe_set_max_label_num (rtx_code_label *x);
+
#endif /* GCC_EMIT_RTL_H */
diff --git a/gcc/function.c b/gcc/function.c
index 0b1d168..2674321 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -1901,7 +1901,8 @@ instantiate_decls (tree fndecl)
instantiate_decl_rtl (DECL_RTL (DECL_VALUE_EXPR (decl)));
/* Now process all variables defined in the function or its subblocks. */
- instantiate_decls_1 (DECL_INITIAL (fndecl));
+ if (DECL_INITIAL (fndecl))
+ instantiate_decls_1 (DECL_INITIAL (fndecl));
FOR_EACH_LOCAL_DECL (cfun, ix, decl)
if (DECL_RTL_SET_P (decl))
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index c49ad6f..64378e3 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2233,7 +2233,7 @@ process_define_subst (void)
class gen_reader : public rtx_reader
{
public:
- gen_reader () : rtx_reader () {}
+ gen_reader () : rtx_reader (false) {}
void handle_unknown_directive (file_location, const char *);
};
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 3bbd395..77e6b05 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -577,7 +577,7 @@ rtx_writer::print_rtx_operand (const_rtx in_rtx, int idx)
string:
if (str == 0)
- fputs (" \"\"", m_outfile);
+ fputs (" (nil)", m_outfile);
else
fprintf (m_outfile, " (\"%s\")", str);
m_sawclose = 1;
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 6d9a1bd..a8462a6 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
#include "system.h"
#include "coretypes.h"
#include "errors.h"
@@ -424,8 +430,8 @@ md_reader::peek_char (void)
/* Read an rtx code name into NAME. It is terminated by any of the
punctuation chars of rtx printed syntax. */
-void
-md_reader::read_name (struct md_name *name)
+bool
+md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
{
int c;
size_t i;
@@ -463,8 +469,12 @@ md_reader::read_name (struct md_name *name)
c = read_char ();
}
+ unread_char (c);
+ *out_loc = get_current_location ();
+ read_char ();
+
if (i == 0)
- fatal_with_file_and_line ("missing name or number");
+ return false;
name->buffer[i] = 0;
name->string = name->buffer;
@@ -485,6 +495,36 @@ md_reader::read_name (struct md_name *name)
}
while (def);
}
+
+ return true;
+}
+
+/* Read an rtx code name into NAME. It is terminated by any of the
+ punctuation chars of rtx printed syntax. */
+
+file_location
+md_reader::read_name (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ fatal_with_file_and_line ("missing name or number");
+ return loc;
+}
+
+file_location
+md_reader::read_name_or_nil (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ {
+ file_location loc = get_current_location ();
+ read_skip_construct (0, loc);
+ /* Skip the ')'. */
+ read_char ();
+ name->buffer[0] = 0;
+ name->string = name->buffer;
+ }
+ return loc;
}
/* Subroutine of the string readers. Handles backslash escapes.
@@ -630,6 +670,14 @@ md_reader::read_string (int star_if_braced)
obstack_1grow (&m_string_obstack, '*');
stringbuf = read_braced_string ();
}
+ else if (saw_paren && c == 'n')
+ {
+ /* Handle (nil) by returning NULL. */
+ require_char ('i');
+ require_char ('l');
+ require_char_ws (')');
+ return NULL;
+ }
else
fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
@@ -924,8 +972,9 @@ md_reader::traverse_enum_types (htab_trav callback, void *info)
/* Constructor for md_reader. */
-md_reader::md_reader ()
-: m_toplevel_fname (NULL),
+md_reader::md_reader (bool compact)
+: m_compact (compact),
+ m_toplevel_fname (NULL),
m_base_dir (NULL),
m_read_md_file (NULL),
m_read_md_filename (NULL),
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 8910b75..06dc80e 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -94,7 +94,7 @@ struct enum_type {
class md_reader
{
public:
- md_reader ();
+ md_reader (bool compact);
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
@@ -107,10 +107,13 @@ class md_reader
file_location get_current_location () const;
+ bool is_compact () const { return m_compact; }
+
/* Defined in read-md.c. */
int read_char (void);
void unread_char (int ch);
- void read_name (struct md_name *name);
+ file_location read_name (struct md_name *name);
+ file_location read_name_or_nil (struct md_name *);
void read_escape ();
char *read_quoted_string ();
char *read_braced_string ();
@@ -167,7 +170,12 @@ class md_reader
void handle_include (file_location loc);
void add_include_path (const char *arg);
+ bool read_name_1 (struct md_name *name, file_location *out_loc);
+
private:
+ /* Are we reading a compact dump? */
+ bool m_compact;
+
/* The name of the toplevel file that indirectly included
m_read_md_file. */
const char *m_toplevel_fname;
@@ -235,7 +243,7 @@ extern md_reader *md_reader_ptr;
class noop_reader : public md_reader
{
public:
- noop_reader () : md_reader () {}
+ noop_reader () : md_reader (false) {}
/* A dummy implementation which skips unknown directives. */
void handle_unknown_directive (file_location, const char *);
@@ -249,14 +257,26 @@ class noop_reader : public md_reader
class rtx_reader : public md_reader
{
public:
- rtx_reader ();
+ rtx_reader (bool compact);
~rtx_reader ();
bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
rtx read_rtx_code (const char *code_name);
- void read_rtx_operand (rtx return_rtx, int idx);
+ virtual rtx read_rtx_operand (rtx return_rtx, int idx);
rtx read_nested_rtx ();
rtx read_rtx_variadic (rtx form);
+ char *read_until (const char *terminator_chars, bool consume_terminator);
+
+ virtual void handle_any_trailing_information (rtx) {}
+ virtual rtx postprocess (rtx x) { return x; }
+ virtual const char *finalize_string (char *stringbuf) { return stringbuf; }
+
+ protected:
+ /* Analogous to rtx_writer's m_in_call_function_usage. */
+ bool m_in_call_function_usage;
+
+ /* Support for "reuse_rtx" directives. */
+ auto_vec<rtx> m_reuse_rtx_by_id;
};
/* Global singleton; constrast with md_reader_ptr above. */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
new file mode 100644
index 0000000..cef834e
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,1657 @@
+/* read-rtl-function.c - Reader for RTL function dumps
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "read-md.h"
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "read-rtl-function.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
+
+/* Forward decls. */
+class function_reader;
+class fixup;
+
+/* Edges are recorded when parsing the "insn-chain" directive,
+ and created at the end when all the blocks ought to exist.
+ This struct records an "edge-from" or "edge-to" directive seen
+ at LOC, which will be turned into an actual CFG edge once
+ the "insn-chain" is fully parsed. */
+
+struct deferred_edge
+{
+ deferred_edge (file_location loc, int src_bb_idx, int dest_bb_idx, int flags)
+ : m_loc (loc), m_src_bb_idx (src_bb_idx), m_dest_bb_idx (dest_bb_idx),
+ m_flags (flags)
+ {}
+
+ file_location m_loc;
+ int m_src_bb_idx;
+ int m_dest_bb_idx;
+ int m_flags;
+};
+
+/* Subclass of rtx_reader for reading function dumps. */
+
+class function_reader : public rtx_reader
+{
+ public:
+ function_reader ();
+ ~function_reader ();
+
+ /* Overridden vfuncs of class md_reader. */
+ void handle_unknown_directive (file_location, const char *) FINAL OVERRIDE;
+
+ /* Overridden vfuncs of class rtx_reader. */
+ rtx read_rtx_operand (rtx x, int idx) FINAL OVERRIDE;
+ void handle_any_trailing_information (rtx x) FINAL OVERRIDE;
+ rtx postprocess (rtx) FINAL OVERRIDE;
+ const char *finalize_string (char *stringbuf) FINAL OVERRIDE;
+
+ rtx_insn **get_insn_by_uid (int uid);
+ tree parse_mem_expr (const char *desc);
+
+ private:
+ void parse_function ();
+ void create_function ();
+ void parse_param ();
+ void parse_insn_chain ();
+ void parse_block ();
+ int parse_bb_idx ();
+ void parse_edge (basic_block block, bool from);
+ rtx_insn *parse_insn (file_location loc, const char *name);
+ void parse_cfg (file_location loc);
+ void parse_crtl (file_location loc);
+ void create_edges ();
+
+ int parse_enum_value (int num_values, const char *const *strings);
+
+ void read_rtx_operand_u (rtx x, int idx);
+ void read_rtx_operand_i_or_n (rtx x, int idx, char format_char);
+ rtx read_rtx_operand_r (rtx x);
+ void extra_parsing_for_operand_code_0 (rtx x, int idx);
+
+ void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid);
+
+ void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx);
+
+ void add_fixup_source_location (file_location loc, rtx insn,
+ int operand_idx,
+ const char *filename, int lineno);
+
+ void add_fixup_expr (file_location loc, rtx x,
+ const char *desc);
+
+ rtx consolidate_singletons (rtx x);
+ rtx parse_rtx ();
+ void maybe_read_location (int operand_idx, rtx insn);
+
+ void handle_insn_uids ();
+ void apply_fixups ();
+
+ private:
+ struct uid_hash : int_hash <int, -1, -2> {};
+ hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+ auto_vec<fixup *> m_fixups;
+ rtx_insn *m_first_insn;
+ auto_vec<tree> m_fake_scope;
+ char *m_name;
+ bool m_have_crtl_directive;
+ basic_block m_bb_to_insert_after;
+ auto_vec <deferred_edge> m_deferred_edges;
+ int m_highest_bb_idx;
+};
+
+/* Abstract base class for recording post-processing steps that must be
+ done after reading a .rtl file. */
+
+class fixup
+{
+ public:
+ fixup (file_location loc, rtx x)
+ : m_loc (loc), m_rtx (x)
+ {}
+ virtual ~fixup () {}
+
+ virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+ file_location m_loc;
+ rtx m_rtx;
+};
+
+/* An abstract subclass of fixup for post-processing steps that
+ act on a specific operand of a specific instruction. */
+
+class operand_fixup : public fixup
+{
+ public:
+ operand_fixup (file_location loc, rtx insn, int operand_idx)
+ : fixup (loc, insn), m_operand_idx (operand_idx)
+ {}
+
+ protected:
+ int m_operand_idx;
+};
+
+/* A concrete subclass of operand_fixup: fixup an rtx_insn *
+ field (NEXT_INSN/PREV_INSN) based on an integer UID. */
+
+class fixup_insn_uid : public operand_fixup
+{
+ public:
+ fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
+ : operand_fixup (loc, insn, operand_idx),
+ m_insn_uid (insn_uid)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_insn_uid;
+};
+
+/* A concrete subclass of operand_fixup: fix up a
+ NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+class fixup_note_insn_basic_block : public operand_fixup
+{
+ public:
+ fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
+ int bb_idx)
+ : operand_fixup (loc, insn, operand_idx),
+ m_bb_idx (bb_idx)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_bb_idx;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+ the expr of an rtx (REG or MEM) based on a textual dump. */
+
+class fixup_expr : public fixup
+{
+ public:
+ fixup_expr (file_location loc, rtx x, const char *desc)
+ : fixup (loc, x),
+ m_desc (xstrdup (desc))
+ {}
+
+ ~fixup_expr () { free (m_desc); }
+
+ void apply (function_reader *reader) const;
+
+ private:
+ char *m_desc;
+};
+
+/* Return a textual description of the given operand of the given rtx. */
+
+static const char *
+get_operand_name (rtx insn, int operand_idx)
+{
+ gcc_assert (is_a <rtx_insn *> (insn));
+ switch (operand_idx)
+ {
+ case 0:
+ return "PREV_INSN";
+ case 1:
+ return "NEXT_INSN";
+ default:
+ return NULL;
+ }
+}
+
+/* Fixup an rtx_insn * field (NEXT_INSN/PREV_INSN) based on an integer
+ UID. */
+
+void
+fixup_insn_uid::apply (function_reader *reader) const
+{
+ rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
+ if (insn_from_uid)
+ XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
+ else
+ {
+ const char *op_name = get_operand_name (m_rtx, m_operand_idx);
+ if (op_name)
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i (`%s') of insn %i",
+ m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
+ else
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i of insn %i",
+ m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
+ }
+}
+
+/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+void
+fixup_note_insn_basic_block::apply (function_reader *) const
+{
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+ gcc_assert (bb);
+ NOTE_BASIC_BLOCK (m_rtx) = bb;
+}
+
+/* Fix up the expr of an rtx (REG or MEM) based on a textual dump. */
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+ tree expr = reader->parse_mem_expr (m_desc);
+ switch (GET_CODE (m_rtx))
+ {
+ case REG:
+ set_reg_attrs_for_decl_rtl (expr, m_rtx);
+ break;
+ case MEM:
+ set_mem_expr (m_rtx, expr);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Strip trailing whitespace from DESC. */
+
+static void
+strip_trailing_whitespace (char *desc)
+{
+ char *terminator = desc + strlen (desc);
+ while (desc < terminator)
+ {
+ terminator--;
+ if (ISSPACE (*terminator))
+ *terminator = '\0';
+ else
+ break;
+ }
+}
+
+/* Return the numeric value n for GET_NOTE_INSN_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+static int
+parse_note_insn_name (const char *string)
+{
+ for (int i = 0; i < NOTE_INSN_MAX; i++)
+ if (0 == strcmp (string, GET_NOTE_INSN_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
+}
+
+/* Return the register number for NAME, or return -1 if it isn't
+ recognized. */
+
+static int
+lookup_reg_by_dump_name (const char *name)
+{
+ for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (reg_names[i][0]
+ && ! strcmp (name, reg_names[i]))
+ return i;
+
+ /* Also lookup virtuals. */
+ if (!strcmp (name, "virtual-incoming-args"))
+ return VIRTUAL_INCOMING_ARGS_REGNUM;
+ if (!strcmp (name, "virtual-stack-vars"))
+ return VIRTUAL_STACK_VARS_REGNUM;
+ if (!strcmp (name, "virtual-stack-dynamic"))
+ return VIRTUAL_STACK_DYNAMIC_REGNUM;
+ if (!strcmp (name, "virtual-outgoing-args"))
+ return VIRTUAL_OUTGOING_ARGS_REGNUM;
+ if (!strcmp (name, "virtual-cfa"))
+ return VIRTUAL_CFA_REGNUM;
+ if (!strcmp (name, "virtual-preferred-stack-boundary"))
+ return VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM;
+ /* TODO: handle "virtual-reg-%d". */
+
+ /* In compact mode, pseudos are printed with a '%' sigil following
+ by the regno, offset by (LAST_VIRTUAL_REGISTER + 1), so that the
+ first non-virtual pseudo is dumped as "%0". */
+ if (name[0] == '%')
+ {
+ int dump_num = atoi (name + 1);
+ return dump_num + LAST_VIRTUAL_REGISTER + 1;
+ }
+
+ /* Not found. */
+ return -1;
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor. */
+
+function_reader::function_reader ()
+: rtx_reader (true),
+ m_first_insn (NULL),
+ m_name (NULL),
+ m_have_crtl_directive (false),
+ m_bb_to_insert_after (NULL),
+ m_highest_bb_idx (EXIT_BLOCK)
+{
+}
+
+/* function_reader's destructor. */
+
+function_reader::~function_reader ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ delete f;
+
+ free (m_name);
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+
+ Require a top-level "function" directive, as emitted by
+ print_rtx_function, and parse it. */
+
+void
+function_reader::handle_unknown_directive (file_location start_loc,
+ const char *name)
+{
+ if (strcmp (name, "function"))
+ fatal_at (start_loc, "expected 'function'");
+
+ parse_function ();
+}
+
+/* Parse the output of print_rtx_function (or hand-written data in the
+ same format), having already parsed the "(function" heading, and
+ finishing immediately before the final ")".
+
+ The "param" and "crtl" clauses are optional. */
+
+void
+function_reader::parse_function ()
+{
+ m_name = xstrdup (read_string (0));
+
+ create_function ();
+
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ if (c == ')')
+ {
+ unread_char (c);
+ break;
+ }
+ unread_char (c);
+ require_char ('(');
+ file_location loc = get_current_location ();
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "param") == 0)
+ parse_param ();
+ else if (strcmp (directive.string, "insn-chain") == 0)
+ parse_insn_chain ();
+ else if (strcmp (directive.string, "crtl") == 0)
+ parse_crtl (loc);
+ else
+ fatal_with_file_and_line ("unrecognized directive: %s",
+ directive.string);
+ }
+
+ handle_insn_uids ();
+
+ apply_fixups ();
+
+ /* Rebuild the JUMP_LABEL field of any JUMP_INSNs in the chain, and the
+ LABEL_NUSES of any CODE_LABELs.
+
+ This has to happen after apply_fixups, since only after then do
+ LABEL_REFs have their label_ref_label set up. */
+ rebuild_jump_labels (get_insns ());
+
+ crtl->init_stack_alignment ();
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+ Create "cfun" and a decl for the function.
+ By default, every function decl is hardcoded as
+ int test_1 (int i, int j, int k);
+ Set up various other state:
+ - the cfg and basic blocks (edges are created later, *after* fixups
+ are applied).
+ - add the function to the callgraph. */
+
+void
+function_reader::create_function ()
+{
+ /* We start in cfgrtl mode, rather than cfglayout mode. */
+ rtl_register_cfg_hooks ();
+
+ /* Create cfun. */
+ tree fn_name = get_identifier (m_name ? m_name : "test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+
+ current_function_decl = fndecl;
+
+ cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+ /* Do we need this to force cgraphunit.c to output the function? */
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_PRESERVE_P (fndecl) = 1;
+
+ /* Add to cgraph. */
+ cgraph_node::finalize_function (fndecl, false);
+
+ /* Create bare-bones cfg. This creates the entry and exit blocks. */
+ init_empty_tree_cfg_for_function (cfun);
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+ EXIT_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+ init_rtl_bb_info (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ init_rtl_bb_info (EXIT_BLOCK_PTR_FOR_FN (cfun));
+ m_bb_to_insert_after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+
+}
+
+/* Parse the content of a "param" directive, having already parsed the
+ "(param". Consume the trailing ')'. */
+
+void
+function_reader::parse_param ()
+{
+ require_char_ws ('"');
+ char *name = read_quoted_string ();
+
+ /* Lookup param by name. */
+ tree t_param = parse_mem_expr (name);
+ // TODO: what if not found?
+
+ /* Parse DECL_RTL. */
+ require_char_ws ('(');
+ require_word_ws ("DECL_RTL");
+ DECL_WRTL_CHECK (t_param)->decl_with_rtl.rtl = parse_rtx ();
+ require_char_ws (')');
+
+ /* Parse DECL_RTL_INCOMING. */
+ require_char_ws ('(');
+ require_word_ws ("DECL_RTL_INCOMING");
+ DECL_INCOMING_RTL (t_param) = parse_rtx ();
+ require_char_ws (')');
+
+ require_char_ws (')');
+}
+
+/* Parse zero or more child insn elements within an
+ "insn-chain" element. Consume the trailing ')'. */
+
+void
+function_reader::parse_insn_chain ()
+{
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ file_location loc = get_current_location ();
+ if (c == ')')
+ break;
+ else if (c == '(')
+ {
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "block") == 0)
+ parse_block ();
+ else
+ parse_insn (loc, directive.string);
+ }
+ else
+ fatal_at (loc, "expected '(' or ')'");
+ }
+
+ create_edges ();
+}
+
+/* Parse zero or more child directives (edges and insns) within a
+ "block" directive, having already parsed the "(block " heading.
+ Consume the trailing ')'. */
+
+void
+function_reader::parse_block ()
+{
+ /* Parse the index value from the dump. This will be an integer;
+ we don't support "entry" or "exit" here (unlike for edges). */
+ struct md_name name;
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+
+ /* The term "index" has two meanings for basic blocks in a CFG:
+ (a) the "index" field within struct basic_block_def.
+ (b) the index of a basic_block within the cfg's x_basic_block_info
+ vector, as accessed via BASIC_BLOCK_FOR_FN.
+
+ These can get out-of-sync when basic blocks are optimized away.
+ They get back in sync by "compact_blocks".
+ We reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
+ values in it for any missing basic blocks, so that (a) == (b) for
+ all of the blocks we create. The doubly-linked list of basic
+ blocks (next_bb/prev_bb) skips over these "holes". */
+
+ if (m_highest_bb_idx < bb_idx)
+ m_highest_bb_idx = bb_idx;
+
+ size_t new_size = m_highest_bb_idx + 1;
+ if (basic_block_info_for_fn (cfun)->length () < new_size)
+ vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
+
+ last_basic_block_for_fn (cfun) = new_size;
+
+ /* Create the basic block.
+
+ We can't call create_basic_block and use the regular RTL block-creation
+ hooks, since this creates NOTE_INSN_BASIC_BLOCK instances. We don't
+ want to do that; we want to use the notes we were provided with. */
+ basic_block bb = alloc_block ();
+ init_rtl_bb_info (bb);
+ bb->index = bb_idx;
+ bb->flags = BB_NEW | BB_RTL;
+ link_block (bb, m_bb_to_insert_after);
+ m_bb_to_insert_after = bb;
+
+ n_basic_blocks_for_fn (cfun)++;
+ SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
+ BB_SET_PARTITION (bb, BB_UNPARTITIONED);
+
+ /* Handle insns, edge-from and edge-to directives. */
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ file_location loc = get_current_location ();
+ if (c == ')')
+ break;
+ else if (c == '(')
+ {
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "edge-from") == 0)
+ parse_edge (bb, true);
+ else if (strcmp (directive.string, "edge-to") == 0)
+ parse_edge (bb, false);
+ else
+ {
+ rtx_insn *insn = parse_insn (loc, directive.string);
+ set_block_for_insn (insn, bb);
+ if (!BB_HEAD (bb))
+ BB_HEAD (bb) = insn;
+ BB_END (bb) = insn;
+ }
+ }
+ else
+ fatal_at (loc, "expected '(' or ')'");
+ }
+}
+
+/* Subroutine of function_reader::parse_edge.
+ Parse a basic block index, handling "entry" and "exit". */
+
+int
+function_reader::parse_bb_idx ()
+{
+ struct md_name name;
+ read_name (&name);
+ if (strcmp (name.string, "entry") == 0)
+ return ENTRY_BLOCK;
+ if (strcmp (name.string, "exit") == 0)
+ return EXIT_BLOCK;
+ return atoi (name.string);
+}
+
+/* Subroutine of parse_edge_flags.
+ Parse a token such as "FALLTHRU", converting to the flag value.
+ Issue an error if the token is unrecognized. */
+
+static int
+parse_edge_flag_token (const char *tok)
+{
+#define DEF_EDGE_FLAG(NAME,IDX) \
+ do { \
+ if (strcmp (tok, #NAME) == 0) \
+ return EDGE_##NAME; \
+ } while (0);
+#include "cfg-flags.def"
+#undef DEF_EDGE_FLAG
+ error ("unrecognized edge flag: '%s'", tok);
+ return 0;
+}
+
+/* Subroutine of function_reader::parse_edge.
+ Parse STR and convert to a flag value (or issue an error).
+ The parser uses strtok and hence modifiers STR in-place. */
+
+static int
+parse_edge_flags (char *str)
+{
+ int result = 0;
+
+ char *tok = strtok (str, "| ");
+ while (tok)
+ {
+ result |= parse_edge_flag_token (tok);
+ tok = strtok (NULL, "| ");
+ }
+
+ return result;
+}
+
+/* Parse an "edge-from" or "edge-to" directive within the "block"
+ directive for BLOCK, having already parsed the "(edge" heading.
+ Consume the final ")". Record the edge within m_deferred_edges. */
+
+void
+function_reader::parse_edge (basic_block block, bool from)
+{
+ gcc_assert (block);
+ int this_bb_idx = block->index;
+ file_location loc = get_current_location ();
+ int other_bb_idx = parse_bb_idx ();
+
+ /* "(edge-from 2)" means src = 2, dest = this_bb_idx, whereas
+ "(edge-to 3)" means src = this_bb_idx, dest = 3. */
+ int src_idx = from ? other_bb_idx : this_bb_idx;
+ int dest_idx = from ? this_bb_idx : other_bb_idx;
+
+ /* Optional "(flags)". */
+ int flags = 0;
+ int c = read_skip_spaces ();
+ if (c == '(')
+ {
+ require_word_ws ("flags");
+ require_char_ws ('"');
+ char *str = read_quoted_string ();
+ flags = parse_edge_flags (str);
+ require_char_ws (')');
+ }
+ else
+ unread_char (c);
+
+ require_char_ws (')');
+
+ /* This BB already exists, but the other BB might not yet.
+ For now, save the edges, and create them at the end of insn-chain
+ processing. */
+ /* For now, only process the (edge-from) to this BB, and (edge-to)
+ that go to the exit block.
+ FIXME: we don't yet verify that the edge-from and edge-to directives
+ are consistent. */
+ if (from || dest_idx == EXIT_BLOCK)
+ m_deferred_edges.safe_push (deferred_edge (loc, src_idx, dest_idx, flags));
+}
+
+/* Parse rtx instructions by calling read_rtx_code, calling
+ set_first_insn and set_last_insn as appropriate, and
+ adding the insn to the insn chain.
+ Consume the trailing ')'. */
+
+rtx_insn *
+function_reader::parse_insn (file_location start_loc, const char *name)
+{
+ rtx x = read_rtx_code (name);
+ if (!x)
+ fatal_at (start_loc, "expected insn type; got '%s'", name);
+ rtx_insn *insn = dyn_cast <rtx_insn *> (x);
+ if (!insn)
+ fatal_at (start_loc, "expected insn type; got '%s'", name);
+
+ /* Consume the trailing ')'. */
+ require_char_ws (')');
+
+ rtx_insn *last_insn = get_last_insn ();
+
+ /* Add "insn" to the insn chain. */
+ if (last_insn)
+ {
+ gcc_assert (NEXT_INSN (last_insn) == NULL);
+ SET_NEXT_INSN (last_insn) = insn;
+ }
+ SET_PREV_INSN (insn) = last_insn;
+
+ /* Add it to the sequence. */
+ set_last_insn (insn);
+ if (!m_first_insn)
+ {
+ m_first_insn = insn;
+ set_first_insn (insn);
+ }
+
+ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
+ maybe_set_max_label_num (label);
+
+ return insn;
+}
+
+/* Postprocessing subroutine for parse_insn_chain: all the basic blocks
+ should have been created by now; create the edges that were seen. */
+
+void
+function_reader::create_edges ()
+{
+ int i;
+ deferred_edge *de;
+ FOR_EACH_VEC_ELT (m_deferred_edges, i, de)
+ {
+ /* The BBs should already have been created by parse_block. */
+ basic_block src = BASIC_BLOCK_FOR_FN (cfun, de->m_src_bb_idx);
+ if (!src)
+ fatal_at (de->m_loc, "error: block index %i not found",
+ de->m_src_bb_idx);
+ basic_block dst = BASIC_BLOCK_FOR_FN (cfun, de->m_dest_bb_idx);
+ if (!dst)
+ fatal_at (de->m_loc, "error: block with index %i not found",
+ de->m_dest_bb_idx);
+ unchecked_make_edge (src, dst, de->m_flags);
+ }
+}
+
+/* Parse a "crtl" directive, having already parsed the "(crtl" heading.
+ Consume the final ")". */
+
+void
+function_reader::parse_crtl (file_location loc)
+{
+ if (m_have_crtl_directive)
+ error_at (loc, "more than one 'crtl' directive");
+ m_have_crtl_directive = true;
+
+ /* return_rtx. */
+ require_char_ws ('(');
+ require_word_ws ("return_rtx");
+ crtl->return_rtx = parse_rtx ();
+ require_char_ws (')');
+
+ require_char_ws (')');
+}
+
+/* Parse operand IDX of X, returning X, or an equivalent rtx
+ expression (for consolidating singletons).
+ This is an overridden implementation of rtx_reader::read_rtx_operand for
+ function_reader, handling various extra data printed by print_rtx,
+ and sometimes calling the base class implementation. */
+
+rtx
+function_reader::read_rtx_operand (rtx x, int idx)
+{
+ RTX_CODE code = GET_CODE (x);
+ const char *format_ptr = GET_RTX_FORMAT (code);
+ const char format_char = format_ptr[idx];
+ struct md_name name;
+
+ /* Override the regular parser for some format codes. */
+ switch (format_char)
+ {
+ case 'e':
+ if (idx == 7 && CALL_P (x))
+ {
+ m_in_call_function_usage = true;
+ return rtx_reader::read_rtx_operand (x, idx);
+ m_in_call_function_usage = false;
+ }
+ else
+ return rtx_reader::read_rtx_operand (x, idx);
+ break;
+
+ case 'u':
+ read_rtx_operand_u (x, idx);
+ /* Don't run regular parser for 'u'. */
+ return x;
+
+ case 'i':
+ case 'n':
+ read_rtx_operand_i_or_n (x, idx, format_char);
+ /* Don't run regular parser for these codes. */
+ return x;
+
+ case 'B':
+ gcc_assert (is_compact ());
+ /* Compact mode doesn't store BBs. */
+ /* Don't run regular parser. */
+ return x;
+
+ case 'r':
+ /* Don't run regular parser for 'r'. */
+ return read_rtx_operand_r (x);
+
+ default:
+ break;
+ }
+
+ /* Call base class implementation. */
+ x = rtx_reader::read_rtx_operand (x, idx);
+
+ /* Handle any additional parsing needed to handle what the dump
+ could contain. */
+ switch (format_char)
+ {
+ case '0':
+ extra_parsing_for_operand_code_0 (x, idx);
+ break;
+
+ case 'w':
+ if (!is_compact ())
+ {
+ /* Strip away the redundant hex dump of the value. */
+ require_char_ws ('[');
+ read_name (&name);
+ require_char_ws (']');
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+/* Parse operand IDX of X, of code 'u', when reading function dumps.
+
+ The RTL file recorded the ID of an insn (or 0 for NULL); we
+ must store this as a pointer, but the insn might not have
+ been loaded yet. Store the ID away for now, via a fixup. */
+
+void
+function_reader::read_rtx_operand_u (rtx x, int idx)
+{
+ /* In compact mode, the PREV/NEXT insn uids are not dumped, so skip
+ the "uu" when reading. */
+ if (is_compact () && GET_CODE (x) != LABEL_REF)
+ return;
+
+ struct md_name name;
+ file_location loc = read_name (&name);
+ int insn_id = atoi (name.string);
+ if (insn_id)
+ add_fixup_insn_uid (loc, x, idx, insn_id);
+}
+
+/* Read a name, looking for a match against a string found in array
+ STRINGS of size NUM_VALUES.
+ Return the index of the the matched string, or emit an error. */
+
+int
+function_reader::parse_enum_value (int num_values, const char *const *strings)
+{
+ struct md_name name;
+ read_name (&name);
+ for (int i = 0; i < num_values; i++)
+ {
+ if (strcmp (name.string, strings[i]) == 0)
+ return i;
+ }
+ error ("unrecognized enum value: '%s'", name.string);
+ return 0;
+}
+
+/* Parse operand IDX of X, of code 'i' or 'n'.
+ Special-cased handling of these, for reading function dumps. */
+
+void
+function_reader::read_rtx_operand_i_or_n (rtx x, int idx,
+ char format_char)
+{
+ /* Handle some of the extra information that print_rtx
+ can write out for these cases. */
+ /* print_rtx only writes out operand 5 for notes
+ for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+ and NOTE_INSN_DELETED_DEBUG_LABEL. */
+ if (idx == 5 && NOTE_P (x))
+ return;
+
+ if (idx == 4 && INSN_P (x))
+ {
+ maybe_read_location (idx, x);
+ return;
+ }
+
+ /* INSN_CODEs aren't printed in compact mode, so don't attempt to
+ parse them. */
+ if (is_compact ()
+ && INSN_P (x)
+ && &INSN_CODE (x) == &XINT (x, idx))
+ {
+ INSN_CODE (x) = -1;
+ return;
+ }
+
+ /* Handle UNSPEC and UNSPEC_VOLATILE's operand 1. */
+#if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0
+ if (idx == 1
+ && GET_CODE (x) == UNSPEC_VOLATILE)
+ {
+ XINT (x, 1)
+ = parse_enum_value (NUM_UNSPECV_VALUES, unspecv_strings);
+ return;
+ }
+#endif
+#if !defined(GENERATOR_FILE) && NUM_UNSPEC_VALUES > 0
+ if (idx == 1
+ && (GET_CODE (x) == UNSPEC
+ || GET_CODE (x) == UNSPEC_VOLATILE))
+ {
+ XINT (x, 1)
+ = parse_enum_value (NUM_UNSPEC_VALUES, unspec_strings);
+ return;
+ }
+#endif
+
+ struct md_name name;
+ read_name (&name);
+ int value;
+ if (format_char == 'n')
+ value = parse_note_insn_name (name.string);
+ else
+ value = atoi (name.string);
+ XINT (x, idx) = value;
+}
+
+/* Parse the 'r' operand of X, returning X, or an equivalent rtx
+ expression (for consolidating singletons).
+ Special-cased handling of code 'r' for reading function dumps. */
+
+rtx
+function_reader::read_rtx_operand_r (rtx x)
+{
+ struct md_name name;
+ file_location loc = read_name (&name);
+ int regno = lookup_reg_by_dump_name (name.string);
+ if (regno == -1)
+ fatal_at (loc, "unrecognized register: '%s'", name.string);
+
+ set_regno_raw (x, regno, 1);
+
+ /* Consolidate singletons. */
+ x = consolidate_singletons (x);
+
+ ORIGINAL_REGNO (x) = regno;
+
+ /* Parse extra stuff at end of 'r'.
+ We may have zero, one, or two sections marked by square
+ brackets. */
+ int ch = read_skip_spaces ();
+ bool expect_original_regno = false;
+ if (ch == '[')
+ {
+ file_location loc = get_current_location ();
+ char *desc = read_until ("]", true);
+ strip_trailing_whitespace (desc);
+ const char *desc_start = desc;
+ /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+ "orig:%i", ORIGINAL_REGNO (rtx).
+ Consume it, we don't set ORIGINAL_REGNO, since we can
+ get that from the 2nd copy later. */
+ if (0 == strncmp (desc, "orig:", 5))
+ {
+ expect_original_regno = true;
+ desc_start += 5;
+ /* Skip to any whitespace following the integer. */
+ const char *space = strchr (desc_start, ' ');
+ if (space)
+ desc_start = space + 1;
+ }
+ /* Any remaining text may be the REG_EXPR. Alternatively we have
+ no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
+ if (ISDIGIT (*desc_start))
+ {
+ /* Assume we have ORIGINAL_REGNO. */
+ ORIGINAL_REGNO (x) = atoi (desc_start);
+ }
+ else
+ {
+ /* Assume we have REG_EXPR. */
+ add_fixup_expr (loc, x, desc_start);
+ }
+ free (desc);
+ }
+ else
+ unread_char (ch);
+ if (expect_original_regno)
+ {
+ require_char_ws ('[');
+ char *desc = read_until ("]", true);
+ ORIGINAL_REGNO (x) = atoi (desc);
+ free (desc);
+ }
+
+ return x;
+}
+
+/* Additional parsing for format code '0' in dumps, handling a variety
+ of special-cases in print_rtx, when parsing operand IDX of X. */
+
+void
+function_reader::extra_parsing_for_operand_code_0 (rtx x, int idx)
+{
+ RTX_CODE code = GET_CODE (x);
+ int c;
+ struct md_name name;
+
+ if (idx == 1 && code == SYMBOL_REF)
+ {
+ /* Possibly wrote " [flags %#x]", SYMBOL_REF_FLAGS (in_rtx). */
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ file_location loc = read_name (&name);
+ if (strcmp (name.string, "flags"))
+ error_at (loc, "was expecting `%s'", "flags");
+ read_name (&name);
+ SYMBOL_REF_FLAGS (x) = strtol (name.string, NULL, 16);
+
+ /* We can't reconstruct SYMBOL_REF_BLOCK; set it to NULL. */
+ if (SYMBOL_REF_HAS_BLOCK_INFO_P (x))
+ SYMBOL_REF_BLOCK (x) = NULL;
+
+ require_char (']');
+ }
+ else
+ unread_char (c);
+
+ /* If X had a non-NULL SYMBOL_REF_DECL,
+ rtx_writer::print_rtx_operand_code_0 would have dumped it
+ using print_node_brief.
+ Skip the content for now. */
+ c = read_skip_spaces ();
+ if (c == '<')
+ {
+ while (1)
+ {
+ char ch = read_char ();
+ if (ch == '>')
+ break;
+ }
+ }
+ else
+ unread_char (c);
+ }
+ else if (idx == 3 && code == NOTE)
+ {
+ /* Note-specific data appears for operand 3, which annoyingly
+ is before the enum specifying which kind of note we have
+ (operand 4). */
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ /* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+ [bb %d]. */
+ file_location bb_loc = read_name (&name);
+ if (strcmp (name.string, "bb"))
+ error_at (bb_loc, "was expecting `%s'", "bb");
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+ add_fixup_note_insn_basic_block (bb_loc, x, idx,
+ bb_idx);
+ require_char_ws (']');
+ }
+ else
+ unread_char (c);
+ }
+}
+
+/* Implementation of rtx_reader::handle_any_trailing_information.
+ Handle the various additional information that print-rtl.c can
+ write after the regular fields, when parsing X. */
+
+void
+function_reader::handle_any_trailing_information (rtx x)
+{
+ struct md_name name;
+
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ {
+ int ch;
+ require_char_ws ('[');
+ read_name (&name);
+ MEM_ALIAS_SET (x) = atoi (name.string);
+ /* We have either a MEM_EXPR, or a space. */
+ if (peek_char () != ' ')
+ {
+ file_location loc = get_current_location ();
+ char *desc = read_until (" +", false);
+ add_fixup_expr (loc, consolidate_singletons (x), desc);
+ free (desc);
+ }
+ else
+ read_char ();
+
+ /* We may optionally have '+' for MEM_OFFSET_KNOWN_P. */
+ ch = read_skip_spaces ();
+ if (ch == '+')
+ {
+ read_name (&name);
+ MEM_OFFSET_KNOWN_P (x) = 1;
+ MEM_OFFSET (x) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " S" for MEM_SIZE. */
+ ch = read_skip_spaces ();
+ if (ch == 'S')
+ {
+ read_name (&name);
+ MEM_SIZE (x) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " A" for MEM_ALIGN. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () != 'S')
+ {
+ read_name (&name);
+ MEM_ALIGN (x) = atoi (name.string);
+ }
+
+ /* Handle optional " AS" for MEM_ADDR_SPACE. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () == 'S')
+ {
+ read_char ();
+ read_name (&name);
+ MEM_ADDR_SPACE (x) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ require_char (']');
+ }
+ break;
+
+ case CODE_LABEL:
+ /* Assume that LABEL_NUSES was not dumped. */
+ /* TODO: parse LABEL_KIND. */
+ /* For now, skip until closing ')'. */
+ do
+ {
+ char ch = read_char ();
+ if (ch == ')')
+ {
+ unread_char (ch);
+ break;
+ }
+ }
+ while (1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Parse a tree dump for a MEM_EXPR in DESC and turn it back into a tree.
+ We handle "<retval>", but for anything else we "cheat" by building a
+ global VAR_DECL of type "int" with that name (returning the same global
+ for a name if we see the same name more than once). */
+
+tree
+function_reader::parse_mem_expr (const char *desc)
+{
+ tree fndecl = cfun->decl;
+
+ if (0 == strcmp (desc, "<retval>"))
+ return DECL_RESULT (fndecl);
+
+ /* Search within function parms. */
+ for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
+ if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (arg))) == 0)
+ return arg;
+
+ /* Search within decls we already created.
+ FIXME: use a hash rather than linear search. */
+ int i;
+ tree t;
+ FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+ if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))) == 0)
+ return t;
+
+ /* Not found? Create it.
+ This allows mimicking of real data but avoids having to specify
+ e.g. names of locals, params etc.
+ Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
+ and we don't know the types. Fake it by making everything be
+ a VAR_DECL of "int" type. */
+ t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (desc),
+ integer_type_node);
+ m_fake_scope.safe_push (t);
+ return t;
+}
+
+/* Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid)
+{
+ m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx)
+{
+ m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+ bb_idx));
+}
+
+/* Record the information for later post-processing. */
+void
+function_reader::add_fixup_source_location (file_location, rtx,
+ int, const char *, int)
+{
+ /* Empty for now. */
+}
+
+/* Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+ const char *desc)
+{
+ gcc_assert (desc);
+ /* Fail early if the RTL reader erroneously hands us an int. */
+ gcc_assert (!ISDIGIT (desc[0]));
+
+ m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Helper function for consolidate_reg. Return the global rtx for
+ the register with regno REGNO. */
+
+static rtx
+lookup_global_register (int regno)
+{
+ /* We can't use a switch here, as some of the REGNUMs might not be constants
+ for some targets. */
+ if (regno == STACK_POINTER_REGNUM)
+ return stack_pointer_rtx;
+ else if (regno == FRAME_POINTER_REGNUM)
+ return frame_pointer_rtx;
+ else if (regno == HARD_FRAME_POINTER_REGNUM)
+ return hard_frame_pointer_rtx;
+ else if (regno == ARG_POINTER_REGNUM)
+ return arg_pointer_rtx;
+ else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
+ return virtual_incoming_args_rtx;
+ else if (regno == VIRTUAL_STACK_VARS_REGNUM)
+ return virtual_stack_vars_rtx;
+ else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
+ return virtual_stack_dynamic_rtx;
+ else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
+ return virtual_outgoing_args_rtx;
+ else if (regno == VIRTUAL_CFA_REGNUM)
+ return virtual_cfa_rtx;
+ else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
+ return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+ else if (regno == RETURN_ADDRESS_POINTER_REGNUM)
+ return return_address_pointer_rtx;
+#endif
+
+ return NULL;
+}
+
+/* Ensure that the backend can cope with a REG with regno REGNO.
+ Normally REG instances are created by gen_reg_rtx which updates
+ regno_reg_rtx, growing it as necessary.
+ The REG instances created from the dumpfile weren't created this
+ way, so we need to manually update regno_reg_rtx. */
+
+static void
+ensure_regno (int regno)
+{
+ if (reg_rtx_no < regno + 1)
+ reg_rtx_no = regno + 1;
+
+ crtl->emit.ensure_regno_capacity ();
+ gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+}
+
+/* Helper function for consolidate_singletons, for handling REG instances.
+ Given REG instance X of some regno, return the singleton rtx for that
+ regno, if it exists, or X. */
+
+static rtx
+consolidate_reg (rtx x)
+{
+ gcc_assert (GET_CODE (x) == REG);
+
+ unsigned int regno = REGNO (x);
+
+ ensure_regno (regno);
+
+ /* Some register numbers have their rtx created in init_emit_regs
+ e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
+ Consolidate on this. */
+ rtx global_reg = lookup_global_register (regno);
+ if (global_reg)
+ return global_reg;
+
+ /* Populate regno_reg_rtx if necessary. */
+ if (regno_reg_rtx[regno] == NULL)
+ regno_reg_rtx[regno] = x;
+ /* Use it. */
+ gcc_assert (GET_CODE (regno_reg_rtx[regno]) == REG);
+ gcc_assert (REGNO (regno_reg_rtx[regno]) == regno);
+ if (GET_MODE (x) == GET_MODE (regno_reg_rtx[regno]))
+ return regno_reg_rtx[regno];
+
+ return x;
+}
+
+/* When reading RTL function dumps, we must consolidate some
+ rtx so that we use singletons where singletons are expected
+ (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
+ these are tested via pointer equality against const0_rtx.
+
+ Return the equivalent singleton rtx for X, if any, otherwise X. */
+
+rtx
+function_reader::consolidate_singletons (rtx x)
+{
+ if (!x)
+ return x;
+
+ switch (GET_CODE (x))
+ {
+ case PC: return pc_rtx;
+ case RETURN: return ret_rtx;
+ case SIMPLE_RETURN: return simple_return_rtx;
+ case CC0: return cc0_rtx;
+
+ case REG:
+ return consolidate_reg (x);
+
+ case CONST_INT:
+ return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+/* Parse an rtx directive, including both the opening/closing parentheses,
+ and the name. */
+
+rtx
+function_reader::parse_rtx ()
+{
+ require_char_ws ('(');
+ struct md_name directive;
+ read_name (&directive);
+ rtx result
+ = consolidate_singletons (read_rtx_code (directive.string));
+ require_char_ws (')');
+
+ return result;
+}
+
+/* Implementation of rtx_reader::postprocess for reading function dumps. */
+
+rtx
+function_reader::postprocess (rtx x)
+{
+ return consolidate_singletons (x);
+}
+
+/* Implementation of rtx_reader::finalize_string for reading function dumps.
+ Make a GC-managed copy of STRINGBUF. */
+
+const char *
+function_reader::finalize_string (char *stringbuf)
+{
+ return ggc_strdup (stringbuf);
+}
+
+/* Handle the optional location information written by print_rtx for
+ instructions. Specifically, operand 4 of instructions (of type "i')
+ is printed thus:
+
+ if (INSN_HAS_LOCATION (in_insn))
+ {
+ expanded_location xloc = insn_location (in_insn);
+ fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+ }
+
+ Hence we need to speculatively read a location of the form
+ " %s:%i", and unread the content if there wasn't one.
+
+ Assume that filenames can't contain whitespace, and can't
+ contain ':'. */
+
+void
+function_reader::maybe_read_location (int operand_idx, rtx insn)
+{
+ file_location loc = get_current_location ();
+
+ /* Skip to first non-whitespace. */
+ int ch = read_skip_spaces ();
+ auto_vec<char> buf;
+ buf.safe_push (ch);
+ while (1)
+ {
+ int ch = read_char ();
+ /* If we see a ':', assume we have a filename. */
+ if (ch == ':')
+ {
+ buf.safe_push ('\0');
+ break;
+ }
+ buf.safe_push (ch);
+
+ /* If we see a space before ':', assume we don't have a
+ filename. */
+ if (ISSPACE (ch))
+ {
+ while (!buf.is_empty ())
+ unread_char (buf.pop ());
+ return;
+ }
+ }
+ char *filename = buf.address ();
+ struct md_name name;
+ read_name (&name);
+
+ add_fixup_source_location (loc, insn, operand_idx,
+ filename, atoi (name.string));
+}
+
+/* Postprocessing subroutine of function_reader::parse_function.
+ Populate m_insns_by_uid. */
+
+void
+function_reader::handle_insn_uids ()
+{
+ /* Locate the currently assigned INSN_UID values, storing
+ them in m_insns_by_uid. */
+ int max_uid = 0;
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (m_insns_by_uid.get (INSN_UID (insn)))
+ error ("duplicate insn UID: %i", INSN_UID (insn));
+ m_insns_by_uid.put (INSN_UID (insn), insn);
+ if (INSN_UID (insn) > max_uid)
+ max_uid = INSN_UID (insn);
+ }
+
+ /* Ensure x_cur_insn_uid is 1 more than the biggest insn UID seen.
+ This is normally updated by the various make_*insn_raw functions. */
+ crtl->emit.x_cur_insn_uid = max_uid + 1;
+}
+
+/* Apply all of the recorded fixups. */
+
+void
+function_reader::apply_fixups ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ f->apply (this);
+}
+
+/* Given a UID value, try to locate a pointer to the corresponding
+ rtx_insn *, or NULL if if can't be found. */
+
+rtx_insn **
+function_reader::get_insn_by_uid (int uid)
+{
+ return m_insns_by_uid.get (uid);
+}
+
+/* Run the RTL dump parser. */
+
+bool
+read_rtl_function_body (int argc, const char **argv,
+ bool (*parse_opt) (const char *))
+{
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ function_reader reader;
+ if (!reader.read_md_files (argc, argv, parse_opt))
+ return false;
+
+ return true;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that parse_edge_flags works. */
+
+static void
+test_edge_flags ()
+{
+ /* parse_edge_flags modifies its input (due to strtok), so we must make
+ a copy of the literals. */
+#define ASSERT_PARSE_EDGE_FLAGS(EXPECTED, STR) \
+ do { \
+ char *str = xstrdup (STR); \
+ ASSERT_EQ (EXPECTED, parse_edge_flags (str)); \
+ free (str); \
+ } while (0)
+
+ ASSERT_PARSE_EDGE_FLAGS (0, "");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_FALLTHRU, "FALLTHRU");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL_CALL, "ABNORMAL_CALL");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL,
+ "ABNORMAL | ABNORMAL_CALL");
+
+#undef ASSERT_PARSE_EDGE_FLAGS
+}
+
+/* Verify that lookup_reg_by_dump_name works. */
+
+static void
+test_parsing_regnos ()
+{
+ ASSERT_EQ (-1, lookup_reg_by_dump_name ("this is not a register"));
+
+ /* Verify lookup of hard registers. */
+#ifdef GCC_AARCH64_H
+ ASSERT_EQ (0, lookup_reg_by_dump_name ("x0"));
+ ASSERT_EQ (1, lookup_reg_by_dump_name ("x1"));
+#endif
+#ifdef I386_OPTS_H
+ ASSERT_EQ (0, lookup_reg_by_dump_name ("ax"));
+ ASSERT_EQ (1, lookup_reg_by_dump_name ("dx"));
+#endif
+
+ /* Verify lookup of virtual registers. */
+ ASSERT_EQ (VIRTUAL_INCOMING_ARGS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-incoming-args"));
+ ASSERT_EQ (VIRTUAL_STACK_VARS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-stack-vars"));
+ ASSERT_EQ (VIRTUAL_STACK_DYNAMIC_REGNUM,
+ lookup_reg_by_dump_name ("virtual-stack-dynamic"));
+ ASSERT_EQ (VIRTUAL_OUTGOING_ARGS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-outgoing-args"));
+ ASSERT_EQ (VIRTUAL_CFA_REGNUM,
+ lookup_reg_by_dump_name ("virtual-cfa"));
+ ASSERT_EQ (VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM,
+ lookup_reg_by_dump_name ("virtual-preferred-stack-boundary"));
+
+ /* Verify lookup of non-virtual pseudos. */
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, lookup_reg_by_dump_name ("%0"));
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 2, lookup_reg_by_dump_name ("%1"));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+read_rtl_function_c_tests ()
+{
+ test_edge_flags ();
+ test_parsing_regnos ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
new file mode 100644
index 0000000..b2a6e81
--- /dev/null
+++ b/gcc/read-rtl-function.h
@@ -0,0 +1,26 @@
+/* read-rtl-function.h - Reader for RTL function dumps
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_READ_RTL_FUNCTION_H
+#define GCC_READ_RTL_FUNCTION_H
+
+extern bool read_rtl_function_body (int argc, const char **argv,
+ bool (*parse_opt) (const char *));
+
+#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index f74c875..eb3b59e 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
/* Disable rtl checking; it conflicts with the iterator handling. */
#undef ENABLE_RTL_CHECKING
@@ -30,6 +36,12 @@ along with GCC; see the file COPYING3. If not see
#include "read-md.h"
#include "gensupport.h"
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#endif
+
/* One element in a singly-linked list of (integer, string) pairs. */
struct map_value {
struct map_value *next;
@@ -106,6 +118,7 @@ htab_t subst_attr_to_iter_map = NULL;
const char *current_iterator_name;
static void validate_const_int (const char *);
+static void one_time_initialization (void);
/* Global singleton. */
rtx_reader *rtx_reader_ptr = NULL;
@@ -142,6 +155,25 @@ apply_mode_iterator (void *loc, int mode)
PUT_MODE ((rtx) loc, (machine_mode) mode);
}
+/* In compact dumps, the code of insns is prefixed with "c", giving "cinsn",
+ "cnote" etc, and CODE_LABEL is special-cased as "clabel". */
+
+struct compact_insn_name {
+ RTX_CODE code;
+ const char *name;
+};
+
+static const compact_insn_name compact_insn_names[] = {
+ { DEBUG_INSN, "cdebug_insn" },
+ { INSN, "cinsn" },
+ { JUMP_INSN, "cjump_insn" },
+ { CALL_INSN, "ccall_insn" },
+ { JUMP_TABLE_DATA, "cjump_table_data" },
+ { BARRIER, "cbarrier" },
+ { CODE_LABEL, "clabel" },
+ { NOTE, "cnote" }
+};
+
/* Implementations of the iterator_group callbacks for codes. */
static int
@@ -153,6 +185,10 @@ find_code (const char *name)
if (strcmp (GET_RTX_NAME (i), name) == 0)
return i;
+ for (i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
+ if (strcmp (compact_insn_names[i].name, name) == 0)
+ return compact_insn_names[i].code;
+
fatal_with_file_and_line ("unknown rtx code `%s'", name);
}
@@ -181,6 +217,8 @@ apply_int_iterator (void *loc, int value)
*(int *)loc = value;
}
+#ifdef GENERATOR_FILE
+
/* This routine adds attribute or does nothing depending on VALUE. When
VALUE is 1, it does nothing - the first duplicate of original
template is kept untouched when it's subjected to a define_subst.
@@ -252,6 +290,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
*slot = value;
}
+#endif /* #ifdef GENERATOR_FILE */
+
/* Return name of a subst-iterator, corresponding to subst-attribute ATTR. */
static char*
@@ -418,6 +458,8 @@ md_reader::copy_rtx_for_iterators (rtx original)
return x;
}
+#ifdef GENERATOR_FILE
+
/* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL
has the form "&& ..." (as used in define_insn_and_splits), assume that
EXTRA is already satisfied. Empty strings are treated like "true". */
@@ -581,6 +623,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
}
}
}
+#endif /* #ifdef GENERATOR_FILE */
/* Add a new "mapping" structure to hashtable TABLE. NAME is the name
of the mapping and GROUP is the group to which it belongs. */
@@ -655,7 +698,9 @@ initialize_iterators (void)
substs.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
substs.find_builtin = find_int; /* We don't use it, anyway. */
+#ifdef GENERATOR_FILE
substs.apply_iterator = apply_subst_iterator;
+#endif
lower = add_mapping (&modes, modes.attrs, "mode");
upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -724,6 +769,8 @@ atoll (const char *p)
}
#endif
\f
+
+#ifdef GENERATOR_FILE
/* Process a define_conditions directive, starting with the optional
space after the "define_conditions". The directive looks like this:
@@ -765,6 +812,7 @@ md_reader::read_conditions ()
add_c_test (expr, value);
}
}
+#endif /* #ifdef GENERATOR_FILE */
static void
validate_const_int (const char *string)
@@ -861,6 +909,8 @@ md_reader::record_potential_iterator_use (struct iterator_group *group,
}
}
+#ifdef GENERATOR_FILE
+
/* Finish reading a declaration of the form:
(define... <name> [<value1> ... <valuen>])
@@ -1020,14 +1070,7 @@ check_code_iterator (struct mapping *iterator)
bool
rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
{
- static bool initialized = false;
-
- /* Do one-time initialization. */
- if (!initialized)
- {
- initialize_iterators ();
- initialized = true;
- }
+ one_time_initialization ();
/* Handle various rtx-related declarations that aren't themselves
encoded as rtxes. */
@@ -1082,6 +1125,103 @@ rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
return true;
}
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization. */
+
+static void
+one_time_initialization (void)
+{
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ initialize_iterators ();
+ initialized = true;
+ }
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+ consuming the terminator character if CONSUME_TERMINATOR is true.
+ Return all characters before the terminator as an allocated buffer. */
+
+char *
+rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
+{
+ int ch = read_skip_spaces ();
+ unread_char (ch);
+ auto_vec<char> buf;
+ while (1)
+ {
+ ch = read_char ();
+ if (strchr (terminator_chars, ch))
+ {
+ if (!consume_terminator)
+ unread_char (ch);
+ break;
+ }
+ buf.safe_push (ch);
+ }
+ buf.safe_push ('\0');
+ return xstrdup (buf.address ());
+}
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags. */
+
+static void
+read_flags (rtx return_rtx)
+{
+ while (1)
+ {
+ int ch = read_char ();
+ if (ch != '/')
+ {
+ unread_char (ch);
+ break;
+ }
+
+ int flag_char = read_char ();
+ switch (flag_char)
+ {
+ case 's':
+ RTX_FLAG (return_rtx, in_struct) = 1;
+ break;
+ case 'v':
+ RTX_FLAG (return_rtx, volatil) = 1;
+ break;
+ case 'u':
+ RTX_FLAG (return_rtx, unchanging) = 1;
+ break;
+ case 'f':
+ RTX_FLAG (return_rtx, frame_related) = 1;
+ break;
+ case 'j':
+ RTX_FLAG (return_rtx, jump) = 1;
+ break;
+ case 'c':
+ RTX_FLAG (return_rtx, call) = 1;
+ break;
+ case 'i':
+ RTX_FLAG (return_rtx, return_val) = 1;
+ break;
+ default:
+ fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+ }
+ }
+}
+
+/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+static int
+parse_reg_note_name (const char *string)
+{
+ for (int i = 0; i < REG_NOTE_MAX; i++)
+ if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
/* 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
return it. */
@@ -1090,11 +1230,12 @@ rtx
rtx_reader::read_rtx_code (const char *code_name)
{
RTX_CODE code;
- struct mapping *iterator;
+ struct mapping *iterator = NULL;
const char *format_ptr;
struct md_name name;
rtx return_rtx;
int c;
+ long reuse_id = -1;
/* Linked list structure for making RTXs: */
struct rtx_list
@@ -1103,13 +1244,39 @@ rtx_reader::read_rtx_code (const char *code_name)
rtx value; /* Value of this node. */
};
+ one_time_initialization ();
+
+ /* Handle reuse_rtx ids e.g. "(0|scratch:DI)". */
+ if (ISDIGIT (code_name[0]))
+ {
+ reuse_id = atoi (code_name);
+ while (char ch = *code_name++)
+ if (ch == '|')
+ break;
+ }
+
+ /* Handle "reuse_rtx". */
+ if (strcmp (code_name, "reuse_rtx") == 0)
+ {
+ read_name (&name);
+ long idx = atoi (name.string);
+ /* Look it up by ID. */
+ gcc_assert (idx < m_reuse_rtx_by_id.length ());
+ return_rtx = m_reuse_rtx_by_id[idx];
+ 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. */
return_rtx = rtx_alloc (code);
@@ -1117,9 +1284,36 @@ rtx_reader::read_rtx_code (const char *code_name)
memset (return_rtx, 0, RTX_CODE_SIZE (code));
PUT_CODE (return_rtx, code);
+ if (reuse_id != -1)
+ {
+ /* Store away for later reuse. */
+ m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1);
+ m_reuse_rtx_by_id[reuse_id] = return_rtx;
+ }
+
if (iterator)
record_iterator_use (iterator, return_rtx);
+ /* Check for flags. */
+ read_flags (return_rtx);
+
+ /* Read REG_NOTE names for EXPR_LIST and INSN_LIST. */
+ if ((GET_CODE (return_rtx) == EXPR_LIST
+ || GET_CODE (return_rtx) == INSN_LIST
+ || GET_CODE (return_rtx) == INT_LIST)
+ && !m_in_call_function_usage)
+ {
+ char ch = read_char ();
+ if (ch == ':')
+ {
+ read_name (&name);
+ PUT_MODE_RAW (return_rtx,
+ (machine_mode)parse_reg_note_name (name.string));
+ }
+ else
+ unread_char (ch);
+ }
+
/* If what follows is `: mode ', read it and
store the mode in the rtx. */
@@ -1132,8 +1326,24 @@ rtx_reader::read_rtx_code (const char *code_name)
else
unread_char (c);
+ if (INSN_CHAIN_CODE_P (code))
+ {
+ read_name (&name);
+ INSN_UID (return_rtx) = atoi (name.string);
+ }
+
+ /* Use the format_ptr to parse the various operands of this rtx.
+ read_rtx_operand is a vfunc, allowing the parser to vary between
+ parsing .md files and parsing .rtl dumps; the function_reader subclass
+ overrides the defaults when loading RTL dumps, to handle the
+ various extra attributes emitted by print_rtx. */
for (int idx = 0; format_ptr[idx] != 0; idx++)
- read_rtx_operand (return_rtx, idx);
+ return_rtx = read_rtx_operand (return_rtx, idx);
+
+ /* Call a vfunc to handle the various additional information that
+ print-rtl.c can write after the regular fields; does nothing when
+ parsing .md files. */
+ handle_any_trailing_information (return_rtx);
if (CONST_WIDE_INT_P (return_rtx))
{
@@ -1197,9 +1407,11 @@ rtx_reader::read_rtx_code (const char *code_name)
/* Subroutine of read_rtx_code. Parse operand IDX within RETURN_RTX,
based on the corresponding format character within GET_RTX_FORMAT
- for the GET_CODE (RETURN_RTX). */
+ for the GET_CODE (RETURN_RTX), and return RETURN_RTX.
+ This is a virtual function, so that function_reader can override
+ some parsing, and potentially return a different rtx. */
-void
+rtx
rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
RTX_CODE code = GET_CODE (return_rtx);
@@ -1217,6 +1429,9 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
break;
case 'e':
+ XEXP (return_rtx, idx) = read_nested_rtx ();
+ break;
+
case 'u':
XEXP (return_rtx, idx) = read_nested_rtx ();
break;
@@ -1273,7 +1488,6 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
char *stringbuf;
int star_if_braced;
- struct obstack *string_obstack = get_string_obstack ();
c = read_skip_spaces ();
unread_char (c);
@@ -1293,7 +1507,10 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
star_if_braced = (format_ptr[idx] == 'T');
stringbuf = read_string (star_if_braced);
+ if (!stringbuf)
+ break;
+#ifdef GENERATOR_FILE
/* For insn patterns, we want to provide a default name
based on the file and line, like "*foo.md:12", if the
given name is blank. These are only for define_insn and
@@ -1303,6 +1520,7 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
&& (GET_CODE (return_rtx) == DEFINE_INSN
|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
{
+ struct obstack *string_obstack = get_string_obstack ();
char line_name[20];
const char *read_md_filename = get_filename ();
const char *fn = (read_md_filename ? read_md_filename : "rtx");
@@ -1348,11 +1566,20 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
if (m != 0)
record_iterator_use (m, return_rtx);
}
+#endif /* #ifdef GENERATOR_FILE */
+
+ /* "stringbuf" was allocated within string_obstack and thus has
+ the its lifetime restricted to that of the rtx_reader. This is
+ OK for the generator programs, but for non-generator programs,
+ XSTR and XTMPL fields are meant to be allocated in the GC-managed
+ heap. Hence we need to allocate a copy in the GC-managed heap
+ for the non-generator case. */
+ const char *string_ptr = finalize_string (stringbuf);
if (star_if_braced)
- XTMPL (return_rtx, idx) = stringbuf;
+ XTMPL (return_rtx, idx) = string_ptr;
else
- XSTR (return_rtx, idx) = stringbuf;
+ XSTR (return_rtx, idx) = string_ptr;
}
break;
@@ -1398,6 +1625,8 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
default:
gcc_unreachable ();
}
+
+ return return_rtx;
}
/* Read a nested rtx construct from the MD file and return it. */
@@ -1408,6 +1637,11 @@ rtx_reader::read_nested_rtx ()
struct md_name name;
rtx return_rtx;
+ /* In compact dumps, trailing "(nil)" values can be omitted.
+ Handle such dumps. */
+ if (peek_char () == ')')
+ return NULL_RTX;
+
require_char_ws ('(');
read_name (&name);
@@ -1418,6 +1652,8 @@ rtx_reader::read_nested_rtx ()
require_char_ws (')');
+ return_rtx = postprocess (return_rtx);
+
return return_rtx;
}
@@ -1454,8 +1690,9 @@ rtx_reader::read_rtx_variadic (rtx form)
/* Constructor for class rtx_reader. */
-rtx_reader::rtx_reader ()
-: md_reader ()
+rtx_reader::rtx_reader (bool compact)
+: md_reader (compact),
+ m_in_call_function_usage (false)
{
/* Set the global singleton pointer. */
rtx_reader_ptr = this;
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
index 8edddfb..bd918a7 100644
--- a/gcc/rtl-tests.c
+++ b/gcc/rtl-tests.c
@@ -200,6 +200,7 @@ test_single_set ()
static void
test_uncond_jump ()
{
+ set_new_first_and_last_insn (NULL, NULL);
rtx_insn *label = gen_label_rtx ();
rtx jump_pat = gen_rtx_SET (pc_rtx,
gen_rtx_LABEL_REF (VOIDmode,
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 7a44e3b..a9a63dc 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3665,7 +3665,9 @@ extern void init_varasm_once (void);
extern rtx make_debug_expr_from_rtl (const_rtx);
/* In read-rtl.c */
+#ifdef GENERATOR_FILE
extern bool read_rtx (const char *, vec<rtx> *);
+#endif
/* In alias.c */
extern rtx canon_rtx (rtx);
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
new file mode 100644
index 0000000..a1e56b1
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,82 @@
+/* Selftest support for RTL.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "read-rtl-function.h"
+#include "read-md.h"
+#include "tree-core.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "selftest-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Constructor for selftest::rtl_dump_test.
+ Read a dumped RTL function from PATH.
+ Takes ownership of PATH, freeing in dtor.
+ Use LOC as the effective location when reporting failures. */
+
+rtl_dump_test::rtl_dump_test (const location &loc, char *path)
+ : m_path (path)
+{
+ /* Parse the tempfile. */
+ auto_vec<const char *> argv (2);
+ argv.safe_push (progname);
+ argv.safe_push (path);
+ bool read_ok
+ = read_rtl_function_body (argv.length (), argv.address (), NULL);
+ ASSERT_TRUE_AT (loc, read_ok);
+}
+
+/* Destructor for selftest::rtl_dump_test.
+ Cleanup global state relating to the function, and free the path. */
+
+selftest::rtl_dump_test::~rtl_dump_test ()
+{
+ /* Cleanups. */
+ current_function_decl = NULL;
+ free_after_compilation (cfun);
+ set_cfun (NULL);
+ free (m_path);
+}
+
+/* Get the insn with the given uid, or NULL if not found. */
+
+rtx_insn *
+get_insn_by_uid (int uid)
+{
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_UID (insn) == uid)
+ return insn;
+
+ /* Not found. */
+ return NULL;
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
index f505018..accb486 100644
--- a/gcc/selftest-rtl.h
+++ b/gcc/selftest-rtl.h
@@ -47,6 +47,23 @@ assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x,
assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX), \
(REUSE_MANAGER))
+/* A class for testing RTL function dumps. */
+
+class rtl_dump_test
+{
+ public:
+ /* Takes ownership of PATH. */
+ rtl_dump_test (const location &loc, char *path);
+ ~rtl_dump_test ();
+
+ private:
+ char *m_path;
+};
+
+/* Get the insn with the given uid, or NULL if not found. */
+
+extern rtx_insn *get_insn_by_uid (int uid);
+
} /* end of namespace selftest. */
#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index c1cd97e..bf2b84a 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -72,6 +72,7 @@ selftest::run_tests ()
tree_c_tests ();
gimple_c_tests ();
rtl_tests_c_tests ();
+ read_rtl_function_c_tests ();
/* Higher-level tests, or for components that other selftests don't
rely on. */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index c390873..d5afa6d 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -184,6 +184,7 @@ extern void hash_map_tests_c_tests ();
extern void hash_set_tests_c_tests ();
extern void input_c_tests ();
extern void pretty_print_c_tests ();
+extern void read_rtl_function_c_tests ();
extern void rtl_tests_c_tests ();
extern void selftest_c_tests ();
extern void spellcheck_c_tests ();
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0396feb..7ec62db 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -305,6 +305,11 @@ ssa_default_def (struct function *fn, tree var)
gcc_assert (VAR_P (var)
|| TREE_CODE (var) == PARM_DECL
|| TREE_CODE (var) == RESULT_DECL);
+
+ /* Always NULL_TREE for rtl function dumps. */
+ if (!fn->gimple_df)
+ return NULL_TREE;
+
in.var = (tree)&ind;
ind.uid = DECL_UID (var);
return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8b/9] Add target-independent selftests of RTL function reader
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
@ 2016-12-02 1:27 ` David Malcolm
2016-12-02 15:06 ` Bernd Schmidt
2016-12-02 1:27 ` [PATCH 8c/9] Add aarch64-specific selftests for " David Malcolm
` (3 subsequent siblings)
4 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-02 1:27 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
gcc/ChangeLog:
* function-tests.c (selftest::verify_three_block_rtl_cfg): Remove
"static".
* read-rtl-function.c (selftest::assert_edge_at): New function.
(ASSERT_EDGE): New macro.
(selftest::test_loading_dump_fragment_1): New function.
(selftest::test_loading_dump_fragment_2): New function.
(selftest::test_loading_labels): New function.
(selftest::test_loading_insn_with_mode): New function.
(selftest::test_loading_jump_to_label_ref): New function.
(selftest::test_loading_jump_to_return): New function.
(selftest::test_loading_jump_to_simple_return): New function.
(selftest::test_loading_note_insn_basic_block): New function.
(selftest::test_loading_note_insn_deleted): New function.
(selftest::test_loading_const_int): New function.
(selftest::test_loading_symbol_ref): New function.
(selftest::test_loading_cfg): New function.
(selftest::test_loading_bb_index): New function.
(selftest::read_rtl_function_c_tests): Call the new functions.
* selftest-rtl.h (selftest::verify_three_block_rtl_cfg): New decl.
gcc/testsuite/ChangeLog:
* selftests/asr_div1.rtl: New file.
* selftests/bb-index.rtl: New file.
* selftests/cfg-test.rtl: New file.
* selftests/const-int.rtl: New file.
* selftests/example-labels.rtl: New file.
* selftests/insn-with-mode.rtl: New file.
* selftests/jump-to-label-ref.rtl: New file.
* selftests/jump-to-return.rtl: New file.
* selftests/jump-to-simple-return.rtl: New file.
* selftests/note-insn-deleted.rtl: New file.
* selftests/note_insn_basic_block.rtl: New file.
* selftests/simple-cse.rtl: New file.
* selftests/symbol-ref.rtl: New file.
---
gcc/function-tests.c | 2 +-
gcc/read-rtl-function.c | 434 ++++++++++++++++++++++
gcc/selftest-rtl.h | 2 +
gcc/testsuite/selftests/asr_div1.rtl | 24 ++
gcc/testsuite/selftests/bb-index.rtl | 8 +
gcc/testsuite/selftests/cfg-test.rtl | 37 ++
gcc/testsuite/selftests/const-int.rtl | 20 +
gcc/testsuite/selftests/example-labels.rtl | 8 +
gcc/testsuite/selftests/insn-with-mode.rtl | 7 +
gcc/testsuite/selftests/jump-to-label-ref.rtl | 17 +
gcc/testsuite/selftests/jump-to-return.rtl | 11 +
gcc/testsuite/selftests/jump-to-simple-return.rtl | 11 +
gcc/testsuite/selftests/note-insn-deleted.rtl | 5 +
gcc/testsuite/selftests/note_insn_basic_block.rtl | 9 +
gcc/testsuite/selftests/simple-cse.rtl | 16 +
gcc/testsuite/selftests/symbol-ref.rtl | 13 +
16 files changed, 623 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/selftests/asr_div1.rtl
create mode 100644 gcc/testsuite/selftests/bb-index.rtl
create mode 100644 gcc/testsuite/selftests/cfg-test.rtl
create mode 100644 gcc/testsuite/selftests/const-int.rtl
create mode 100644 gcc/testsuite/selftests/example-labels.rtl
create mode 100644 gcc/testsuite/selftests/insn-with-mode.rtl
create mode 100644 gcc/testsuite/selftests/jump-to-label-ref.rtl
create mode 100644 gcc/testsuite/selftests/jump-to-return.rtl
create mode 100644 gcc/testsuite/selftests/jump-to-simple-return.rtl
create mode 100644 gcc/testsuite/selftests/note-insn-deleted.rtl
create mode 100644 gcc/testsuite/selftests/note_insn_basic_block.rtl
create mode 100644 gcc/testsuite/selftests/simple-cse.rtl
create mode 100644 gcc/testsuite/selftests/symbol-ref.rtl
diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index b0c44cf..90fec6d 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -421,7 +421,7 @@ verify_three_block_gimple_cfg (function *fun)
/* As above, but additionally verify the RTL insns are sane. */
-static void
+void
verify_three_block_rtl_cfg (function *fun)
{
verify_three_block_cfg (fun);
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index cef834e..07c0e7a 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -1643,6 +1643,427 @@ test_parsing_regnos ()
ASSERT_EQ (LAST_VIRTUAL_REGISTER + 2, lookup_reg_by_dump_name ("%1"));
}
+/* Verify that edge E is as expected, with the src and dest basic blocks
+ having indices EXPECTED_SRC_IDX and EXPECTED_DEST_IDX respectively, and
+ the edge having flags equal to EXPECTED_FLAGS.
+ Use LOC as the effective location when reporting failures. */
+
+static void
+assert_edge_at (const location &loc, edge e, int expected_src_idx,
+ int expected_dest_idx, int expected_flags)
+{
+ ASSERT_EQ_AT (loc, expected_src_idx, e->src->index);
+ ASSERT_EQ_AT (loc, expected_dest_idx, e->dest->index);
+ ASSERT_EQ_AT (loc, expected_flags, e->flags);
+}
+
+/* Verify that edge EDGE is as expected, with the src and dest basic blocks
+ having indices EXPECTED_SRC_IDX and EXPECTED_DEST_IDX respectively, and
+ the edge having flags equal to EXPECTED_FLAGS. */
+
+#define ASSERT_EDGE(EDGE, EXPECTED_SRC_IDX, EXPECTED_DEST_IDX, \
+ EXPECTED_FLAGS) \
+ assert_edge_at (SELFTEST_LOCATION, EDGE, EXPECTED_SRC_IDX, \
+ EXPECTED_DEST_IDX, EXPECTED_FLAGS)
+
+/* Verify that we can load RTL dumps. */
+
+static void
+test_loading_dump_fragment_1 ()
+{
+ // TODO: filter on target?
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("asr_div1.rtl"));
+
+ /* Verify that the insns were loaded correctly. */
+ rtx_insn *insn_1 = get_insns ();
+ ASSERT_TRUE (insn_1);
+ ASSERT_EQ (1, INSN_UID (insn_1));
+ ASSERT_EQ (INSN, GET_CODE (insn_1));
+ ASSERT_EQ (SET, GET_CODE (PATTERN (insn_1)));
+ ASSERT_EQ (NULL, PREV_INSN (insn_1));
+
+ rtx_insn *insn_2 = NEXT_INSN (insn_1);
+ ASSERT_TRUE (insn_2);
+ ASSERT_EQ (2, INSN_UID (insn_2));
+ ASSERT_EQ (INSN, GET_CODE (insn_2));
+ ASSERT_EQ (insn_1, PREV_INSN (insn_2));
+ ASSERT_EQ (NULL, NEXT_INSN (insn_2));
+
+ /* Verify that registers were loaded correctly. */
+ rtx insn_1_dest = SET_DEST (PATTERN (insn_1));
+ ASSERT_EQ (REG, GET_CODE (insn_1_dest));
+ ASSERT_EQ ((LAST_VIRTUAL_REGISTER + 1) + 2, REGNO (insn_1_dest));
+ rtx insn_1_src = SET_SRC (PATTERN (insn_1));
+ ASSERT_EQ (LSHIFTRT, GET_CODE (insn_1_src));
+ rtx reg = XEXP (insn_1_src, 0);
+ ASSERT_EQ (REG, GET_CODE (reg));
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, REGNO (reg));
+
+ /* Verify that get_insn_by_uid works. */
+ ASSERT_EQ (insn_1, get_insn_by_uid (1));
+ ASSERT_EQ (insn_2, get_insn_by_uid (2));
+
+ /* Verify that basic blocks were created. */
+ ASSERT_EQ (2, BLOCK_FOR_INSN (insn_1)->index);
+ ASSERT_EQ (2, BLOCK_FOR_INSN (insn_2)->index);
+
+ /* Verify that the CFG was recreated. */
+ ASSERT_TRUE (cfun);
+ verify_three_block_rtl_cfg (cfun);
+ basic_block bb2 = BASIC_BLOCK_FOR_FN (cfun, 2);
+ ASSERT_TRUE (bb2 != NULL);
+ ASSERT_EQ (BB_RTL, bb2->flags & BB_RTL);
+ ASSERT_EQ (2, bb2->index);
+ ASSERT_EQ (insn_1, BB_HEAD (bb2));
+ ASSERT_EQ (insn_2, BB_END (bb2));
+}
+
+/* Verify loading another RTL dump. */
+
+static void
+test_loading_dump_fragment_2 ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("simple-cse.rtl"));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ rtx_insn *insn_2 = get_insn_by_uid (2);
+ rtx_insn *insn_3 = get_insn_by_uid (3);
+
+ rtx set1 = single_set (insn_1);
+ ASSERT_NE (NULL, set1);
+ rtx set2 = single_set (insn_2);
+ ASSERT_NE (NULL, set2);
+ rtx set3 = single_set (insn_3);
+ ASSERT_NE (NULL, set3);
+
+ rtx src1 = SET_SRC (set1);
+ ASSERT_EQ (PLUS, GET_CODE (src1));
+
+ rtx src2 = SET_SRC (set2);
+ ASSERT_EQ (PLUS, GET_CODE (src2));
+
+ /* Both src1 and src2 refer to "(reg:SI %0)".
+ Verify that we have pointer equality. */
+ rtx lhs1 = XEXP (src1, 0);
+ rtx lhs2 = XEXP (src2, 0);
+ ASSERT_EQ (lhs1, lhs2);
+
+ /* Verify that the CFG was recreated. */
+ ASSERT_TRUE (cfun);
+ verify_three_block_rtl_cfg (cfun);
+}
+
+/* Verify that CODE_LABEL insns are loaded correctly. */
+
+static void
+test_loading_labels ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("example-labels.rtl"));
+
+ rtx_insn *insn_100 = get_insn_by_uid (100);
+ ASSERT_EQ (CODE_LABEL, GET_CODE (insn_100));
+ ASSERT_EQ (100, INSN_UID (insn_100));
+ ASSERT_EQ (NULL, LABEL_NAME (insn_100));
+ ASSERT_EQ (0, LABEL_NUSES (insn_100));
+ ASSERT_EQ (30, CODE_LABEL_NUMBER (insn_100));
+
+ rtx_insn *insn_200 = get_insn_by_uid (200);
+ ASSERT_EQ (CODE_LABEL, GET_CODE (insn_200));
+ ASSERT_EQ (200, INSN_UID (insn_200));
+ ASSERT_STREQ ("some_label_name", LABEL_NAME (insn_200));
+ ASSERT_EQ (0, LABEL_NUSES (insn_200));
+ ASSERT_EQ (40, CODE_LABEL_NUMBER (insn_200));
+
+ /* Ensure that the presence of CODE_LABEL_NUMBER == 40
+ means that the next label num to be handed out will be 41. */
+ ASSERT_EQ (41, max_label_num ());
+
+ /* Ensure that label names read from a dump are GC-managed
+ and are found through the insn. */
+ forcibly_ggc_collect ();
+ ASSERT_TRUE (ggc_marked_p (insn_200));
+ ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_200)));
+}
+
+/* Verify that the loader copes with an insn with a mode. */
+
+static void
+test_loading_insn_with_mode ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("insn-with-mode.rtl"));
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (INSN, GET_CODE (insn));
+
+ /* Verify that the "TI" mode was set from "insn:TI". */
+ ASSERT_EQ (TImode, GET_MODE (insn));
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref. */
+
+static void
+test_loading_jump_to_label_ref ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-label-ref.rtl"));
+
+ rtx_insn *jump_insn = get_insn_by_uid (1);
+ ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+
+ rtx_insn *barrier = get_insn_by_uid (2);
+ ASSERT_EQ (BARRIER, GET_CODE (barrier));
+
+ rtx_insn *code_label = get_insn_by_uid (100);
+ ASSERT_EQ (CODE_LABEL, GET_CODE (code_label));
+
+ /* Verify the jump_insn. */
+ ASSERT_EQ (4, BLOCK_FOR_INSN (jump_insn)->index);
+ ASSERT_EQ (SET, GET_CODE (PATTERN (jump_insn)));
+ /* Ensure that the "(pc)" is using the global singleton. */
+ ASSERT_EQ (pc_rtx, SET_DEST (PATTERN (jump_insn)));
+ // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+ rtx label_ref = SET_SRC (PATTERN (jump_insn));
+ ASSERT_EQ (LABEL_REF, GET_CODE (label_ref));
+ ASSERT_EQ (code_label, label_ref_label (label_ref));
+ ASSERT_EQ (code_label, JUMP_LABEL (jump_insn));
+
+ /* Verify the code_label. */
+ ASSERT_EQ (5, BLOCK_FOR_INSN (code_label)->index);
+ ASSERT_EQ (NULL, LABEL_NAME (code_label));
+ ASSERT_EQ (1, LABEL_NUSES (code_label));
+
+ /* Verify the generated CFG. */
+
+ /* Locate blocks. */
+ basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (entry != NULL);
+ ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+ basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (exit != NULL);
+ ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+ basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
+ basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
+ ASSERT_EQ (4, bb4->index);
+ ASSERT_EQ (5, bb5->index);
+
+ /* Entry block. */
+ ASSERT_EQ (NULL, entry->preds);
+ ASSERT_EQ (1, entry->succs->length ());
+ ASSERT_EDGE ((*entry->succs)[0], 0, 4, EDGE_FALLTHRU);
+
+ /* bb4. */
+ ASSERT_EQ (1, bb4->preds->length ());
+ ASSERT_EDGE ((*bb4->preds)[0], 0, 4, EDGE_FALLTHRU);
+ ASSERT_EQ (1, bb4->succs->length ());
+ ASSERT_EDGE ((*bb4->succs)[0], 4, 5, 0x0);
+
+ /* bb5. */
+ ASSERT_EQ (1, bb5->preds->length ());
+ ASSERT_EDGE ((*bb5->preds)[0], 4, 5, 0x0);
+ ASSERT_EQ (1, bb5->succs->length ());
+ ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
+
+ /* Exit block. */
+ ASSERT_EQ (1, exit->preds->length ());
+ ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
+ ASSERT_EQ (NULL, exit->succs);
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+ marked "return". */
+
+static void
+test_loading_jump_to_return ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("jump-to-return.rtl"));
+
+ rtx_insn *jump_insn = get_insn_by_uid (1);
+ ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+ ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
+ // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a jump_insn to a label_ref
+ marked "simple_return". */
+
+static void
+test_loading_jump_to_simple_return ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("jump-to-simple-return.rtl"));
+
+ rtx_insn *jump_insn = get_insn_by_uid (1);
+ ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
+ ASSERT_EQ (simple_return_rtx, JUMP_LABEL (jump_insn));
+ // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
+}
+
+/* Verify that the loader copes with a NOTE_INSN_BASIC_BLOCK. */
+
+static void
+test_loading_note_insn_basic_block ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("note_insn_basic_block.rtl"));
+
+ rtx_insn *note = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (note));
+ ASSERT_EQ (2, BLOCK_FOR_INSN (note)->index);
+
+ ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (note));
+ ASSERT_EQ (2, NOTE_BASIC_BLOCK (note)->index);
+ ASSERT_EQ (BASIC_BLOCK_FOR_FN (cfun, 2), NOTE_BASIC_BLOCK (note));
+}
+
+/* Verify that the loader copes with a NOTE_INSN_DELETED. */
+
+static void
+test_loading_note_insn_deleted ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("note-insn-deleted.rtl"));
+
+ rtx_insn *note = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (note));
+ ASSERT_EQ (NOTE_INSN_DELETED, NOTE_KIND (note));
+}
+
+/* Verify that the const_int values are consolidated, since
+ pointer equality corresponds to value equality.
+ TODO: do this for all in CASE_CONST_UNIQUE. */
+
+static void
+test_loading_const_int ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("const-int.rtl"));
+
+ /* Verify that const_int values below MAX_SAVED_CONST_INT use
+ the global values. */
+ ASSERT_EQ (const0_rtx, SET_SRC (PATTERN (get_insn_by_uid (1))));
+ ASSERT_EQ (const1_rtx, SET_SRC (PATTERN (get_insn_by_uid (2))));
+ ASSERT_EQ (constm1_rtx, SET_SRC (PATTERN (get_insn_by_uid (3))));
+
+ /* Verify that other const_int values are consolidated. */
+ rtx int256 = gen_rtx_CONST_INT (SImode, 256);
+ ASSERT_EQ (int256, SET_SRC (PATTERN (get_insn_by_uid (4))));
+}
+
+/* Verify that the loader copes with a SYMBOL_REF. */
+
+static void
+test_loading_symbol_ref ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("symbol-ref.rtl"));
+
+ rtx_insn *insn = get_insns ();
+
+ rtx high = SET_SRC (PATTERN (insn));
+ ASSERT_EQ (HIGH, GET_CODE (high));
+
+ rtx symbol_ref = XEXP (high, 0);
+ ASSERT_EQ (SYMBOL_REF, GET_CODE (symbol_ref));
+
+ /* Verify that "[flags 0xc0]" was parsed. */
+ ASSERT_EQ (0xc0, SYMBOL_REF_FLAGS (symbol_ref));
+ /* TODO: we don't yet load SYMBOL_REF_DECL. */
+}
+
+/* Verify that the loader can rebuild a CFG. */
+
+static void
+test_loading_cfg ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("cfg-test.rtl"));
+
+ ASSERT_STREQ ("cfg_test", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ ASSERT_TRUE (cfun->cfg != NULL);
+ ASSERT_EQ (6, n_basic_blocks_for_fn (cfun));
+ ASSERT_EQ (6, n_edges_for_fn (cfun));
+
+ /* The "fake" basic blocks. */
+ basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (entry != NULL);
+ ASSERT_EQ (ENTRY_BLOCK, entry->index);
+
+ basic_block exit = EXIT_BLOCK_PTR_FOR_FN (cfun);
+ ASSERT_TRUE (exit != NULL);
+ ASSERT_EQ (EXIT_BLOCK, exit->index);
+
+ /* The "real" basic blocks. */
+ basic_block bb2 = (*cfun->cfg->x_basic_block_info)[2];
+ basic_block bb3 = (*cfun->cfg->x_basic_block_info)[3];
+ basic_block bb4 = (*cfun->cfg->x_basic_block_info)[4];
+ basic_block bb5 = (*cfun->cfg->x_basic_block_info)[5];
+
+ ASSERT_EQ (2, bb2->index);
+ ASSERT_EQ (3, bb3->index);
+ ASSERT_EQ (4, bb4->index);
+ ASSERT_EQ (5, bb5->index);
+
+ /* Verify connectivity. */
+
+ /* Entry block. */
+ ASSERT_EQ (NULL, entry->preds);
+ ASSERT_EQ (1, entry->succs->length ());
+ ASSERT_EDGE ((*entry->succs)[0], 0, 2, EDGE_FALLTHRU);
+
+ /* bb2. */
+ ASSERT_EQ (1, bb2->preds->length ());
+ ASSERT_EDGE ((*bb2->preds)[0], 0, 2, EDGE_FALLTHRU);
+ ASSERT_EQ (2, bb2->succs->length ());
+ ASSERT_EDGE ((*bb2->succs)[0], 2, 3, EDGE_TRUE_VALUE);
+ ASSERT_EDGE ((*bb2->succs)[1], 2, 4, EDGE_FALSE_VALUE);
+
+ /* bb3. */
+ ASSERT_EQ (1, bb3->preds->length ());
+ ASSERT_EDGE ((*bb3->preds)[0], 2, 3, EDGE_TRUE_VALUE);
+ ASSERT_EQ (1, bb3->succs->length ());
+ ASSERT_EDGE ((*bb3->succs)[0], 3, 5, EDGE_FALLTHRU);
+
+ /* bb4. */
+ ASSERT_EQ (1, bb4->preds->length ());
+ ASSERT_EDGE ((*bb4->preds)[0], 2, 4, EDGE_FALSE_VALUE);
+ ASSERT_EQ (1, bb4->succs->length ());
+ ASSERT_EDGE ((*bb4->succs)[0], 4, 5, EDGE_FALLTHRU);
+
+ /* bb5. */
+ ASSERT_EQ (2, bb5->preds->length ());
+ ASSERT_EDGE ((*bb5->preds)[0], 3, 5, EDGE_FALLTHRU);
+ ASSERT_EDGE ((*bb5->preds)[1], 4, 5, EDGE_FALLTHRU);
+ ASSERT_EQ (1, bb5->succs->length ());
+ ASSERT_EDGE ((*bb5->succs)[0], 5, 1, EDGE_FALLTHRU);
+
+ /* Exit block. */
+ ASSERT_EQ (1, exit->preds->length ());
+ ASSERT_EDGE ((*exit->preds)[0], 5, 1, EDGE_FALLTHRU);
+ ASSERT_EQ (NULL, exit->succs);
+}
+
+/* Verify that the loader copes with sparse block indices.
+ This testcase loads a file with a "(block 42)". */
+
+static void
+test_loading_bb_index ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("bb-index.rtl"));
+
+ ASSERT_STREQ ("test_bb_index", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ ASSERT_TRUE (cfun->cfg != NULL);
+ ASSERT_EQ (3, n_basic_blocks_for_fn (cfun));
+ ASSERT_EQ (43, basic_block_info_for_fn (cfun)->length ());
+ ASSERT_EQ (2, n_edges_for_fn (cfun));
+
+ ASSERT_EQ (NULL, (*cfun->cfg->x_basic_block_info)[41]);
+ basic_block bb42 = (*cfun->cfg->x_basic_block_info)[42];
+ ASSERT_NE (NULL, bb42);
+ ASSERT_EQ (42, bb42->index);
+}
+
/* Run all of the selftests within this file. */
void
@@ -1650,6 +2071,19 @@ read_rtl_function_c_tests ()
{
test_edge_flags ();
test_parsing_regnos ();
+ test_loading_dump_fragment_1 ();
+ test_loading_dump_fragment_2 ();
+ test_loading_labels ();
+ test_loading_insn_with_mode ();
+ test_loading_jump_to_label_ref ();
+ test_loading_jump_to_return ();
+ test_loading_jump_to_simple_return ();
+ test_loading_note_insn_basic_block ();
+ test_loading_note_insn_deleted ();
+ test_loading_const_int ();
+ test_loading_symbol_ref ();
+ test_loading_cfg ();
+ test_loading_bb_index ();
}
} // namespace selftest
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
index accb486..35d6437 100644
--- a/gcc/selftest-rtl.h
+++ b/gcc/selftest-rtl.h
@@ -64,6 +64,8 @@ class rtl_dump_test
extern rtx_insn *get_insn_by_uid (int uid);
+extern void verify_three_block_rtl_cfg (function *fun);
+
} /* end of namespace selftest. */
#endif /* #if CHECKING_P */
diff --git a/gcc/testsuite/selftests/asr_div1.rtl b/gcc/testsuite/selftests/asr_div1.rtl
new file mode 100644
index 0000000..1507893
--- /dev/null
+++ b/gcc/testsuite/selftests/asr_div1.rtl
@@ -0,0 +1,24 @@
+;; Taken from
+;; gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+;; for aarch64, hand editing to the new format.
+
+(function "f1"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (reg:DI %2)
+ (lshiftrt:DI (reg:DI %0)
+ (const_int 32)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %0)
+ (nil)))
+ (cinsn 2 (set (reg:SI %1)
+ (ashiftrt:SI (subreg:SI (reg:DI %2) 0)
+ (const_int 3)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %2)
+ (nil)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/bb-index.rtl b/gcc/testsuite/selftests/bb-index.rtl
new file mode 100644
index 0000000..7c66f22
--- /dev/null
+++ b/gcc/testsuite/selftests/bb-index.rtl
@@ -0,0 +1,8 @@
+(function "test_bb_index"
+ (insn-chain
+ (block 42
+ (edge-from entry (flags "FALLTHRU"))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 42
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/cfg-test.rtl b/gcc/testsuite/selftests/cfg-test.rtl
new file mode 100644
index 0000000..08a0e22
--- /dev/null
+++ b/gcc/testsuite/selftests/cfg-test.rtl
@@ -0,0 +1,37 @@
+/* Example of a loading a CFG like this:
+ 0 (entry)
+ |
+ 2
+ / \
+ 3 4
+ \ /
+ 5
+ |
+ 1 (exit). */
+
+(function "cfg_test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (edge-to 3 (flags "TRUE_VALUE"))
+ (edge-to 4 (flags "FALSE_VALUE"))
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "TRUE_VALUE"))
+ (cnote 2 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 3
+ (block 4
+ (edge-from 2 (flags "FALSE_VALUE"))
+ (cnote 3 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 3 (flags "FALLTHRU"))
+ (edge-from 4 (flags "FALLTHRU"))
+ (cnote 4 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/const-int.rtl b/gcc/testsuite/selftests/const-int.rtl
new file mode 100644
index 0000000..e50dd88
--- /dev/null
+++ b/gcc/testsuite/selftests/const-int.rtl
@@ -0,0 +1,20 @@
+(function "const_int_examples"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1
+ (set (reg:SI %0) (const_int 0))
+ "test.c":2 (nil))
+ (cinsn 2
+ (set (reg:SI %1) (const_int 1))
+ "test.c":2 (nil))
+ (cinsn 3
+ (set (reg:SI %2) (const_int -1))
+ "test.c":2 (nil))
+ (cinsn 4
+ (set (reg:SI %3) (const_int 256))
+ "test.c":2 (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/example-labels.rtl b/gcc/testsuite/selftests/example-labels.rtl
new file mode 100644
index 0000000..ec33bfd
--- /dev/null
+++ b/gcc/testsuite/selftests/example-labels.rtl
@@ -0,0 +1,8 @@
+(function "example_labels"
+ (insn-chain
+ (block 6
+ (clabel 100 30 (nil))
+ (clabel 200 40 ("some_label_name"))
+ ) ;; block 6
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/insn-with-mode.rtl b/gcc/testsuite/selftests/insn-with-mode.rtl
new file mode 100644
index 0000000..8c4609b
--- /dev/null
+++ b/gcc/testsuite/selftests/insn-with-mode.rtl
@@ -0,0 +1,7 @@
+(function "insn_with_mode"
+ (insn-chain
+ (block 2
+ (insn:TI 1 (set (reg:SI %0) (reg:SI %1)) (nil))
+ ) ;; block
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/jump-to-label-ref.rtl b/gcc/testsuite/selftests/jump-to-label-ref.rtl
new file mode 100644
index 0000000..29184bf
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-label-ref.rtl
@@ -0,0 +1,17 @@
+(function "jump_to_label_ref"
+ (insn-chain
+ (block 4
+ (edge-from entry (flags "FALLTHRU"))
+ (cjump_insn 1 (set (pc) (label_ref 100))
+ "../../src/gcc/testsuite/rtl.dg/test.c":4)
+ (edge-to 5)
+ ) ;; block 4
+ (cbarrier 2)
+ (block 5
+ (edge-from 4)
+ (clabel 100 2 (nil) [1 uses])
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+) ;; function
+
diff --git a/gcc/testsuite/selftests/jump-to-return.rtl b/gcc/testsuite/selftests/jump-to-return.rtl
new file mode 100644
index 0000000..9da89ef
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-return.rtl
@@ -0,0 +1,11 @@
+(function "jump_to_return"
+ (insn-chain
+ (block 4
+ (edge-from entry (flags "FALLTHRU"))
+ (cjump_insn 1 (return)
+ "../../src/gcc/testsuite/rtl.dg/test.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 4
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/jump-to-simple-return.rtl b/gcc/testsuite/selftests/jump-to-simple-return.rtl
new file mode 100644
index 0000000..5a9c1d5
--- /dev/null
+++ b/gcc/testsuite/selftests/jump-to-simple-return.rtl
@@ -0,0 +1,11 @@
+(function "jump_to_simple_return"
+ (insn-chain
+ (block 4
+ (edge-from entry (flags "FALLTHRU"))
+ (cjump_insn 1 (simple_return)
+ "../../src/gcc/testsuite/rtl.dg/test.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 4
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/note-insn-deleted.rtl b/gcc/testsuite/selftests/note-insn-deleted.rtl
new file mode 100644
index 0000000..a388acd
--- /dev/null
+++ b/gcc/testsuite/selftests/note-insn-deleted.rtl
@@ -0,0 +1,5 @@
+(function "example_note"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/note_insn_basic_block.rtl b/gcc/testsuite/selftests/note_insn_basic_block.rtl
new file mode 100644
index 0000000..e792d98
--- /dev/null
+++ b/gcc/testsuite/selftests/note_insn_basic_block.rtl
@@ -0,0 +1,9 @@
+(function "example_of_note"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/simple-cse.rtl b/gcc/testsuite/selftests/simple-cse.rtl
new file mode 100644
index 0000000..5fe745d
--- /dev/null
+++ b/gcc/testsuite/selftests/simple-cse.rtl
@@ -0,0 +1,16 @@
+(function "test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (reg:SI %1)
+ (plus:SI (reg:SI %0)
+ (const_int 1))) (nil))
+ (cinsn 2 (set (reg:SI %2)
+ (plus:SI (reg:SI %0)
+ (const_int 1))) (nil))
+ (cinsn 3 (set (mem:SI (reg:SI %3) [1 i+0 S4 A32])
+ (mult:SI (reg:SI %1) (reg:SI %2))) (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/symbol-ref.rtl b/gcc/testsuite/selftests/symbol-ref.rtl
new file mode 100644
index 0000000..8339eca
--- /dev/null
+++ b/gcc/testsuite/selftests/symbol-ref.rtl
@@ -0,0 +1,13 @@
+(function "example_of_symbol_ref"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1
+ (set (reg:SI %0)
+ (high:SI (symbol_ref:SI ("isl_obj_map_vtable") [flags 0xc0] <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ "y.c":12702
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8b/9] Add target-independent selftests of RTL function reader
2016-12-02 1:27 ` [PATCH 8b/9] Add target-independent selftests of RTL function reader David Malcolm
@ 2016-12-02 15:06 ` Bernd Schmidt
2016-12-05 5:55 ` Jeff Law
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-02 15:06 UTC (permalink / raw)
To: David Malcolm, gcc-patches
Conceptually, the concept of "target-independent RTL" seems weird to me.
But I guess you expect these to work because the backend never gets
involved trying to recognize insns or addressing modes? I think a
comment to that effect somewhere near the C code to load these tests
would be good.
I think this potentially suggests a missing feature: the dump should
indicate whether the reader should leave it alone or ask the target to
verify it by recognizing the insns.
Also,
> + (edge-from entry (flags "FALLTHRU"))
> + (cinsn 1 (set (reg:DI %2)
> + (lshiftrt:DI (reg:DI %0)
> + (const_int 32)))
> + "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
Weren't we going to make file/line information optional?
Otherwise this is probably going to be OK since I got past my "this is
all wrong" initial reaction. You'll want to Cc target maintainers for
the other two patches.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8b/9] Add target-independent selftests of RTL function reader
2016-12-02 15:06 ` Bernd Schmidt
@ 2016-12-05 5:55 ` Jeff Law
0 siblings, 0 replies; 78+ messages in thread
From: Jeff Law @ 2016-12-05 5:55 UTC (permalink / raw)
To: Bernd Schmidt, David Malcolm, gcc-patches
On 12/02/2016 08:06 AM, Bernd Schmidt wrote:
> Conceptually, the concept of "target-independent RTL" seems weird to me.
> But I guess you expect these to work because the backend never gets
> involved trying to recognize insns or addressing modes? I think a
> comment to that effect somewhere near the C code to load these tests
> would be good.
That's one of the very interesting issues here. IMHO the place we want
to go with this stuff is marry it with your idea of a RTL testing backend.
Alternately we're stuck trying to get our grubby fingers into things
like recog_for_combine.
Jeff
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8c/9] Add aarch64-specific selftests for RTL function reader
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
2016-12-02 1:27 ` [PATCH 8b/9] Add target-independent selftests of RTL function reader David Malcolm
@ 2016-12-02 1:27 ` David Malcolm
2016-12-06 17:22 ` James Greenhalgh
2016-12-02 1:27 ` [PATCH 8d/9] Add x86_64-specific " David Malcolm
` (2 subsequent siblings)
4 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-02 1:27 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
This patch adds more selftests for class function_reader, where
the dumps to be read contain aarch64-specific features.
In an earlier version of the patch kit, these were handled using
#ifndef GCC_AARCH64_H to conditionalize running them.
This version instead runs them via a target hook for running
target-specific selftests, thus putting them within aarch64.c.
gcc/ChangeLog:
* config/aarch64/aarch64.c: Include selftest.h and
selftest-rtl.h.
(selftest::aarch64_test_loading_full_dump): New function.
(selftest::aarch64_run_selftests): New function.
(TARGET_RUN_TARGET_SELFTESTS): Wire it up to
selftest::aarch64_run_selftests.
gcc/testsuite/ChangeLog:
* selftests/aarch64: New subdirectory.
* selftests/aarch64/times-two.rtl: New file.
---
gcc/config/aarch64/aarch64.c | 49 +++++++++++++++++++++++++++
gcc/testsuite/selftests/aarch64/times-two.rtl | 36 ++++++++++++++++++++
2 files changed, 85 insertions(+)
create mode 100644 gcc/testsuite/selftests/aarch64/times-two.rtl
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index bd97c5b..d19bee3 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -64,6 +64,8 @@
#include "sched-int.h"
#include "target-globals.h"
#include "common/common-target.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
/* This file should be included last. */
#include "target-def.h"
@@ -14168,6 +14170,48 @@ aarch64_optab_supported_p (int op, machine_mode mode1, machine_mode,
}
}
+/* Target-specific selftests. */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftest for the RTL loader. This test is target-specific and thus
+ here since the dump contains target-specific hard reg names.
+ Verify that the RTL loader copes with a dump from print_rtx_function. */
+
+static void
+aarch64_test_loading_full_dump ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times-two.rtl"));
+
+ ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+ rtx_insn *insn_15 = get_insn_by_uid (15);
+ ASSERT_EQ (INSN, GET_CODE (insn_15));
+ ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+ /* Verify crtl->return_rtx. */
+ ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+ ASSERT_EQ (0, REGNO (crtl->return_rtx));
+ ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Run all target-specific selftests. */
+
+static void
+aarch64_run_selftests (void)
+{
+ aarch64_test_loading_full_dump ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST aarch64_address_cost
@@ -14502,6 +14546,11 @@ aarch64_optab_supported_p (int op, machine_mode mode1, machine_mode,
#undef TARGET_OMIT_STRUCT_RETURN_REG
#define TARGET_OMIT_STRUCT_RETURN_REG true
+#if CHECKING_P
+#undef TARGET_RUN_TARGET_SELFTESTS
+#define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
+#endif /* #if CHECKING_P */
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-aarch64.h"
diff --git a/gcc/testsuite/selftests/aarch64/times-two.rtl b/gcc/testsuite/selftests/aarch64/times-two.rtl
new file mode 100644
index 0000000..dbce67e
--- /dev/null
+++ b/gcc/testsuite/selftests/aarch64/times-two.rtl
@@ -0,0 +1,36 @@
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI x0 [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1))) "../../src/times-two.c":3
+ (nil))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI x0)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI x0)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI x0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8c/9] Add aarch64-specific selftests for RTL function reader
2016-12-02 1:27 ` [PATCH 8c/9] Add aarch64-specific selftests for " David Malcolm
@ 2016-12-06 17:22 ` James Greenhalgh
2016-12-06 19:38 ` David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: James Greenhalgh @ 2016-12-06 17:22 UTC (permalink / raw)
To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches, nd
On Thu, Dec 01, 2016 at 09:00:11PM -0500, David Malcolm wrote:
> This patch adds more selftests for class function_reader, where
> the dumps to be read contain aarch64-specific features.
>
> In an earlier version of the patch kit, these were handled using
> #ifndef GCC_AARCH64_H to conditionalize running them.
> This version instead runs them via a target hook for running
> target-specific selftests, thus putting them within aarch64.c.
I'm probably missing something obvious here.
This looks OK, but can we have a comment somewhere near the code as to
what this test is actually testing?
Is it just that x0 is correctly identfied as the return register?
Thanks,
James
>
> gcc/ChangeLog:
> * config/aarch64/aarch64.c: Include selftest.h and
> selftest-rtl.h.
> (selftest::aarch64_test_loading_full_dump): New function.
> (selftest::aarch64_run_selftests): New function.
> (TARGET_RUN_TARGET_SELFTESTS): Wire it up to
> selftest::aarch64_run_selftests.
>
> gcc/testsuite/ChangeLog:
> * selftests/aarch64: New subdirectory.
> * selftests/aarch64/times-two.rtl: New file.
> ---
> gcc/config/aarch64/aarch64.c | 49 +++++++++++++++++++++++++++
> gcc/testsuite/selftests/aarch64/times-two.rtl | 36 ++++++++++++++++++++
> 2 files changed, 85 insertions(+)
> create mode 100644 gcc/testsuite/selftests/aarch64/times-two.rtl
>
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index bd97c5b..d19bee3 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c
> @@ -64,6 +64,8 @@
> #include "sched-int.h"
> #include "target-globals.h"
> #include "common/common-target.h"
> +#include "selftest.h"
> +#include "selftest-rtl.h"
>
> /* This file should be included last. */
> #include "target-def.h"
> @@ -14168,6 +14170,48 @@ aarch64_optab_supported_p (int op, machine_mode mode1, machine_mode,
> }
> }
>
> +/* Target-specific selftests. */
> +
> +#if CHECKING_P
> +
> +namespace selftest {
> +
> +/* Selftest for the RTL loader. This test is target-specific and thus
> + here since the dump contains target-specific hard reg names.
> + Verify that the RTL loader copes with a dump from print_rtx_function. */
> +
> +static void
> +aarch64_test_loading_full_dump ()
> +{
> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times-two.rtl"));
> +
> + ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
> +
> + rtx_insn *insn_1 = get_insn_by_uid (1);
> + ASSERT_EQ (NOTE, GET_CODE (insn_1));
> +
> + rtx_insn *insn_15 = get_insn_by_uid (15);
> + ASSERT_EQ (INSN, GET_CODE (insn_15));
> + ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
> +
> + /* Verify crtl->return_rtx. */
> + ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
> + ASSERT_EQ (0, REGNO (crtl->return_rtx));
> + ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
> +}
> +
> +/* Run all target-specific selftests. */
> +
> +static void
> +aarch64_run_selftests (void)
> +{
> + aarch64_test_loading_full_dump ();
> +}
> +
> +} // namespace selftest
> +
> +#endif /* #if CHECKING_P */
> +
> #undef TARGET_ADDRESS_COST
> #define TARGET_ADDRESS_COST aarch64_address_cost
>
> @@ -14502,6 +14546,11 @@ aarch64_optab_supported_p (int op, machine_mode mode1, machine_mode,
> #undef TARGET_OMIT_STRUCT_RETURN_REG
> #define TARGET_OMIT_STRUCT_RETURN_REG true
>
> +#if CHECKING_P
> +#undef TARGET_RUN_TARGET_SELFTESTS
> +#define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
> +#endif /* #if CHECKING_P */
> +
> struct gcc_target targetm = TARGET_INITIALIZER;
>
> #include "gt-aarch64.h"
> diff --git a/gcc/testsuite/selftests/aarch64/times-two.rtl b/gcc/testsuite/selftests/aarch64/times-two.rtl
> new file mode 100644
> index 0000000..dbce67e
> --- /dev/null
> +++ b/gcc/testsuite/selftests/aarch64/times-two.rtl
> @@ -0,0 +1,36 @@
> +(function "times_two"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI x0 [ i ])) "../../src/times-two.c":2
> + (nil))
> + (cnote 3 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 6 (set (reg:SI %2)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
> + (nil))
> + (cinsn 7 (set (reg:SI %0 [ _2 ])
> + (ashift:SI (reg:SI %2)
> + (const_int 1))) "../../src/times-two.c":3
> + (nil))
> + (cinsn 10 (set (reg:SI %1 [ <retval> ])
> + (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
> + (nil))
> + (cinsn 14 (set (reg/i:SI x0)
> + (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
> + (nil))
> + (cinsn 15 (use (reg/i:SI x0)) "../../src/times-two.c":4
> + (nil))
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI x0)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "times_two"
> --
> 1.8.5.3
>
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8c/9] Add aarch64-specific selftests for RTL function reader
2016-12-06 17:22 ` James Greenhalgh
@ 2016-12-06 19:38 ` David Malcolm
2016-12-07 9:30 ` James Greenhalgh
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-06 19:38 UTC (permalink / raw)
To: James Greenhalgh; +Cc: Bernd Schmidt, gcc-patches, nd
On Tue, 2016-12-06 at 17:22 +0000, James Greenhalgh wrote:
> On Thu, Dec 01, 2016 at 09:00:11PM -0500, David Malcolm wrote:
> > This patch adds more selftests for class function_reader, where
> > the dumps to be read contain aarch64-specific features.
> >
> > In an earlier version of the patch kit, these were handled using
> > #ifndef GCC_AARCH64_H to conditionalize running them.
> > This version instead runs them via a target hook for running
> > target-specific selftests, thus putting them within aarch64.c.
>
> I'm probably missing something obvious here.
>
> This looks OK, but can we have a comment somewhere near the code as
> to
> what this test is actually testing?
>
> Is it just that x0 is correctly identfied as the return register?
The original point of the test was to have an integration test of
loading a real dump from print_rtx_function, to verify that the loader
can actually load it.
The dump contains a target-specific item, and thus the test needs to be
made target-specific (I did one of these for x86_64, and one for
aarch64, which are the two targets that I've done the most testing of
the patch kit on).
Looking over it now, yeah, it's not a great test (but hopefully not a
bad one either).
It does verify that "x0" is correctly parsed, so it is giving some test
coverage for lookup_reg_by_dump_name's handling of hard regs (in patch
8a in the kit). I also picked a couple of insns to verify (one outside
of a bb, the other inside of a bb).
Currently the comment reads:
/* Selftest for the RTL loader. This test is target-specific and
here since the dump contains target-specific hard reg names.
Verify that the RTL loader copes with a dump from
print_rtx_function. */
Would you be OK with the test if it read:
/* Selftest for the RTL loader.
Verify that the RTL loader copes with a dump from
print_rtx_function. This is essentially just a test that class
function_reader can handle a real dump, but it also verifies
that lookup_reg_by_dump_name correctly handles hard regs.
The presence of hard reg names in the dump means that the test is
target-specific, hence it is in this file. */
or somesuch?
Alternatively, I can drop this patch.
Thanks
Dave
> Thanks,
> James
>
> >
> > gcc/ChangeLog:
> > * config/aarch64/aarch64.c: Include selftest.h and
> > selftest-rtl.h.
> > (selftest::aarch64_test_loading_full_dump): New function.
> > (selftest::aarch64_run_selftests): New function.
> > (TARGET_RUN_TARGET_SELFTESTS): Wire it up to
> > selftest::aarch64_run_selftests.
> >
> > gcc/testsuite/ChangeLog:
> > * selftests/aarch64: New subdirectory.
> > * selftests/aarch64/times-two.rtl: New file.
> > ---
> > gcc/config/aarch64/aarch64.c | 49
> > +++++++++++++++++++++++++++
> > gcc/testsuite/selftests/aarch64/times-two.rtl | 36
> > ++++++++++++++++++++
> > 2 files changed, 85 insertions(+)
> > create mode 100644 gcc/testsuite/selftests/aarch64/times-two.rtl
> >
> > diff --git a/gcc/config/aarch64/aarch64.c
> > b/gcc/config/aarch64/aarch64.c
> > index bd97c5b..d19bee3 100644
> > --- a/gcc/config/aarch64/aarch64.c
> > +++ b/gcc/config/aarch64/aarch64.c
> > @@ -64,6 +64,8 @@
> > #include "sched-int.h"
> > #include "target-globals.h"
> > #include "common/common-target.h"
> > +#include "selftest.h"
> > +#include "selftest-rtl.h"
> >
> > /* This file should be included last. */
> > #include "target-def.h"
> > @@ -14168,6 +14170,48 @@ aarch64_optab_supported_p (int op,
> > machine_mode mode1, machine_mode,
> > }
> > }
> >
> > +/* Target-specific selftests. */
> > +
> > +#if CHECKING_P
> > +
> > +namespace selftest {
> > +
> > +/* Selftest for the RTL loader. This test is target-specific and
> > thus
> > + here since the dump contains target-specific hard reg names.
> > + Verify that the RTL loader copes with a dump from
> > print_rtx_function. */
> > +
> > +static void
> > +aarch64_test_loading_full_dump ()
> > +{
> > + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("aarch64/times
> > -two.rtl"));
> > +
> > + ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun
> > ->decl)));
> > +
> > + rtx_insn *insn_1 = get_insn_by_uid (1);
> > + ASSERT_EQ (NOTE, GET_CODE (insn_1));
> > +
> > + rtx_insn *insn_15 = get_insn_by_uid (15);
> > + ASSERT_EQ (INSN, GET_CODE (insn_15));
> > + ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
> > +
> > + /* Verify crtl->return_rtx. */
> > + ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
> > + ASSERT_EQ (0, REGNO (crtl->return_rtx));
> > + ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
> > +}
> > +
> > +/* Run all target-specific selftests. */
> > +
> > +static void
> > +aarch64_run_selftests (void)
> > +{
> > + aarch64_test_loading_full_dump ();
> > +}
> > +
> > +} // namespace selftest
> > +
> > +#endif /* #if CHECKING_P */
> > +
> > #undef TARGET_ADDRESS_COST
> > #define TARGET_ADDRESS_COST aarch64_address_cost
> >
> > @@ -14502,6 +14546,11 @@ aarch64_optab_supported_p (int op,
> > machine_mode mode1, machine_mode,
> > #undef TARGET_OMIT_STRUCT_RETURN_REG
> > #define TARGET_OMIT_STRUCT_RETURN_REG true
> >
> > +#if CHECKING_P
> > +#undef TARGET_RUN_TARGET_SELFTESTS
> > +#define TARGET_RUN_TARGET_SELFTESTS
> > selftest::aarch64_run_selftests
> > +#endif /* #if CHECKING_P */
> > +
> > struct gcc_target targetm = TARGET_INITIALIZER;
> >
> > #include "gt-aarch64.h"
> > diff --git a/gcc/testsuite/selftests/aarch64/times-two.rtl
> > b/gcc/testsuite/selftests/aarch64/times-two.rtl
> > new file mode 100644
> > index 0000000..dbce67e
> > --- /dev/null
> > +++ b/gcc/testsuite/selftests/aarch64/times-two.rtl
> > @@ -0,0 +1,36 @@
> > +(function "times_two"
> > + (insn-chain
> > + (cnote 1 NOTE_INSN_DELETED)
> > + (block 2
> > + (edge-from entry (flags "FALLTHRU"))
> > + (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
> > + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack
> > -vars)
> > + (const_int -4)) [1 i+0 S4 A32])
> > + (reg:SI x0 [ i ])) "../../src/times-two.c":2
> > + (nil))
> > + (cnote 3 NOTE_INSN_FUNCTION_BEG)
> > + (cinsn 6 (set (reg:SI %2)
> > + (mem/c:SI (plus:DI (reg/f:DI virtual-stack
> > -vars)
> > + (const_int -4)) [1 i+0 S4 A32]))
> > "../../src/times-two.c":3
> > + (nil))
> > + (cinsn 7 (set (reg:SI %0 [ _2 ])
> > + (ashift:SI (reg:SI %2)
> > + (const_int 1))) "../../src/times-two.c":3
> > + (nil))
> > + (cinsn 10 (set (reg:SI %1 [ <retval> ])
> > + (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
> > + (nil))
> > + (cinsn 14 (set (reg/i:SI x0)
> > + (reg:SI %1 [ <retval> ])) "../../src/times
> > -two.c":4
> > + (nil))
> > + (cinsn 15 (use (reg/i:SI x0)) "../../src/times-two.c":4
> > + (nil))
> > + (edge-to exit (flags "FALLTHRU"))
> > + ) ;; block 2
> > + ) ;; insn-chain
> > + (crtl
> > + (return_rtx
> > + (reg/i:SI x0)
> > + ) ;; return_rtx
> > + ) ;; crtl
> > +) ;; function "times_two"
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8c/9] Add aarch64-specific selftests for RTL function reader
2016-12-06 19:38 ` David Malcolm
@ 2016-12-07 9:30 ` James Greenhalgh
0 siblings, 0 replies; 78+ messages in thread
From: James Greenhalgh @ 2016-12-07 9:30 UTC (permalink / raw)
To: David Malcolm; +Cc: Bernd Schmidt, gcc-patches, nd
On Tue, Dec 06, 2016 at 02:38:45PM -0500, David Malcolm wrote:
> On Tue, 2016-12-06 at 17:22 +0000, James Greenhalgh wrote:
> > On Thu, Dec 01, 2016 at 09:00:11PM -0500, David Malcolm wrote:
> > > This patch adds more selftests for class function_reader, where
> > > the dumps to be read contain aarch64-specific features.
> > >
> > > In an earlier version of the patch kit, these were handled using
> > > #ifndef GCC_AARCH64_H to conditionalize running them.
> > > This version instead runs them via a target hook for running
> > > target-specific selftests, thus putting them within aarch64.c.
> >
> > I'm probably missing something obvious here.
> >
> > This looks OK, but can we have a comment somewhere near the code as
> > to
> > what this test is actually testing?
> >
> > Is it just that x0 is correctly identfied as the return register?
>
> The original point of the test was to have an integration test of
> loading a real dump from print_rtx_function, to verify that the loader
> can actually load it.
>
> The dump contains a target-specific item, and thus the test needs to be
> made target-specific (I did one of these for x86_64, and one for
> aarch64, which are the two targets that I've done the most testing of
> the patch kit on).
>
> Looking over it now, yeah, it's not a great test (but hopefully not a
> bad one either).
>
> It does verify that "x0" is correctly parsed, so it is giving some test
> coverage for lookup_reg_by_dump_name's handling of hard regs (in patch
> 8a in the kit). I also picked a couple of insns to verify (one outside
> of a bb, the other inside of a bb).
>
> Currently the comment reads:
>
> /* Selftest for the RTL loader. This test is target-specific and
> here since the dump contains target-specific hard reg names.
> Verify that the RTL loader copes with a dump from
> print_rtx_function. */
>
> Would you be OK with the test if it read:
>
> /* Selftest for the RTL loader.
> Verify that the RTL loader copes with a dump from
> print_rtx_function. This is essentially just a test that class
> function_reader can handle a real dump, but it also verifies
> that lookup_reg_by_dump_name correctly handles hard regs.
> The presence of hard reg names in the dump means that the test is
> target-specific, hence it is in this file. */
>
> or somesuch?
That looks fine to me. Thanks for the more detailed explanation.
> Alternatively, I can drop this patch.
No, this is good, and I'm happy to approve it - I just haven't followed the
rest of the patch series so it wasn't clear to me from the syntax what made
this target specific. With your explanation I now understand.
This is OK for trunk.
Thanks,
James
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8d/9] Add x86_64-specific selftests for RTL function reader
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
2016-12-02 1:27 ` [PATCH 8b/9] Add target-independent selftests of RTL function reader David Malcolm
2016-12-02 1:27 ` [PATCH 8c/9] Add aarch64-specific selftests for " David Malcolm
@ 2016-12-02 1:27 ` David Malcolm
2016-12-19 16:43 ` [PATCH] Add x86_64-specific selftests for RTL function reader (v2) David Malcolm
2016-12-02 1:28 ` [PATCH 9/9] Add "__RTL" to cc1 (v6) David Malcolm
2016-12-02 14:41 ` [PATCH 8a/9] Introduce class function_reader (v6) Bernd Schmidt
4 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-02 1:27 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
This patch adds more selftests for class function_reader, where
the dumps to be read contain x86_64-specific features.
In an earlier version of the patch kit, these were handled using
This version instead runs them via a target hook for running
target-specific selftests, thus putting them within i386.c.
gcc/ChangeLog:
* config/i386/i386.c
(selftest::ix86_test_loading_dump_fragment_1): New function.
(selftest::ix86_test_loading_call_insn): New function.
(selftest::ix86_test_loading_full_dump): New function.
(selftest::ix86_test_loading_unspec): New function.
(selftest::ix86_run_selftests): Call the new functions.
gcc/testsuite/ChangeLog:
* selftests/x86_64: New subdirectory.
* selftests/x86_64/call-insn.rtl: New file.
* selftests/x86_64/copy-hard-reg-into-frame.rtl: New file.
* selftests/x86_64/times-two.rtl: New file.
* selftests/x86_64/unspec.rtl: New file.
---
gcc/config/i386/i386.c | 207 +++++++++++++++++++++
gcc/testsuite/selftests/x86_64/call-insn.rtl | 17 ++
.../selftests/x86_64/copy-hard-reg-into-frame.rtl | 15 ++
gcc/testsuite/selftests/x86_64/times-two.rtl | 51 +++++
gcc/testsuite/selftests/x86_64/unspec.rtl | 20 ++
5 files changed, 310 insertions(+)
create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/unspec.rtl
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 6c608e0..0dda786 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -50672,6 +50672,206 @@ ix86_test_dumping_memory_blockage ()
" ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
}
+/* Verify loading an RTL dump; specifically a dump of copying
+ a param on x86_64 from a hard reg into the frame.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_dump_fragment_1 ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("x86_64/copy-hard-reg-into-frame.rtl"));
+
+ rtx_insn *insn = get_insn_by_uid (1);
+
+ /* The block structure and indentation here is purely for
+ readability; it mirrors the structure of the rtx. */
+ tree mem_expr;
+ {
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (SET, GET_CODE (pat));
+ {
+ rtx dest = SET_DEST (pat);
+ ASSERT_EQ (MEM, GET_CODE (dest));
+ /* Verify the "/c" was parsed. */
+ ASSERT_TRUE (RTX_FLAG (dest, call));
+ ASSERT_EQ (SImode, GET_MODE (dest));
+ {
+ rtx addr = XEXP (dest, 0);
+ ASSERT_EQ (PLUS, GET_CODE (addr));
+ ASSERT_EQ (DImode, GET_MODE (addr));
+ {
+ rtx lhs = XEXP (addr, 0);
+ ASSERT_EQ (REG, GET_CODE (lhs));
+ /* Verify the "/f" was parsed. */
+ ASSERT_TRUE (RTX_FLAG (lhs, frame_related));
+ ASSERT_EQ (DImode, GET_MODE (lhs));
+ }
+ {
+ rtx rhs = XEXP (addr, 1);
+ ASSERT_EQ (CONST_INT, GET_CODE (rhs));
+ ASSERT_EQ (-4, INTVAL (rhs));
+ }
+ }
+ /* Verify the "[1 i+0 S4 A32]" was parsed. */
+ ASSERT_EQ (1, MEM_ALIAS_SET (dest));
+ /* "i" should have been handled by synthesizing a global int
+ variable named "i". */
+ mem_expr = MEM_EXPR (dest);
+ ASSERT_NE (mem_expr, NULL);
+ ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
+ ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
+ ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
+ ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
+ /* "+0". */
+ ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
+ ASSERT_EQ (0, MEM_OFFSET (dest));
+ /* "S4". */
+ ASSERT_EQ (4, MEM_SIZE (dest));
+ /* "A32. */
+ ASSERT_EQ (32, MEM_ALIGN (dest));
+ }
+ {
+ rtx src = SET_SRC (pat);
+ ASSERT_EQ (REG, GET_CODE (src));
+ ASSERT_EQ (SImode, GET_MODE (src));
+ ASSERT_EQ (5, REGNO (src));
+ tree reg_expr = REG_EXPR (src);
+ /* "i" here should point to the same var as for the MEM_EXPR. */
+ ASSERT_EQ (reg_expr, mem_expr);
+ }
+ }
+}
+
+/* Verify that the RTL loader copes with a call_insn dump.
+ This test is target-specific since the dump contains a target-specific
+ hard reg name. */
+
+static void
+ix86_test_loading_call_insn ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call-insn.rtl"));
+
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (CALL_INSN, GET_CODE (insn));
+
+ /* "/j". */
+ ASSERT_TRUE (RTX_FLAG (insn, jump));
+
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
+
+ /* Verify REG_NOTES. */
+ {
+ /* "(expr_list:REG_CALL_DECL". */
+ ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn)));
+ rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES (insn));
+ ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
+
+ /* "(expr_list:REG_EH_REGION (const_int 0 [0])". */
+ rtx_expr_list *note1 = note0->next ();
+ ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
+
+ ASSERT_EQ (NULL, note1->next ());
+ }
+
+ /* Verify CALL_INSN_FUNCTION_USAGE. */
+ {
+ /* "(expr_list:DF (use (reg:DF 21 xmm0))". */
+ rtx_expr_list *usage
+ = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn));
+ ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
+ ASSERT_EQ (DFmode, GET_MODE (usage));
+ ASSERT_EQ (USE, GET_CODE (usage->element ()));
+ ASSERT_EQ (NULL, usage->next ());
+ }
+}
+
+/* Verify that the RTL loader copes a dump from print_rtx_function.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_full_dump ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times-two.rtl"));
+
+ ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+ rtx_insn *insn_7 = get_insn_by_uid (7);
+ ASSERT_EQ (INSN, GET_CODE (insn_7));
+ ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
+
+ rtx_insn *insn_15 = get_insn_by_uid (15);
+ ASSERT_EQ (INSN, GET_CODE (insn_15));
+ ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+ /* Verify crtl->return_rtx. */
+ ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+ ASSERT_EQ (0, REGNO (crtl->return_rtx));
+ ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Verify that the RTL loader copes with UNSPEC and UNSPEC_VOLATILE insns.
+ In particular, verify that it correctly loads the 2nd operand.
+ This test is target-specific since these are machine-specific
+ operands (and enums). */
+
+static void
+ix86_test_loading_unspec ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/unspec.rtl"));
+
+ ASSERT_STREQ ("test_unspec", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ /* Test of an UNSPEC. */
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (INSN, GET_CODE (insn));
+ rtx set = single_set (insn);
+ ASSERT_NE (NULL, set);
+ rtx dst = SET_DEST (set);
+ ASSERT_EQ (MEM, GET_CODE (dst));
+ rtx src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC, GET_CODE (src));
+ ASSERT_EQ (BLKmode, GET_MODE (src));
+ ASSERT_EQ (UNSPEC_MEMORY_BLOCKAGE, XINT (src, 1));
+
+ rtx v0 = XVECEXP (src, 0, 0);
+
+ /* Verify that the two uses of the first SCRATCH have pointer
+ equality. */
+ rtx scratch_a = XEXP (dst, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_a));
+
+ rtx scratch_b = XEXP (v0, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_b));
+
+ ASSERT_EQ (scratch_a, scratch_b);
+
+ /* Verify that the two mems are thus treated as equal. */
+ ASSERT_TRUE (rtx_equal_p (dst, v0));
+
+ /* Verify the the insn is recognized. */
+ ASSERT_NE(-1, recog_memoized (insn));
+
+ /* Test of an UNSPEC_VOLATILE, which has its own enum values. */
+ insn = NEXT_INSN (insn);
+ ASSERT_EQ (INSN, GET_CODE (insn));
+
+ set = single_set (insn);
+ ASSERT_NE (NULL, set);
+
+ src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC_VOLATILE, GET_CODE (src));
+ ASSERT_EQ (UNSPECV_RDTSCP, XINT (src, 1));
+}
+
/* Run all target-specific selftests. */
static void
@@ -50679,6 +50879,13 @@ ix86_run_selftests (void)
{
ix86_test_dumping_hard_regs ();
ix86_test_dumping_memory_blockage ();
+
+ /* Various tests of loading RTL dumps, here because they contain
+ ix86-isms (e.g. names of hard regs). */
+ ix86_test_loading_dump_fragment_1 ();
+ ix86_test_loading_call_insn ();
+ ix86_test_loading_full_dump ();
+ ix86_test_loading_unspec ();
}
} // namespace selftest
diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl b/gcc/testsuite/selftests/x86_64/call-insn.rtl
new file mode 100644
index 0000000..8f3a781
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
@@ -0,0 +1,17 @@
+(function "test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (ccall_insn/j 1
+ (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "test.c":19
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)
+ (nil)))
+ (expr_list:DF (use (reg:DF xmm0))
+ (nil)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function "test"
diff --git a/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
new file mode 100644
index 0000000..4598a1c
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
@@ -0,0 +1,15 @@
+(function "copy_hard_reg_into_frame"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/c:SI
+ (plus:DI
+ (reg/f:DI frame)
+ (const_int -4))
+ [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "test.c":2
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl b/gcc/testsuite/selftests/x86_64/times-two.rtl
new file mode 100644
index 0000000..a26d888
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
@@ -0,0 +1,51 @@
+;; Dump of this C function:
+;;
+;; int times_two (int i)
+;; {
+;; return i * 2;
+;; }
+;;
+;; after expand for target==x86_64
+
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
diff --git a/gcc/testsuite/selftests/x86_64/unspec.rtl b/gcc/testsuite/selftests/x86_64/unspec.rtl
new file mode 100644
index 0000000..ac822ac
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/unspec.rtl
@@ -0,0 +1,20 @@
+(function "test_unspec"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (cinsn 2 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec_volatile:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPECV_RDTSCP)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Add x86_64-specific selftests for RTL function reader (v2)
2016-12-02 1:27 ` [PATCH 8d/9] Add x86_64-specific " David Malcolm
@ 2016-12-19 16:43 ` David Malcolm
2017-01-03 16:47 ` PING " David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-19 16:43 UTC (permalink / raw)
To: gcc-patches, Uros Bizjak, Jan Hubicka; +Cc: Bernd Schmidt, David Malcolm
Note to i386 maintainters: this patch is part of the RTL frontend.
It adds selftests for verifying that the RTL dump reader works as
expected, with a mixture of real and hand-written "dumps" to
exercise various aspects of the loader. Many RTL dumps contain
target-specific features (e.g. names of hard regs), and so these
selftests need to be target-specific, and hence this patch puts
them in i386.c.
Tested on i686-pc-linux-gnu and x86_64-pc-linux-gnu.
OK for trunk, assuming bootstrap®rtest?
(this is dependent on patch 8a within the kit).
Changed in v2:
- fixed selftest failures on i686:
* config/i386/i386.c
(selftest::ix86_test_loading_dump_fragment_1): Fix handling of
"frame" reg.
(selftest::ix86_test_loading_call_insn): Require TARGET_SSE.
- updated to use "<3>" syntax for pseudos, rather than "$3"
Blurb from v1:
This patch adds more selftests for class function_reader, where
the dumps to be read contain x86_64-specific features.
In an earlier version of the patch kit, these were handled using
preprocessor conditionals.
This version instead runs them via a target hook for running
target-specific selftests, thus putting them within i386.c.
gcc/ChangeLog:
* config/i386/i386.c
(selftest::ix86_test_loading_dump_fragment_1): New function.
(selftest::ix86_test_loading_call_insn): New function.
(selftest::ix86_test_loading_full_dump): New function.
(selftest::ix86_test_loading_unspec): New function.
(selftest::ix86_run_selftests): Call the new functions.
gcc/testsuite/ChangeLog:
* selftests/x86_64: New subdirectory.
* selftests/x86_64/call-insn.rtl: New file.
* selftests/x86_64/copy-hard-reg-into-frame.rtl: New file.
* selftests/x86_64/times-two.rtl: New file.
* selftests/x86_64/unspec.rtl: New file.
---
gcc/config/i386/i386.c | 210 +++++++++++++++++++++
gcc/testsuite/selftests/x86_64/call-insn.rtl | 17 ++
.../selftests/x86_64/copy-hard-reg-into-frame.rtl | 15 ++
gcc/testsuite/selftests/x86_64/times-two.rtl | 51 +++++
gcc/testsuite/selftests/x86_64/unspec.rtl | 20 ++
5 files changed, 313 insertions(+)
create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl
create mode 100644 gcc/testsuite/selftests/x86_64/unspec.rtl
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 1cd1cd8..dc1a86f 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -51200,6 +51200,209 @@ ix86_test_dumping_memory_blockage ()
" ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
}
+/* Verify loading an RTL dump; specifically a dump of copying
+ a param on x86_64 from a hard reg into the frame.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_dump_fragment_1 ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION,
+ locate_file ("x86_64/copy-hard-reg-into-frame.rtl"));
+
+ rtx_insn *insn = get_insn_by_uid (1);
+
+ /* The block structure and indentation here is purely for
+ readability; it mirrors the structure of the rtx. */
+ tree mem_expr;
+ {
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (SET, GET_CODE (pat));
+ {
+ rtx dest = SET_DEST (pat);
+ ASSERT_EQ (MEM, GET_CODE (dest));
+ /* Verify the "/c" was parsed. */
+ ASSERT_TRUE (RTX_FLAG (dest, call));
+ ASSERT_EQ (SImode, GET_MODE (dest));
+ {
+ rtx addr = XEXP (dest, 0);
+ ASSERT_EQ (PLUS, GET_CODE (addr));
+ ASSERT_EQ (DImode, GET_MODE (addr));
+ {
+ rtx lhs = XEXP (addr, 0);
+ /* Verify that the "frame" REG was consolidated. */
+ ASSERT_RTX_PTR_EQ (frame_pointer_rtx, lhs);
+ }
+ {
+ rtx rhs = XEXP (addr, 1);
+ ASSERT_EQ (CONST_INT, GET_CODE (rhs));
+ ASSERT_EQ (-4, INTVAL (rhs));
+ }
+ }
+ /* Verify the "[1 i+0 S4 A32]" was parsed. */
+ ASSERT_EQ (1, MEM_ALIAS_SET (dest));
+ /* "i" should have been handled by synthesizing a global int
+ variable named "i". */
+ mem_expr = MEM_EXPR (dest);
+ ASSERT_NE (mem_expr, NULL);
+ ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
+ ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
+ ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
+ ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
+ /* "+0". */
+ ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
+ ASSERT_EQ (0, MEM_OFFSET (dest));
+ /* "S4". */
+ ASSERT_EQ (4, MEM_SIZE (dest));
+ /* "A32. */
+ ASSERT_EQ (32, MEM_ALIGN (dest));
+ }
+ {
+ rtx src = SET_SRC (pat);
+ ASSERT_EQ (REG, GET_CODE (src));
+ ASSERT_EQ (SImode, GET_MODE (src));
+ ASSERT_EQ (5, REGNO (src));
+ tree reg_expr = REG_EXPR (src);
+ /* "i" here should point to the same var as for the MEM_EXPR. */
+ ASSERT_EQ (reg_expr, mem_expr);
+ }
+ }
+}
+
+/* Verify that the RTL loader copes with a call_insn dump.
+ This test is target-specific since the dump contains a target-specific
+ hard reg name. */
+
+static void
+ix86_test_loading_call_insn ()
+{
+ /* The test dump includes register "xmm0", where requires TARGET_SSE
+ to exist. */
+ if (!TARGET_SSE)
+ return;
+
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call-insn.rtl"));
+
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (CALL_INSN, GET_CODE (insn));
+
+ /* "/j". */
+ ASSERT_TRUE (RTX_FLAG (insn, jump));
+
+ rtx pat = PATTERN (insn);
+ ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
+
+ /* Verify REG_NOTES. */
+ {
+ /* "(expr_list:REG_CALL_DECL". */
+ ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn)));
+ rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES (insn));
+ ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
+
+ /* "(expr_list:REG_EH_REGION (const_int 0 [0])". */
+ rtx_expr_list *note1 = note0->next ();
+ ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
+
+ ASSERT_EQ (NULL, note1->next ());
+ }
+
+ /* Verify CALL_INSN_FUNCTION_USAGE. */
+ {
+ /* "(expr_list:DF (use (reg:DF 21 xmm0))". */
+ rtx_expr_list *usage
+ = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn));
+ ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
+ ASSERT_EQ (DFmode, GET_MODE (usage));
+ ASSERT_EQ (USE, GET_CODE (usage->element ()));
+ ASSERT_EQ (NULL, usage->next ());
+ }
+}
+
+/* Verify that the RTL loader copes a dump from print_rtx_function.
+ This test is target-specific since the dump contains target-specific
+ hard reg names. */
+
+static void
+ix86_test_loading_full_dump ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times-two.rtl"));
+
+ ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ ASSERT_EQ (NOTE, GET_CODE (insn_1));
+
+ rtx_insn *insn_7 = get_insn_by_uid (7);
+ ASSERT_EQ (INSN, GET_CODE (insn_7));
+ ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
+
+ rtx_insn *insn_15 = get_insn_by_uid (15);
+ ASSERT_EQ (INSN, GET_CODE (insn_15));
+ ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
+
+ /* Verify crtl->return_rtx. */
+ ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
+ ASSERT_EQ (0, REGNO (crtl->return_rtx));
+ ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
+}
+
+/* Verify that the RTL loader copes with UNSPEC and UNSPEC_VOLATILE insns.
+ In particular, verify that it correctly loads the 2nd operand.
+ This test is target-specific since these are machine-specific
+ operands (and enums). */
+
+static void
+ix86_test_loading_unspec ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/unspec.rtl"));
+
+ ASSERT_STREQ ("test_unspec", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+
+ ASSERT_TRUE (cfun);
+
+ /* Test of an UNSPEC. */
+ rtx_insn *insn = get_insns ();
+ ASSERT_EQ (INSN, GET_CODE (insn));
+ rtx set = single_set (insn);
+ ASSERT_NE (NULL, set);
+ rtx dst = SET_DEST (set);
+ ASSERT_EQ (MEM, GET_CODE (dst));
+ rtx src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC, GET_CODE (src));
+ ASSERT_EQ (BLKmode, GET_MODE (src));
+ ASSERT_EQ (UNSPEC_MEMORY_BLOCKAGE, XINT (src, 1));
+
+ rtx v0 = XVECEXP (src, 0, 0);
+
+ /* Verify that the two uses of the first SCRATCH have pointer
+ equality. */
+ rtx scratch_a = XEXP (dst, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_a));
+
+ rtx scratch_b = XEXP (v0, 0);
+ ASSERT_EQ (SCRATCH, GET_CODE (scratch_b));
+
+ ASSERT_EQ (scratch_a, scratch_b);
+
+ /* Verify that the two mems are thus treated as equal. */
+ ASSERT_TRUE (rtx_equal_p (dst, v0));
+
+ /* Verify the the insn is recognized. */
+ ASSERT_NE(-1, recog_memoized (insn));
+
+ /* Test of an UNSPEC_VOLATILE, which has its own enum values. */
+ insn = NEXT_INSN (insn);
+ ASSERT_EQ (INSN, GET_CODE (insn));
+
+ set = single_set (insn);
+ ASSERT_NE (NULL, set);
+
+ src = SET_SRC (set);
+ ASSERT_EQ (UNSPEC_VOLATILE, GET_CODE (src));
+ ASSERT_EQ (UNSPECV_RDTSCP, XINT (src, 1));
+}
+
/* Run all target-specific selftests. */
static void
@@ -51207,6 +51410,13 @@ ix86_run_selftests (void)
{
ix86_test_dumping_hard_regs ();
ix86_test_dumping_memory_blockage ();
+
+ /* Various tests of loading RTL dumps, here because they contain
+ ix86-isms (e.g. names of hard regs). */
+ ix86_test_loading_dump_fragment_1 ();
+ ix86_test_loading_call_insn ();
+ ix86_test_loading_full_dump ();
+ ix86_test_loading_unspec ();
}
} // namespace selftest
diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl b/gcc/testsuite/selftests/x86_64/call-insn.rtl
new file mode 100644
index 0000000..8f3a781
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
@@ -0,0 +1,17 @@
+(function "test"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (ccall_insn/j 1
+ (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "test.c":19
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7f82b1429d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)
+ (nil)))
+ (expr_list:DF (use (reg:DF xmm0))
+ (nil)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function "test"
diff --git a/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
new file mode 100644
index 0000000..4598a1c
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
@@ -0,0 +1,15 @@
+(function "copy_hard_reg_into_frame"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/c:SI
+ (plus:DI
+ (reg/f:DI frame)
+ (const_int -4))
+ [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "test.c":2
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl b/gcc/testsuite/selftests/x86_64/times-two.rtl
new file mode 100644
index 0000000..8cec47a
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
@@ -0,0 +1,51 @@
+;; Dump of this C function:
+;;
+;; int times_two (int i)
+;; {
+;; return i * 2;
+;; }
+;;
+;; after expand for target==x86_64
+
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI <2>)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI <0> [ _2 ])
+ (ashift:SI (reg:SI <2>)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI <1> [ <retval> ])
+ (reg:SI <0> [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI <1> [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
diff --git a/gcc/testsuite/selftests/x86_64/unspec.rtl b/gcc/testsuite/selftests/x86_64/unspec.rtl
new file mode 100644
index 0000000..ac822ac
--- /dev/null
+++ b/gcc/testsuite/selftests/x86_64/unspec.rtl
@@ -0,0 +1,20 @@
+(function "test_unspec"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (cinsn 2 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec_volatile:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPECV_RDTSCP)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
+ (nil))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* PING Re: [PATCH] Add x86_64-specific selftests for RTL function reader (v2)
2016-12-19 16:43 ` [PATCH] Add x86_64-specific selftests for RTL function reader (v2) David Malcolm
@ 2017-01-03 16:47 ` David Malcolm
2017-01-05 9:43 ` Uros Bizjak
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2017-01-03 16:47 UTC (permalink / raw)
To: gcc-patches, Uros Bizjak, Jan Hubicka; +Cc: Bernd Schmidt
Ping:
https://gcc.gnu.org/ml/gcc-patches/2016-12/msg01616.html
(the patch has been successfully bootstrap®rtested on
x86_64-pc-linux-gnu, and also tested on i686-pc-linux-gnu).
On Mon, 2016-12-19 at 12:12 -0500, David Malcolm wrote:
> Note to i386 maintainters: this patch is part of the RTL frontend.
> It adds selftests for verifying that the RTL dump reader works as
> expected, with a mixture of real and hand-written "dumps" to
> exercise various aspects of the loader. Many RTL dumps contain
> target-specific features (e.g. names of hard regs), and so these
> selftests need to be target-specific, and hence this patch puts
> them in i386.c.
>
> Tested on i686-pc-linux-gnu and x86_64-pc-linux-gnu.
>
> OK for trunk, assuming bootstrap®rtest?
> (this is dependent on patch 8a within the kit).
>
> Changed in v2:
> - fixed selftest failures on i686:
> * config/i386/i386.c
> (selftest::ix86_test_loading_dump_fragment_1): Fix handling of
> "frame" reg.
> (selftest::ix86_test_loading_call_insn): Require TARGET_SSE.
> - updated to use "<3>" syntax for pseudos, rather than "$3"
>
> Blurb from v1:
> This patch adds more selftests for class function_reader, where
> the dumps to be read contain x86_64-specific features.
>
> In an earlier version of the patch kit, these were handled using
> preprocessor conditionals.
> This version instead runs them via a target hook for running
> target-specific selftests, thus putting them within i386.c.
>
> gcc/ChangeLog:
> * config/i386/i386.c
> (selftest::ix86_test_loading_dump_fragment_1): New function.
> (selftest::ix86_test_loading_call_insn): New function.
> (selftest::ix86_test_loading_full_dump): New function.
> (selftest::ix86_test_loading_unspec): New function.
> (selftest::ix86_run_selftests): Call the new functions.
>
> gcc/testsuite/ChangeLog:
> * selftests/x86_64: New subdirectory.
> * selftests/x86_64/call-insn.rtl: New file.
> * selftests/x86_64/copy-hard-reg-into-frame.rtl: New file.
> * selftests/x86_64/times-two.rtl: New file.
> * selftests/x86_64/unspec.rtl: New file.
>
> ---
> gcc/config/i386/i386.c | 210
> +++++++++++++++++++++
> gcc/testsuite/selftests/x86_64/call-insn.rtl | 17 ++
> .../selftests/x86_64/copy-hard-reg-into-frame.rtl | 15 ++
> gcc/testsuite/selftests/x86_64/times-two.rtl | 51 +++++
> gcc/testsuite/selftests/x86_64/unspec.rtl | 20 ++
> 5 files changed, 313 insertions(+)
> create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
> create mode 100644 gcc/testsuite/selftests/x86_64/copy-hard-reg-into
> -frame.rtl
> create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl
> create mode 100644 gcc/testsuite/selftests/x86_64/unspec.rtl
>
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index 1cd1cd8..dc1a86f 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -51200,6 +51200,209 @@ ix86_test_dumping_memory_blockage ()
> " ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
> }
>
> +/* Verify loading an RTL dump; specifically a dump of copying
> + a param on x86_64 from a hard reg into the frame.
> + This test is target-specific since the dump contains target
> -specific
> + hard reg names. */
> +
> +static void
> +ix86_test_loading_dump_fragment_1 ()
> +{
> + rtl_dump_test t (SELFTEST_LOCATION,
> + locate_file ("x86_64/copy-hard-reg-into
> -frame.rtl"));
> +
> + rtx_insn *insn = get_insn_by_uid (1);
> +
> + /* The block structure and indentation here is purely for
> + readability; it mirrors the structure of the rtx. */
> + tree mem_expr;
> + {
> + rtx pat = PATTERN (insn);
> + ASSERT_EQ (SET, GET_CODE (pat));
> + {
> + rtx dest = SET_DEST (pat);
> + ASSERT_EQ (MEM, GET_CODE (dest));
> + /* Verify the "/c" was parsed. */
> + ASSERT_TRUE (RTX_FLAG (dest, call));
> + ASSERT_EQ (SImode, GET_MODE (dest));
> + {
> + rtx addr = XEXP (dest, 0);
> + ASSERT_EQ (PLUS, GET_CODE (addr));
> + ASSERT_EQ (DImode, GET_MODE (addr));
> + {
> + rtx lhs = XEXP (addr, 0);
> + /* Verify that the "frame" REG was consolidated. */
> + ASSERT_RTX_PTR_EQ (frame_pointer_rtx, lhs);
> + }
> + {
> + rtx rhs = XEXP (addr, 1);
> + ASSERT_EQ (CONST_INT, GET_CODE (rhs));
> + ASSERT_EQ (-4, INTVAL (rhs));
> + }
> + }
> + /* Verify the "[1 i+0 S4 A32]" was parsed. */
> + ASSERT_EQ (1, MEM_ALIAS_SET (dest));
> + /* "i" should have been handled by synthesizing a global int
> + variable named "i". */
> + mem_expr = MEM_EXPR (dest);
> + ASSERT_NE (mem_expr, NULL);
> + ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
> + ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
> + ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
> + ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
> + /* "+0". */
> + ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
> + ASSERT_EQ (0, MEM_OFFSET (dest));
> + /* "S4". */
> + ASSERT_EQ (4, MEM_SIZE (dest));
> + /* "A32. */
> + ASSERT_EQ (32, MEM_ALIGN (dest));
> + }
> + {
> + rtx src = SET_SRC (pat);
> + ASSERT_EQ (REG, GET_CODE (src));
> + ASSERT_EQ (SImode, GET_MODE (src));
> + ASSERT_EQ (5, REGNO (src));
> + tree reg_expr = REG_EXPR (src);
> + /* "i" here should point to the same var as for the MEM_EXPR.
> */
> + ASSERT_EQ (reg_expr, mem_expr);
> + }
> + }
> +}
> +
> +/* Verify that the RTL loader copes with a call_insn dump.
> + This test is target-specific since the dump contains a target
> -specific
> + hard reg name. */
> +
> +static void
> +ix86_test_loading_call_insn ()
> +{
> + /* The test dump includes register "xmm0", where requires
> TARGET_SSE
> + to exist. */
> + if (!TARGET_SSE)
> + return;
> +
> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call
> -insn.rtl"));
> +
> + rtx_insn *insn = get_insns ();
> + ASSERT_EQ (CALL_INSN, GET_CODE (insn));
> +
> + /* "/j". */
> + ASSERT_TRUE (RTX_FLAG (insn, jump));
> +
> + rtx pat = PATTERN (insn);
> + ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
> +
> + /* Verify REG_NOTES. */
> + {
> + /* "(expr_list:REG_CALL_DECL". */
> + ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn)));
> + rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES
> (insn));
> + ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
> +
> + /* "(expr_list:REG_EH_REGION (const_int 0 [0])". */
> + rtx_expr_list *note1 = note0->next ();
> + ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
> +
> + ASSERT_EQ (NULL, note1->next ());
> + }
> +
> + /* Verify CALL_INSN_FUNCTION_USAGE. */
> + {
> + /* "(expr_list:DF (use (reg:DF 21 xmm0))". */
> + rtx_expr_list *usage
> + = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn));
> + ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
> + ASSERT_EQ (DFmode, GET_MODE (usage));
> + ASSERT_EQ (USE, GET_CODE (usage->element ()));
> + ASSERT_EQ (NULL, usage->next ());
> + }
> +}
> +
> +/* Verify that the RTL loader copes a dump from print_rtx_function.
> + This test is target-specific since the dump contains target
> -specific
> + hard reg names. */
> +
> +static void
> +ix86_test_loading_full_dump ()
> +{
> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times
> -two.rtl"));
> +
> + ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun
> ->decl)));
> +
> + rtx_insn *insn_1 = get_insn_by_uid (1);
> + ASSERT_EQ (NOTE, GET_CODE (insn_1));
> +
> + rtx_insn *insn_7 = get_insn_by_uid (7);
> + ASSERT_EQ (INSN, GET_CODE (insn_7));
> + ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
> +
> + rtx_insn *insn_15 = get_insn_by_uid (15);
> + ASSERT_EQ (INSN, GET_CODE (insn_15));
> + ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
> +
> + /* Verify crtl->return_rtx. */
> + ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
> + ASSERT_EQ (0, REGNO (crtl->return_rtx));
> + ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
> +}
> +
> +/* Verify that the RTL loader copes with UNSPEC and UNSPEC_VOLATILE
> insns.
> + In particular, verify that it correctly loads the 2nd operand.
> + This test is target-specific since these are machine-specific
> + operands (and enums). */
> +
> +static void
> +ix86_test_loading_unspec ()
> +{
> + rtl_dump_test t (SELFTEST_LOCATION, locate_file
> ("x86_64/unspec.rtl"));
> +
> + ASSERT_STREQ ("test_unspec", IDENTIFIER_POINTER (DECL_NAME (cfun
> ->decl)));
> +
> + ASSERT_TRUE (cfun);
> +
> + /* Test of an UNSPEC. */
> + rtx_insn *insn = get_insns ();
> + ASSERT_EQ (INSN, GET_CODE (insn));
> + rtx set = single_set (insn);
> + ASSERT_NE (NULL, set);
> + rtx dst = SET_DEST (set);
> + ASSERT_EQ (MEM, GET_CODE (dst));
> + rtx src = SET_SRC (set);
> + ASSERT_EQ (UNSPEC, GET_CODE (src));
> + ASSERT_EQ (BLKmode, GET_MODE (src));
> + ASSERT_EQ (UNSPEC_MEMORY_BLOCKAGE, XINT (src, 1));
> +
> + rtx v0 = XVECEXP (src, 0, 0);
> +
> + /* Verify that the two uses of the first SCRATCH have pointer
> + equality. */
> + rtx scratch_a = XEXP (dst, 0);
> + ASSERT_EQ (SCRATCH, GET_CODE (scratch_a));
> +
> + rtx scratch_b = XEXP (v0, 0);
> + ASSERT_EQ (SCRATCH, GET_CODE (scratch_b));
> +
> + ASSERT_EQ (scratch_a, scratch_b);
> +
> + /* Verify that the two mems are thus treated as equal. */
> + ASSERT_TRUE (rtx_equal_p (dst, v0));
> +
> + /* Verify the the insn is recognized. */
> + ASSERT_NE(-1, recog_memoized (insn));
> +
> + /* Test of an UNSPEC_VOLATILE, which has its own enum values. */
> + insn = NEXT_INSN (insn);
> + ASSERT_EQ (INSN, GET_CODE (insn));
> +
> + set = single_set (insn);
> + ASSERT_NE (NULL, set);
> +
> + src = SET_SRC (set);
> + ASSERT_EQ (UNSPEC_VOLATILE, GET_CODE (src));
> + ASSERT_EQ (UNSPECV_RDTSCP, XINT (src, 1));
> +}
> +
> /* Run all target-specific selftests. */
>
> static void
> @@ -51207,6 +51410,13 @@ ix86_run_selftests (void)
> {
> ix86_test_dumping_hard_regs ();
> ix86_test_dumping_memory_blockage ();
> +
> + /* Various tests of loading RTL dumps, here because they contain
> + ix86-isms (e.g. names of hard regs). */
> + ix86_test_loading_dump_fragment_1 ();
> + ix86_test_loading_call_insn ();
> + ix86_test_loading_full_dump ();
> + ix86_test_loading_unspec ();
> }
>
> } // namespace selftest
> diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl
> b/gcc/testsuite/selftests/x86_64/call-insn.rtl
> new file mode 100644
> index 0000000..8f3a781
> --- /dev/null
> +++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
> @@ -0,0 +1,17 @@
> +(function "test"
> + (insn-chain
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (ccall_insn/j 1
> + (set (reg:DF xmm0)
> + (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]
> <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
> + (const_int 0))) "test.c":19
> + (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags
> 0x41] <function_decl 0x7f82b1429d00 sqrt>)
> + (expr_list:REG_EH_REGION (const_int 0)
> + (nil)))
> + (expr_list:DF (use (reg:DF xmm0))
> + (nil)))
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> +) ;; function "test"
> diff --git a/gcc/testsuite/selftests/x86_64/copy-hard-reg-into
> -frame.rtl b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into
> -frame.rtl
> new file mode 100644
> index 0000000..4598a1c
> --- /dev/null
> +++ b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
> @@ -0,0 +1,15 @@
> +(function "copy_hard_reg_into_frame"
> + (insn-chain
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cinsn 1 (set (mem/c:SI
> + (plus:DI
> + (reg/f:DI frame)
> + (const_int -4))
> + [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "test.c":2
> + (nil))
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> +) ;; function
> diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl
> b/gcc/testsuite/selftests/x86_64/times-two.rtl
> new file mode 100644
> index 0000000..8cec47a
> --- /dev/null
> +++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
> @@ -0,0 +1,51 @@
> +;; Dump of this C function:
> +;;
> +;; int times_two (int i)
> +;; {
> +;; return i * 2;
> +;; }
> +;;
> +;; after expand for target==x86_64
> +
> +(function "times_two"
> + (insn-chain
> + (cnote 1 NOTE_INSN_DELETED)
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (reg:SI di [ i ])) "../../src/times-two.c":2
> + (nil))
> + (cnote 3 NOTE_INSN_FUNCTION_BEG)
> + (cinsn 6 (set (reg:SI <2>)
> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32]))
> "../../src/times-two.c":3
> + (nil))
> + (cinsn 7 (parallel [
> + (set (reg:SI <0> [ _2 ])
> + (ashift:SI (reg:SI <2>)
> + (const_int 1)))
> + (clobber (reg:CC flags))
> + ]) "../../src/times-two.c":3
> + (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI
> (reg/f:DI virtual-stack-vars)
> + (const_int -4)) [1 i+0 S4 A32])
> + (const_int 1))
> + (nil)))
> + (cinsn 10 (set (reg:SI <1> [ <retval> ])
> + (reg:SI <0> [ _2 ])) "../../src/times-two.c":3
> + (nil))
> + (cinsn 14 (set (reg/i:SI ax)
> + (reg:SI <1> [ <retval> ])) "../../src/times
> -two.c":4
> + (nil))
> + (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
> + (nil))
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> + (crtl
> + (return_rtx
> + (reg/i:SI ax)
> + ) ;; return_rtx
> + ) ;; crtl
> +) ;; function "times_two"
> diff --git a/gcc/testsuite/selftests/x86_64/unspec.rtl
> b/gcc/testsuite/selftests/x86_64/unspec.rtl
> new file mode 100644
> index 0000000..ac822ac
> --- /dev/null
> +++ b/gcc/testsuite/selftests/x86_64/unspec.rtl
> @@ -0,0 +1,20 @@
> +(function "test_unspec"
> + (insn-chain
> + (block 2
> + (edge-from entry (flags "FALLTHRU"))
> + (cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])
> + (unspec:BLK [
> + (mem/v:BLK (reuse_rtx 0) [0 A8])
> + ] UNSPEC_MEMORY_BLOCKAGE))
> "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
> + (nil))
> +
> + (cinsn 2 (set (mem/v:BLK (1|scratch:DI) [0 A8])
> + (unspec_volatile:BLK [
> + (mem/v:BLK (reuse_rtx 1) [0 A8])
> + ] UNSPECV_RDTSCP))
> "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
> + (nil))
> +
> + (edge-to exit (flags "FALLTHRU"))
> + ) ;; block 2
> + ) ;; insn-chain
> +) ;; function
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: PING Re: [PATCH] Add x86_64-specific selftests for RTL function reader (v2)
2017-01-03 16:47 ` PING " David Malcolm
@ 2017-01-05 9:43 ` Uros Bizjak
0 siblings, 0 replies; 78+ messages in thread
From: Uros Bizjak @ 2017-01-05 9:43 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches, Jan Hubicka, Bernd Schmidt
On Tue, Jan 3, 2017 at 5:47 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> Ping:
> https://gcc.gnu.org/ml/gcc-patches/2016-12/msg01616.html
>
> (the patch has been successfully bootstrap®rtested on
> x86_64-pc-linux-gnu, and also tested on i686-pc-linux-gnu).
I consider this part of testing ifrastructure, not part of
target-dependent functionality, IOW, testing infrastructure just
happens to live in i386.md.
So, if there is nothing fundamentally x86 specific, I think that
previous OKs were enough.
Uros.
> On Mon, 2016-12-19 at 12:12 -0500, David Malcolm wrote:
>> Note to i386 maintainters: this patch is part of the RTL frontend.
>> It adds selftests for verifying that the RTL dump reader works as
>> expected, with a mixture of real and hand-written "dumps" to
>> exercise various aspects of the loader. Many RTL dumps contain
>> target-specific features (e.g. names of hard regs), and so these
>> selftests need to be target-specific, and hence this patch puts
>> them in i386.c.
>>
>> Tested on i686-pc-linux-gnu and x86_64-pc-linux-gnu.
>>
>> OK for trunk, assuming bootstrap®rtest?
>> (this is dependent on patch 8a within the kit).
>>
>> Changed in v2:
>> - fixed selftest failures on i686:
>> * config/i386/i386.c
>> (selftest::ix86_test_loading_dump_fragment_1): Fix handling of
>> "frame" reg.
>> (selftest::ix86_test_loading_call_insn): Require TARGET_SSE.
>> - updated to use "<3>" syntax for pseudos, rather than "$3"
>>
>> Blurb from v1:
>> This patch adds more selftests for class function_reader, where
>> the dumps to be read contain x86_64-specific features.
>>
>> In an earlier version of the patch kit, these were handled using
>> preprocessor conditionals.
>> This version instead runs them via a target hook for running
>> target-specific selftests, thus putting them within i386.c.
>>
>> gcc/ChangeLog:
>> * config/i386/i386.c
>> (selftest::ix86_test_loading_dump_fragment_1): New function.
>> (selftest::ix86_test_loading_call_insn): New function.
>> (selftest::ix86_test_loading_full_dump): New function.
>> (selftest::ix86_test_loading_unspec): New function.
>> (selftest::ix86_run_selftests): Call the new functions.
>>
>> gcc/testsuite/ChangeLog:
>> * selftests/x86_64: New subdirectory.
>> * selftests/x86_64/call-insn.rtl: New file.
>> * selftests/x86_64/copy-hard-reg-into-frame.rtl: New file.
>> * selftests/x86_64/times-two.rtl: New file.
>> * selftests/x86_64/unspec.rtl: New file.
>>
>> ---
>> gcc/config/i386/i386.c | 210
>> +++++++++++++++++++++
>> gcc/testsuite/selftests/x86_64/call-insn.rtl | 17 ++
>> .../selftests/x86_64/copy-hard-reg-into-frame.rtl | 15 ++
>> gcc/testsuite/selftests/x86_64/times-two.rtl | 51 +++++
>> gcc/testsuite/selftests/x86_64/unspec.rtl | 20 ++
>> 5 files changed, 313 insertions(+)
>> create mode 100644 gcc/testsuite/selftests/x86_64/call-insn.rtl
>> create mode 100644 gcc/testsuite/selftests/x86_64/copy-hard-reg-into
>> -frame.rtl
>> create mode 100644 gcc/testsuite/selftests/x86_64/times-two.rtl
>> create mode 100644 gcc/testsuite/selftests/x86_64/unspec.rtl
>>
>> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
>> index 1cd1cd8..dc1a86f 100644
>> --- a/gcc/config/i386/i386.c
>> +++ b/gcc/config/i386/i386.c
>> @@ -51200,6 +51200,209 @@ ix86_test_dumping_memory_blockage ()
>> " ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
>> }
>>
>> +/* Verify loading an RTL dump; specifically a dump of copying
>> + a param on x86_64 from a hard reg into the frame.
>> + This test is target-specific since the dump contains target
>> -specific
>> + hard reg names. */
>> +
>> +static void
>> +ix86_test_loading_dump_fragment_1 ()
>> +{
>> + rtl_dump_test t (SELFTEST_LOCATION,
>> + locate_file ("x86_64/copy-hard-reg-into
>> -frame.rtl"));
>> +
>> + rtx_insn *insn = get_insn_by_uid (1);
>> +
>> + /* The block structure and indentation here is purely for
>> + readability; it mirrors the structure of the rtx. */
>> + tree mem_expr;
>> + {
>> + rtx pat = PATTERN (insn);
>> + ASSERT_EQ (SET, GET_CODE (pat));
>> + {
>> + rtx dest = SET_DEST (pat);
>> + ASSERT_EQ (MEM, GET_CODE (dest));
>> + /* Verify the "/c" was parsed. */
>> + ASSERT_TRUE (RTX_FLAG (dest, call));
>> + ASSERT_EQ (SImode, GET_MODE (dest));
>> + {
>> + rtx addr = XEXP (dest, 0);
>> + ASSERT_EQ (PLUS, GET_CODE (addr));
>> + ASSERT_EQ (DImode, GET_MODE (addr));
>> + {
>> + rtx lhs = XEXP (addr, 0);
>> + /* Verify that the "frame" REG was consolidated. */
>> + ASSERT_RTX_PTR_EQ (frame_pointer_rtx, lhs);
>> + }
>> + {
>> + rtx rhs = XEXP (addr, 1);
>> + ASSERT_EQ (CONST_INT, GET_CODE (rhs));
>> + ASSERT_EQ (-4, INTVAL (rhs));
>> + }
>> + }
>> + /* Verify the "[1 i+0 S4 A32]" was parsed. */
>> + ASSERT_EQ (1, MEM_ALIAS_SET (dest));
>> + /* "i" should have been handled by synthesizing a global int
>> + variable named "i". */
>> + mem_expr = MEM_EXPR (dest);
>> + ASSERT_NE (mem_expr, NULL);
>> + ASSERT_EQ (VAR_DECL, TREE_CODE (mem_expr));
>> + ASSERT_EQ (integer_type_node, TREE_TYPE (mem_expr));
>> + ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (DECL_NAME (mem_expr)));
>> + ASSERT_STREQ ("i", IDENTIFIER_POINTER (DECL_NAME (mem_expr)));
>> + /* "+0". */
>> + ASSERT_TRUE (MEM_OFFSET_KNOWN_P (dest));
>> + ASSERT_EQ (0, MEM_OFFSET (dest));
>> + /* "S4". */
>> + ASSERT_EQ (4, MEM_SIZE (dest));
>> + /* "A32. */
>> + ASSERT_EQ (32, MEM_ALIGN (dest));
>> + }
>> + {
>> + rtx src = SET_SRC (pat);
>> + ASSERT_EQ (REG, GET_CODE (src));
>> + ASSERT_EQ (SImode, GET_MODE (src));
>> + ASSERT_EQ (5, REGNO (src));
>> + tree reg_expr = REG_EXPR (src);
>> + /* "i" here should point to the same var as for the MEM_EXPR.
>> */
>> + ASSERT_EQ (reg_expr, mem_expr);
>> + }
>> + }
>> +}
>> +
>> +/* Verify that the RTL loader copes with a call_insn dump.
>> + This test is target-specific since the dump contains a target
>> -specific
>> + hard reg name. */
>> +
>> +static void
>> +ix86_test_loading_call_insn ()
>> +{
>> + /* The test dump includes register "xmm0", where requires
>> TARGET_SSE
>> + to exist. */
>> + if (!TARGET_SSE)
>> + return;
>> +
>> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/call
>> -insn.rtl"));
>> +
>> + rtx_insn *insn = get_insns ();
>> + ASSERT_EQ (CALL_INSN, GET_CODE (insn));
>> +
>> + /* "/j". */
>> + ASSERT_TRUE (RTX_FLAG (insn, jump));
>> +
>> + rtx pat = PATTERN (insn);
>> + ASSERT_EQ (CALL, GET_CODE (SET_SRC (pat)));
>> +
>> + /* Verify REG_NOTES. */
>> + {
>> + /* "(expr_list:REG_CALL_DECL". */
>> + ASSERT_EQ (EXPR_LIST, GET_CODE (REG_NOTES (insn)));
>> + rtx_expr_list *note0 = as_a <rtx_expr_list *> (REG_NOTES
>> (insn));
>> + ASSERT_EQ (REG_CALL_DECL, REG_NOTE_KIND (note0));
>> +
>> + /* "(expr_list:REG_EH_REGION (const_int 0 [0])". */
>> + rtx_expr_list *note1 = note0->next ();
>> + ASSERT_EQ (REG_EH_REGION, REG_NOTE_KIND (note1));
>> +
>> + ASSERT_EQ (NULL, note1->next ());
>> + }
>> +
>> + /* Verify CALL_INSN_FUNCTION_USAGE. */
>> + {
>> + /* "(expr_list:DF (use (reg:DF 21 xmm0))". */
>> + rtx_expr_list *usage
>> + = as_a <rtx_expr_list *> (CALL_INSN_FUNCTION_USAGE (insn));
>> + ASSERT_EQ (EXPR_LIST, GET_CODE (usage));
>> + ASSERT_EQ (DFmode, GET_MODE (usage));
>> + ASSERT_EQ (USE, GET_CODE (usage->element ()));
>> + ASSERT_EQ (NULL, usage->next ());
>> + }
>> +}
>> +
>> +/* Verify that the RTL loader copes a dump from print_rtx_function.
>> + This test is target-specific since the dump contains target
>> -specific
>> + hard reg names. */
>> +
>> +static void
>> +ix86_test_loading_full_dump ()
>> +{
>> + rtl_dump_test t (SELFTEST_LOCATION, locate_file ("x86_64/times
>> -two.rtl"));
>> +
>> + ASSERT_STREQ ("times_two", IDENTIFIER_POINTER (DECL_NAME (cfun
>> ->decl)));
>> +
>> + rtx_insn *insn_1 = get_insn_by_uid (1);
>> + ASSERT_EQ (NOTE, GET_CODE (insn_1));
>> +
>> + rtx_insn *insn_7 = get_insn_by_uid (7);
>> + ASSERT_EQ (INSN, GET_CODE (insn_7));
>> + ASSERT_EQ (PARALLEL, GET_CODE (PATTERN (insn_7)));
>> +
>> + rtx_insn *insn_15 = get_insn_by_uid (15);
>> + ASSERT_EQ (INSN, GET_CODE (insn_15));
>> + ASSERT_EQ (USE, GET_CODE (PATTERN (insn_15)));
>> +
>> + /* Verify crtl->return_rtx. */
>> + ASSERT_EQ (REG, GET_CODE (crtl->return_rtx));
>> + ASSERT_EQ (0, REGNO (crtl->return_rtx));
>> + ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
>> +}
>> +
>> +/* Verify that the RTL loader copes with UNSPEC and UNSPEC_VOLATILE
>> insns.
>> + In particular, verify that it correctly loads the 2nd operand.
>> + This test is target-specific since these are machine-specific
>> + operands (and enums). */
>> +
>> +static void
>> +ix86_test_loading_unspec ()
>> +{
>> + rtl_dump_test t (SELFTEST_LOCATION, locate_file
>> ("x86_64/unspec.rtl"));
>> +
>> + ASSERT_STREQ ("test_unspec", IDENTIFIER_POINTER (DECL_NAME (cfun
>> ->decl)));
>> +
>> + ASSERT_TRUE (cfun);
>> +
>> + /* Test of an UNSPEC. */
>> + rtx_insn *insn = get_insns ();
>> + ASSERT_EQ (INSN, GET_CODE (insn));
>> + rtx set = single_set (insn);
>> + ASSERT_NE (NULL, set);
>> + rtx dst = SET_DEST (set);
>> + ASSERT_EQ (MEM, GET_CODE (dst));
>> + rtx src = SET_SRC (set);
>> + ASSERT_EQ (UNSPEC, GET_CODE (src));
>> + ASSERT_EQ (BLKmode, GET_MODE (src));
>> + ASSERT_EQ (UNSPEC_MEMORY_BLOCKAGE, XINT (src, 1));
>> +
>> + rtx v0 = XVECEXP (src, 0, 0);
>> +
>> + /* Verify that the two uses of the first SCRATCH have pointer
>> + equality. */
>> + rtx scratch_a = XEXP (dst, 0);
>> + ASSERT_EQ (SCRATCH, GET_CODE (scratch_a));
>> +
>> + rtx scratch_b = XEXP (v0, 0);
>> + ASSERT_EQ (SCRATCH, GET_CODE (scratch_b));
>> +
>> + ASSERT_EQ (scratch_a, scratch_b);
>> +
>> + /* Verify that the two mems are thus treated as equal. */
>> + ASSERT_TRUE (rtx_equal_p (dst, v0));
>> +
>> + /* Verify the the insn is recognized. */
>> + ASSERT_NE(-1, recog_memoized (insn));
>> +
>> + /* Test of an UNSPEC_VOLATILE, which has its own enum values. */
>> + insn = NEXT_INSN (insn);
>> + ASSERT_EQ (INSN, GET_CODE (insn));
>> +
>> + set = single_set (insn);
>> + ASSERT_NE (NULL, set);
>> +
>> + src = SET_SRC (set);
>> + ASSERT_EQ (UNSPEC_VOLATILE, GET_CODE (src));
>> + ASSERT_EQ (UNSPECV_RDTSCP, XINT (src, 1));
>> +}
>> +
>> /* Run all target-specific selftests. */
>>
>> static void
>> @@ -51207,6 +51410,13 @@ ix86_run_selftests (void)
>> {
>> ix86_test_dumping_hard_regs ();
>> ix86_test_dumping_memory_blockage ();
>> +
>> + /* Various tests of loading RTL dumps, here because they contain
>> + ix86-isms (e.g. names of hard regs). */
>> + ix86_test_loading_dump_fragment_1 ();
>> + ix86_test_loading_call_insn ();
>> + ix86_test_loading_full_dump ();
>> + ix86_test_loading_unspec ();
>> }
>>
>> } // namespace selftest
>> diff --git a/gcc/testsuite/selftests/x86_64/call-insn.rtl
>> b/gcc/testsuite/selftests/x86_64/call-insn.rtl
>> new file mode 100644
>> index 0000000..8f3a781
>> --- /dev/null
>> +++ b/gcc/testsuite/selftests/x86_64/call-insn.rtl
>> @@ -0,0 +1,17 @@
>> +(function "test"
>> + (insn-chain
>> + (block 2
>> + (edge-from entry (flags "FALLTHRU"))
>> + (ccall_insn/j 1
>> + (set (reg:DF xmm0)
>> + (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]
>> <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
>> + (const_int 0))) "test.c":19
>> + (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags
>> 0x41] <function_decl 0x7f82b1429d00 sqrt>)
>> + (expr_list:REG_EH_REGION (const_int 0)
>> + (nil)))
>> + (expr_list:DF (use (reg:DF xmm0))
>> + (nil)))
>> + (edge-to exit (flags "FALLTHRU"))
>> + ) ;; block 2
>> + ) ;; insn-chain
>> +) ;; function "test"
>> diff --git a/gcc/testsuite/selftests/x86_64/copy-hard-reg-into
>> -frame.rtl b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into
>> -frame.rtl
>> new file mode 100644
>> index 0000000..4598a1c
>> --- /dev/null
>> +++ b/gcc/testsuite/selftests/x86_64/copy-hard-reg-into-frame.rtl
>> @@ -0,0 +1,15 @@
>> +(function "copy_hard_reg_into_frame"
>> + (insn-chain
>> + (block 2
>> + (edge-from entry (flags "FALLTHRU"))
>> + (cinsn 1 (set (mem/c:SI
>> + (plus:DI
>> + (reg/f:DI frame)
>> + (const_int -4))
>> + [1 i+0 S4 A32])
>> + (reg:SI di [ i ])) "test.c":2
>> + (nil))
>> + (edge-to exit (flags "FALLTHRU"))
>> + ) ;; block 2
>> + ) ;; insn-chain
>> +) ;; function
>> diff --git a/gcc/testsuite/selftests/x86_64/times-two.rtl
>> b/gcc/testsuite/selftests/x86_64/times-two.rtl
>> new file mode 100644
>> index 0000000..8cec47a
>> --- /dev/null
>> +++ b/gcc/testsuite/selftests/x86_64/times-two.rtl
>> @@ -0,0 +1,51 @@
>> +;; Dump of this C function:
>> +;;
>> +;; int times_two (int i)
>> +;; {
>> +;; return i * 2;
>> +;; }
>> +;;
>> +;; after expand for target==x86_64
>> +
>> +(function "times_two"
>> + (insn-chain
>> + (cnote 1 NOTE_INSN_DELETED)
>> + (block 2
>> + (edge-from entry (flags "FALLTHRU"))
>> + (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
>> + (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
>> + (const_int -4)) [1 i+0 S4 A32])
>> + (reg:SI di [ i ])) "../../src/times-two.c":2
>> + (nil))
>> + (cnote 3 NOTE_INSN_FUNCTION_BEG)
>> + (cinsn 6 (set (reg:SI <2>)
>> + (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
>> + (const_int -4)) [1 i+0 S4 A32]))
>> "../../src/times-two.c":3
>> + (nil))
>> + (cinsn 7 (parallel [
>> + (set (reg:SI <0> [ _2 ])
>> + (ashift:SI (reg:SI <2>)
>> + (const_int 1)))
>> + (clobber (reg:CC flags))
>> + ]) "../../src/times-two.c":3
>> + (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI
>> (reg/f:DI virtual-stack-vars)
>> + (const_int -4)) [1 i+0 S4 A32])
>> + (const_int 1))
>> + (nil)))
>> + (cinsn 10 (set (reg:SI <1> [ <retval> ])
>> + (reg:SI <0> [ _2 ])) "../../src/times-two.c":3
>> + (nil))
>> + (cinsn 14 (set (reg/i:SI ax)
>> + (reg:SI <1> [ <retval> ])) "../../src/times
>> -two.c":4
>> + (nil))
>> + (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
>> + (nil))
>> + (edge-to exit (flags "FALLTHRU"))
>> + ) ;; block 2
>> + ) ;; insn-chain
>> + (crtl
>> + (return_rtx
>> + (reg/i:SI ax)
>> + ) ;; return_rtx
>> + ) ;; crtl
>> +) ;; function "times_two"
>> diff --git a/gcc/testsuite/selftests/x86_64/unspec.rtl
>> b/gcc/testsuite/selftests/x86_64/unspec.rtl
>> new file mode 100644
>> index 0000000..ac822ac
>> --- /dev/null
>> +++ b/gcc/testsuite/selftests/x86_64/unspec.rtl
>> @@ -0,0 +1,20 @@
>> +(function "test_unspec"
>> + (insn-chain
>> + (block 2
>> + (edge-from entry (flags "FALLTHRU"))
>> + (cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])
>> + (unspec:BLK [
>> + (mem/v:BLK (reuse_rtx 0) [0 A8])
>> + ] UNSPEC_MEMORY_BLOCKAGE))
>> "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
>> + (nil))
>> +
>> + (cinsn 2 (set (mem/v:BLK (1|scratch:DI) [0 A8])
>> + (unspec_volatile:BLK [
>> + (mem/v:BLK (reuse_rtx 1) [0 A8])
>> + ] UNSPECV_RDTSCP))
>> "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2
>> + (nil))
>> +
>> + (edge-to exit (flags "FALLTHRU"))
>> + ) ;; block 2
>> + ) ;; insn-chain
>> +) ;; function
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 9/9] Add "__RTL" to cc1 (v6)
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
` (2 preceding siblings ...)
2016-12-02 1:27 ` [PATCH 8d/9] Add x86_64-specific " David Malcolm
@ 2016-12-02 1:28 ` David Malcolm
2016-12-02 14:41 ` [PATCH 8a/9] Introduce class function_reader (v6) Bernd Schmidt
4 siblings, 0 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-02 1:28 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
Changed in v6:
- Handle EOF in c_parser_parse_rtl_body
- Various fixups from review
Changed in v5:
- rebased from r242065 to r242392. In particular, this
brings in the gimple FE; rewrote the "startwith" pass-skipping
mechanism to work with both __GIMPLE and __RTL.
- rewrote the "__RTL" parser so that it shares code with the
"__GIMPLE" parser, within c_parser_declspecs.
Updated all the test cases to use the 'startwith' syntax.
The gimple FE has a "flag_gimple" to enable __GIMPLE; should
I add an equivalent for __RTL?
- eliminated the new "native_RTL" field, instead just using
curr_properties & PROP_rtl.
- added original_copy_tables_initialized_p and reinstate:
gcc_assert (original_copy_bb_pool);
within free_original_copy_tables.
- added a test of multiple __RTL-marked functions within one test
case.
Links to previous versions:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00263.html
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00500.html
****************************************************************************
gcc/ChangeLog:
* Makefile.in (OBJS): Add run-rtl-passes.o.
gcc/c-family/ChangeLog:
* c-common.c (c_common_reswords): Add "__RTL".
* c-common.h (enum rid): Add RID_RTL.
gcc/c/ChangeLog:
* c-parser.c: Include "read-rtl-function.h" and
"run-rtl-passes.h".
(c_parser_declaration_or_fndef): Rename "gimple-pass-list" in
grammar to gimple-or-rtl-pass-list. Add rtl-function-definition
production. Update for renaming of field "gimple_pass" to
"gimple_or_rtl_pass". If __RTL was seen, call
c_parser_parse_rtl_body. Convert a timevar_push/pop pair
to an auto_timevar, to cope with early exit.
(c_parser_declspecs): Update RID_GIMPLE handling for renaming of
field "gimple_pass" to "gimple_or_rtl_pass", and for renaming of
c_parser_gimple_pass_list to c_parser_gimple_or_rtl_pass_list.
Handle RID_RTL.
(c_parser_parse_rtl_body): New function.
* c-tree.h (enum c_declspec_word): Add cdw_rtl.
(struct c_declspecs): Rename field "gimple_pass" to
"gimple_or_rtl_pass". Add field "rtl_p".
* gimple-parser.c (c_parser_gimple_pass_list): Rename to...
(c_parser_gimple_or_rtl_pass_list): ...this, updating accordingly.
* gimple-parser.h (c_parser_gimple_pass_list): Rename to...
(c_parser_gimple_or_rtl_pass_list): ...this.
gcc/ChangeLog:
* cfg.c (original_copy_tables_initialized_p): New function.
* cfg.h (original_copy_tables_initialized_p): New decl.
* cfgrtl.c (relink_block_chain): Guard the call to
free_original_copy_tables with a call to
original_copy_tables_initialized_p.
* cgraph.h (symtab_node::native_rtl_p): New decl.
* cgraphunit.c (symtab_node::native_rtl_p): New function.
(symtab_node::needed_p): Don't assert for early assembly output
for __RTL functions.
(cgraph_node::finalize_function): Set "force_output" for __RTL
functions.
(cgraph_node::analyze): Bail out early for __RTL functions.
(analyze_functions): Update assertion to support __RTL functions.
(cgraph_node::expand): Bail out early for __RTL functions.
* final.c (rest_of_clean_state): Don't call delete_tree_ssa for
_RTL functions.
* gimple-expr.c: Include "tree-pass.h".
(gimple_has_body_p): Return false for __RTL functions.
* pass_manager.h (gcc::pass_manager::get_rest_of_compilation): New
accessor.
(gcc::pass_manager::get_clean_slate): New accessor.
* passes.c: Include "insn-addr.h".
(execute_one_pass): Split out logic for skipping passes into...
(determine_pass_name_match): ...this new function, ...
(should_skip_pass_p): ...and this new function, adding logging
and special-casing dfinit.
(skip_pass): New function.
* read-md.c (md_reader::read_char): Support filtering
the input to a subset of line numbers.
(md_reader::md_reader): Initialize fields
m_first_line and m_last_line.
(md_reader::read_file_fragment): New function.
* read-md.h (md_reader::read_file_fragment): New decl.
(md_reader::m_first_line): New field.
(md_reader::int m_last_line): New field.
* read-rtl-function.c (function_reader::create_function): Only
create cfun if it doesn't already exist. Set PROP_rtl on cfun's
curr_properties. Set DECL_INITIAL to a dummy block.
(read_rtl_function_body_from_file_range): New function.
* read-rtl-function.h (read_rtl_function_body_from_file_range):
New decl.
* run-rtl-passes.c: New file.
* run-rtl-passes.h: New file.
gcc/testsuite/ChangeLog:
* gcc.dg/rtl/aarch64/asr_div1.c: New file.
* gcc.dg/rtl/aarch64/pr71779.c: New file.
* gcc.dg/rtl/rtl.exp: New file.
* gcc.dg/rtl/test.c: New file.
* gcc.dg/rtl/truncated-rtl-file.c: New file.
* gcc.dg/rtl/unknown-rtx-code.c: New file.
* gcc.dg/rtl/x86_64/dfinit.c: New file.
* gcc.dg/rtl/x86_64/different-structs.c: New file.
* gcc.dg/rtl/x86_64/final.c: New file.
* gcc.dg/rtl/x86_64/into-cfglayout.c: New file.
* gcc.dg/rtl/x86_64/ira.c: New file.
* gcc.dg/rtl/x86_64/pro_and_epilogue.c: New file.
* gcc.dg/rtl/x86_64/test-multiple-fns.c: New file.
* gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c: New file.
* gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c: New file.
* gcc.dg/rtl/x86_64/test-rtl.c: New file.
* gcc.dg/rtl/x86_64/test_1.h: New file.
* gcc.dg/rtl/x86_64/times-two.c.after-expand.c: New file.
* gcc.dg/rtl/x86_64/times-two.c.before-df.c: New file.
* gcc.dg/rtl/x86_64/vregs.c: New file.
---
gcc/Makefile.in | 1 +
gcc/c-family/c-common.c | 1 +
gcc/c-family/c-common.h | 3 +
gcc/c/c-parser.c | 109 ++++++++++++++++-
gcc/c/c-tree.h | 7 +-
gcc/c/gimple-parser.c | 8 +-
gcc/c/gimple-parser.h | 2 +-
gcc/cfg.c | 9 ++
gcc/cfg.h | 1 +
gcc/cfgrtl.c | 3 +-
gcc/cgraph.h | 4 +
gcc/cgraphunit.c | 41 ++++++-
gcc/final.c | 3 +-
gcc/function.h | 2 +-
gcc/gimple-expr.c | 3 +-
gcc/pass_manager.h | 6 +
gcc/passes.c | 130 ++++++++++++++++----
gcc/read-md.c | 35 +++++-
gcc/read-md.h | 7 ++
gcc/read-rtl-function.c | 83 ++++++++++---
gcc/read-rtl-function.h | 3 +
gcc/run-rtl-passes.c | 88 ++++++++++++++
gcc/run-rtl-passes.h | 25 ++++
gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c | 41 +++++++
gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c | 50 ++++++++
gcc/testsuite/gcc.dg/rtl/rtl.exp | 41 +++++++
gcc/testsuite/gcc.dg/rtl/test.c | 31 +++++
gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c | 2 +
gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c | 8 ++
gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c | 116 ++++++++++++++++++
.../gcc.dg/rtl/x86_64/different-structs.c | 81 +++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/final.c | 133 +++++++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c | 117 ++++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/ira.c | 111 +++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c | 110 +++++++++++++++++
.../gcc.dg/rtl/x86_64/test-multiple-fns.c | 105 ++++++++++++++++
.../rtl/x86_64/test-return-const.c.after-expand.c | 39 ++++++
.../rtl/x86_64/test-return-const.c.before-fwprop.c | 42 +++++++
gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c | 101 ++++++++++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h | 16 +++
.../gcc.dg/rtl/x86_64/times-two.c.after-expand.c | 70 +++++++++++
.../gcc.dg/rtl/x86_64/times-two.c.before-df.c | 54 +++++++++
gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c | 112 +++++++++++++++++
43 files changed, 1891 insertions(+), 63 deletions(-)
create mode 100644 gcc/run-rtl-passes.c
create mode 100644 gcc/run-rtl-passes.h
create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/rtl.exp
create mode 100644 gcc/testsuite/gcc.dg/rtl/test.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/final.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
create mode 100644 gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 73d12dc..14ffb96 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1429,6 +1429,7 @@ OBJS = \
rtlhash.o \
rtlanal.o \
rtlhooks.o \
+ run-rtl-passes.o \
sbitmap.o \
sched-deps.o \
sched-ebb.o \
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 2997c83..7ba3539 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -437,6 +437,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__volatile__", RID_VOLATILE, 0 },
{ "__GIMPLE", RID_GIMPLE, D_CONLY },
{ "__PHI", RID_PHI, D_CONLY },
+ { "__RTL", RID_RTL, D_CONLY },
{ "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "asm", RID_ASM, D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 241b345..89a5f6f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -124,6 +124,9 @@ enum rid
/* "__PHI", for parsing PHI function in GIMPLE FE. */
RID_PHI,
+ /* "__RTL", for the RTL-parsing extension to the C frontend. */
+ RID_RTL,
+
/* C11 */
RID_ALIGNAS, RID_GENERIC,
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 00fe731..fef882a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3. If not see
#include "gcc-rich-location.h"
#include "c-parser.h"
#include "gimple-parser.h"
+#include "read-rtl-function.h"
+#include "run-rtl-passes.h"
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
@@ -1310,6 +1312,8 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
static void c_parser_cilk_grainsize (c_parser *, bool *);
+static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass);
+
/* Parse a translation unit (C90 6.7, C99 6.9).
translation-unit:
@@ -1546,7 +1550,11 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
GIMPLE:
gimple-function-definition:
- declaration-specifiers[opt] __GIMPLE (gimple-pass-list) declarator
+ declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator
+ declaration-list[opt] compound-statement
+
+ rtl-function-definition:
+ declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator
declaration-list[opt] compound-statement */
static void
@@ -2042,7 +2050,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
tv = TV_PARSE_INLINE;
else
tv = TV_PARSE_FUNC;
- timevar_push (tv);
+ auto_timevar at (g_timer, tv);
/* Parse old-style parameter declarations. ??? Attributes are
not allowed to start declaration specifiers here because of a
@@ -2074,12 +2082,28 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
function body as GIMPLE. */
if (specs->gimple_p)
{
- cfun->pass_startwith = specs->gimple_pass;
+ cfun->pass_startwith = specs->gimple_or_rtl_pass;
bool saved = in_late_binary_op;
in_late_binary_op = true;
c_parser_parse_gimple_body (parser);
in_late_binary_op = saved;
}
+ /* Similarly, if it was marked with __RTL, use the RTL parser now,
+ consuming the function body. */
+ else if (specs->rtl_p)
+ {
+ c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
+
+ /* Normally, store_parm_decls sets next_is_function_body,
+ anticipating a function body. We need a push_scope/pop_scope
+ pair to flush out this state, or subsequent function parsing
+ will go wrong. */
+ push_scope ();
+ pop_scope ();
+
+ finish_function ();
+ return;
+ }
else
{
fnbody = c_parser_compound_statement (parser);
@@ -2110,7 +2134,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (specs->gimple_p)
DECL_SAVED_TREE (fndecl) = NULL_TREE;
- timevar_pop (tv);
break;
}
}
@@ -2602,7 +2625,13 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
c_parser_consume_token (parser);
specs->gimple_p = true;
specs->locations[cdw_gimple] = loc;
- specs->gimple_pass = c_parser_gimple_pass_list (parser);
+ specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+ break;
+ case RID_RTL:
+ c_parser_consume_token (parser);
+ specs->rtl_p = true;
+ specs->locations[cdw_rtl] = loc;
+ specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
break;
default:
goto out;
@@ -18258,4 +18287,74 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
return value_tree;
}
+/* Parse the body of a function declaration marked with "__RTL".
+
+ The RTL parser works on the level of characters read from a
+ FILE *, whereas c_parser works at the level of tokens.
+ Square this circle by consuming all of the tokens up to and
+ including the closing brace, recording the start/end of the RTL
+ fragment, and reopening the file and re-reading the relevant
+ lines within the RTL parser.
+
+ This requires the opening and closing braces of the C function
+ to be on separate lines from the RTL they wrap.
+
+ Take ownership of START_WITH_PASS, if non-NULL. */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
+{
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ free (start_with_pass);
+ return;
+ }
+
+ location_t start_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume all tokens, up to the closing brace, handling
+ matching pairs of braces in the rtl dump. */
+ int num_open_braces = 1;
+ while (1)
+ {
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_BRACE:
+ num_open_braces++;
+ break;
+ case CPP_CLOSE_BRACE:
+ if (--num_open_braces == 0)
+ goto found_closing_brace;
+ break;
+ case CPP_EOF:
+ error_at (start_loc, "no closing brace");
+ free (start_with_pass);
+ return;
+ default:
+ break;
+ }
+ c_parser_consume_token (parser);
+ }
+
+ found_closing_brace:
+ /* At the closing brace; record its location. */
+ location_t end_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume the closing brace. */
+ c_parser_consume_token (parser);
+
+ /* Invoke the RTL parser. */
+ if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+ {
+ free (start_with_pass);
+ return;
+ }
+
+ /* If a pass name was provided for START_WITH_PASS, run the backend
+ accordingly now, on the cfun created above, transferring
+ ownership of START_WITH_PASS. */
+ if (start_with_pass)
+ run_rtl_passes (start_with_pass);
+}
+
#include "gt-c-c-parser.h"
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a8cf353..94821d8 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -268,6 +268,7 @@ enum c_declspec_word {
cdw_alignas,
cdw_address_space,
cdw_gimple,
+ cdw_rtl,
cdw_number_of_elements /* This one must always be the last
enumerator. */
};
@@ -291,8 +292,8 @@ struct c_declspecs {
NULL; attributes (possibly from multiple lists) will be passed
separately. */
tree attrs;
- /* The pass to start compiling a __GIMPLE function with. */
- char *gimple_pass;
+ /* The pass to start compiling a __GIMPLE or __RTL function with. */
+ char *gimple_or_rtl_pass;
/* The base-2 log of the greatest alignment required by an _Alignas
specifier, in bytes, or -1 if no such specifiers with nonzero
alignment. */
@@ -367,6 +368,8 @@ struct c_declspecs {
BOOL_BITFIELD alignas_p : 1;
/* Whether any __GIMPLE specifier was specified. */
BOOL_BITFIELD gimple_p : 1;
+ /* Whether any __RTL specifier was specified. */
+ BOOL_BITFIELD rtl_p : 1;
/* The address space that the declaration belongs to. */
addr_space_t address_space;
};
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
index 9b6af13..f5b2c44 100644
--- a/gcc/c/gimple-parser.c
+++ b/gcc/c/gimple-parser.c
@@ -1000,18 +1000,18 @@ c_parser_gimple_label (c_parser *parser, gimple_seq *seq)
return;
}
-/* Parse gimple pass list.
+/* Parse gimple/RTL pass list.
- gimple-pass-list:
+ gimple-or-rtl-pass-list:
startwith("pass-name")
*/
char *
-c_parser_gimple_pass_list (c_parser *parser)
+c_parser_gimple_or_rtl_pass_list (c_parser *parser)
{
char *pass = NULL;
- /* Accept __GIMPLE. */
+ /* Accept __GIMPLE/__RTL. */
if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
return NULL;
c_parser_consume_token (parser);
diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
index f72b626..e3ab019 100644
--- a/gcc/c/gimple-parser.h
+++ b/gcc/c/gimple-parser.h
@@ -22,6 +22,6 @@ along with GCC; see the file COPYING3. If not see
/* Gimple parsing functions. */
extern void c_parser_parse_gimple_body (c_parser *);
-extern char *c_parser_gimple_pass_list (c_parser *);
+extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
#endif
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 6604b02..1ca6592 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -1094,6 +1094,15 @@ free_original_copy_tables (void)
original_copy_bb_pool = NULL;
}
+/* Return true iff we have had a call to initialize_original_copy_tables
+ without a corresponding call to free_original_copy_tables. */
+
+bool
+original_copy_tables_initialized_p (void)
+{
+ return original_copy_bb_pool != NULL;
+}
+
/* Removes the value associated with OBJ from table TAB. */
static void
diff --git a/gcc/cfg.h b/gcc/cfg.h
index ad935e3..df1480f 100644
--- a/gcc/cfg.h
+++ b/gcc/cfg.h
@@ -110,6 +110,7 @@ extern void scale_bbs_frequencies_gcov_type (basic_block *, int, gcov_type,
extern void initialize_original_copy_tables (void);
extern void reset_original_copy_tables (void);
extern void free_original_copy_tables (void);
+extern bool original_copy_tables_initialized_p (void);
extern void set_bb_original (basic_block, basic_block);
extern basic_block get_bb_original (basic_block);
extern void set_bb_copy (basic_block, basic_block);
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index d2719db..de53295 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -3647,7 +3647,8 @@ relink_block_chain (bool stay_in_cfglayout_mode)
/* Maybe reset the original copy tables, they are not valid anymore
when we renumber the basic blocks in compact_blocks. If we are
are going out of cfglayout mode, don't re-allocate the tables. */
- free_original_copy_tables ();
+ if (original_copy_tables_initialized_p ())
+ free_original_copy_tables ();
if (stay_in_cfglayout_mode)
initialize_original_copy_tables ();
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cc730d2..79e33da 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -328,6 +328,10 @@ public:
configury. This function is used just during symbol creation. */
bool needed_p (void);
+ /* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+ bool native_rtl_p () const;
+
/* Return true when there are references to the node. */
bool referred_to_p (bool include_self = true);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index e315a77..aae7b2a 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -217,6 +217,19 @@ static void handle_alias_pairs (void);
/* Used for vtable lookup in thunk adjusting. */
static GTY (()) tree vtable_entry_type;
+/* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+
+bool
+symtab_node::native_rtl_p () const
+{
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ return false;
+ if (!DECL_STRUCT_FUNCTION (decl))
+ return false;
+ return DECL_STRUCT_FUNCTION (decl)->curr_properties & PROP_rtl;
+}
+
/* Determine if symbol declaration is needed. That is, visible to something
either outside this translation unit, something magic in the system
configury */
@@ -225,8 +238,10 @@ symtab_node::needed_p (void)
{
/* Double check that no one output the function into assembly file
early. */
- gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl)
- || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
+ if (!native_rtl_p ())
+ gcc_checking_assert
+ (!DECL_ASSEMBLER_NAME_SET_P (decl)
+ || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
if (!definition)
return false;
@@ -435,6 +450,14 @@ cgraph_node::finalize_function (tree decl, bool no_collect)
&& !DECL_DISREGARD_INLINE_LIMITS (decl))
node->force_output = 1;
+ /* __RTL functions were already output as soon as they were parsed (due
+ to the large amount of global state in the backend).
+ Mark such functions as "force_output" to reflect the fact that they
+ will be in the asm file when considering the symbols they reference.
+ The attempt to output them later on will bail out immediately. */
+ if (node->native_rtl_p ())
+ node->force_output = 1;
+
/* When not optimizing, also output the static functions. (see
PR24561), but don't do so for always_inline functions, functions
declared inline and nested functions. These were optimized out
@@ -568,6 +591,12 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
void
cgraph_node::analyze (void)
{
+ if (native_rtl_p ())
+ {
+ analyzed = true;
+ return;
+ }
+
tree decl = this->decl;
location_t saved_loc = input_location;
input_location = DECL_SOURCE_LOCATION (decl);
@@ -1226,7 +1255,8 @@ analyze_functions (bool first_time)
gcc_assert (!cnode->definition || cnode->thunk.thunk_p
|| cnode->alias
- || gimple_has_body_p (decl));
+ || gimple_has_body_p (decl)
+ || cnode->native_rtl_p ());
gcc_assert (cnode->analyzed == cnode->definition);
}
node->aux = NULL;
@@ -1965,6 +1995,11 @@ cgraph_node::expand (void)
/* We ought to not compile any inline clones. */
gcc_assert (!global.inlined_to);
+ /* __RTL functions are compiled as soon as they are parsed, so don't
+ do it again. */
+ if (native_rtl_p ())
+ return;
+
announce_function (decl);
process = 0;
gcc_assert (lowered);
diff --git a/gcc/final.c b/gcc/final.c
index 5709d0e..c1afc57 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4701,7 +4701,8 @@ rest_of_clean_state (void)
free_bb_for_insn ();
- delete_tree_ssa (cfun);
+ if (cfun->gimple_df)
+ delete_tree_ssa (cfun);
/* We can reduce stack alignment on call site only when we are sure that
the function body just produced will be actually used in the final
diff --git a/gcc/function.h b/gcc/function.h
index cabffb9..19c26c8 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -236,7 +236,7 @@ struct GTY(()) function {
/* The loops in this function. */
struct loops *x_current_loops;
- /* Filled by the GIMPLE FE, pass to start compilation with. */
+ /* Filled by the GIMPLE and RTL FEs, pass to start compilation with. */
char *pass_startwith;
/* The stack usage of this function. */
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index de5cce1..e60c607 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "demangle.h"
#include "hash-set.h"
#include "rtl.h"
+#include "tree-pass.h"
/* ----- Type related ----- */
@@ -323,7 +324,7 @@ bool
gimple_has_body_p (tree fndecl)
{
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
- return (gimple_body (fndecl) || (fn && fn->cfg));
+ return (gimple_body (fndecl) || (fn && fn->cfg && !(fn->curr_properties & PROP_rtl)));
}
/* Return a printable name for symbol DECL. */
diff --git a/gcc/pass_manager.h b/gcc/pass_manager.h
index 464e25f..7278d97 100644
--- a/gcc/pass_manager.h
+++ b/gcc/pass_manager.h
@@ -82,6 +82,12 @@ public:
opt_pass *get_pass_by_name (const char *name);
+ opt_pass *get_rest_of_compilation () const
+ {
+ return pass_rest_of_compilation_1;
+ }
+ opt_pass *get_clean_slate () const { return pass_clean_state_1; }
+
public:
/* The root of the compilation pass tree, once constructed. */
opt_pass *all_passes;
diff --git a/gcc/passes.c b/gcc/passes.c
index 51d0d84..5086868 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgrtl.h"
#include "tree-ssa-live.h" /* For remove_unused_locals. */
#include "tree-cfgcleanup.h"
+#include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC. */
using namespace gcc;
@@ -2273,6 +2274,106 @@ override_gate_status (opt_pass *pass, tree func, bool gate_status)
return gate_status;
}
+/* Determine if PASS_NAME matches CRITERION.
+ Not a pure predicate, since it can update CRITERION, to support
+ matching the Nth invocation of a pass.
+ Subroutine of should_skip_pass_p. */
+
+static bool
+determine_pass_name_match (const char *pass_name, char *criterion)
+{
+ size_t namelen = strlen (pass_name);
+ if (!strncmp (pass_name, criterion, namelen))
+ {
+ /* The following supports starting with the Nth invocation
+ of a pass (where N does not necessarily is equal to the
+ dump file suffix). */
+ if (criterion[namelen] == '\0'
+ || (criterion[namelen] == '1'
+ && criterion[namelen + 1] == '\0'))
+ return true;
+ else
+ {
+ if (criterion[namelen + 1] == '\0')
+ --criterion[namelen];
+ return false;
+ }
+ }
+ else
+ return false;
+}
+
+/* For skipping passes until "startwith" pass.
+ Return true iff PASS should be skipped.
+ Clear cfun->pass_startwith when encountering the "startwith" pass,
+ so that all subsequent passes are run. */
+
+static bool
+should_skip_pass_p (opt_pass *pass)
+{
+ if (!cfun)
+ return false;
+ if (!cfun->pass_startwith)
+ return false;
+
+ /* We can't skip the lowering phase yet -- ideally we'd
+ drive that phase fully via properties. */
+ if (pass->type == GIMPLE_PASS
+ && !(cfun->curr_properties & PROP_ssa))
+ {
+ if (!quiet_flag)
+ fprintf (stderr, "running pass anyway: %s\n", pass->name);
+ return false;
+ }
+
+ if (determine_pass_name_match (pass->name, cfun->pass_startwith))
+ {
+ if (!quiet_flag)
+ fprintf (stderr, "found starting pass: %s\n", pass->name);
+ cfun->pass_startwith = NULL;
+ return false;
+ }
+
+ /* Don't skip df init; later RTL passes need it. */
+ if (strstr (pass->name, "dfinit") != NULL)
+ return false;
+
+ if (!quiet_flag)
+ fprintf (stderr, "skipping pass: %s\n", pass->name);
+ return true;
+}
+
+/* Skip the given pass, for handling passes before "startwith"
+ in __GIMPLE and__RTL-marked functions.
+ In theory, this ought to be a no-op, but some of the RTL passes
+ need additional processing here. */
+
+static void
+skip_pass (opt_pass *pass)
+{
+ /* Pass "reload" sets the global "reload_completed", and many
+ things depend on this (e.g. instructions in .md files). */
+ if (strcmp (pass->name, "reload") == 0)
+ reload_completed = 1;
+
+ /* The INSN_ADDRESSES vec is normally set up by
+ shorten_branches; set it up for the benefit of passes that
+ run after this. */
+ if (strcmp (pass->name, "shorten") == 0)
+ INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+ /* Update the cfg hooks as appropriate. */
+ if (strcmp (pass->name, "into_cfglayout") == 0)
+ {
+ cfg_layout_rtl_register_cfg_hooks ();
+ cfun->curr_properties |= PROP_cfglayout;
+ }
+ if (strcmp (pass->name, "outof_cfglayout") == 0)
+ {
+ rtl_register_cfg_hooks ();
+ cfun->curr_properties &= ~PROP_cfglayout;
+ }
+}
/* Execute PASS. */
@@ -2313,33 +2414,10 @@ execute_one_pass (opt_pass *pass)
return false;
}
- /* For skipping passes until startwith pass */
- if (cfun
- && cfun->pass_startwith
- /* But we can't skip the lowering phase yet -- ideally we'd
- drive that phase fully via properties. */
- && (cfun->curr_properties & PROP_ssa))
+ if (should_skip_pass_p (pass))
{
- size_t namelen = strlen (pass->name);
- if (! strncmp (pass->name, cfun->pass_startwith, namelen))
- {
- /* The following supports starting with the Nth invocation
- of a pass (where N does not necessarily is equal to the
- dump file suffix). */
- if (cfun->pass_startwith[namelen] == '\0'
- || (cfun->pass_startwith[namelen] == '1'
- && cfun->pass_startwith[namelen + 1] == '\0'))
- cfun->pass_startwith = NULL;
- else
- {
- if (cfun->pass_startwith[namelen + 1] != '\0')
- return true;
- --cfun->pass_startwith[namelen];
- return true;
- }
- }
- else
- return true;
+ skip_pass (pass);
+ return true;
}
/* Pass execution event trigger: useful to identify passes being
diff --git a/gcc/read-md.c b/gcc/read-md.c
index a8462a6..25bc3c4 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -399,6 +399,16 @@ md_reader::read_char (void)
else
m_read_md_colno++;
+ /* If we're filtering lines, treat everything before the range of
+ interest as a space, and as EOF for everything after. */
+ if (m_first_line && m_last_line)
+ {
+ if (m_read_md_lineno < m_first_line)
+ return ' ';
+ if (m_read_md_lineno > m_last_line)
+ return EOF;
+ }
+
return ch;
}
@@ -981,7 +991,9 @@ md_reader::md_reader (bool compact)
m_read_md_lineno (0),
m_read_md_colno (0),
m_first_dir_md_include (NULL),
- m_last_dir_md_include_ptr (&m_first_dir_md_include)
+ m_last_dir_md_include_ptr (&m_first_dir_md_include),
+ m_first_line (0),
+ m_last_line (0)
{
/* Set the global singleton pointer. */
md_reader_ptr = this;
@@ -1284,6 +1296,27 @@ md_reader::read_md_files (int argc, const char **argv,
return !have_error;
}
+
+/* Read FILENAME, filtering to just the given lines. */
+
+bool
+md_reader::read_file_fragment (const char *filename,
+ int first_line,
+ int last_line)
+{
+ m_read_md_filename = filename;
+ m_read_md_file = fopen (m_read_md_filename, "r");
+ if (m_read_md_file == 0)
+ {
+ perror (m_read_md_filename);
+ return false;
+ }
+ m_first_line = first_line;
+ m_last_line = last_line;
+ handle_toplevel_file ();
+ return !have_error;
+}
+
/* class noop_reader : public md_reader */
/* A dummy implementation which skips unknown directives. */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 06dc80e..674e1e4 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -98,6 +98,9 @@ class md_reader
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
+ bool read_file_fragment (const char *filename,
+ int first_line,
+ int last_line);
/* A hook that handles a single .md-file directive, up to but not
including the closing ')'. It takes two arguments: the file position
@@ -232,6 +235,10 @@ class md_reader
/* A table of enum_type structures, hashed by name. */
htab_t m_enum_types;
+
+ /* If non-zero, filter the input to just this subset of lines. */
+ int m_first_line;
+ int m_last_line;
};
/* Global singleton; constrast with rtx_reader_ptr below. */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 07c0e7a..fb3059b 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -468,23 +468,38 @@ function_reader::create_function ()
/* We start in cfgrtl mode, rather than cfglayout mode. */
rtl_register_cfg_hooks ();
- /* Create cfun. */
- tree fn_name = get_identifier (m_name ? m_name : "test_1");
- tree int_type = integer_type_node;
- tree return_type = int_type;
- tree arg_types[3] = {int_type, int_type, int_type};
- tree fn_type = build_function_type_array (return_type, 3, arg_types);
- tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
- fn_type);
- tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
- return_type);
- DECL_ARTIFICIAL (resdecl) = 1;
- DECL_IGNORED_P (resdecl) = 1;
- DECL_RESULT (fndecl) = resdecl;
- allocate_struct_function (fndecl, false);
- /* This sets cfun. */
-
- current_function_decl = fndecl;
+ /* When run from selftests or "rtl1", cfun is NULL.
+ When run from "cc1" for a C function tagged with __RTL, cfun is the
+ tagged function. */
+ if (!cfun)
+ {
+ tree fn_name = get_identifier (m_name ? m_name : "test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+ current_function_decl = fndecl;
+ }
+
+ gcc_assert (cfun);
+ gcc_assert (current_function_decl);
+ tree fndecl = current_function_decl;
+
+ /* Mark this function as being specified as __RTL. */
+ cfun->curr_properties |= PROP_rtl;
+
+ /* cc1 normally inits DECL_INITIAL (fndecl) to be error_mark_node.
+ Create a dummy block for it. */
+ DECL_INITIAL (fndecl) = make_node (BLOCK);
cfun->curr_properties = (PROP_cfg | PROP_rtl);
@@ -1580,6 +1595,40 @@ read_rtl_function_body (int argc, const char **argv,
return true;
}
+/* Run the RTL dump parser on the range of lines between START_LOC and
+ END_LOC (including those lines). */
+
+bool
+read_rtl_function_body_from_file_range (location_t start_loc,
+ location_t end_loc)
+{
+ expanded_location exploc_start = expand_location (start_loc);
+ expanded_location exploc_end = expand_location (end_loc);
+
+ if (exploc_start.file != exploc_end.file)
+ {
+ error_at (end_loc, "start/end of RTL fragment are in different files");
+ return false;
+ }
+ if (exploc_start.line >= exploc_end.line)
+ {
+ error_at (end_loc,
+ "start of RTL fragment must be on an earlier line than end");
+ return false;
+ }
+
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ function_reader reader;
+ if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
+ exploc_end.line - 1))
+ return false;
+
+ return true;
+}
+
#if CHECKING_P
namespace selftest {
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index b2a6e81..a69d3a2 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -23,4 +23,7 @@ along with GCC; see the file COPYING3. If not see
extern bool read_rtl_function_body (int argc, const char **argv,
bool (*parse_opt) (const char *));
+extern bool read_rtl_function_body_from_file_range (location_t start_loc,
+ location_t end_loc);
+
#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/run-rtl-passes.c b/gcc/run-rtl-passes.c
new file mode 100644
index 0000000..eefbad4
--- /dev/null
+++ b/gcc/run-rtl-passes.c
@@ -0,0 +1,88 @@
+/* run-rtl-passes.c - Run just one RTL pass
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "insn-attr-common.h" /* for INSN_SCHEDULING. */
+#include "insn-attr.h" /* for init_sched_attrs. */
+#include "run-rtl-passes.h"
+
+/* Run the backend passes, starting at the given pass.
+ Take ownership of INITIAL_PASS_NAME. */
+
+void
+run_rtl_passes (char *initial_pass_name)
+{
+ cfun->pass_startwith = initial_pass_name;
+ max_regno = max_reg_num ();
+
+ /* Pass "expand" normally sets this up. */
+#ifdef INSN_SCHEDULING
+ init_sched_attrs ();
+#endif
+
+ bitmap_obstack_initialize (NULL);
+ bitmap_obstack_initialize (®_obstack);
+
+ opt_pass *rest_of_compilation
+ = g->get_passes ()->get_rest_of_compilation ();
+ gcc_assert (rest_of_compilation);
+ execute_pass_list (cfun, rest_of_compilation);
+
+ opt_pass *clean_slate = g->get_passes ()->get_clean_slate ();
+ gcc_assert (clean_slate);
+ execute_pass_list (cfun, clean_slate);
+
+ bitmap_obstack_release (®_obstack);
+
+ cfun->curr_properties |= PROP_rtl;
+}
diff --git a/gcc/run-rtl-passes.h b/gcc/run-rtl-passes.h
new file mode 100644
index 0000000..aa035c5
--- /dev/null
+++ b/gcc/run-rtl-passes.h
@@ -0,0 +1,25 @@
+/* run-rtl-passes.h - Run a subset of the RTL passes
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_RUN_RTL_PASSES_H
+#define GCC_RUN_RTL_PASSES_H
+
+extern void run_rtl_passes (char *initial_pass_name);
+
+#endif /* GCC_RUN_RTL_PASSES_H */
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
new file mode 100644
index 0000000..bc39a70
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/asr_div1.c
@@ -0,0 +1,41 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-mtune=cortex-a53 -fdump-rtl-combine -O2" } */
+
+/* Taken from
+ gcc/testsuite/gcc.dg/asr_div1.c -O2 -fdump-rtl-all -mtune=cortex-a53
+ for aarch64, hand editing to the new format. */
+
+int __RTL (startwith ("combine")) f1 (int n)
+{
+(function "f1"
+ (param "n"
+ (DECL_RTL (reg/v:SI %1 [ n ]))
+ (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
+ ) ;; param "n"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 8 (set (reg:DI %2)
+ (lshiftrt:DI (reg:DI %0)
+ (const_int 32)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %0)))
+ (cinsn 9 (set (reg:SI %1)
+ (ashiftrt:SI (subreg:SI (reg:DI %2) 0)
+ (const_int 3)))
+ "../../src/gcc/testsuite/gcc.dg/asr_div1.c":14
+ (expr_list:REG_DEAD (reg:DI %2)))
+
+ ;; Extra insn, to avoid all of the above from being deleted by DCE
+ (insn 10 (use (reg/i:SI %1)))
+
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
+}
+
+/* Verify that insns 8 and 9 get combined into a shift of 35 (0x23) */
+/* { dg-final { scan-rtl-dump "allowing combination of insns 8 and 9" "combine" } } */
+/* { dg-final { scan-rtl-dump "modifying insn i3 9: r\[0-9\]+:SI#0=r\[0-9\]+:DI>>0x23" "combine" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
new file mode 100644
index 0000000..91ae937
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/aarch64/pr71779.c
@@ -0,0 +1,50 @@
+/* { dg-do compile { target aarch64-*-* } } */
+/* { dg-options "-fdump-rtl-cse1" } */
+
+/* Dump taken from comment 2 of PR 71779, of
+ "...the relevant memory access coming out of expand"
+ hand-edited to the compact dump format. */
+
+int __RTL (startwith ("cse1")) test (int n)
+{
+(function "fragment"
+ (param "n"
+ (DECL_RTL (reg/v:SI %1 [ n ]))
+ (DECL_RTL_INCOMING (reg:SI x0 [ n ]))
+ ) ;; param "n"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+
+;; MEM[(struct isl_obj *)&obj1] = &isl_obj_map_vtable;
+(insn 1045 (set (reg:SI %480)
+ (high:SI (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ y.c:12702)
+(insn 1046 (set (reg/f:SI %479)
+ (lo_sum:SI (reg:SI %480)
+ (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+ y.c:12702
+ (expr_list:REG_EQUAL (symbol_ref:SI ("isl_obj_map_vtable")
+ [flags 0xc0]
+ <var_decl 0x7fa0363ea240 isl_obj_map_vtable>)))
+(insn 1047 (set (reg:DI %481)
+ (subreg:DI (reg/f:SI %479) 0)) y.c:12702)
+(insn 1048 (set (zero_extract:DI (reg/v:DI %191 [ obj1D.17368 ])
+ (const_int 32)
+ (const_int 0))
+ (reg:DI %481)) y.c:12702)
+;; Extra insn, to avoid all of the above from being deleted by DCE
+(insn 1049 (set (mem:DI (reg:DI %191) [1 i+0 S4 A32])
+ (const_int 1)))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+) ;; function
+}
+
+/* TODO: scan the dump. */
diff --git a/gcc/testsuite/gcc.dg/rtl/rtl.exp b/gcc/testsuite/gcc.dg/rtl/rtl.exp
new file mode 100644
index 0000000..3c6648b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/rtl.exp
@@ -0,0 +1,41 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+ set DEFAULT_RTLFLAGS ""
+ # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.c]]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/rtl/test.c b/gcc/testsuite/gcc.dg/rtl/test.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/test.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+}
+
+/* Example showing:
+ - data structure
+ - loop
+ - call to "abort". */
+
+struct foo
+{
+ int count;
+ float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+ float result = 0.0f;
+
+ if (lhs->count != rhs->count)
+ __builtin_abort ();
+
+ for (int i = 0; i < lhs->count; i++)
+ result += lhs->data[i] * rhs->data[i];
+
+ return result;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c b/gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c
new file mode 100644
index 0000000..4dd8214
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/truncated-rtl-file.c
@@ -0,0 +1,2 @@
+void __RTL test (void)
+{ /* { dg-error "no closing brace" } */
diff --git a/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
new file mode 100644
index 0000000..dd252f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/unknown-rtx-code.c
@@ -0,0 +1,8 @@
+void __RTL test (void)
+{
+ (function "test"
+ (insn-chain
+ (not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
+ ) ;; insn-chain
+ ) ;; function
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
new file mode 100644
index 0000000..8701c1d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/dfinit.c
@@ -0,0 +1,116 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+#include "test_1.h"
+
+/* Lightly-modified dump of test.c.261r.split1 for x86_64. */
+
+int __RTL (startwith ("no-opt dfinit")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that the dataflow information matches what cc1 would normally
+ have generated. In particular, in earlier versions of the RTL
+ frontend, the exit block use of reg 0 (ax) wasn't picked up
+ on, due to not setting up crtl->return_rtx based on
+ DECL_RESULT (fndecl). */
+/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
new file mode 100644
index 0000000..8db1161
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c
@@ -0,0 +1,81 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+extern double sqrt(double x);
+
+struct foo
+{
+ double x;
+ double y;
+};
+
+struct bar
+{
+ double x;
+ double y;
+};
+
+double __RTL test (struct foo *f, const struct bar *b)
+{
+#if 0
+ /* Result of "expand" on this C code, compiled for x86_64 with -Os. */
+ f->x += b->x;
+ f->y += b->y;
+ return sqrt (f->x * f->x + f->y * f->y);
+#endif
+(function "test"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 5 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (reg/v/f:DI %10 [ f ])
+ (reg:DI di [ f ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
+ (cinsn 3 (set (reg/v/f:DI %11 [ b ])
+ (reg:DI si [ b ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":18)
+ (cnote 4 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 7 (set (reg:DF %12)
+ (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 8 (set (reg:DF %2 [ _3 ])
+ (plus:DF (reg:DF %12)
+ (mem:DF (reg/v/f:DI %11 [ b ]) [2 b_12(D)->x+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 9 (set (mem:DF (reg/v/f:DI %10 [ f ]) [2 f_11(D)->x+0 S8 A64])
+ (reg:DF %2 [ _3 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":21)
+ (cinsn 10 (set (reg:DF %13)
+ (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
+ (const_int 8)) [2 f_11(D)->y+0 S8 A64])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 11 (set (reg:DF %5 [ _6 ])
+ (plus:DF (reg:DF %13)
+ (mem:DF (plus:DI (reg/v/f:DI %11 [ b ])
+ (const_int 8)) [2 b_12(D)->y+0 S8 A64]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 12 (set (mem:DF (plus:DI (reg/v/f:DI %10 [ f ])
+ (const_int 8)) [2 f_11(D)->y+0 S8 A64])
+ (reg:DF %5 [ _6 ])) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":22)
+ (cinsn 13 (set (reg:DF %14)
+ (mult:DF (reg:DF %2 [ _3 ])
+ (reg:DF %2 [ _3 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 14 (set (reg:DF %15)
+ (mult:DF (reg:DF %5 [ _6 ])
+ (reg:DF %5 [ _6 ]))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 15 (set (reg:DF %16)
+ (plus:DF (reg:DF %14)
+ (reg:DF %15))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (cinsn 16 (set (reg:DF xmm0)
+ (reg:DF %16)) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23)
+ (ccall_insn/j 17 (set (reg:DF xmm0)
+ (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>) [0 __builtin_sqrt S1 A8])
+ (const_int 0))) "../../src/gcc/testsuite/gcc.dg/rtl/x86_64/different-structs.c":23
+ (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41] <function_decl 0x7fa24e331d00 sqrt>)
+ (expr_list:REG_EH_REGION (const_int 0)))
+ (expr_list:DF (use (reg:DF xmm0))))
+ (edge-to exit (flags "ABNORMAL | SIBCALL"))
+ ) ;; block 2
+ (cbarrier 18)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:DF xmm0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test"
+
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/final.c b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
new file mode 100644
index 0000000..1b8ea09
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/final.c
@@ -0,0 +1,133 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.304r.dwarf2 for x86_64 target,
+ with various NOTE_INSN_CFI deleted by hand for now. */
+
+int __RTL (startwith ("final")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn/f 32 (set (mem:DI (pre_dec:DI (reg/f:DI sp)) [0 S8 A8])
+ (reg/f:DI bp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn/f 33 (set (reg/f:DI bp)
+ (reg/f:DI sp)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 34 (set (mem/v:BLK (0|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 0) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 35 NOTE_INSN_PROLOGUE_END)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI ax [90])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (plus:SI (reg:SI ax [90])
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI ax [91])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (neg:SI (reg:SI ax [91])))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cnote 36 NOTE_INSN_EPILOGUE_BEG)
+ (cinsn 37 (set (mem/v:BLK (1|scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (reuse_rtx 1) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn/f 38 (set (reg/f:DI bp)
+ (mem:DI (post_inc:DI (reg/f:DI sp)) [0 S8 A8])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7
+ (expr_list:REG_CFA_DEF_CFA (plus:DI (reg/f:DI sp)
+ (const_int 8))))
+ (cjump_insn 39 (simple_return) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit)
+ ) ;; block 5
+ (cbarrier 40)
+ (cnote 31 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that asm was emitted. */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+ FIXME: this assumes i386.md. */
+/* { dg-final { scan-assembler "ret" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
new file mode 100644
index 0000000..ab92004
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/into-cfglayout.c
@@ -0,0 +1,117 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-into_cfglayout" } */
+
+/* Lightly-modified dump of test.c.226r.vregs for x86_64. */
+
+#include "test_1.h"
+
+int __RTL (startwith ("into_cfglayout")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* The conversion to cfglayout should eliminate unconditional jump
+ instructions... */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "barrier" "into_cfglayout" } } */
+
+/* ...but conditional jumps should be preserved. */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
new file mode 100644
index 0000000..d23cca4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/ira.c
@@ -0,0 +1,111 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.265r.asmcons for x86_64. */
+
+#include "test_1.h"
+
+int __RTL (startwith ("ira")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that IRA was run. */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
new file mode 100644
index 0000000..4ba3d6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/pro_and_epilogue.c
@@ -0,0 +1,110 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.274r.split2 for x86_64. */
+
+int __RTL (startwith ("pro_and_epilogue")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI ax [89])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 3 (flags "FALLTHRU"))
+ (edge-to 4)
+ ) ;; block 2
+ (block 3
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 3] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI ax [90])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (plus:SI (reg:SI ax [90])
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 29 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 5)
+ ) ;; block 3
+ (cbarrier 30)
+ (block 4
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI ax [91])
+ (mem/c:SI (plus:DI (reg/f:DI bp)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI ax [orig:87 _1 ] [87])
+ (neg:SI (reg:SI ax [91])))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 5 (flags "FALLTHRU"))
+ ) ;; block 4
+ (block 5
+ (edge-from 4 (flags "FALLTHRU"))
+ (edge-from 3)
+ (clabel 20 3)
+ (cnote 21 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 5
+ (cnote 31 NOTE_INSN_DELETED)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* Verify that the prologue and epilogue were added. */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } } */
+
+/* We expect a jump_insn to "simple_return". */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } } */
+
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c
new file mode 100644
index 0000000..ac0ebe4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-multiple-fns.c
@@ -0,0 +1,105 @@
+/* { dg-do run { target x86_64-*-* } } */
+
+/* Verify that we can have multiple __RTL functions in one test case.
+ Each of these __RTL functions returns a const, dumped immediately after
+ expand. */
+
+extern void abort (void);
+
+int __RTL (startwith ("vregs")) test_return_42 (void)
+{
+ /* C code:
+ return 42; */
+(function "test_return_42"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_return_42"
+}
+
+int __RTL (startwith ("vregs")) test_return_43 (void)
+{
+ /* C code:
+ return 43; */
+(function "test_return_43"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 43)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_return_43"
+}
+
+int __RTL (startwith ("vregs")) test_return_44 (void)
+{
+ /* C code:
+ return 44; */
+(function "test_return_44"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 44)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_return_44"
+}
+
+int main (void)
+{
+ if (test_return_42 () != 42)
+ abort ();
+ if (test_return_43 () != 43)
+ abort ();
+ if (test_return_44 () != 44)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
new file mode 100644
index 0000000..8753809
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.after-expand.c
@@ -0,0 +1,39 @@
+/* { dg-do run { target x86_64-*-* } } */
+
+extern void abort (void);
+
+int __RTL (startwith ("vregs")) test_returning_constant (void)
+{
+ /* C code:
+ return 42; */
+(function "test_returning_constant"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ _1 ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 8 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])) "../../src/test-return-const.c":3)
+ (cinsn 12 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/test-return-const.c":4)
+ (cinsn 13 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_returning_constant"
+}
+
+int main (void)
+{
+ if (test_returning_constant () != 42)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
new file mode 100644
index 0000000..603caa3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-return-const.c.before-fwprop.c
@@ -0,0 +1,42 @@
+/* { dg-do run { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-fwprop1 -O2" } */
+
+extern void abort (void);
+
+int __RTL (startwith ("fwprop1")) test_returning_constant (void)
+{
+ /* C code:
+ return 42; */
+(function "test_returning_constant"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 5 (set (reg:SI %0 [ <retval> ])
+ (const_int 42)) "../../src/test-return-const.c":3)
+ (cinsn 9 (set (reg/i:SI ax)
+ (const_int 42)) "../../src/test-return-const.c":4
+ (expr_list:REG_DEAD (reg:SI %0 [ <retval> ])))
+ (cinsn 10 (use (reg/i:SI ax)) "../../src/test-return-const.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_returning_constant"
+}
+
+/* Verify that insn 5 is eliminated. */
+/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
+/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
+
+int main (void)
+{
+ if (test_returning_constant () != 42)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
new file mode 100644
index 0000000..b4d1e6d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test-rtl.c
@@ -0,0 +1,101 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+ This is a dump of test.c from immediately after "expand", for x86_64. */
+
+int __RTL test_1 (int i, int j, int k)
+{
+ /*
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+ */
+(function "test_1"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
new file mode 100644
index 0000000..a783ea8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/test_1.h
@@ -0,0 +1,16 @@
+/* Shared test code for the various __RTL tests of test_1 that
+ start at different passes. */
+
+extern void abort (void);
+extern int test_1 (int i, int j, int k);
+
+int main (void)
+{
+ if (test_1 (0, 0, 3) != -3)
+ abort ();
+
+ if (test_1 (0, 1, 3) != 7)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
new file mode 100644
index 0000000..f6eb1c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.after-expand.c
@@ -0,0 +1,70 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+
+extern void abort (void);
+
+int __RTL (startwith ("vregs")) times_two (int i)
+{
+ /* C function:
+ return i * 2; */
+(function "times_two"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ]))
+ ) ;; param "i"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2
+ (nil))
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))
+ (nil)))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3
+ (nil))
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4
+ (nil))
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4
+ (nil))
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
+}
+
+int main (void)
+{
+ if (times_two (0) != 0)
+ abort ();
+
+ if (times_two (1) != 2)
+ abort ();
+
+ if (times_two (100) != 200)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
new file mode 100644
index 0000000..1321eaf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/times-two.c.before-df.c
@@ -0,0 +1,54 @@
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+int __RTL (startwith ("rtl-dfinit")) times_two (int i)
+{
+ /* C function:
+ return i * 2; */
+(function "times_two"
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 4 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/times-two.c":2)
+ (cnote 3 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 6 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/times-two.c":3)
+ (cinsn 7 (parallel [
+ (set (reg:SI %0 [ _2 ])
+ (ashift:SI (reg:SI %2)
+ (const_int 1)))
+ (clobber (reg:CC flags))
+ ]) "../../src/times-two.c":3
+ (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32])
+ (const_int 1))))
+ (cinsn 10 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _2 ])) "../../src/times-two.c":3)
+ (cinsn 14 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/times-two.c":4)
+ (cinsn 15 (use (reg/i:SI ax)) "../../src/times-two.c":4)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 2
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "times_two"
+}
+
+/* Verify that the dataflow information matches what cc1 would have
+ generated. In particular, in earlier versions of the RTL
+ frontend, the exit block use of reg 0 (ax) wasn't picked up
+ on, due to not setting up crtl->return_rtx based on
+ DECL_RESULT (fndecl). */
+
+/* { dg-final { scan-rtl-dump ";; exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+
+/* { dg-final { scan-rtl-dump ";; regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
diff --git a/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
new file mode 100644
index 0000000..50d90dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/rtl/x86_64/vregs.c
@@ -0,0 +1,112 @@
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-vregs" } */
+
+/* Lightly-modified dump of test.c.225r.expand for x86_64. */
+
+#include "test_1.h"
+
+int __RTL (startwith ("vregs")) test_1 (int i, int j, int k)
+{
+(function "test_1"
+ (param "i"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -4)) [1 i+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI di [ i ])))
+ (param "j"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -8)) [1 j+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI si [ j ])))
+ (param "k"
+ (DECL_RTL (mem/c:SI (plus:DI (reg/f:DI frame)
+ (const_int -12)) [1 k+0 S4 A32]))
+ (DECL_RTL_INCOMING (reg:SI dx [ k ])))
+ (insn-chain
+ (cnote 1 NOTE_INSN_DELETED)
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 6 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 2 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])
+ (reg:SI di [ i ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 3 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32])
+ (reg:SI si [ j ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cinsn 4 (set (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (reg:SI dx [ k ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":2)
+ (cnote 5 NOTE_INSN_FUNCTION_BEG)
+ (cinsn 8 (set (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -4)) [1 i+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cinsn 9 (set (reg:CCGC flags)
+ (compare:CCGC (reg:SI %2)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -8)) [1 j+0 S4 A32]))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (cjump_insn 10 (set (pc)
+ (if_then_else (ge (reg:CCGC flags)
+ (const_int 0))
+ (label_ref 16)
+ (pc))) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":3)
+ (edge-to 4 (flags "FALLTHRU"))
+ (edge-to 5)
+ ) ;; block 2
+ (block 4
+ (edge-from 2 (flags "FALLTHRU"))
+ (cnote 11 [bb 4] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 12 (set (reg:SI %3)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (cinsn 13 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (plus:SI (reg:SI %3)
+ (const_int 4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4
+ (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])
+ (const_int 4))))
+ (cjump_insn 14 (set (pc)
+ (label_ref 20)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":4)
+ (edge-to 6)
+ ) ;; block 4
+ (cbarrier 15)
+ (block 5
+ (edge-from 2)
+ (clabel 16 2)
+ (cnote 17 [bb 5] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 18 (set (reg:SI %4)
+ (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6)
+ (cinsn 19 (parallel [
+ (set (reg:SI %0 [ _1 ])
+ (neg:SI (reg:SI %4)))
+ (clobber (reg:CC flags))
+ ]) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":6
+ (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI virtual-stack-vars)
+ (const_int -12)) [1 k+0 S4 A32]))))
+ (edge-to 6 (flags "FALLTHRU"))
+ ) ;; block 5
+ (block 6
+ (edge-from 4)
+ (edge-from 5 (flags "FALLTHRU"))
+ (clabel 20 3)
+ (cnote 21 [bb 6] NOTE_INSN_BASIC_BLOCK)
+ (cinsn 22 (set (reg:SI %1 [ <retval> ])
+ (reg:SI %0 [ _1 ])))
+ (cinsn 26 (set (reg/i:SI ax)
+ (reg:SI %1 [ <retval> ])) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (cinsn 27 (use (reg/i:SI ax)) "../../src/gcc/testsuite/gcc.dg/rtl/test.c":7)
+ (edge-to exit (flags "FALLTHRU"))
+ ) ;; block 6
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:SI ax)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_1"
+}
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame". */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } } */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } } */
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8a/9] Introduce class function_reader (v6)
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
` (3 preceding siblings ...)
2016-12-02 1:28 ` [PATCH 9/9] Add "__RTL" to cc1 (v6) David Malcolm
@ 2016-12-02 14:41 ` Bernd Schmidt
2016-12-02 18:12 ` [PATCH 8a/9] Introduce class function_reader (v7) David Malcolm
4 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-02 14:41 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/02/2016 03:00 AM, David Malcolm wrote:
> Changed in v6:
> - split out dump-reading selftests into followup patches
> (target-independent, and target-specific)
> - removes unneeded headers from read-rtl-function.c
> - numerous other cleanups identified in review
Ok, starting to look very close to done.
It appears I accidentally made you change element->directive. It seems
like a good change but all I wanted to point out was a plural where I
would have expected a singular.
>
> + /* Lookup param by name. */
> + tree t_param = parse_mem_expr (name);
> + // TODO: what if not found?
Error out?
> +/* Implementation of rtx_reader::handle_unknown_directive.
> +
> + Require a top-level "function" directive, as emitted by
> + print_rtx_function, and parse it. */
Should document START_LOC and NAME.
> + /* Do we need this to force cgraphunit.c to output the function? */
Well, what happens if you don't do this? Seems reasonable anyway, so
maybe lose the comment.
> +/* Parse rtx instructions by calling read_rtx_code, calling
> + set_first_insn and set_last_insn as appropriate, and
> + adding the insn to the insn chain.
> + Consume the trailing ')'. */
> +
> +rtx_insn *
> +function_reader::parse_insn (file_location start_loc, const char *name)
Once again, please document args - make another pass over all the
functions to make sure.
> +
> +/* Parse operand IDX of X, of code 'i' or 'n'.
"... as specified by FORMAT_CHAR", presumably.
> + if (0 == strncmp (desc, "orig:", 5))
> + {
> + expect_original_regno = true;
> + desc_start += 5;
> + /* Skip to any whitespace following the integer. */
> + const char *space = strchr (desc_start, ' ');
> + if (space)
> + desc_start = space + 1;
> + }
> + /* Any remaining text may be the REG_EXPR. Alternatively we have
> + no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
> + if (ISDIGIT (*desc_start))
> + {
> + /* Assume we have ORIGINAL_REGNO. */
> + ORIGINAL_REGNO (x) = atoi (desc_start);
> + }
This looks like an issue. You'll want to have ORIGINAL_REGNOs printed
and parsed like other regnos, i.e. with %number for pseudos. Can be done
as a followup if it's involved.
> + /* Verify lookup of hard registers. */
> +#ifdef GCC_AARCH64_H
> + ASSERT_EQ (0, lookup_reg_by_dump_name ("x0"));
> + ASSERT_EQ (1, lookup_reg_by_dump_name ("x1"));
> +#endif
> +#ifdef I386_OPTS_H
> + ASSERT_EQ (0, lookup_reg_by_dump_name ("ax"));
> + ASSERT_EQ (1, lookup_reg_by_dump_name ("dx"));
> +#endif
Please just remove this for now; not important enough to break the rule
about target-specific bits in generic code.
> @@ -1103,13 +1244,39 @@ rtx_reader::read_rtx_code (const char *code_name)
> rtx value; /* Value of this node. */
> };
>
> + one_time_initialization ();
I still don't understand why this isn't in the rtx_reader constructor?
Seems pointless to call this each time we want to parse an rtx.
> +
> + /* Use the format_ptr to parse the various operands of this rtx.
> + read_rtx_operand is a vfunc, allowing the parser to vary between
> + parsing .md files and parsing .rtl dumps; the function_reader subclass
> + overrides the defaults when loading RTL dumps, to handle the
> + various extra attributes emitted by print_rtx. */
> for (int idx = 0; format_ptr[idx] != 0; idx++)
> - read_rtx_operand (return_rtx, idx);
> + return_rtx = read_rtx_operand (return_rtx, idx);
> +
> + /* Call a vfunc to handle the various additional information that
> + print-rtl.c can write after the regular fields; does nothing when
> + parsing .md files. */
> + handle_any_trailing_information (return_rtx);
I still think just drop the bulk of these comments. Virtual functions
aren't that arcane.
> + /* "stringbuf" was allocated within string_obstack and thus has
> + the its lifetime restricted to that of the rtx_reader. This is
> + OK for the generator programs, but for non-generator programs,
> + XSTR and XTMPL fields are meant to be allocated in the GC-managed
> + heap. Hence we need to allocate a copy in the GC-managed heap
> + for the non-generator case. */
> + const char *string_ptr = finalize_string (stringbuf);
Put the comment near the implementation that makes the copy (and maybe
one explaining why the no-op in the other implementation), not here.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8a/9] Introduce class function_reader (v7)
2016-12-02 14:41 ` [PATCH 8a/9] Introduce class function_reader (v6) Bernd Schmidt
@ 2016-12-02 18:12 ` David Malcolm
2016-12-02 18:58 ` Bernd Schmidt
2016-12-08 20:06 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b David Malcolm
0 siblings, 2 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-02 18:12 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
On Fri, 2016-12-02 at 15:41 +0100, Bernd Schmidt wrote:
> On 12/02/2016 03:00 AM, David Malcolm wrote:
> > Changed in v6:
> > - split out dump-reading selftests into followup patches
> > (target-independent, and target-specific)
> > - removes unneeded headers from read-rtl-function.c
> > - numerous other cleanups identified in review
>
> Ok, starting to look very close to done.
Thanks for the reviews so far.
> It appears I accidentally made you change element->directive. It
> seems
> like a good change but all I wanted to point out was a plural where I
> would have expected a singular.
(nods)
> >
> > + /* Lookup param by name. */
> > + tree t_param = parse_mem_expr (name);
> > + // TODO: what if not found?
>
> Error out?
Currently, function_reader::parse_mem_expr can't fail; it creates a
VAR_DECL for anything it doesn't recognize.
But here, we should be looking specifically for a PARAM_DECL.
I've moved the find-param-by-name code out from
function_reader::parse_mem_expr into a new function, and call that
instead, and error out if it isn't found from that.
> > +/* Implementation of rtx_reader::handle_unknown_directive.
> > +
> > + Require a top-level "function" directive, as emitted by
> > + print_rtx_function, and parse it. */
>
> Should document START_LOC and NAME.
Done.
> > + /* Do we need this to force cgraphunit.c to output the function?
> > */
>
> Well, what happens if you don't do this? Seems reasonable anyway, so
> maybe lose the comment.
The two flag assignments don't seem to be needed; I think this is due
to adding:
if (node->native_rtl_p ())
node->force_output = 1;
to cgraph_node::finalize_function in patch 9.
Should I lose them (and the comment)?
> > +/* Parse rtx instructions by calling read_rtx_code, calling
> > + set_first_insn and set_last_insn as appropriate, and
> > + adding the insn to the insn chain.
> > + Consume the trailing ')'. */
> > +
> > +rtx_insn *
> > +function_reader::parse_insn (file_location start_loc, const char
> > *name)
>
> Once again, please document args - make another pass over all the
> functions to make sure.
Done. In doing so, I noticed that the args to read_rtl_function_body
were unnecessarily complicated, so I simplified it to just take a path.
I also made some simplifications to the various fixup_source_location
functions.
> > +
> > +/* Parse operand IDX of X, of code 'i' or 'n'.
>
> "... as specified by FORMAT_CHAR", presumably.
Done.
> > + if (0 == strncmp (desc, "orig:", 5))
> > + {
> > + expect_original_regno = true;
> > + desc_start += 5;
> > + /* Skip to any whitespace following the integer. */
> > + const char *space = strchr (desc_start, ' ');
> > + if (space)
> > + desc_start = space + 1;
> > + }
> > + /* Any remaining text may be the REG_EXPR. Alternatively we
> > have
> > + no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
> > + if (ISDIGIT (*desc_start))
> > + {
> > + /* Assume we have ORIGINAL_REGNO. */
> > + ORIGINAL_REGNO (x) = atoi (desc_start);
> > + }
>
> This looks like an issue. You'll want to have ORIGINAL_REGNOs printed
> and parsed like other regnos, i.e. with %number for pseudos. Can be
> done
> as a followup if it's involved.
This is involved; let's do this as a followup.
> > + /* Verify lookup of hard registers. */
> > +#ifdef GCC_AARCH64_H
> > + ASSERT_EQ (0, lookup_reg_by_dump_name ("x0"));
> > + ASSERT_EQ (1, lookup_reg_by_dump_name ("x1"));
> > +#endif
> > +#ifdef I386_OPTS_H
> > + ASSERT_EQ (0, lookup_reg_by_dump_name ("ax"));
> > + ASSERT_EQ (1, lookup_reg_by_dump_name ("dx"));
> > +#endif
>
> Please just remove this for now; not important enough to break the
> rule
> about target-specific bits in generic code.
Removed for now.
> > @@ -1103,13 +1244,39 @@ rtx_reader::read_rtx_code (const char
> > *code_name)
> > rtx value; /* Value of this node. */
> > };
> >
> > + one_time_initialization ();
>
> I still don't understand why this isn't in the rtx_reader
> constructor?
> Seems pointless to call this each time we want to parse an rtx.
Aha; that makes much more sense.
Done.
> > +
> > + /* Use the format_ptr to parse the various operands of this rtx.
> > + read_rtx_operand is a vfunc, allowing the parser to vary
> > between
> > + parsing .md files and parsing .rtl dumps; the function_reader
> > subclass
> > + overrides the defaults when loading RTL dumps, to handle the
> > + various extra attributes emitted by print_rtx. */
> > for (int idx = 0; format_ptr[idx] != 0; idx++)
> > - read_rtx_operand (return_rtx, idx);
> > + return_rtx = read_rtx_operand (return_rtx, idx);
> > +
> > + /* Call a vfunc to handle the various additional information
> > that
> > + print-rtl.c can write after the regular fields; does nothing
> > when
> > + parsing .md files. */
> > + handle_any_trailing_information (return_rtx);
>
> I still think just drop the bulk of these comments. Virtual functions
> aren't that arcane.
I've removed the references to vfuncs.
> > + /* "stringbuf" was allocated within string_obstack and
> > thus has
> > + the its lifetime restricted to that of the rtx_reader.
> > This is
> > + OK for the generator programs, but for non-generator
> > programs,
> > + XSTR and XTMPL fields are meant to be allocated in the
> > GC-managed
> > + heap. Hence we need to allocate a copy in the GC
> > -managed heap
> > + for the non-generator case. */
> > + const char *string_ptr = finalize_string (stringbuf);
>
> Put the comment near the implementation that makes the copy (and
> maybe
> one explaining why the no-op in the other implementation), not here.
Done.
> Bernd
Changed in v7:
- added documentation for all arguments
- removed redundant operand_idx from *fixup_source_location; strengthened param
from rtx to rtx_insn *.
- simplified arguments to read_rtl_function_body
- added find_param_by_name
- rewrote filename parsing to use read_quoted_string, rather than the
strange hack I had previously
- remove selftest of hard reg
- move one_time_initialization on rtx_reader ctor
Changed in v6:
- split out dump-reading selftests into followup patches
(target-independent, and target-specific)
- removes unneeded headers from read-rtl-function.c
- numerous other cleanups identified in review
Changed in v5:
- updated for change to emit_status::ensure_regno_capacity
Changed in v4:
- error-handling changes split out into a separate patch
- rewritten the loader to use the new "compact" dump format
- support for reuse_rtx in loader
- handling of params, DECL_RTL and DECL_RTL_INCOMING
- moved target-dependent selftests to target-specific code
(aarch64.c and i386.c)
Link to earlier version of the patch:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00267.html
gcc/ChangeLog:
* Makefile.in (OBJS): Add read-md.o, read-rtl.o,
read-rtl-function.o, and selftest-rtl.o.
* emit-rtl.c (maybe_set_max_label_num): New function.
* emit-rtl.h (maybe_set_max_label_num): New decl.
* function.c (instantiate_decls): Guard call to
instantiate_decls_1 with if (DECL_INITIAL (fndecl)).
* gensupport.c (gen_reader::gen_reader): Pass "false"
for new "compact" param of rtx_reader.
* print-rtl.c (rtx_writer::print_rtx_operand): Print "(nil)"
rather than an empty string for NULL strings.
* read-md.c: Potentially include config.h rather than bconfig.h.
(md_reader::read_name): Rename to...
(md_reader::read_name_1): ...this, adding "out_loc" param,
and converting "missing name or number" to returning false, rather
than failing.
(md_reader::read_name): Reimplement in terms of read_name_1.
(md_reader::read_name_or_nil): New function.
(md_reader::read_string): Handle "(nil)" by returning NULL.
(md_reader::md_reader): Add new param "compact".
* read-md.h (md_reader::md_reader): Add new param "compact".
(md_reader::is_compact): New accessor.
(md_reader::read_name): Convert return type from void to
file_location.
(md_reader::read_name_or_nil): New decl.
(md_reader::read_name_1): New decl.
(md_reader::m_compact): New field.
(noop_reader::noop_reader): Pass "false" for new "compact" param
of rtx_reader.
(rtx_reader::rtx_reader): Add new "compact" param.
(rtx_reader::read_rtx_operand): Make virtual and convert return
type from void to rtx.
(rtx_reader::read_until): New decl.
(rtx_reader::handle_any_trailing_information): New virtual
function.
(rtx_reader::postprocess): New virtual function.
(rtx_reader::finalize_string): New virtual function.
(rtx_reader::m_in_call_function_usage): New field.
(rtx_reader::m_reuse_rtx_by_id): New field.
* read-rtl-function.c: New file.
* read-rtl-function.h: New file.
* read-rtl.c: Potentially include config.h rather than bconfig.h.
For host, include function.h, memmodel.h, and emit-rtl.h.
(one_time_initialization): New function.
(struct compact_insn_name): New struct.
(compact_insn_names): New array.
(find_code): Handle insn codes in compact dumps.
(apply_subst_iterator): Wrap with #ifdef GENERATOR_FILE.
(bind_subst_iter_and_attr): Likewise.
(add_condition_to_string): Likewise.
(add_condition_to_rtx): Likewise.
(apply_attribute_uses): Likewise.
(add_current_iterators): Likewise.
(apply_iterators): Likewise.
(initialize_iterators): Guard usage of apply_subst_iterator with
#ifdef GENERATOR_FILE.
(read_conditions): Wrap with #ifdef GENERATOR_FILE.
(md_reader::read_mapping): Likewise.
(add_define_attr_for_define_subst): Likewise.
(add_define_subst_attr): Likewise.
(read_subst_mapping): Likewise.
(check_code_iterator): Likewise.
(rtx_reader::read_rtx): Likewise. Move one-time initialization
logic to...
(one_time_initialization): New function.
(rtx_reader::read_until): New method.
(read_flags): New function.
(parse_reg_note_name): New function.
(rtx_reader::read_rtx_code): Initialize "iterator" to NULL.
Handle reuse_rtx ids.
Wrap iterator lookup within #ifdef GENERATOR_FILE.
Add parsing support for RTL dumps, mirroring the special-cases in
print_rtx, by calling read_flags, reading REG_NOTE names, INSN_UID
values, and calling handle_any_trailing_information.
(rtx_reader::read_rtx_operand): Convert return type from void
to rtx, returning return_rtx. Handle case 'e'. Call
finalize_string on XSTR and XTMPL fields.
(rtx_reader::read_nested_rtx): Handle dumps in which trailing
"(nil)" values were omitted. Call the postprocess vfunc on the
return_rtx.
(rtx_reader::rtx_reader): Add new "compact" param and pass to base
class ctor. Initialize m_in_call_function_usage. Call
one_time_initialization.
* rtl-tests.c (selftest::test_uncond_jump): Call
set_new_first_and_last_insn.
* rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE.
* selftest-rtl.c: New file.
* selftest-rtl.h (class selftest::rtl_dump_test): New class.
(selftest::get_insn_by_uid): New decl.
* selftest-run-tests.c (selftest::run_tests): Call
read_rtl_function_c_tests.
* selftest.h (selftest::read_rtl_function_c_tests): New decl.
* tree-dfa.c (ssa_default_def): Return NULL_TREE for rtl function
dumps.
---
gcc/Makefile.in | 4 +
gcc/emit-rtl.c | 13 +
gcc/emit-rtl.h | 2 +
gcc/function.c | 3 +-
gcc/gensupport.c | 2 +-
gcc/print-rtl.c | 2 +-
gcc/read-md.c | 59 +-
gcc/read-md.h | 34 +-
gcc/read-rtl-function.c | 1653 ++++++++++++++++++++++++++++++++++++++++++++++
gcc/read-rtl-function.h | 25 +
gcc/read-rtl.c | 260 +++++++-
gcc/rtl-tests.c | 1 +
gcc/rtl.h | 2 +
gcc/selftest-rtl.c | 77 +++
gcc/selftest-rtl.h | 17 +
gcc/selftest-run-tests.c | 1 +
gcc/selftest.h | 1 +
gcc/tree-dfa.c | 5 +
18 files changed, 2130 insertions(+), 31 deletions(-)
create mode 100644 gcc/read-rtl-function.c
create mode 100644 gcc/read-rtl-function.h
create mode 100644 gcc/selftest-rtl.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c265893..73d12dc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1407,6 +1407,9 @@ OBJS = \
print-rtl-function.o \
print-tree.o \
profile.o \
+ read-md.o \
+ read-rtl.o \
+ read-rtl-function.o \
real.o \
realmpfr.o \
recog.o \
@@ -1434,6 +1437,7 @@ OBJS = \
sel-sched-ir.o \
sel-sched-dump.o \
sel-sched.o \
+ selftest-rtl.o \
selftest-run-tests.o \
sese.o \
shrink-wrap.o \
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index b2b5fde..6d64ad6 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1374,6 +1374,19 @@ maybe_set_first_label_num (rtx_code_label *x)
if (CODE_LABEL_NUMBER (x) < first_label_num)
first_label_num = CODE_LABEL_NUMBER (x);
}
+
+/* For use by the RTL function loader, when mingling with normal
+ functions.
+ Ensure that label_num is greater than the label num of X, to avoid
+ duplicate labels in the generated assembler. */
+
+void
+maybe_set_max_label_num (rtx_code_label *x)
+{
+ if (CODE_LABEL_NUMBER (x) >= label_num)
+ label_num = CODE_LABEL_NUMBER (x) + 1;
+}
+
\f
/* Return a value representing some low-order bits of X, where the number
of low-order bits is given by MODE. Note that no conversion is done
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 21c180b..01f16a7 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -507,4 +507,6 @@ extern int get_mem_align_offset (rtx, unsigned int);
MODE and adjusted by OFFSET. */
extern rtx widen_memory_access (rtx, machine_mode, HOST_WIDE_INT);
+extern void maybe_set_max_label_num (rtx_code_label *x);
+
#endif /* GCC_EMIT_RTL_H */
diff --git a/gcc/function.c b/gcc/function.c
index 0b1d168..2674321 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -1901,7 +1901,8 @@ instantiate_decls (tree fndecl)
instantiate_decl_rtl (DECL_RTL (DECL_VALUE_EXPR (decl)));
/* Now process all variables defined in the function or its subblocks. */
- instantiate_decls_1 (DECL_INITIAL (fndecl));
+ if (DECL_INITIAL (fndecl))
+ instantiate_decls_1 (DECL_INITIAL (fndecl));
FOR_EACH_LOCAL_DECL (cfun, ix, decl)
if (DECL_RTL_SET_P (decl))
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index c49ad6f..64378e3 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2233,7 +2233,7 @@ process_define_subst (void)
class gen_reader : public rtx_reader
{
public:
- gen_reader () : rtx_reader () {}
+ gen_reader () : rtx_reader (false) {}
void handle_unknown_directive (file_location, const char *);
};
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 3bbd395..77e6b05 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -577,7 +577,7 @@ rtx_writer::print_rtx_operand (const_rtx in_rtx, int idx)
string:
if (str == 0)
- fputs (" \"\"", m_outfile);
+ fputs (" (nil)", m_outfile);
else
fprintf (m_outfile, " (\"%s\")", str);
m_sawclose = 1;
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 6d9a1bd..a8462a6 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
#include "system.h"
#include "coretypes.h"
#include "errors.h"
@@ -424,8 +430,8 @@ md_reader::peek_char (void)
/* Read an rtx code name into NAME. It is terminated by any of the
punctuation chars of rtx printed syntax. */
-void
-md_reader::read_name (struct md_name *name)
+bool
+md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
{
int c;
size_t i;
@@ -463,8 +469,12 @@ md_reader::read_name (struct md_name *name)
c = read_char ();
}
+ unread_char (c);
+ *out_loc = get_current_location ();
+ read_char ();
+
if (i == 0)
- fatal_with_file_and_line ("missing name or number");
+ return false;
name->buffer[i] = 0;
name->string = name->buffer;
@@ -485,6 +495,36 @@ md_reader::read_name (struct md_name *name)
}
while (def);
}
+
+ return true;
+}
+
+/* Read an rtx code name into NAME. It is terminated by any of the
+ punctuation chars of rtx printed syntax. */
+
+file_location
+md_reader::read_name (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ fatal_with_file_and_line ("missing name or number");
+ return loc;
+}
+
+file_location
+md_reader::read_name_or_nil (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ {
+ file_location loc = get_current_location ();
+ read_skip_construct (0, loc);
+ /* Skip the ')'. */
+ read_char ();
+ name->buffer[0] = 0;
+ name->string = name->buffer;
+ }
+ return loc;
}
/* Subroutine of the string readers. Handles backslash escapes.
@@ -630,6 +670,14 @@ md_reader::read_string (int star_if_braced)
obstack_1grow (&m_string_obstack, '*');
stringbuf = read_braced_string ();
}
+ else if (saw_paren && c == 'n')
+ {
+ /* Handle (nil) by returning NULL. */
+ require_char ('i');
+ require_char ('l');
+ require_char_ws (')');
+ return NULL;
+ }
else
fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
@@ -924,8 +972,9 @@ md_reader::traverse_enum_types (htab_trav callback, void *info)
/* Constructor for md_reader. */
-md_reader::md_reader ()
-: m_toplevel_fname (NULL),
+md_reader::md_reader (bool compact)
+: m_compact (compact),
+ m_toplevel_fname (NULL),
m_base_dir (NULL),
m_read_md_file (NULL),
m_read_md_filename (NULL),
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 8910b75..eb53a85 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -94,7 +94,7 @@ struct enum_type {
class md_reader
{
public:
- md_reader ();
+ md_reader (bool compact);
virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
@@ -107,10 +107,13 @@ class md_reader
file_location get_current_location () const;
+ bool is_compact () const { return m_compact; }
+
/* Defined in read-md.c. */
int read_char (void);
void unread_char (int ch);
- void read_name (struct md_name *name);
+ file_location read_name (struct md_name *name);
+ file_location read_name_or_nil (struct md_name *);
void read_escape ();
char *read_quoted_string ();
char *read_braced_string ();
@@ -167,7 +170,12 @@ class md_reader
void handle_include (file_location loc);
void add_include_path (const char *arg);
+ bool read_name_1 (struct md_name *name, file_location *out_loc);
+
private:
+ /* Are we reading a compact dump? */
+ bool m_compact;
+
/* The name of the toplevel file that indirectly included
m_read_md_file. */
const char *m_toplevel_fname;
@@ -235,7 +243,7 @@ extern md_reader *md_reader_ptr;
class noop_reader : public md_reader
{
public:
- noop_reader () : md_reader () {}
+ noop_reader () : md_reader (false) {}
/* A dummy implementation which skips unknown directives. */
void handle_unknown_directive (file_location, const char *);
@@ -249,14 +257,30 @@ class noop_reader : public md_reader
class rtx_reader : public md_reader
{
public:
- rtx_reader ();
+ rtx_reader (bool compact);
~rtx_reader ();
bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
rtx read_rtx_code (const char *code_name);
- void read_rtx_operand (rtx return_rtx, int idx);
+ virtual rtx read_rtx_operand (rtx return_rtx, int idx);
rtx read_nested_rtx ();
rtx read_rtx_variadic (rtx form);
+ char *read_until (const char *terminator_chars, bool consume_terminator);
+
+ virtual void handle_any_trailing_information (rtx) {}
+ virtual rtx postprocess (rtx x) { return x; }
+
+ /* Hook to allow function_reader subclass to put STRINGBUF into gc-managed
+ memory, rather than within an obstack.
+ This base class implementation is a no-op. */
+ virtual const char *finalize_string (char *stringbuf) { return stringbuf; }
+
+ protected:
+ /* Analogous to rtx_writer's m_in_call_function_usage. */
+ bool m_in_call_function_usage;
+
+ /* Support for "reuse_rtx" directives. */
+ auto_vec<rtx> m_reuse_rtx_by_id;
};
/* Global singleton; constrast with md_reader_ptr above. */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
new file mode 100644
index 0000000..b12e3df
--- /dev/null
+++ b/gcc/read-rtl-function.c
@@ -0,0 +1,1653 @@
+/* read-rtl-function.c - Reader for RTL function dumps
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "read-md.h"
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "read-rtl-function.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
+
+/* Forward decls. */
+class function_reader;
+class fixup;
+
+/* Edges are recorded when parsing the "insn-chain" directive,
+ and created at the end when all the blocks ought to exist.
+ This struct records an "edge-from" or "edge-to" directive seen
+ at LOC, which will be turned into an actual CFG edge once
+ the "insn-chain" is fully parsed. */
+
+struct deferred_edge
+{
+ deferred_edge (file_location loc, int src_bb_idx, int dest_bb_idx, int flags)
+ : m_loc (loc), m_src_bb_idx (src_bb_idx), m_dest_bb_idx (dest_bb_idx),
+ m_flags (flags)
+ {}
+
+ file_location m_loc;
+ int m_src_bb_idx;
+ int m_dest_bb_idx;
+ int m_flags;
+};
+
+/* Subclass of rtx_reader for reading function dumps. */
+
+class function_reader : public rtx_reader
+{
+ public:
+ function_reader ();
+ ~function_reader ();
+
+ /* Overridden vfuncs of class md_reader. */
+ void handle_unknown_directive (file_location, const char *) FINAL OVERRIDE;
+
+ /* Overridden vfuncs of class rtx_reader. */
+ rtx read_rtx_operand (rtx x, int idx) FINAL OVERRIDE;
+ void handle_any_trailing_information (rtx x) FINAL OVERRIDE;
+ rtx postprocess (rtx) FINAL OVERRIDE;
+ const char *finalize_string (char *stringbuf) FINAL OVERRIDE;
+
+ rtx_insn **get_insn_by_uid (int uid);
+ tree parse_mem_expr (const char *desc);
+
+ private:
+ void parse_function ();
+ void create_function ();
+ void parse_param ();
+ void parse_insn_chain ();
+ void parse_block ();
+ int parse_bb_idx ();
+ void parse_edge (basic_block block, bool from);
+ rtx_insn *parse_insn (file_location loc, const char *name);
+ void parse_cfg (file_location loc);
+ void parse_crtl (file_location loc);
+ void create_edges ();
+
+ int parse_enum_value (int num_values, const char *const *strings);
+
+ void read_rtx_operand_u (rtx x, int idx);
+ void read_rtx_operand_i_or_n (rtx x, int idx, char format_char);
+ rtx read_rtx_operand_r (rtx x);
+ void extra_parsing_for_operand_code_0 (rtx x, int idx);
+
+ void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid);
+
+ void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx);
+
+ void add_fixup_source_location (file_location loc, rtx_insn *insn,
+ const char *filename, int lineno);
+
+ void add_fixup_expr (file_location loc, rtx x,
+ const char *desc);
+
+ rtx consolidate_singletons (rtx x);
+ rtx parse_rtx ();
+ void maybe_read_location (rtx_insn *insn);
+
+ void handle_insn_uids ();
+ void apply_fixups ();
+
+ private:
+ struct uid_hash : int_hash <int, -1, -2> {};
+ hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+ auto_vec<fixup *> m_fixups;
+ rtx_insn *m_first_insn;
+ auto_vec<tree> m_fake_scope;
+ char *m_name;
+ bool m_have_crtl_directive;
+ basic_block m_bb_to_insert_after;
+ auto_vec <deferred_edge> m_deferred_edges;
+ int m_highest_bb_idx;
+};
+
+/* Abstract base class for recording post-processing steps that must be
+ done after reading a .rtl file. */
+
+class fixup
+{
+ public:
+ /* Constructor for a fixup at LOC affecting X. */
+ fixup (file_location loc, rtx x)
+ : m_loc (loc), m_rtx (x)
+ {}
+ virtual ~fixup () {}
+
+ virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+ file_location m_loc;
+ rtx m_rtx;
+};
+
+/* An abstract subclass of fixup for post-processing steps that
+ act on a specific operand of a specific instruction. */
+
+class operand_fixup : public fixup
+{
+ public:
+ /* Constructor for a fixup at LOC affecting INSN's operand
+ with index OPERAND_IDX. */
+ operand_fixup (file_location loc, rtx insn, int operand_idx)
+ : fixup (loc, insn), m_operand_idx (operand_idx)
+ {}
+
+ protected:
+ int m_operand_idx;
+};
+
+/* A concrete subclass of operand_fixup: fixup an rtx_insn *
+ field based on an integer UID. */
+
+class fixup_insn_uid : public operand_fixup
+{
+ public:
+ /* Constructor for a fixup at LOC affecting INSN's operand
+ with index OPERAND_IDX. Record INSN_UID as the uid. */
+ fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
+ : operand_fixup (loc, insn, operand_idx),
+ m_insn_uid (insn_uid)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_insn_uid;
+};
+
+/* A concrete subclass of operand_fixup: fix up a
+ NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+class fixup_note_insn_basic_block : public operand_fixup
+{
+ public:
+ fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
+ int bb_idx)
+ : operand_fixup (loc, insn, operand_idx),
+ m_bb_idx (bb_idx)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_bb_idx;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+ the expr of an rtx (REG or MEM) based on a textual dump. */
+
+class fixup_expr : public fixup
+{
+ public:
+ fixup_expr (file_location loc, rtx x, const char *desc)
+ : fixup (loc, x),
+ m_desc (xstrdup (desc))
+ {}
+
+ ~fixup_expr () { free (m_desc); }
+
+ void apply (function_reader *reader) const;
+
+ private:
+ char *m_desc;
+};
+
+/* Return a textual description of the operand of INSN with
+ index OPERAND_IDX. */
+
+static const char *
+get_operand_name (rtx insn, int operand_idx)
+{
+ gcc_assert (is_a <rtx_insn *> (insn));
+ switch (operand_idx)
+ {
+ case 0:
+ return "PREV_INSN";
+ case 1:
+ return "NEXT_INSN";
+ default:
+ return NULL;
+ }
+}
+
+/* Fixup an rtx_insn * field based on an integer UID, as read by READER. */
+
+void
+fixup_insn_uid::apply (function_reader *reader) const
+{
+ rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
+ if (insn_from_uid)
+ XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
+ else
+ {
+ const char *op_name = get_operand_name (m_rtx, m_operand_idx);
+ if (op_name)
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i (`%s') of insn %i",
+ m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
+ else
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i of insn %i",
+ m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
+ }
+}
+
+/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+void
+fixup_note_insn_basic_block::apply (function_reader *) const
+{
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+ gcc_assert (bb);
+ NOTE_BASIC_BLOCK (m_rtx) = bb;
+}
+
+/* Fix up the expr of an rtx (REG or MEM) based on a textual dump
+ read by READER. */
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+ tree expr = reader->parse_mem_expr (m_desc);
+ switch (GET_CODE (m_rtx))
+ {
+ case REG:
+ set_reg_attrs_for_decl_rtl (expr, m_rtx);
+ break;
+ case MEM:
+ set_mem_expr (m_rtx, expr);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Strip trailing whitespace from DESC. */
+
+static void
+strip_trailing_whitespace (char *desc)
+{
+ char *terminator = desc + strlen (desc);
+ while (desc < terminator)
+ {
+ terminator--;
+ if (ISSPACE (*terminator))
+ *terminator = '\0';
+ else
+ break;
+ }
+}
+
+/* Return the numeric value n for GET_NOTE_INSN_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+static int
+parse_note_insn_name (const char *string)
+{
+ for (int i = 0; i < NOTE_INSN_MAX; i++)
+ if (0 == strcmp (string, GET_NOTE_INSN_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
+}
+
+/* Return the register number for NAME, or return -1 if it isn't
+ recognized. */
+
+static int
+lookup_reg_by_dump_name (const char *name)
+{
+ for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (reg_names[i][0]
+ && ! strcmp (name, reg_names[i]))
+ return i;
+
+ /* Also lookup virtuals. */
+ if (!strcmp (name, "virtual-incoming-args"))
+ return VIRTUAL_INCOMING_ARGS_REGNUM;
+ if (!strcmp (name, "virtual-stack-vars"))
+ return VIRTUAL_STACK_VARS_REGNUM;
+ if (!strcmp (name, "virtual-stack-dynamic"))
+ return VIRTUAL_STACK_DYNAMIC_REGNUM;
+ if (!strcmp (name, "virtual-outgoing-args"))
+ return VIRTUAL_OUTGOING_ARGS_REGNUM;
+ if (!strcmp (name, "virtual-cfa"))
+ return VIRTUAL_CFA_REGNUM;
+ if (!strcmp (name, "virtual-preferred-stack-boundary"))
+ return VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM;
+ /* TODO: handle "virtual-reg-%d". */
+
+ /* In compact mode, pseudos are printed with a '%' sigil following
+ by the regno, offset by (LAST_VIRTUAL_REGISTER + 1), so that the
+ first non-virtual pseudo is dumped as "%0". */
+ if (name[0] == '%')
+ {
+ int dump_num = atoi (name + 1);
+ return dump_num + LAST_VIRTUAL_REGISTER + 1;
+ }
+
+ /* Not found. */
+ return -1;
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor. */
+
+function_reader::function_reader ()
+: rtx_reader (true),
+ m_first_insn (NULL),
+ m_name (NULL),
+ m_have_crtl_directive (false),
+ m_bb_to_insert_after (NULL),
+ m_highest_bb_idx (EXIT_BLOCK)
+{
+}
+
+/* function_reader's destructor. */
+
+function_reader::~function_reader ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ delete f;
+
+ free (m_name);
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive,
+ for parsing the remainder of a directive with name NAME
+ seen at START_LOC.
+
+ Require a top-level "function" directive, as emitted by
+ print_rtx_function, and parse it. */
+
+void
+function_reader::handle_unknown_directive (file_location start_loc,
+ const char *name)
+{
+ if (strcmp (name, "function"))
+ fatal_at (start_loc, "expected 'function'");
+
+ parse_function ();
+}
+
+/* Parse the output of print_rtx_function (or hand-written data in the
+ same format), having already parsed the "(function" heading, and
+ finishing immediately before the final ")".
+
+ The "param" and "crtl" clauses are optional. */
+
+void
+function_reader::parse_function ()
+{
+ m_name = xstrdup (read_string (0));
+
+ create_function ();
+
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ if (c == ')')
+ {
+ unread_char (c);
+ break;
+ }
+ unread_char (c);
+ require_char ('(');
+ file_location loc = get_current_location ();
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "param") == 0)
+ parse_param ();
+ else if (strcmp (directive.string, "insn-chain") == 0)
+ parse_insn_chain ();
+ else if (strcmp (directive.string, "crtl") == 0)
+ parse_crtl (loc);
+ else
+ fatal_with_file_and_line ("unrecognized directive: %s",
+ directive.string);
+ }
+
+ handle_insn_uids ();
+
+ apply_fixups ();
+
+ /* Rebuild the JUMP_LABEL field of any JUMP_INSNs in the chain, and the
+ LABEL_NUSES of any CODE_LABELs.
+
+ This has to happen after apply_fixups, since only after then do
+ LABEL_REFs have their label_ref_label set up. */
+ rebuild_jump_labels (get_insns ());
+
+ crtl->init_stack_alignment ();
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+ Create "cfun" and a decl for the function.
+ By default, every function decl is hardcoded as
+ int test_1 (int i, int j, int k);
+ Set up various other state:
+ - the cfg and basic blocks (edges are created later, *after* fixups
+ are applied).
+ - add the function to the callgraph. */
+
+void
+function_reader::create_function ()
+{
+ /* We start in cfgrtl mode, rather than cfglayout mode. */
+ rtl_register_cfg_hooks ();
+
+ /* Create cfun. */
+ tree fn_name = get_identifier (m_name ? m_name : "test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+
+ current_function_decl = fndecl;
+
+ cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+ /* Do we need this to force cgraphunit.c to output the function? */
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_PRESERVE_P (fndecl) = 1;
+
+ /* Add to cgraph. */
+ cgraph_node::finalize_function (fndecl, false);
+
+ /* Create bare-bones cfg. This creates the entry and exit blocks. */
+ init_empty_tree_cfg_for_function (cfun);
+ ENTRY_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+ EXIT_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_RTL;
+ init_rtl_bb_info (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ init_rtl_bb_info (EXIT_BLOCK_PTR_FOR_FN (cfun));
+ m_bb_to_insert_after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+
+}
+
+/* Look within the the params of FNDECL for a param named NAME.
+ Return NULL_TREE if one isn't found. */
+
+static tree
+find_param_by_name (tree fndecl, const char *name)
+{
+ for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg))
+ if (strcmp (name, IDENTIFIER_POINTER (DECL_NAME (arg))) == 0)
+ return arg;
+ return NULL_TREE;
+}
+
+/* Parse the content of a "param" directive, having already parsed the
+ "(param". Consume the trailing ')'. */
+
+void
+function_reader::parse_param ()
+{
+ require_char_ws ('"');
+ file_location loc = get_current_location ();
+ char *name = read_quoted_string ();
+
+ /* Lookup param by name. */
+ tree t_param = find_param_by_name (cfun->decl, name);
+ if (!t_param)
+ fatal_at (loc, "param not found: %s", name);
+
+ /* Parse DECL_RTL. */
+ require_char_ws ('(');
+ require_word_ws ("DECL_RTL");
+ DECL_WRTL_CHECK (t_param)->decl_with_rtl.rtl = parse_rtx ();
+ require_char_ws (')');
+
+ /* Parse DECL_RTL_INCOMING. */
+ require_char_ws ('(');
+ require_word_ws ("DECL_RTL_INCOMING");
+ DECL_INCOMING_RTL (t_param) = parse_rtx ();
+ require_char_ws (')');
+
+ require_char_ws (')');
+}
+
+/* Parse zero or more child insn elements within an
+ "insn-chain" element. Consume the trailing ')'. */
+
+void
+function_reader::parse_insn_chain ()
+{
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ file_location loc = get_current_location ();
+ if (c == ')')
+ break;
+ else if (c == '(')
+ {
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "block") == 0)
+ parse_block ();
+ else
+ parse_insn (loc, directive.string);
+ }
+ else
+ fatal_at (loc, "expected '(' or ')'");
+ }
+
+ create_edges ();
+}
+
+/* Parse zero or more child directives (edges and insns) within a
+ "block" directive, having already parsed the "(block " heading.
+ Consume the trailing ')'. */
+
+void
+function_reader::parse_block ()
+{
+ /* Parse the index value from the dump. This will be an integer;
+ we don't support "entry" or "exit" here (unlike for edges). */
+ struct md_name name;
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+
+ /* The term "index" has two meanings for basic blocks in a CFG:
+ (a) the "index" field within struct basic_block_def.
+ (b) the index of a basic_block within the cfg's x_basic_block_info
+ vector, as accessed via BASIC_BLOCK_FOR_FN.
+
+ These can get out-of-sync when basic blocks are optimized away.
+ They get back in sync by "compact_blocks".
+ We reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
+ values in it for any missing basic blocks, so that (a) == (b) for
+ all of the blocks we create. The doubly-linked list of basic
+ blocks (next_bb/prev_bb) skips over these "holes". */
+
+ if (m_highest_bb_idx < bb_idx)
+ m_highest_bb_idx = bb_idx;
+
+ size_t new_size = m_highest_bb_idx + 1;
+ if (basic_block_info_for_fn (cfun)->length () < new_size)
+ vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
+
+ last_basic_block_for_fn (cfun) = new_size;
+
+ /* Create the basic block.
+
+ We can't call create_basic_block and use the regular RTL block-creation
+ hooks, since this creates NOTE_INSN_BASIC_BLOCK instances. We don't
+ want to do that; we want to use the notes we were provided with. */
+ basic_block bb = alloc_block ();
+ init_rtl_bb_info (bb);
+ bb->index = bb_idx;
+ bb->flags = BB_NEW | BB_RTL;
+ link_block (bb, m_bb_to_insert_after);
+ m_bb_to_insert_after = bb;
+
+ n_basic_blocks_for_fn (cfun)++;
+ SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
+ BB_SET_PARTITION (bb, BB_UNPARTITIONED);
+
+ /* Handle insns, edge-from and edge-to directives. */
+ while (1)
+ {
+ int c = read_skip_spaces ();
+ file_location loc = get_current_location ();
+ if (c == ')')
+ break;
+ else if (c == '(')
+ {
+ struct md_name directive;
+ read_name (&directive);
+ if (strcmp (directive.string, "edge-from") == 0)
+ parse_edge (bb, true);
+ else if (strcmp (directive.string, "edge-to") == 0)
+ parse_edge (bb, false);
+ else
+ {
+ rtx_insn *insn = parse_insn (loc, directive.string);
+ set_block_for_insn (insn, bb);
+ if (!BB_HEAD (bb))
+ BB_HEAD (bb) = insn;
+ BB_END (bb) = insn;
+ }
+ }
+ else
+ fatal_at (loc, "expected '(' or ')'");
+ }
+}
+
+/* Subroutine of function_reader::parse_edge.
+ Parse a basic block index, handling "entry" and "exit". */
+
+int
+function_reader::parse_bb_idx ()
+{
+ struct md_name name;
+ read_name (&name);
+ if (strcmp (name.string, "entry") == 0)
+ return ENTRY_BLOCK;
+ if (strcmp (name.string, "exit") == 0)
+ return EXIT_BLOCK;
+ return atoi (name.string);
+}
+
+/* Subroutine of parse_edge_flags.
+ Parse TOK, a token such as "FALLTHRU", converting to the flag value.
+ Issue an error if the token is unrecognized. */
+
+static int
+parse_edge_flag_token (const char *tok)
+{
+#define DEF_EDGE_FLAG(NAME,IDX) \
+ do { \
+ if (strcmp (tok, #NAME) == 0) \
+ return EDGE_##NAME; \
+ } while (0);
+#include "cfg-flags.def"
+#undef DEF_EDGE_FLAG
+ error ("unrecognized edge flag: '%s'", tok);
+ return 0;
+}
+
+/* Subroutine of function_reader::parse_edge.
+ Parse STR and convert to a flag value (or issue an error).
+ The parser uses strtok and hence modifiers STR in-place. */
+
+static int
+parse_edge_flags (char *str)
+{
+ int result = 0;
+
+ char *tok = strtok (str, "| ");
+ while (tok)
+ {
+ result |= parse_edge_flag_token (tok);
+ tok = strtok (NULL, "| ");
+ }
+
+ return result;
+}
+
+/* Parse an "edge-from" or "edge-to" directive within the "block"
+ directive for BLOCK, having already parsed the "(edge" heading.
+ Consume the final ")". Record the edge within m_deferred_edges.
+ FROM is true for an "edge-from" directive, false for an "edge-to"
+ directive. */
+
+void
+function_reader::parse_edge (basic_block block, bool from)
+{
+ gcc_assert (block);
+ int this_bb_idx = block->index;
+ file_location loc = get_current_location ();
+ int other_bb_idx = parse_bb_idx ();
+
+ /* "(edge-from 2)" means src = 2, dest = this_bb_idx, whereas
+ "(edge-to 3)" means src = this_bb_idx, dest = 3. */
+ int src_idx = from ? other_bb_idx : this_bb_idx;
+ int dest_idx = from ? this_bb_idx : other_bb_idx;
+
+ /* Optional "(flags)". */
+ int flags = 0;
+ int c = read_skip_spaces ();
+ if (c == '(')
+ {
+ require_word_ws ("flags");
+ require_char_ws ('"');
+ char *str = read_quoted_string ();
+ flags = parse_edge_flags (str);
+ require_char_ws (')');
+ }
+ else
+ unread_char (c);
+
+ require_char_ws (')');
+
+ /* This BB already exists, but the other BB might not yet.
+ For now, save the edges, and create them at the end of insn-chain
+ processing. */
+ /* For now, only process the (edge-from) to this BB, and (edge-to)
+ that go to the exit block.
+ FIXME: we don't yet verify that the edge-from and edge-to directives
+ are consistent. */
+ if (from || dest_idx == EXIT_BLOCK)
+ m_deferred_edges.safe_push (deferred_edge (loc, src_idx, dest_idx, flags));
+}
+
+/* Parse an rtx instruction, having parsed the opening and parenthesis, and
+ name NAME, seen at START_LOC, by calling read_rtx_code, calling
+ set_first_insn and set_last_insn as appropriate, and
+ adding the insn to the insn chain.
+ Consume the trailing ')'. */
+
+rtx_insn *
+function_reader::parse_insn (file_location start_loc, const char *name)
+{
+ rtx x = read_rtx_code (name);
+ if (!x)
+ fatal_at (start_loc, "expected insn type; got '%s'", name);
+ rtx_insn *insn = dyn_cast <rtx_insn *> (x);
+ if (!insn)
+ fatal_at (start_loc, "expected insn type; got '%s'", name);
+
+ /* Consume the trailing ')'. */
+ require_char_ws (')');
+
+ rtx_insn *last_insn = get_last_insn ();
+
+ /* Add "insn" to the insn chain. */
+ if (last_insn)
+ {
+ gcc_assert (NEXT_INSN (last_insn) == NULL);
+ SET_NEXT_INSN (last_insn) = insn;
+ }
+ SET_PREV_INSN (insn) = last_insn;
+
+ /* Add it to the sequence. */
+ set_last_insn (insn);
+ if (!m_first_insn)
+ {
+ m_first_insn = insn;
+ set_first_insn (insn);
+ }
+
+ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
+ maybe_set_max_label_num (label);
+
+ return insn;
+}
+
+/* Postprocessing subroutine for parse_insn_chain: all the basic blocks
+ should have been created by now; create the edges that were seen. */
+
+void
+function_reader::create_edges ()
+{
+ int i;
+ deferred_edge *de;
+ FOR_EACH_VEC_ELT (m_deferred_edges, i, de)
+ {
+ /* The BBs should already have been created by parse_block. */
+ basic_block src = BASIC_BLOCK_FOR_FN (cfun, de->m_src_bb_idx);
+ if (!src)
+ fatal_at (de->m_loc, "error: block index %i not found",
+ de->m_src_bb_idx);
+ basic_block dst = BASIC_BLOCK_FOR_FN (cfun, de->m_dest_bb_idx);
+ if (!dst)
+ fatal_at (de->m_loc, "error: block with index %i not found",
+ de->m_dest_bb_idx);
+ unchecked_make_edge (src, dst, de->m_flags);
+ }
+}
+
+/* Parse a "crtl" directive, having already parsed the "(crtl" heading
+ at location LOC.
+ Consume the final ")". */
+
+void
+function_reader::parse_crtl (file_location loc)
+{
+ if (m_have_crtl_directive)
+ error_at (loc, "more than one 'crtl' directive");
+ m_have_crtl_directive = true;
+
+ /* return_rtx. */
+ require_char_ws ('(');
+ require_word_ws ("return_rtx");
+ crtl->return_rtx = parse_rtx ();
+ require_char_ws (')');
+
+ require_char_ws (')');
+}
+
+/* Parse operand IDX of X, returning X, or an equivalent rtx
+ expression (for consolidating singletons).
+ This is an overridden implementation of rtx_reader::read_rtx_operand for
+ function_reader, handling various extra data printed by print_rtx,
+ and sometimes calling the base class implementation. */
+
+rtx
+function_reader::read_rtx_operand (rtx x, int idx)
+{
+ RTX_CODE code = GET_CODE (x);
+ const char *format_ptr = GET_RTX_FORMAT (code);
+ const char format_char = format_ptr[idx];
+ struct md_name name;
+
+ /* Override the regular parser for some format codes. */
+ switch (format_char)
+ {
+ case 'e':
+ if (idx == 7 && CALL_P (x))
+ {
+ m_in_call_function_usage = true;
+ return rtx_reader::read_rtx_operand (x, idx);
+ m_in_call_function_usage = false;
+ }
+ else
+ return rtx_reader::read_rtx_operand (x, idx);
+ break;
+
+ case 'u':
+ read_rtx_operand_u (x, idx);
+ /* Don't run regular parser for 'u'. */
+ return x;
+
+ case 'i':
+ case 'n':
+ read_rtx_operand_i_or_n (x, idx, format_char);
+ /* Don't run regular parser for these codes. */
+ return x;
+
+ case 'B':
+ gcc_assert (is_compact ());
+ /* Compact mode doesn't store BBs. */
+ /* Don't run regular parser. */
+ return x;
+
+ case 'r':
+ /* Don't run regular parser for 'r'. */
+ return read_rtx_operand_r (x);
+
+ default:
+ break;
+ }
+
+ /* Call base class implementation. */
+ x = rtx_reader::read_rtx_operand (x, idx);
+
+ /* Handle any additional parsing needed to handle what the dump
+ could contain. */
+ switch (format_char)
+ {
+ case '0':
+ extra_parsing_for_operand_code_0 (x, idx);
+ break;
+
+ case 'w':
+ if (!is_compact ())
+ {
+ /* Strip away the redundant hex dump of the value. */
+ require_char_ws ('[');
+ read_name (&name);
+ require_char_ws (']');
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+/* Parse operand IDX of X, of code 'u', when reading function dumps.
+
+ The RTL file recorded the ID of an insn (or 0 for NULL); we
+ must store this as a pointer, but the insn might not have
+ been loaded yet. Store the ID away for now, via a fixup. */
+
+void
+function_reader::read_rtx_operand_u (rtx x, int idx)
+{
+ /* In compact mode, the PREV/NEXT insn uids are not dumped, so skip
+ the "uu" when reading. */
+ if (is_compact () && GET_CODE (x) != LABEL_REF)
+ return;
+
+ struct md_name name;
+ file_location loc = read_name (&name);
+ int insn_id = atoi (name.string);
+ if (insn_id)
+ add_fixup_insn_uid (loc, x, idx, insn_id);
+}
+
+/* Read a name, looking for a match against a string found in array
+ STRINGS of size NUM_VALUES.
+ Return the index of the the matched string, or emit an error. */
+
+int
+function_reader::parse_enum_value (int num_values, const char *const *strings)
+{
+ struct md_name name;
+ read_name (&name);
+ for (int i = 0; i < num_values; i++)
+ {
+ if (strcmp (name.string, strings[i]) == 0)
+ return i;
+ }
+ error ("unrecognized enum value: '%s'", name.string);
+ return 0;
+}
+
+/* Parse operand IDX of X, of code 'i' or 'n' (as specified by FORMAT_CHAR).
+ Special-cased handling of these, for reading function dumps. */
+
+void
+function_reader::read_rtx_operand_i_or_n (rtx x, int idx,
+ char format_char)
+{
+ /* Handle some of the extra information that print_rtx
+ can write out for these cases. */
+ /* print_rtx only writes out operand 5 for notes
+ for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+ and NOTE_INSN_DELETED_DEBUG_LABEL. */
+ if (idx == 5 && NOTE_P (x))
+ return;
+
+ if (idx == 4 && INSN_P (x))
+ {
+ maybe_read_location (as_a <rtx_insn *> (x));
+ return;
+ }
+
+ /* INSN_CODEs aren't printed in compact mode, so don't attempt to
+ parse them. */
+ if (is_compact ()
+ && INSN_P (x)
+ && &INSN_CODE (x) == &XINT (x, idx))
+ {
+ INSN_CODE (x) = -1;
+ return;
+ }
+
+ /* Handle UNSPEC and UNSPEC_VOLATILE's operand 1. */
+#if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0
+ if (idx == 1
+ && GET_CODE (x) == UNSPEC_VOLATILE)
+ {
+ XINT (x, 1)
+ = parse_enum_value (NUM_UNSPECV_VALUES, unspecv_strings);
+ return;
+ }
+#endif
+#if !defined(GENERATOR_FILE) && NUM_UNSPEC_VALUES > 0
+ if (idx == 1
+ && (GET_CODE (x) == UNSPEC
+ || GET_CODE (x) == UNSPEC_VOLATILE))
+ {
+ XINT (x, 1)
+ = parse_enum_value (NUM_UNSPEC_VALUES, unspec_strings);
+ return;
+ }
+#endif
+
+ struct md_name name;
+ read_name (&name);
+ int value;
+ if (format_char == 'n')
+ value = parse_note_insn_name (name.string);
+ else
+ value = atoi (name.string);
+ XINT (x, idx) = value;
+}
+
+/* Parse the 'r' operand of X, returning X, or an equivalent rtx
+ expression (for consolidating singletons).
+ Special-cased handling of code 'r' for reading function dumps. */
+
+rtx
+function_reader::read_rtx_operand_r (rtx x)
+{
+ struct md_name name;
+ file_location loc = read_name (&name);
+ int regno = lookup_reg_by_dump_name (name.string);
+ if (regno == -1)
+ fatal_at (loc, "unrecognized register: '%s'", name.string);
+
+ set_regno_raw (x, regno, 1);
+
+ /* Consolidate singletons. */
+ x = consolidate_singletons (x);
+
+ ORIGINAL_REGNO (x) = regno;
+
+ /* Parse extra stuff at end of 'r'.
+ We may have zero, one, or two sections marked by square
+ brackets. */
+ int ch = read_skip_spaces ();
+ bool expect_original_regno = false;
+ if (ch == '[')
+ {
+ file_location loc = get_current_location ();
+ char *desc = read_until ("]", true);
+ strip_trailing_whitespace (desc);
+ const char *desc_start = desc;
+ /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+ "orig:%i", ORIGINAL_REGNO (rtx).
+ Consume it, we don't set ORIGINAL_REGNO, since we can
+ get that from the 2nd copy later. */
+ if (0 == strncmp (desc, "orig:", 5))
+ {
+ expect_original_regno = true;
+ desc_start += 5;
+ /* Skip to any whitespace following the integer. */
+ const char *space = strchr (desc_start, ' ');
+ if (space)
+ desc_start = space + 1;
+ }
+ /* Any remaining text may be the REG_EXPR. Alternatively we have
+ no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
+ if (ISDIGIT (*desc_start))
+ {
+ /* Assume we have ORIGINAL_REGNO. */
+ ORIGINAL_REGNO (x) = atoi (desc_start);
+ }
+ else
+ {
+ /* Assume we have REG_EXPR. */
+ add_fixup_expr (loc, x, desc_start);
+ }
+ free (desc);
+ }
+ else
+ unread_char (ch);
+ if (expect_original_regno)
+ {
+ require_char_ws ('[');
+ char *desc = read_until ("]", true);
+ ORIGINAL_REGNO (x) = atoi (desc);
+ free (desc);
+ }
+
+ return x;
+}
+
+/* Additional parsing for format code '0' in dumps, handling a variety
+ of special-cases in print_rtx, when parsing operand IDX of X. */
+
+void
+function_reader::extra_parsing_for_operand_code_0 (rtx x, int idx)
+{
+ RTX_CODE code = GET_CODE (x);
+ int c;
+ struct md_name name;
+
+ if (idx == 1 && code == SYMBOL_REF)
+ {
+ /* Possibly wrote " [flags %#x]", SYMBOL_REF_FLAGS (in_rtx). */
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ file_location loc = read_name (&name);
+ if (strcmp (name.string, "flags"))
+ error_at (loc, "was expecting `%s'", "flags");
+ read_name (&name);
+ SYMBOL_REF_FLAGS (x) = strtol (name.string, NULL, 16);
+
+ /* We can't reconstruct SYMBOL_REF_BLOCK; set it to NULL. */
+ if (SYMBOL_REF_HAS_BLOCK_INFO_P (x))
+ SYMBOL_REF_BLOCK (x) = NULL;
+
+ require_char (']');
+ }
+ else
+ unread_char (c);
+
+ /* If X had a non-NULL SYMBOL_REF_DECL,
+ rtx_writer::print_rtx_operand_code_0 would have dumped it
+ using print_node_brief.
+ Skip the content for now. */
+ c = read_skip_spaces ();
+ if (c == '<')
+ {
+ while (1)
+ {
+ char ch = read_char ();
+ if (ch == '>')
+ break;
+ }
+ }
+ else
+ unread_char (c);
+ }
+ else if (idx == 3 && code == NOTE)
+ {
+ /* Note-specific data appears for operand 3, which annoyingly
+ is before the enum specifying which kind of note we have
+ (operand 4). */
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ /* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+ [bb %d]. */
+ file_location bb_loc = read_name (&name);
+ if (strcmp (name.string, "bb"))
+ error_at (bb_loc, "was expecting `%s'", "bb");
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+ add_fixup_note_insn_basic_block (bb_loc, x, idx,
+ bb_idx);
+ require_char_ws (']');
+ }
+ else
+ unread_char (c);
+ }
+}
+
+/* Implementation of rtx_reader::handle_any_trailing_information.
+ Handle the various additional information that print-rtl.c can
+ write after the regular fields, when parsing X. */
+
+void
+function_reader::handle_any_trailing_information (rtx x)
+{
+ struct md_name name;
+
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ {
+ int ch;
+ require_char_ws ('[');
+ read_name (&name);
+ MEM_ALIAS_SET (x) = atoi (name.string);
+ /* We have either a MEM_EXPR, or a space. */
+ if (peek_char () != ' ')
+ {
+ file_location loc = get_current_location ();
+ char *desc = read_until (" +", false);
+ add_fixup_expr (loc, consolidate_singletons (x), desc);
+ free (desc);
+ }
+ else
+ read_char ();
+
+ /* We may optionally have '+' for MEM_OFFSET_KNOWN_P. */
+ ch = read_skip_spaces ();
+ if (ch == '+')
+ {
+ read_name (&name);
+ MEM_OFFSET_KNOWN_P (x) = 1;
+ MEM_OFFSET (x) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " S" for MEM_SIZE. */
+ ch = read_skip_spaces ();
+ if (ch == 'S')
+ {
+ read_name (&name);
+ MEM_SIZE (x) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " A" for MEM_ALIGN. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () != 'S')
+ {
+ read_name (&name);
+ MEM_ALIGN (x) = atoi (name.string);
+ }
+
+ /* Handle optional " AS" for MEM_ADDR_SPACE. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () == 'S')
+ {
+ read_char ();
+ read_name (&name);
+ MEM_ADDR_SPACE (x) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ require_char (']');
+ }
+ break;
+
+ case CODE_LABEL:
+ /* Assume that LABEL_NUSES was not dumped. */
+ /* TODO: parse LABEL_KIND. */
+ /* For now, skip until closing ')'. */
+ do
+ {
+ char ch = read_char ();
+ if (ch == ')')
+ {
+ unread_char (ch);
+ break;
+ }
+ }
+ while (1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Parse a tree dump for a MEM_EXPR in DESC and turn it back into a tree.
+ We handle "<retval>" and param names within cfun, but for anything else
+ we "cheat" by building a global VAR_DECL of type "int" with that name
+ (returning the same global for a name if we see the same name more
+ than once). */
+
+tree
+function_reader::parse_mem_expr (const char *desc)
+{
+ tree fndecl = cfun->decl;
+
+ if (0 == strcmp (desc, "<retval>"))
+ return DECL_RESULT (fndecl);
+
+ tree param = find_param_by_name (fndecl, desc);
+ if (param)
+ return param;
+
+ /* Search within decls we already created.
+ FIXME: use a hash rather than linear search. */
+ int i;
+ tree t;
+ FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+ if (strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))) == 0)
+ return t;
+
+ /* Not found? Create it.
+ This allows mimicking of real data but avoids having to specify
+ e.g. names of locals, params etc.
+ Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
+ and we don't know the types. Fake it by making everything be
+ a VAR_DECL of "int" type. */
+ t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (desc),
+ integer_type_node);
+ m_fake_scope.safe_push (t);
+ return t;
+}
+
+/* Record that at LOC we saw an insn uid INSN_UID for the operand with index
+ OPERAND_IDX within INSN, so that the pointer value can be fixed up in
+ later post-processing. */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid)
+{
+ m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Record that at LOC we saw an basic block index BB_IDX for the operand with index
+ OPERAND_IDX within INSN, so that the pointer value can be fixed up in
+ later post-processing. */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx)
+{
+ m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+ bb_idx));
+}
+
+/* Placeholder hook for recording source location information seen in a dump.
+ This is empty for now. */
+
+void
+function_reader::add_fixup_source_location (file_location, rtx_insn *,
+ const char *, int)
+{
+}
+
+/* Record that at LOC we saw textual description DESC of the MEM_EXPR or REG_EXPR
+ of INSN, so that the fields can be fixed up in later post-processing. */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+ const char *desc)
+{
+ gcc_assert (desc);
+ /* Fail early if the RTL reader erroneously hands us an int. */
+ gcc_assert (!ISDIGIT (desc[0]));
+
+ m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Helper function for consolidate_reg. Return the global rtx for
+ the register with regno REGNO. */
+
+static rtx
+lookup_global_register (int regno)
+{
+ /* We can't use a switch here, as some of the REGNUMs might not be constants
+ for some targets. */
+ if (regno == STACK_POINTER_REGNUM)
+ return stack_pointer_rtx;
+ else if (regno == FRAME_POINTER_REGNUM)
+ return frame_pointer_rtx;
+ else if (regno == HARD_FRAME_POINTER_REGNUM)
+ return hard_frame_pointer_rtx;
+ else if (regno == ARG_POINTER_REGNUM)
+ return arg_pointer_rtx;
+ else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
+ return virtual_incoming_args_rtx;
+ else if (regno == VIRTUAL_STACK_VARS_REGNUM)
+ return virtual_stack_vars_rtx;
+ else if (regno == VIRTUAL_STACK_DYNAMIC_REGNUM)
+ return virtual_stack_dynamic_rtx;
+ else if (regno == VIRTUAL_OUTGOING_ARGS_REGNUM)
+ return virtual_outgoing_args_rtx;
+ else if (regno == VIRTUAL_CFA_REGNUM)
+ return virtual_cfa_rtx;
+ else if (regno == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
+ return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+ else if (regno == RETURN_ADDRESS_POINTER_REGNUM)
+ return return_address_pointer_rtx;
+#endif
+
+ return NULL;
+}
+
+/* Ensure that the backend can cope with a REG with regno REGNO.
+ Normally REG instances are created by gen_reg_rtx which updates
+ regno_reg_rtx, growing it as necessary.
+ The REG instances created from the dumpfile weren't created this
+ way, so we need to manually update regno_reg_rtx. */
+
+static void
+ensure_regno (int regno)
+{
+ if (reg_rtx_no < regno + 1)
+ reg_rtx_no = regno + 1;
+
+ crtl->emit.ensure_regno_capacity ();
+ gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+}
+
+/* Helper function for consolidate_singletons, for handling REG instances.
+ Given REG instance X of some regno, return the singleton rtx for that
+ regno, if it exists, or X. */
+
+static rtx
+consolidate_reg (rtx x)
+{
+ gcc_assert (GET_CODE (x) == REG);
+
+ unsigned int regno = REGNO (x);
+
+ ensure_regno (regno);
+
+ /* Some register numbers have their rtx created in init_emit_regs
+ e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
+ Consolidate on this. */
+ rtx global_reg = lookup_global_register (regno);
+ if (global_reg)
+ return global_reg;
+
+ /* Populate regno_reg_rtx if necessary. */
+ if (regno_reg_rtx[regno] == NULL)
+ regno_reg_rtx[regno] = x;
+ /* Use it. */
+ gcc_assert (GET_CODE (regno_reg_rtx[regno]) == REG);
+ gcc_assert (REGNO (regno_reg_rtx[regno]) == regno);
+ if (GET_MODE (x) == GET_MODE (regno_reg_rtx[regno]))
+ return regno_reg_rtx[regno];
+
+ return x;
+}
+
+/* When reading RTL function dumps, we must consolidate some
+ rtx so that we use singletons where singletons are expected
+ (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
+ these are tested via pointer equality against const0_rtx.
+
+ Return the equivalent singleton rtx for X, if any, otherwise X. */
+
+rtx
+function_reader::consolidate_singletons (rtx x)
+{
+ if (!x)
+ return x;
+
+ switch (GET_CODE (x))
+ {
+ case PC: return pc_rtx;
+ case RETURN: return ret_rtx;
+ case SIMPLE_RETURN: return simple_return_rtx;
+ case CC0: return cc0_rtx;
+
+ case REG:
+ return consolidate_reg (x);
+
+ case CONST_INT:
+ return gen_rtx_CONST_INT (GET_MODE (x), INTVAL (x));
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+/* Parse an rtx directive, including both the opening/closing parentheses,
+ and the name. */
+
+rtx
+function_reader::parse_rtx ()
+{
+ require_char_ws ('(');
+ struct md_name directive;
+ read_name (&directive);
+ rtx result
+ = consolidate_singletons (read_rtx_code (directive.string));
+ require_char_ws (')');
+
+ return result;
+}
+
+/* Implementation of rtx_reader::postprocess for reading function dumps.
+ Return the equivalent singleton rtx for X, if any, otherwise X. */
+
+rtx
+function_reader::postprocess (rtx x)
+{
+ return consolidate_singletons (x);
+}
+
+/* Implementation of rtx_reader::finalize_string for reading function dumps.
+ Make a GC-managed copy of STRINGBUF. */
+
+const char *
+function_reader::finalize_string (char *stringbuf)
+{
+ return ggc_strdup (stringbuf);
+}
+
+/* Attempt to parse optional location information for insn INSN, as
+ potentially written out by rtx_writer::print_rtx_operand_code_i.
+ We look for a quoted string followed by a colon. */
+
+void
+function_reader::maybe_read_location (rtx_insn *insn)
+{
+ file_location loc = get_current_location ();
+
+ /* Attempt to parse a quoted string. */
+ int ch = read_skip_spaces ();
+ if (ch == '"')
+ {
+ char *filename = read_quoted_string ();
+ require_char (':');
+ struct md_name line_num;
+ read_name (&line_num);
+ add_fixup_source_location (loc, insn, filename, atoi (line_num.string));
+ }
+ else
+ unread_char (ch);
+}
+
+/* Postprocessing subroutine of function_reader::parse_function.
+ Populate m_insns_by_uid. */
+
+void
+function_reader::handle_insn_uids ()
+{
+ /* Locate the currently assigned INSN_UID values, storing
+ them in m_insns_by_uid. */
+ int max_uid = 0;
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (m_insns_by_uid.get (INSN_UID (insn)))
+ error ("duplicate insn UID: %i", INSN_UID (insn));
+ m_insns_by_uid.put (INSN_UID (insn), insn);
+ if (INSN_UID (insn) > max_uid)
+ max_uid = INSN_UID (insn);
+ }
+
+ /* Ensure x_cur_insn_uid is 1 more than the biggest insn UID seen.
+ This is normally updated by the various make_*insn_raw functions. */
+ crtl->emit.x_cur_insn_uid = max_uid + 1;
+}
+
+/* Apply all of the recorded fixups. */
+
+void
+function_reader::apply_fixups ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ f->apply (this);
+}
+
+/* Given a UID value, try to locate a pointer to the corresponding
+ rtx_insn *, or NULL if if can't be found. */
+
+rtx_insn **
+function_reader::get_insn_by_uid (int uid)
+{
+ return m_insns_by_uid.get (uid);
+}
+
+/* Run the RTL dump parser, parsing a dump located at PATH.
+ Return true iff the file was successfully parsed. */
+
+bool
+read_rtl_function_body (const char *path)
+{
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ auto_vec<const char *> argv (2);
+ argv.safe_push (progname);
+ argv.safe_push (path);
+
+ function_reader reader;
+ if (!reader.read_md_files (argv.length (), argv.address (), NULL))
+ return false;
+
+ return true;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that parse_edge_flags works. */
+
+static void
+test_edge_flags ()
+{
+ /* parse_edge_flags modifies its input (due to strtok), so we must make
+ a copy of the literals. */
+#define ASSERT_PARSE_EDGE_FLAGS(EXPECTED, STR) \
+ do { \
+ char *str = xstrdup (STR); \
+ ASSERT_EQ (EXPECTED, parse_edge_flags (str)); \
+ free (str); \
+ } while (0)
+
+ ASSERT_PARSE_EDGE_FLAGS (0, "");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_FALLTHRU, "FALLTHRU");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL_CALL, "ABNORMAL_CALL");
+ ASSERT_PARSE_EDGE_FLAGS (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL,
+ "ABNORMAL | ABNORMAL_CALL");
+
+#undef ASSERT_PARSE_EDGE_FLAGS
+}
+
+/* Verify that lookup_reg_by_dump_name works. */
+
+static void
+test_parsing_regnos ()
+{
+ ASSERT_EQ (-1, lookup_reg_by_dump_name ("this is not a register"));
+
+ /* Verify lookup of virtual registers. */
+ ASSERT_EQ (VIRTUAL_INCOMING_ARGS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-incoming-args"));
+ ASSERT_EQ (VIRTUAL_STACK_VARS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-stack-vars"));
+ ASSERT_EQ (VIRTUAL_STACK_DYNAMIC_REGNUM,
+ lookup_reg_by_dump_name ("virtual-stack-dynamic"));
+ ASSERT_EQ (VIRTUAL_OUTGOING_ARGS_REGNUM,
+ lookup_reg_by_dump_name ("virtual-outgoing-args"));
+ ASSERT_EQ (VIRTUAL_CFA_REGNUM,
+ lookup_reg_by_dump_name ("virtual-cfa"));
+ ASSERT_EQ (VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM,
+ lookup_reg_by_dump_name ("virtual-preferred-stack-boundary"));
+
+ /* Verify lookup of non-virtual pseudos. */
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 1, lookup_reg_by_dump_name ("%0"));
+ ASSERT_EQ (LAST_VIRTUAL_REGISTER + 2, lookup_reg_by_dump_name ("%1"));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+read_rtl_function_c_tests ()
+{
+ test_edge_flags ();
+ test_parsing_regnos ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
new file mode 100644
index 0000000..2e683e2
--- /dev/null
+++ b/gcc/read-rtl-function.h
@@ -0,0 +1,25 @@
+/* read-rtl-function.h - Reader for RTL function dumps
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_READ_RTL_FUNCTION_H
+#define GCC_READ_RTL_FUNCTION_H
+
+extern bool read_rtl_function_body (const char *path);
+
+#endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index f74c875..dabfc98 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
/* Disable rtl checking; it conflicts with the iterator handling. */
#undef ENABLE_RTL_CHECKING
@@ -30,6 +36,12 @@ along with GCC; see the file COPYING3. If not see
#include "read-md.h"
#include "gensupport.h"
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#endif
+
/* One element in a singly-linked list of (integer, string) pairs. */
struct map_value {
struct map_value *next;
@@ -106,6 +118,7 @@ htab_t subst_attr_to_iter_map = NULL;
const char *current_iterator_name;
static void validate_const_int (const char *);
+static void one_time_initialization (void);
/* Global singleton. */
rtx_reader *rtx_reader_ptr = NULL;
@@ -142,6 +155,25 @@ apply_mode_iterator (void *loc, int mode)
PUT_MODE ((rtx) loc, (machine_mode) mode);
}
+/* In compact dumps, the code of insns is prefixed with "c", giving "cinsn",
+ "cnote" etc, and CODE_LABEL is special-cased as "clabel". */
+
+struct compact_insn_name {
+ RTX_CODE code;
+ const char *name;
+};
+
+static const compact_insn_name compact_insn_names[] = {
+ { DEBUG_INSN, "cdebug_insn" },
+ { INSN, "cinsn" },
+ { JUMP_INSN, "cjump_insn" },
+ { CALL_INSN, "ccall_insn" },
+ { JUMP_TABLE_DATA, "cjump_table_data" },
+ { BARRIER, "cbarrier" },
+ { CODE_LABEL, "clabel" },
+ { NOTE, "cnote" }
+};
+
/* Implementations of the iterator_group callbacks for codes. */
static int
@@ -153,6 +185,10 @@ find_code (const char *name)
if (strcmp (GET_RTX_NAME (i), name) == 0)
return i;
+ for (i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
+ if (strcmp (compact_insn_names[i].name, name) == 0)
+ return compact_insn_names[i].code;
+
fatal_with_file_and_line ("unknown rtx code `%s'", name);
}
@@ -181,6 +217,8 @@ apply_int_iterator (void *loc, int value)
*(int *)loc = value;
}
+#ifdef GENERATOR_FILE
+
/* This routine adds attribute or does nothing depending on VALUE. When
VALUE is 1, it does nothing - the first duplicate of original
template is kept untouched when it's subjected to a define_subst.
@@ -252,6 +290,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
*slot = value;
}
+#endif /* #ifdef GENERATOR_FILE */
+
/* Return name of a subst-iterator, corresponding to subst-attribute ATTR. */
static char*
@@ -418,6 +458,8 @@ md_reader::copy_rtx_for_iterators (rtx original)
return x;
}
+#ifdef GENERATOR_FILE
+
/* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL
has the form "&& ..." (as used in define_insn_and_splits), assume that
EXTRA is already satisfied. Empty strings are treated like "true". */
@@ -581,6 +623,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
}
}
}
+#endif /* #ifdef GENERATOR_FILE */
/* Add a new "mapping" structure to hashtable TABLE. NAME is the name
of the mapping and GROUP is the group to which it belongs. */
@@ -655,7 +698,9 @@ initialize_iterators (void)
substs.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
substs.find_builtin = find_int; /* We don't use it, anyway. */
+#ifdef GENERATOR_FILE
substs.apply_iterator = apply_subst_iterator;
+#endif
lower = add_mapping (&modes, modes.attrs, "mode");
upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -724,6 +769,8 @@ atoll (const char *p)
}
#endif
\f
+
+#ifdef GENERATOR_FILE
/* Process a define_conditions directive, starting with the optional
space after the "define_conditions". The directive looks like this:
@@ -765,6 +812,7 @@ md_reader::read_conditions ()
add_c_test (expr, value);
}
}
+#endif /* #ifdef GENERATOR_FILE */
static void
validate_const_int (const char *string)
@@ -861,6 +909,8 @@ md_reader::record_potential_iterator_use (struct iterator_group *group,
}
}
+#ifdef GENERATOR_FILE
+
/* Finish reading a declaration of the form:
(define... <name> [<value1> ... <valuen>])
@@ -1020,15 +1070,6 @@ check_code_iterator (struct mapping *iterator)
bool
rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
{
- static bool initialized = false;
-
- /* Do one-time initialization. */
- if (!initialized)
- {
- initialize_iterators ();
- initialized = true;
- }
-
/* Handle various rtx-related declarations that aren't themselves
encoded as rtxes. */
if (strcmp (rtx_name, "define_conditions") == 0)
@@ -1082,6 +1123,103 @@ rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
return true;
}
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization. */
+
+static void
+one_time_initialization (void)
+{
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ initialize_iterators ();
+ initialized = true;
+ }
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+ consuming the terminator character if CONSUME_TERMINATOR is true.
+ Return all characters before the terminator as an allocated buffer. */
+
+char *
+rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
+{
+ int ch = read_skip_spaces ();
+ unread_char (ch);
+ auto_vec<char> buf;
+ while (1)
+ {
+ ch = read_char ();
+ if (strchr (terminator_chars, ch))
+ {
+ if (!consume_terminator)
+ unread_char (ch);
+ break;
+ }
+ buf.safe_push (ch);
+ }
+ buf.safe_push ('\0');
+ return xstrdup (buf.address ());
+}
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags. */
+
+static void
+read_flags (rtx return_rtx)
+{
+ while (1)
+ {
+ int ch = read_char ();
+ if (ch != '/')
+ {
+ unread_char (ch);
+ break;
+ }
+
+ int flag_char = read_char ();
+ switch (flag_char)
+ {
+ case 's':
+ RTX_FLAG (return_rtx, in_struct) = 1;
+ break;
+ case 'v':
+ RTX_FLAG (return_rtx, volatil) = 1;
+ break;
+ case 'u':
+ RTX_FLAG (return_rtx, unchanging) = 1;
+ break;
+ case 'f':
+ RTX_FLAG (return_rtx, frame_related) = 1;
+ break;
+ case 'j':
+ RTX_FLAG (return_rtx, jump) = 1;
+ break;
+ case 'c':
+ RTX_FLAG (return_rtx, call) = 1;
+ break;
+ case 'i':
+ RTX_FLAG (return_rtx, return_val) = 1;
+ break;
+ default:
+ fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+ }
+ }
+}
+
+/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+static int
+parse_reg_note_name (const char *string)
+{
+ for (int i = 0; i < REG_NOTE_MAX; i++)
+ if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
/* 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
return it. */
@@ -1090,11 +1228,12 @@ rtx
rtx_reader::read_rtx_code (const char *code_name)
{
RTX_CODE code;
- struct mapping *iterator;
+ struct mapping *iterator = NULL;
const char *format_ptr;
struct md_name name;
rtx return_rtx;
int c;
+ long reuse_id = -1;
/* Linked list structure for making RTXs: */
struct rtx_list
@@ -1103,13 +1242,37 @@ rtx_reader::read_rtx_code (const char *code_name)
rtx value; /* Value of this node. */
};
+ /* Handle reuse_rtx ids e.g. "(0|scratch:DI)". */
+ if (ISDIGIT (code_name[0]))
+ {
+ reuse_id = atoi (code_name);
+ while (char ch = *code_name++)
+ if (ch == '|')
+ break;
+ }
+
+ /* Handle "reuse_rtx". */
+ if (strcmp (code_name, "reuse_rtx") == 0)
+ {
+ read_name (&name);
+ long idx = atoi (name.string);
+ /* Look it up by ID. */
+ gcc_assert (idx < m_reuse_rtx_by_id.length ());
+ return_rtx = m_reuse_rtx_by_id[idx];
+ 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. */
return_rtx = rtx_alloc (code);
@@ -1117,9 +1280,36 @@ rtx_reader::read_rtx_code (const char *code_name)
memset (return_rtx, 0, RTX_CODE_SIZE (code));
PUT_CODE (return_rtx, code);
+ if (reuse_id != -1)
+ {
+ /* Store away for later reuse. */
+ m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1);
+ m_reuse_rtx_by_id[reuse_id] = return_rtx;
+ }
+
if (iterator)
record_iterator_use (iterator, return_rtx);
+ /* Check for flags. */
+ read_flags (return_rtx);
+
+ /* Read REG_NOTE names for EXPR_LIST and INSN_LIST. */
+ if ((GET_CODE (return_rtx) == EXPR_LIST
+ || GET_CODE (return_rtx) == INSN_LIST
+ || GET_CODE (return_rtx) == INT_LIST)
+ && !m_in_call_function_usage)
+ {
+ char ch = read_char ();
+ if (ch == ':')
+ {
+ read_name (&name);
+ PUT_MODE_RAW (return_rtx,
+ (machine_mode)parse_reg_note_name (name.string));
+ }
+ else
+ unread_char (ch);
+ }
+
/* If what follows is `: mode ', read it and
store the mode in the rtx. */
@@ -1132,8 +1322,19 @@ rtx_reader::read_rtx_code (const char *code_name)
else
unread_char (c);
+ if (INSN_CHAIN_CODE_P (code))
+ {
+ read_name (&name);
+ INSN_UID (return_rtx) = atoi (name.string);
+ }
+
+ /* Use the format_ptr to parse the various operands of this rtx. */
for (int idx = 0; format_ptr[idx] != 0; idx++)
- read_rtx_operand (return_rtx, idx);
+ return_rtx = read_rtx_operand (return_rtx, idx);
+
+ /* Handle any additional information that after the regular fields
+ (e.g. when parsing function dumps). */
+ handle_any_trailing_information (return_rtx);
if (CONST_WIDE_INT_P (return_rtx))
{
@@ -1197,9 +1398,11 @@ rtx_reader::read_rtx_code (const char *code_name)
/* Subroutine of read_rtx_code. Parse operand IDX within RETURN_RTX,
based on the corresponding format character within GET_RTX_FORMAT
- for the GET_CODE (RETURN_RTX). */
+ for the GET_CODE (RETURN_RTX), and return RETURN_RTX.
+ This is a virtual function, so that function_reader can override
+ some parsing, and potentially return a different rtx. */
-void
+rtx
rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
RTX_CODE code = GET_CODE (return_rtx);
@@ -1217,6 +1420,9 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
break;
case 'e':
+ XEXP (return_rtx, idx) = read_nested_rtx ();
+ break;
+
case 'u':
XEXP (return_rtx, idx) = read_nested_rtx ();
break;
@@ -1273,7 +1479,6 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
char *stringbuf;
int star_if_braced;
- struct obstack *string_obstack = get_string_obstack ();
c = read_skip_spaces ();
unread_char (c);
@@ -1293,7 +1498,10 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
star_if_braced = (format_ptr[idx] == 'T');
stringbuf = read_string (star_if_braced);
+ if (!stringbuf)
+ break;
+#ifdef GENERATOR_FILE
/* For insn patterns, we want to provide a default name
based on the file and line, like "*foo.md:12", if the
given name is blank. These are only for define_insn and
@@ -1303,6 +1511,7 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
&& (GET_CODE (return_rtx) == DEFINE_INSN
|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
{
+ struct obstack *string_obstack = get_string_obstack ();
char line_name[20];
const char *read_md_filename = get_filename ();
const char *fn = (read_md_filename ? read_md_filename : "rtx");
@@ -1348,11 +1557,14 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
if (m != 0)
record_iterator_use (m, return_rtx);
}
+#endif /* #ifdef GENERATOR_FILE */
+
+ const char *string_ptr = finalize_string (stringbuf);
if (star_if_braced)
- XTMPL (return_rtx, idx) = stringbuf;
+ XTMPL (return_rtx, idx) = string_ptr;
else
- XSTR (return_rtx, idx) = stringbuf;
+ XSTR (return_rtx, idx) = string_ptr;
}
break;
@@ -1398,6 +1610,8 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
default:
gcc_unreachable ();
}
+
+ return return_rtx;
}
/* Read a nested rtx construct from the MD file and return it. */
@@ -1408,6 +1622,11 @@ rtx_reader::read_nested_rtx ()
struct md_name name;
rtx return_rtx;
+ /* In compact dumps, trailing "(nil)" values can be omitted.
+ Handle such dumps. */
+ if (peek_char () == ')')
+ return NULL_RTX;
+
require_char_ws ('(');
read_name (&name);
@@ -1418,6 +1637,8 @@ rtx_reader::read_nested_rtx ()
require_char_ws (')');
+ return_rtx = postprocess (return_rtx);
+
return return_rtx;
}
@@ -1454,11 +1675,14 @@ rtx_reader::read_rtx_variadic (rtx form)
/* Constructor for class rtx_reader. */
-rtx_reader::rtx_reader ()
-: md_reader ()
+rtx_reader::rtx_reader (bool compact)
+: md_reader (compact),
+ m_in_call_function_usage (false)
{
/* Set the global singleton pointer. */
rtx_reader_ptr = this;
+
+ one_time_initialization ();
}
/* Destructor for class rtx_reader. */
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
index 8edddfb..bd918a7 100644
--- a/gcc/rtl-tests.c
+++ b/gcc/rtl-tests.c
@@ -200,6 +200,7 @@ test_single_set ()
static void
test_uncond_jump ()
{
+ set_new_first_and_last_insn (NULL, NULL);
rtx_insn *label = gen_label_rtx ();
rtx jump_pat = gen_rtx_SET (pc_rtx,
gen_rtx_LABEL_REF (VOIDmode,
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 7a44e3b..a9a63dc 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3665,7 +3665,9 @@ extern void init_varasm_once (void);
extern rtx make_debug_expr_from_rtl (const_rtx);
/* In read-rtl.c */
+#ifdef GENERATOR_FILE
extern bool read_rtx (const char *, vec<rtx> *);
+#endif
/* In alias.c */
extern rtx canon_rtx (rtx);
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
new file mode 100644
index 0000000..41206c3
--- /dev/null
+++ b/gcc/selftest-rtl.c
@@ -0,0 +1,77 @@
+/* Selftest support for RTL.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "read-rtl-function.h"
+#include "read-md.h"
+#include "tree-core.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "selftest-rtl.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Constructor for selftest::rtl_dump_test.
+ Read a dumped RTL function from PATH.
+ Takes ownership of PATH, freeing in dtor.
+ Use LOC as the effective location when reporting failures. */
+
+rtl_dump_test::rtl_dump_test (const location &loc, char *path)
+ : m_path (path)
+{
+ bool read_ok = read_rtl_function_body (path);
+ ASSERT_TRUE_AT (loc, read_ok);
+}
+
+/* Destructor for selftest::rtl_dump_test.
+ Cleanup global state relating to the function, and free the path. */
+
+selftest::rtl_dump_test::~rtl_dump_test ()
+{
+ /* Cleanups. */
+ current_function_decl = NULL;
+ free_after_compilation (cfun);
+ set_cfun (NULL);
+ free (m_path);
+}
+
+/* Get the insn with the given uid, or NULL if not found. */
+
+rtx_insn *
+get_insn_by_uid (int uid)
+{
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_UID (insn) == uid)
+ return insn;
+
+ /* Not found. */
+ return NULL;
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
index f505018..accb486 100644
--- a/gcc/selftest-rtl.h
+++ b/gcc/selftest-rtl.h
@@ -47,6 +47,23 @@ assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x,
assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX), \
(REUSE_MANAGER))
+/* A class for testing RTL function dumps. */
+
+class rtl_dump_test
+{
+ public:
+ /* Takes ownership of PATH. */
+ rtl_dump_test (const location &loc, char *path);
+ ~rtl_dump_test ();
+
+ private:
+ char *m_path;
+};
+
+/* Get the insn with the given uid, or NULL if not found. */
+
+extern rtx_insn *get_insn_by_uid (int uid);
+
} /* end of namespace selftest. */
#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index c1cd97e..bf2b84a 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -72,6 +72,7 @@ selftest::run_tests ()
tree_c_tests ();
gimple_c_tests ();
rtl_tests_c_tests ();
+ read_rtl_function_c_tests ();
/* Higher-level tests, or for components that other selftests don't
rely on. */
diff --git a/gcc/selftest.h b/gcc/selftest.h
index c390873..d5afa6d 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -184,6 +184,7 @@ extern void hash_map_tests_c_tests ();
extern void hash_set_tests_c_tests ();
extern void input_c_tests ();
extern void pretty_print_c_tests ();
+extern void read_rtl_function_c_tests ();
extern void rtl_tests_c_tests ();
extern void selftest_c_tests ();
extern void spellcheck_c_tests ();
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0396feb..7ec62db 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -305,6 +305,11 @@ ssa_default_def (struct function *fn, tree var)
gcc_assert (VAR_P (var)
|| TREE_CODE (var) == PARM_DECL
|| TREE_CODE (var) == RESULT_DECL);
+
+ /* Always NULL_TREE for rtl function dumps. */
+ if (!fn->gimple_df)
+ return NULL_TREE;
+
in.var = (tree)&ind;
ind.uid = DECL_UID (var);
return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8a/9] Introduce class function_reader (v7)
2016-12-02 18:12 ` [PATCH 8a/9] Introduce class function_reader (v7) David Malcolm
@ 2016-12-02 18:58 ` Bernd Schmidt
2016-12-08 2:29 ` [PATCH] Avoid double unread_char (c) in patch 8a of RTL frontend David Malcolm
2016-12-08 20:06 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b David Malcolm
1 sibling, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-02 18:58 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/02/2016 07:44 PM, David Malcolm wrote:
> The two flag assignments don't seem to be needed; I think this is due
> to adding:
>
> if (node->native_rtl_p ())
> node->force_output = 1;
>
> to cgraph_node::finalize_function in patch 9.
>
> Should I lose them (and the comment)?
Let's keep this patch self-contained and not dependent on #9. So, leave
them in for now.
I think we can call this one OK for now (the orig_reg thing needs fixing
and we'll probably want to do something about making locations optional,
but all that can be done later).
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Avoid double unread_char (c) in patch 8a of RTL frontend
2016-12-02 18:58 ` Bernd Schmidt
@ 2016-12-08 2:29 ` David Malcolm
2016-12-08 15:16 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-08 2:29 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
The RTL frontend patch kit failed to build on powerpc-ibm-aix7.1.3.0
(gcc111), with this error:
build/genmddeps ../../src/gcc/common.md ../../src/gcc/config/rs6000/rs6000.md > tmp-mddeps
../../src/gcc/config/rs6000/rs6000.md:2255:1: unterminated construct
due to the final close paren on line 2259 of rs6000.md:
2259 (and:GPR (match_dup 1)
not being detected by read_skip_construct.
Bisecting the patch kit, it appears to be due to this hunk in patch 8a:
@@ -463,8 +481,12 @@ md_reader::read_name (struct md_name *name)
c = read_char ();
}
+ unread_char (c);
+ *out_loc = get_current_location ();
+ read_char ();
+
It appears that this can lead to unread_char (c) being called twice
for the same c, followed by a read_char () (i.e. the 2nd call to
unread_char passes the wrong character back). Given that unread_char
is a wrapper around libc's ungetc, I *think* this is showing up a
difference between glibc and AIX's libc implementation (and possibly
a reliance on undefined behavior).
The attached tweak to patch 8a simplifies the function, eliminating
these calls, by using the start of the name for the location, rather
than the end.
It fixes the build of the kit on powerpc-ibm-aix7.1.3.0
(and continues to build correctly on x86_64-pc-linux-gnu).
gcc/ChangeLog:
* read-md.c (md_reader::read_name_1): Write out the location of
the start of the name, rather than the end, eliminating
unread_char and read_char calls.
---
gcc/read-md.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/gcc/read-md.c b/gcc/read-md.c
index e581326..ad61cdd 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -461,6 +461,8 @@ md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
c = read_skip_spaces ();
+ *out_loc = get_current_location ();
+
i = 0;
angle_bracket_depth = 0;
while (1)
@@ -491,10 +493,6 @@ md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
c = read_char ();
}
- unread_char (c);
- *out_loc = get_current_location ();
- read_char ();
-
if (i == 0)
return false;
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Avoid double unread_char (c) in patch 8a of RTL frontend
2016-12-08 2:29 ` [PATCH] Avoid double unread_char (c) in patch 8a of RTL frontend David Malcolm
@ 2016-12-08 15:16 ` Bernd Schmidt
0 siblings, 0 replies; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-08 15:16 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/08/2016 04:01 AM, David Malcolm wrote:
> gcc/ChangeLog:
> * read-md.c (md_reader::read_name_1): Write out the location of
> the start of the name, rather than the end, eliminating
> unread_char and read_char calls.
For avoidance of doubt, ok to check in the currently approved patches
with this change as well.
>
> - unread_char (c);
> - *out_loc = get_current_location ();
> - read_char ();
Might be worth trying to look for this pattern in other parts of the
patch kit to see if it can be replaced.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Fix bug in MEM parsing in patches 8a/8b
2016-12-02 18:12 ` [PATCH 8a/9] Introduce class function_reader (v7) David Malcolm
2016-12-02 18:58 ` Bernd Schmidt
@ 2016-12-08 20:06 ` David Malcolm
2016-12-08 20:08 ` Bernd Schmidt
2016-12-19 22:15 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b Jeff Law
1 sibling, 2 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-08 20:06 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
Testing the patch kit on i686 showed numerous failures of this
assertion in set_mem_attributes_minus_bitpos in emit-rtl.c:
1821 gcc_assert (!defattrs->offset_known_p);
when expanding "main" in the rtl.exp test files, after parsing
an __RTL-tagged function.
Root cause is various assignments within the RTL parser of the
form:
1222 MEM_OFFSET (x) = atoi (name.string);
where a MEM_* macro appears on the left-hand side of an assignment.
These macros are defined as a field lookup on the result of a call
to get_mem_attrs, e.g.:
#define MEM_OFFSET(RTX) (get_mem_attrs (RTX)->offset)
get_mem_attrs can return the struct mem_attrs * of an rtx, but if
it isn't set, it returns:
mode_mem_attrs[(int) GET_MODE (x)];
which is this field within struct GTY(()) target_rtl:
/* The default memory attributes for each mode. */
struct mem_attrs *x_mode_mem_attrs[(int) MAX_MACHINE_MODE];
These assignments in the parser were erroneously writing to these
default per-mode values, rather than assigning to a unique-per-rtx
instance of struct mem_attrs.
The fix is to call the appropriate set_mem_ functions in the
parser, e.g. set_mem_offset; the patch below is intended as a tweak
to patch 8a of the kit, and would be merged with it before committing.
The patch also adds extra test coverage for MEM parsing. This extends
the target-independent selftests, and so would go into patch 8b.
Tested for targets x86_64-pc-linux-gnu, i686-pc-linux-gnu,
and aarch64-linux-gnu, and on powerpc-ibm-aix7.1.3.0.
OK as adjustments to patches 8a and 8b?
For patch 8a:
gcc/ChangeLog:
* read-rtl-function.c
(function_reader::handle_any_trailing_information): Replace writes
through macros MEM_ALIAS_SET, MEM_OFFSET, MEM_SIZE, MEM_ALIGN,
and MEM_ADDR_SPACE with calls to set_mem_ functions. Add missing
call to unread_char when handling "A" for alignment.
For patch 8b:
gcc/ChangeLog:
* read-rtl-function.c (selftest::test_loading_mem): New function.
(selftest::read_rtl_function_c_tests): Call it.
gcc/testsuite/ChangeLog:
* selftests/mem.rtl: New file.
---
gcc/read-rtl-function.c | 55 ++++++++++++++++++++++++++++++++++++-----
gcc/testsuite/selftests/mem.rtl | 9 +++++++
2 files changed, 58 insertions(+), 6 deletions(-)
create mode 100644 gcc/testsuite/selftests/mem.rtl
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index 5188b86..c3f5c64 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -1201,7 +1201,7 @@ function_reader::handle_any_trailing_information (rtx x)
int ch;
require_char_ws ('[');
read_name (&name);
- MEM_ALIAS_SET (x) = atoi (name.string);
+ set_mem_alias_set (x, atoi (name.string));
/* We have either a MEM_EXPR, or a space. */
if (peek_char () != ' ')
{
@@ -1218,8 +1218,7 @@ function_reader::handle_any_trailing_information (rtx x)
if (ch == '+')
{
read_name (&name);
- MEM_OFFSET_KNOWN_P (x) = 1;
- MEM_OFFSET (x) = atoi (name.string);
+ set_mem_offset (x, atoi (name.string));
}
else
unread_char (ch);
@@ -1229,7 +1228,7 @@ function_reader::handle_any_trailing_information (rtx x)
if (ch == 'S')
{
read_name (&name);
- MEM_SIZE (x) = atoi (name.string);
+ set_mem_size (x, atoi (name.string));
}
else
unread_char (ch);
@@ -1239,8 +1238,10 @@ function_reader::handle_any_trailing_information (rtx x)
if (ch == 'A' && peek_char () != 'S')
{
read_name (&name);
- MEM_ALIGN (x) = atoi (name.string);
+ set_mem_align (x, atoi (name.string));
}
+ else
+ unread_char (ch);
/* Handle optional " AS" for MEM_ADDR_SPACE. */
ch = read_skip_spaces ();
@@ -1248,7 +1249,7 @@ function_reader::handle_any_trailing_information (rtx x)
{
read_char ();
read_name (&name);
- MEM_ADDR_SPACE (x) = atoi (name.string);
+ set_mem_addr_space (x, atoi (name.string));
}
else
unread_char (ch);
@@ -2102,6 +2103,47 @@ test_loading_bb_index ()
ASSERT_EQ (42, bb42->index);
}
+/* Verify that function_reader::handle_any_trailing_information correctly
+ parses all the possible items emitted for a MEM. */
+
+static void
+test_loading_mem ()
+{
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("mem.rtl"));
+
+ ASSERT_STREQ ("test_mem", IDENTIFIER_POINTER (DECL_NAME (cfun->decl)));
+ ASSERT_TRUE (cfun);
+
+ /* Verify parsing of "[42 i+17 S8 A128 AS5]". */
+ rtx_insn *insn_1 = get_insn_by_uid (1);
+ rtx set1 = single_set (insn_1);
+ rtx mem1 = SET_DEST (set1);
+ ASSERT_EQ (42, MEM_ALIAS_SET (mem1));
+ /* "+17". */
+ ASSERT_TRUE (MEM_OFFSET_KNOWN_P (mem1));
+ ASSERT_EQ (17, MEM_OFFSET (mem1));
+ /* "S8". */
+ ASSERT_EQ (8, MEM_SIZE (mem1));
+ /* "A128. */
+ ASSERT_EQ (128, MEM_ALIGN (mem1));
+ /* "AS5. */
+ ASSERT_EQ (5, MEM_ADDR_SPACE (mem1));
+
+ /* Verify parsing of "43 i+18 S9 AS6"
+ (an address space without an alignment). */
+ rtx_insn *insn_2 = get_insn_by_uid (2);
+ rtx set2 = single_set (insn_2);
+ rtx mem2 = SET_DEST (set2);
+ ASSERT_EQ (43, MEM_ALIAS_SET (mem2));
+ /* "+18". */
+ ASSERT_TRUE (MEM_OFFSET_KNOWN_P (mem2));
+ ASSERT_EQ (18, MEM_OFFSET (mem2));
+ /* "S9". */
+ ASSERT_EQ (9, MEM_SIZE (mem2));
+ /* "AS6. */
+ ASSERT_EQ (6, MEM_ADDR_SPACE (mem2));
+}
+
/* Run all of the selftests within this file. */
void
@@ -2122,6 +2164,7 @@ read_rtl_function_c_tests ()
test_loading_symbol_ref ();
test_loading_cfg ();
test_loading_bb_index ();
+ test_loading_mem ();
}
} // namespace selftest
diff --git a/gcc/testsuite/selftests/mem.rtl b/gcc/testsuite/selftests/mem.rtl
new file mode 100644
index 0000000..9261d79
--- /dev/null
+++ b/gcc/testsuite/selftests/mem.rtl
@@ -0,0 +1,9 @@
+(function "test_mem"
+ (insn-chain
+ (block 2
+ ;; Various nonsensical values, to exercise the parser:
+ (cinsn 1 (set (mem:SI (reg:SI %10) [42 i+17 S8 A128 AS5]) (reg:SI %1)))
+ (cinsn 2 (set (mem:SI (reg:SI %11) [43 i+18 S9 AS6]) (reg:SI %2)))
+ ) ;; block 6
+ ) ;; insn-chain
+) ;; function
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Fix bug in MEM parsing in patches 8a/8b
2016-12-08 20:06 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b David Malcolm
@ 2016-12-08 20:08 ` Bernd Schmidt
2016-12-09 1:29 ` [PATCH] Prevent use of MEM_* attr accessor macros as lvalues David Malcolm
2016-12-19 22:15 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b Jeff Law
1 sibling, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-08 20:08 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/08/2016 09:39 PM, David Malcolm wrote:
>
> OK as adjustments to patches 8a and 8b?
Ok. Is it possible to adjust these macros to return something like a
const reference to ensure people can't make this kind of error?
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Prevent use of MEM_* attr accessor macros as lvalues
2016-12-08 20:08 ` Bernd Schmidt
@ 2016-12-09 1:29 ` David Malcolm
2016-12-09 1:32 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-09 1:29 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
On Thu, 2016-12-08 at 21:08 +0100, Bernd Schmidt wrote:
> On 12/08/2016 09:39 PM, David Malcolm wrote:
> >
> > OK as adjustments to patches 8a and 8b?
>
> Ok. Is it possible to adjust these macros to return something like a
> const reference to ensure people can't make this kind of error?
>
>
> Bernd
The following patch leads to errors like this for that kind
of mistake:
error: assignment of member 'mem_attrs::offset' in read-only object
MEM_OFFSET (x) = atoi (name.string);
^
Successfully bootstrapped®rtested on x86_64-pc-linux-gnu.
OK for trunk?
gcc/ChangeLog:
* rtl.h (get_mem_attrs): Add "const" qualifier to returned
pointer.
---
gcc/rtl.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index a5efa28..4f0efa6 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3355,7 +3355,7 @@ extern struct target_rtl *this_target_rtl;
#ifndef GENERATOR_FILE
/* Return the attributes of a MEM rtx. */
-static inline struct mem_attrs *
+static inline const struct mem_attrs *
get_mem_attrs (const_rtx x)
{
struct mem_attrs *attrs;
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Fix bug in MEM parsing in patches 8a/8b
2016-12-08 20:06 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b David Malcolm
2016-12-08 20:08 ` Bernd Schmidt
@ 2016-12-19 22:15 ` Jeff Law
2016-12-19 23:02 ` David Malcolm
1 sibling, 1 reply; 78+ messages in thread
From: Jeff Law @ 2016-12-19 22:15 UTC (permalink / raw)
To: David Malcolm, Bernd Schmidt, gcc-patches
On 12/08/2016 01:39 PM, David Malcolm wrote:
> Testing the patch kit on i686 showed numerous failures of this
> assertion in set_mem_attributes_minus_bitpos in emit-rtl.c:
>
> 1821 gcc_assert (!defattrs->offset_known_p);
>
> when expanding "main" in the rtl.exp test files, after parsing
> an __RTL-tagged function.
>
> Root cause is various assignments within the RTL parser of the
> form:
>
> 1222 MEM_OFFSET (x) = atoi (name.string);
>
> where a MEM_* macro appears on the left-hand side of an assignment.
>
> These macros are defined as a field lookup on the result of a call
> to get_mem_attrs, e.g.:
>
> #define MEM_OFFSET(RTX) (get_mem_attrs (RTX)->offset)
>
> get_mem_attrs can return the struct mem_attrs * of an rtx, but if
> it isn't set, it returns:
> mode_mem_attrs[(int) GET_MODE (x)];
>
> which is this field within struct GTY(()) target_rtl:
> /* The default memory attributes for each mode. */
> struct mem_attrs *x_mode_mem_attrs[(int) MAX_MACHINE_MODE];
>
> These assignments in the parser were erroneously writing to these
> default per-mode values, rather than assigning to a unique-per-rtx
> instance of struct mem_attrs.
>
> The fix is to call the appropriate set_mem_ functions in the
> parser, e.g. set_mem_offset; the patch below is intended as a tweak
> to patch 8a of the kit, and would be merged with it before committing.
>
> The patch also adds extra test coverage for MEM parsing. This extends
> the target-independent selftests, and so would go into patch 8b.
>
> Tested for targets x86_64-pc-linux-gnu, i686-pc-linux-gnu,
> and aarch64-linux-gnu, and on powerpc-ibm-aix7.1.3.0.
>
> OK as adjustments to patches 8a and 8b?
>
> For patch 8a:
> gcc/ChangeLog:
> * read-rtl-function.c
> (function_reader::handle_any_trailing_information): Replace writes
> through macros MEM_ALIAS_SET, MEM_OFFSET, MEM_SIZE, MEM_ALIGN,
> and MEM_ADDR_SPACE with calls to set_mem_ functions. Add missing
> call to unread_char when handling "A" for alignment.
>
> For patch 8b:
> gcc/ChangeLog:
> * read-rtl-function.c (selftest::test_loading_mem): New function.
> (selftest::read_rtl_function_c_tests): Call it.
> gcc/testsuite/ChangeLog:
> * selftests/mem.rtl: New file.
They seem like reasonable adjustments.
I know you posted the cc1 patches to add the RTL front-end. What's the
status on this kit?
[ Yes, I keep falling behind... ]
jeff
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH] Fix bug in MEM parsing in patches 8a/8b
2016-12-19 22:15 ` [PATCH] Fix bug in MEM parsing in patches 8a/8b Jeff Law
@ 2016-12-19 23:02 ` David Malcolm
0 siblings, 0 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-19 23:02 UTC (permalink / raw)
To: Jeff Law, Bernd Schmidt, gcc-patches
On Mon, 2016-12-19 at 15:10 -0700, Jeff Law wrote:
> On 12/08/2016 01:39 PM, David Malcolm wrote:
> > Testing the patch kit on i686 showed numerous failures of this
> > assertion in set_mem_attributes_minus_bitpos in emit-rtl.c:
> >
> > 1821 gcc_assert (!defattrs->offset_known_p);
> >
> > when expanding "main" in the rtl.exp test files, after parsing
> > an __RTL-tagged function.
> >
> > Root cause is various assignments within the RTL parser of the
> > form:
> >
> > 1222 MEM_OFFSET (x) = atoi (name.string);
> >
> > where a MEM_* macro appears on the left-hand side of an assignment.
> >
> > These macros are defined as a field lookup on the result of a call
> > to get_mem_attrs, e.g.:
> >
> > #define MEM_OFFSET(RTX) (get_mem_attrs (RTX)->offset)
> >
> > get_mem_attrs can return the struct mem_attrs * of an rtx, but if
> > it isn't set, it returns:
> > mode_mem_attrs[(int) GET_MODE (x)];
> >
> > which is this field within struct GTY(()) target_rtl:
> > /* The default memory attributes for each mode. */
> > struct mem_attrs *x_mode_mem_attrs[(int) MAX_MACHINE_MODE];
> >
> > These assignments in the parser were erroneously writing to these
> > default per-mode values, rather than assigning to a unique-per-rtx
> > instance of struct mem_attrs.
> >
> > The fix is to call the appropriate set_mem_ functions in the
> > parser, e.g. set_mem_offset; the patch below is intended as a tweak
> > to patch 8a of the kit, and would be merged with it before
> > committing.
> >
> > The patch also adds extra test coverage for MEM parsing. This
> > extends
> > the target-independent selftests, and so would go into patch 8b.
> >
> > Tested for targets x86_64-pc-linux-gnu, i686-pc-linux-gnu,
> > and aarch64-linux-gnu, and on powerpc-ibm-aix7.1.3.0.
> >
> > OK as adjustments to patches 8a and 8b?
> >
> > For patch 8a:
> > gcc/ChangeLog:
> > * read-rtl-function.c
> > (function_reader::handle_any_trailing_information): Replace
> > writes
> > through macros MEM_ALIAS_SET, MEM_OFFSET, MEM_SIZE, MEM_ALIGN,
> > and MEM_ADDR_SPACE with calls to set_mem_ functions. Add
> > missing
> > call to unread_char when handling "A" for alignment.
> >
> > For patch 8b:
> > gcc/ChangeLog:
> > * read-rtl-function.c (selftest::test_loading_mem): New
> > function.
> > (selftest::read_rtl_function_c_tests): Call it.
> > gcc/testsuite/ChangeLog:
> > * selftests/mem.rtl: New file.
> They seem like reasonable adjustments.
>
> I know you posted the cc1 patches to add the RTL front-end. What's
> the
> status on this kit?
>
> [ Yes, I keep falling behind... ]
Current status of RTL frontend patch kit:
In summary: patch 8d and patch 9 need review.
In detail:
* patches 1-6 of the kit are committed to trunk
* patch 7 (in extremely minimal form) has been approved, merged into
patch 8a.
* patch 8 (adding function_reader class, and selftests to verify it
works) split into four subpatches, not yet in trunk:
* patches 8a, 8b, and 8c are approved (the reader itself, selftests
for it that don't depend on any target, and selftests that are aarch64
-specific)
* patches 8d isn't approved yet; I reposted this today as:
* "[PATCH] Add x86_64-specific selftests for RTL function reader
(v2)"
https://gcc.gnu.org/ml/gcc-patches/2016-12/msg01616.html
* I'm successfully run config-list.mk testing across 191 targets to
verify that these selftests don't break the build for anything (there
was some snafu with our dump syntax for pseudos conflicting with hard
reg names on iq2000, but this is resolved now)
* my plan is to commit 8a-8d as one combined patch once 8d is
approved (assuming it is)
* patch 9 (wiring it up into cc1) needs review:
* "[PATCH] Add "__RTL" to cc1 (v7)"
* https://gcc.gnu.org/ml/gcc-patches/2016-12/msg01662.html
Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 8/9] Introduce class function_reader (v4)
2016-12-01 21:43 ` David Malcolm
2016-12-02 1:27 ` [PATCH 8a/9] Introduce class function_reader (v6) David Malcolm
@ 2016-12-02 15:28 ` Bernd Schmidt
2016-12-02 19:51 ` [PATCH] Add ASSERT_RTX_PTR_EQ David Malcolm
1 sibling, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-02 15:28 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/01/2016 10:43 PM, David Malcolm wrote:
>>> + rtx_insn *jump_insn = get_insn_by_uid (1);
>>> + ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
>>> + ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
>>> + // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
>>
>> Why is this a fixme and not just done that way (several instances)?
>
> ASSERT_RTX_PTR_EQ doesn't exist yet; there was some discussion about it
> in earlier versions of the patch, but I haven't written it. It would
> be equivalent to ASSERT_EQ, checking pointer equality, but would dump
> the mismatching expected vs actual rtx on failure.
>
> Should I convert this to a TODO, or go ahead and implement
> ASSERT_RTX_PTR_EQ?
Missed this question. Just add ASSERT_RTX_PTR_EQ, that shouldn't be
hard, should it?
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH] Add ASSERT_RTX_PTR_EQ
2016-12-02 15:28 ` [PATCH 8/9] Introduce class function_reader (v4) Bernd Schmidt
@ 2016-12-02 19:51 ` David Malcolm
2016-12-06 12:09 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-02 19:51 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: David Malcolm
On Fri, 2016-12-02 at 16:28 +0100, Bernd Schmidt wrote:
> On 12/01/2016 10:43 PM, David Malcolm wrote:
> > > > + rtx_insn *jump_insn = get_insn_by_uid (1);
> > > > + ASSERT_EQ (JUMP_INSN, GET_CODE (jump_insn));
> > > > + ASSERT_EQ (ret_rtx, JUMP_LABEL (jump_insn));
> > > > + // FIXME: ^^^ use ASSERT_RTX_PTR_EQ here ^^^
> > >
> > > Why is this a fixme and not just done that way (several
> > > instances)?
> >
> > ASSERT_RTX_PTR_EQ doesn't exist yet; there was some discussion
> > about it
> > in earlier versions of the patch, but I haven't written it. It
> > would
> > be equivalent to ASSERT_EQ, checking pointer equality, but would
> > dump
> > the mismatching expected vs actual rtx on failure.
> >
> > Should I convert this to a TODO, or go ahead and implement
> > ASSERT_RTX_PTR_EQ?
>
> Missed this question. Just add ASSERT_RTX_PTR_EQ, that shouldn't be
> hard, should it?
>
>
> Bernd
This patch implements an ASSERT_RTX_PTR_EQ macro, like ASSERT_EQ,
but which dumps both rtx to stderr if the assertion fails.
gcc/ChangeLog:
* selftest-rtl.c (selftest::assert_rtx_ptr_eq_at): New function.
* selftest-rtl.h (ASSERT_RTX_PTR_EQ): New macro.
---
gcc/selftest-rtl.c | 23 +++++++++++++++++++++++
gcc/selftest-rtl.h | 18 ++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/gcc/selftest-rtl.c b/gcc/selftest-rtl.c
index 20e6550..c14db43 100644
--- a/gcc/selftest-rtl.c
+++ b/gcc/selftest-rtl.c
@@ -36,6 +36,29 @@ along with GCC; see the file COPYING3. If not see
namespace selftest {
+/* Compare rtx EXPECTED and ACTUAL by pointer equality, calling
+ ::selftest::pass if they are equal, aborting if they are non-equal.
+ LOC is the effective location of the assertion, MSG describes it. */
+
+void
+assert_rtx_ptr_eq_at (const location &loc, const char *msg,
+ rtx expected, rtx actual)
+{
+ if (expected == actual)
+ ::selftest::pass (loc, msg);
+ else
+ {
+ fprintf (stderr, "%s:%i: %s: FAIL: %s\n", loc.m_file, loc.m_line,
+ loc.m_function, msg);
+ fprintf (stderr, " expected (at %p): ", (void *)expected);
+ print_rtl (stderr, expected);
+ fprintf (stderr, "\n actual (at %p): ", (void *)actual);
+ print_rtl (stderr, actual);
+ fprintf (stderr, "\n");
+ abort ();
+ }
+}
+
/* Constructor for selftest::rtl_dump_test.
Read a dumped RTL function from PATH.
Takes ownership of PATH, freeing in dtor.
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
index 35d6437..cb2772d 100644
--- a/gcc/selftest-rtl.h
+++ b/gcc/selftest-rtl.h
@@ -47,6 +47,24 @@ assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x,
assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX), \
(REUSE_MANAGER))
+/* Evaluate rtx EXPECTED and ACTUAL and compare them with ==
+ (i.e. pointer equality), calling ::selftest::pass if they are
+ equal, aborting if they are non-equal. */
+
+#define ASSERT_RTX_PTR_EQ(EXPECTED, ACTUAL) \
+ SELFTEST_BEGIN_STMT \
+ const char *desc = "ASSERT_RTX_PTR_EQ (" #EXPECTED ", " #ACTUAL ")"; \
+ ::selftest::assert_rtx_ptr_eq_at (SELFTEST_LOCATION, desc, (EXPECTED), \
+ (ACTUAL)); \
+ SELFTEST_END_STMT
+
+/* Compare rtx EXPECTED and ACTUAL by pointer equality, calling
+ ::selftest::pass if they are equal, aborting if they are non-equal.
+ LOC is the effective location of the assertion, MSG describes it. */
+
+extern void assert_rtx_ptr_eq_at (const location &loc, const char *msg,
+ rtx expected, rtx actual);
+
/* A class for testing RTL function dumps. */
class rtl_dump_test
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/9] print_rtx: implement support for reuse IDs (v2)
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
` (5 preceding siblings ...)
2016-11-11 20:44 ` [PATCH 8/9] Introduce class function_reader (v4) David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-12-01 23:05 ` Jeff Law
2016-11-11 20:44 ` [PATCH 5/9] Introduce selftest::locate_file (v4) David Malcolm
2016-11-11 20:44 ` [PATCH 6/9] Split class rtx_reader into md_reader vs rtx_reader David Malcolm
8 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Posted earlier here:
https://gcc.gnu.org/ml/gcc-patches/2016-11/msg00651.html
Link to earlier discussion:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg01801.html
This version:
- eliminates the rtx_reuse_manager singleton
- eliminates print-rtl-reuse.h, moving class rtx_reuse_manager into
print-rtl.h and print-rtl.c
- fixes the formatting issues you noted in the earlier patch
gcc/ChangeLog:
* config/i386/i386.c: Include print-rtl.h.
(selftest::ix86_test_dumping_memory_blockage): New function.
(selftest::ix86_run_selftests): Call it.
* print-rtl-function.c (print_rtx_function): Create an
rtx_reuse_manager and use it.
* print-rtl.c: Include "rtl-iter.h".
(rtx_writer::rtx_writer): Add reuse_manager param.
(rtx_reuse_manager::rtx_reuse_manager): New ctor.
(uses_rtx_reuse_p): New function.
(rtx_reuse_manager::preprocess): New function.
(rtx_reuse_manager::has_reuse_id): New function.
(rtx_reuse_manager::seen_def_p): New function.
(rtx_reuse_manager::set_seen_def): New function.
(rtx_writer::print_rtx): If "in_rtx" has a reuse ID, print it as a
prefix the first time in_rtx is seen, and print reuse_rtx
subsequently.
(print_inline_rtx): Supply NULL for new reuse_manager param.
(debug_rtx): Likewise.
(print_rtl): Likewise.
(print_rtl_single): Likewise.
(rtx_writer::print_rtl_single_with_indent): Likewise.
* print-rtl.h: Include bitmap.h when building for host.
(rtx_writer::rtx_writer): Add reuse_manager param.
(rtx_writer::m_rtx_reuse_manager): New field.
(class rtx_reuse_manager): New class.
* rtl-tests.c (selftest::assert_rtl_dump_eq): Add reuse_manager
param and use it when constructing rtx_writer.
(selftest::test_dumping_rtx_reuse): New function.
(selftest::rtl_tests_c_tests): Call it.
* selftest-rtl.h (class rtx_reuse_manager): New forward decl.
(selftest::assert_rtl_dump_eq): Add reuse_manager param.
(ASSERT_RTL_DUMP_EQ): Supply NULL for reuse_manager param.
(ASSERT_RTL_DUMP_EQ_WITH_REUSE): New macro.
---
gcc/config/i386/i386.c | 24 ++++++++
gcc/print-rtl-function.c | 7 ++-
gcc/print-rtl.c | 139 +++++++++++++++++++++++++++++++++++++++++++----
gcc/print-rtl.h | 81 ++++++++++++++++++++++++++-
gcc/rtl-tests.c | 53 +++++++++++++++++-
gcc/selftest-rtl.h | 13 ++++-
6 files changed, 300 insertions(+), 17 deletions(-)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index a5c4ba7..6c608e0 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssanames.h"
#include "selftest.h"
#include "selftest-rtl.h"
+#include "print-rtl.h"
/* This file should be included last. */
#include "target-def.h"
@@ -50649,12 +50650,35 @@ ix86_test_dumping_hard_regs ()
ASSERT_RTL_DUMP_EQ ("(reg:SI dx)", gen_raw_REG (SImode, 1));
}
+/* Test dumping an insn with repeated references to the same SCRATCH,
+ to verify the rtx_reuse code. */
+
+static void
+ix86_test_dumping_memory_blockage ()
+{
+ set_new_first_and_last_insn (NULL, NULL);
+
+ rtx pat = gen_memory_blockage ();
+ rtx_reuse_manager r;
+ r.preprocess (pat);
+
+ /* Verify that the repeated references to the SCRATCH show use
+ reuse IDS. The first should be prefixed with a reuse ID,
+ and the second should be dumped as a "reuse_rtx" of that ID. */
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE
+ ("(cinsn 1 (set (mem/v:BLK (0|scratch:DI) [0 A8])\n"
+ " (unspec:BLK [\n"
+ " (mem/v:BLK (reuse_rtx 0) [0 A8])\n"
+ " ] UNSPEC_MEMORY_BLOCKAGE)))\n", pat, &r);
+}
+
/* Run all target-specific selftests. */
static void
ix86_run_selftests (void)
{
ix86_test_dumping_hard_regs ();
+ ix86_test_dumping_memory_blockage ();
}
} // namespace selftest
diff --git a/gcc/print-rtl-function.c b/gcc/print-rtl-function.c
index 8842226..dea84fe 100644
--- a/gcc/print-rtl-function.c
+++ b/gcc/print-rtl-function.c
@@ -221,7 +221,12 @@ print_param (FILE *outfile, rtx_writer &w, tree arg)
DEBUG_FUNCTION void
print_rtx_function (FILE *outfile, function *fn, bool compact)
{
- rtx_writer w (outfile, 0, false, compact);
+ rtx_reuse_manager r;
+ rtx_writer w (outfile, 0, false, compact, &r);
+
+ /* Support "reuse_rtx" in the dump. */
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ r.preprocess (insn);
tree fdecl = fn->decl;
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index e7368c7..3bbd395 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see
#endif
#include "print-rtl.h"
+#include "rtl-iter.h"
/* String printed at beginning of each RTL when it is dumped.
This string is set to ASM_COMMENT_START when the RTL is dumped in
@@ -74,13 +75,103 @@ int flag_dump_unnumbered_links = 0;
/* Constructor for rtx_writer. */
-rtx_writer::rtx_writer (FILE *outf, int ind, bool simple, bool compact)
+rtx_writer::rtx_writer (FILE *outf, int ind, bool simple, bool compact,
+ rtx_reuse_manager *reuse_manager)
: m_outfile (outf), m_sawclose (0), m_indent (ind),
- m_in_call_function_usage (false), m_simple (simple), m_compact (compact)
+ m_in_call_function_usage (false), m_simple (simple), m_compact (compact),
+ m_rtx_reuse_manager (reuse_manager)
{
}
#ifndef GENERATOR_FILE
+
+/* rtx_reuse_manager's ctor. */
+
+rtx_reuse_manager::rtx_reuse_manager ()
+: m_next_id (0)
+{
+ bitmap_initialize (&m_defs_seen, NULL);
+}
+
+/* Determine if X is of a kind suitable for dumping via reuse_rtx. */
+
+static bool
+uses_rtx_reuse_p (const_rtx x)
+{
+ if (x == NULL)
+ return false;
+
+ switch (GET_CODE (x))
+ {
+ case DEBUG_EXPR:
+ case VALUE:
+ case SCRATCH:
+ return true;
+
+ /* We don't use reuse_rtx for consts. */
+ CASE_CONST_UNIQUE:
+ default:
+ return false;
+ }
+}
+
+/* Traverse X and its descendents, determining if we see any rtx more than
+ once. Any rtx suitable for "reuse_rtx" that is seen more than once is
+ assigned an ID. */
+
+void
+rtx_reuse_manager::preprocess (const_rtx x)
+{
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, NONCONST)
+ if (uses_rtx_reuse_p (*iter))
+ {
+ if (int *count = m_rtx_occurrence_count.get (*iter))
+ {
+ if (*(count++) == 1)
+ m_rtx_reuse_ids.put (*iter, m_next_id++);
+ }
+ else
+ m_rtx_occurrence_count.put (*iter, 1);
+ }
+}
+
+/* Return true iff X has been assigned a reuse ID. If it has,
+ and OUT is non-NULL, then write the reuse ID to *OUT. */
+
+bool
+rtx_reuse_manager::has_reuse_id (const_rtx x, int *out)
+{
+ int *id = m_rtx_reuse_ids.get (x);
+ if (id)
+ {
+ if (out)
+ *out = *id;
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Determine if set_seen_def has been called for the given reuse ID. */
+
+bool
+rtx_reuse_manager::seen_def_p (int reuse_id)
+{
+ return bitmap_bit_p (&m_defs_seen, reuse_id);
+}
+
+/* Record that the definition of the given reuse ID has been seen. */
+
+void
+rtx_reuse_manager::set_seen_def (int reuse_id)
+{
+ bitmap_set_bit (&m_defs_seen, reuse_id);
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+#ifndef GENERATOR_FILE
void
print_mem_expr (FILE *outfile, const_tree expr)
{
@@ -631,8 +722,34 @@ rtx_writer::print_rtx (const_rtx in_rtx)
return;
}
+ fputc ('(', m_outfile);
+
/* Print name of expression code. */
+ /* Handle reuse. */
+#ifndef GENERATOR_FILE
+ if (m_rtx_reuse_manager)
+ {
+ int reuse_id;
+ if (m_rtx_reuse_manager->has_reuse_id (in_rtx, &reuse_id))
+ {
+ /* Have we already seen the defn of this rtx? */
+ if (m_rtx_reuse_manager->seen_def_p (reuse_id))
+ {
+ fprintf (m_outfile, "reuse_rtx %i)", reuse_id);
+ m_sawclose = 1;
+ return;
+ }
+ else
+ {
+ /* First time we've seen this reused-rtx. */
+ fprintf (m_outfile, "%i|", reuse_id);
+ m_rtx_reuse_manager->set_seen_def (reuse_id);
+ }
+ }
+ }
+#endif /* #ifndef GENERATOR_FILE */
+
/* In compact mode, prefix the code of insns with "c",
giving "cinsn", "cnote" etc. */
if (m_compact && is_a <const rtx_insn *, const struct rtx_def> (in_rtx))
@@ -641,14 +758,14 @@ rtx_writer::print_rtx (const_rtx in_rtx)
just "clabel". */
rtx_code code = GET_CODE (in_rtx);
if (code == CODE_LABEL)
- fprintf (m_outfile, "(clabel");
+ fprintf (m_outfile, "clabel");
else
- fprintf (m_outfile, "(c%s", GET_RTX_NAME (code));
+ fprintf (m_outfile, "c%s", GET_RTX_NAME (code));
}
else if (m_simple && CONST_INT_P (in_rtx))
- fputc ('(', m_outfile);
+ ; /* no code. */
else
- fprintf (m_outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
+ fprintf (m_outfile, "%s", GET_RTX_NAME (GET_CODE (in_rtx)));
if (! m_simple)
{
@@ -819,7 +936,7 @@ rtx_writer::finish_directive ()
void
print_inline_rtx (FILE *outf, const_rtx x, int ind)
{
- rtx_writer w (outf, ind, false, false);
+ rtx_writer w (outf, ind, false, false, NULL);
w.print_rtx (x);
}
@@ -828,7 +945,7 @@ print_inline_rtx (FILE *outf, const_rtx x, int ind)
DEBUG_FUNCTION void
debug_rtx (const_rtx x)
{
- rtx_writer w (stderr, 0, false, false);
+ rtx_writer w (stderr, 0, false, false, NULL);
w.print_rtx (x);
fprintf (stderr, "\n");
}
@@ -975,7 +1092,7 @@ rtx_writer::print_rtl (const_rtx rtx_first)
void
print_rtl (FILE *outf, const_rtx rtx_first)
{
- rtx_writer w (outf, 0, false, false);
+ rtx_writer w (outf, 0, false, false, NULL);
w.print_rtl (rtx_first);
}
@@ -985,7 +1102,7 @@ print_rtl (FILE *outf, const_rtx rtx_first)
int
print_rtl_single (FILE *outf, const_rtx x)
{
- rtx_writer w (outf, 0, false, false);
+ rtx_writer w (outf, 0, false, false, NULL);
return w.print_rtl_single_with_indent (x, 0);
}
@@ -1016,7 +1133,7 @@ rtx_writer::print_rtl_single_with_indent (const_rtx x, int ind)
void
print_simple_rtl (FILE *outf, const_rtx x)
{
- rtx_writer w (outf, 0, true, false);
+ rtx_writer w (outf, 0, true, false, NULL);
w.print_rtl (x);
}
diff --git a/gcc/print-rtl.h b/gcc/print-rtl.h
index e722038..5f7cefb 100644
--- a/gcc/print-rtl.h
+++ b/gcc/print-rtl.h
@@ -20,12 +20,19 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_PRINT_RTL_H
#define GCC_PRINT_RTL_H
+#ifndef GENERATOR_FILE
+#include "bitmap.h"
+#endif /* #ifndef GENERATOR_FILE */
+
+class rtx_reuse_manager;
+
/* A class for writing rtx to a FILE *. */
class rtx_writer
{
public:
- rtx_writer (FILE *outfile, int ind, bool simple, bool compact);
+ rtx_writer (FILE *outfile, int ind, bool simple, bool compact,
+ rtx_reuse_manager *reuse_manager);
void print_rtx (const_rtx in_rtx);
void print_rtl (const_rtx rtx_first);
@@ -60,6 +67,9 @@ class rtx_writer
printed with a '%' sigil e.g. "%0" for (LAST_VIRTUAL_REGISTER + 1),
- insn names are prefixed with "c" (e.g. "cinsn", "cnote", etc). */
bool m_compact;
+
+ /* An optional instance of rtx_reuse_manager. */
+ rtx_reuse_manager *m_rtx_reuse_manager;
};
#ifdef BUFSIZ
@@ -80,4 +90,73 @@ extern const char *str_pattern_slim (const_rtx);
extern void print_rtx_function (FILE *file, function *fn, bool compact);
+#ifndef GENERATOR_FILE
+
+/* For some rtx codes (such as SCRATCH), instances are defined to only be
+ equal for pointer equality: two distinct SCRATCH instances are non-equal.
+ copy_rtx preserves this equality by reusing the SCRATCH instance.
+
+ For example, in this x86 instruction:
+
+ (cinsn (set (mem/v:BLK (scratch:DI) [0 A8])
+ (unspec:BLK [
+ (mem/v:BLK (scratch:DI) [0 A8])
+ ] UNSPEC_MEMORY_BLOCKAGE)) "test.c":2
+ (nil))
+
+ the two instances of "(scratch:DI)" are actually the same underlying
+ rtx pointer (and thus "equal"), and the insn will only be recognized
+ (as "*memory_blockage") if this pointer-equality is preserved.
+
+ To be able to preserve this pointer-equality when round-tripping
+ through dumping/loading the rtl, we need some syntax. The first
+ time a reused rtx is encountered in the dump, we prefix it with
+ a reuse ID:
+
+ (0|scratch:DI)
+
+ Subsequent references to the rtx in the dump can be expressed using
+ "reuse_rtx" e.g.:
+
+ (reuse_rtx 0)
+
+ This class is responsible for tracking a set of reuse IDs during a dump.
+
+ Dumping with reuse-support is done in two passes:
+
+ (a) a first pass in which "preprocess" is called on each top-level rtx
+ to be seen in the dump. This traverses the rtx and its descendents,
+ identifying rtx that will be seen more than once in the actual dump,
+ and assigning them reuse IDs.
+
+ (b) the actual dump, via print_rtx etc. print_rtx detect the presence
+ of a live rtx_reuse_manager and uses it if there is one. Any rtx
+ that were assigned reuse IDs will be printed with it the first time
+ that they are seen, and then printed as "(reuse_rtx ID)" subsequently.
+
+ The first phase is needed since otherwise there would be no way to tell
+ if an rtx will be reused when first encountering it. */
+
+class rtx_reuse_manager
+{
+ public:
+ rtx_reuse_manager ();
+
+ /* The first pass. */
+ void preprocess (const_rtx x);
+
+ /* The second pass (within print_rtx). */
+ bool has_reuse_id (const_rtx x, int *out);
+ bool seen_def_p (int reuse_id);
+ void set_seen_def (int reuse_id);
+
+ private:
+ hash_map<const_rtx, int> m_rtx_occurrence_count;
+ hash_map<const_rtx, int> m_rtx_reuse_ids;
+ bitmap_head m_defs_seen;
+ int m_next_id;
+};
+
+#endif /* #ifndef GENERATOR_FILE */
+
#endif // GCC_PRINT_RTL_H
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
index 228226b..8edddfb 100644
--- a/gcc/rtl-tests.c
+++ b/gcc/rtl-tests.c
@@ -62,11 +62,12 @@ verify_print_pattern (const char *expected, rtx pat)
Use LOC as the effective location when reporting errors. */
void
-assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x)
+assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x,
+ rtx_reuse_manager *reuse_manager)
{
named_temp_file tmp_out (".rtl");
FILE *outfile = fopen (tmp_out.get_filename (), "w");
- rtx_writer w (outfile, 0, false, true);
+ rtx_writer w (outfile, 0, false, true, reuse_manager);
w.print_rtl (x);
fclose (outfile);
@@ -128,6 +129,53 @@ test_dumping_insns ()
ASSERT_RTL_DUMP_EQ ("(clabel 0 42 (\"some_label\"))\n", label);
}
+/* Manually exercise the rtx_reuse_manager code. */
+
+static void
+test_dumping_rtx_reuse ()
+{
+ rtx_reuse_manager r;
+
+ rtx x = rtx_alloc (SCRATCH);
+ rtx y = rtx_alloc (SCRATCH);
+ rtx z = rtx_alloc (SCRATCH);
+
+ /* x and y will be seen more than once. */
+ r.preprocess (x);
+ r.preprocess (x);
+ r.preprocess (y);
+ r.preprocess (y);
+
+ /* z will be only seen once. */
+ r.preprocess (z);
+
+ /* Verify that x and y have been assigned reuse IDs. */
+ int reuse_id_for_x;
+ ASSERT_TRUE (r.has_reuse_id (x, &reuse_id_for_x));
+ ASSERT_EQ (0, reuse_id_for_x);
+
+ int reuse_id_for_y;
+ ASSERT_TRUE (r.has_reuse_id (y, &reuse_id_for_y));
+ ASSERT_EQ (1, reuse_id_for_y);
+
+ /* z is only seen once and thus shouldn't get a reuse ID. */
+ ASSERT_FALSE (r.has_reuse_id (z, NULL));
+
+ /* The first dumps of x and y should be prefixed by reuse ID;
+ all subsequent dumps of them should show up as "reuse_rtx". */
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(0|scratch)", x, &r);
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 0)", x, &r);
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 0)", x, &r);
+
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(1|scratch)", y, &r);
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 1)", y, &r);
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 1)", y, &r);
+
+ /* z only appears once and thus shouldn't be prefixed with a
+ reuse ID. */
+ ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(scratch)", z, &r);
+}
+
/* Unit testing of "single_set". */
static void
@@ -187,6 +235,7 @@ rtl_tests_c_tests ()
{
test_dumping_regs ();
test_dumping_insns ();
+ test_dumping_rtx_reuse ();
test_single_set ();
test_uncond_jump ();
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
index 0f0e167..f505018 100644
--- a/gcc/selftest-rtl.h
+++ b/gcc/selftest-rtl.h
@@ -25,18 +25,27 @@ along with GCC; see the file COPYING3. If not see
#if CHECKING_P
+class rtx_reuse_manager;
+
namespace selftest {
/* Verify that X is dumped as EXPECTED_DUMP, using compact mode.
Use LOC as the effective location when reporting errors. */
extern void
-assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x);
+assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x,
+ rtx_reuse_manager *reuse_manager);
/* Verify that RTX is dumped as EXPECTED_DUMP, using compact mode. */
#define ASSERT_RTL_DUMP_EQ(EXPECTED_DUMP, RTX) \
- assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX))
+ assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX), NULL)
+
+/* As above, but using REUSE_MANAGER when dumping. */
+
+#define ASSERT_RTL_DUMP_EQ_WITH_REUSE(EXPECTED_DUMP, RTX, REUSE_MANAGER) \
+ assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX), \
+ (REUSE_MANAGER))
} /* end of namespace selftest. */
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 5/9] Introduce selftest::locate_file (v4)
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
` (6 preceding siblings ...)
2016-11-11 20:44 ` [PATCH 1/9] print_rtx: implement support for reuse IDs (v2) David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-12-01 13:29 ` Bernd Schmidt
2016-11-11 20:44 ` [PATCH 6/9] Split class rtx_reader into md_reader vs rtx_reader David Malcolm
8 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Link to discussion of earlier version of patch:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00260.html
On Wed, 2016-10-05 at 18:10 +0200, Bernd Schmidt wrote:
> On 10/05/2016 06:15 PM, David Malcolm wrote:
> > selftest: s-selftest
> > s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
> > - $(GCC_FOR_TARGET) -xc -S -c /dev/null -fself-test
> > + $(GCC_FOR_TARGET) -xc -S -c /dev/null -fself
> > -test=$(srcdir)
> > $(STAMP) $@
>
> I suspect the Makefile parts will need updating once Thomas commits
> his
> change.
Updated.
> Also,
>
> > + return concat (path_to_src_gcc, "/testsuite/selftests/", name,
> > NULL);
>
> why hardcode directory names here? I think this should just be passed
> as
> a full pathname so only the Makefiles have knowledge of source
> directory
> structure.
Done, renaming path_to_src_gcc to path_to_selftest_files.
I also added a dep on selftest data dir to s-selftests in Makefile.in, so
that edits to the data mean re-running the selftests.
gcc/ChangeLog:
* Makefile.in (SELFTEST_FLAGS): Add path argument to -fself-test.
(s-selftest): Add dependency on the selftests data directory.
* common.opt (fself-test): Rename to...
(fself-test=): ...this, documenting the meaning of the argument.
* selftest-run-tests.c (along): Likewise.
* selftest-run-tests.c: Include "options.h".
(selftest::run_tests): Initialize selftest::path_to_selftest_files
from flag_self_test.
* selftest.c (selftest::path_to_selftest_files): New global.
(selftest::locate_file): New function.
(selftest::test_locate_file): New function.
(selftest_c_tests): Likewise.
(selftest::selftest_c_tests): Call test_locate_file.
* selftest.h (selftest::locate_file): New decl.
(selftest::path_to_selftest_files): New decl.
gcc/testsuite/ChangeLog:
* gcc.dg/cpp/pr71591.c: Add a fake value for the argument of
-fself-test.
* selftests/example.txt: New file.
---
gcc/Makefile.in | 10 +++++++---
gcc/common.opt | 6 +++---
gcc/selftest-run-tests.c | 8 ++++++++
gcc/selftest.c | 28 ++++++++++++++++++++++++++++
gcc/selftest.h | 10 ++++++++++
gcc/testsuite/gcc.dg/cpp/pr71591.c | 2 +-
gcc/testsuite/selftests/example.txt | 1 +
7 files changed, 58 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/selftests/example.txt
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7ecd1e4..fa54215 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1882,15 +1882,19 @@ rest.cross: specs
# Specify -o /dev/null so the output of -S is discarded. More importantly
# It does not try to create a file with the name "null.s" on POSIX and
# "nul.s" on Windows. Because on Windows "nul" is a reserved file name.
-SELFTEST_FLAGS = -nostdinc -x c /dev/null -S -fself-test -o /dev/null
+# Specify the path to gcc/testsuite/selftests within the srcdir
+# as an argument to -fself-test.
+SELFTEST_FLAGS = -nostdinc -x c /dev/null -S -o /dev/null \
+ -fself-test=$(srcdir)/testsuite/selftests
# Run the selftests during the build once we have a driver and a cc1,
# so that self-test failures are caught as early as possible.
# Use "s-selftest" to ensure that we only run the selftests if the
-# driver or cc1 change.
+# driver, cc1, or selftest data change.
.PHONY: selftest
selftest: s-selftest
-s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs \
+ $(srcdir)/testsuite/selftests
$(GCC_FOR_TARGET) $(SELFTEST_FLAGS)
$(STAMP) $@
diff --git a/gcc/common.opt b/gcc/common.opt
index 314145a..e868c36 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2131,9 +2131,9 @@ fselective-scheduling2
Common Report Var(flag_selective_scheduling2) Optimization
Run selective scheduling after reload.
-fself-test
-Common Undocumented Var(flag_self_test)
-Run self-tests.
+fself-test=
+Common Undocumented Joined Var(flag_self_test)
+Run self-tests, using the given path to locate test files.
fsel-sched-pipelining
Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index a4cdb55..c1cd97e 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "target.h"
#include "langhooks.h"
+#include "options.h"
/* This function needed to be split out from selftest.c as it references
tests from the whole source tree, and so is within
@@ -38,6 +39,13 @@ along with GCC; see the file COPYING3. If not see
void
selftest::run_tests ()
{
+ /* Makefile.in has -fself-test=$(srcdir)/testsuite/selftests, so that
+ flag_self_test contains the path to the selftest subdirectory of the
+ source tree (without a trailing slash). Copy it up to
+ path_to_selftest_files, to avoid selftest.c depending on
+ option-handling. */
+ path_to_selftest_files = flag_self_test;
+
long start_time = get_run_time ();
/* Run all the tests, in hand-coded order of (approximate) dependencies:
diff --git a/gcc/selftest.c b/gcc/selftest.c
index 2a729be..268fc36 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -198,6 +198,21 @@ read_file (const location &loc, const char *path)
return result;
}
+/* The path of SRCDIR/testsuite/selftests. */
+
+const char *path_to_selftest_files = NULL;
+
+/* Convert a path relative to SRCDIR/testsuite/selftests
+ to a real path (either absolute, or relative to pwd).
+ The result should be freed by the caller. */
+
+char *
+locate_file (const char *name)
+{
+ ASSERT_NE (NULL, path_to_selftest_files);
+ return concat (path_to_selftest_files, "/", name, NULL);
+}
+
/* Selftests for the selftest system itself. */
/* Sanity-check the ASSERT_ macros with various passing cases. */
@@ -240,6 +255,18 @@ test_read_file ()
free (buf);
}
+/* Verify locate_file (and read_file). */
+
+static void
+test_locate_file ()
+{
+ char *path = locate_file ("example.txt");
+ char *buf = read_file (SELFTEST_LOCATION, path);
+ ASSERT_STREQ ("example of a selftest file\n", buf);
+ free (buf);
+ free (path);
+}
+
/* Run all of the selftests within this file. */
void
@@ -248,6 +275,7 @@ selftest_c_tests ()
test_assertions ();
test_named_temp_file ();
test_read_file ();
+ test_locate_file ();
}
} // namespace selftest
diff --git a/gcc/selftest.h b/gcc/selftest.h
index dcce474..c390873 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -158,6 +158,16 @@ extern char *read_file (const location &loc, const char *path);
extern void forcibly_ggc_collect ();
+/* Convert a path relative to SRCDIR/gcc/testsuite/selftests
+ to a real path (either absolute, or relative to pwd).
+ The result should be freed by the caller. */
+
+extern char *locate_file (const char *path);
+
+/* The path of SRCDIR/testsuite/selftests. */
+
+extern const char *path_to_selftest_files;
+
/* Declarations for specific families of tests (by source file), in
alphabetical order. */
extern void bitmap_c_tests ();
diff --git a/gcc/testsuite/gcc.dg/cpp/pr71591.c b/gcc/testsuite/gcc.dg/cpp/pr71591.c
index e92cb52..0e3d7b1 100644
--- a/gcc/testsuite/gcc.dg/cpp/pr71591.c
+++ b/gcc/testsuite/gcc.dg/cpp/pr71591.c
@@ -1,5 +1,5 @@
/* PR rtl-optimization/71591 */
/* { dg-do preprocess } */
-/* { dg-options "-fself-test" } */
+/* { dg-options "-fself-test=fake-value" } */
/* { dg-message "self-tests incompatible with -E" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/selftests/example.txt b/gcc/testsuite/selftests/example.txt
new file mode 100644
index 0000000..fbfaa33
--- /dev/null
+++ b/gcc/testsuite/selftests/example.txt
@@ -0,0 +1 @@
+example of a selftest file
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 5/9] Introduce selftest::locate_file (v4)
2016-11-11 20:44 ` [PATCH 5/9] Introduce selftest::locate_file (v4) David Malcolm
@ 2016-12-01 13:29 ` Bernd Schmidt
2016-12-02 1:20 ` David Malcolm
2016-12-08 21:47 ` David Malcolm
0 siblings, 2 replies; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-01 13:29 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 11/11/2016 10:15 PM, David Malcolm wrote:
> + /* Makefile.in has -fself-test=$(srcdir)/testsuite/selftests, so that
> + flag_self_test contains the path to the selftest subdirectory of the
> + source tree (without a trailing slash). Copy it up to
> + path_to_selftest_files, to avoid selftest.c depending on
> + option-handling. */
> + path_to_selftest_files = flag_self_test;
> +
What kind of dependency are you avoiding? If it's just one include I'd
prefer to get rid of the extraneous variable.
Otherwise ok.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 5/9] Introduce selftest::locate_file (v4)
2016-12-01 13:29 ` Bernd Schmidt
@ 2016-12-02 1:20 ` David Malcolm
2016-12-08 21:47 ` David Malcolm
1 sibling, 0 replies; 78+ messages in thread
From: David Malcolm @ 2016-12-02 1:20 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches
On Thu, 2016-12-01 at 14:29 +0100, Bernd Schmidt wrote:
> On 11/11/2016 10:15 PM, David Malcolm wrote:
> > + /* Makefile.in has -fself-test=$(srcdir)/testsuite/selftests, so
> > that
> > + flag_self_test contains the path to the selftest subdirectory
> > of the
> > + source tree (without a trailing slash). Copy it up to
> > + path_to_selftest_files, to avoid selftest.c depending on
> > + option-handling. */
> > + path_to_selftest_files = flag_self_test;
> > +
>
> What kind of dependency are you avoiding? If it's just one include
> I'd
> prefer to get rid of the extraneous variable.
I was thinking more about keeping selftest.h/c modularized; I didn't
want them knowing anything about gcc option-handling, in case we want
to move the core of the selftests into some other support directory
(libiberty or similar).
Perhaps a better approach is to add the path as a param to locate_file,
to use it from callers. That would support multiple subprojects using
selftest::locate_file (avoiding a global variable), at the slight cost
of requiring the use of flag_self_test (actually a macro) everywhere in
gcc that we use locate_file.
Should I update the patches to reflect that?
> Otherwise ok.
>
>
> Bernd
>
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 5/9] Introduce selftest::locate_file (v4)
2016-12-01 13:29 ` Bernd Schmidt
2016-12-02 1:20 ` David Malcolm
@ 2016-12-08 21:47 ` David Malcolm
2016-12-09 1:48 ` Bernd Schmidt
1 sibling, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-08 21:47 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches
On Thu, 2016-12-01 at 14:29 +0100, Bernd Schmidt wrote:
> On 11/11/2016 10:15 PM, David Malcolm wrote:
> > + /* Makefile.in has -fself-test=$(srcdir)/testsuite/selftests, so
> > that
> > + flag_self_test contains the path to the selftest subdirectory
> > of the
> > + source tree (without a trailing slash). Copy it up to
> > + path_to_selftest_files, to avoid selftest.c depending on
> > + option-handling. */
> > + path_to_selftest_files = flag_self_test;
> > +
>
> What kind of dependency are you avoiding? If it's just one include
> I'd
> prefer to get rid of the extraneous variable.
>
> Otherwise ok.
I attempted to eliminate the global, and include "options.h" from
selftest.c, and to use flag_self_test directly (implicitly accessing
the global_options global).
The *code* changes were relatively simple, with only one extra
#include.
However, from a linker perspective, it's more awkward. selftest.o is
used by (amongst other things) OBJS-libcommon: libcommon.a currently
has selftest.o, but doesn't have options.o. Various things in
libcommon.a use selftest.o for selftests and thus libcommon.a needs
selftest.o.
Hence doing so brings in a dependency on the option-handling objects
into libcommon.a, which seems wrong to me.
It seems simplest to go with either:
(A) the approach in the patch, with an extra global, keeping the
selftest code independent from gcc's option-handling code (both at
compile time and link time) or
(B) add the path as an extra param, passing it in at all callsites,
so that every
locate_file (some_path)
in the kit becomes
locate_file (flag_self_test, some_path)
Is (A) OK, or would you prefer (B)? (I prefer (A) fwiw)
Thanks
Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 5/9] Introduce selftest::locate_file (v4)
2016-12-08 21:47 ` David Malcolm
@ 2016-12-09 1:48 ` Bernd Schmidt
2016-12-09 19:32 ` PR target/78213 revisited (was Re: [PATCH 5/9] Introduce selftest::locate_file (v4)) David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-09 1:48 UTC (permalink / raw)
To: David Malcolm, gcc-patches
On 12/08/2016 10:47 PM, David Malcolm wrote:
> Is (A) OK, or would you prefer (B)? (I prefer (A) fwiw)
Oh well, just keep it as it is.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* PR target/78213 revisited (was Re: [PATCH 5/9] Introduce selftest::locate_file (v4))
2016-12-09 1:48 ` Bernd Schmidt
@ 2016-12-09 19:32 ` David Malcolm
2016-12-14 14:04 ` Bernd Schmidt
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-09 19:32 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: aldyh
On Fri, 2016-12-09 at 02:48 +0100, Bernd Schmidt wrote:
> On 12/08/2016 10:47 PM, David Malcolm wrote:
>
> > Is (A) OK, or would you prefer (B)? (I prefer (A) fwiw)
>
> Oh well, just keep it as it is.
>
>
> Bernd
Thanks. Unfortunately, applying the "locate_file" patch
https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
would now introduce a regression in a recently-added test case:
Tests changing outcome in gcc/testsuite/gcc/gcc.sum: 2
------------------------------------------------------
PASS -> FAIL : gcc.dg/pr78213.c (test for excess errors)
PASS -> FAIL : gcc.dg/pr78213.c -fself-test (test for warnings, line )
This test case was added in r242748 (aka
7c889936fe48e15a57b6d1509197a1492d49b0fb) by aldy (CCed) to fix
PR target/78213:
commit 7c889936fe48e15a57b6d1509197a1492d49b0fb
Author: aldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Wed Nov 23 12:18:23 2016 +0000
PR target/78213
* opts.c (finish_options): Set -fsyntax-only if running self
tests.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@242748 138bc75d-0d04-0410-961f-82ee72b054a4
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 192d6e4..ec1fe96 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2016-11-23 Aldy Hernandez <aldyh@redhat.com>
+
+ PR target/78213
+ * opts.c (finish_options): Set -fsyntax-only if running self
+ tests.
+
2016-11-23 Richard Biener <rguenther@suse.de>
PR middle-end/71762
diff --git a/gcc/opts.c b/gcc/opts.c
index d2d6100..cb20154 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -744,6 +744,14 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
opts->x_flag_toplevel_reorder = 0;
}
+ /* -fself-test depends on the state of the compiler prior to
+ compiling anything. Ideally it should be run on an empty source
+ file. However, in case we get run with actual source, assume
+ -fsyntax-only which will inhibit any compiler initialization
+ which may confuse the self tests. */
+ if (opts->x_flag_self_test)
+ opts->x_flag_syntax_only = 1;
+
if (opts->x_flag_tm && opts->x_flag_non_call_exceptions)
sorry ("transactional memory is not supported with non-call exceptions");
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
new file mode 100644
index 0000000..e43c83c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fself-test" } */
+
+/* Verify that -fself-test does not fail on a non empty source. */
+
+int i; void bar();
+{
+ while (i--)
+ bar();
+}
+/* { dg-message "fself\-test: " "-fself-test" { target *-*-* } 0 } */
The problem is that this DejaGnu test case uses -fself-test, and
doesn't provide any arguments. With the locate_file patch, we need to
pass the path to $(srcdir)/testsuite/selftests as an argument to -fself
-test, and it's not clear to me how to do that sanely in a DejaGnu test
case; if I pass in a dummy value (like for pr71591.c), then the
selftests that use locate_file fail.
(fwiw I'm not particularly fond of us running the selftests a second
time from within DejaGnu, or for that matter, of supporting non-empty
source files in the selftests; my preferred fix for this is to delete
gcc/testsuite/gcc.dg/pr78213.c).
The motivation for the patch is to be able to verify that the RTL
function parser code works properly, by having selftests that read RTL
function dumps, and asserting various properties of the in-memory
representation. Doing this means we need some way to locate the
dumpfiles from within the selftests, hence selftest::locate_file.
Thoughts?
Dave
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: PR target/78213 revisited (was Re: [PATCH 5/9] Introduce selftest::locate_file (v4))
2016-12-09 19:32 ` PR target/78213 revisited (was Re: [PATCH 5/9] Introduce selftest::locate_file (v4)) David Malcolm
@ 2016-12-14 14:04 ` Bernd Schmidt
2016-12-15 2:14 ` [committed] Introduce selftest::locate_file (v5) David Malcolm
0 siblings, 1 reply; 78+ messages in thread
From: Bernd Schmidt @ 2016-12-14 14:04 UTC (permalink / raw)
To: David Malcolm, gcc-patches; +Cc: aldyh
On 12/09/2016 08:32 PM, David Malcolm wrote:
> Thanks. Unfortunately, applying the "locate_file" patch
> https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
> would now introduce a regression in a recently-added test case:
> The problem is that this DejaGnu test case uses -fself-test, and
> doesn't provide any arguments. With the locate_file patch, we need to
> pass the path to $(srcdir)/testsuite/selftests as an argument to -fself
> -test, and it's not clear to me how to do that sanely in a DejaGnu test
> case; if I pass in a dummy value (like for pr71591.c), then the
> selftests that use locate_file fail.
I think this part of the selftest framework (how to locate files and
tests) is possibly going to need some rethinking. But for now, I'm ok
with just adding dg-skip-if *-*-* to the problematic testcase, with a
comment describing the situation.
Bernd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [committed] Introduce selftest::locate_file (v5)
2016-12-14 14:04 ` Bernd Schmidt
@ 2016-12-15 2:14 ` David Malcolm
2021-08-17 7:00 ` Thomas Schwinge
0 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-12-15 2:14 UTC (permalink / raw)
To: Bernd Schmidt, gcc-patches; +Cc: aldyh, David Malcolm
On Wed, 2016-12-14 at 15:02 +0100, Bernd Schmidt wrote:
> On 12/09/2016 08:32 PM, David Malcolm wrote:
> > Thanks. Unfortunately, applying the "locate_file" patch
> > https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
> > would now introduce a regression in a recently-added test case:
>
> > The problem is that this DejaGnu test case uses -fself-test, and
> > doesn't provide any arguments. With the locate_file patch, we need
> > to
> > pass the path to $(srcdir)/testsuite/selftests as an argument to
> > -fself
> > -test, and it's not clear to me how to do that sanely in a DejaGnu
> > test
> > case; if I pass in a dummy value (like for pr71591.c), then the
> > selftests that use locate_file fail.
>
> I think this part of the selftest framework (how to locate files and
> tests) is possibly going to need some rethinking. But for now, I'm ok
> with just adding dg-skip-if *-*-* to the problematic testcase, with a
> comment describing the situation.
>
>
> Bernd
Thanks.
I've committed the following updated version to trunk (as r243681).
Changed in v5:
* disable DejaGnu test for PR 78213
Successfully bootstrapped®rtested on x86_64-pc-linux-gnu (with 2 PASS
results converted to 1 UNSUPPORTED in gcc.sum, re gcc.dg/pr78213.c).
Verified absence of regressions under "make selftest-valgrind".
Successfully tested stage1 of the build (and s-selftest) on
powerpc-ibm-aix7.1.3.0 (gcc111).
FWIW, the last known remaining issues with the RTL frontend are:
* dumping of non-virtual pseudos
(see https://gcc.gnu.org/ml/gcc-patches/2016-12/msg01302.html)
* review of patch 9 of the kit ("__RTL" within cc1)
(see https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00151.html)
gcc/ChangeLog:
* Makefile.in (SELFTEST_FLAGS): Add path argument to -fself-test.
(s-selftest): Add dependency on the selftests data directory.
* common.opt (fself-test): Rename to...
(fself-test=): ...this, documenting the meaning of the argument.
* selftest-run-tests.c (along): Likewise.
* selftest-run-tests.c: Include "options.h".
(selftest::run_tests): Initialize selftest::path_to_selftest_files
from flag_self_test.
* selftest.c (selftest::path_to_selftest_files): New global.
(selftest::locate_file): New function.
(selftest::test_locate_file): New function.
(selftest_c_tests): Likewise.
(selftest::selftest_c_tests): Call test_locate_file.
* selftest.h (selftest::locate_file): New decl.
(selftest::path_to_selftest_files): New decl.
gcc/testsuite/ChangeLog:
PR target/78213
* gcc.dg/cpp/pr71591.c: Add a fake value for the argument of
-fself-test.
* gcc.dg/pr78213.c: Disable this test.
* selftests/example.txt: New file.
---
gcc/Makefile.in | 10 +++++++---
gcc/common.opt | 6 +++---
gcc/selftest-run-tests.c | 8 ++++++++
gcc/selftest.c | 28 ++++++++++++++++++++++++++++
gcc/selftest.h | 10 ++++++++++
gcc/testsuite/gcc.dg/cpp/pr71591.c | 2 +-
gcc/testsuite/gcc.dg/pr78213.c | 7 +++++++
gcc/testsuite/selftests/example.txt | 1 +
8 files changed, 65 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/selftests/example.txt
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c7b1eaf..aaf742e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1892,15 +1892,19 @@ rest.cross: specs
# Specify -o /dev/null so the output of -S is discarded. More importantly
# It does not try to create a file with the name "null.s" on POSIX and
# "nul.s" on Windows. Because on Windows "nul" is a reserved file name.
-SELFTEST_FLAGS = -nostdinc -x c /dev/null -S -fself-test -o /dev/null
+# Specify the path to gcc/testsuite/selftests within the srcdir
+# as an argument to -fself-test.
+SELFTEST_FLAGS = -nostdinc -x c /dev/null -S -o /dev/null \
+ -fself-test=$(srcdir)/testsuite/selftests
# Run the selftests during the build once we have a driver and a cc1,
# so that self-test failures are caught as early as possible.
# Use "s-selftest" to ensure that we only run the selftests if the
-# driver or cc1 change.
+# driver, cc1, or selftest data change.
.PHONY: selftest
selftest: s-selftest
-s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs
+s-selftest: $(GCC_PASSES) cc1$(exeext) stmp-int-hdrs \
+ $(srcdir)/testsuite/selftests
$(GCC_FOR_TARGET) $(SELFTEST_FLAGS)
$(STAMP) $@
diff --git a/gcc/common.opt b/gcc/common.opt
index b350b07..de06844 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2152,9 +2152,9 @@ fselective-scheduling2
Common Report Var(flag_selective_scheduling2) Optimization
Run selective scheduling after reload.
-fself-test
-Common Undocumented Var(flag_self_test)
-Run self-tests.
+fself-test=
+Common Undocumented Joined Var(flag_self_test)
+Run self-tests, using the given path to locate test files.
fsel-sched-pipelining
Common Report Var(flag_sel_sched_pipelining) Init(0) Optimization
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index a4cdb55..c1cd97e 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "target.h"
#include "langhooks.h"
+#include "options.h"
/* This function needed to be split out from selftest.c as it references
tests from the whole source tree, and so is within
@@ -38,6 +39,13 @@ along with GCC; see the file COPYING3. If not see
void
selftest::run_tests ()
{
+ /* Makefile.in has -fself-test=$(srcdir)/testsuite/selftests, so that
+ flag_self_test contains the path to the selftest subdirectory of the
+ source tree (without a trailing slash). Copy it up to
+ path_to_selftest_files, to avoid selftest.c depending on
+ option-handling. */
+ path_to_selftest_files = flag_self_test;
+
long start_time = get_run_time ();
/* Run all the tests, in hand-coded order of (approximate) dependencies:
diff --git a/gcc/selftest.c b/gcc/selftest.c
index 40c6cb5..3ff3b3d 100644
--- a/gcc/selftest.c
+++ b/gcc/selftest.c
@@ -198,6 +198,21 @@ read_file (const location &loc, const char *path)
return result;
}
+/* The path of SRCDIR/testsuite/selftests. */
+
+const char *path_to_selftest_files = NULL;
+
+/* Convert a path relative to SRCDIR/testsuite/selftests
+ to a real path (either absolute, or relative to pwd).
+ The result should be freed by the caller. */
+
+char *
+locate_file (const char *name)
+{
+ ASSERT_NE (NULL, path_to_selftest_files);
+ return concat (path_to_selftest_files, "/", name, NULL);
+}
+
/* Selftests for libiberty. */
/* Verify that xstrndup generates EXPECTED when called on SRC and N. */
@@ -281,6 +296,18 @@ test_read_file ()
free (buf);
}
+/* Verify locate_file (and read_file). */
+
+static void
+test_locate_file ()
+{
+ char *path = locate_file ("example.txt");
+ char *buf = read_file (SELFTEST_LOCATION, path);
+ ASSERT_STREQ ("example of a selftest file\n", buf);
+ free (buf);
+ free (path);
+}
+
/* Run all of the selftests within this file. */
void
@@ -290,6 +317,7 @@ selftest_c_tests ()
test_assertions ();
test_named_temp_file ();
test_read_file ();
+ test_locate_file ();
}
} // namespace selftest
diff --git a/gcc/selftest.h b/gcc/selftest.h
index dcce474..c390873 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -158,6 +158,16 @@ extern char *read_file (const location &loc, const char *path);
extern void forcibly_ggc_collect ();
+/* Convert a path relative to SRCDIR/gcc/testsuite/selftests
+ to a real path (either absolute, or relative to pwd).
+ The result should be freed by the caller. */
+
+extern char *locate_file (const char *path);
+
+/* The path of SRCDIR/testsuite/selftests. */
+
+extern const char *path_to_selftest_files;
+
/* Declarations for specific families of tests (by source file), in
alphabetical order. */
extern void bitmap_c_tests ();
diff --git a/gcc/testsuite/gcc.dg/cpp/pr71591.c b/gcc/testsuite/gcc.dg/cpp/pr71591.c
index e92cb52..0e3d7b1 100644
--- a/gcc/testsuite/gcc.dg/cpp/pr71591.c
+++ b/gcc/testsuite/gcc.dg/cpp/pr71591.c
@@ -1,5 +1,5 @@
/* PR rtl-optimization/71591 */
/* { dg-do preprocess } */
-/* { dg-options "-fself-test" } */
+/* { dg-options "-fself-test=fake-value" } */
/* { dg-message "self-tests incompatible with -E" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
index e43c83c..ebc2cce 100644
--- a/gcc/testsuite/gcc.dg/pr78213.c
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -1,6 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-fself-test" } */
+/* When this test was written -fself-test took no argument, but it
+ has subsequently gained a mandatory argument, giving the path
+ to selftest support files (within the srcdir).
+ It's not clear how to provide this path sanely from
+ within DejaGnu, so for now, this test is disabled. */
+/* { dg-skip-if "" { *-*-* } } */
+
/* Verify that -fself-test does not fail on a non empty source. */
int i; void bar(); void foo()
diff --git a/gcc/testsuite/selftests/example.txt b/gcc/testsuite/selftests/example.txt
new file mode 100644
index 0000000..fbfaa33
--- /dev/null
+++ b/gcc/testsuite/selftests/example.txt
@@ -0,0 +1 @@
+example of a selftest file
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [committed] Introduce selftest::locate_file (v5)
2016-12-15 2:14 ` [committed] Introduce selftest::locate_file (v5) David Malcolm
@ 2021-08-17 7:00 ` Thomas Schwinge
2021-08-17 9:00 ` Richard Biener
2021-08-18 23:56 ` H.J. Lu
0 siblings, 2 replies; 78+ messages in thread
From: Thomas Schwinge @ 2021-08-17 7:00 UTC (permalink / raw)
To: David Malcolm, gcc-patches, Rainer Orth, Mike Stump
[-- Attachment #1: Type: text/plain, Size: 2449 bytes --]
Hi!
On 2016-12-14T21:31:05-0500, David Malcolm <dmalcolm@redhat.com> wrote:
> On Wed, 2016-12-14 at 15:02 +0100, Bernd Schmidt wrote:
>> On 12/09/2016 08:32 PM, David Malcolm wrote:
>> > Thanks. Unfortunately, applying the "locate_file" patch
>> > https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
>> > would now introduce a regression in a recently-added test case:
>>
>> > The problem is that this DejaGnu test case uses -fself-test, and
>> > doesn't provide any arguments. With the locate_file patch, we need to
>> > pass the path to $(srcdir)/testsuite/selftests as an argument to -fself
>> > -test, and it's not clear to me how to do that sanely in a DejaGnu test
>> > case
Rather simple, actually -- once you realize how all this works. ;-)
>> > if I pass in a dummy value (like for pr71591.c), then the
>> > selftests that use locate_file fail.
> I've committed the following updated version to trunk (as r243681).
>
> Changed in v5:
> * disable DejaGnu test for PR 78213
>
> Successfully bootstrapped®rtested on x86_64-pc-linux-gnu (with 2 PASS
> results converted to 1 UNSUPPORTED in gcc.sum, re gcc.dg/pr78213.c).
> --- a/gcc/testsuite/gcc.dg/pr78213.c
> +++ b/gcc/testsuite/gcc.dg/pr78213.c
> @@ -1,6 +1,13 @@
> /* { dg-do compile } */
> /* { dg-options "-fself-test" } */
>
> +/* When this test was written -fself-test took no argument, but it
> + has subsequently gained a mandatory argument, giving the path
> + to selftest support files (within the srcdir).
> + It's not clear how to provide this path sanely from
> + within DejaGnu, so for now, this test is disabled. */
> +/* { dg-skip-if "" { *-*-* } } */
> +
> /* Verify that -fself-test does not fail on a non empty source. */
>
> int i; void bar(); void foo()
OK to push the attached "Restore 'gcc.dg/pr78213.c' testing" to master
branch?
See 'git grep --cached 'dg-.*options .*\$' -- */testsuite/' for
pre-existing '$srcdir' usage in DejaGnu directives.
Grüße
Thomas
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Restore-gcc.dg-pr78213.c-testing.patch --]
[-- Type: text/x-diff, Size: 1240 bytes --]
From 84c75f25c05dde591b6ee74d7aacbc3bfec640d3 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Tue, 17 Aug 2021 08:45:18 +0200
Subject: [PATCH] Restore 'gcc.dg/pr78213.c' testing
... after it had gotten disabled in r243681 (Git
commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f)
"Introduce selftest::locate_file".
gcc/testsuite/
* gcc.dg/pr78213.c: Restore testing.
---
gcc/testsuite/gcc.dg/pr78213.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
index ebc2cce78f4..40dd3c82b60 100644
--- a/gcc/testsuite/gcc.dg/pr78213.c
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -1,12 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-fself-test" } */
-
-/* When this test was written -fself-test took no argument, but it
- has subsequently gained a mandatory argument, giving the path
- to selftest support files (within the srcdir).
- It's not clear how to provide this path sanely from
- within DejaGnu, so for now, this test is disabled. */
-/* { dg-skip-if "" { *-*-* } } */
+/* { dg-options "-fself-test=$srcdir/selftests" } */
/* Verify that -fself-test does not fail on a non empty source. */
--
2.30.2
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [committed] Introduce selftest::locate_file (v5)
2021-08-17 7:00 ` Thomas Schwinge
@ 2021-08-17 9:00 ` Richard Biener
2021-08-18 23:56 ` H.J. Lu
1 sibling, 0 replies; 78+ messages in thread
From: Richard Biener @ 2021-08-17 9:00 UTC (permalink / raw)
To: Thomas Schwinge; +Cc: David Malcolm, GCC Patches, Rainer Orth, Mike Stump
On Tue, Aug 17, 2021 at 9:01 AM Thomas Schwinge <thomas@codesourcery.com> wrote:
>
> Hi!
>
> On 2016-12-14T21:31:05-0500, David Malcolm <dmalcolm@redhat.com> wrote:
> > On Wed, 2016-12-14 at 15:02 +0100, Bernd Schmidt wrote:
> >> On 12/09/2016 08:32 PM, David Malcolm wrote:
> >> > Thanks. Unfortunately, applying the "locate_file" patch
> >> > https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
> >> > would now introduce a regression in a recently-added test case:
> >>
> >> > The problem is that this DejaGnu test case uses -fself-test, and
> >> > doesn't provide any arguments. With the locate_file patch, we need to
> >> > pass the path to $(srcdir)/testsuite/selftests as an argument to -fself
> >> > -test, and it's not clear to me how to do that sanely in a DejaGnu test
> >> > case
>
> Rather simple, actually -- once you realize how all this works. ;-)
>
> >> > if I pass in a dummy value (like for pr71591.c), then the
> >> > selftests that use locate_file fail.
>
> > I've committed the following updated version to trunk (as r243681).
> >
> > Changed in v5:
> > * disable DejaGnu test for PR 78213
> >
> > Successfully bootstrapped®rtested on x86_64-pc-linux-gnu (with 2 PASS
> > results converted to 1 UNSUPPORTED in gcc.sum, re gcc.dg/pr78213.c).
>
> > --- a/gcc/testsuite/gcc.dg/pr78213.c
> > +++ b/gcc/testsuite/gcc.dg/pr78213.c
> > @@ -1,6 +1,13 @@
> > /* { dg-do compile } */
> > /* { dg-options "-fself-test" } */
> >
> > +/* When this test was written -fself-test took no argument, but it
> > + has subsequently gained a mandatory argument, giving the path
> > + to selftest support files (within the srcdir).
> > + It's not clear how to provide this path sanely from
> > + within DejaGnu, so for now, this test is disabled. */
> > +/* { dg-skip-if "" { *-*-* } } */
> > +
> > /* Verify that -fself-test does not fail on a non empty source. */
> >
> > int i; void bar(); void foo()
>
> OK to push the attached "Restore 'gcc.dg/pr78213.c' testing" to master
> branch?
OK.
> See 'git grep --cached 'dg-.*options .*\$' -- */testsuite/' for
> pre-existing '$srcdir' usage in DejaGnu directives.
>
>
> Grüße
> Thomas
>
>
> -----------------
> Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [committed] Introduce selftest::locate_file (v5)
2021-08-17 7:00 ` Thomas Schwinge
2021-08-17 9:00 ` Richard Biener
@ 2021-08-18 23:56 ` H.J. Lu
2021-08-19 7:01 ` Thomas Schwinge
1 sibling, 1 reply; 78+ messages in thread
From: H.J. Lu @ 2021-08-18 23:56 UTC (permalink / raw)
To: Thomas Schwinge; +Cc: David Malcolm, GCC Patches, Rainer Orth, Mike Stump
On Tue, Aug 17, 2021 at 12:01 AM Thomas Schwinge
<thomas@codesourcery.com> wrote:
>
> Hi!
>
> On 2016-12-14T21:31:05-0500, David Malcolm <dmalcolm@redhat.com> wrote:
> > On Wed, 2016-12-14 at 15:02 +0100, Bernd Schmidt wrote:
> >> On 12/09/2016 08:32 PM, David Malcolm wrote:
> >> > Thanks. Unfortunately, applying the "locate_file" patch
> >> > https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
> >> > would now introduce a regression in a recently-added test case:
> >>
> >> > The problem is that this DejaGnu test case uses -fself-test, and
> >> > doesn't provide any arguments. With the locate_file patch, we need to
> >> > pass the path to $(srcdir)/testsuite/selftests as an argument to -fself
> >> > -test, and it's not clear to me how to do that sanely in a DejaGnu test
> >> > case
>
> Rather simple, actually -- once you realize how all this works. ;-)
>
> >> > if I pass in a dummy value (like for pr71591.c), then the
> >> > selftests that use locate_file fail.
>
> > I've committed the following updated version to trunk (as r243681).
> >
> > Changed in v5:
> > * disable DejaGnu test for PR 78213
> >
> > Successfully bootstrapped®rtested on x86_64-pc-linux-gnu (with 2 PASS
> > results converted to 1 UNSUPPORTED in gcc.sum, re gcc.dg/pr78213.c).
>
> > --- a/gcc/testsuite/gcc.dg/pr78213.c
> > +++ b/gcc/testsuite/gcc.dg/pr78213.c
> > @@ -1,6 +1,13 @@
> > /* { dg-do compile } */
> > /* { dg-options "-fself-test" } */
> >
> > +/* When this test was written -fself-test took no argument, but it
> > + has subsequently gained a mandatory argument, giving the path
> > + to selftest support files (within the srcdir).
> > + It's not clear how to provide this path sanely from
> > + within DejaGnu, so for now, this test is disabled. */
> > +/* { dg-skip-if "" { *-*-* } } */
> > +
> > /* Verify that -fself-test does not fail on a non empty source. */
> >
> > int i; void bar(); void foo()
>
> OK to push the attached "Restore 'gcc.dg/pr78213.c' testing" to master
> branch?
>
> See 'git grep --cached 'dg-.*options .*\$' -- */testsuite/' for
> pre-existing '$srcdir' usage in DejaGnu directives.
>
This caused:
cc1: note: self-tests are not enabled in this build
FAIL: gcc.dg/pr78213.c -fself-test (test for warnings, line )
on release branches.
--
H.J.
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [committed] Introduce selftest::locate_file (v5)
2021-08-18 23:56 ` H.J. Lu
@ 2021-08-19 7:01 ` Thomas Schwinge
0 siblings, 0 replies; 78+ messages in thread
From: Thomas Schwinge @ 2021-08-19 7:01 UTC (permalink / raw)
To: H.J. Lu, gcc-patches, seurer
[-- Attachment #1: Type: text/plain, Size: 4006 bytes --]
Hi!
On 2021-08-18T16:56:18-0700, "H.J. Lu" <hjl.tools@gmail.com> wrote:
> On Tue, Aug 17, 2021 at 12:01 AM Thomas Schwinge
> <thomas@codesourcery.com> wrote:
>> On 2016-12-14T21:31:05-0500, David Malcolm <dmalcolm@redhat.com> wrote:
>> > On Wed, 2016-12-14 at 15:02 +0100, Bernd Schmidt wrote:
>> >> On 12/09/2016 08:32 PM, David Malcolm wrote:
>> >> > Thanks. Unfortunately, applying the "locate_file" patch
>> >> > https://gcc.gnu.org/ml/gcc-patches/2016-11/msg01186.html
>> >> > would now introduce a regression in a recently-added test case:
>> >>
>> >> > The problem is that this DejaGnu test case uses -fself-test, and
>> >> > doesn't provide any arguments. With the locate_file patch, we need to
>> >> > pass the path to $(srcdir)/testsuite/selftests as an argument to -fself
>> >> > -test, and it's not clear to me how to do that sanely in a DejaGnu test
>> >> > case
>>
>> Rather simple, actually -- once you realize how all this works. ;-)
>>
>> >> > if I pass in a dummy value (like for pr71591.c), then the
>> >> > selftests that use locate_file fail.
>>
>> > I've committed the following updated version to trunk (as r243681).
>> >
>> > Changed in v5:
>> > * disable DejaGnu test for PR 78213
>> >
>> > Successfully bootstrapped®rtested on x86_64-pc-linux-gnu (with 2 PASS
>> > results converted to 1 UNSUPPORTED in gcc.sum, re gcc.dg/pr78213.c).
>>
>> > --- a/gcc/testsuite/gcc.dg/pr78213.c
>> > +++ b/gcc/testsuite/gcc.dg/pr78213.c
>> > @@ -1,6 +1,13 @@
>> > /* { dg-do compile } */
>> > /* { dg-options "-fself-test" } */
>> >
>> > +/* When this test was written -fself-test took no argument, but it
>> > + has subsequently gained a mandatory argument, giving the path
>> > + to selftest support files (within the srcdir).
>> > + It's not clear how to provide this path sanely from
>> > + within DejaGnu, so for now, this test is disabled. */
>> > +/* { dg-skip-if "" { *-*-* } } */
>> > +
>> > /* Verify that -fself-test does not fail on a non empty source. */
>> >
>> > int i; void bar(); void foo()
>>
>> OK to push the attached "Restore 'gcc.dg/pr78213.c' testing" to master
>> branch?
>>
>> See 'git grep --cached 'dg-.*options .*\$' -- */testsuite/' for
>> pre-existing '$srcdir' usage in DejaGnu directives.
>
> This caused:
>
> cc1: note: self-tests are not enabled in this build
> FAIL: gcc.dg/pr78213.c -fself-test (test for warnings, line )
Sorry for that.
> on release branches.
Specifically: in '--enable-checking=release' etc. configurations.
(I had done my testing with checking enabled...)
This is, in fact, a problem in the original
r242748 (commit 3615816da830d41f67a5d8955ae588eba7f0b6fb)
"[PR target/78213] Do not ICE on non-empty -fself-test", as made
apparent by recent commit a42467bdb70650cd2f421e67b6c3418f74feaec2
"Restore 'gcc.dg/pr78213.c' testing", after the test case had gotten
disabled in r243681 (commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f)
"Introduce selftest::locate_file" shortly after its original introduction.
(This can be seen in a few <gcc-testresults@gcc.gnu.org> reports from
back then.)
I've pushed "Fix up 'gcc.dg/pr78213.c' for '--enable-checking=release' etc."
to master branch in commit b7fc42073c04813f6b63e0641d3f6765424857c9,
cherry-picked into releases/gcc-11 branch in
commit 5fb588a677bf34dc864c577ed848405752905b89, releases/gcc-10 branch
in commit ee7502e5fec1a1c0215febfd486a0df9ffaf5692, and releases/gcc-9
branch in commit fc1993af02a3076e91c24f372be1883517453095, see attached.
Grüße
Thomas
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-up-gcc.dg-pr78213.c-for-enable-checking-release-.patch --]
[-- Type: text/x-diff, Size: 1304 bytes --]
From b7fc42073c04813f6b63e0641d3f6765424857c9 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Thu, 19 Aug 2021 08:25:47 +0200
Subject: [PATCH] Fix up 'gcc.dg/pr78213.c' for '--enable-checking=release'
etc.
Fix up for r242748 (commit 3615816da830d41f67a5d8955ae588eba7f0b6fb)
"[PR target/78213] Do not ICE on non-empty -fself-test", as made
apparent by recent commit a42467bdb70650cd2f421e67b6c3418f74feaec2
"Restore 'gcc.dg/pr78213.c' testing", after the test case had gotten
disabled in r243681 (commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f)
"Introduce selftest::locate_file" shortly after its original introduction.
gcc/testsuite/
PR testsuite/101969
* gcc.dg/pr78213.c: Fix up for '--enable-checking=release' etc.
---
gcc/testsuite/gcc.dg/pr78213.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
index 40dd3c82b60..04bf0381f76 100644
--- a/gcc/testsuite/gcc.dg/pr78213.c
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -8,4 +8,5 @@ int i;
while (i--)
bar();
}
-/* { dg-message "fself\-test: " "-fself-test" { target *-*-* } 0 } */
+
+/* { dg-regexp {^-fself-test: [0-9]+ pass\(es\) in [.0-9]+ seconds$|.*: note: self-tests are not enabled in this build$} } */
--
2.30.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Fix-up-gcc.dg-pr78213.c-for-enable-checking-rele.g11.patch --]
[-- Type: text/x-diff, Size: 1374 bytes --]
From 5fb588a677bf34dc864c577ed848405752905b89 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Thu, 19 Aug 2021 08:25:47 +0200
Subject: [PATCH] Fix up 'gcc.dg/pr78213.c' for '--enable-checking=release'
etc.
Fix up for r242748 (commit 3615816da830d41f67a5d8955ae588eba7f0b6fb)
"[PR target/78213] Do not ICE on non-empty -fself-test", as made
apparent by recent commit a42467bdb70650cd2f421e67b6c3418f74feaec2
"Restore 'gcc.dg/pr78213.c' testing", after the test case had gotten
disabled in r243681 (commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f)
"Introduce selftest::locate_file" shortly after its original introduction.
gcc/testsuite/
PR testsuite/101969
* gcc.dg/pr78213.c: Fix up for '--enable-checking=release' etc.
(cherry picked from commit b7fc42073c04813f6b63e0641d3f6765424857c9)
---
gcc/testsuite/gcc.dg/pr78213.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
index 40dd3c82b60..04bf0381f76 100644
--- a/gcc/testsuite/gcc.dg/pr78213.c
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -8,4 +8,5 @@ int i;
while (i--)
bar();
}
-/* { dg-message "fself\-test: " "-fself-test" { target *-*-* } 0 } */
+
+/* { dg-regexp {^-fself-test: [0-9]+ pass\(es\) in [.0-9]+ seconds$|.*: note: self-tests are not enabled in this build$} } */
--
2.30.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0001-Fix-up-gcc.dg-pr78213.c-for-enable-checking-rele.g10.patch --]
[-- Type: text/x-diff, Size: 1374 bytes --]
From ee7502e5fec1a1c0215febfd486a0df9ffaf5692 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Thu, 19 Aug 2021 08:25:47 +0200
Subject: [PATCH] Fix up 'gcc.dg/pr78213.c' for '--enable-checking=release'
etc.
Fix up for r242748 (commit 3615816da830d41f67a5d8955ae588eba7f0b6fb)
"[PR target/78213] Do not ICE on non-empty -fself-test", as made
apparent by recent commit a42467bdb70650cd2f421e67b6c3418f74feaec2
"Restore 'gcc.dg/pr78213.c' testing", after the test case had gotten
disabled in r243681 (commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f)
"Introduce selftest::locate_file" shortly after its original introduction.
gcc/testsuite/
PR testsuite/101969
* gcc.dg/pr78213.c: Fix up for '--enable-checking=release' etc.
(cherry picked from commit b7fc42073c04813f6b63e0641d3f6765424857c9)
---
gcc/testsuite/gcc.dg/pr78213.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
index 40dd3c82b60..04bf0381f76 100644
--- a/gcc/testsuite/gcc.dg/pr78213.c
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -8,4 +8,5 @@ int i;
while (i--)
bar();
}
-/* { dg-message "fself\-test: " "-fself-test" { target *-*-* } 0 } */
+
+/* { dg-regexp {^-fself-test: [0-9]+ pass\(es\) in [.0-9]+ seconds$|.*: note: self-tests are not enabled in this build$} } */
--
2.30.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0001-Fix-up-gcc.dg-pr78213.c-for-enable-checking-relea.g9.patch --]
[-- Type: text/x-diff, Size: 1374 bytes --]
From fc1993af02a3076e91c24f372be1883517453095 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Thu, 19 Aug 2021 08:25:47 +0200
Subject: [PATCH] Fix up 'gcc.dg/pr78213.c' for '--enable-checking=release'
etc.
Fix up for r242748 (commit 3615816da830d41f67a5d8955ae588eba7f0b6fb)
"[PR target/78213] Do not ICE on non-empty -fself-test", as made
apparent by recent commit a42467bdb70650cd2f421e67b6c3418f74feaec2
"Restore 'gcc.dg/pr78213.c' testing", after the test case had gotten
disabled in r243681 (commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f)
"Introduce selftest::locate_file" shortly after its original introduction.
gcc/testsuite/
PR testsuite/101969
* gcc.dg/pr78213.c: Fix up for '--enable-checking=release' etc.
(cherry picked from commit b7fc42073c04813f6b63e0641d3f6765424857c9)
---
gcc/testsuite/gcc.dg/pr78213.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c
index 40dd3c82b60..04bf0381f76 100644
--- a/gcc/testsuite/gcc.dg/pr78213.c
+++ b/gcc/testsuite/gcc.dg/pr78213.c
@@ -8,4 +8,5 @@ int i;
while (i--)
bar();
}
-/* { dg-message "fself\-test: " "-fself-test" { target *-*-* } 0 } */
+
+/* { dg-regexp {^-fself-test: [0-9]+ pass\(es\) in [.0-9]+ seconds$|.*: note: self-tests are not enabled in this build$} } */
--
2.30.2
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 6/9] Split class rtx_reader into md_reader vs rtx_reader
2016-11-11 20:44 [PATCH 0/9] RTL frontend v4 David Malcolm
` (7 preceding siblings ...)
2016-11-11 20:44 ` [PATCH 5/9] Introduce selftest::locate_file (v4) David Malcolm
@ 2016-11-11 20:44 ` David Malcolm
2016-11-22 21:26 ` Richard Sandiford
8 siblings, 1 reply; 78+ messages in thread
From: David Malcolm @ 2016-11-11 20:44 UTC (permalink / raw)
To: gcc-patches; +Cc: David Malcolm
Link to earlier discussion:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg01690.html
This moves read_rtx and friends into rtx_reader, and splits
rtx_reader into two classes:
class md_reader: has responsibility for reading chars, managing
include files, top-level directives etc. It is the read-md.o part.
class rtx_reader, a subclass, has the code for reading hierarchical
rtx expressions using the format codes. It is the read-rtl.o part.
This split is needed by a followup patch, which converts
read_rtx_operand to a virtual function of rtx_reader. To do this,
instances of rtx_reader (or its subclasses) need a vtable, which
needs to include a ptr to the code in read-rtl.o. Splitting it up
allows the gen* tools that currently purely use read-md.o to continue
to do so.
gcc/ChangeLog:
* genpreds.c (write_tm_constrs_h): Update for renaming of
rtx_reader_ptr to md_reader_ptr.
(write_tm_preds_h): Likewise.
(write_insn_preds_c): Likewise.
* read-md.c (rtx_reader_ptr): Rename to...
(md_reader_ptr): ...this, and convert from an
rtx_reader * to a md_reader *.
(rtx_reader::set_md_ptr_loc): Rename to...
(md_reader::set_md_ptr_loc): ...this.
(rtx_reader::get_md_ptr_loc): Rename to...
(md_reader::get_md_ptr_loc): ...this.
(rtx_reader::copy_md_ptr_loc): Rename to...
(md_reader::copy_md_ptr_loc): ...this.
(rtx_reader::fprint_md_ptr_loc): Rename to...
(md_reader::fprint_md_ptr_loc): ...this.
(rtx_reader::print_md_ptr_loc): Rename to...
(md_reader::print_md_ptr_loc): ...this.
(rtx_reader::join_c_conditions): Rename to...
(md_reader::join_c_conditions): ...this.
(rtx_reader::fprint_c_condition): ...this.
(rtx_reader::print_c_condition): Rename to...
(md_reader::print_c_condition): ...this.
(fatal_with_file_and_line): Update for renaming of
rtx_reader_ptr to md_reader_ptr.
(rtx_reader::require_char): Rename to...
(md_reader::require_char): ...this.
(rtx_reader::require_char_ws): Rename to...
(md_reader::require_char_ws): ...this.
(rtx_reader::require_word_ws): Rename to...
(md_reader::require_word_ws): ...this.
(rtx_reader::read_char): Rename to...
(md_reader::read_char): ...this.
(rtx_reader::unread_char): Rename to...
(md_reader::unread_char): ...this.
(rtx_reader::peek_char): Rename to...
(md_reader::peek_char): ...this.
(rtx_reader::read_name): Rename to...
(md_reader::read_name): ...this.
(rtx_reader::read_escape): Rename to...
(md_reader::read_escape): ...this.
(rtx_reader::read_quoted_string): Rename to...
(md_reader::read_quoted_string): ...this.
(rtx_reader::read_braced_string): Rename to...
(md_reader::read_braced_string): ...this.
(rtx_reader::read_string): Rename to...
(md_reader::read_string): ...this.
(rtx_reader::read_skip_construct): Rename to...
(md_reader::read_skip_construct): ...this.
(rtx_reader::handle_constants): Rename to...
(md_reader::handle_constants): ...this.
(rtx_reader::traverse_md_constants): Rename to...
(md_reader::traverse_md_constants): ...this.
(rtx_reader::handle_enum): Rename to...
(md_reader::handle_enum): ...this.
(rtx_reader::lookup_enum_type): Rename to...
(md_reader::lookup_enum_type): ...this.
(rtx_reader::traverse_enum_types): Rename to...
(md_reader::traverse_enum_types): ...this.
(rtx_reader::rtx_reader): Rename to...
(md_reader::md_reader): ...this, and update for renaming of
rtx_reader_ptr to md_reader_ptr.
(rtx_reader::~rtx_reader): Rename to...
(md_reader::~md_reader): ...this, and update for renaming of
rtx_reader_ptr to md_reader_ptr.
(rtx_reader::handle_include): Rename to...
(md_reader::handle_include): ...this.
(rtx_reader::handle_file): Rename to...
(md_reader::handle_file): ...this.
(rtx_reader::handle_toplevel_file): Rename to...
(md_reader::handle_toplevel_file): ...this.
(rtx_reader::get_current_location): Rename to...
(md_reader::get_current_location): ...this.
(rtx_reader::add_include_path): Rename to...
(md_reader::add_include_path): ...this.
(rtx_reader::read_md_files): Rename to...
(md_reader::read_md_files): ...this.
* read-md.h (class rtx_reader): Split into...
(class md_reader): ...new class.
(rtx_reader_ptr): Rename to...
(md_reader_ptr): ...this, and convert to a md_reader *.
(class noop_reader): Update base class to be md_reader.
(class rtx_reader): Reintroduce as a subclass of md_reader.
(rtx_reader_ptr): Reintroduce as a rtx_reader *.
(read_char): Update for renaming of rtx_reader_ptr to
md_reader_ptr.
(unread_char): Likewise.
* read-rtl.c (rtx_reader_ptr): New global.
(rtx_reader::apply_iterator_to_string): Rename to...
(md_reader::apply_iterator_to_string): ...this.
(rtx_reader::copy_rtx_for_iterators): Rename to...
(md_reader::copy_rtx_for_iterators): ...this.
(rtx_reader::read_conditions): Rename to...
(md_reader::read_conditions): ...this.
(rtx_reader::record_potential_iterator_use): Rename to...
(md_reader::record_potential_iterator_use): ...this.
(rtx_reader::read_mapping): Rename to...
(md_reader::read_mapping): ...this.
(rtx_reader::read_rtx): Use rtx_reader_ptr when calling
read_rtx_code.
(rtx_reader::read_rtx_operand): Use get_string_obstack rather
than directly accessing m_string_obstack.
(rtx_reader::rtx_reader): New ctor.
(rtx_reader::~rtx_reader): New dtor.
---
gcc/genpreds.c | 6 ++--
gcc/read-md.c | 90 ++++++++++++++++++++++++++++++----------------------------
gcc/read-md.h | 59 ++++++++++++++++++++++++++++----------
gcc/read-rtl.c | 43 +++++++++++++++++++++-------
4 files changed, 125 insertions(+), 73 deletions(-)
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index c5d597c..58e9238 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1205,7 +1205,7 @@ write_tm_constrs_h (void)
printf ("\
/* Generated automatically by the program '%s'\n\
from the machine description file '%s'. */\n\n", progname,
- rtx_reader_ptr->get_top_level_filename ());
+ md_reader_ptr->get_top_level_filename ());
puts ("\
#ifndef GCC_TM_CONSTRS_H\n\
@@ -1405,7 +1405,7 @@ write_tm_preds_h (void)
printf ("\
/* Generated automatically by the program '%s'\n\
from the machine description file '%s'. */\n\n", progname,
- rtx_reader_ptr->get_top_level_filename ());
+ md_reader_ptr->get_top_level_filename ());
puts ("\
#ifndef GCC_TM_PREDS_H\n\
@@ -1555,7 +1555,7 @@ write_insn_preds_c (void)
printf ("\
/* Generated automatically by the program '%s'\n\
from the machine description file '%s'. */\n\n", progname,
- rtx_reader_ptr->get_top_level_filename ());
+ md_reader_ptr->get_top_level_filename ());
puts ("\
#include \"config.h\"\n\
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 095075f..6d9a1bd 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -39,7 +39,7 @@ void (*include_callback) (const char *);
/* Global singleton. */
-rtx_reader *rtx_reader_ptr;
+md_reader *md_reader_ptr;
/* Given an object that starts with a char * name field, return a hash
code for its name. */
@@ -79,7 +79,7 @@ leading_ptr_eq_p (const void *def1, const void *def2)
/* Associate PTR with the file position given by FILENAME and LINENO. */
void
-rtx_reader::set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
+md_reader::set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
{
struct ptr_loc *loc;
@@ -95,7 +95,7 @@ rtx_reader::set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
position was set. */
const struct ptr_loc *
-rtx_reader::get_md_ptr_loc (const void *ptr)
+md_reader::get_md_ptr_loc (const void *ptr)
{
return (const struct ptr_loc *) htab_find (m_ptr_locs, &ptr);
}
@@ -103,7 +103,7 @@ rtx_reader::get_md_ptr_loc (const void *ptr)
/* Associate NEW_PTR with the same file position as OLD_PTR. */
void
-rtx_reader::copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
+md_reader::copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
{
const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
if (loc != 0)
@@ -114,7 +114,7 @@ rtx_reader::copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
directive for it to OUTF. */
void
-rtx_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
+md_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
{
const struct ptr_loc *loc = get_md_ptr_loc (ptr);
if (loc != 0)
@@ -123,7 +123,7 @@ rtx_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
/* Special fprint_md_ptr_loc for writing to STDOUT. */
void
-rtx_reader::print_md_ptr_loc (const void *ptr)
+md_reader::print_md_ptr_loc (const void *ptr)
{
fprint_md_ptr_loc (stdout, ptr);
}
@@ -132,7 +132,7 @@ rtx_reader::print_md_ptr_loc (const void *ptr)
may be null or empty. */
const char *
-rtx_reader::join_c_conditions (const char *cond1, const char *cond2)
+md_reader::join_c_conditions (const char *cond1, const char *cond2)
{
char *result;
const void **entry;
@@ -161,7 +161,7 @@ rtx_reader::join_c_conditions (const char *cond1, const char *cond2)
directive for COND if its original file position is known. */
void
-rtx_reader::fprint_c_condition (FILE *outf, const char *cond)
+md_reader::fprint_c_condition (FILE *outf, const char *cond)
{
const char **halves = (const char **) htab_find (m_joined_conditions, &cond);
if (halves != 0)
@@ -183,7 +183,7 @@ rtx_reader::fprint_c_condition (FILE *outf, const char *cond)
/* Special fprint_c_condition for writing to STDOUT. */
void
-rtx_reader::print_c_condition (const char *cond)
+md_reader::print_c_condition (const char *cond)
{
fprint_c_condition (stdout, cond);
}
@@ -250,8 +250,9 @@ fatal_with_file_and_line (const char *msg, ...)
va_start (ap, msg);
- fprintf (stderr, "%s:%d:%d: error: ", rtx_reader_ptr->get_filename (),
- rtx_reader_ptr->get_lineno (), rtx_reader_ptr->get_colno ());
+ fprintf (stderr, "%s:%d:%d: error: ", md_reader_ptr->get_filename (),
+ md_reader_ptr->get_lineno (),
+ md_reader_ptr->get_colno ());
vfprintf (stderr, msg, ap);
putc ('\n', stderr);
@@ -271,8 +272,9 @@ fatal_with_file_and_line (const char *msg, ...)
context[i] = '\0';
fprintf (stderr, "%s:%d:%d: note: following context is `%s'\n",
- rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
- rtx_reader_ptr->get_colno (), context);
+ md_reader_ptr->get_filename (),
+ md_reader_ptr->get_lineno (),
+ md_reader_ptr->get_colno (), context);
va_end (ap);
exit (1);
@@ -344,7 +346,7 @@ read_skip_spaces (void)
EXPECTED. */
void
-rtx_reader::require_char (char expected)
+md_reader::require_char (char expected)
{
int ch = read_char ();
if (ch != expected)
@@ -355,7 +357,7 @@ rtx_reader::require_char (char expected)
character, issuing a fatal error if it is not EXPECTED. */
void
-rtx_reader::require_char_ws (char expected)
+md_reader::require_char_ws (char expected)
{
int ch = read_skip_spaces ();
if (ch != expected)
@@ -366,7 +368,7 @@ rtx_reader::require_char_ws (char expected)
issuing a fatal error if it is not EXPECTED. */
void
-rtx_reader::require_word_ws (const char *expected)
+md_reader::require_word_ws (const char *expected)
{
struct md_name name;
read_name (&name);
@@ -377,7 +379,7 @@ rtx_reader::require_word_ws (const char *expected)
/* Read the next character from the file. */
int
-rtx_reader::read_char (void)
+md_reader::read_char (void)
{
int ch;
@@ -397,7 +399,7 @@ rtx_reader::read_char (void)
/* Put back CH, which was the last character read from the file. */
void
-rtx_reader::unread_char (int ch)
+md_reader::unread_char (int ch)
{
if (ch == '\n')
{
@@ -412,7 +414,7 @@ rtx_reader::unread_char (int ch)
/* Peek at the next character from the file without consuming it. */
int
-rtx_reader::peek_char (void)
+md_reader::peek_char (void)
{
int ch = read_char ();
unread_char (ch);
@@ -423,7 +425,7 @@ rtx_reader::peek_char (void)
punctuation chars of rtx printed syntax. */
void
-rtx_reader::read_name (struct md_name *name)
+md_reader::read_name (struct md_name *name)
{
int c;
size_t i;
@@ -489,7 +491,7 @@ rtx_reader::read_name (struct md_name *name)
Caller has read the backslash, but not placed it into the obstack. */
void
-rtx_reader::read_escape ()
+md_reader::read_escape ()
{
int c = read_char ();
@@ -542,7 +544,7 @@ rtx_reader::read_escape ()
the leading quote. */
char *
-rtx_reader::read_quoted_string ()
+md_reader::read_quoted_string ()
{
int c;
@@ -569,7 +571,7 @@ rtx_reader::read_quoted_string ()
the outermost braces _are_ included in the string constant. */
char *
-rtx_reader::read_braced_string ()
+md_reader::read_braced_string ()
{
int c;
int brace_depth = 1; /* caller-processed */
@@ -606,7 +608,7 @@ rtx_reader::read_braced_string ()
and dispatch to the appropriate string constant reader. */
char *
-rtx_reader::read_string (int star_if_braced)
+md_reader::read_string (int star_if_braced)
{
char *stringbuf;
int saw_paren = 0;
@@ -642,7 +644,7 @@ rtx_reader::read_string (int star_if_braced)
is currently nested by DEPTH levels of parentheses. */
void
-rtx_reader::read_skip_construct (int depth, file_location loc)
+md_reader::read_skip_construct (int depth, file_location loc)
{
struct md_name name;
int c;
@@ -784,7 +786,7 @@ add_constant (htab_t defs, char *name, char *value,
after the "define_constants". */
void
-rtx_reader::handle_constants ()
+md_reader::handle_constants ()
{
int c;
htab_t defs;
@@ -815,7 +817,7 @@ rtx_reader::handle_constants ()
Stop when CALLBACK returns zero. */
void
-rtx_reader::traverse_md_constants (htab_trav callback, void *info)
+md_reader::traverse_md_constants (htab_trav callback, void *info)
{
htab_traverse (get_md_constants (), callback, info);
}
@@ -838,7 +840,7 @@ md_decimal_string (int number)
directive is a define_enum rather than a define_c_enum. */
void
-rtx_reader::handle_enum (file_location loc, bool md_p)
+md_reader::handle_enum (file_location loc, bool md_p)
{
char *enum_name, *value_name;
struct md_name name;
@@ -904,7 +906,7 @@ rtx_reader::handle_enum (file_location loc, bool md_p)
/* Try to find the definition of the given enum. Return null on failure. */
struct enum_type *
-rtx_reader::lookup_enum_type (const char *name)
+md_reader::lookup_enum_type (const char *name)
{
return (struct enum_type *) htab_find (m_enum_types, &name);
}
@@ -914,15 +916,15 @@ rtx_reader::lookup_enum_type (const char *name)
returns zero. */
void
-rtx_reader::traverse_enum_types (htab_trav callback, void *info)
+md_reader::traverse_enum_types (htab_trav callback, void *info)
{
htab_traverse (m_enum_types, callback, info);
}
-/* Constructor for rtx_reader. */
+/* Constructor for md_reader. */
-rtx_reader::rtx_reader ()
+md_reader::md_reader ()
: m_toplevel_fname (NULL),
m_base_dir (NULL),
m_read_md_file (NULL),
@@ -933,7 +935,7 @@ rtx_reader::rtx_reader ()
m_last_dir_md_include_ptr (&m_first_dir_md_include)
{
/* Set the global singleton pointer. */
- rtx_reader_ptr = this;
+ md_reader_ptr = this;
obstack_init (&m_string_obstack);
@@ -953,9 +955,9 @@ rtx_reader::rtx_reader ()
unlock_std_streams ();
}
-/* rtx_reader's destructor. */
+/* md_reader's destructor. */
-rtx_reader::~rtx_reader ()
+md_reader::~md_reader ()
{
free (m_base_dir);
@@ -972,7 +974,7 @@ rtx_reader::~rtx_reader ()
obstack_free (&m_string_obstack, NULL);
/* Clear the global singleton pointer. */
- rtx_reader_ptr = NULL;
+ md_reader_ptr = NULL;
}
/* Process an "include" directive, starting with the optional space
@@ -981,7 +983,7 @@ rtx_reader::~rtx_reader ()
which the "include" occurred. */
void
-rtx_reader::handle_include (file_location loc)
+md_reader::handle_include (file_location loc)
{
const char *filename;
const char *old_filename;
@@ -1059,7 +1061,7 @@ rtx_reader::handle_include (file_location loc)
unknown directives. */
void
-rtx_reader::handle_file ()
+md_reader::handle_file ()
{
struct md_name directive;
int c;
@@ -1093,7 +1095,7 @@ rtx_reader::handle_file ()
and m_base_dir accordingly. */
void
-rtx_reader::handle_toplevel_file ()
+md_reader::handle_toplevel_file ()
{
const char *base;
@@ -1108,7 +1110,7 @@ rtx_reader::handle_toplevel_file ()
}
file_location
-rtx_reader::get_current_location () const
+md_reader::get_current_location () const
{
return file_location (m_read_md_filename, m_read_md_lineno, m_read_md_colno);
}
@@ -1116,7 +1118,7 @@ rtx_reader::get_current_location () const
/* Parse a -I option with argument ARG. */
void
-rtx_reader::add_include_path (const char *arg)
+md_reader::add_include_path (const char *arg)
{
struct file_name_list *dirtmp;
@@ -1137,8 +1139,8 @@ rtx_reader::add_include_path (const char *arg)
generic error should be reported. */
bool
-rtx_reader::read_md_files (int argc, const char **argv,
- bool (*parse_opt) (const char *))
+md_reader::read_md_files (int argc, const char **argv,
+ bool (*parse_opt) (const char *))
{
int i;
bool no_more_options;
@@ -1233,7 +1235,7 @@ rtx_reader::read_md_files (int argc, const char **argv,
return !have_error;
}
-/* class noop_reader : public rtx_reader */
+/* class noop_reader : public md_reader */
/* A dummy implementation which skips unknown directives. */
void
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 06b89b4..27fc9c2 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -91,11 +91,23 @@ struct enum_type {
unsigned int num_values;
};
-class rtx_reader
+/* A class for reading .md files and RTL dump files.
+
+ Implemented in read-md.c.
+
+ This class has responsibility for reading chars from input files, and
+ for certain common top-level directives including the "include"
+ directive.
+
+ It does not handle parsing the hierarchically-nested expressions of
+ rtl.def; for that see the rtx_reader subclass below (implemented in
+ read-rtl.c). */
+
+class md_reader
{
public:
- rtx_reader ();
- virtual ~rtx_reader ();
+ md_reader ();
+ virtual ~md_reader ();
bool read_md_files (int, const char **, bool (*) (const char *));
@@ -145,11 +157,6 @@ class rtx_reader
void record_potential_iterator_use (struct iterator_group *group,
void *ptr, const char *name);
struct mapping *read_mapping (struct iterator_group *group, htab_t table);
- bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
- rtx read_rtx_code (const char *code_name);
- void read_rtx_operand (rtx return_rtx, int idx);
- rtx read_nested_rtx ();
- rtx read_rtx_variadic (rtx form);
const char *get_top_level_filename () const { return m_toplevel_fname; }
const char *get_filename () const { return m_read_md_filename; }
@@ -231,20 +238,42 @@ class rtx_reader
htab_t m_enum_types;
};
-/* Global singleton. */
-extern rtx_reader *rtx_reader_ptr;
+/* Global singleton; constrast with rtx_reader_ptr below. */
+extern md_reader *md_reader_ptr;
-/* An rtx_reader subclass which skips unknown directives. */
+/* An md_reader subclass which skips unknown directives, for
+ the gen* tools that purely use read-md.o. */
-class noop_reader : public rtx_reader
+class noop_reader : public md_reader
{
public:
- noop_reader () : rtx_reader () {}
+ noop_reader () : md_reader () {}
/* A dummy implementation which skips unknown directives. */
void handle_unknown_directive (file_location, const char *);
};
+/* An md_reader subclass that actually handles full hierarchical
+ rtx expressions.
+
+ Implemented in read-rtl.c. */
+
+class rtx_reader : public md_reader
+{
+ public:
+ rtx_reader ();
+ ~rtx_reader ();
+
+ bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
+ rtx read_rtx_code (const char *code_name);
+ void read_rtx_operand (rtx return_rtx, int idx);
+ rtx read_nested_rtx ();
+ rtx read_rtx_variadic (rtx form);
+};
+
+/* Global singleton; constrast with md_reader_ptr above. */
+extern rtx_reader *rtx_reader_ptr;
+
extern void (*include_callback) (const char *);
/* Read the next character from the MD file. */
@@ -252,7 +281,7 @@ extern void (*include_callback) (const char *);
static inline int
read_char (void)
{
- return rtx_reader_ptr->read_char ();
+ return md_reader_ptr->read_char ();
}
/* Put back CH, which was the last character read from the MD file. */
@@ -260,7 +289,7 @@ read_char (void)
static inline void
unread_char (int ch)
{
- rtx_reader_ptr->unread_char (ch);
+ md_reader_ptr->unread_char (ch);
}
extern hashval_t leading_string_hash (const void *);
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 7a2021a..f74c875 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -107,6 +107,9 @@ const char *current_iterator_name;
static void validate_const_int (const char *);
+/* Global singleton. */
+rtx_reader *rtx_reader_ptr = NULL;
+
/* The mode and code iterator structures. */
static struct iterator_group modes, codes, ints, substs;
@@ -326,7 +329,7 @@ map_attr_string (const char *p)
if any changes were needed, otherwise return STRING itself. */
const char *
-rtx_reader::apply_iterator_to_string (const char *string)
+md_reader::apply_iterator_to_string (const char *string)
{
char *base, *copy, *p, *start, *end;
struct map_value *v;
@@ -365,7 +368,7 @@ rtx_reader::apply_iterator_to_string (const char *string)
values into any strings. */
rtx
-rtx_reader::copy_rtx_for_iterators (rtx original)
+md_reader::copy_rtx_for_iterators (rtx original)
{
const char *format_ptr, *p;
int i, j;
@@ -735,7 +738,7 @@ atoll (const char *p)
slipped in at the beginning of the sequence of MD files read by
most of the other generators. */
void
-rtx_reader::read_conditions ()
+md_reader::read_conditions ()
{
int c;
@@ -834,8 +837,8 @@ record_attribute_use (struct iterator_group *group, void *ptr,
callback. */
void
-rtx_reader::record_potential_iterator_use (struct iterator_group *group,
- void *ptr, const char *name)
+md_reader::record_potential_iterator_use (struct iterator_group *group,
+ void *ptr, const char *name)
{
struct mapping *m;
size_t len;
@@ -869,7 +872,7 @@ rtx_reader::record_potential_iterator_use (struct iterator_group *group,
(which belongs to GROUP) and return it. */
struct mapping *
-rtx_reader::read_mapping (struct iterator_group *group, htab_t table)
+md_reader::read_mapping (struct iterator_group *group, htab_t table)
{
struct md_name name;
struct mapping *m;
@@ -1072,7 +1075,7 @@ rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
return true;
}
- apply_iterators (read_rtx_code (rtx_name), rtxen);
+ apply_iterators (rtx_reader_ptr->read_rtx_code (rtx_name), rtxen);
iterator_uses.truncate (0);
attribute_uses.truncate (0);
@@ -1270,6 +1273,7 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
char *stringbuf;
int star_if_braced;
+ struct obstack *string_obstack = get_string_obstack ();
c = read_skip_spaces ();
unread_char (c);
@@ -1306,11 +1310,11 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
for (slash = fn; *slash; slash ++)
if (*slash == '/' || *slash == '\\' || *slash == ':')
fn = slash + 1;
- obstack_1grow (&m_string_obstack, '*');
- obstack_grow (&m_string_obstack, fn, strlen (fn));
+ obstack_1grow (string_obstack, '*');
+ obstack_grow (string_obstack, fn, strlen (fn));
sprintf (line_name, ":%d", get_lineno ());
- obstack_grow (&m_string_obstack, line_name, strlen (line_name)+1);
- stringbuf = XOBFINISH (&m_string_obstack, char *);
+ obstack_grow (string_obstack, line_name, strlen (line_name)+1);
+ stringbuf = XOBFINISH (string_obstack, char *);
}
/* Find attr-names in the string. */
@@ -1447,3 +1451,20 @@ rtx_reader::read_rtx_variadic (rtx form)
unread_char (c);
return form;
}
+
+/* Constructor for class rtx_reader. */
+
+rtx_reader::rtx_reader ()
+: md_reader ()
+{
+ /* Set the global singleton pointer. */
+ rtx_reader_ptr = this;
+}
+
+/* Destructor for class rtx_reader. */
+
+rtx_reader::~rtx_reader ()
+{
+ /* Clear the global singleton pointer. */
+ rtx_reader_ptr = NULL;
+}
--
1.8.5.3
^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 6/9] Split class rtx_reader into md_reader vs rtx_reader
2016-11-11 20:44 ` [PATCH 6/9] Split class rtx_reader into md_reader vs rtx_reader David Malcolm
@ 2016-11-22 21:26 ` Richard Sandiford
0 siblings, 0 replies; 78+ messages in thread
From: Richard Sandiford @ 2016-11-22 21:26 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches
Sorry, only just realised that this one hadn't been approved as
part of the earlier series.
David Malcolm <dmalcolm@redhat.com> writes:
> gcc/ChangeLog:
> * genpreds.c (write_tm_constrs_h): Update for renaming of
> rtx_reader_ptr to md_reader_ptr.
> (write_tm_preds_h): Likewise.
> (write_insn_preds_c): Likewise.
> * read-md.c (rtx_reader_ptr): Rename to...
> (md_reader_ptr): ...this, and convert from an
> rtx_reader * to a md_reader *.
> (rtx_reader::set_md_ptr_loc): Rename to...
> (md_reader::set_md_ptr_loc): ...this.
> (rtx_reader::get_md_ptr_loc): Rename to...
> (md_reader::get_md_ptr_loc): ...this.
> (rtx_reader::copy_md_ptr_loc): Rename to...
> (md_reader::copy_md_ptr_loc): ...this.
> (rtx_reader::fprint_md_ptr_loc): Rename to...
> (md_reader::fprint_md_ptr_loc): ...this.
> (rtx_reader::print_md_ptr_loc): Rename to...
> (md_reader::print_md_ptr_loc): ...this.
> (rtx_reader::join_c_conditions): Rename to...
> (md_reader::join_c_conditions): ...this.
> (rtx_reader::fprint_c_condition): ...this.
> (rtx_reader::print_c_condition): Rename to...
> (md_reader::print_c_condition): ...this.
> (fatal_with_file_and_line): Update for renaming of
> rtx_reader_ptr to md_reader_ptr.
> (rtx_reader::require_char): Rename to...
> (md_reader::require_char): ...this.
> (rtx_reader::require_char_ws): Rename to...
> (md_reader::require_char_ws): ...this.
> (rtx_reader::require_word_ws): Rename to...
> (md_reader::require_word_ws): ...this.
> (rtx_reader::read_char): Rename to...
> (md_reader::read_char): ...this.
> (rtx_reader::unread_char): Rename to...
> (md_reader::unread_char): ...this.
> (rtx_reader::peek_char): Rename to...
> (md_reader::peek_char): ...this.
> (rtx_reader::read_name): Rename to...
> (md_reader::read_name): ...this.
> (rtx_reader::read_escape): Rename to...
> (md_reader::read_escape): ...this.
> (rtx_reader::read_quoted_string): Rename to...
> (md_reader::read_quoted_string): ...this.
> (rtx_reader::read_braced_string): Rename to...
> (md_reader::read_braced_string): ...this.
> (rtx_reader::read_string): Rename to...
> (md_reader::read_string): ...this.
> (rtx_reader::read_skip_construct): Rename to...
> (md_reader::read_skip_construct): ...this.
> (rtx_reader::handle_constants): Rename to...
> (md_reader::handle_constants): ...this.
> (rtx_reader::traverse_md_constants): Rename to...
> (md_reader::traverse_md_constants): ...this.
> (rtx_reader::handle_enum): Rename to...
> (md_reader::handle_enum): ...this.
> (rtx_reader::lookup_enum_type): Rename to...
> (md_reader::lookup_enum_type): ...this.
> (rtx_reader::traverse_enum_types): Rename to...
> (md_reader::traverse_enum_types): ...this.
> (rtx_reader::rtx_reader): Rename to...
> (md_reader::md_reader): ...this, and update for renaming of
> rtx_reader_ptr to md_reader_ptr.
> (rtx_reader::~rtx_reader): Rename to...
> (md_reader::~md_reader): ...this, and update for renaming of
> rtx_reader_ptr to md_reader_ptr.
> (rtx_reader::handle_include): Rename to...
> (md_reader::handle_include): ...this.
> (rtx_reader::handle_file): Rename to...
> (md_reader::handle_file): ...this.
> (rtx_reader::handle_toplevel_file): Rename to...
> (md_reader::handle_toplevel_file): ...this.
> (rtx_reader::get_current_location): Rename to...
> (md_reader::get_current_location): ...this.
> (rtx_reader::add_include_path): Rename to...
> (md_reader::add_include_path): ...this.
> (rtx_reader::read_md_files): Rename to...
> (md_reader::read_md_files): ...this.
> * read-md.h (class rtx_reader): Split into...
> (class md_reader): ...new class.
> (rtx_reader_ptr): Rename to...
> (md_reader_ptr): ...this, and convert to a md_reader *.
> (class noop_reader): Update base class to be md_reader.
> (class rtx_reader): Reintroduce as a subclass of md_reader.
> (rtx_reader_ptr): Reintroduce as a rtx_reader *.
> (read_char): Update for renaming of rtx_reader_ptr to
> md_reader_ptr.
> (unread_char): Likewise.
> * read-rtl.c (rtx_reader_ptr): New global.
> (rtx_reader::apply_iterator_to_string): Rename to...
> (md_reader::apply_iterator_to_string): ...this.
> (rtx_reader::copy_rtx_for_iterators): Rename to...
> (md_reader::copy_rtx_for_iterators): ...this.
> (rtx_reader::read_conditions): Rename to...
> (md_reader::read_conditions): ...this.
> (rtx_reader::record_potential_iterator_use): Rename to...
> (md_reader::record_potential_iterator_use): ...this.
> (rtx_reader::read_mapping): Rename to...
> (md_reader::read_mapping): ...this.
> (rtx_reader::read_rtx): Use rtx_reader_ptr when calling
> read_rtx_code.
> (rtx_reader::read_rtx_operand): Use get_string_obstack rather
> than directly accessing m_string_obstack.
> (rtx_reader::rtx_reader): New ctor.
> (rtx_reader::~rtx_reader): New dtor.
OK, thanks. It'd be nice to split the rtl stuff out of read-md.h
at some point, but there's no reason it should happen here.
Richard
^ permalink raw reply [flat|nested] 78+ messages in thread