From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-f51.google.com (mail-ej1-f51.google.com [209.85.218.51]) by sourceware.org (Postfix) with ESMTPS id CEAE93858D28; Mon, 31 Jan 2022 11:27:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CEAE93858D28 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=nieper-wisskirchen.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-f51.google.com with SMTP id ka4so41969506ejc.11; Mon, 31 Jan 2022 03:27:34 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=kLkjBDdxPRjjr0lKBmNnlde+WdtCmlUaMwGoXDyoygg=; b=ij+t50Y7msk/P9B7os3xsb/RRzX9+B51HxEG5OU8H1duE0Q8Kb9gqBTj5yEUfHozce xsrza8vTFDj2BF4fvefGSj6kibSVsQTC6Lzm7bTlpXIS/vH4iWfMaqBNe8EEUZzey3gc sUguJJeHh7pLch6LZAE8WNmeWOw2PKl0EK3tm/f1gC/gkgebDqjKYaEtCHVre0+LL8/m ZVEwcczU1fPuXpEJpYNeX7hg2gh59dB26Y8ZJnmtF1tkXYj/U49eo61FxOREyKjaPX5c 1CeYdlyOvRqrlrG1aoB5vXAD5rj/mWCwgVKkn8Ii/EoSLcDwWUlUvXWXKQmwZPt3CHR5 Caxg== X-Gm-Message-State: AOAM532bn4FgCTa4RJTEr+n58S1+0cl2Ub0jUJpW6aZi9h4g+Kx9ES2n 23bgJ7DSpe8T05CtjO3GMCzhEMEpm6A= X-Google-Smtp-Source: ABdhPJyeaBKoLbuXWL1K0FawLDGr2rNpcELYgQbb5dFPczB526laA/dwnuMl81AikQlbej8IVbsEZA== X-Received: by 2002:a17:907:9725:: with SMTP id jg37mr16755920ejc.396.1643628453095; Mon, 31 Jan 2022 03:27:33 -0800 (PST) Received: from atiyah.. (ipb218f8cd.dynamic.kabel-deutschland.de. [178.24.248.205]) by smtp.googlemail.com with ESMTPSA id de43sm13522881ejc.12.2022.01.31.03.27.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Jan 2022 03:27:32 -0800 (PST) From: Marc Nieper-Wisskirchen To: gcc-patches@gcc.gnu.org, jit@gcc.gnu.org Cc: marc.nieper+gnu@gmail.com, Marc Nieper-Wisskirchen Subject: [PATCH] libgccjit: structs/unions: bring the C++ API more on par with C Date: Mon, 31 Jan 2022 12:25:40 +0100 Message-Id: <20220131112540.429699-1-marc@nieper-wisskirchen.de> X-Mailer: git-send-email 2.32.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: jit@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Jit mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 31 Jan 2022 11:27:37 -0000 This patch adds yet missing C++ API entry points to create union types and to set the fields of structs previously defined as opaque. A missing convenience method returning NULL pointer values is also added and used in one of the two provided tests. gcc/jit * docs/cp/topics/expressions.rst: Update doc. * docs/cp/topics/types.rst: Update doc. * libgccjit++.h (context::new_union_type): New method. (context::null): New method. (type::null): New method. (struct_::set_fields): New method. gcc/testsuite * jit.dg/test-accessing-union.cc: New test. * jit.dg/test-linked-list.cc: New test. --- gcc/jit/docs/cp/topics/expressions.rst | 10 ++ gcc/jit/docs/cp/topics/types.rst | 27 +++- gcc/jit/libgccjit++.h | 61 ++++++++- gcc/testsuite/jit.dg/test-accessing-union.cc | 86 +++++++++++++ gcc/testsuite/jit.dg/test-linked-list.cc | 128 +++++++++++++++++++ 5 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-accessing-union.cc create mode 100644 gcc/testsuite/jit.dg/test-linked-list.cc diff --git a/gcc/jit/docs/cp/topics/expressions.rst b/gcc/jit/docs/cp/topics/expressions.rst index 239e004371e..3e9534790a3 100644 --- a/gcc/jit/docs/cp/topics/expressions.rst +++ b/gcc/jit/docs/cp/topics/expressions.rst @@ -86,6 +86,16 @@ Simple expressions ctxt.new_rvalue (numeric_type, 1) +.. function:: gccjit::rvalue \ + gccjit::context::null (gccjit::type pointer_type) const + + Given a pointer type, get the rvalue for the null pointer. + Essentially this is just a shortcut for: + + .. code-block:: c++ + + ctxt.new_rvalue (pointer_type, (void *) 0) + .. function:: gccjit::rvalue \ gccjit::context::new_rvalue (gccjit::type numeric_type, \ double value) const diff --git a/gcc/jit/docs/cp/topics/types.rst b/gcc/jit/docs/cp/topics/types.rst index c695ceb3098..f41f504da6a 100644 --- a/gcc/jit/docs/cp/topics/types.rst +++ b/gcc/jit/docs/cp/topics/types.rst @@ -179,8 +179,6 @@ You can model C `struct` types by creating :class:`gccjit::struct_` and fields.push_back (field_next); node.set_fields (fields); -.. FIXME: the above API doesn't seem to exist yet - .. function:: gccjit::field \ gccjit::context::new_field (gccjit::type type,\ const char *name, \ @@ -196,10 +194,25 @@ You can model C `struct` types by creating :class:`gccjit::struct_` and Construct a new struct type, with the given name and fields. .. function:: gccjit::struct_ \ - gccjit::context::new_opaque_struct (const std::string &name, \ - gccjit::location loc) + gccjit::context::new_opaque_struct (const std::string &name, \ + gccjit::location loc) Construct a new struct type, with the given name, but without - specifying the fields. The fields can be omitted (in which case the - size of the struct is not known), or later specified using - :c:func:`gcc_jit_struct_set_fields`. + specifying the fields. The fields can be omitted (in which case + the size of the struct is not known), or later specified using + :func:`set_fields`. + +.. function:: void \ + gccjit::struct_::set_fields (std::vector &fields, \ + gccjit::location loc) + + Populate the fields of a formerly-opaque struct type. + + This can only be called once on a given struct type. + +.. function:: gccjit::type \ + gccjit::context::new_union_type (const std::string &name, \ + std::vector &fields,\ + gccjit::location loc) + + Construct a new union type, with the given name and fields. diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 4b88e877bc9..17b10bc55c3 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -165,6 +165,10 @@ namespace gccjit struct_ new_opaque_struct_type (const std::string &name, location loc = location ()); + type new_union_type (const std::string &name, + std::vector &fields, + location loc = location ()); + param new_param (type type_, const std::string &name, location loc = location ()); @@ -189,6 +193,7 @@ namespace gccjit long value) const; rvalue zero (type numeric_type) const; rvalue one (type numeric_type) const; + rvalue null (type pointer_type) const; rvalue new_rvalue (type numeric_type, double value) const; rvalue new_rvalue (type pointer_type, @@ -361,9 +366,10 @@ namespace gccjit type get_aligned (size_t alignment_in_bytes); type get_vector (size_t num_units); - // Shortcuts for getting values of numeric types: + // Shortcuts for getting values of numeric and pointer types: rvalue zero (); rvalue one (); + rvalue null (); }; class struct_ : public type @@ -373,6 +379,9 @@ namespace gccjit struct_ (gcc_jit_struct *inner); gcc_jit_struct *get_inner_struct () const; + + void set_fields (std::vector &fields, + location loc = location ()); }; class function : public object @@ -864,6 +873,26 @@ context::new_opaque_struct_type (const std::string &name, name.c_str ())); } +inline type +context::new_union_type (const std::string &name, + std::vector &fields, + location loc) +{ + /* Treat std::vector as an array, relying on it not being resized: */ + field *as_array_of_wrappers = &fields[0]; + + /* Treat the array as being of the underlying pointers, relying on + the wrapper type being such a pointer internally. */ + gcc_jit_field **as_array_of_ptrs = + reinterpret_cast (as_array_of_wrappers); + + return type (gcc_jit_context_new_union_type (m_inner_ctxt, + loc.get_inner_location (), + name.c_str (), + fields.size (), + as_array_of_ptrs)); +} + inline param context::new_param (type type_, const std::string &name, @@ -955,6 +984,13 @@ context::one (type numeric_type) const numeric_type.get_inner_type ())); } +inline rvalue +context::null (type pointer_type) const +{ + return rvalue (gcc_jit_context_null (m_inner_ctxt, + pointer_type.get_inner_type ())); +} + inline rvalue context::new_rvalue (type numeric_type, double value) const @@ -1442,6 +1478,12 @@ type::one () return get_context ().new_rvalue (*this, 1); } +inline rvalue +type::null () +{ + return get_context ().null (*this); +} + // class struct_ inline struct_::struct_ () : type (NULL) {} inline struct_::struct_ (gcc_jit_struct *inner) : @@ -1456,6 +1498,23 @@ struct_::get_inner_struct () const return reinterpret_cast (get_inner_object ()); } +inline void +struct_::set_fields (std::vector &fields, location loc) +{ + /* Treat std::vector as an array, relying on it not being resized: */ + field *as_array_of_wrappers = &fields[0]; + + /* Treat the array as being of the underlying pointers, relying on + the wrapper type being such a pointer internally. */ + gcc_jit_field **as_array_of_ptrs = + reinterpret_cast (as_array_of_wrappers); + + gcc_jit_struct_set_fields (get_inner_struct (), + loc.get_inner_location (), + fields.size (), + as_array_of_ptrs); +} + // class function inline function::function () : object () {} inline function::function (gcc_jit_function *inner) diff --git a/gcc/testsuite/jit.dg/test-accessing-union.cc b/gcc/testsuite/jit.dg/test-accessing-union.cc new file mode 100644 index 00000000000..8fa03fd209c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-accessing-union.cc @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "libgccjit++.h" + +#include "harness.h" + +union int_or_float +{ + int as_int; + float as_float; +}; + +void +create_code (gcc_jit_context* c_ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + float + test_union (int i) + { + union int_or_float u; + u.as_int = i; + return u.as_float; + } + */ + gccjit::context ctxt (c_ctxt); + gccjit::type int_type = + ctxt.get_type (GCC_JIT_TYPE_INT); + gccjit::type float_type = + ctxt.get_type (GCC_JIT_TYPE_FLOAT); + gccjit::field as_int = + ctxt.new_field (int_type, "as_int"); + gccjit::field as_float = + ctxt.new_field (float_type, "as_float"); + std::vector fields; + fields.push_back (as_int); + fields.push_back (as_float); + gccjit::type union_type = + ctxt.new_union_type ("int_or_float", fields); + + /* Build the test function. */ + gccjit::param param_i = + ctxt.new_param (int_type, "i"); + std::vector params; + params.push_back (param_i); + gccjit::function test_fn = + ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + float_type, + "test_union", + params, + 0); + + gccjit::lvalue u = + test_fn.new_local (union_type, "u"); + + gccjit::block block = test_fn.new_block (); + + /* u.as_int = i; */ + block.add_assignment ( + /* "u.as_int = ..." */ + u.access_field (as_int), + param_i); + + /* return u.as_float; */ + block.end_with_return (u.access_field (as_float)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef float (*fn_type) (int i); + CHECK_NON_NULL (result); + + fn_type test_union = + (fn_type)gcc_jit_result_get_code (result, "test_union"); + CHECK_NON_NULL (test_union); + + /* Call the JIT-generated function. */ + float f_result = test_union (42); + + union int_or_float u; + u.as_float = f_result; + + CHECK_VALUE (u.as_int, 42); +} diff --git a/gcc/testsuite/jit.dg/test-linked-list.cc b/gcc/testsuite/jit.dg/test-linked-list.cc new file mode 100644 index 00000000000..933ab706b00 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-linked-list.cc @@ -0,0 +1,128 @@ +#include +#include +#include + +#include "libgccjit++.h" + +#include "harness.h" + +/* A doubly-linked list, to ensure that the JIT API can cope with + self-referential types. */ +struct node +{ + struct node *prev; + struct node *next; + int value; +}; + +void +create_code (gcc_jit_context *c_ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + int + test_linked_list (struct node *n) + { + int total = 0; + while (n) + { + total += n->value; + n = n->next; + } + return total; + } + */ + gccjit::context ctxt (c_ctxt); + gccjit::type t_int = + ctxt.get_type (GCC_JIT_TYPE_INT); + gccjit::struct_ t_node = + ctxt.new_opaque_struct_type ("node"); + gccjit::type t_node_ptr = + t_node.get_pointer (); + + gccjit::field f_prev = + ctxt.new_field (t_node_ptr, "prev"); + gccjit::field f_next = + ctxt.new_field (t_node_ptr, "next"); + gccjit::field f_value = + ctxt.new_field (t_int, "value"); + std::vector fields; + fields.push_back (f_prev); + fields.push_back (f_next); + fields.push_back (f_value); + t_node.set_fields (fields); + + /* Build the test function. */ + gccjit::param param_n = + ctxt.new_param (t_node_ptr, "n"); + std::vector params; + params.push_back (param_n); + gccjit::function fn = + ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + t_int, + "test_linked_list", + params, + 0); + /* int total; */ + gccjit::lvalue total = + fn.new_local (t_int, "total"); + + gccjit::block initial = fn.new_block ("initial"); + gccjit::block loop_test = fn.new_block ("loop_test"); + gccjit::block loop_body = fn.new_block ("loop_body"); + gccjit::block final = fn.new_block ("final"); + + /* total = 0; */ + initial.add_assignment ( + total, + ctxt.zero (t_int)); + initial.end_with_jump (loop_test); + + /* while (n) */ + loop_test.end_with_conditional (param_n != t_node_ptr.null (), + loop_body, + final); + + /* total += n->value; */ + loop_body.add_assignment_op (total, + GCC_JIT_BINARY_OP_PLUS, + param_n.dereference_field (f_value)); + + /* n = n->next; */ + loop_body.add_assignment (param_n, + param_n.dereference_field (f_next)); + + loop_body.end_with_jump (loop_test); + + /* return total; */ + final.end_with_return (total); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + struct node a, b, c; + typedef int (*fn_type) (struct node *n); + CHECK_NON_NULL (result); + + fn_type test_linked_list = + (fn_type)gcc_jit_result_get_code (result, "test_linked_list"); + CHECK_NON_NULL (test_linked_list); + + /* Construct a simple linked-list on the stack: a->b->c: */ + a.prev = NULL; + a.next = &b; + a.value = 5; + + b.prev = &a; + b.next = &c; + b.value = 3; + + c.prev = &b; + c.next = NULL; + c.value = 7; + + CHECK_VALUE (test_linked_list (NULL), 0); + CHECK_VALUE (test_linked_list (&a), 15); + CHECK_VALUE (test_linked_list (&b), 10); + CHECK_VALUE (test_linked_list (&c), 7); +} -- 2.32.0