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 <tom...@kth.se>
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 <tom...@kth.se>
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 <pthread.h>
@@ -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 <int>. */
template <>
@@ -694,6 +715,25 @@ new_rvalue_from_const <int> (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 <long> (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 <double> (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 <double _Complex>. */
+
+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 <void *>. */
@@ -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 <pthread.h>
+#include <complex.h>
#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 <int>;
template class recording::memento_of_new_rvalue_from_const <long>;
template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <_Complex double>;
template class recording::memento_of_new_rvalue_from_const <void *>;
/* Implementation of the pure virtual hook recording::memento::replay_into
@@ -4881,6 +4937,53 @@ recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproduc
m_value);
}
+/* The make_debug_string specialization for <double complex>, 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 <double complex>. */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <_Complex double>::
+get_wide_int (wide_int *) const
+{
+ return false;
+}
+
+/* The write_reproducer specialization for <double>. */
+
+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 <void *>, 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 <double> (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 <double _Complex> (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 <math.h>
+#include <complex.h>
+
+#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 <math.h>
+#include <complex.h>
+
+#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 <math.h>
+#include <complex.h>
+
+#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 <math.h>
+#include <complex.h>
+
+#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 <math.h>
+#include <complex.h>
+
+#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