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:
David Malcolm 2015-01-13 22:14:46 +00:00 committed by David Malcolm
parent 9c80f9197e
commit 86d0ac8876
16 changed files with 2354 additions and 413 deletions

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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
-------

View File

@ -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.

View File

@ -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, \

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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]
}

View 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);