From patchwork Tue Sep 14 23:40:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petter Tomner X-Patchwork-Id: 45002 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 6A006385780A for ; Tue, 14 Sep 2021 23:41:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6A006385780A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1631662885; bh=UfwruiuNcQeDZ+1Q0adf6Siy8EZbobF3yk6mpzU3dhI=; 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=gYh+OQSgH8yWAWTlj5pQkOkNOBKS2EbkiOm7pRoFtMzb/1iULDfX9bbTvP+tZ5oVk 5/whUBe6QR0RApp82GbyS0ujsnALEvX4zupuCD3Qz1J0vA9vT/W2k5IuzKkG8JdoVy y0tXjxwXTYbkBa6XHSQYPRMsSILmGabajaj0xE0A= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp-4.sys.kth.se (smtp-4.sys.kth.se [IPv6:2001:6b0:1:1300:250:56ff:fea6:2de3]) by sourceware.org (Postfix) with ESMTPS id 3BDD83858402; Tue, 14 Sep 2021 23:40:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 3BDD83858402 Received: from smtp-4.sys.kth.se (localhost.localdomain [127.0.0.1]) by smtp-4.sys.kth.se (Postfix) with ESMTP id 4765D63E; Wed, 15 Sep 2021 01:40:50 +0200 (CEST) X-Virus-Scanned: by amavisd-new at kth.se Received: from smtp-4.sys.kth.se ([127.0.0.1]) by smtp-4.sys.kth.se (smtp-4.sys.kth.se [127.0.0.1]) (amavisd-new, port 10024) with LMTP id p1hlrzqPdbqQ; Wed, 15 Sep 2021 01:40:48 +0200 (CEST) Received: from exdb5.ug.kth.se (exdb5.ug.kth.se [192.168.32.60]) by smtp-4.sys.kth.se (Postfix) with ESMTPS id CCCB7139; Wed, 15 Sep 2021 01:40:47 +0200 (CEST) Received: from exdb6.ug.kth.se (192.168.32.61) by exdb5.ug.kth.se (192.168.32.60) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.858.15; Wed, 15 Sep 2021 01:40:47 +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.0858.015; Wed, 15 Sep 2021 01:40:47 +0200 To: "gcc-patches@gcc.gnu.org" , "jit@gcc.gnu.org" Subject: [PATCH 2/2] jit: Add support for complex types Thread-Topic: [PATCH 2/2] jit: Add support for complex types Thread-Index: AQHXqcHx9OAzEPOSmEuKPGeiv3D0Tw== Date: Tue, 14 Sep 2021 23:40:47 +0000 Message-ID: References: <38cabc705eaf4fe6b26e312b4c5a2cd9@kth.se> In-Reply-To: <38cabc705eaf4fe6b26e312b4c5a2cd9@kth.se> Accept-Language: sv-SE, en-US Content-Language: sv-SE X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [192.168.32.250] MIME-Version: 1.0 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, SPF_HELO_PASS, 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" From a833639e6dfe9ff44b1084b5a5cbbf477d023cf5 Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Tue, 14 Sep 2021 23:52:06 +0200 Subject: [PATCH 2/2] jit: Testcases and documentation for complex types Will squash with path 1 Signed-off-by: 2021-09-15 Petter Tomner gcc/jit/docs/topics/ * gcc/jit/docs/topics/contexts.rst Updated docs * gcc/jit/docs/topics/expressions.rst * gcc/jit/docs/topics/types.rst * test-complex-builtins.c New * test-complex-literals.c New * test-complex-misc.c New * test-complex-operators.c New * test-complex-types.c New --- gcc/jit/docs/topics/contexts.rst | 20 + gcc/jit/docs/topics/expressions.rst | 89 ++- gcc/jit/docs/topics/types.rst | 12 +- 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 | 206 ++++++ gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++ gcc/testsuite/jit.dg/test-complex-types.c | 677 ++++++++++++++++++ 9 files changed, 1720 insertions(+), 29 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 diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst index 00fb17e155d..42fdef7c654 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..fc0345c3e1d 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/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..c35275b21de --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-misc.c @@ -0,0 +1,206 @@ +/* + 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); + } + + gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE, "misc.o"); +} + +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); + } + } +}