From patchwork Tue Oct 15 01:04:48 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 283432 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0F6E52C0185 for ; Tue, 15 Oct 2013 12:05:30 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; q=dns; s=default; b=Hp/zqymQpIOv BDLcPa8W1pLGZ40efB3G/8GFO6kAgqgrwUYThFrEeldeZsd1qF9u4x6we4bsBfer KimtBuUtkqvHYp05lQ0TWz9tno4aDUT1q/jzNDjwcyoiXFjfjyIHHTe76RpwhAR+ 7/773j0neqNN10V518KaNLr5H0KjAP4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; s=default; bh=E095AhPNAkRUqlv+SR x3pVXbfEs=; b=vl2HlrLbuX+m2DoLsWb1G+NTL2mmRj0siQ4Vy+zyWiMIXFLZ0T 6IKWGSW68+UBJfxnhpZqCvtVtsjQoytman9YPUWuuxY2jzbTjiZewTLhLTvaBs7v JLkeiRd/gR86jarS+0SlbsP+Etxoa9ECtQU+GQMcLkDdRJQAdf8z6IH78= Received: (qmail 19508 invoked by alias); 15 Oct 2013 01:05:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 19490 invoked by uid 89); 15 Oct 2013 01:05:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.1 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 15 Oct 2013 01:05:19 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r9F15HWj018000 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 14 Oct 2013 21:05:17 -0400 Received: from surprise.redhat.com (vpn-239-52.phx2.redhat.com [10.3.239.52]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r9F15GbO022319; Mon, 14 Oct 2013 21:05:16 -0400 From: David Malcolm To: gcc-patches@gcc.gnu.org, jit@gcc.gnu.org Cc: David Malcolm Subject: [jit] Implement source code location support (API change) Date: Mon, 14 Oct 2013 21:04:48 -0400 Message-Id: <1381799088-2728-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes 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 + + * 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 * 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_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 (lhs); + const gcc::jit::source_line *line_rhs = \ + *static_cast (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 (lhs); + const gcc::jit::location *loc_rhs = \ + *static_cast (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 *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 // 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 m_source_files; + + vec > 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 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 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 + + * 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 * 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 (