PR jit/64166: Add API entrypoint gcc_jit_context_enable_dump

gcc/jit/ChangeLog:
	PR jit/64166
	* docs/topics/contexts.rst (Debugging): Add description of
	gcc_jit_context_enable_dump.
	* docs/_build/texinfo/libgccjit.texi: Regenerate.
	* jit-playback.c: Include context.h.
	(class auto_argvec): New class.
	(auto_argvec::~auto_argvec): New function.
	(gcc::jit::playback::context::compile): Convert fake_args to be
	an auto_argvec, so that it can contain dynamically-allocated
	strings.   Construct a vec of all requested dumps, and pass it to
	make_fake_args.  Extract requested dumps between the calls to
	toplev::main and toplev::finalize.
	(gcc::jit::playback::context::make_fake_args): Convert param
	"argvec" to be a vec <char *>, and gain a "requested_dumps"
	param.  Convert to dynamically-allocated arg strings by converting
	ADD_ARG to take a copy of the arg, and add ADD_ARG_TAKE_OWNERSHIP
	for args that are already a copy.  Add args for all requested dumps.
	(gcc::jit::playback::context::extract_any_requested_dumps): New
	function.
	(gcc::jit::playback::context::read_dump_file): New function.
	* jit-playback.h (gcc::jit::playback::context::make_fake_args):
	Convert param "argvec" to be a vec <char *>, and gain a
	"requested_dumps" param.
	(gcc::jit::playback::context::extract_any_requested_dumps): New
	function.
	(gcc::jit::playback::context::read_dump_file): New function.
	* jit-recording.c (gcc::jit::recording::context::enable_dump): New
	function.
	(gcc::jit::recording::context::get_all_requested_dumps): New
	function.
	* jit-recording.h (gcc::jit::recording::requested_dump): New
	struct.
	(gcc::jit::recording::context::enable_dump): New function.
	(gcc::jit::recording::context::get_all_requested_dumps): New
	function.
	(gcc::jit::recording::context::m_requested_dumps): New field.
	* libgccjit.c (gcc_jit_context_enable_dump): New API entrypoint.
	* libgccjit.h (gcc_jit_context_enable_dump): New API entrypoint.
	* libgccjit.map (gcc_jit_context_enable_dump): New API entrypoint.

gcc/testsuite/ChangeLog:
	PR jit/64166
	PR jit/64020
	* jit.dg/harness.h (CHECK_STRING_CONTAINS): New macro.
	(check_string_contains): New function.
	* jit.dg/test-error-unrecognized-dump.c: New file.
	* jit.dg/test-functions.c (trig_sincos_dump): New variable.
	(trig_statistics_dump): New variable.
	(create_test_of_builtin_trig): Enable dumping of "sincos" and
	"statistics" into "trig_sincos_dump" and "trig_statistics_dump".
	(verify_test_of_builtin_trig): Verify the sincos and statistics
	dumps.
	* jit.dg/test-sum-of-squares.c (dump_vrp1): New variable.
	(create_code): Enable dumping of "tree-vrp1" into dump_vrp1.
	(verify_code): Verify the tree-vrp1 dump.

From-SVN: r218521
This commit is contained in:
David Malcolm 2014-12-09 15:35:39 +00:00 committed by David Malcolm
parent 799505ae0c
commit 463366a06a
14 changed files with 662 additions and 153 deletions

View File

@ -1,3 +1,45 @@
2014-12-09 David Malcolm <dmalcolm@redhat.com>
PR jit/64166
* docs/topics/contexts.rst (Debugging): Add description of
gcc_jit_context_enable_dump.
* docs/_build/texinfo/libgccjit.texi: Regenerate.
* jit-playback.c: Include context.h.
(class auto_argvec): New class.
(auto_argvec::~auto_argvec): New function.
(gcc::jit::playback::context::compile): Convert fake_args to be
an auto_argvec, so that it can contain dynamically-allocated
strings. Construct a vec of all requested dumps, and pass it to
make_fake_args. Extract requested dumps between the calls to
toplev::main and toplev::finalize.
(gcc::jit::playback::context::make_fake_args): Convert param
"argvec" to be a vec <char *>, and gain a "requested_dumps"
param. Convert to dynamically-allocated arg strings by converting
ADD_ARG to take a copy of the arg, and add ADD_ARG_TAKE_OWNERSHIP
for args that are already a copy. Add args for all requested dumps.
(gcc::jit::playback::context::extract_any_requested_dumps): New
function.
(gcc::jit::playback::context::read_dump_file): New function.
* jit-playback.h (gcc::jit::playback::context::make_fake_args):
Convert param "argvec" to be a vec <char *>, and gain a
"requested_dumps" param.
(gcc::jit::playback::context::extract_any_requested_dumps): New
function.
(gcc::jit::playback::context::read_dump_file): New function.
* jit-recording.c (gcc::jit::recording::context::enable_dump): New
function.
(gcc::jit::recording::context::get_all_requested_dumps): New
function.
* jit-recording.h (gcc::jit::recording::requested_dump): New
struct.
(gcc::jit::recording::context::enable_dump): New function.
(gcc::jit::recording::context::get_all_requested_dumps): New
function.
(gcc::jit::recording::context::m_requested_dumps): New field.
* libgccjit.c (gcc_jit_context_enable_dump): New API entrypoint.
* libgccjit.h (gcc_jit_context_enable_dump): New API entrypoint.
* libgccjit.map (gcc_jit_context_enable_dump): New API entrypoint.
2014-12-09 David Malcolm <dmalcolm@redhat.com>
PR jit/64166

File diff suppressed because it is too large Load Diff

View File

@ -152,6 +152,53 @@ Debugging
:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to allow stepping through the
code in a debugger.
.. function:: void\
gcc_jit_context_enable_dump (gcc_jit_context *ctxt,\
const char *dumpname, \
char **out_ptr)
Enable the dumping of a specific set of internal state from the
compilation, capturing the result in-memory as a buffer.
Parameter "dumpname" corresponds to the equivalent gcc command-line
option, without the "-fdump-" prefix.
For example, to get the equivalent of :option:`-fdump-tree-vrp1`,
supply ``"tree-vrp1"``:
.. code-block:: c
static char *dump_vrp1;
void
create_code (gcc_jit_context *ctxt)
{
gcc_jit_context_enable_dump (ctxt, "tree-vrp1", &dump_vrp1);
/* (other API calls omitted for brevity) */
}
The context directly stores the dumpname as a ``(const char *)``, so
the passed string must outlive the context.
:func:`gcc_jit_context_compile` will capture the dump as a
dynamically-allocated buffer, writing it to ``*out_ptr``.
The caller becomes responsible for calling:
.. code-block:: c
free (*out_ptr)
each time that :func:`gcc_jit_context_compile` is called.
``*out_ptr`` will be written to, either with the address of a buffer,
or with ``NULL`` if an error occurred.
.. warning::
This API entrypoint is likely to be less stable than the others.
In particular, both the precise dumpnames, and the format and content
of the dumps are subject to change.
It exists primarily for writing the library's own test suite.
Options
-------

View File

@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "gcc-driver-name.h"
#include "attribs.h"
#include "context.h"
#include "jit-common.h"
#include "jit-playback.h"
@ -1552,6 +1553,26 @@ make_tempdir_path_template ()
return result;
}
/* A subclass of auto_vec <char *> that frees all of its elements on
deletion. */
class auto_argvec : public auto_vec <char *>
{
public:
~auto_argvec ();
};
/* auto_argvec's dtor, freeing all contained strings, automatically
chaining up to ~auto_vec <char *>, which frees the internal buffer. */
auto_argvec::~auto_argvec ()
{
int i;
char *str;
FOR_EACH_VEC_ELT (*this, i, str)
free (str);
}
/* Compile a playback::context:
- Use the context's options to cconstruct command-line options, and
@ -1594,14 +1615,25 @@ compile ()
if (!ctxt_progname)
ctxt_progname = "libgccjit.so";
auto_vec <const char *> fake_args;
make_fake_args (&fake_args, ctxt_progname);
auto_vec <recording::requested_dump> requested_dumps;
m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
auto_argvec fake_args;
make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
if (errors_occurred ())
return NULL;
/* This runs the compiler. */
toplev toplev (false);
toplev.main (fake_args.length (),
const_cast <char **> (fake_args.address ()));
/* Extracting dumps makes use of the gcc::dump_manager, hence we
need to do it between toplev::main (which creates the dump manager)
and toplev::finalize (which deletes it). */
extract_any_requested_dumps (&requested_dumps);
/* Clean up the compiler. */
toplev.finalize ();
active_playback_ctxt = NULL;
@ -1645,10 +1677,12 @@ compile ()
void
playback::context::
make_fake_args (auto_vec <const char *> *argvec,
const char *ctxt_progname)
make_fake_args (vec <char *> *argvec,
const char *ctxt_progname,
vec <recording::requested_dump> *requested_dumps)
{
#define ADD_ARG(arg) argvec->safe_push (arg)
#define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
#define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
ADD_ARG (ctxt_progname);
ADD_ARG (m_path_c_file);
@ -1707,7 +1741,104 @@ make_fake_args (auto_vec <const char *> *argvec,
ADD_ARG ("-fdump-rtl-all");
ADD_ARG ("-fdump-ipa-all");
}
/* Add "-fdump-" options for any calls to
gcc_jit_context_enable_dump. */
{
int i;
recording::requested_dump *d;
FOR_EACH_VEC_ELT (*requested_dumps, i, d)
{
char *arg = concat ("-fdump-", d->m_dumpname, NULL);
ADD_ARG_TAKE_OWNERSHIP (arg);
}
}
#undef ADD_ARG
#undef ADD_ARG_TAKE_OWNERSHIP
}
/* The second half of the implementation of gcc_jit_context_enable_dump.
Iterate through the requested dumps, reading the underlying files
into heap-allocated buffers, writing pointers to the buffers into
the char ** pointers provided by client code.
Client code is responsible for calling free on the results. */
void
playback::context::
extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
{
int i;
recording::requested_dump *d;
FOR_EACH_VEC_ELT (*requested_dumps, i, d)
{
dump_file_info *dfi;
char *filename;
char *content;
dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
if (!dfi)
{
add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
continue;
}
filename = g->get_dumps ()->get_dump_file_name (dfi);
content = read_dump_file (filename);
*(d->m_out_ptr) = content;
free (filename);
}
}
/* Helper function for playback::context::extract_any_requested_dumps
(itself for use in implementation of gcc_jit_context_enable_dump).
Attempt to read the complete file at the given path, returning the
bytes found there as a buffer.
The caller is responsible for calling free on the result.
Errors will be reported on the context, and lead to NULL being
returned; an out-of-memory error will terminate the process. */
char *
playback::context::read_dump_file (const char *path)
{
char *result = NULL;
size_t total_sz = 0;
char buf[4096];
size_t sz;
FILE *f_in;
f_in = fopen (path, "r");
if (!f_in)
{
add_error (NULL, "unable to open %s for reading", path);
return NULL;
}
while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
{
size_t old_total_sz = total_sz;
total_sz += sz;
result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
memcpy (result + old_total_sz, buf, sz);
}
if (!feof (f_in))
{
add_error (NULL, "error reading from %s", path);
free (result);
return NULL;
}
fclose (f_in);
if (result)
{
result[total_sz] = '\0';
return result;
}
else
return xstrdup ("");
}
/* Part of playback::context::compile ().

View File

@ -236,8 +236,16 @@ private:
/* Functions for implementing "compile". */
void
make_fake_args (auto_vec <const char *> *argvec,
const char *ctxt_progname);
make_fake_args (vec <char *> *argvec,
const char *ctxt_progname,
vec <recording::requested_dump> *requested_dumps);
void
extract_any_requested_dumps
(vec <recording::requested_dump> *requested_dumps);
char *
read_dump_file (const char *path);
void
convert_to_dso (const char *ctxt_progname);

View File

@ -868,6 +868,27 @@ recording::context::set_bool_option (enum gcc_jit_bool_option opt,
m_bool_options[opt] = value ? true : false;
}
/* Add the given dumpname/out_ptr pair to this context's list of requested
dumps.
Implements the post-error-checking part of
gcc_jit_context_enable_dump. */
void
recording::context::enable_dump (const char *dumpname,
char **out_ptr)
{
requested_dump d;
gcc_assert (dumpname);
gcc_assert (out_ptr);
d.m_dumpname = dumpname;
d.m_out_ptr = out_ptr;
*out_ptr = NULL;
m_requested_dumps.safe_push (d);
}
/* This mutex guards gcc::jit::recording::context::compile, so that only
one thread can be accessing the bulk of GCC's state at once. */
@ -1026,6 +1047,19 @@ recording::context::dump_to_file (const char *path, bool update_locations)
}
}
/* Copy the requested dumps within this context and all ancestors into
OUT. */
void
recording::context::get_all_requested_dumps (vec <recording::requested_dump> *out)
{
if (m_parent_ctxt)
m_parent_ctxt->get_all_requested_dumps (out);
out->reserve (m_requested_dumps.length ());
out->splice (m_requested_dumps);
}
/* This is a pre-compilation check for the context (and any parents).
Detect errors within the context, adding errors if any are found. */

View File

@ -45,6 +45,13 @@ playback_string (string *str);
playback::block *
playback_block (block *b);
/* A recording of a call to gcc_jit_context_enable_dump. */
struct requested_dump
{
const char *m_dumpname;
char **m_out_ptr;
};
/* A JIT-compilation context. */
class context
{
@ -191,6 +198,10 @@ public:
set_bool_option (enum gcc_jit_bool_option opt,
int value);
void
enable_dump (const char *dumpname,
char **out_ptr);
const char *
get_str_option (enum gcc_jit_str_option opt) const
{
@ -235,6 +246,9 @@ public:
void dump_to_file (const char *path, bool update_locations);
void
get_all_requested_dumps (vec <recording::requested_dump> *out);
private:
void validate ();
@ -250,6 +264,9 @@ private:
int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
/* Dumpfiles that were requested via gcc_jit_context_enable_dump. */
auto_vec<requested_dump> m_requested_dumps;
/* Recorded API usage. */
auto_vec<memento *> m_mementos;

View File

@ -2001,6 +2001,24 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
ctxt->set_bool_option (opt, value);
}
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
gcc::jit::recording::context::enable_dump method in
jit-recording.c. */
void
gcc_jit_context_enable_dump (gcc_jit_context *ctxt,
const char *dumpname,
char **out_ptr)
{
RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
RETURN_IF_FAIL (dumpname, ctxt, NULL, "NULL dumpname");
RETURN_IF_FAIL (out_ptr, ctxt, NULL, "NULL out_ptr");
ctxt->enable_dump (dumpname, out_ptr);
}
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the

View File

@ -985,6 +985,40 @@ gcc_jit_block_end_with_void_return (gcc_jit_block *block,
extern gcc_jit_context *
gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt);
/**********************************************************************
Implementation support.
**********************************************************************/
/* Enable the dumping of a specific set of internal state from the
compilation, capturing the result in-memory as a buffer.
Parameter "dumpname" corresponds to the equivalent gcc command-line
option, without the "-fdump-" prefix.
For example, to get the equivalent of "-fdump-tree-vrp1", supply
"tree-vrp1".
The context directly stores the dumpname as a (const char *), so the
passed string must outlive the context.
gcc_jit_context_compile will capture the dump as a
dynamically-allocated buffer, writing it to ``*out_ptr``.
The caller becomes responsible for calling
free (*out_ptr)
each time that gcc_jit_context_compile is called. *out_ptr will be
written to, either with the address of a buffer, or with NULL if an
error occurred.
This API entrypoint is likely to be less stable than the others.
In particular, both the precise dumpnames, and the format and content
of the dumps are subject to change.
It exists primarily for writing the library's own test suite. */
extern void
gcc_jit_context_enable_dump (gcc_jit_context *ctxt,
const char *dumpname,
char **out_ptr);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -33,6 +33,7 @@
gcc_jit_context_acquire;
gcc_jit_context_compile;
gcc_jit_context_dump_to_file;
gcc_jit_context_enable_dump;
gcc_jit_context_get_builtin_function;
gcc_jit_context_get_first_error;
gcc_jit_context_get_type;

View File

@ -1,3 +1,20 @@
2014-12-09 David Malcolm <dmalcolm@redhat.com>
PR jit/64166
PR jit/64020
* jit.dg/harness.h (CHECK_STRING_CONTAINS): New macro.
(check_string_contains): New function.
* jit.dg/test-error-unrecognized-dump.c: New file.
* jit.dg/test-functions.c (trig_sincos_dump): New variable.
(trig_statistics_dump): New variable.
(create_test_of_builtin_trig): Enable dumping of "sincos" and
"statistics" into "trig_sincos_dump" and "trig_statistics_dump".
(verify_test_of_builtin_trig): Verify the sincos and statistics
dumps.
* jit.dg/test-sum-of-squares.c (dump_vrp1): New variable.
(create_code): Enable dumping of "tree-vrp1" into dump_vrp1.
(verify_code): Verify the tree-vrp1 dump.
2014-12-09 Uros Bizjak <ubizjak@gmail.com>
PR bootstrap/64213

View File

@ -84,6 +84,9 @@ static char test[1024];
#define CHECK_STRING_STARTS_WITH(ACTUAL, EXPECTED_PREFIX) \
check_string_starts_with ((ACTUAL), (EXPECTED_PREFIX));
#define CHECK_STRING_CONTAINS(ACTUAL, EXPECTED_SUBSTRING) \
check_string_contains (#ACTUAL, (ACTUAL), (EXPECTED_SUBSTRING));
#define CHECK(COND) \
do { \
if (COND) \
@ -110,6 +113,11 @@ extern void
check_string_starts_with (const char *actual,
const char *expected_prefix);
extern void
check_string_contains (const char *name,
const char *actual,
const char *expected_substring);
/* Implement framework needed for turning the testcase hooks into an
executable. test-combination.c and test-threads.c each combine multiple
testcases into larger testcases, so we have COMBINED_TEST as a way of
@ -168,6 +176,31 @@ check_string_starts_with (const char *actual,
test, actual, expected_prefix);
}
void
check_string_contains (const char *name,
const char *actual,
const char *expected_substring)
{
if (!actual)
{
fail ("%s: %s: actual: NULL does not contain expected substring: \"%s\"",
test, name, expected_substring);
fprintf (stderr, "incorrect value\n");
abort ();
}
if (!strstr (actual, expected_substring))
{
fail ("%s: %s: actual: \"%s\" did not contain expected substring: \"%s\"",
test, name, actual, expected_substring);
fprintf (stderr, "incorrect value\n");
abort ();
}
pass ("%s: %s: found substring: \"%s\"",
test, name, expected_substring);
}
static void set_options (gcc_jit_context *ctxt, const char *argv0)
{
/* Set up options. */

View File

@ -167,6 +167,9 @@ create_test_of_builtin_strcmp (gcc_jit_context *ctxt)
gcc_jit_block_end_with_return (initial, NULL, call);
}
static char *trig_sincos_dump;
static char *trig_statistics_dump;
static void
create_test_of_builtin_trig (gcc_jit_context *ctxt)
{
@ -178,6 +181,14 @@ create_test_of_builtin_trig (gcc_jit_context *ctxt)
}
(in theory, optimizable to sin (2 * theta))
*/
gcc_jit_context_enable_dump (ctxt,
"tree-sincos",
&trig_sincos_dump);
gcc_jit_context_enable_dump (ctxt,
"statistics",
&trig_statistics_dump);
gcc_jit_type *double_t =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
@ -266,6 +277,22 @@ verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result)
CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2 ), 0.0);
CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0);
CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI ), 0.0);
/* PR jit/64020:
The "sincos" pass merges sin/cos calls into the cexpi builtin.
Verify that a dump of the "sincos" pass was provided, and that it
shows a call to the cexpi builtin on a SSA name of "theta". */
CHECK_NON_NULL (trig_sincos_dump);
CHECK_STRING_CONTAINS (trig_sincos_dump, " = __builtin_cexpi (theta_");
free (trig_sincos_dump);
/* Similarly, verify that the statistics dump was provided, and that
it shows the sincos optimization. */
CHECK_NON_NULL (trig_statistics_dump);
CHECK_STRING_CONTAINS (
trig_statistics_dump,
"sincos \"sincos statements inserted\" \"test_of_builtin_trig\" 1");
free (trig_statistics_dump);
}
static void

View File

@ -6,6 +6,8 @@
#include "harness.h"
static char *dump_vrp1;
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
@ -22,6 +24,8 @@ create_code (gcc_jit_context *ctxt, void *user_data)
}
return sum;
*/
gcc_jit_context_enable_dump (ctxt, "tree-vrp1", &dump_vrp1);
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = the_type;
@ -123,4 +127,16 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
int val = loop_test (10);
note ("loop_test returned: %d", val);
CHECK_VALUE (val, 285);
CHECK_NON_NULL (dump_vrp1);
/* PR jit/64166
An example of using gcc_jit_context_enable_dump to verify a property
of the compile.
In this case, verify that vrp is able to deduce the
bounds of the iteration variable. Specifically, verify that some
variable is known to be in the range negative infinity to some
expression based on param "n" (actually n-1). */
CHECK_STRING_CONTAINS (dump_vrp1, ": [-INF, n_");
free (dump_vrp1);
}