From patchwork Thu Oct 21 13:07:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petter Tomner X-Patchwork-Id: 46489 X-Patchwork-Delegate: dmalcolm@redhat.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5B05B3857C77 for ; Thu, 21 Oct 2021 13:08:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5B05B3857C77 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1634821709; bh=ur2MWTkFr7PdlWmtWlZaJbds5lAdkc9ROCankrtPsfY=; h=To:Subject:Date:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=kq82laB0Lqo1Pw/sPuSTKctDEFIDeVuSz7gw7yUoqx6WsMauaftsFdlAnnpooT5+u OJSzQLqHewWAWmUdA1T2HQmYCqYHGJwg2A+zg+NyqyB4D66ctOwaZN8vBWlR6rdWAn lEuxDEpzhbKVT5W2Guw2W/z2Qf3QiXEVIRqhVXdM= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp-relay-3.sys.kth.se (smtp-relay-3.sys.kth.se [IPv6:2001:6b0:1:1200:250:56ff:fead:700c]) by sourceware.org (Postfix) with ESMTPS id 408653858D39; Thu, 21 Oct 2021 13:07:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 408653858D39 Received: from exdb6.ug.kth.se (exdb6.ug.kth.se [192.168.32.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp-relay-3.sys.kth.se (Postfix) with ESMTPS id 4HZnpG4R1SzPRyB; Thu, 21 Oct 2021 15:07:50 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp-relay-3.sys.kth.se 4HZnpG4R1SzPRyB Received: from exdb6.ug.kth.se (192.168.32.61) by exdb6.ug.kth.se (192.168.32.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.14; Thu, 21 Oct 2021 15:07:49 +0200 Received: from exdb6.ug.kth.se ([192.168.32.61]) by exdb6.ug.kth.se ([192.168.32.61]) with mapi id 15.02.0922.014; Thu, 21 Oct 2021 15:07:49 +0200 To: "gcc-patches@gcc.gnu.org" , "jit@gcc.gnu.org" Subject: [PATCH 1/2] jit: Complex types and loong constants Thread-Topic: [PATCH 1/2] jit: Complex types and loong constants Thread-Index: AQHXxnylvWs49PYyo0WX5NUUp6WRLQ== Date: Thu, 21 Oct 2021 13:07:49 +0000 Message-ID: References: In-Reply-To: Accept-Language: sv-SE, en-US Content-Language: sv-SE X-MS-Has-Attach: yes X-MS-TNEF-Correlator: x-originating-ip: [192.168.32.250] MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP 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: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Petter Tomner via Gcc-patches From: Petter Tomner Reply-To: Petter Tomner Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch fixes support for complex types. It adds the entrypoints: gcc_jit_context_new_rvalue_from_complex_double gcc_jit_context_set_bool_enable_complex_types Aswell as the binary operator GCC_JIT_BINARY_OP_COMPLEX, to make complex numbers from two real number rvalues. Note that the complex types already are in the type enum, so I thought the cleanest solution is to enable them, rather than to have a "get_complex_type" function. See attachement. From 6d5d7ce40f9bb84a7943e5113c8954ae4b941905 Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Fri, 15 Oct 2021 20:16:54 +0200 Subject: [PATCH 1/3] Complex Fix support for complex types The patch adds support of complex floating point types to libgccjit. A new binary operator 'COMPLEX' is added to create complex values from real values. Aswell as a function to create a complex double literal. To notify users if a binary linking to libgccjit depends on complex types, complex type support most be enabled with a new option function since they allready are in the types enum. Signed-off-by: 2021-10-21 Petter Tomner gcc/jit/ * jit-common.h : (INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES): New * jit-playback.c : Create imaginary literals, conversions (complex_real_to_real) : New (new_rvalue_from_const<...>) : Also build complex constants (new_rvalue_from_const <_Complex double>) : New (new_binary_op) : Add COMPLEX operator (build_cast) : Casts to complex (memento_of_new_rvalue_from_const <_Complex double>) : New (binary_op::make_debug_string) : Handle complex operator * jit-recording.c : Reproducer, debug strings, forwarding * jit-recording.h : (float_size_qual) : Poll size qualifier of float types (is_complex) : Poll if type is complex * libgccjit++.h : New entrypoints, see below * libgccjit.c : Implementation of new entry points, see .h (gcc_jit_context_get_type) : Extend range check, validation (valid_binary_op_p) : Extend range check (gcc_jit_context_new_binary_op) : Validation (gcc_jit_context_new_unary_op) : Validation (gcc_jit_context_new_comparison) : Validation * libgccjit.h : (gcc_jit_context_new_rvalue_from_complex_double) : New (GCC_JIT_BINARY_OP_COMPLEX) : New (LIBGCCJIT_HAVE_COMPLEX) : New (gcc_jit_context_set_bool_enable_complex_types) : New * libgccjit.map : Added new entrypoints (LIBGCCJIT_ABI_16) : New gcc/testsuite/ * jit.dg/test-complex-builtins.c : New * jit.dg/test-complex-literals.c : New * jit.dg/test-complex-misc.c : New * jit.dg/test-complex-operators.c : New * jit.dg/test-complex-types.c : New * jit.dg/test-error-complex-noenable.c : New gcc/jit/docs/topics/ * contexts.rst : Update docs * expressions.rst * types.rst --- gcc/jit/docs/topics/contexts.rst | 20 + gcc/jit/docs/topics/expressions.rst | 89 ++- gcc/jit/docs/topics/types.rst | 12 +- gcc/jit/jit-common.h | 1 + gcc/jit/jit-playback.c | 165 ++++- gcc/jit/jit-recording.c | 126 +++- gcc/jit/jit-recording.h | 28 + gcc/jit/libgccjit++.h | 21 + gcc/jit/libgccjit.c | 97 ++- gcc/jit/libgccjit.h | 44 +- gcc/jit/libgccjit.map | 6 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 30 + gcc/testsuite/jit.dg/test-complex-builtins.c | 217 ++++++ gcc/testsuite/jit.dg/test-complex-literals.c | 145 ++++ gcc/testsuite/jit.dg/test-complex-misc.c | 204 ++++++ gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++ gcc/testsuite/jit.dg/test-complex-types.c | 677 ++++++++++++++++++ .../jit.dg/test-error-complex-noenable.c | 31 + 18 files changed, 2221 insertions(+), 45 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-complex-builtins.c create mode 100644 gcc/testsuite/jit.dg/test-complex-literals.c create mode 100644 gcc/testsuite/jit.dg/test-complex-misc.c create mode 100644 gcc/testsuite/jit.dg/test-complex-operators.c create mode 100644 gcc/testsuite/jit.dg/test-complex-types.c create mode 100644 gcc/testsuite/jit.dg/test-error-complex-noenable.c diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst index 00fb17e155d..d8689407cc6 100644 --- a/gcc/jit/docs/topics/contexts.rst +++ b/gcc/jit/docs/topics/contexts.rst @@ -489,6 +489,26 @@ Boolean options #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver +.. function:: void\ + gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt,\ + int bool_value); + + This option can enable complex type support in libgccjit. By default, + no complex types can be used. + + If you use complex types, it is recommended to use builtin functions + `creal`, `cimag` and `conj` etc. with the correct type suffix, since + those are inlined into the code, rather then imported functions from + the math lib which are not. See :ref:`gcc_jit_context_get_builtin_function`. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_COMPLEX + + Integer options *************** diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 396259ef07e..a98f35572b4 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -98,6 +98,15 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :c:type:`double` value. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + _Complex double value) + + Given a floating point type, build an rvalue for + the given constant :c:type:`_Complex double`. When the result type is + non-complex, the imaginary part is discarded. + .. function:: gcc_jit_rvalue *\ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \ gcc_jit_type *pointer_type, \ @@ -168,14 +177,14 @@ Unary Operations The available unary operations are: -========================================== ============ -Unary Operation C equivalent -========================================== ============ -:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)` -:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)` -:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)` -:c:macro:`GCC_JIT_UNARY_OP_ABS` `abs (EXPR)` -========================================== ============ +========================================== ============ ====================== +Unary Operation C equivalent Supported types +========================================== ============ ====================== +:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)` integer, real, complex +:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)` integer +:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)` integer +:c:macro:`GCC_JIT_UNARY_OP_ABS` `abs (EXPR)` integer, real +========================================== ============ ====================== .. c:macro:: GCC_JIT_UNARY_OP_MINUS @@ -235,22 +244,23 @@ Binary Operations The available binary operations are: -======================================== ============ -Binary Operation C equivalent -======================================== ============ -:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y` -:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y` -:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y` -:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y` -:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y` -:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y` -:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y` -:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y` -:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y` -:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y` -:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y` -:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y` -======================================== ============ +======================================== ============ ======================= +Binary Operation C equivalent Supported operand types +======================================== ============ ======================= +:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y` integer +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y` integer +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y` integer +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y` integer +:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y` integer +:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y` integer +:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y` integer +:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y` integer +:c:macro:`GCC_JIT_BINARY_OP_COMPLEX` `CMPLX (r, i)` real +======================================== =============== ======================= .. c:macro:: GCC_JIT_BINARY_OP_PLUS @@ -378,6 +388,25 @@ Binary Operation C equivalent in C. +.. c:macro:: GCC_JIT_BINARY_OP_COMPLEX + + Create a complex floating point value from + two real floating point values with the same + size qualifier as the complex result type. + I.e two floats for a _Complex float, etc. + + Analogous to: + CMPLX (real,imag) + in C. + + The first operand is the real part, the other + the imaginary. Negative zeroes are preserved + and Inf:s do not lead to NaNs. + + This operator was added in LIBGCCJIT_ABI_16; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_COMPLEX` + Comparisons *********** @@ -402,6 +431,7 @@ Comparison C equivalent :c:macro:`GCC_JIT_COMPARISON_GE` `x >= y` ======================================= ============ + Note: Only `==` and `!=` are defined for complex types. Function calls ************** @@ -504,10 +534,17 @@ Type-coercion Currently only a limited set of conversions are possible: - * int <-> float - * int <-> bool + * integer <-> integer + * floating point <-> floating point + * integer <-> floating point + * integer <-> bool * P* <-> Q*, for pointer types P and Q + Note: "floating point" includes complex types. + + When a complex type is converted to a non-complex type, the + imaginary part is discarded. + Lvalues ------- diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index 831f11b679a..5b5ba050658 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -82,11 +82,17 @@ Standard types :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR` C type: ``(const char *)`` :c:data:`GCC_JIT_TYPE_SIZE_T` C's ``size_t`` type :c:data:`GCC_JIT_TYPE_FILE_PTR` C type: ``(FILE *)`` - :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT` C99's ``_Complex float`` - :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE` C99's ``_Complex double`` - :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE` C99's ``_Complex long double`` + :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT` C99's ``_Complex float``, ABI 16 + :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE` C99's ``_Complex double``, ABI 16 + :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE` C99's ``_Complex long double``, ABI 16 ========================================== ================================ + The complex types are available from :ref:`LIBGCCJIT_ABI_16` after + setting :ref:`gcc_jit_context_set_bool_enable_complex_types`. + + You can test for complex types support with the define + `#ifdef LIBGCCJIT_HAVE_COMPLEX`. + .. function:: gcc_jit_type *\ gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \ int num_bytes, int is_signed) diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index f88e6755b00..bc0453fba05 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -198,6 +198,7 @@ enum inner_bool_option { INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS, INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER, + INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES, NUM_INNER_BOOL_OPTIONS }; diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 59399dee251..8b1cb818b90 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "gcc.h" #include "diagnostic.h" #include "stmt.h" +#include "complex.h" #include @@ -78,6 +79,8 @@ convert (tree dst_type, tree expr) case INTEGER_TYPE: case ENUMERAL_TYPE: return fold (convert_to_integer (dst_type, expr)); + case REAL_TYPE: + return fold (convert_to_real (dst_type, expr)); default: gcc_assert (gcc::jit::active_playback_ctxt); @@ -679,6 +682,24 @@ new_global_initialized (location *loc, namespace playback { +/* Return the corrensponding not complex float type of a + float type. I.e. complex float -> float */ +static tree +complex_real_to_real (tree complex_type) +{ + if (TYPE_CANONICAL (complex_type) == + TYPE_CANONICAL (complex_float_type_node)) + return float_type_node; + else if (TYPE_CANONICAL (complex_type) == + TYPE_CANONICAL (complex_double_type_node)) + return double_type_node; + else if (TYPE_CANONICAL (complex_type) == + TYPE_CANONICAL (complex_long_double_type_node)) + return long_double_type_node; + else + gcc_unreachable(); +} + /* Specialization of making an rvalue from a const, for host . */ template <> @@ -694,6 +715,25 @@ new_rvalue_from_const (type *type, tree inner = build_int_cst (inner_type, value); return new rvalue (this, inner); } + else if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + REAL_VALUE_TYPE real_value; + REAL_VALUE_TYPE imag_value; + + real_type = complex_real_to_real (inner_type); + + real_from_integer (&real_value, VOIDmode, value, SIGNED); + real_from_integer (&imag_value, VOIDmode, 0, SIGNED); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } else { REAL_VALUE_TYPE real_value; @@ -718,6 +758,25 @@ new_rvalue_from_const (type *type, tree inner = build_int_cst (inner_type, value); return new rvalue (this, inner); } + else if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + REAL_VALUE_TYPE real_value; + REAL_VALUE_TYPE imag_value; + + real_type = complex_real_to_real (inner_type); + + real_from_integer (&real_value, VOIDmode, value, SIGNED); + real_from_integer (&imag_value, VOIDmode, 0, SIGNED); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } else { REAL_VALUE_TYPE real_value; @@ -743,19 +802,104 @@ new_rvalue_from_const (type *type, real.c:real_from_target appears to require the representation to be split into 32-bit values, and then sent as an pair of host long ints. */ + + union + { + double as_double; + uint32_t as_uint32s[2]; + } u_real, u_imag; + + u_real.as_double = value; + long int as_long_ints[2]; + as_long_ints[0] = u_real.as_uint32s[0]; + as_long_ints[1] = u_real.as_uint32s[1]; + REAL_VALUE_TYPE real_value; + real_from_target (&real_value, as_long_ints, DFmode); + + if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + + REAL_VALUE_TYPE imag_value; + + long int zero_as_long_ints[2]; + u_imag.as_double = 0.; + zero_as_long_ints[0] = u_imag.as_uint32s[0]; + zero_as_long_ints[1] = u_imag.as_uint32s[1]; + + real_from_target (&imag_value, zero_as_long_ints, DFmode); + + real_type = complex_real_to_real (inner_type); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } + else + { + tree inner = build_real (inner_type, real_value); + return new rvalue (this, inner); + } +} + +/* Specialization of making an rvalue from a const, + for host . */ + +template <> +rvalue * +context:: +new_rvalue_from_const <_Complex double> (type *type, + _Complex double value) +{ + tree inner_type = type->as_tree (); + union { double as_double; uint32_t as_uint32s[2]; - } u; - u.as_double = value; + } u_real, u_imag; + + u_real.as_double = creal(value); long int as_long_ints[2]; - as_long_ints[0] = u.as_uint32s[0]; - as_long_ints[1] = u.as_uint32s[1]; + as_long_ints[0] = u_real.as_uint32s[0]; + as_long_ints[1] = u_real.as_uint32s[1]; + + REAL_VALUE_TYPE real_value; real_from_target (&real_value, as_long_ints, DFmode); - tree inner = build_real (inner_type, real_value); - return new rvalue (this, inner); + + if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + + REAL_VALUE_TYPE imag_value; + + long int value_as_long_ints[2]; + u_imag.as_double = cimag(value); + value_as_long_ints[0] = u_imag.as_uint32s[0]; + value_as_long_ints[1] = u_imag.as_uint32s[1]; + + real_from_target (&imag_value, value_as_long_ints, DFmode); + + real_type = complex_real_to_real (inner_type); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } + else + { + tree inner = build_real (inner_type, real_value); + return new rvalue (this, inner); + } } /* Specialization of making an rvalue from a const, for host . */ @@ -985,6 +1129,11 @@ new_binary_op (location *loc, case GCC_JIT_BINARY_OP_RSHIFT: inner_op = RSHIFT_EXPR; break; + + /* Create complex value from two real values */ + case GCC_JIT_BINARY_OP_COMPLEX: + inner_op = COMPLEX_EXPR; + break; } tree inner_expr = build2 (inner_op, @@ -1163,6 +1312,10 @@ playback::context::build_cast (playback::location *loc, build_int_cst (TREE_TYPE (t_expr), 0)); goto maybe_fold; + case COMPLEX_TYPE: + t_ret = convert_to_complex (t_dst_type, t_expr); + goto maybe_fold; + case REAL_TYPE: t_ret = convert_to_real (t_dst_type, t_expr); goto maybe_fold; diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 117ff70114c..b3bb6acfeb9 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include +#include #include "jit-builtins.h" #include "jit-recording.h" @@ -1609,7 +1610,8 @@ static const char * const static const char * const inner_bool_option_reproducer_strings[NUM_INNER_BOOL_OPTIONS] = { "gcc_jit_context_set_bool_allow_unreachable_blocks", - "gcc_jit_context_set_bool_use_external_driver" + "gcc_jit_context_set_bool_use_external_driver", + "gcc_jit_context_set_bool_enable_complex_types" }; /* Write the current value of all options to the log file (if any). */ @@ -2423,6 +2425,59 @@ recording::memento_of_get_type::is_float () const } } +/* Implementation of pure virtual hook recording::type::is_complex for + recording::memento_of_get_type. */ + +bool +recording::memento_of_get_type::is_complex () const +{ + switch (m_kind) + { + default: gcc_unreachable (); + + case GCC_JIT_TYPE_VOID: + return false; + + case GCC_JIT_TYPE_VOID_PTR: + return false; + + case GCC_JIT_TYPE_BOOL: + return false; + + case GCC_JIT_TYPE_CHAR: + case GCC_JIT_TYPE_SIGNED_CHAR: + case GCC_JIT_TYPE_UNSIGNED_CHAR: + case GCC_JIT_TYPE_SHORT: + case GCC_JIT_TYPE_UNSIGNED_SHORT: + case GCC_JIT_TYPE_INT: + case GCC_JIT_TYPE_UNSIGNED_INT: + case GCC_JIT_TYPE_LONG: + case GCC_JIT_TYPE_UNSIGNED_LONG: + case GCC_JIT_TYPE_LONG_LONG: + case GCC_JIT_TYPE_UNSIGNED_LONG_LONG: + return false; + + case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_DOUBLE: + case GCC_JIT_TYPE_LONG_DOUBLE: + return false; + + case GCC_JIT_TYPE_CONST_CHAR_PTR: + return false; + + case GCC_JIT_TYPE_SIZE_T: + return false; + + case GCC_JIT_TYPE_FILE_PTR: + return false; + + case GCC_JIT_TYPE_COMPLEX_FLOAT: + case GCC_JIT_TYPE_COMPLEX_DOUBLE: + case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE: + return true; + } +} + /* Implementation of pure virtual hook recording::type::is_bool for recording::memento_of_get_type. */ @@ -4704,6 +4759,7 @@ recording::global::write_reproducer (reproducer &r) template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const ; +template class recording::memento_of_new_rvalue_from_const <_Complex double>; template class recording::memento_of_new_rvalue_from_const ; /* Implementation of the pure virtual hook recording::memento::replay_into @@ -4881,6 +4937,53 @@ recording::memento_of_new_rvalue_from_const ::write_reproducer (reproduc m_value); } +/* The make_debug_string specialization for , rendering it as + (TARGET_TYPE)LITERAL + e.g. + "(complex float)(42.0+42.0j)". */ + +template <> +string * +memento_of_new_rvalue_from_const <_Complex double>::make_debug_string () +{ + double real = creal(m_value); + double imag = cimag(m_value); + return string::from_printf (m_ctxt, + "(%s)(%g%+gj)", + m_type->get_debug_string (), + real, imag); +} + +/* The get_wide_int specialization for . */ + +template <> +bool +memento_of_new_rvalue_from_const <_Complex double>:: +get_wide_int (wide_int *) const +{ + return false; +} + +/* The write_reproducer specialization for . */ + +template <> +void +recording::memento_of_new_rvalue_from_const <_Complex double>:: +write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + double real = creal(m_value); + double imag = cimag(m_value); + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_complex_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " %f+%fj); /* double value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + real, imag); +} + /* The make_debug_string specialization for , rendering it as (TARGET_TYPE)HEX e.g. @@ -5178,17 +5281,24 @@ static const char * const binary_op_strings[] = { "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */ "<<", /* GCC_JIT_BINARY_OP_LSHIFT */ ">>", /* GCC_JIT_BINARY_OP_RSHIFT */ + "", /* GCC_JIT_BINARY_OP_COMPLEX - dummy not used */ }; recording::string * recording::binary_op::make_debug_string () { enum precedence prec = get_precedence (); - return string::from_printf (m_ctxt, - "%s %s %s", - m_a->get_debug_string_parens (prec), - binary_op_strings[m_op], - m_b->get_debug_string_parens (prec)); + if (m_op == GCC_JIT_BINARY_OP_COMPLEX) + return string::from_printf (m_ctxt, + "(%s + %s * _Imaginary_I)", + m_a->get_debug_string_parens (prec), + m_b->get_debug_string_parens (prec)); + else + return string::from_printf (m_ctxt, + "%s %s %s", + m_a->get_debug_string_parens (prec), + binary_op_strings[m_op], + m_b->get_debug_string_parens (prec)); } const char * const binary_op_reproducer_strings[] = { @@ -5203,7 +5313,8 @@ const char * const binary_op_reproducer_strings[] = { "GCC_JIT_BINARY_OP_LOGICAL_AND", "GCC_JIT_BINARY_OP_LOGICAL_OR", "GCC_JIT_BINARY_OP_LSHIFT", - "GCC_JIT_BINARY_OP_RSHIFT" + "GCC_JIT_BINARY_OP_RSHIFT", + "GCC_JIT_BINARY_OP_COMPLEX", }; /* Implementation of recording::memento::write_reproducer for binary ops. */ @@ -5244,6 +5355,7 @@ static const enum precedence binary_op_precedence[] = { PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */ PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */ PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */ + PRECEDENCE_CAST, /* GCC_JIT_BINARY_OP_COMPLEX */ }; } /* namespace recording */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 03fa1160cf0..d5e0c359a48 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -544,10 +544,14 @@ public: virtual bool is_int () const = 0; virtual bool is_float () const = 0; virtual bool is_bool () const = 0; + virtual bool is_complex () const = 0; virtual type *is_pointer () = 0; virtual type *is_array () = 0; virtual bool is_void () const { return false; } virtual bool has_known_size () const { return true; } + /* Used to pair complex float types with real float type + of the same "base type". */ + virtual int float_size_qual () const { return 0; } bool is_numeric () const { @@ -598,9 +602,28 @@ public: return type::accepts_writes_from (rtype); } + int float_size_qual () const FINAL OVERRIDE + { + switch (m_kind) + { + default: + return 0; + case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_COMPLEX_FLOAT: + return 1; + case GCC_JIT_TYPE_DOUBLE: + case GCC_JIT_TYPE_COMPLEX_DOUBLE: + return 2; + case GCC_JIT_TYPE_LONG_DOUBLE: + case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE: + return 3; + } + } + bool is_int () const FINAL OVERRIDE; bool is_float () const FINAL OVERRIDE; bool is_bool () const FINAL OVERRIDE; + bool is_complex () const FINAL OVERRIDE; type *is_pointer () FINAL OVERRIDE { return dereference (); } type *is_array () FINAL OVERRIDE { return NULL; } bool is_void () const FINAL OVERRIDE { return m_kind == GCC_JIT_TYPE_VOID; } @@ -635,6 +658,7 @@ public: bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return m_other_type; } type *is_array () FINAL OVERRIDE { return NULL; } @@ -661,6 +685,7 @@ public: bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); } bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); } bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); } + bool is_complex () const FINAL OVERRIDE { return m_other_type->is_complex (); } type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } @@ -771,6 +796,7 @@ class array_type : public type bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return m_element_type; } int num_elements () { return m_num_elements; } @@ -805,6 +831,7 @@ public: bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return NULL; } @@ -918,6 +945,7 @@ public: bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return NULL; } diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 82831ff5da0..c97aeb82812 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -128,6 +128,7 @@ namespace gccjit void set_bool_allow_unreachable_blocks (int bool_value); void set_bool_use_external_driver (int bool_value); + void set_bool_enable_complex_types (int bool_value); void add_command_line_option (const char *optname); void add_driver_option (const char *optname); @@ -191,6 +192,8 @@ namespace gccjit rvalue one (type numeric_type) const; rvalue new_rvalue (type numeric_type, double value) const; + rvalue new_rvalue (type numeric_type, + _Complex double value) const; rvalue new_rvalue (type pointer_type, void *value) const; rvalue new_rvalue (const std::string &value) const; @@ -732,6 +735,13 @@ context::set_bool_use_external_driver (int bool_value) bool_value); } +inline void +context::set_bool_enable_complex_types (int bool_value) +{ + gcc_jit_context_set_bool_enable_complex_types (m_inner_ctxt, + bool_value); +} + inline void context::add_command_line_option (const char *optname) { @@ -950,6 +960,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + _Complex double value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_complex_double ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::new_rvalue (type pointer_type, void *value) const diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 7fa948007ad..64630b810f4 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -448,9 +448,17 @@ gcc_jit_context_get_type (gcc_jit_context *ctxt, JIT_LOG_FUNC (ctxt->get_logger ()); RETURN_NULL_IF_FAIL_PRINTF1 ( (type >= GCC_JIT_TYPE_VOID - && type <= GCC_JIT_TYPE_FILE_PTR), + && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE), ctxt, NULL, "unrecognized value for enum gcc_jit_types: %i", type); + if (type >= GCC_JIT_TYPE_COMPLEX_FLOAT + && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE) + RETURN_NULL_IF_FAIL ( + ctxt->get_inner_bool_option( + gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES), + ctxt, NULL, + "complex types are only available after enabling them with" + " gcc_jit_context_set_bool_enable_complex_types()"); return (gcc_jit_type *)ctxt->get_type (type); } @@ -1320,6 +1328,26 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + double _Complex value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + RETURN_NULL_IF_FAIL_PRINTF1 ( + numeric_type->is_float (), + ctxt, NULL, + "not a floating point type (type: %s)", + numeric_type->get_debug_string ()); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const (numeric_type, value)); +} + + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -1415,6 +1443,14 @@ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, result_type->get_debug_string ()); RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); + if (rvalue->get_type ()->is_complex ()) + RETURN_NULL_IF_FAIL_PRINTF2 ( + op == GCC_JIT_UNARY_OP_MINUS, + ctxt, loc, + "only unary minus defined for complex types: %s (type: %s)", + rvalue->get_debug_string (), + rvalue->get_type ()->get_debug_string ()); + return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue); } @@ -1426,7 +1462,7 @@ static bool valid_binary_op_p (enum gcc_jit_binary_op op) { return (op >= GCC_JIT_BINARY_OP_PLUS - && op <= GCC_JIT_BINARY_OP_RSHIFT); + && op <= GCC_JIT_BINARY_OP_COMPLEX); } /* Public entrypoint. See description in libgccjit.h. @@ -1470,6 +1506,38 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, a->get_debug_string (), b->get_debug_string (), result_type->get_debug_string ()); + if (op == GCC_JIT_BINARY_OP_COMPLEX) + { + RETURN_NULL_IF_FAIL ( + result_type->is_complex (), + ctxt, loc, + "return type is not complex"); + RETURN_NULL_IF_FAIL_PRINTF3 ( + !a->get_type ()->is_complex () && + a->get_type ()->is_float (), + ctxt, loc, + "first operand of %s is not real: %s (type: %s)", + gcc::jit::binary_op_reproducer_strings[op], + a->get_debug_string (), + a->get_type ()->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF3 ( + !b->get_type ()->is_complex () && + b->get_type ()->is_float (), + ctxt, loc, + "2nd operand of %s is not real: %s (type: %s)", + gcc::jit::binary_op_reproducer_strings[op], + b->get_debug_string (), + b->get_type ()->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF2 ( + a->get_type ()-> float_size_qual () == + result_type->float_size_qual (), + ctxt, loc, + "size qualifiers of complex operand's not the same as the result:" + " operands: %s, result: %s", + a->get_type ()->get_debug_string (), + result_type->get_debug_string ()); + } + return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b); } @@ -1506,6 +1574,14 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt, b->get_debug_string (), b->get_type ()->get_debug_string ()); + if (a->get_type ()->is_complex()) + RETURN_NULL_IF_FAIL_PRINTF1 ( + (op == GCC_JIT_COMPARISON_EQ + || op == GCC_JIT_COMPARISON_NE), + ctxt, loc, + "invalid enum gcc_jit_comparison for complex operands: %i", + op); + return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b); } @@ -2735,6 +2811,23 @@ gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context *ctxt, bool_value); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::set_inner_bool_option method in + jit-recording.c. */ + +void +gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt, + int bool_value) +{ + RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + ctxt->set_inner_bool_option ( + gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES, + bool_value); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 5c722c2c57f..d4b10fc0644 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -848,6 +848,16 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, double value); +/* Complex floating-point constants. + + This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_COMPLEX */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + _Complex double value); + /* Pointers. */ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, @@ -959,7 +969,26 @@ enum gcc_jit_binary_op /* Right shift; analogous to: (EXPR_A) >> (EXPR_B) in C. */ - GCC_JIT_BINARY_OP_RSHIFT + GCC_JIT_BINARY_OP_RSHIFT, + + /* Create a complex floating point value from + two real floating point values. The operands + and the result need to have the same size + qualifier. + + Analogous to: + CMPLX (real,imag) + in C. + + The first operand is the real part, the other + the imaginary. Negative zeroes are preserved + and Inf:s do not lead to NaNs. + + This operator was added in LIBGCCJIT_ABI_16; + you can test for its presence using + #ifdef LIBGCCJIT_HAVE_COMPLEX + */ + GCC_JIT_BINARY_OP_COMPLEX }; extern gcc_jit_rvalue * @@ -1434,6 +1463,19 @@ gcc_jit_timer_print (gcc_jit_timer *timer, FILE *f_out); +#define LIBGCCJIT_HAVE_COMPLEX + +/* Enables complex type support in libgccjit. + + This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_COMPLEX +*/ + +extern void +gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt, + int bool_value); + #define LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call /* Mark/clear a call as needing tail-call optimization. diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 337ea6c7fe4..c9b044dc8f5 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -205,3 +205,9 @@ LIBGCCJIT_ABI_15 { gcc_jit_extended_asm_add_clobber; gcc_jit_context_add_top_level_asm; } LIBGCCJIT_ABI_14; + +LIBGCCJIT_ABI_16 { + global: + gcc_jit_context_new_rvalue_from_complex_double; + gcc_jit_context_set_bool_enable_complex_types; +} LIBGCCJIT_ABI_15; \ No newline at end of file diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 84ef54a0386..7b45acd4b9c 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -105,6 +105,36 @@ #undef create_code #undef verify_code +/* test-complex-builtins.c */ +#define create_code create_code_complex_builtins +#define verify_code verify_code_complex_builtins +#include "test-complex-builtins.c" +#undef create_code +#undef verify_code + +/* test-complex-literals.c */ +#define create_code create_code_complex_literals +#define verify_code verify_code_complex_literals +#include "test-complex-literals.c" +#undef create_code +#undef verify_code + +/* test-complex-misc.c */ +#define create_code create_code_complex_misc +#define verify_code verify_code_complex_misc +#include "test-complex-misc.c" +#undef create_code +#undef verify_code + +/* test-complex-operators.c */ +#define create_code create_code_complex_operators +#define verify_code verify_code_complex_operators +#include "test-complex-operators.c" +#undef create_code +#undef verify_code + +/* test-complex-types.c: Quite long, don't include here */ + /* test-compound-assignment.c */ #define create_code create_code_compound_assignment #define verify_code verify_code_compound_assignment diff --git a/gcc/testsuite/jit.dg/test-complex-builtins.c b/gcc/testsuite/jit.dg/test-complex-builtins.c new file mode 100644 index 00000000000..fce2c9b2d09 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-builtins.c @@ -0,0 +1,217 @@ +/* + This test just checks that the builtins cimag, creal and + conj are usable. + + Also, they should be inlined, which can be checked by + disassembling the object file manually. +*/ + +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +static void +make_code_unop_builtins (gcc_jit_context *ctxt, + const char *fn_name, + int type_return, + int type_arg, + gcc_jit_function *fn) +{ + gcc_jit_block *block; + + gcc_jit_type *tr = gcc_jit_context_get_type (ctxt, type_return); + gcc_jit_type *ta = gcc_jit_context_get_type (ctxt, type_arg); + + gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, ta, "f1"); + + gcc_jit_param *params[] = {param1}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tr, fn_name, 1, params, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param (foo, 0)); + + gcc_jit_rvalue *args[] = { + gcc_jit_lvalue_as_rvalue (f1) + }; + + /* return fn(f1); */ + gcc_jit_rvalue *r = gcc_jit_context_new_call + (ctxt, 0, fn, + 1, + args); + + gcc_jit_block_end_with_return (block, 0, r); +} + +static void +make_code_binop_builtins (gcc_jit_context *ctxt, + const char *fn_name, + int type1, + int type2, + gcc_jit_function *builtin) +{ + gcc_jit_block *block; + + gcc_jit_type *t1 = gcc_jit_context_get_type (ctxt, type1); + gcc_jit_type *t2 = gcc_jit_context_get_type (ctxt, type2); + + gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, t1, "f1"); + gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, t2, "f2"); + + gcc_jit_param *params[] = {param1, param2}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + t1, fn_name, 2, params, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param(foo, 0)); + gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param(foo, 1)); + + gcc_jit_rvalue *args[] = { + gcc_jit_lvalue_as_rvalue (f1), + gcc_jit_lvalue_as_rvalue (f2) + }; + + /* return builtin(f1,f2); */ + gcc_jit_rvalue *r = gcc_jit_context_new_call + (ctxt, 0, builtin, + 2, + args); + + gcc_jit_block_end_with_return (block, 0, r); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + gcc_jit_function *fn_cpow = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_cpow"); + + make_code_binop_builtins (ctxt, "cpow_builtin", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_cpow); + + gcc_jit_function *fn_conj = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_conj"); + + /* In a good world conj should be inlined */ + make_code_unop_builtins (ctxt, "conj_inlined", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_conj); + + gcc_jit_function *fn_creal = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_creal"); + gcc_jit_function *fn_crealf = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_crealf"); + gcc_jit_function *fn_creall = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_creall"); + gcc_jit_function *fn_cimag = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_cimag"); + + /* These should be inlined too */ + make_code_unop_builtins (ctxt, "creal_inlined", + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_creal); + make_code_unop_builtins (ctxt, "cimag_inlined", + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_cimag); + + make_code_unop_builtins (ctxt, "crealf_inlined", + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + fn_crealf); + make_code_unop_builtins (ctxt, "creall_inlined", + GCC_JIT_TYPE_LONG_DOUBLE, + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + fn_creall); + + /* Use to inspect code manually and assure conj, creal, cimag + are inlined. At the time of writing they are on my x64 machine */ + #if 0 + gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE, + "test-complex-builtins.o"); + #endif +} + +typedef _Complex double (*cd_cdcd)(_Complex double, _Complex double); +typedef _Complex double (*cd_cd)(_Complex double); +typedef double (*d_cd)(_Complex double); +typedef float (*f_cf)(_Complex float); +typedef long double (*ld_cld)(_Complex long double); + +/* We need this to fool GCC into not precomputing the built-in ... + precomputing seems like a feuture libgccjit misses. */ +volatile _Complex double half = 0.5; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + {/* Test binary builtins */ + { + cd_cdcd fn = + gcc_jit_result_get_code (result, "cpow_builtin"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (2, 2), 4.); + _Complex double ans = fn (-1., 0.5); + _Complex double key = __builtin_cpow (-1., half); + + /* This test fails if libgccjit can precompute builtins */ + CHECK_VALUE (ans, key); /* Almost 1.j */ + } + } + {/* Test unary builtins */ + { /* conj */ + cd_cd fn = gcc_jit_result_get_code (result, "conj_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE( fn (1. - 1.j), 1. + 1.j); + } + { /* creal */ + d_cd fn = gcc_jit_result_get_code (result, "creal_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. - 1.j), 1.); + } + { /* cimag */ + d_cd fn = gcc_jit_result_get_code (result, "cimag_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. - 1.j), -1.); + } + { /* crealf */ + f_cf fn = gcc_jit_result_get_code (result, "crealf_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f - 1.fj), 1.f); + } + { /* creall */ + ld_cld fn = gcc_jit_result_get_code (result, "creall_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.L - 1.Lj), 1.L); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-literals.c b/gcc/testsuite/jit.dg/test-complex-literals.c new file mode 100644 index 00000000000..422cff1048d --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-literals.c @@ -0,0 +1,145 @@ +/* + Test the new 'gcc_jit_context_new_rvalue_from_complex_double()' + aswell as test that the old '_from_int ... _from_double" + can produce complex values. +*/ + +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +static void +make_code (gcc_jit_context *ctxt, + const char *fn_name, + int type, + _Complex double local_val, + int lit_type) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + if (lit_type == 'c') + r1 = gcc_jit_context_new_rvalue_from_complex_double (ctxt, tt, local_val); + else if (lit_type == 'd') + r1 = gcc_jit_context_new_rvalue_from_double (ctxt, tt, creal(local_val)); + else if (lit_type == 'l') + r1 = gcc_jit_context_new_rvalue_from_long (ctxt, tt, creal(local_val)); + else if (lit_type == 'i') + r1 = gcc_jit_context_new_rvalue_from_int (ctxt, tt, creal(local_val)); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + make_code (ctxt, "complex_float_clit_1c1_2c2j", + GCC_JIT_TYPE_COMPLEX_FLOAT, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "complex_double_clit_1c1_2c2j", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "complex_long_double_clit_1c1_2c2j", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "float_clit_1c1", + GCC_JIT_TYPE_FLOAT, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "double_clit_1c1", + GCC_JIT_TYPE_DOUBLE, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "long_double_clit_1c1", + GCC_JIT_TYPE_LONG_DOUBLE, + 1.1 + 2.2j, 'c'); + + /* Make complex from "from_double", "from_long","from_int" */ + make_code (ctxt, "complex_float_dlit_1c1", + GCC_JIT_TYPE_COMPLEX_FLOAT, + 1.1, 'd'); + make_code (ctxt, "complex_double_dlit_1c1", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 1.1, 'd'); + make_code (ctxt, "complex_long_double_dlit_1c1", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + 1.1, 'd'); + make_code (ctxt, "complex_double_llit_2", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 2, 'l'); + make_code (ctxt, "complex_double_ilit_3", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 3, 'i'); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + {/* Test literals */ + { + _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_clit_1c1_2c2j"); + + CHECK_VALUE(f (), 1.1f + 2.2fj); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_clit_1c1_2c2j"); + CHECK_VALUE(f (), 1.1 + 2.2j); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_clit_1c1_2c2j"); + /* Note: The literal in the function is complex double */ + CHECK_VALUE(f (),1.1 + 2.2j); + } + { + float (*f)() = gcc_jit_result_get_code (result, "float_clit_1c1"); + CHECK_VALUE(f (), 1.1f); + } + { + double (*f)() = gcc_jit_result_get_code (result, "double_clit_1c1"); + CHECK_VALUE(f (), 1.1); + } + { + long double (*f)() = gcc_jit_result_get_code (result, "long_double_clit_1c1"); + CHECK_VALUE(f (), 1.1); + } + { + float (*f)() = gcc_jit_result_get_code (result, "complex_float_dlit_1c1"); + CHECK_VALUE(f (), 1.1f); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_dlit_1c1"); + CHECK_VALUE(f (), 1.1); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_dlit_1c1"); + /* Note: The literal in the function is complex double */ + CHECK_VALUE(f (), 1.1); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_llit_2"); + CHECK_VALUE(f (), 2); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_ilit_3"); + CHECK_VALUE(f (), 3); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-misc.c b/gcc/testsuite/jit.dg/test-complex-misc.c new file mode 100644 index 00000000000..fe0cdade927 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-misc.c @@ -0,0 +1,204 @@ +/* + This test checks wether complex types work with structs, unions + and pointers. + + Aswell as const and volatile, but only in the sense that having + those qualifiers doesn't crash gcc. + +*/ + +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + gcc_jit_type *type_int = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *type_cd = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE); + + gcc_jit_lvalue *cd_gbl = gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + type_cd, + "a_complex_global_double_2"); + + /* These globals are not used for anything */ + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_type_get_volatile (type_cd), + "a_volatile_complex_double"); + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_type_get_const (type_cd), + "a_const_complex_double"); + + gcc_jit_type *arr_type = + gcc_jit_context_new_array_type (ctxt, + 0, type_cd, 10); + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + arr_type, + "a_const_complex_double_array"); + + {/* Make a function returning union with 3.14 + 1516.j in it */ + gcc_jit_field *cd_field = + gcc_jit_context_new_field (ctxt, + 0, + type_cd, + "cd"); + gcc_jit_field *i_field = + gcc_jit_context_new_field (ctxt, + 0, + type_int, + "i"); + gcc_jit_field *fields[] = {cd_field, i_field}; + gcc_jit_type *cdi = + gcc_jit_context_new_union_type (ctxt, + 0, + "cdi", + 2, + fields); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + cdi, "a_uniony_fn_returning_union", 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + gcc_jit_lvalue *local = + gcc_jit_function_new_local (foo, 0, cdi, "union_local"); + gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field + (local, 0, cd_field); + gcc_jit_block_add_assignment + (block, 0, lv_field, + gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, type_cd, 3.14 + 1592.j)); + + /* Note: Writes to global here */ + gcc_jit_block_add_assignment ( + block, 0, cd_gbl, + gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, type_cd, 6535 + 9.j)); + + gcc_jit_block_end_with_return ( + block, 0, gcc_jit_lvalue_as_rvalue (local)); + } + {/* Make a function returning a complexy struct */ + gcc_jit_field *cd_field = + gcc_jit_context_new_field (ctxt, + 0, + type_cd, + "cd"); + gcc_jit_field *i_field = + gcc_jit_context_new_field (ctxt, + 0, + type_int, + "i"); + gcc_jit_field *fields[] = {cd_field, i_field}; + gcc_jit_type *cdi_struct = + gcc_jit_struct_as_type( + gcc_jit_context_new_struct_type (ctxt, + 0, + "cdi_struct", + 2, + fields)); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + cdi_struct, "a_structy_fn_returning_struct", 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + gcc_jit_lvalue *local = + gcc_jit_function_new_local (foo, 0, cdi_struct, "local"); + gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field ( + local, 0, cd_field); + gcc_jit_block_add_assignment ( + block, 0, lv_field, + /* Note: Reads from global here */ + gcc_jit_lvalue_as_rvalue(cd_gbl)); + + gcc_jit_block_end_with_return ( + block, 0, gcc_jit_lvalue_as_rvalue (local)); + } + {/* Make a function taking a pointer to a complex double, + add 1+1.j to it, and return the pointer */ + gcc_jit_type *type_return = + gcc_jit_type_get_pointer (type_cd); + + gcc_jit_param *param = gcc_jit_context_new_param ( + ctxt, 0, gcc_jit_type_get_pointer (type_cd), "pcd"); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + type_return, + "a_pointy_fn_returning_points", 1, ¶m, 0); + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_rvalue *param_rv = gcc_jit_param_as_rvalue ( + gcc_jit_function_get_param (foo, 0)); + + gcc_jit_rvalue *rval = gcc_jit_context_new_binary_op ( + ctxt, 0, GCC_JIT_BINARY_OP_PLUS, type_cd, + gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, type_cd, 1 + 1.j), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference ( + param_rv, 0))); + gcc_jit_block_add_assignment (block, 0, + gcc_jit_rvalue_dereference ( + param_rv, 0), + rval); + + gcc_jit_block_end_with_return ( + block, 0, param_rv); + } +} + +typedef union { + _Complex double cd; + int i; +} complex_test_union; + +typedef struct { + _Complex double cd; + int i; +} complex_test_struct; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + { + complex_test_union (*fn)() = gcc_jit_result_get_code (result, "a_uniony_fn_returning_union"); + CHECK_NON_NULL (fn); + + complex_test_union u = fn(); + CHECK_VALUE (u.cd, 3.14 + 1592.j); + } + { + complex_test_struct (*fn)() = gcc_jit_result_get_code (result, "a_structy_fn_returning_struct"); + CHECK_NON_NULL (fn); + + complex_test_struct s = fn(); + CHECK_VALUE (s.cd, 6535 + 9.j); + } + { + _Complex double * + (*fn)(_Complex double *) = gcc_jit_result_get_code (result, "a_pointy_fn_returning_points"); + CHECK_NON_NULL (fn); + + _Complex double s = 2. + 3.i; + _Complex double *p = fn(&s); + CHECK_VALUE (p, &s); + CHECK_VALUE (s, 3. + 4.i); + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-operators.c b/gcc/testsuite/jit.dg/test-complex-operators.c new file mode 100644 index 00000000000..091b56fb4d2 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-operators.c @@ -0,0 +1,353 @@ +/* + Test ==, !=, the create-complex-from-reals-operator, + unary minus and *-/+ + */ + + +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +static void +make_code_compop (gcc_jit_context *ctxt, + const char *fn_name, + int type, + enum gcc_jit_comparison op) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); + + gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, tt, "f1"); + gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, tt, "f2"); + + gcc_jit_param *params[] = {param1, param2}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + bool_type, fn_name, 2, params, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param (foo, 0)); + gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param (foo, 1)); + + /* return f1 op f2; */ + gcc_jit_rvalue *rcompop = gcc_jit_context_new_comparison + (ctxt, 0, op, + gcc_jit_lvalue_as_rvalue (f1), + gcc_jit_lvalue_as_rvalue (f2)); + + gcc_jit_block_end_with_return (block, 0, rcompop); +} + +static void +make_code_binop (gcc_jit_context *ctxt, + const char *fn_name, + int type1, + int type2, + int return_type, + enum gcc_jit_binary_op op) +{ + gcc_jit_type *tt1 = gcc_jit_context_get_type(ctxt, type1); + gcc_jit_type *tt2 = gcc_jit_context_get_type(ctxt, type2); + gcc_jit_type *tr = gcc_jit_context_get_type(ctxt, return_type); + + gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt1, "f1"); + gcc_jit_param *param2 = gcc_jit_context_new_param(ctxt, 0, tt2, "f2"); + + gcc_jit_param *params[] = {param1, param2}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tr, fn_name, 2, params, 0); + + gcc_jit_block *block = gcc_jit_function_new_block(foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue( + gcc_jit_function_get_param(foo, 0)); + gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue( + gcc_jit_function_get_param(foo, 1)); + + /* return f1 op f2; */ + gcc_jit_rvalue *rbinop = gcc_jit_context_new_binary_op + (ctxt, 0, op, tr, + gcc_jit_lvalue_as_rvalue (f1), + gcc_jit_lvalue_as_rvalue (f2)); + + gcc_jit_block_end_with_return (block, 0, rbinop); +} + +static void +make_code_unop (gcc_jit_context *ctxt, + const char *fn_name, + int type1, + enum gcc_jit_unary_op op) +{ + gcc_jit_type *tt = gcc_jit_context_get_type(ctxt, type1); + + gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt, "f1"); + + gcc_jit_param *params[] = {param1}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 1, params, 0); + + gcc_jit_block *block = gcc_jit_function_new_block(foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue( + gcc_jit_function_get_param(foo, 0)); + + /* return op f1; */ + gcc_jit_rvalue *rbinop = gcc_jit_context_new_unary_op + (ctxt, 0, op, tt, + gcc_jit_lvalue_as_rvalue (f1)); + + gcc_jit_block_end_with_return (block, 0, rbinop); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + make_code_binop (ctxt, "plus_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_PLUS); + make_code_binop (ctxt, "minus_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_MINUS); + make_code_binop (ctxt, "div_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_DIVIDE); + make_code_binop (ctxt, "mul_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_MULT); + + make_code_binop (ctxt, "cmplx_float_float", + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_COMPLEX); + + /* Unundef to test different error msgs */ +#if 0 + make_code_binop (ctxt, "should_not_work", + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_BINARY_OP_COMPLEX); +#endif + + make_code_binop (ctxt, "cmplx_double_double", + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_BINARY_OP_COMPLEX); + + make_code_binop (ctxt, "cmplx_long_double_long_double", + GCC_JIT_TYPE_LONG_DOUBLE, + GCC_JIT_TYPE_LONG_DOUBLE, + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_BINARY_OP_COMPLEX); + + make_code_unop (ctxt, "minus_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_UNARY_OP_MINUS); + + make_code_compop (ctxt, "equal_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_COMPARISON_EQ); + make_code_compop (ctxt, "nequal_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_COMPARISON_NE); + make_code_compop (ctxt, "equal_complex_double", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_COMPARISON_EQ); + make_code_compop (ctxt, "nequal_complex_double", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_COMPARISON_NE); + make_code_compop (ctxt, "equal_complex_long_double", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_COMPARISON_EQ); + make_code_compop (ctxt, "nequal_complex_long_double", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_COMPARISON_NE); + + /* Unundef to test different error msgs */ +#if 0 + make_code_compop (ctxt, "qweasdzxc", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_COMPARISON_GE); +#endif + +} + +typedef _Complex float (*cf_cfcf)(_Complex float, _Complex float); +typedef _Complex float (*cf_cf)(_Complex float); +typedef _Bool (*b_cfcf)(_Complex float, _Complex float); +typedef _Bool (*b_cdcd)(_Complex double, _Complex double); +typedef _Bool (*b_cldcld)(_Complex long double, _Complex long double); + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + (void) ctxt; + CHECK_NON_NULL (result); + + {/* Test binary operators */ + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "plus_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) + (3.f + 4.fj)); + } + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "minus_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) - (3.f + 4.fj)); + } + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "div_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)/(3.f + 4.fj)); + } + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "mul_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)*(3.f + 4.fj)); + } + { + _Complex float (*fn)(float, float) = + gcc_jit_result_get_code (result, "cmplx_float_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1, 2), 1.f + 2.fi); + /* Note that the real answer is 0 not nan as it would have been by + multiplying INF * 1.fi */ + CHECK_VALUE (fn (0, INFINITY), CMPLXF (0, INFINITY)); + CHECK_VALUE (fn (0, -INFINITY), CMPLXF (0, -INFINITY)); + + CHECK_VALUE (crealf (fn (0, NAN)), crealf (CMPLXF (0, NAN))); + CHECK (isnanf (cimagf (fn (0, NAN)))); + + /* -0 need be preserved */ + _Complex float f = fn (0, -0.); + CHECK (signbit ( cimagf (f)) != 0); + CHECK_VALUE (f, CMPLXF (0, -0.)); + } + { + _Complex double (*fn)(double, double) = + gcc_jit_result_get_code (result, "cmplx_double_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1, 2), 1. + 2.i); + CHECK_VALUE (fn (0, INFINITY), CMPLX (0, INFINITY)); + CHECK_VALUE (fn (0, -INFINITY), CMPLX (0, -INFINITY)); + + CHECK_VALUE (creal (fn (0, NAN)), creal (CMPLX (0, NAN))); + CHECK (isnan (cimag (fn (0, NAN)))); + + _Complex double f = fn (0, -0.); + CHECK (signbit (cimag (f)) != 0); + CHECK_VALUE (f, CMPLXF (0, -0.)); + } + { + _Complex long double (*fn)(long double, long double) = + gcc_jit_result_get_code (result, "cmplx_long_double_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1, 2), 1.L + 2.Li); + CHECK_VALUE (fn (0, INFINITY), CMPLXL (0, INFINITY)); + CHECK_VALUE (fn (0, -INFINITY), CMPLXL (0, -INFINITY)); + + CHECK_VALUE (creall (fn (0, NAN)), creall (CMPLXL (0, NAN))); + CHECK (isnanl (cimagl (fn (0, NAN)))); + + _Complex long double f = fn (0, -0.); + CHECK (signbit (cimag (f)) != 0); + CHECK_VALUE (f, CMPLXL (0, -0.)); + } + } + + {/* Test unary ops */ + { + cf_cf fn = + gcc_jit_result_get_code (result, "minus_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj), -(1.f + 2.fj)); + } + } + {/* Test comp ops */ + { + b_cfcf fn = + gcc_jit_result_get_code (result, "equal_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 1); + CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 0); + } + { + b_cfcf fn = + gcc_jit_result_get_code (result, "nequal_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 0); + CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 1); + } + { + b_cdcd fn = + gcc_jit_result_get_code (result, "equal_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0); + } + { + b_cdcd fn = + gcc_jit_result_get_code (result, "nequal_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1); + } + { + b_cldcld fn = + gcc_jit_result_get_code (result, "equal_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0); + } + { + b_cldcld fn = + gcc_jit_result_get_code (result, "nequal_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-types.c b/gcc/testsuite/jit.dg/test-complex-types.c new file mode 100644 index 00000000000..c555133367b --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-types.c @@ -0,0 +1,677 @@ +/* + Test cast from all complex types to all primitive types + except bool and amongst the complex types them self. + + Also test some cast from non-complex to complex. + + Also call a mathlib complex function and create a + complex global. + */ + +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +/* + Make code 1: (check that function calls works) + complex float csqrtf(complex float f); + + complex float complex_float_foo(complex float f) + { + return csqrtf( f * (complex float)2.); + } + + Make code 2: (check casts) + int float complex_float_to_int (complex float f) + { + return f; + } + + with different types and function names. + */ + + +static void +make_code1(gcc_jit_context* ctxt, + const char *fn_name, + const char *sqrt_fn, + int type) +{ + gcc_jit_rvalue *rval1, *rval2; + gcc_jit_block *block; + + gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, type); + gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f"); + gcc_jit_function *func = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_IMPORTED, + ct, sqrt_fn, 1, ¶m, 0); + + param = gcc_jit_context_new_param (ctxt, 0, ct, "f"); + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + ct, fn_name, 1, ¶m, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + rval1 = gcc_jit_context_new_binary_op (ctxt, 0, GCC_JIT_BINARY_OP_MULT, ct, + gcc_jit_param_as_rvalue ( + gcc_jit_function_get_param (foo, 0)), + gcc_jit_context_new_rvalue_from_double (ctxt, ct, 2.)); + + rval2 = gcc_jit_context_new_call (ctxt, 0, func, 1, &rval1); + + gcc_jit_block_end_with_return (block, 0, rval2); +} + +static void +make_code2 (gcc_jit_context *ctxt, + const char *fn_name, + int complex_type, + int target_type) +{ + gcc_jit_block *block; + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, target_type); + gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, complex_type); + + gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f"); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 1, ¶m, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_block_end_with_return (block, 0, + gcc_jit_context_new_cast (ctxt, 0, + gcc_jit_param_as_rvalue ( + gcc_jit_function_get_param (foo, 0)), tt)); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE), + "a_complex_global_double"); + + make_code1 (ctxt, "complex_float_foo", "csqrtf", GCC_JIT_TYPE_COMPLEX_FLOAT); + make_code1 (ctxt, "complex_double_foo", "csqrt", GCC_JIT_TYPE_COMPLEX_DOUBLE); + make_code1 (ctxt, "complex_long_double_foo", "csqrtl", GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE); + +#define MAKE_CODE_2(name ,complex_type, target_type)\ + make_code2 (ctxt, #name, GCC_JIT_TYPE_ ## complex_type, GCC_JIT_TYPE_ ## target_type); + +#define MAKE_CODE_2_OUTER(name, type)\ + MAKE_CODE_2(name ## _to_char, type, CHAR)\ + MAKE_CODE_2(name ## _to_long_double, type, LONG_DOUBLE)\ + MAKE_CODE_2(name ## _to_double, type, DOUBLE)\ + MAKE_CODE_2(name ## _to_float, type, FLOAT)\ + MAKE_CODE_2(name ## _to_signed_char, type, SIGNED_CHAR)\ + MAKE_CODE_2(name ## _to_short, type, SHORT)\ + MAKE_CODE_2(name ## _to_int, type, INT)\ + MAKE_CODE_2(name ## _to_long, type, LONG)\ + MAKE_CODE_2(name ## _to_long_long, type, LONG_LONG)\ + MAKE_CODE_2(name ## _to_u_char, type, UNSIGNED_CHAR)\ + MAKE_CODE_2(name ## _to_u_short, type, UNSIGNED_SHORT)\ + MAKE_CODE_2(name ## _to_u_int, type, UNSIGNED_INT)\ + MAKE_CODE_2(name ## _to_u_long, type, UNSIGNED_LONG)\ + MAKE_CODE_2(name ## _to_u_long_long, type, UNSIGNED_LONG_LONG)\ + MAKE_CODE_2(name ## _to_complex_float, type, COMPLEX_FLOAT)\ + MAKE_CODE_2(name ## _to_complex_double, type, COMPLEX_DOUBLE)\ + MAKE_CODE_2(name ## _to_complex_long_double, type, COMPLEX_LONG_DOUBLE) + + /* Test all these casts */ + MAKE_CODE_2_OUTER (complex_float, COMPLEX_FLOAT) + MAKE_CODE_2_OUTER (complex_double, COMPLEX_DOUBLE) + MAKE_CODE_2_OUTER (complex_long_double, COMPLEX_LONG_DOUBLE) + + /* Test some of these casts */ + MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG) + MAKE_CODE_2_OUTER(float, FLOAT) + MAKE_CODE_2_OUTER(int, INT) + + /* Writing the reproducer takes annoyingly long time with all these + functions bellow, so #if them out. */ +#if 0 + MAKE_CODE_2_OUTER(long_double,LONG_DOUBLE) + MAKE_CODE_2_OUTER(double, DOUBLE) + MAKE_CODE_2_OUTER(long_long, LONG_LONG) + MAKE_CODE_2_OUTER(long, LONG) + MAKE_CODE_2_OUTER(short, UNSIGNED_SHORT) + MAKE_CODE_2_OUTER(signed_char, SIGNED_CHAR) + MAKE_CODE_2_OUTER(unsigned_long_long, UNSIGNED_LONG_LONG) + MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG) + MAKE_CODE_2_OUTER(unsigned_int, UNSIGNED_INT) + MAKE_CODE_2_OUTER(unsigned_short, UNSIGNED_SHORT) + MAKE_CODE_2_OUTER(unsigned_char, UNSIGNED_CHAR) + + MAKE_CODE_2_OUTER(char, CHAR) + /* Note: No bool */ +#endif + +#undef MAKE_CODE_2 +#undef MAKE_CODE_2_OUTER +} + +typedef complex long double (*ld_foop)(); +typedef complex double (*d_foop)(); +typedef complex float (*f_foop)(); + +#define FOO_to_BAR(foo, foo_txt) \ +typedef long long (* foo_txt ## _to_ll)(_Complex foo);\ +typedef long (* foo_txt ## _to_l)(_Complex foo);\ +typedef int (* foo_txt ## _to_i)(_Complex foo);\ +typedef short (* foo_txt ## _to_h)(_Complex foo);\ +typedef signed char (* foo_txt ## _to_sc)(_Complex foo);\ +typedef char (* foo_txt ## _to_c)(_Complex foo);\ +typedef unsigned long long (* foo_txt ## _to_ull)(_Complex foo);\ +typedef unsigned long (* foo_txt ## _to_ul)(_Complex foo);\ +typedef unsigned int (* foo_txt ## _to_ui)(_Complex foo);\ +typedef unsigned short (* foo_txt ## _to_uh)(_Complex foo);\ +typedef unsigned char (* foo_txt ## _to_uc)(_Complex foo);\ +typedef double (* foo_txt ## _to_d)(_Complex foo);\ +typedef float (* foo_txt ## _to_f)(_Complex foo);\ +typedef long double (* foo_txt ## _to_ld)(_Complex foo);\ +typedef _Complex double (* foo_txt ## _to_cd)(_Complex foo);\ +typedef _Complex float (* foo_txt ## _to_cf)(_Complex foo);\ +typedef _Complex long double (* foo_txt ## _to_cld)(_Complex foo);\ +typedef _Bool (* foo_txt ## _to_b)(_Complex foo); + +FOO_to_BAR (float, cf) +FOO_to_BAR (double, cd) +FOO_to_BAR (long double, cld) + +#undef FOO_to_BAR + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + { + {/* Just check that we can get the global. */ + _Complex double *d = gcc_jit_result_get_global (result, "a_complex_global_double"); + CHECK_NON_NULL (d); + } + } + {/* Check the square rooty thing. */ + { + d_foop d_foop = gcc_jit_result_get_code (result, "complex_double_foo"); + CHECK_NON_NULL (d_foop); + + complex double q = 2. + 2.i; + complex double ref = csqrt (q * 2.); + complex double ans = d_foop (q); + CHECK_VALUE (ref, ans); + } + { + f_foop f_foop = gcc_jit_result_get_code (result, "complex_float_foo"); + CHECK_NON_NULL (f_foop); + + complex float q = 2.f + 2.fi; + complex float ref = csqrtf (q * 2.f); + complex float ans = f_foop (q); + CHECK_VALUE (ref, ans); + } + { + ld_foop ld_foop = gcc_jit_result_get_code (result, "complex_long_double_foo"); + CHECK_NON_NULL (ld_foop); + + complex long double q = 2.L + 2.Li; + complex long double ref = csqrtl (q * 2.L); + complex long double ans = ld_foop (q); + CHECK_VALUE (ref, ans); + } + } + /* With the power of M-w C-y */ + + {/* Cast hither and thither */ + { + cf_to_ld fn = gcc_jit_result_get_code (result, "complex_float_to_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cf_to_d fn = gcc_jit_result_get_code (result, "complex_float_to_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cf_to_f fn = gcc_jit_result_get_code (result, "complex_float_to_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.fi), 1.1f); + CHECK_VALUE (fn (0.f + 2.2fi), 0.f); + } + { + cf_to_ll fn = gcc_jit_result_get_code (result, "complex_float_to_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_l fn = gcc_jit_result_get_code (result, "complex_float_to_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_i fn = gcc_jit_result_get_code (result, "complex_float_to_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_h fn = gcc_jit_result_get_code (result, "complex_float_to_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_sc fn = gcc_jit_result_get_code (result, "complex_float_to_signed_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_c fn = gcc_jit_result_get_code (result, "complex_float_to_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_ull fn = gcc_jit_result_get_code (result, "complex_float_to_u_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_ul fn = gcc_jit_result_get_code (result, "complex_float_to_u_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_ui fn = gcc_jit_result_get_code (result, "complex_float_to_u_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_uh fn = gcc_jit_result_get_code (result, "complex_float_to_u_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_uc fn = gcc_jit_result_get_code (result, "complex_float_to_u_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + } + + {/* complex double to ... */ + { + cd_to_ld fn = gcc_jit_result_get_code (result, "complex_double_to_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1); + CHECK_VALUE (fn (0.0 + 2.2i), 0.); + } + { + cd_to_d fn = gcc_jit_result_get_code (result, "complex_double_to_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cd_to_f fn = gcc_jit_result_get_code (result, "complex_double_to_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cd_to_ll fn = gcc_jit_result_get_code (result, "complex_double_to_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_l fn = gcc_jit_result_get_code (result, "complex_double_to_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_i fn = gcc_jit_result_get_code (result, "complex_double_to_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_h fn = gcc_jit_result_get_code (result, "complex_double_to_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_sc fn = gcc_jit_result_get_code (result, "complex_double_to_signed_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_c fn = gcc_jit_result_get_code (result, "complex_double_to_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_ull fn = gcc_jit_result_get_code (result, "complex_double_to_u_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_ul fn = gcc_jit_result_get_code (result, "complex_double_to_u_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_ui fn = gcc_jit_result_get_code (result, "complex_double_to_u_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_uh fn = gcc_jit_result_get_code (result, "complex_double_to_u_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_uc fn = gcc_jit_result_get_code (result, "complex_double_to_u_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + } + + {/* complex long double to ... */ + { + cld_to_ld fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.); + } + { + cld_to_d fn = gcc_jit_result_get_code (result, "complex_long_double_to_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.); + } + { + cld_to_f fn = gcc_jit_result_get_code (result, "complex_long_double_to_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.); + } + { + cld_to_ll fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_l fn = gcc_jit_result_get_code (result, "complex_long_double_to_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_i fn = gcc_jit_result_get_code (result, "complex_long_double_to_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_h fn = gcc_jit_result_get_code (result, "complex_long_double_to_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_sc fn = gcc_jit_result_get_code (result, "complex_long_double_to_signed_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_c fn = gcc_jit_result_get_code (result, "complex_long_double_to_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_ull fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_ul fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_ui fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_uh fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_uc fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + } + + { /* Try casting complex types to complex types */ + { + cld_to_cld fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L + 2.2Li); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L + 0.0Li); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.0L + 2.2Li); + } + { + cld_to_cd fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1 + 2.2i); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1 + 0.0i); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.0 + 2.2i); + } + { + cld_to_cf fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.0f + 2.2fi); + } + { + cd_to_cld fn = gcc_jit_result_get_code (result, "complex_double_to_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i); + } + { + cd_to_cd fn = gcc_jit_result_get_code (result, "complex_double_to_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i); + } + { + cd_to_cf fn = gcc_jit_result_get_code (result, "complex_double_to_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + { + cf_to_cld fn = gcc_jit_result_get_code (result, "complex_float_to_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + { + cf_to_cd fn = gcc_jit_result_get_code (result, "complex_float_to_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + { + cf_to_cf fn = gcc_jit_result_get_code (result, "complex_float_to_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + } + + {/* Test some of the non-complex to non-complex/complex casts */ + { + _Complex float(*fn)(float) = gcc_jit_result_get_code (result, "float_to_complex_float"); + CHECK_VALUE ( fn(3.f), 3.f); + } + { + _Complex float(*fn)(int) = gcc_jit_result_get_code (result, "int_to_complex_float"); + CHECK_VALUE ( fn(-3), -3.f); + } + { + _Complex double(*fn)(unsigned long) = gcc_jit_result_get_code (result, "unsigned_long_to_complex_double"); + CHECK_VALUE ( fn(3), 3.f); + } + { + double(*fn)(int) = gcc_jit_result_get_code (result, "int_to_double"); + CHECK_VALUE ( fn(3), 3.f); + } + { + int(*fn)(float) = gcc_jit_result_get_code (result, "float_to_int"); + CHECK_VALUE ( fn(3.), 3); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-error-complex-noenable.c b/gcc/testsuite/jit.dg/test-error-complex-noenable.c new file mode 100644 index 00000000000..0a7ba131f28 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-complex-noenable.c @@ -0,0 +1,31 @@ +/* + Test that we can't get a complex type without enabling them first + with + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); +*/ + +#include "libgccjit.h" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, + GCC_JIT_TYPE_COMPLEX_DOUBLE); + CHECK_VALUE (tt, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Verify that the diagnostic led to the context failing... */ + CHECK_VALUE (result, NULL); + + /* ...and that the message was captured by the API. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_get_type: complex types are only " + "available after enabling them with " + "gcc_jit_context_set_bool_enable_complex_types()"); +} -- 2.30.2 From patchwork Thu Oct 21 13:13:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petter Tomner X-Patchwork-Id: 46490 X-Patchwork-Delegate: dmalcolm@redhat.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 21E643857C70 for ; Thu, 21 Oct 2021 13:14:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 21E643857C70 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1634822073; bh=Smq01vjLoRI6cn69FL47sQPdqa1vNm7U0gGVkGQYTvg=; h=To:Subject:Date:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=VeOd9u0UVU7P4zmDnEUqHCSvAjj+DmrTU9v266Dw95GnoxoX3h9LqLb/sPx31YnJ2 l/0PELjlNbTIEKN8D/5Uc0s6N/6mcfyuC0HrdoS2xkEmeFNEXKCmtyJL4UKj1KcVIS UKgolAtwV7vki+bCAy+bUUYlPjQvBPjScmpB/7GY= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp-relay-2.sys.kth.se (smtp-relay-2.sys.kth.se [IPv6:2001:6b0:1:1200:250:56ff:fead:963e]) by sourceware.org (Postfix) with ESMTPS id 599E03858D39; Thu, 21 Oct 2021 13:13:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 599E03858D39 Received: from exdb2.ug.kth.se (exdb2.ug.kth.se [192.168.32.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp-relay-2.sys.kth.se (Postfix) with ESMTPS id 4HZnxB11lzzPMdX; Thu, 21 Oct 2021 15:13:50 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp-relay-2.sys.kth.se 4HZnxB11lzzPMdX Received: from exdb6.ug.kth.se (192.168.32.61) by exdb2.ug.kth.se (192.168.32.57) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.14; Thu, 21 Oct 2021 15:13:49 +0200 Received: from exdb6.ug.kth.se ([192.168.32.61]) by exdb6.ug.kth.se ([192.168.32.61]) with mapi id 15.02.0922.014; Thu, 21 Oct 2021 15:13:49 +0200 To: "gcc-patches@gcc.gnu.org" , "jit@gcc.gnu.org" Subject: [PATCH 2/2] jit: Complex types and loong constants Thread-Topic: [PATCH 2/2] jit: Complex types and loong constants Thread-Index: AQHXxn18wbXmptbjmk26GA1pYBQQPw== Date: Thu, 21 Oct 2021 13:13:49 +0000 Message-ID: <232536ab07e440938261425628490be9@kth.se> References: In-Reply-To: Accept-Language: sv-SE, en-US Content-Language: sv-SE X-MS-Has-Attach: yes X-MS-TNEF-Correlator: x-originating-ip: [192.168.32.250] MIME-Version: 1.0 X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP 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: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Petter Tomner via Gcc-patches From: Petter Tomner Reply-To: Petter Tomner Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch adds the possibility to make the following constants: * long long * long double * complex long double The long long one is needed for 32bit systems. The new entrypoints are: gcc_jit_context_new_rvalue_from_long_long gcc_jit_context_new_rvalue_from_long_double gcc_jit_context_new_rvalue_from_complex_long_double The patch also fixes a issue with the reproducer's debug c-file writer, which does not handle floating point numbers very well. I.e. infs, NaN and losing precision on doubles. make check-jit runs fine with the patch series on Debian 64x. See attachment. From f49cea6830b08a019958ef3f6a1ced1e416f80b3 Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Sat, 16 Oct 2021 21:55:20 +0200 Subject: [PATCH 2/3] long long Add long long, long double and complex long double constants This patch adds entrypoints to make constants (literals) for long long, long double and complex long double types. Also, it fixes problems with all floating point numbers in write_reproducer. I.e. support NAN and INF values, aswell as proper precision for double and long double. Which is needed for testing this patch. Signed-off-by: 2021-10-21 Petter Tomner gcc/jit/ * jit-playback.c : (new_rvalue_from_const ): New (new_rvalue_from_const ): Uses long long instead (new_rvalue_from_const ): New (new_rvalue_from_const <_Complex long double>) : New * jit-recording.c : (dump_reproducer_to_file) : Type punning NANs (reproducer_write_arr) : arr -> "char array literal"-string (memento_of_new_rvalue_from_const ) : New (memento_of_new_rvalue_from_const ) : New (memento_of_new_rvalue_from_const <_Complex long double>) : New (memento_of_new_rvalue_from_const ::make_debug_string): %g instead of %f (memento_of_new_rvalue_from_const ::write_reproducer): %a instead of %f, handle NAN and INF (memento_of_new_rvalue_from_const <_Complex double>::write_reproducer): %a instead of %f, handle NAN and INF. Use CMPLX macro. * libgccjit.c : * libgccjit.h : (LIBGCCJIT_HAVE_LONGLONG_CONSTANTS) : New (gcc_jit_context_new_rvalue_from_long_long) : New (gcc_jit_context_new_rvalue_from_long_double) : New (gcc_jit_context_new_rvalue_from_complex_long_double) : New * libgccjit++.h : New entrypoints * libgccjit.map: New entrypoints added to ABI 16 gcc/testsuite/ * jit.dg/all-non-failing-tests.h: Added test-long-literals.c * jit.dg/test-long-literals.c: New gcc/jit/docs/topics/ * expressions.rst : Updated docks --- gcc/jit/docs/topics/expressions.rst | 43 +- gcc/jit/jit-playback.c | 143 +++++- gcc/jit/jit-recording.c | 442 ++++++++++++++++++- gcc/jit/libgccjit++.h | 39 ++ gcc/jit/libgccjit.c | 46 ++ gcc/jit/libgccjit.h | 33 +- gcc/jit/libgccjit.map | 3 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 7 + gcc/testsuite/jit.dg/test-long-literals.c | 283 ++++++++++++ 9 files changed, 1017 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-long-literals.c diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index a98f35572b4..30a3b9780f9 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -70,6 +70,18 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :c:type:`long` value. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + long long value) + + Given a numeric type (integer or floating point), build an rvalue for + the given constant :c:type:`long long` value. + + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS` + .. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \ gcc_jit_type *numeric_type) @@ -98,6 +110,18 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :c:type:`double` value. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + long double value) + + Given a floating point type, build an rvalue for + the given constant :c:type:`long double`. + + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS` + .. function:: gcc_jit_rvalue *\ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \ gcc_jit_type *numeric_type, \ @@ -107,6 +131,23 @@ Simple expressions the given constant :c:type:`_Complex double`. When the result type is non-complex, the imaginary part is discarded. + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_COMPLEX` + +.. function:: extern gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_complex_long_double (gcc_jit_context *ctxt,\ + gcc_jit_type *numeric_type,\ + _Complex long double value); + + Given a floating point type, build an rvalue for + the given constant :c:type:`_Complex long double`. When the result type is + non-complex, the imaginary part is discarded. + + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS` + .. function:: gcc_jit_rvalue *\ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \ gcc_jit_type *pointer_type, \ @@ -403,7 +444,7 @@ Binary Operation C equivalent Supported operand type the imaginary. Negative zeroes are preserved and Inf:s do not lead to NaNs. - This operator was added in LIBGCCJIT_ABI_16; + This operator was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its presence using `#ifdef LIBGCCJIT_HAVE_COMPLEX` diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 8b1cb818b90..1f4dc31a1c1 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -61,6 +61,13 @@ along with GCC; see the file COPYING3. If not see #define SET_DECL_JIT_BIT_FIELD(NODE) \ (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1) +/* "There are always [atleast] 32 bits in each long, no matter the + size of the hosts long. We handle floating point representations + with up to 192 bits", says native_interpret_real() in fold-const.c. + That means 6 longs to store a long double. We'll make it 8 to + be safe with padding. */ +#define N_LONGS_LDOUBLE 8 + /* gcc::jit::playback::context::build_cast uses the convert.h API, which in turn requires the frontend to provide a "convert" function, apparently as a fallback for casts that can be simplified @@ -743,15 +750,14 @@ new_rvalue_from_const (type *type, } } -/* Specialization of making an rvalue from a const, for host . */ +/* Specialization of making an rvalue from a const, for host . */ template <> rvalue * context:: -new_rvalue_from_const (type *type, - long value) +new_rvalue_from_const (type *type, + long long value) { - // FIXME: type-checking, or coercion? tree inner_type = type->as_tree (); if (INTEGRAL_TYPE_P (inner_type)) { @@ -786,6 +792,17 @@ new_rvalue_from_const (type *type, } } +/* Specialization of making an rvalue from a const, for host . */ + +template <> +rvalue * +context:: +new_rvalue_from_const (type *type, + long value) +{ + return new_rvalue_from_const (type, value); +} + /* Specialization of making an rvalue from a const, for host . */ template <> @@ -847,6 +864,65 @@ new_rvalue_from_const (type *type, } } +/* Specialization of making an rvalue from a const, for host . */ + +template <> +rvalue * +context:: +new_rvalue_from_const (type *type, + long double value) +{ + tree inner_type = type->as_tree (); + + scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (long_double_type_node); + + union + { + long double as_long_double; + uint32_t as_uint32s[N_LONGS_LDOUBLE]; + } u_real, u_imag; + + u_real.as_long_double = value; + + long int as_long_ints[N_LONGS_LDOUBLE]; + + for (int i = 0; i < N_LONGS_LDOUBLE; i++) + as_long_ints[i] = u_real.as_uint32s[i]; + + REAL_VALUE_TYPE real_value; + real_from_target (&real_value, as_long_ints, mode); + + if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + + REAL_VALUE_TYPE imag_value; + + long int zero_as_long_ints[N_LONGS_LDOUBLE]; + u_imag.as_long_double = 0.; + + for (int i = 0; i < N_LONGS_LDOUBLE; i++) + zero_as_long_ints[i] = u_imag.as_uint32s[i]; + + real_from_target (&imag_value, zero_as_long_ints, mode); + + real_type = complex_real_to_real (inner_type); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } + else + { + tree inner = build_real (inner_type, real_value); + return new rvalue (this, inner); + } +} + /* Specialization of making an rvalue from a const, for host . */ @@ -902,6 +978,65 @@ new_rvalue_from_const <_Complex double> (type *type, } } +/* Specialization of making an rvalue from a const, + for host <_Complex long double>. */ + +template <> +rvalue * +context:: +new_rvalue_from_const <_Complex long double> (type *type, + _Complex long double value) +{ + tree inner_type = type->as_tree (); + + scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (long_double_type_node); + + union + { + long double as_long_double; + uint32_t as_uint32s[N_LONGS_LDOUBLE]; + } u_real, u_imag; + + u_real.as_long_double = creall(value); + long int as_long_ints[N_LONGS_LDOUBLE]; + + for (int i = 0; i < N_LONGS_LDOUBLE; i++) + as_long_ints[i] = u_real.as_uint32s[i]; + + REAL_VALUE_TYPE real_value; + real_from_target (&real_value, as_long_ints, mode); + + if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + + REAL_VALUE_TYPE imag_value; + + long int value_as_long_ints[N_LONGS_LDOUBLE]; + u_imag.as_long_double = cimagl(value); + + for (int i = 0; i < N_LONGS_LDOUBLE; i++) + value_as_long_ints[i] = u_imag.as_uint32s[i]; + + real_from_target (&imag_value, value_as_long_ints, mode); + + real_type = complex_real_to_real (inner_type); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } + else + { + tree inner = build_real (inner_type, real_value); + return new rvalue (this, inner); + } +} + /* Specialization of making an rvalue from a const, for host . */ template <> diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index b3bb6acfeb9..8d34956fc67 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include #include +#include #include "jit-builtins.h" #include "jit-recording.h" @@ -1734,8 +1735,48 @@ recording::context::dump_reproducer_to_file (const char *path) " gcc_jit_context_dump_reproducer_to_file.\n\n"); print_version (r.get_file (), " ", false); r.write ("*/\n"); - r.write ("#include \n\n"); - r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n\n"); + r.write ( + "#include \n" + "#include \n" + "#include \n" + "#include \n\n"); + r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n"); + r.write ("#pragma GCC diagnostic ignored \"-Wunused-function\"\n\n"); + /* Type punning unions */ + r.write ("union dull { double d; unsigned long long ull; };\n\n"); + r.write ( + "union ldarr { long double ld; unsigned arr[sizeof (long double)];};\n\n"); + + /* Functions for type punning nan:s, keeping bit representation */ + r.write ( + "/* Convert type punned uint 64 to double NaN.\n" + " Might lose/corrupt payload between architectures. */\n" + "static double\n" + "ull_to_d (unsigned long long ull)\n" + "{\n" + " union dull u; u.ull = ull;\n" + " /* Paranoia check for foreign NaN representation. */\n" + " if (!isnan (u.d)) return NAN;\n" + " return u.d;\n" + "}\n\n"); + r.write ( + "/* Convert array to long double NaN.\n" + " Might lose/corrupt payload between architectures. */\n" + "static long double\n" + "arr_to_ld (unsigned char *arr, int len)\n" + "{\n" + " union ldarr u;\n" + /* Since long double sizes can vary between architectures, + we need to handle that. */ + " /* For foreign long double sizes */\n" + " if (sizeof u.arr != len) return NAN;\n" + " memcpy (u.arr, arr, len);\n" + /* The size might fool us becouse of padding, so check it is a nan. */ + " /* Handle foreign representations that is not NaN on this machine. */\n" + " if (!isnan (u.ld)) return NAN;\n" + " return u.ld;\n" + "}\n\n"); + r.write ("static void\nset_options ("); r.write_params (contexts); r.write (");\n\n"); @@ -4758,8 +4799,11 @@ recording::global::write_reproducer (reproducer &r) /* Explicit specialization of the various mementos we're interested in. */ template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const ; +template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const ; +template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const <_Complex double>; +template class recording::memento_of_new_rvalue_from_const <_Complex long double>; template class recording::memento_of_new_rvalue_from_const ; /* Implementation of the pure virtual hook recording::memento::replay_into @@ -4896,6 +4940,70 @@ recording::memento_of_new_rvalue_from_const ::write_reproducer (reproducer m_value); } +/* The make_debug_string specialization for , rendering it as + (TARGET_TYPE)LITERAL + e.g. + "(long long)42". */ + +template <> +string * +memento_of_new_rvalue_from_const ::make_debug_string () +{ + return string::from_printf (m_ctxt, + "(%s)%lli", + m_type->get_debug_string (), + m_value); +} + +/* The get_wide_int specialization for . */ + +template <> +bool +memento_of_new_rvalue_from_const ::get_wide_int (wide_int *out) const +{ + *out = wi::shwi (m_value, sizeof (m_value) * 8); + return true; +} + +/* The write_reproducer specialization for . */ + +template <> +void +recording::memento_of_new_rvalue_from_const :: +write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + + /* Same special case as in long */ + if (m_value == LONG_LONG_MIN) + { + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_long (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " %lldLL - 1); /* long long value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value + 1); + return; + } + + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_long (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " %lldLL); /* long long value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value); +} + + + /* The make_debug_string specialization for , rendering it as (TARGET_TYPE)LITERAL e.g. @@ -4906,7 +5014,7 @@ string * memento_of_new_rvalue_from_const ::make_debug_string () { return string::from_printf (m_ctxt, - "(%s)%f", + "(%s)%g", m_type->get_debug_string (), m_value); } @@ -4920,6 +5028,18 @@ memento_of_new_rvalue_from_const ::get_wide_int (wide_int *) const return false; } +/* For typepruning NaNs. */ +union dull { + double d; + unsigned long long ull; +}; + +union ldarr { + long double ld; + unsigned char arr[sizeof(long double)]; +}; + + /* The write_reproducer specialization for . */ template <> @@ -4927,14 +5047,154 @@ void recording::memento_of_new_rvalue_from_const ::write_reproducer (reproducer &r) { const char *id = r.make_identifier (this, "rvalue"); - r.write (" gcc_jit_rvalue *%s =\n" - " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" - " %s, /* gcc_jit_type *numeric_type */\n" - " %f); /* double value */\n", - id, - r.get_identifier (get_context ()), - r.get_identifier_as_type (m_type), - m_value); + + if (std::isfinite (m_value)) + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9g */\n" + " %a);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value, m_value); + else if (std::isinf (m_value)) + { + const char *sign = ""; + if (m_value < 0) + sign = "-"; + + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* inf */\n" + " %sINFINITY);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + sign); + } + else if (std::isnan (m_value)) { + union dull u; + u.d = m_value; + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* NaN */\n" + " ull_to_d(%#llx));\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + u.ull); + + } +} + +/* The make_debug_string specialization for , rendering it as + (TARGET_TYPE)LITERAL + e.g. + "(float)42.0". */ + +template <> +string * +memento_of_new_rvalue_from_const ::make_debug_string () +{ + return string::from_printf (m_ctxt, + "(%s)%Lg", + m_type->get_debug_string (), + m_value); +} + +/* The get_wide_int specialization for . */ + +template <> +bool +memento_of_new_rvalue_from_const ::get_wide_int (wide_int *) const +{ + return false; +} + +/* Helper function for write_reproducer() + + Write an array of unsigned chars to the reproducer, like: + {0x12, 0x34, ... } */ +static void +reproducer_write_arr (reproducer &r, unsigned char *arr, int len) +{ + if (len == 0) + return; + + r.write ("{"); + for (int i = 0; i < len - 1; i++) + r.write ("%#x , ", arr[i]); + r.write ("%#x }", arr[len - 1]); +} + +/* The write_reproducer specialization for . */ + +template <> +void +recording::memento_of_new_rvalue_from_const :: +write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + + if (std::isfinite (m_value)) + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9Lg */\n" + " %LaL); /* long double value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value, m_value); + else if (std::isinf (m_value)) + { + const char *sign = ""; + if (m_value < 0) + sign = "-"; + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* inf */\n" + " %sINFINITY);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + sign); + } + else + { + union ldarr u; /* For type punning to array */ + u.ld = m_value; + + r.write (" gcc_jit_rvalue *%s;\n", id); + /* Scope for local */ + r.write (" { /* long double NaN stored in char arr */\n"); + /* Write an char arr of the bytes of the NaN */ + r.write (" unsigned char arr[] = "); + reproducer_write_arr (r, u.arr, sizeof u.arr); + r.write (";\n"); + + r.write ( + " %s =\n" + " gcc_jit_context_new_rvalue_from_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %Lg */\n" + " arr_to_ld (arr, sizeof arr));\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value); + + r.write (" }\n"); /* Close scope */ + } } /* The make_debug_string specialization for , rendering it as @@ -4964,7 +5224,7 @@ get_wide_int (wide_int *) const return false; } -/* The write_reproducer specialization for . */ +/* The write_reproducer specialization for <_Complex double>. */ template <> void @@ -4974,14 +5234,164 @@ write_reproducer (reproducer &r) const char *id = r.make_identifier (this, "rvalue"); double real = creal(m_value); double imag = cimag(m_value); - r.write (" gcc_jit_rvalue *%s =\n" - " gcc_jit_context_new_rvalue_from_complex_double (%s, /* gcc_jit_context *ctxt */\n" - " %s, /* gcc_jit_type *numeric_type */\n" - " %f+%fj); /* double value */\n", + + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_complex_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9g + %.9gj */\n" + " CMPLX (",/* ... real, imag)); */ + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + real, imag); + + if (std::isfinite (real)) + r.write("%a,", real); + else if (std::isinf (real)) + { + if (real < 0) + r.write ("-INFINITY,"); + else + r.write ("INFINITY,"); + } + else /* NaN */ + { + /* Store the NaN as a unsigned long long literal. + ull_to_d() will convert it back to double */ + union dull u; + u.d = real; + r.write ("ull_to_d (%#llx),", u.ull); + } + + if (std::isfinite (imag)) + r.write("%a)", imag); + else if (std::isinf (imag)) + { + if (real < 0) + r.write ("-INFINITY)"); + else + r.write ("INFINITY)"); + } + else /* NaN */ + { + union dull u; + u.d = imag; + r.write ("ull_to_d (%#llx))", u.ull); + } + + r.write (");\n\n"); /* Close the function call */ +} + +template <> +string * +memento_of_new_rvalue_from_const <_Complex long double>::make_debug_string () +{ + long double real = creall(m_value); + long double imag = cimagl(m_value); + return string::from_printf (m_ctxt, + "(%s)(%Lg%+Lgj)", + m_type->get_debug_string (), + real, imag); +} + +/* The get_wide_int specialization for <_Complex long double>. */ + +template <> +bool +memento_of_new_rvalue_from_const <_Complex long double>:: +get_wide_int (wide_int *) const +{ + return false; +} + +/* The write_reproducer specialization for <_Complex long double>. */ + +template <> +void +recording::memento_of_new_rvalue_from_const <_Complex long double>:: +write_reproducer (reproducer &r) +{ + union ldarr ureal, uimag; + const char *id = r.make_identifier (this, "rvalue"); + long double real = creall(m_value); + long double imag = cimagl(m_value); + + int has_nan = std::isnan (real) || std::isnan (imag); + + if (has_nan) + { + r.write (" gcc_jit_rvalue *%s;\n", id); + /* Scope for multiple "NaN-arrays" in the source file to not clash */ + r.write (" {\n"); + } + if (std::isnan (real)) + { + /* Write the raw bytes of the long double as an char array + to store it in the source code. + I.e. unsigned char arr[] = {0x1, 0x2, 0x3 ... }; */ + ureal.ld = real; + r.write (" unsigned char arr_real[] = "); + reproducer_write_arr (r, ureal.arr, sizeof ureal.arr); + r.write (";\n"); + } + if (std::isnan (imag)) + { + uimag.ld = imag; + r.write (" unsigned char arr_imag[] = "); + reproducer_write_arr (r, uimag.arr, sizeof uimag.arr); + r.write (";\n"); + } + + if (has_nan) + r.write (" "); /* Definition is outside the scope for NaNs */ + else + r.write (" gcc_jit_rvalue *"); + + r.write ("%s =\n" + " gcc_jit_context_new_rvalue_from_complex_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9Lg + i*%.9Lg */\n" + " CMPLXL (", id, r.get_identifier (get_context ()), r.get_identifier_as_type (m_type), real, imag); + + if (std::isfinite (real)) + r.write ("%LaL, ", real); + else if (std::isinf (real)) + { + if (real < 0) + r.write ("-INFINITY, "); + else + r.write ("INFINITY, "); + } + else if (std::isnan (real)) + { + /* Convert the char array written above, to a long double */ + r.write ("arr_to_ld (arr_real, sizeof arr_real), "); + } + + if (std::isfinite (imag)) + r.write ("%LaL)", imag); + else if (std::isinf (imag)) + { + if (imag < 0) + r.write ("-INFINITY)"); + else + r.write ("INFINITY)"); + } + else if (std::isnan (imag)) + { + r.write ("arr_to_ld (arr_imag, sizeof arr_imag))"); + } + r.write(");\n\n"); /* Close function call */ + + if (has_nan) + r.write (" }\n"); /* Close NaN-array scope */ } /* The make_debug_string specialization for , rendering it as diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index c97aeb82812..b94cdc85c8e 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -188,12 +188,18 @@ namespace gccjit int value) const; rvalue new_rvalue (type numeric_type, long value) const; + rvalue new_rvalue (type numeric_type, + long long value) const; rvalue zero (type numeric_type) const; rvalue one (type numeric_type) const; rvalue new_rvalue (type numeric_type, double value) const; + rvalue new_rvalue (type numeric_type, + long double value) const; rvalue new_rvalue (type numeric_type, _Complex double value) const; + rvalue new_rvalue (type numeric_type, + _Complex long double value) const; rvalue new_rvalue (type pointer_type, void *value) const; rvalue new_rvalue (const std::string &value) const; @@ -936,6 +942,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + long long value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_long_long ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::zero (type numeric_type) const { @@ -960,6 +977,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + long double value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_long_double ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::new_rvalue (type numeric_type, _Complex double value) const @@ -971,6 +999,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + _Complex long double value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_complex_long_double ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::new_rvalue (type pointer_type, void *value) const diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 64630b810f4..97c5aba643e 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -1275,6 +1275,19 @@ gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long long value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const (numeric_type, value)); +} + /* Public entrypoint. See description in libgccjit.h. This is essentially equivalent to: @@ -1328,6 +1341,19 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long double value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const (numeric_type, value)); +} + gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, @@ -1347,6 +1373,26 @@ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_long_double ( + gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + _Complex long double value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + RETURN_NULL_IF_FAIL_PRINTF1 ( + numeric_type->is_float (), + ctxt, NULL, + "not a floating point type (type: %s)", + numeric_type->get_debug_string ()); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const <_Complex long double> (numeric_type, value)); +} + /* Public entrypoint. See description in libgccjit.h. diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index d4b10fc0644..c510c5cc902 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -834,6 +834,16 @@ gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, long value); +#define LIBGCCJIT_HAVE_LONGLONG_CONSTANTS +/* Get a constant from a long long. + + This function was added in LIBGCCJIT_ABI_16. You can test for + its presens with: + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long long value); extern gcc_jit_rvalue * gcc_jit_context_zero (gcc_jit_context *ctxt, gcc_jit_type *numeric_type); @@ -848,7 +858,17 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, double value); -/* Complex floating-point constants. +/* Get a constant from a long double. + + This function was added in LIBGCCJIT_ABI_16. You can test for + its presence with: + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long double value); + +/* Get a constant from a complex double. This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its presence using @@ -858,6 +878,17 @@ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, _Complex double value); +/* Get a constant from a complex long double. + + This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_long_double ( + gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + _Complex long double value); + /* Pointers. */ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index c9b044dc8f5..4022dbb6fbc 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -209,5 +209,8 @@ LIBGCCJIT_ABI_15 { LIBGCCJIT_ABI_16 { global: gcc_jit_context_new_rvalue_from_complex_double; + gcc_jit_context_new_rvalue_from_complex_long_double; gcc_jit_context_set_bool_enable_complex_types; + gcc_jit_context_new_rvalue_from_long_double; + gcc_jit_context_new_rvalue_from_long_long; } LIBGCCJIT_ABI_15; \ No newline at end of file diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 7b45acd4b9c..8416b312bad 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -239,6 +239,13 @@ #undef create_code #undef verify_code +/* test-long-literals.c */ +#define create_code create_code_long_literals +#define verify_code verify_code_long_literals +#include "test-long-literals.c" +#undef create_code +#undef verify_code + /* test-long-string-literal.c */ #define create_code create_code_long_string_literal #define verify_code verify_code_long_string_literal diff --git a/gcc/testsuite/jit.dg/test-long-literals.c b/gcc/testsuite/jit.dg/test-long-literals.c new file mode 100644 index 00000000000..a83af8b0eb1 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-long-literals.c @@ -0,0 +1,283 @@ +/* Test long literals. + + I.e. long long, long double and long complex doubles. + + Also test NaN:s and inf:s with double. */ + + +#include +#include +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +int compare_nans(double d1, double d2) +{ + union {double d; unsigned long long ull;} u1, u2; + + u1.d = d1; + u2.d = d2; + + return u1.ull == u2.ull; +} + +int compare_nansl(long double d1, long double d2) +{ + union { long double ld; unsigned char arr[sizeof (long double)];} + u1 = {.arr = {0}}, + u2 = {.arr = {0}}; + /* Zero the arrs. I don't know if long double zeroes all its size + since some of it is padding. */ + + u1.ld = d1; + u2.ld = d2; + + return memcmp (u1.arr, u2.arr, sizeof u1.arr) == 0; +} + +static void +make_code_lit_cld(gcc_jit_context *ctxt, + const char *fn_name, + int type, + _Complex long double local_val, + int lit_type) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + if (lit_type == 'L') + r1 = gcc_jit_context_new_rvalue_from_long_double ( + ctxt, tt, creall(local_val)); + else if (lit_type == 'C') + r1 = gcc_jit_context_new_rvalue_from_complex_long_double ( + ctxt, tt, local_val); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + +static void +make_code_lit_d (gcc_jit_context *ctxt, + const char *fn_name, + int type, + _Complex double local_val, + int lit_type) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + if (lit_type == 'd') + r1 = gcc_jit_context_new_rvalue_from_double ( + ctxt, tt, local_val); + else if (lit_type == 'c') + r1 = gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, tt, local_val); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + +static void +make_code_lit_ll (gcc_jit_context *ctxt, + const char *fn_name, + int type, + long long local_val) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + r1 = gcc_jit_context_new_rvalue_from_long_long ( + ctxt, tt, creall(local_val)); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + + +union uu { double d; long long l; } u; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + make_code_lit_cld (ctxt, "long_double_ldlit_1c1", + GCC_JIT_TYPE_LONG_DOUBLE, + -1.1L, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_1Ldiv3L", + GCC_JIT_TYPE_LONG_DOUBLE, + 1/3.L, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_inf", + GCC_JIT_TYPE_LONG_DOUBLE, + INFINITY, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_minf", + GCC_JIT_TYPE_LONG_DOUBLE, + -INFINITY, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_nan1", + GCC_JIT_TYPE_LONG_DOUBLE, + nanl("1"), 'L'); + + make_code_lit_cld (ctxt, "complex_long_double_cldlit_1div3_2div3j", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + 1/3.L + 2.Lj/3, 'C'); + + make_code_lit_cld (ctxt, "complex_long_double_cldlit_inf_infj", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + CMPLXL (INFINITY, INFINITY), 'C'); + make_code_lit_cld (ctxt, "complex_long_double_cldlit_minf_minfj", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + CMPLXL (-INFINITY, -INFINITY), 'C'); + make_code_lit_cld (ctxt, "complex_long_double_cldlit_nan1_nan2j", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + CMPLXL (nanl ("1"), nanl ("2")), 'C'); + + make_code_lit_ll (ctxt, "long_long_lllit_2", + GCC_JIT_TYPE_LONG_LONG, + 2); + + make_code_lit_ll (ctxt, "long_long_lllit_min", + GCC_JIT_TYPE_LONG_LONG, + LLONG_MIN); + + make_code_lit_ll (ctxt, "long_long_lllit_max", + GCC_JIT_TYPE_LONG_LONG, + LLONG_MAX); + + make_code_lit_ll (ctxt, "ulong_long_lllit_max", + GCC_JIT_TYPE_UNSIGNED_LONG_LONG, + ULLONG_MAX); + + make_code_lit_d (ctxt, "double_nan1", + GCC_JIT_TYPE_DOUBLE, + nan("1"), 'd'); + make_code_lit_d (ctxt, "double_inf", + GCC_JIT_TYPE_DOUBLE, + INFINITY, 'd'); + make_code_lit_d (ctxt, "double_minf", + GCC_JIT_TYPE_DOUBLE, + -INFINITY, 'd'); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + { + double (*f)() = gcc_jit_result_get_code ( + result, "double_nan1"); + + CHECK(compare_nans (f(), nan("1"))); + } + { + double (*f)() = gcc_jit_result_get_code ( + result, "double_inf"); + + CHECK_VALUE (f(), INFINITY); + } + { + double (*f)() = gcc_jit_result_get_code ( + result, "double_minf"); + + CHECK_VALUE (f(), -INFINITY); + } + { + long double (*f)() = gcc_jit_result_get_code ( + result, "long_double_ldlit_1c1"); + + CHECK_VALUE(f (), -1.1L); + } + { + long double (*f)() = gcc_jit_result_get_code ( + result, "long_double_ldlit_1Ldiv3L"); + + CHECK_VALUE(f (), 1.L/3.L); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_1div3_2div3j"); + + CHECK_VALUE (f(), 1/3.L + 2.Lj/3); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_inf_infj"); + + CHECK_VALUE (f(),CMPLXL (INFINITY, INFINITY)); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_minf_minfj"); + + CHECK_VALUE (f(),CMPLXL (-INFINITY, -INFINITY)); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_nan1_nan2j"); + _Complex double key = CMPLXL (nanl ("1"), nanl ("2")); + _Complex double ans = f(); + + CHECK (compare_nansl (creall (key), creall (ans))); + CHECK (compare_nansl (cimagl (key), cimagl (ans))); + } + { + long long (*f)() = gcc_jit_result_get_code ( + result, "long_long_lllit_2"); + + CHECK_VALUE (f(), 2); + } + { + long long (*f)() = gcc_jit_result_get_code ( + result, "long_long_lllit_min"); + + CHECK_VALUE (f(), LLONG_MIN); + } + { + long long (*f)() = gcc_jit_result_get_code ( + result, "long_long_lllit_max"); + + CHECK_VALUE (f(), LLONG_MAX); + } + { + unsigned long long (*f)() = gcc_jit_result_get_code ( + result, "ulong_long_lllit_max"); + + CHECK_VALUE (f(), ULLONG_MAX); + } +} -- 2.30.2