[jit] Implement source code location support (API change)
David Malcolm
dmalcolm@redhat.com
Tue Oct 15 01:17:00 GMT 2013
I've pushed the following to the "dmalcolm/jit" branch:
http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=6cc326e5ad7c269a295fb6108e34b5c885a96b12
This patch implements gcc_jit_location, so that client code can mark
the various constructs with an underlying code location. For example, a
JIT compiler for an interpreted scripting language may want to associate
the machine code with locations in the original script, allowing the
user to step through the JIT-compiled code in a debugger.
There is an API change in this patch:
gcc_jit_function_place_forward_label has gained a location as its
second parameter, and now has this signature:
extern void
gcc_jit_function_place_forward_label (gcc_jit_function *func,
gcc_jit_location *loc,
gcc_jit_label *lab);
An example of using this can be seen in jit.dg/test-fibonacci.c, where
the JIT code is set up to point the debugger at a comment within
that file containing C-like code. It is possible to step through this
comment in the debugger:
(gdb) break my_fibonacci
(gdb) run
Breakpoint 1, my_fibonacci (x=10) at testsuite/jit.dg/test-fibonacci.c:19
19 FIRST_LINE + 3: if (x < 2)
(gdb) list
14 0000000001111111111222222222233333333334444444444555555555566666666667
15 1234567890123456789012345678901234567890123456789012345678901234567890
16 FIRST_LINE + 0: int
17 FIRST_LINE + 1: my_fibonacci (int x)
18 FIRST_LINE + 2: {
19 FIRST_LINE + 3: if (x < 2)
20 FIRST_LINE + 4: return x;
21 FIRST_LINE + 5: else
22 FIRST_LINE + 6: return my_fibonacci (x - 1) + my_fibonacci (x - 2);
23 FIRST_LINE + 7: }
(gdb) next
22 FIRST_LINE + 6: return my_fibonacci (x - 1) + my_fibonacci (x - 2);
(gdb) p x
$1 = 10
(gdb) step
Breakpoint 1, my_fibonacci (x=9) at testsuite/jit.dg/test-fibonacci.c:19
19 FIRST_LINE + 3: if (x < 2)
File and line information appear to be correct, but looking at the .s
output, columns are zero, so there may be a bug in how I'm setting up
columns.
my_fibonacci:
.LFB0:
.file 1 "testsuite/jit.dg/test-fibonacci.c"
.loc 1 16 0
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
pushq %rbx
subq $24, %rsp
.cfi_offset 3, -24
movl %edi, -20(%rbp)
.loc 1 19 0
cmpl $2, -20(%rbp)
jge .L2
.loc 1 20 0
movl -20(%rbp), %eax
jmp .L4
.L2:
.loc 1 22 0
movl -20(%rbp), %eax
subl $1, %eax
movl %eax, %edi
call my_fibonacci@PLT
Implementation notes:
The linemap API appears to require source code locations to be created
in a very particular way, by creating references to files, and then,
within them, lines and columns, in the order the lines and columns
appear in the source file.
This is well-suited to a tokenizer, but for the JIT case we want to
allow the user to submit code without having to care about sorting
the source-code locations into order.
Hence internally we defer location creation: within the client's
code-creation hook, a gcc_jit_location represents a future location.
These are grouped by file and line, and a record is kept of associations
to be made between tree instances and gcc_jit_locations instances.
Upon return from the code-creation hook, all such locations are sorted,
and used in the linemap API to create source_location instances.
The various tree nodes then have their locations set to these instances.
---
gcc/jit/ChangeLog.jit | 58 ++++++
gcc/jit/internal-api.c | 300 ++++++++++++++++++++++++++---
gcc/jit/internal-api.h | 100 +++++++++-
gcc/jit/libgccjit.c | 13 +-
gcc/jit/libgccjit.h | 8 +
gcc/jit/libgccjit.map | 7 +-
gcc/testsuite/ChangeLog.jit | 10 +
gcc/testsuite/jit.dg/test-factorial.c | 4 +-
gcc/testsuite/jit.dg/test-fibonacci.c | 79 +++++---
gcc/testsuite/jit.dg/test-sum-of-squares.c | 2 +-
10 files changed, 516 insertions(+), 65 deletions(-)
diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index cb6c2dd..5c06a72 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,61 @@
+2013-10-14 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::new_field): Implement
+ location support, by calling set_tree_location.
+ (gcc::jit::context::new_struct_type): Likewise.
+ (gcc::jit::context::new_param): Likewise.
+ (gcc::jit::context::new_function): Likewise.
+ (gcc::jit::context::new_global): Likewise.
+ (gcc::jit::context::new_local): Likewise.
+ (gcc::jit::context::new_binary_op): Likewise.
+ (gcc::jit::context::new_comparison): Likewise.
+ (gcc::jit::context::new_call): Likewise.
+ (gcc::jit::context::new_array_lookup): Likewise.
+ (gcc::jit::context::new_field_access): Likewise.
+ (gcc::jit::context::add_assignment): Likewise.
+ (gcc::jit::context::add_conditional): Likewise.
+ (gcc::jit::function::add_label): Likewise.
+ (gcc::jit::function::add_jump): Likewise.
+ (gcc::jit::function::add_return): Likewise.
+ (gcc::jit::function::place_forward_label): Likewise, adding
+ location parameter.
+ (gcc::jit::loop::loop): Add loc arg to place_forward_label.
+ (gcc::jit::loop::end): Likewise.
+ (gcc::jit::context::invoke_code_factory): Call handle_locations
+ after the client callback is done, before any GC can run.
+ (line_comparator): New.
+ (location_comparator): New.
+ (gcc::jit::context::handle_locations): New.
+ (gcc::jit::context::new_location): New.
+ (gcc::jit::context::set_tree_location): New.
+ (gcc::jit::context::get_source_file): New.
+ (gcc::jit::source_file::source_file): New.
+ (gcc::jit::source_file::get_source_line): New.
+ (gcc::jit::source_line::source_line): New.
+ (gcc::jit::source_line::get_location): New.
+ (gcc::jit::location::location): New.
+ * internal-api.h (gcc::jit::context::new_location): New.
+ (gcc::jit::context::set_tree_location): New.
+ (gcc::jit::context::handle_locations): New.
+ (gcc::jit::context::get_source_file): New.
+ (gcc::jit::context::m_source_files): New field.
+ (gcc::jit::context::m_cached_locations: New field.
+ (gcc::jit::function::place_forward_label): Add location
+ parameter.
+ (gcc::jit::function::set_tree_location): New.
+ (gcc::jit::source_file): New class.
+ (gcc::jit::source_line): New class.
+ (gcc::jit::location): New class.
+ * libgccjit.c (gcc_jit_context_new_location): New.
+ (gcc_jit_function_place_forward_label): Add location parameter,
+ changing public API.
+ * libgccjit.h (gcc_jit_context_new_location): New.
+ (gcc_jit_function_place_forward_label): Add location parameter,
+ changing public API.
+ * libgccjit.map (gcc_jit_context_new_location): New.
+ (main): Remove obsolete export.
+ (called_function): Likewise.
+
2013-10-11 David Malcolm <dmalcolm@redhat.com>
* internal-api.c: Update includes to reflect move of decl of
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index bec8544..158ea40 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -108,7 +108,6 @@ new_field (gcc::jit::location *loc,
gcc::jit::type *type,
const char *name)
{
- gcc_assert (NULL == loc);
gcc_assert (type);
gcc_assert (name);
@@ -116,6 +115,9 @@ new_field (gcc::jit::location *loc,
tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
get_identifier (name), type->as_tree ());
+ if (loc)
+ set_tree_location (decl, loc);
+
return new field (decl);
}
@@ -126,7 +128,6 @@ new_struct_type (gcc::jit::location *loc,
int num_fields,
gcc::jit::field **fields)
{
- gcc_assert (NULL == loc);
gcc_assert (name);
gcc_assert ((num_fields == 0) || fields);
@@ -148,6 +149,9 @@ new_struct_type (gcc::jit::location *loc,
layout_type (t);
+ if (loc)
+ set_tree_location (t, loc);
+
return new type (t);
}
@@ -158,11 +162,13 @@ new_param (location *loc,
type *type,
const char *name)
{
- gcc_assert (NULL == loc);
gcc_assert (type);
gcc_assert (name);
tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
get_identifier (name), type->as_tree ());
+ if (loc)
+ set_tree_location (inner, loc);
+
return new param (inner);
}
@@ -176,7 +182,6 @@ new_function (location *loc,
param **params,
int is_variadic)
{
- gcc_assert (NULL == loc);
//can return_type be NULL?
gcc_assert (name);
gcc_assert ((num_params == 0) || params);
@@ -198,6 +203,9 @@ new_function (location *loc,
/* FIXME: this uses input_location: */
tree fndecl = build_fn_decl (name, fn_type);
+ if (loc)
+ set_tree_location (fndecl, loc);
+
tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
NULL_TREE, return_type->as_tree ());
DECL_ARTIFICIAL (resdecl) = 1;
@@ -237,7 +245,6 @@ new_global (location *loc,
type *type,
const char *name)
{
- gcc_assert (NULL == loc);
gcc_assert (type);
gcc_assert (name);
tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
@@ -247,6 +254,9 @@ new_global (location *loc,
DECL_COMMON (inner) = 1;
DECL_EXTERNAL (inner) = 1;
+ if (loc)
+ set_tree_location (inner, loc);
+
return new lvalue (inner);
}
@@ -256,12 +266,13 @@ new_local (location *loc,
type *type,
const char *name)
{
- gcc_assert (NULL == loc);
gcc_assert (type);
gcc_assert (name);
tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
get_identifier (name),
type->as_tree ());
+ if (loc)
+ set_tree_location (inner, loc);
return new local (inner);
}
@@ -313,7 +324,6 @@ new_binary_op (location *loc,
// FIXME: type-checking, or coercion?
enum tree_code inner_op;
- gcc_assert (NULL == loc);
gcc_assert (result_type);
gcc_assert (a);
gcc_assert (b);
@@ -338,6 +348,9 @@ new_binary_op (location *loc,
result_type->as_tree (),
a->as_tree (),
b->as_tree ());
+ if (loc)
+ set_tree_location (inner_expr, loc);
+
return new rvalue (inner_expr);
}
@@ -350,7 +363,6 @@ new_comparison (location *loc,
// FIXME: type-checking, or coercion?
enum tree_code inner_op;
- gcc_assert (NULL == loc);
gcc_assert (a);
gcc_assert (b);
@@ -369,6 +381,8 @@ new_comparison (location *loc,
boolean_type_node,
a->as_tree (),
b->as_tree ());
+ if (loc)
+ set_tree_location (inner_expr, loc);
return new rvalue (inner_expr);
}
@@ -381,7 +395,6 @@ new_call (location *loc,
tree fndecl;
vec<tree, va_gc> *tree_args;
- gcc_assert (NULL == loc);
gcc_assert (func);
gcc_assert (numargs >= 0);
gcc_assert ((args == 0) || (args != NULL));
@@ -398,6 +411,9 @@ new_call (location *loc,
tree fntype = TREE_TYPE (fndecl);
tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+ if (loc)
+ set_tree_location (fn, loc);
+
return new rvalue (build_call_vec (func->get_return_type_as_tree (),
fn, tree_args));
@@ -418,7 +434,6 @@ new_array_lookup (location *loc,
rvalue *ptr,
rvalue *index)
{
- gcc_assert (NULL == loc);
gcc_assert (ptr);
gcc_assert (index);
@@ -435,6 +450,8 @@ new_array_lookup (location *loc,
{
tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
NULL_TREE, NULL_TREE);
+ if (loc)
+ set_tree_location (t_result, loc);
return new rvalue (t_result);
}
else
@@ -448,6 +465,14 @@ new_array_lookup (location *loc,
tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+ if (loc)
+ {
+ set_tree_location (t_sizeof, loc);
+ set_tree_location (t_offset, loc);
+ set_tree_location (t_address, loc);
+ set_tree_location (t_indirection, loc);
+ }
+
return new rvalue (t_indirection);
}
}
@@ -467,7 +492,6 @@ new_field_access (location *loc,
rvalue *ptr_or_struct,
const char *fieldname)
{
- gcc_assert (NULL == loc);
gcc_assert (ptr_or_struct);
gcc_assert (fieldname);
@@ -479,6 +503,8 @@ new_field_access (location *loc,
if (TREE_CODE (type) == POINTER_TYPE)
{
datum = build1 (INDIRECT_REF, type, datum);
+ if (loc)
+ set_tree_location (datum, loc);
type = TREE_TYPE (type);
}
@@ -491,6 +517,8 @@ new_field_access (location *loc,
}
tree ref = build3 (COMPONENT_REF, TREE_TYPE (field), datum,
field, NULL_TREE);
+ if (loc)
+ set_tree_location (ref, loc);
return new lvalue (ref);
}
@@ -603,7 +631,6 @@ add_assignment (location *loc,
lvalue *lvalue,
rvalue *rvalue)
{
- gcc_assert (NULL == loc);
gcc_assert (lvalue);
gcc_assert (rvalue);
gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
@@ -611,13 +638,19 @@ add_assignment (location *loc,
tree t_lvalue = lvalue->as_tree ();
tree t_rvalue = rvalue->as_tree ();
if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
- t_rvalue = build1 (CONVERT_EXPR,
- TREE_TYPE (t_lvalue),
- t_rvalue);
+ {
+ t_rvalue = build1 (CONVERT_EXPR,
+ TREE_TYPE (t_lvalue),
+ t_rvalue);
+ if (loc)
+ set_tree_location (t_rvalue, loc);
+ }
tree stmt =
build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
t_lvalue, t_rvalue);
+ if (loc)
+ set_tree_location (stmt, loc);
tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
}
@@ -628,7 +661,6 @@ add_conditional (location *loc,
label *on_true,
label *on_false)
{
- gcc_assert (NULL == loc);
gcc_assert (boolval);
gcc_assert (on_true);
/* on_false can be NULL */
@@ -639,16 +671,24 @@ add_conditional (location *loc,
Shim it by creating jumps to the labels */
tree true_jump = build1 (GOTO_EXPR, void_type_node,
on_true->as_label_decl ());
+ if (loc)
+ set_tree_location (true_jump, loc);
tree false_jump;
if (on_false)
- false_jump = build1 (GOTO_EXPR, void_type_node,
- on_false->as_label_decl ());
+ {
+ false_jump = build1 (GOTO_EXPR, void_type_node,
+ on_false->as_label_decl ());
+ if (loc)
+ set_tree_location (false_jump, loc);
+ }
else
false_jump = NULL;
tree stmt =
build3 (COND_EXPR, void_type_node, boolval->as_tree (),
true_jump, false_jump);
+ if (loc)
+ set_tree_location (stmt, loc);
tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
}
@@ -657,17 +697,16 @@ gcc::jit::function::
add_label (location *loc,
const char *name)
{
- gcc_assert (NULL == loc);
gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
label *lab = new label (this, name);
- place_forward_label (lab);
+ place_forward_label (loc, lab);
return lab;
}
void
gcc::jit::function::
-place_forward_label (label *lab)
+place_forward_label (location *loc, label *lab)
{
gcc_assert (lab);
gcc_assert (NULL == lab->m_label_expr); // must not have already been placed
@@ -676,6 +715,8 @@ place_forward_label (label *lab)
lab->m_label_expr = build1 (LABEL_EXPR,
void_type_node,
lab->as_label_decl ());
+ if (loc)
+ set_tree_location (lab->m_label_expr, loc);
tsi_link_after (&m_stmt_iter, lab->m_label_expr, TSI_CONTINUE_LINKING);
}
@@ -684,7 +725,6 @@ gcc::jit::function::
add_jump (location *loc,
label *target)
{
- gcc_assert (NULL == loc);
gcc_assert (target);
gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
@@ -695,6 +735,8 @@ add_jump (location *loc,
//tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
TREE_USED (target->as_label_decl ()) = 1;
tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
+ if (loc)
+ set_tree_location (stmt, loc);
tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
/*
@@ -721,7 +763,6 @@ gcc::jit::function::
add_return (location *loc,
rvalue *rvalue)
{
- gcc_assert (NULL == loc);
gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
tree return_type = TREE_TYPE (TREE_TYPE (m_inner_fndecl));
@@ -735,6 +776,11 @@ add_return (location *loc,
t_lvalue, t_rvalue);
tree return_stmt = build1 (RETURN_EXPR, return_type,
modify_retval);
+ if (loc)
+ {
+ set_tree_location (modify_retval, loc);
+ set_tree_location (return_stmt, loc);
+ }
tsi_link_after (&m_stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
}
@@ -773,7 +819,7 @@ loop (function *func, location *loc, rvalue *boolval) :
m_label_body = func->new_forward_label ("loop_body");
m_label_end = func->new_forward_label ("loop_end");
func->add_conditional (loc, boolval, m_label_body, m_label_end);
- func->place_forward_label (m_label_body);
+ func->place_forward_label (loc, m_label_body);
}
void
@@ -781,7 +827,7 @@ gcc::jit::loop::
end (location *loc)
{
m_func->add_jump (loc, m_label_cond);
- m_func->place_forward_label (m_label_end);
+ m_func->place_forward_label (loc, m_label_end);
}
void
@@ -1030,6 +1076,11 @@ invoke_code_factory ()
{
int i;
function *func;
+
+ /* No GC can happen yet; process the cached source locations. */
+ handle_locations ();
+
+ /* Postprocess the functions. This could trigger GC. */
FOR_EACH_VEC_ELT (m_functions, i, func)
{
gcc_assert (func);
@@ -1038,6 +1089,102 @@ invoke_code_factory ()
}
}
+static int
+line_comparator (const void *lhs, const void *rhs)
+{
+ const gcc::jit::source_line *line_lhs = \
+ *static_cast<const gcc::jit::source_line * const*> (lhs);
+ const gcc::jit::source_line *line_rhs = \
+ *static_cast<const gcc::jit::source_line * const*> (rhs);
+ return line_lhs->get_line_num () - line_rhs->get_line_num ();
+}
+
+static int
+location_comparator (const void *lhs, const void *rhs)
+{
+ const gcc::jit::location *loc_lhs = \
+ *static_cast<const gcc::jit::location * const *> (lhs);
+ const gcc::jit::location *loc_rhs = \
+ *static_cast<const gcc::jit::location * const *> (rhs);
+ return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
+}
+
+void
+gcc::jit::context::
+handle_locations ()
+{
+ /* Create the source code locations, following the ordering rules
+ imposed by the linemap API.
+
+ line_table is a global. */
+ int i;
+ source_file *file;
+
+ FOR_EACH_VEC_ELT (m_source_files, i, file)
+ {
+ linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
+
+ /* Sort lines by ascending line numbers. */
+ file->m_source_lines.qsort (&line_comparator);
+
+ int j;
+ source_line *line;
+ FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
+ {
+ int k;
+ location *loc;
+
+ /* Sort locations in line by ascending column numbers. */
+ line->m_locations.qsort (&location_comparator);
+
+ /* Determine maximum column within this line. */
+ gcc_assert (line->m_locations.length () > 0);
+ location *final_column =
+ line->m_locations[line->m_locations.length () - 1];
+ int max_col = final_column->get_column_num ();
+
+ linemap_line_start (line_table, line->get_line_num (), max_col);
+ FOR_EACH_VEC_ELT (line->m_locations, k, loc)
+ {
+ loc->m_srcloc = \
+ linemap_position_for_column (line_table, loc->get_column_num ());
+ }
+ }
+
+ linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+ }
+
+ /* Now assign them to tree nodes as appropriate. */
+ std::pair<tree, location *> *cached_location;
+
+ FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
+ {
+ tree t = cached_location->first;
+ source_location srcloc = cached_location->second->m_srcloc;
+#if 0
+ inform (srcloc, "location of ");
+ debug_tree (t);
+#endif
+
+ /* This covers expressions: */
+ if (CAN_HAVE_LOCATION_P (t))
+ SET_EXPR_LOCATION (t, srcloc);
+ else if (DECL_MINIMAL_CHECK (t))
+ DECL_SOURCE_LOCATION (t) = srcloc;
+ else
+ {
+ /* Don't know how to set location on this node. */
+ if (0)
+ {
+ fprintf (stderr, "can't set location on:");
+ debug_tree (t);
+ fprintf (stderr, "\n");
+ }
+ }
+ }
+}
+
+
void
gcc::jit::context::
add_error (const char */*msg*/)
@@ -1075,3 +1222,106 @@ get_code (const char *funcname)
return code;
}
+
+/* Dealing with the linemap API. */
+
+gcc::jit::location *
+gcc::jit::context::
+new_location (const char *filename,
+ int line,
+ int column)
+{
+ /* Get the source_file for filename, creating if necessary. */
+ source_file *src_file = get_source_file (filename);
+ /* Likewise for the line within the file. */
+ source_line *src_line = src_file->get_source_line (line);
+ /* Likewise for the column within the line. */
+ location *loc = src_line->get_location (column);
+ return loc;
+}
+
+void
+gcc::jit::context::
+set_tree_location (tree t, location *loc)
+{
+ m_cached_locations.safe_push (std::make_pair (t, loc));
+}
+
+
+gcc::jit::source_file *
+gcc::jit::context::
+get_source_file (const char *filename)
+{
+ /* Locate the file.
+ For simplicitly, this is currently a linear search.
+ Replace with a hash if this shows up in the profile. */
+ int i;
+ source_file *file;
+ tree ident_filename = get_identifier (filename);
+
+ FOR_EACH_VEC_ELT (m_source_files, i, file)
+ if (file->filename_as_tree () == ident_filename)
+ return file;
+
+ /* Not found. */
+ file = new source_file (ident_filename);
+ m_source_files.safe_push (file);
+ return file;
+}
+
+gcc::jit::source_file::source_file (tree filename) :
+ m_source_lines (),
+ m_filename (filename)
+{
+}
+
+gcc::jit::source_line *
+gcc::jit::source_file::
+get_source_line (int line_num)
+{
+ /* Locate the line.
+ For simplicitly, this is currently a linear search.
+ Replace with a hash if this shows up in the profile. */
+ int i;
+ source_line *line;
+
+ FOR_EACH_VEC_ELT (m_source_lines, i, line)
+ if (line->get_line_num () == line_num)
+ return line;
+
+ /* Not found. */
+ line = new source_line (this, line_num);
+ m_source_lines.safe_push (line);
+ return line;
+}
+
+gcc::jit::source_line::source_line (source_file *file, int line_num) :
+ m_locations (),
+ m_source_file (file),
+ m_line_num (line_num)
+{
+}
+
+gcc::jit::location *
+gcc::jit::source_line::
+get_location (int column_num)
+{
+ int i;
+ location *loc;
+
+ /* Another linear search that probably should be a hash table. */
+ FOR_EACH_VEC_ELT (m_locations, i, loc)
+ if (loc->get_column_num () == column_num)
+ return loc;
+
+ /* Not found. */
+ loc = new location (this, column_num);
+ m_locations.safe_push (loc);
+ return loc;
+}
+
+gcc::jit::location::location (source_line *line, int column_num) :
+ m_line (line),
+ m_column_num(column_num)
+{
+}
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 7124d1d..32ec1ba 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -3,11 +3,15 @@
#include "tree.h"
#include "tree-iterator.h"
+#include <utility> // for std::pair
+
namespace gcc {
namespace jit {
class result;
+class source_file;
+class source_line;
class location;
class type;
class field;
@@ -31,6 +35,11 @@ public:
set_code_factory (gcc_jit_code_callback cb,
void *user_data);
+ location *
+ new_location (const char *filename,
+ int line,
+ int column);
+
type *
get_void_type ();
@@ -145,6 +154,15 @@ public:
void
add_error (const char *msg);
+ void
+ set_tree_location (tree t, location *loc);
+
+private:
+ source_file *
+ get_source_file (const char *filename);
+
+ void handle_locations ();
+
private:
gcc_jit_code_callback m_code_factory;
bool m_within_code_factory;
@@ -168,6 +186,11 @@ private:
bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
tree m_char_array_type_node;
tree m_const_char_ptr;
+
+ /* Source location handling. */
+ vec<source_file *> m_source_files;
+
+ vec<std::pair<tree, location *> > m_cached_locations;
};
/* The result of JIT-compilation. */
@@ -202,10 +225,6 @@ public:
};
-class location : public wrapper
-{
-};
-
class type : public wrapper
{
public:
@@ -273,7 +292,7 @@ public:
const char *name);
void
- place_forward_label (label *lab);
+ place_forward_label (location *loc, label *lab);
void
add_jump (location *loc,
@@ -294,6 +313,13 @@ public:
context *m_ctxt;
private:
+ void
+ set_tree_location (tree t, location *loc)
+ {
+ m_ctxt->set_tree_location (t, loc);
+ }
+
+private:
tree m_inner_fndecl;
enum gcc_jit_function_kind m_kind;
tree m_stmt_list;
@@ -375,6 +401,70 @@ private:
label *m_label_end;
};
+/* Dealing with the linemap API.
+
+ It appears that libcpp requires locations to be created as if by
+ a tokenizer, creating them by filename, in ascending order of
+ line/column, whereas our API doesn't impose any such constraints:
+ we allow client code to create locations in arbitrary orders.
+
+ To square this circle, we need to cache all location creation,
+ grouping things up by filename/line, and then creating the linemap
+ entries in a post-processing phase. */
+
+/* A set of locations, all sharing a filename */
+class source_file : public wrapper
+{
+public:
+ source_file (tree filename);
+
+ source_line *
+ get_source_line (int line_num);
+
+ tree filename_as_tree () const { return m_filename; }
+
+ const char*
+ get_filename () const { return IDENTIFIER_POINTER (m_filename); }
+
+ vec<source_line *> m_source_lines;
+
+private:
+ tree m_filename;
+};
+
+/* A source line, with one or more locations of interest. */
+class source_line : public wrapper
+{
+public:
+ source_line (source_file *file, int line_num);
+
+ location *
+ get_location (int column_num);
+
+ int get_line_num () const { return m_line_num; }
+
+ vec<location *> m_locations;
+
+private:
+ source_file *m_source_file;
+ int m_line_num;
+};
+
+/* A specific location on a source line. This is what we expose
+ to the client API. */
+class location : public wrapper
+{
+public:
+ location (source_line *line, int column_num);
+
+ int get_column_num () const { return m_column_num; }
+
+ source_location m_srcloc;
+
+private:
+ source_line *m_line;
+ int m_column_num;
+};
} // namespace gcc::jit
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 3dceba9..50ccae1 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -90,6 +90,16 @@ gcc_jit_context_set_code_factory (gcc_jit_context *ctxt,
gcc_assert (!(CTXT)->within_code_factory ()); \
} while (0)
+gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+ const char *filename,
+ int line,
+ int column)
+{
+ ASSERT_WITHIN_CALLBACK (ctxt);
+ return (gcc_jit_location *)ctxt->new_location (filename, line, column);
+}
+
gcc_jit_type *
gcc_jit_context_get_void_type (gcc_jit_context *ctxt)
{
@@ -343,9 +353,10 @@ gcc_jit_function_add_label (gcc_jit_function *func,
void
gcc_jit_function_place_forward_label (gcc_jit_function *func,
+ gcc_jit_location *loc,
gcc_jit_label *lab)
{
- func->place_forward_label (lab);
+ func->place_forward_label (loc, lab);
}
void
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 88a8dd2..a17ab09 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -236,6 +236,13 @@ gcc_jit_result_release (gcc_jit_result *result);
/**********************************************************************
Functions for use within the code factory.
**********************************************************************/
+/* Creating source code locations for use by the debugger.
+ Line and column numbers are 1-based. */
+extern gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+ const char *filename,
+ int line,
+ int column);
/* Access to specific types. */
extern gcc_jit_type *
@@ -442,6 +449,7 @@ gcc_jit_function_add_label (gcc_jit_function *func,
extern void
gcc_jit_function_place_forward_label (gcc_jit_function *func,
+ gcc_jit_location *loc,
gcc_jit_label *lab);
extern void
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 9593672..859dc5e 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -4,6 +4,7 @@
gcc_jit_context_acquire;
gcc_jit_context_release;
gcc_jit_context_set_code_factory;
+ gcc_jit_context_new_location;
gcc_jit_context_get_void_type;
gcc_jit_context_get_char_type;
gcc_jit_context_get_int_type;
@@ -49,11 +50,5 @@
gcc_jit_result_get_code;
gcc_jit_result_release;
- # For now:
- main;
-
- # For use by test functions:
- called_function;
-
local: *;
};
\ No newline at end of file
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 40fb34d..3d63d4b 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,13 @@
+2013-10-14 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-factorial.c (code_making_callback): Update
+ for change to gcc_jit_function_place_forward_label.
+ * jit.dg/test-fibonacci.c (code_making_callback): Add line
+ numbering to comment, and set up source locations throughout)
+ allowing stepping throught the comment in the debugger.
+ * jit.dg/test-sum-of-squares.c (code_making_callback): Update
+ for change to gcc_jit_function_place_forward_label.
+
2013-10-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h: Set GCC_JIT_BOOL_OPTION_DUMP_SUMMARY when
diff --git a/gcc/testsuite/jit.dg/test-factorial.c b/gcc/testsuite/jit.dg/test-factorial.c
index d3b83ba..90b4fbe 100644
--- a/gcc/testsuite/jit.dg/test-factorial.c
+++ b/gcc/testsuite/jit.dg/test-factorial.c
@@ -57,7 +57,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
label_false);
/* true branch: */
- gcc_jit_function_place_forward_label (func, label_true);
+ gcc_jit_function_place_forward_label (func, NULL, label_true);
/* return x */
gcc_jit_function_add_return (
func,
@@ -65,7 +65,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
gcc_jit_param_as_rvalue (x));
/* false branch: */
- gcc_jit_function_place_forward_label (func, label_false);
+ gcc_jit_function_place_forward_label (func, NULL, label_false);
gcc_jit_rvalue *x_minus_1 =
gcc_jit_context_new_binary_op (
ctxt, NULL,
diff --git a/gcc/testsuite/jit.dg/test-fibonacci.c b/gcc/testsuite/jit.dg/test-fibonacci.c
index 235e86e..215546c 100644
--- a/gcc/testsuite/jit.dg/test-fibonacci.c
+++ b/gcc/testsuite/jit.dg/test-fibonacci.c
@@ -9,25 +9,41 @@
int
code_making_callback (gcc_jit_context *ctxt, void *user_data)
{
+ const int FIRST_LINE = __LINE__ + 4;
/* Let's try to inject the equivalent of:
+0000000001111111111222222222233333333334444444444555555555566666666667
+1234567890123456789012345678901234567890123456789012345678901234567890
+FIRST_LINE + 0: int
+FIRST_LINE + 1: my_fibonacci (int x)
+FIRST_LINE + 2: {
+FIRST_LINE + 3: if (x < 2)
+FIRST_LINE + 4: return x;
+FIRST_LINE + 5: else
+FIRST_LINE + 6: return my_fibonacci (x - 1) + my_fibonacci (x - 2);
+FIRST_LINE + 7: }
+0000000001111111111222222222233333333334444444444555555555566666666667
+1234567890123456789012345678901234567890123456789012345678901234567890
- fib.c: 1: int
- fib.c: 2: my_fibonacci (int x)
- fib.c: 3: {
- fib.c: 4: if (x < 2)
- fib.c: 5: return x;
- fib.c: 6: else
- fib.c: 7 return my_fibonacci (x - 1) + my_fibonacci (x - 2);
- fib.c: 8 }
+ where the source locations are set up to point to the commented-out
+ code above.
+ It should therefore be possible to step through the generated code
+ in the debugger, stepping through the above commented-out code
+ fragement.
*/
gcc_jit_type *the_type = gcc_jit_context_get_int_type (ctxt);
gcc_jit_type *return_type = the_type;
gcc_jit_param *x =
- gcc_jit_context_new_param (ctxt, NULL, the_type, "x");
+ gcc_jit_context_new_param (
+ ctxt,
+ gcc_jit_context_new_location (
+ ctxt, __FILE__, FIRST_LINE + 1, 35),
+ the_type, "x");
gcc_jit_param *params[1] = {x};
gcc_jit_function *func =
- gcc_jit_context_new_function (ctxt, NULL,
+ gcc_jit_context_new_function (ctxt,
+ gcc_jit_context_new_location (
+ ctxt, __FILE__, FIRST_LINE, 17),
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"my_fibonacci",
@@ -42,9 +58,11 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
/* if (x < 2) */
gcc_jit_function_add_conditional (
- func, NULL,
+ func,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 19),
gcc_jit_context_new_comparison (
- ctxt, NULL,
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 25),
GCC_JIT_COMPARISON_LT,
gcc_jit_param_as_rvalue (x),
gcc_jit_context_new_rvalue_from_int (
@@ -55,18 +73,25 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
label_false);
/* true branch: */
- gcc_jit_function_place_forward_label (func, label_true);
+ gcc_jit_function_place_forward_label (
+ func,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 4, 21),
+ label_true);
/* return x */
gcc_jit_function_add_return (
func,
- NULL,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 4, 21),
gcc_jit_param_as_rvalue (x));
/* false branch: */
- gcc_jit_function_place_forward_label (func, label_false);
+ gcc_jit_function_place_forward_label (
+ func,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 21),
+ label_false);
gcc_jit_rvalue *x_minus_1 =
gcc_jit_context_new_binary_op (
- ctxt, NULL,
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 44),
GCC_JIT_BINARY_OP_MINUS, the_type,
gcc_jit_param_as_rvalue (x),
gcc_jit_context_new_rvalue_from_int (
@@ -75,7 +100,8 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
1));
gcc_jit_rvalue *x_minus_2 =
gcc_jit_context_new_binary_op (
- ctxt, NULL,
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 67),
GCC_JIT_BINARY_OP_MINUS, the_type,
gcc_jit_param_as_rvalue (x),
gcc_jit_context_new_rvalue_from_int (
@@ -84,20 +110,23 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
2));
gcc_jit_function_add_return (
func,
- NULL,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 21),
gcc_jit_context_new_binary_op (
- ctxt, NULL,
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 49),
GCC_JIT_BINARY_OP_PLUS, the_type,
/* my_fibonacci (x - 1) */
gcc_jit_context_new_call (
- ctxt, NULL,
- func,
- 1, &x_minus_1),
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 28),
+ func,
+ 1, &x_minus_1),
/* my_fibonacci (x - 2) */
gcc_jit_context_new_call (
- ctxt, NULL,
- func,
- 1, &x_minus_2)));
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 51),
+ func,
+ 1, &x_minus_2)));
return 0;
}
diff --git a/gcc/testsuite/jit.dg/test-sum-of-squares.c b/gcc/testsuite/jit.dg/test-sum-of-squares.c
index 4f1685d..bef0457 100644
--- a/gcc/testsuite/jit.dg/test-sum-of-squares.c
+++ b/gcc/testsuite/jit.dg/test-sum-of-squares.c
@@ -106,7 +106,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data)
label_cond);
/* label "after_loop:" */
- gcc_jit_function_place_forward_label (func, label_after_loop);
+ gcc_jit_function_place_forward_label (func, NULL, label_after_loop);
/* return sum */
gcc_jit_function_add_return (
--
1.7.11.7
More information about the Gcc-patches
mailing list