jit: New API entrypoint: gcc_jit_context_dump_reproducer_to_file
gcc/jit/ChangeLog: * docs/cp/topics/contexts.rst (Debugging): Add gccjit::context::dump_reproducer_to_file. * docs/internals/index.rst (Design notes): New section, discussing input validation and gcc_jit_context_dump_reproducer_to_file. * docs/topics/contexts.rst (Debugging): Add gcc_jit_context_dump_reproducer_to_file. * docs/_build/texinfo/libgccjit.texi: Regenerate. * jit-common.h (gcc::jit::dump::get_context): New accessor. * jit-recording.c: Include "hash-map.h". Within namespace ::gcc::jit... (dump::write): Flush each line. (dump::make_location): Pass false for new param "created_by_user". (class allocator): New class. (allocator::~allocator): New function. (allocator::xstrdup_printf): New function. (allocator::xstrdup_printf_va): New function. (class reproducer): New subclass of dump. (reproducer::reproducer): New function. (reproducer::write_params): New function. (reproducer::write_args): New function. (reproducer::make_identifier): New function. (reproducer::make_tmp_identifier): New function. (reproducer::get_identifier): New pair of functions. (reproducer::get_identifier_as_rvalue): New function. (reproducer::get_identifier_as_lvalue): New function. (reproducer::get_identifier_as_type): New function. (reproducer::xstrdup_printf): New function. (recording::context::context): Initialize m_toplevel_ctxt. (recording::context::new_location): Add param created_by_user. (str_option_reproducer_strings): New table of strings. (int_option_reproducer_strings): Likewise. (bool_option_reproducer_strings): Likewise. (get_type_enum_strings): Likewise. (names_of_function_kinds): Likewise. (global_kind_reproducer_strings): Likewise. (unary_op_reproducer_strings): Likewise. (binary_op_reproducer_strings): Likewise. (comparison_reproducer_strings): Likewise. Within namespace ::gcc::jit::recording::... (context::dump_reproducer_to_file): New function. (string::write_reproducer): Likewise. (location::write_reproducer): Likewise. (type::access_as_type): Likewise. (memento_of_get_type::write_reproducer): Likewise. (memento_of_get_pointer::write_reproducer): Likewise. (memento_of_get_const::write_reproducer): Likewise. (memento_of_get_volatile::write_reproducer): Likewise. (array_type::write_reproducer): Likewise. (function_type::write_reproducer): Likewise. (function_type::write_deferred_reproducer): Likewise. (field::write_reproducer): Likewise. (struct_::access_as_type): Likewise. (struct_::write_reproducer): Likewise. (union_::write_reproducer): Likewise. (fields::write_reproducer): Likewise. (rvalue::access_as_rvalue): Likewise. (lvalue::access_as_rvalue): Likewise. (lvalue::access_as_lvalue): Likewise. (param::access_as_rvalue): Likewise. (param::access_as_lvalue): Likewise. (param::write_reproducer): Likewise. (function::write_reproducer): Likewise. (block::write_reproducer): Likewise. (global::write_reproducer): Likewise. (memento_of_new_rvalue_from_const <int>::write_reproducer): Likewise. (memento_of_new_rvalue_from_const <long>::write_reproducer): Likewise. (memento_of_new_rvalue_from_const <double>::write_reproducer): Likewise. (memento_of_new_rvalue_from_const <void *>::write_reproducer): Likewise. (memento_of_new_string_literal::write_reproducer): Likewise. (unary_op::write_reproducer): Likewise. (binary_op::write_reproducer): Likewise. (comparison::write_reproducer): Likewise. (cast::write_reproducer): Likewise. (call::write_reproducer): Likewise. (call_through_ptr::write_reproducer): Likewise. (array_access::write_reproducer): Likewise. (access_field_of_lvalue::write_reproducer): Likewise. (access_field_rvalue::write_reproducer): Likewise. (dereference_field_rvalue::write_reproducer): Likewise. (dereference_rvalue::write_reproducer): Likewise. (get_address_of_lvalue::write_reproducer): Likewise. (local::write_reproducer): Likewise. (eval::write_reproducer): Likewise. (assignment::write_reproducer): Likewise. (assignment_op::write_reproducer): Likewise. (comment::write_reproducer): Likewise. (conditional::write_reproducer): Likewise. (jump::write_reproducer): Likewise. (return_::write_reproducer): Likewise. * jit-recording.h (gcc::jit::reproducer): New forward declararion. Within namespace ::gcc::jit::recording::... (context::new_location): Add "created_by_user" param. (context::dump_reproducer_to_file): New method. (context::m_toplevel_ctxt): New field. (memento::write_reproducer): New pure virtual function. (memento::dyn_cast_location): New virtual function. (string::write_reproducer): (location::location): Add "created_by_user" param. (location::dyn_cast_location): New function. (location::created_by_user): New accessor. (location::write_reproducer): New function. (location::m_created_by_user): New field. (type::access_as_type): New virtual function. (location::write_reproducer): Likewise. (type::access_as_type): Likewise. (memento_of_get_type::write_reproducer): Likewise. (memento_of_get_pointer::write_reproducer): Likewise. (memento_of_get_const::write_reproducer): Likewise. (memento_of_get_volatile::write_reproducer): Likewise. (array_type::write_reproducer): Likewise. (function_type::write_reproducer): Likewise. (function_type::write_deferred_reproducer): Likewise. (field::write_reproducer): Likewise. (struct_::access_as_type): Likewise. (struct_::write_reproducer): Likewise. (union_::write_reproducer): Likewise. (union_::m_fields): Remove stray unused field. (fields::length): New accessor. (fields::get_field): New accessor. (fields::write_reproducer): New function. (rvalue::access_as_rvalue): Likewise. (lvalue::access_as_rvalue): Likewise. (lvalue::access_as_lvalue): Likewise. (param::access_as_rvalue): Likewise. (param::access_as_lvalue): Likewise. (param::write_reproducer): Likewise. (function::write_reproducer): Likewise. (block::write_reproducer): Likewise. (global::write_reproducer): Likewise. (memento_of_new_rvalue_from_const <HOST_TYPE>::write_reproducer): Likewise. (memento_of_new_string_literal::write_reproducer): Likewise. (unary_op::write_reproducer): Likewise. (binary_op::write_reproducer): Likewise. (comparison::write_reproducer): Likewise. (cast::write_reproducer): Likewise. (call::write_reproducer): Likewise. (call_through_ptr::write_reproducer): Likewise. (array_access::write_reproducer): Likewise. (access_field_of_lvalue::write_reproducer): Likewise. (access_field_rvalue::write_reproducer): Likewise. (dereference_field_rvalue::write_reproducer): Likewise. (dereference_rvalue::write_reproducer): Likewise. (get_address_of_lvalue::write_reproducer): Likewise. (local::write_reproducer): Likewise. (eval::write_reproducer): Likewise. (assignment::write_reproducer): Likewise. (assignment_op::write_reproducer): Likewise. (comment::write_reproducer): Likewise. (conditional::write_reproducer): Likewise. (jump::write_reproducer): Likewise. (return_::write_reproducer): Likewise. * libgccjit++.h (gccjit::context::dump_reproducer_to_file): New. * libgccjit.c (gcc_jit_context_new_location): Pass "true" as param "created_by_user". (gcc_jit_context_dump_reproducer_to_file): New API entrypoint. * libgccjit.h (gcc_jit_context_dump_reproducer_to_file): New API entrypoint. * libgccjit.map (gcc_jit_context_dump_reproducer_to_file): New API entrypoint. gcc/testsuite/ChangeLog: * jit.dg/harness.h (set_up_logging): Move string concatenation into... (concat_strings): New function. (dump_reproducer): New function. (test_jit): Call dump_reproducer. * jit.dg/jit.exp (is_testcase_meant_to_generate_a_reproducer): New function. (jit-dg-test): Delete any generated reproducer from previous runs. Verify that a generated reproducer was created, and verify that it compiles. * jit.dg/test-nested-contexts.c (main): Call gcc_jit_context_dump_reproducer_to_file. From-SVN: r219564
This commit is contained in:
parent
9c80f9197e
commit
86d0ac8876
@ -1,3 +1,171 @@
|
||||
2015-01-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* docs/cp/topics/contexts.rst (Debugging): Add
|
||||
gccjit::context::dump_reproducer_to_file.
|
||||
* docs/internals/index.rst (Design notes): New section,
|
||||
discussing input validation and
|
||||
gcc_jit_context_dump_reproducer_to_file.
|
||||
* docs/topics/contexts.rst (Debugging): Add
|
||||
gcc_jit_context_dump_reproducer_to_file.
|
||||
* docs/_build/texinfo/libgccjit.texi: Regenerate.
|
||||
* jit-common.h (gcc::jit::dump::get_context): New accessor.
|
||||
* jit-recording.c: Include "hash-map.h".
|
||||
Within namespace ::gcc::jit...
|
||||
(dump::write): Flush each line.
|
||||
(dump::make_location): Pass false for new param "created_by_user".
|
||||
(class allocator): New class.
|
||||
(allocator::~allocator): New function.
|
||||
(allocator::xstrdup_printf): New function.
|
||||
(allocator::xstrdup_printf_va): New function.
|
||||
(class reproducer): New subclass of dump.
|
||||
(reproducer::reproducer): New function.
|
||||
(reproducer::write_params): New function.
|
||||
(reproducer::write_args): New function.
|
||||
(reproducer::make_identifier): New function.
|
||||
(reproducer::make_tmp_identifier): New function.
|
||||
(reproducer::get_identifier): New pair of functions.
|
||||
(reproducer::get_identifier_as_rvalue): New function.
|
||||
(reproducer::get_identifier_as_lvalue): New function.
|
||||
(reproducer::get_identifier_as_type): New function.
|
||||
(reproducer::xstrdup_printf): New function.
|
||||
(recording::context::context): Initialize m_toplevel_ctxt.
|
||||
(recording::context::new_location): Add param created_by_user.
|
||||
(str_option_reproducer_strings): New table of strings.
|
||||
(int_option_reproducer_strings): Likewise.
|
||||
(bool_option_reproducer_strings): Likewise.
|
||||
(get_type_enum_strings): Likewise.
|
||||
(names_of_function_kinds): Likewise.
|
||||
(global_kind_reproducer_strings): Likewise.
|
||||
(unary_op_reproducer_strings): Likewise.
|
||||
(binary_op_reproducer_strings): Likewise.
|
||||
(comparison_reproducer_strings): Likewise.
|
||||
Within namespace ::gcc::jit::recording::...
|
||||
(context::dump_reproducer_to_file): New function.
|
||||
(string::write_reproducer): Likewise.
|
||||
(location::write_reproducer): Likewise.
|
||||
(type::access_as_type): Likewise.
|
||||
(memento_of_get_type::write_reproducer): Likewise.
|
||||
(memento_of_get_pointer::write_reproducer): Likewise.
|
||||
(memento_of_get_const::write_reproducer): Likewise.
|
||||
(memento_of_get_volatile::write_reproducer): Likewise.
|
||||
(array_type::write_reproducer): Likewise.
|
||||
(function_type::write_reproducer): Likewise.
|
||||
(function_type::write_deferred_reproducer): Likewise.
|
||||
(field::write_reproducer): Likewise.
|
||||
(struct_::access_as_type): Likewise.
|
||||
(struct_::write_reproducer): Likewise.
|
||||
(union_::write_reproducer): Likewise.
|
||||
(fields::write_reproducer): Likewise.
|
||||
(rvalue::access_as_rvalue): Likewise.
|
||||
(lvalue::access_as_rvalue): Likewise.
|
||||
(lvalue::access_as_lvalue): Likewise.
|
||||
(param::access_as_rvalue): Likewise.
|
||||
(param::access_as_lvalue): Likewise.
|
||||
(param::write_reproducer): Likewise.
|
||||
(function::write_reproducer): Likewise.
|
||||
(block::write_reproducer): Likewise.
|
||||
(global::write_reproducer): Likewise.
|
||||
(memento_of_new_rvalue_from_const <int>::write_reproducer):
|
||||
Likewise.
|
||||
(memento_of_new_rvalue_from_const <long>::write_reproducer):
|
||||
Likewise.
|
||||
(memento_of_new_rvalue_from_const <double>::write_reproducer):
|
||||
Likewise.
|
||||
(memento_of_new_rvalue_from_const <void *>::write_reproducer):
|
||||
Likewise.
|
||||
(memento_of_new_string_literal::write_reproducer): Likewise.
|
||||
(unary_op::write_reproducer): Likewise.
|
||||
(binary_op::write_reproducer): Likewise.
|
||||
(comparison::write_reproducer): Likewise.
|
||||
(cast::write_reproducer): Likewise.
|
||||
(call::write_reproducer): Likewise.
|
||||
(call_through_ptr::write_reproducer): Likewise.
|
||||
(array_access::write_reproducer): Likewise.
|
||||
(access_field_of_lvalue::write_reproducer): Likewise.
|
||||
(access_field_rvalue::write_reproducer): Likewise.
|
||||
(dereference_field_rvalue::write_reproducer): Likewise.
|
||||
(dereference_rvalue::write_reproducer): Likewise.
|
||||
(get_address_of_lvalue::write_reproducer): Likewise.
|
||||
(local::write_reproducer): Likewise.
|
||||
(eval::write_reproducer): Likewise.
|
||||
(assignment::write_reproducer): Likewise.
|
||||
(assignment_op::write_reproducer): Likewise.
|
||||
(comment::write_reproducer): Likewise.
|
||||
(conditional::write_reproducer): Likewise.
|
||||
(jump::write_reproducer): Likewise.
|
||||
(return_::write_reproducer): Likewise.
|
||||
* jit-recording.h (gcc::jit::reproducer): New forward declararion.
|
||||
Within namespace ::gcc::jit::recording::...
|
||||
(context::new_location): Add "created_by_user" param.
|
||||
(context::dump_reproducer_to_file): New method.
|
||||
(context::m_toplevel_ctxt): New field.
|
||||
(memento::write_reproducer): New pure virtual function.
|
||||
(memento::dyn_cast_location): New virtual function.
|
||||
(string::write_reproducer):
|
||||
(location::location): Add "created_by_user" param.
|
||||
(location::dyn_cast_location): New function.
|
||||
(location::created_by_user): New accessor.
|
||||
(location::write_reproducer): New function.
|
||||
(location::m_created_by_user): New field.
|
||||
(type::access_as_type): New virtual function.
|
||||
(location::write_reproducer): Likewise.
|
||||
(type::access_as_type): Likewise.
|
||||
(memento_of_get_type::write_reproducer): Likewise.
|
||||
(memento_of_get_pointer::write_reproducer): Likewise.
|
||||
(memento_of_get_const::write_reproducer): Likewise.
|
||||
(memento_of_get_volatile::write_reproducer): Likewise.
|
||||
(array_type::write_reproducer): Likewise.
|
||||
(function_type::write_reproducer): Likewise.
|
||||
(function_type::write_deferred_reproducer): Likewise.
|
||||
(field::write_reproducer): Likewise.
|
||||
(struct_::access_as_type): Likewise.
|
||||
(struct_::write_reproducer): Likewise.
|
||||
(union_::write_reproducer): Likewise.
|
||||
(union_::m_fields): Remove stray unused field.
|
||||
(fields::length): New accessor.
|
||||
(fields::get_field): New accessor.
|
||||
(fields::write_reproducer): New function.
|
||||
(rvalue::access_as_rvalue): Likewise.
|
||||
(lvalue::access_as_rvalue): Likewise.
|
||||
(lvalue::access_as_lvalue): Likewise.
|
||||
(param::access_as_rvalue): Likewise.
|
||||
(param::access_as_lvalue): Likewise.
|
||||
(param::write_reproducer): Likewise.
|
||||
(function::write_reproducer): Likewise.
|
||||
(block::write_reproducer): Likewise.
|
||||
(global::write_reproducer): Likewise.
|
||||
(memento_of_new_rvalue_from_const <HOST_TYPE>::write_reproducer):
|
||||
Likewise.
|
||||
(memento_of_new_string_literal::write_reproducer): Likewise.
|
||||
(unary_op::write_reproducer): Likewise.
|
||||
(binary_op::write_reproducer): Likewise.
|
||||
(comparison::write_reproducer): Likewise.
|
||||
(cast::write_reproducer): Likewise.
|
||||
(call::write_reproducer): Likewise.
|
||||
(call_through_ptr::write_reproducer): Likewise.
|
||||
(array_access::write_reproducer): Likewise.
|
||||
(access_field_of_lvalue::write_reproducer): Likewise.
|
||||
(access_field_rvalue::write_reproducer): Likewise.
|
||||
(dereference_field_rvalue::write_reproducer): Likewise.
|
||||
(dereference_rvalue::write_reproducer): Likewise.
|
||||
(get_address_of_lvalue::write_reproducer): Likewise.
|
||||
(local::write_reproducer): Likewise.
|
||||
(eval::write_reproducer): Likewise.
|
||||
(assignment::write_reproducer): Likewise.
|
||||
(assignment_op::write_reproducer): Likewise.
|
||||
(comment::write_reproducer): Likewise.
|
||||
(conditional::write_reproducer): Likewise.
|
||||
(jump::write_reproducer): Likewise.
|
||||
(return_::write_reproducer): Likewise.
|
||||
* libgccjit++.h (gccjit::context::dump_reproducer_to_file): New.
|
||||
* libgccjit.c (gcc_jit_context_new_location): Pass "true" as
|
||||
param "created_by_user".
|
||||
(gcc_jit_context_dump_reproducer_to_file): New API entrypoint.
|
||||
* libgccjit.h (gcc_jit_context_dump_reproducer_to_file): New API
|
||||
entrypoint.
|
||||
* libgccjit.map (gcc_jit_context_dump_reproducer_to_file): New API
|
||||
entrypoint.
|
||||
|
||||
2015-01-12 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit-recording.c (class gcc::jit::rvalue_usage_validator): New.
|
||||
|
823
gcc/jit/docs/_build/texinfo/libgccjit.texi
vendored
823
gcc/jit/docs/_build/texinfo/libgccjit.texi
vendored
File diff suppressed because it is too large
Load Diff
@ -144,6 +144,16 @@ Debugging
|
||||
:c:macro:`GCCJIT::BOOL_OPTION_DEBUGINFO` to allow stepping through the
|
||||
code in a debugger.
|
||||
|
||||
.. function:: void\
|
||||
gccjit::context::dump_reproducer_to_file (gcc_jit_context *ctxt,\
|
||||
const char *path)
|
||||
|
||||
This is a thin wrapper around the C API
|
||||
:c:func:`gcc_jit_context_dump_reproducer_to_file`, and hence works the
|
||||
same way.
|
||||
|
||||
Note that the generated source is C code, not C++; this might be of use
|
||||
for seeing what the C++ bindings are doing at the C level.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
@ -277,3 +277,13 @@ generated via this call:
|
||||
|
||||
.. literalinclude:: test-hello-world.exe.log.txt
|
||||
:lines: 1-
|
||||
|
||||
Design notes
|
||||
------------
|
||||
It should not be possible for client code to cause an internal compiler
|
||||
error. If this *does* happen, the root cause should be isolated (perhaps
|
||||
using :c:func:`gcc_jit_context_dump_reproducer_to_file`) and the cause
|
||||
should be rejected via additional checking. The checking ideally should
|
||||
be within the libgccjit API entrypoints in libgccjit.c, since this is as
|
||||
close as possible to the error; failing that, a good place is within
|
||||
``recording::context::validate ()`` in jit-recording.c.
|
||||
|
@ -218,6 +218,30 @@ current state of a context to the given path, whereas
|
||||
:c:func:`gcc_jit_context_set_logfile` enables on-going logging of
|
||||
future activies on a context to the given `FILE *`.
|
||||
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_context_dump_reproducer_to_file (gcc_jit_context *ctxt,\
|
||||
const char *path)
|
||||
|
||||
Write C source code into `path` that can be compiled into a
|
||||
self-contained executable (i.e. with libgccjit as the only dependency).
|
||||
The generated code will attempt to replay the API calls that have been
|
||||
made into the given context.
|
||||
|
||||
This may be useful when debugging the library or client code, for
|
||||
reducing a complicated recipe for reproducing a bug into a simpler
|
||||
form. For example, consider client code that parses some source file
|
||||
into some internal representation, and then walks this IR, calling into
|
||||
libgccjit. If this encounters a bug, a call to
|
||||
`gcc_jit_context_dump_reproducer_to_file` will write out C code for
|
||||
a much simpler executable that performs the equivalent calls into
|
||||
libgccjit, without needing the client code and its data.
|
||||
|
||||
Typically you need to supply :option:`-Wno-unused-variable` when
|
||||
compiling the generated file (since the result of each API call is
|
||||
assigned to a unique variable within the generated C source, and not
|
||||
all are necessarily then used).
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_context_enable_dump (gcc_jit_context *ctxt,\
|
||||
const char *dumpname, \
|
||||
|
@ -168,6 +168,8 @@ public:
|
||||
bool update_locations);
|
||||
~dump ();
|
||||
|
||||
recording::context &get_context () { return m_ctxt; }
|
||||
|
||||
void write (const char *fmt, ...)
|
||||
GNU_PRINTF(2, 3);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@ namespace jit {
|
||||
|
||||
class result;
|
||||
class dump;
|
||||
class reproducer;
|
||||
|
||||
/**********************************************************************
|
||||
Recording.
|
||||
@ -73,7 +74,8 @@ public:
|
||||
location *
|
||||
new_location (const char *filename,
|
||||
int line,
|
||||
int column);
|
||||
int column,
|
||||
bool created_by_user);
|
||||
|
||||
type *
|
||||
get_type (enum gcc_jit_types type);
|
||||
@ -244,6 +246,8 @@ public:
|
||||
|
||||
void dump_to_file (const char *path, bool update_locations);
|
||||
|
||||
void dump_reproducer_to_file (const char *path);
|
||||
|
||||
void
|
||||
get_all_requested_dumps (vec <recording::requested_dump> *out);
|
||||
|
||||
@ -253,6 +257,10 @@ private:
|
||||
private:
|
||||
context *m_parent_ctxt;
|
||||
|
||||
/* The ultimate ancestor of the contexts within a family tree of
|
||||
contexts. This has itself as its own m_toplevel_ctxt. */
|
||||
context *m_toplevel_ctxt;
|
||||
|
||||
int m_error_count;
|
||||
|
||||
char *m_first_error_str;
|
||||
@ -314,6 +322,8 @@ public:
|
||||
get_debug_string ();
|
||||
|
||||
virtual void write_to_dump (dump &d);
|
||||
virtual void write_reproducer (reproducer &r) = 0;
|
||||
virtual location *dyn_cast_location () { return NULL; }
|
||||
|
||||
protected:
|
||||
memento (context *ctxt)
|
||||
@ -355,6 +365,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
size_t m_len;
|
||||
@ -364,11 +375,13 @@ private:
|
||||
class location : public memento
|
||||
{
|
||||
public:
|
||||
location (context *ctxt, string *filename, int line, int column)
|
||||
location (context *ctxt, string *filename, int line, int column,
|
||||
bool created_by_user)
|
||||
: memento (ctxt),
|
||||
m_filename (filename),
|
||||
m_line (line),
|
||||
m_column (column)
|
||||
m_column (column),
|
||||
m_created_by_user (created_by_user)
|
||||
{}
|
||||
|
||||
void replay_into (replayer *r);
|
||||
@ -400,13 +413,18 @@ public:
|
||||
return static_cast <playback::location *> (m_playback_obj);
|
||||
}
|
||||
|
||||
location *dyn_cast_location () { return this; }
|
||||
bool created_by_user () const { return m_created_by_user; }
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
string *m_filename;
|
||||
int m_line;
|
||||
int m_column;
|
||||
bool m_created_by_user;
|
||||
};
|
||||
|
||||
class type : public memento
|
||||
@ -458,6 +476,8 @@ public:
|
||||
return static_cast <playback::type *> (m_playback_obj);
|
||||
}
|
||||
|
||||
virtual const char *access_as_type (reproducer &r);
|
||||
|
||||
protected:
|
||||
type (context *ctxt)
|
||||
: memento (ctxt),
|
||||
@ -504,6 +524,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
enum gcc_jit_types m_kind;
|
||||
@ -531,6 +552,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
type *m_other_type;
|
||||
@ -565,6 +587,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
type *m_other_type;
|
||||
@ -593,6 +616,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
type *m_other_type;
|
||||
@ -623,6 +647,7 @@ class array_type : public type
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
location *m_loc;
|
||||
@ -657,9 +682,14 @@ public:
|
||||
|
||||
string * make_debug_string_with_ptr ();
|
||||
|
||||
void
|
||||
write_deferred_reproducer (reproducer &r,
|
||||
memento *ptr_type);
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
string * make_debug_string_with (const char *);
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
type *m_return_type;
|
||||
@ -698,6 +728,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
location *m_loc;
|
||||
@ -757,9 +788,11 @@ public:
|
||||
|
||||
void replay_into (replayer *r);
|
||||
|
||||
const char *access_as_type (reproducer &r);
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
|
||||
void write_reproducer (reproducer &r);
|
||||
};
|
||||
|
||||
// memento of struct_::set_fields
|
||||
@ -774,8 +807,12 @@ public:
|
||||
|
||||
void write_to_dump (dump &d);
|
||||
|
||||
int length () const { return m_fields.length (); }
|
||||
field *get_field (int i) const { return m_fields[i]; }
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
compound_type *m_struct_or_union;
|
||||
@ -793,11 +830,11 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
location *m_loc;
|
||||
string *m_name;
|
||||
fields *m_fields;
|
||||
};
|
||||
|
||||
/* An abstract base class for operations that visit all rvalues within an
|
||||
@ -861,6 +898,8 @@ public:
|
||||
/* Dynamic cast. */
|
||||
virtual param *dyn_cast_param () { return NULL; }
|
||||
|
||||
virtual const char *access_as_rvalue (reproducer &r);
|
||||
|
||||
protected:
|
||||
location *m_loc;
|
||||
type *m_type;
|
||||
@ -893,6 +932,9 @@ public:
|
||||
|
||||
rvalue *
|
||||
as_rvalue () { return this; }
|
||||
|
||||
const char *access_as_rvalue (reproducer &r);
|
||||
virtual const char *access_as_lvalue (reproducer &r);
|
||||
};
|
||||
|
||||
class param : public lvalue
|
||||
@ -920,8 +962,12 @@ public:
|
||||
|
||||
param *dyn_cast_param () { return this; }
|
||||
|
||||
const char *access_as_rvalue (reproducer &r);
|
||||
const char *access_as_lvalue (reproducer &r);
|
||||
|
||||
private:
|
||||
string * make_debug_string () { return m_name; }
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
string *m_name;
|
||||
@ -978,6 +1024,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
location *m_loc;
|
||||
@ -1065,6 +1112,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
void replay_into (replayer *r);
|
||||
|
||||
@ -1103,6 +1151,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string () { return m_name; }
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
enum gcc_jit_global_kind m_kind;
|
||||
@ -1126,6 +1175,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
HOST_TYPE m_value;
|
||||
@ -1146,6 +1196,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
string *m_value;
|
||||
@ -1170,6 +1221,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
enum gcc_jit_unary_op m_op;
|
||||
@ -1195,6 +1247,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
enum gcc_jit_binary_op m_op;
|
||||
@ -1221,6 +1274,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
enum gcc_jit_comparison m_op;
|
||||
@ -1245,6 +1299,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_rvalue;
|
||||
@ -1265,6 +1320,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
function *m_func;
|
||||
@ -1286,6 +1342,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_fn_ptr;
|
||||
@ -1310,6 +1367,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_ptr;
|
||||
@ -1334,6 +1392,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
lvalue *m_lvalue;
|
||||
@ -1358,6 +1417,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_rvalue;
|
||||
@ -1382,6 +1442,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_rvalue;
|
||||
@ -1403,6 +1464,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_rvalue;
|
||||
@ -1424,6 +1486,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
lvalue *m_lvalue;
|
||||
@ -1448,6 +1511,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string () { return m_name; }
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
function *m_func;
|
||||
@ -1495,6 +1559,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_rvalue;
|
||||
@ -1515,6 +1580,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
lvalue *m_lvalue;
|
||||
@ -1538,6 +1604,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
lvalue *m_lvalue;
|
||||
@ -1558,6 +1625,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
string *m_text;
|
||||
@ -1583,6 +1651,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_boolval;
|
||||
@ -1606,6 +1675,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
block *m_target;
|
||||
@ -1627,6 +1697,7 @@ public:
|
||||
|
||||
private:
|
||||
string * make_debug_string ();
|
||||
void write_reproducer (reproducer &r);
|
||||
|
||||
private:
|
||||
rvalue *m_rvalue;
|
||||
|
@ -106,6 +106,8 @@ namespace gccjit
|
||||
int flags,
|
||||
int verbosity);
|
||||
|
||||
void dump_reproducer_to_file (const char *path);
|
||||
|
||||
void set_str_option (enum gcc_jit_str_option opt,
|
||||
const char *value);
|
||||
|
||||
@ -558,6 +560,13 @@ context::set_logfile (FILE *logfile,
|
||||
verbosity);
|
||||
}
|
||||
|
||||
inline void
|
||||
context::dump_reproducer_to_file (const char *path)
|
||||
{
|
||||
gcc_jit_context_dump_reproducer_to_file (m_inner_ctxt,
|
||||
path);
|
||||
}
|
||||
|
||||
inline void
|
||||
context::set_str_option (enum gcc_jit_str_option opt,
|
||||
const char *value)
|
||||
|
@ -386,7 +386,7 @@ gcc_jit_context_new_location (gcc_jit_context *ctxt,
|
||||
{
|
||||
RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
|
||||
JIT_LOG_FUNC (ctxt->get_logger ());
|
||||
return (gcc_jit_location *)ctxt->new_location (filename, line, column);
|
||||
return (gcc_jit_location *)ctxt->new_location (filename, line, column, true);
|
||||
}
|
||||
|
||||
/* Public entrypoint. See description in libgccjit.h.
|
||||
@ -2234,6 +2234,22 @@ gcc_jit_context_set_logfile (gcc_jit_context *ctxt,
|
||||
ctxt->set_logger (logger);
|
||||
}
|
||||
|
||||
/* Public entrypoint. See description in libgccjit.h.
|
||||
|
||||
After error-checking, the real work is done by the
|
||||
gcc::jit::recording::context::dump_reproducer_to_file method in
|
||||
jit-recording.c. */
|
||||
|
||||
void
|
||||
gcc_jit_context_dump_reproducer_to_file (gcc_jit_context *ctxt,
|
||||
const char *path)
|
||||
{
|
||||
RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
|
||||
JIT_LOG_FUNC (ctxt->get_logger ());
|
||||
RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
|
||||
ctxt->dump_reproducer_to_file (path);
|
||||
}
|
||||
|
||||
/* Public entrypoint. See description in libgccjit.h.
|
||||
|
||||
After error-checking, the real work is done by the
|
||||
|
@ -1051,6 +1051,24 @@ gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt);
|
||||
Implementation support.
|
||||
**********************************************************************/
|
||||
|
||||
/* Write C source code into "path" that can be compiled into a
|
||||
self-contained executable (i.e. with libgccjit as the only dependency).
|
||||
The generated code will attempt to replay the API calls that have been
|
||||
made into the given context.
|
||||
|
||||
This may be useful when debugging the library or client code, for
|
||||
reducing a complicated recipe for reproducing a bug into a simpler
|
||||
form.
|
||||
|
||||
Typically you need to supply the option "-Wno-unused-variable" when
|
||||
compiling the generated file (since the result of each API call is
|
||||
assigned to a unique variable within the generated C source, and not
|
||||
all are necessarily then used). */
|
||||
|
||||
extern void
|
||||
gcc_jit_context_dump_reproducer_to_file (gcc_jit_context *ctxt,
|
||||
const char *path);
|
||||
|
||||
/* Enable the dumping of a specific set of internal state from the
|
||||
compilation, capturing the result in-memory as a buffer.
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
gcc_jit_context_acquire;
|
||||
gcc_jit_context_compile;
|
||||
gcc_jit_context_dump_to_file;
|
||||
gcc_jit_context_dump_reproducer_to_file;
|
||||
gcc_jit_context_enable_dump;
|
||||
gcc_jit_context_get_builtin_function;
|
||||
gcc_jit_context_get_first_error;
|
||||
|
@ -1,3 +1,18 @@
|
||||
2015-01-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (set_up_logging): Move string concatenation
|
||||
into...
|
||||
(concat_strings): New function.
|
||||
(dump_reproducer): New function.
|
||||
(test_jit): Call dump_reproducer.
|
||||
* jit.dg/jit.exp (is_testcase_meant_to_generate_a_reproducer): New
|
||||
function.
|
||||
(jit-dg-test): Delete any generated reproducer from previous runs.
|
||||
Verify that a generated reproducer was created, and verify that it
|
||||
compiles.
|
||||
* jit.dg/test-nested-contexts.c (main): Call
|
||||
gcc_jit_context_dump_reproducer_to_file.
|
||||
|
||||
2015-01-13 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* gcc.dg/aru-2.c: Add dg-require-profiling.
|
||||
|
@ -250,6 +250,23 @@ static void set_options (gcc_jit_context *ctxt, const char *argv0)
|
||||
0);
|
||||
}
|
||||
|
||||
/* Concatenate two strings. The result must be released using "free". */
|
||||
|
||||
char *
|
||||
concat_strings (const char *prefix, const char *suffix)
|
||||
{
|
||||
char *result = (char *)malloc (strlen (prefix) + strlen (suffix) + 1);
|
||||
if (!result)
|
||||
{
|
||||
fail ("malloc failure");
|
||||
return NULL;
|
||||
}
|
||||
strcpy (result, prefix);
|
||||
strcpy (result + strlen (prefix), suffix);
|
||||
result[strlen (prefix) + strlen (suffix)] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef TEST_ESCHEWS_TEST_JIT
|
||||
/* Set up logging to a logfile of the form "test-FOO.exe.log.txt".
|
||||
|
||||
@ -271,18 +288,9 @@ set_up_logging (gcc_jit_context *ctxt, const char *argv0)
|
||||
FILE *logfile = NULL;
|
||||
|
||||
/* Build a logfile name of the form "test-FOO.exe.log.txt". */
|
||||
logfile_name = (char *)malloc (strlen (argv0)
|
||||
+ strlen (logfile_name_suffix)
|
||||
+ 1);
|
||||
logfile_name = concat_strings (argv0, logfile_name_suffix);
|
||||
if (!logfile_name)
|
||||
{
|
||||
fail ("malloc failure");
|
||||
return NULL;
|
||||
}
|
||||
strcpy (logfile_name, argv0);
|
||||
strcpy (logfile_name + strlen (argv0), logfile_name_suffix);
|
||||
logfile_name[strlen (argv0) + strlen (logfile_name_suffix)] = '\0';
|
||||
|
||||
return NULL;
|
||||
logfile = fopen (logfile_name, "w");
|
||||
CHECK_NON_NULL (logfile);
|
||||
free (logfile_name);
|
||||
@ -293,6 +301,21 @@ set_up_logging (gcc_jit_context *ctxt, const char *argv0)
|
||||
return logfile;
|
||||
}
|
||||
|
||||
/* Exercise the API entrypoint:
|
||||
gcc_jit_context_dump_reproducer_to_file
|
||||
by calling it on the context, using the path expected by jit.exp. */
|
||||
static void
|
||||
dump_reproducer (gcc_jit_context *ctxt, const char *argv0)
|
||||
{
|
||||
char *reproducer_name;
|
||||
reproducer_name = concat_strings (argv0, ".reproducer.c");
|
||||
if (!reproducer_name)
|
||||
return;
|
||||
note ("%s: writing reproducer to %s", test, reproducer_name);
|
||||
gcc_jit_context_dump_reproducer_to_file (ctxt, reproducer_name);
|
||||
free (reproducer_name);
|
||||
}
|
||||
|
||||
/* Run one iteration of the test. */
|
||||
static void
|
||||
test_jit (const char *argv0, void *user_data)
|
||||
@ -314,6 +337,8 @@ test_jit (const char *argv0, void *user_data)
|
||||
|
||||
create_code (ctxt, user_data);
|
||||
|
||||
dump_reproducer (ctxt, argv0);
|
||||
|
||||
/* This actually calls into GCC and runs the build, all
|
||||
in a mutex for now. */
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
|
@ -301,6 +301,21 @@ set tests [lsort $tests]
|
||||
|
||||
verbose "tests: $tests"
|
||||
|
||||
# Is testcase NAME meant to generate a reproducer?
|
||||
proc is_testcase_meant_to_generate_a_reproducer {name} {
|
||||
# We expect most testcases to generate a reproducer.
|
||||
# The exceptions are the tutorials (which don't have a "test-"
|
||||
# prefix), and test-threads.c (which is unique).
|
||||
verbose "is_testcase_meant_to_generate_a_reproducer: $name"
|
||||
if { [string match "*test-*" $name] } {
|
||||
if { [string match "*test-threads.c" $name] } {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
# libgloss has found the driver (as "xgcc" or "gcc) and stored
|
||||
# its full path as GCC_UNDER_TEST.
|
||||
proc get_path_of_driver {} {
|
||||
@ -365,6 +380,14 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
|
||||
return
|
||||
}
|
||||
|
||||
# Most of the test cases use gcc_jit_context_dump_reproducer_to_file
|
||||
# as they run to write out a .c file that reproduces their behavior,
|
||||
# exercising that API.
|
||||
set generated_reproducer "${output_file}.reproducer.c"
|
||||
|
||||
# Delete any such generated .c file from a previous run.
|
||||
catch "exec rm -f $generated_reproducer"
|
||||
|
||||
# Run the test executable, capturing the PASS/FAIL textual output
|
||||
# from the C API, converting it into the Tcl API.
|
||||
|
||||
@ -456,6 +479,54 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
|
||||
|
||||
restore_ld_library_path_env_vars
|
||||
|
||||
# Most of the test cases use gcc_jit_context_dump_reproducer_to_file
|
||||
# as they run to write out a .c file that reproduces their behavior,
|
||||
# exercising that API.
|
||||
|
||||
if { [is_testcase_meant_to_generate_a_reproducer $name] } {
|
||||
verbose "$name is meant to generate a reproducer"
|
||||
# Verify that a reproducer was generated
|
||||
if { [file exists $generated_reproducer] == 1} {
|
||||
pass "found generated reproducer: $generated_reproducer"
|
||||
set output_file "${generated_reproducer}.exe"
|
||||
# (this overwrites output_file)
|
||||
|
||||
# Try to compile the generated reproducer
|
||||
verbose "compilation_function=$compilation_function"
|
||||
|
||||
# The .c file written by gcc_jit_context_dump_reproducer_to_file
|
||||
# assigns the result of each API call to a unique variable, and not
|
||||
# all are necessarily used, so we need -Wno-unused-variable.
|
||||
set options \
|
||||
"{additional_flags=$extra_tool_flags -Wno-unused-variable}"
|
||||
verbose "options=$options"
|
||||
|
||||
set comp_output2 [$compilation_function $generated_reproducer \
|
||||
$output_file "executable" $options]
|
||||
if ![jit_check_compile "generated reproducer from $name" "initial compilation" \
|
||||
$output_file $comp_output2] then {
|
||||
return
|
||||
}
|
||||
|
||||
# The caller, dg-test, will verify comp_output, which contains
|
||||
# the output from compiling the testcase and will issue a fail
|
||||
# if it's non-empty (e.g. containing warnings, the
|
||||
# "test for excess errors").
|
||||
#
|
||||
# Append the output from compiling the reproducer, so that this is also
|
||||
# verified:
|
||||
append comp_output $comp_output2
|
||||
|
||||
# TODO: we should try to run the built executable
|
||||
# It's not quite a quine, since it embeds ptrs which could change
|
||||
# from run to run.
|
||||
} else {
|
||||
fail "did not find a generated reproducer: $generated_reproducer"
|
||||
}
|
||||
} else {
|
||||
verbose "$name is not meant to generate a reproducer"
|
||||
}
|
||||
|
||||
return [list $comp_output $output_file]
|
||||
}
|
||||
|
||||
|
@ -626,6 +626,14 @@ main (int argc, char **argv)
|
||||
"dump-of-test-nested-contexts-bottom.c",
|
||||
1);
|
||||
|
||||
/* Dump a reproducer for the bottom context.
|
||||
The generated reproducer needs to also regenerate the
|
||||
parent contexts, so this gives us test coverage for
|
||||
that case. */
|
||||
gcc_jit_context_dump_reproducer_to_file (
|
||||
bottom_level.ctxt,
|
||||
"test-nested-contexts.c.exe.reproducer.c");
|
||||
|
||||
gcc_jit_result *bottom_result =
|
||||
gcc_jit_context_compile (bottom_level.ctxt);
|
||||
verify_bottom_code (bottom_level.ctxt, bottom_result);
|
||||
|
Loading…
Reference in New Issue
Block a user