From 6d40e82935943ecf0c93c2fede0c236a640cb6d2 Mon Sep 17 00:00:00 2001 From: ZERICO2005 <71151164+ZERICO2005@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:37:03 -0600 Subject: [PATCH] Added C11 , along with CMPLX creal cimag conj --- src/libc/cimagf.src | 15 ++ src/libc/cimagl.src | 15 ++ src/libc/cmplxf.src | 23 ++ src/libc/cmplxl.src | 21 ++ src/libc/conjf.src | 66 ++++++ src/libc/conjl.src | 23 ++ src/libc/crealf.src | 12 ++ src/libc/creall.src | 11 + src/libc/header_test.c | 1 + src/libc/include/complex.h | 124 +++++++++++ test/floating_point/complex/autotest.json | 43 ++++ test/floating_point/complex/makefile | 17 ++ .../complex/src/complex_alias.asm | 29 +++ test/floating_point/complex/src/main.c | 202 ++++++++++++++++++ 14 files changed, 602 insertions(+) create mode 100644 src/libc/cimagf.src create mode 100644 src/libc/cimagl.src create mode 100644 src/libc/cmplxf.src create mode 100644 src/libc/cmplxl.src create mode 100644 src/libc/conjf.src create mode 100644 src/libc/conjl.src create mode 100644 src/libc/crealf.src create mode 100644 src/libc/creall.src create mode 100644 src/libc/include/complex.h create mode 100644 test/floating_point/complex/autotest.json create mode 100644 test/floating_point/complex/makefile create mode 100644 test/floating_point/complex/src/complex_alias.asm create mode 100644 test/floating_point/complex/src/main.c diff --git a/src/libc/cimagf.src b/src/libc/cimagf.src new file mode 100644 index 000000000..cf0030064 --- /dev/null +++ b/src/libc/cimagf.src @@ -0,0 +1,15 @@ + assume adl=1 + + section .text + + public _cimagf, _cimag + +; float cimagf(float _Complex) +_cimagf: +_cimag: + ld iy, 0 + add iy, sp + ld sp, iy + ld hl, (iy + 7) + ld e, (iy + 10) + ret diff --git a/src/libc/cimagl.src b/src/libc/cimagl.src new file mode 100644 index 000000000..575fa97c2 --- /dev/null +++ b/src/libc/cimagl.src @@ -0,0 +1,15 @@ + assume adl=1 + + section .text + + public _cimagl + +; long double cimagl(long double _Complex) +_cimagl: + ld iy, 0 + add iy, sp + ld sp, iy + ld hl, (iy + 11) + ld de, (iy + 14) + ld bc, (iy + 17) + ret diff --git a/src/libc/cmplxf.src b/src/libc/cmplxf.src new file mode 100644 index 000000000..3a6832baf --- /dev/null +++ b/src/libc/cmplxf.src @@ -0,0 +1,23 @@ + assume adl=1 + + section .text + + public _CMPLXF, _CMPLX + +; float _Complex CMPLXF(float x, float y) /* struct ABI */ +_CMPLXF: +_CMPLX: + pop iy, de + or a, a + sbc hl, hl + add hl, sp + push de ; ZDS II sret + ld bc, 4 ; sizeof(float _Complex) + ldir + ; skip over the padding + inc hl + inc hl + ld c, 4 + ldir + ex (sp), hl ; ZDS II sret + jp (iy) diff --git a/src/libc/cmplxl.src b/src/libc/cmplxl.src new file mode 100644 index 000000000..d2628ed64 --- /dev/null +++ b/src/libc/cmplxl.src @@ -0,0 +1,21 @@ + assume adl=1 + + section .text + + public _CMPLXL + +; long double _Complex CMPLXL(long double x, long double y) /* struct ABI */ +_CMPLXL: + pop iy, de + or a, a + sbc hl, hl + add hl, sp + push de ; ZDS II sret + ld bc, 8 ; sizeof(long double _Complex) + ldir + ; skip over the padding + inc hl + ld c, 8 + ldir + ex (sp), hl ; ZDS II sret + jp (iy) diff --git a/src/libc/conjf.src b/src/libc/conjf.src new file mode 100644 index 000000000..82056c53e --- /dev/null +++ b/src/libc/conjf.src @@ -0,0 +1,66 @@ + assume adl=1 + + section .text + + public _conjf, _conj + +; enable if fpneg is required +if 1 + +; float _Complex conjf(float _Complex) /* struct ABI */ +_conjf: +_conj: + pop iy, de + ld hl, 7 + add hl, sp + + ; negate the complex part + ld a, (hl) + or a, a + jr nz, .do_fpneg + ; test if value is +0.0f + push hl + dec hl + dec hl + dec hl + ld bc, (hl) + sbc hl, hl + sbc hl, bc + pop hl + jr z, .skip_fpneg +.do_fpneg: + xor a, $80 + ld (hl), a +.skip_fpneg: + + ld bc, 8 ; sizeof(float _Complex) + sbc hl, bc + inc hl ; hl = sp + 0 + push de ; ZDS II sret + ldir + ex de, hl + ex (sp), hl ; ZDS II sret + jp (iy) + +else + +; float _Complex conjf(float _Complex) /* struct ABI */ +_conjf: +_conj: + pop iy, de + ld hl, 7 + add hl, sp + ld a, (hl) + xor a, $80 ; negate imag-part + ld (hl), a + + ld bc, 8 ; sizeof(float _Complex) + sbc hl, bc + inc hl ; hl = sp + 0 + push de ; ZDS II sret + ldir + ex de, hl + ex (sp), hl ; ZDS II sret + jp (iy) + +end if diff --git a/src/libc/conjl.src b/src/libc/conjl.src new file mode 100644 index 000000000..3b9db2d3a --- /dev/null +++ b/src/libc/conjl.src @@ -0,0 +1,23 @@ + assume adl=1 + + section .text + + public _conjl + +; long double _Complex conjl(long double _Complex) /* struct ABI */ +_conjl: + pop iy, de + ld hl, 15 + add hl, sp + ld a, (hl) + xor a, $80 ; negate imag-part + ld (hl), a + + ld bc, 16 ; sizeof(long double _Complex) + sbc hl, bc + inc hl ; hl = sp + 0 + push de ; ZDS II sret + ldir + ex de, hl + ex (sp), hl ; ZDS II sret + jp (iy) diff --git a/src/libc/crealf.src b/src/libc/crealf.src new file mode 100644 index 000000000..0db75d3cc --- /dev/null +++ b/src/libc/crealf.src @@ -0,0 +1,12 @@ + assume adl=1 + + section .text + + public _crealf, _creal + +; float crealf(float _Complex) +_crealf: +_creal: + pop bc, hl, de + push de, hl, bc + ret diff --git a/src/libc/creall.src b/src/libc/creall.src new file mode 100644 index 000000000..16555cc10 --- /dev/null +++ b/src/libc/creall.src @@ -0,0 +1,11 @@ + assume adl=1 + + section .text + + public _creall + +; long double creall(long double _Complex) +_creall: + pop iy, hl, de, bc + push bc, de, hl + jp (iy) diff --git a/src/libc/header_test.c b/src/libc/header_test.c index 8b9b50a64..6ea62aabd 100644 --- a/src/libc/header_test.c +++ b/src/libc/header_test.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libc/include/complex.h b/src/libc/include/complex.h new file mode 100644 index 000000000..7ca66469b --- /dev/null +++ b/src/libc/include/complex.h @@ -0,0 +1,124 @@ +#ifndef _COMPLEX_H +#define _COMPLEX_H + +#ifndef __FAST_MATH__ +#warning "-ffast-math is required for complex multiplication and division to work properly at this time" +#endif + +#ifndef __cplusplus +#define complex _Complex +#endif + +#ifdef _Imaginary +#define imaginary _Imaginary +#endif + +#ifndef I +# ifdef _Imaginary_I +# define I _Imaginary_I +# else +# define I _Complex_I +# endif +#endif + +double _Complex CMPLX(double x, double y); +float _Complex CMPLXF(float x, float y); +long double _Complex CMPLXL(long double x, long double y); + +#ifdef _Imaginary_I + +#define CMPLX(x, y) ((double _Complex)((double)(x) + _Imaginary_I * (double)(y))) +#define CMPLXF(x, y) ((float _Complex)((float)(x) + _Imaginary_I * (float)(y))) +#define CMPLXL(x, y) ((long double _Complex)((long double)(x) + _Imaginary_I * (long double)(y))) + +#endif /* _Imaginary_I */ + +double creal(double _Complex); +float crealf(float _Complex); +long double creall(long double _Complex); + +double cimag(double _Complex); +float cimagf(float _Complex); +long double cimagl(long double _Complex); + +double cabs(double _Complex); +float cabsf(float _Complex); +long double cabsl(long double _Complex); + +double carg(double _Complex); +float cargf(float _Complex); +long double cargl(long double _Complex); + +double _Complex conj(double _Complex); +float _Complex conjf(float _Complex); +long double _Complex conjl(long double _Complex); + +double _Complex cproj(double _Complex); +float _Complex cprojf(float _Complex); +long double _Complex cprojl(long double _Complex); + +double _Complex csqrt(double _Complex); +float _Complex csqrtf(float _Complex); +long double _Complex csqrtl(long double _Complex); + +double _Complex cexp(double _Complex); +float _Complex cexpf(float _Complex); +long double _Complex cexpl(long double _Complex); + +double _Complex clog(double _Complex); +float _Complex clogf(float _Complex); +long double _Complex clogl(long double _Complex); + +double _Complex cpow(double _Complex, double _Complex); +float _Complex cpowf(float _Complex, float _Complex); +long double _Complex cpowl(long double _Complex, long double _Complex); + +double _Complex csin(double _Complex); +float _Complex csinf(float _Complex); +long double _Complex csinl(long double _Complex); + +double _Complex ccos(double _Complex); +float _Complex ccosf(float _Complex); +long double _Complex ccosl(long double _Complex); + +double _Complex ctan(double _Complex); +float _Complex ctanf(float _Complex); +long double _Complex ctanl(long double _Complex); + +double _Complex casin(double _Complex); +float _Complex casinf(float _Complex); +long double _Complex casinl(long double _Complex); + +double _Complex cacos(double _Complex); +float _Complex cacosf(float _Complex); +long double _Complex cacosl(long double _Complex); + +double _Complex catan(double _Complex); +float _Complex catanf(float _Complex); +long double _Complex catanl(long double _Complex); + +double _Complex csinh(double _Complex); +float _Complex csinhf(float _Complex); +long double _Complex csinhl(long double _Complex); + +double _Complex ccosh(double _Complex); +float _Complex ccoshf(float _Complex); +long double _Complex ccoshl(long double _Complex); + +double _Complex ctanh(double _Complex); +float _Complex ctanhf(float _Complex); +long double _Complex ctanhl(long double _Complex); + +double _Complex casinh(double _Complex); +float _Complex casinhf(float _Complex); +long double _Complex casinhl(long double _Complex); + +double _Complex cacosh(double _Complex); +float _Complex cacoshf(float _Complex); +long double _Complex cacoshl(long double _Complex); + +double _Complex catanh(double _Complex); +float _Complex catanhf(float _Complex); +long double _Complex catanhl(long double _Complex); + +#endif /* _COMPLEX_H */ diff --git a/test/floating_point/complex/autotest.json b/test/floating_point/complex/autotest.json new file mode 100644 index 000000000..235f78521 --- /dev/null +++ b/test/floating_point/complex/autotest.json @@ -0,0 +1,43 @@ +{ + "transfer_files": [ + "bin/DEMO.8xp" + ], + "target": { + "name": "DEMO", + "isASM": true + }, + "sequence": [ + "action|launch", + "delay|1000", + "hashWait|1", + "key|enter", + "delay|200", + "hashWait|2" + ], + "hashes": { + "1": { + "description": "All tests passed or GDB1 error", + "timeout": 5000, + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "38E2AD5A", + "2C812DC2" + ] + }, + "2": { + "description": "Exit or GDB1 error", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "FFAF89BA", + "101734A5", + "9DA19F44", + "A32840C8", + "349F4775", + "271A9FBF", + "82FD0B1E" + ] + } + } +} diff --git a/test/floating_point/complex/makefile b/test/floating_point/complex/makefile new file mode 100644 index 000000000..458e3baa2 --- /dev/null +++ b/test/floating_point/complex/makefile @@ -0,0 +1,17 @@ +# ---------------------------- +# Makefile Options +# ---------------------------- + +NAME = DEMO +ICON = icon.png +DESCRIPTION = "CE C Toolchain Demo" +COMPRESSED = NO + +CFLAGS = -Wall -Wextra -Wshadow -Wimplicit-float-conversion -Wimplicit-int-float-conversion -std=c17 -Ofast +CXXFLAGS = -Wall -Wextra -Wshadow -Wimplicit-float-conversion -Wimplicit-int-float-conversion -std=c++20 -Ofast + +PREFER_OS_LIBC = NO + +# ---------------------------- + +include $(shell cedev-config --makefile) diff --git a/test/floating_point/complex/src/complex_alias.asm b/test/floating_point/complex/src/complex_alias.asm new file mode 100644 index 000000000..633ff6700 --- /dev/null +++ b/test/floating_point/complex/src/complex_alias.asm @@ -0,0 +1,29 @@ + assume adl=1 + + section .text + + public _T_CMPLXF, _T_CMPLX, _T_CMPLXL + public _T_creal, _T_crealf, _T_creall + public _T_cimag, _T_cimagf, _T_cimagl + public _T_conj, _T_conjf, _T_conjl + +_T_CMPLXF := _CMPLXF +_T_CMPLX := _CMPLX +_T_CMPLXL := _CMPLXL + +_T_creal := _creal +_T_crealf := _crealf +_T_creall := _creall + +_T_cimag := _cimag +_T_cimagf := _cimagf +_T_cimagl := _cimagl + +_T_conj := _conj +_T_conjf := _conjf +_T_conjl := _conjl + + extern _CMPLXF, _CMPLX, _CMPLXL + extern _creal, _crealf, _creall + extern _cimag, _cimagf, _cimagl + extern _conj, _conjf, _conjl diff --git a/test/floating_point/complex/src/main.c b/test/floating_point/complex/src/main.c new file mode 100644 index 000000000..55ae55543 --- /dev/null +++ b/test/floating_point/complex/src/main.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef union CF32_pun { + float complex c; + float f[2]; +} CF32_pun; + +static_assert(sizeof(CF32_pun) == sizeof(float) * 2, "sizeof(float _Complex) has changed"); + +typedef union CFD2_pun { + double complex c; + double f[2]; +} CD32_pun; + +static_assert(sizeof(CD32_pun) == sizeof(double) * 2, "sizeof(double _Complex) has changed"); + + +typedef union CF64_pun { + long double complex c; + long double f[2]; +} CF64_pun; + +static_assert(sizeof(CF64_pun) == sizeof(long double) * 2, "sizeof(long double _Complex) has changed"); + +#define CF32_RE (1.23f) +#define CF32_IM (-4.56f) + +#define CD32_RE (1.23) +#define CD32_IM (-4.56) + +#define CF64_RE (1.23L) +#define CF64_IM (-4.56L) + +double _Complex T_CMPLX(double x, double y); +float _Complex T_CMPLXF(float x, float y); +long double _Complex T_CMPLXL(long double x, long double y); + +double T_creal(double _Complex); +float T_crealf(float _Complex); +long double T_creall(long double _Complex); + +double T_cimag(double _Complex); +float T_cimagf(float _Complex); +long double T_cimagl(long double _Complex); + +double _Complex T_conj(double _Complex); +float _Complex T_conjf(float _Complex); +long double _Complex T_conjl(long double _Complex); + +static size_t run_test(void) { + /* test float _Complex without any Clang chicanery */ + { + CF32_pun c32; + c32.c = T_CMPLXF(CF32_RE, CF32_IM); + if (c32.f[0] != CF32_RE) { return __LINE__; } + if (c32.f[1] != CF32_IM) { return __LINE__; } + if (T_crealf(c32.c) != CF32_RE) { return __LINE__; } + if (T_cimagf(c32.c) != CF32_IM) { return __LINE__; } + c32.c = conjf(c32.c); + if (c32.f[0] != CF32_RE) { return __LINE__; } + if (c32.f[1] != -CF32_IM) { return __LINE__; } + if (T_crealf(c32.c) != CF32_RE) { return __LINE__; } + if (T_cimagf(c32.c) != -CF32_IM) { return __LINE__; } + c32.c = T_conjf(T_CMPLXF(T_cimagf(c32.c), T_crealf(c32.c))); + if (T_crealf(c32.c) != -CF32_IM) { return __LINE__; } + if (T_cimagf(c32.c) != -CF32_RE) { return __LINE__; } + } + + /* test double _Complex without any Clang chicanery */ + { + CD32_pun c32; + c32.c = T_CMPLX(CD32_RE, CD32_IM); + if (c32.f[0] != CD32_RE) { return __LINE__; } + if (c32.f[1] != CD32_IM) { return __LINE__; } + if (T_creal(c32.c) != CD32_RE) { return __LINE__; } + if (T_cimag(c32.c) != CD32_IM) { return __LINE__; } + c32.c = conj(c32.c); + if (c32.f[0] != CD32_RE) { return __LINE__; } + if (c32.f[1] != -CD32_IM) { return __LINE__; } + if (T_creal(c32.c) != CD32_RE) { return __LINE__; } + if (T_cimag(c32.c) != -CD32_IM) { return __LINE__; } + c32.c = T_conj(T_CMPLX(T_cimag(c32.c), T_creal(c32.c))); + if (T_creal(c32.c) != -CD32_IM) { return __LINE__; } + if (T_cimag(c32.c) != -CD32_RE) { return __LINE__; } + } + + /* test long double _Complex without any Clang chicanery */ + { + CF64_pun c64; + c64.c = T_CMPLXL(CF64_RE, CF64_IM); + if (c64.f[0] != CF64_RE) { return __LINE__; } + if (c64.f[1] != CF64_IM) { return __LINE__; } + if (T_creall(c64.c) != CF64_RE) { return __LINE__; } + if (T_cimagl(c64.c) != CF64_IM) { return __LINE__; } + c64.c = T_conjl(c64.c); + if (c64.f[0] != CF64_RE) { return __LINE__; } + if (c64.f[1] != -CF64_IM) { return __LINE__; } + if (T_creall(c64.c) != CF64_RE) { return __LINE__; } + if (T_cimagl(c64.c) != -CF64_IM) { return __LINE__; } + c64.c = T_conjl(T_CMPLXL(T_cimagl(c64.c), T_creall(c64.c))); + if (T_creall(c64.c) != -CF64_IM) { return __LINE__; } + if (T_cimagl(c64.c) != -CF64_RE) { return __LINE__; } + } + + /* special zero test for TiOS floats (-0.0f != +0.0f) */ + { + CF32_pun c32; + c32.c = T_CMPLXF(0.0f, 0.0f); + if (c32.f[0] != 0.0f) { return __LINE__; } + if (c32.f[1] != 0.0f) { return __LINE__; } + if (T_crealf(c32.c) != 0.0f) { return __LINE__; } + if (T_cimagf(c32.c) != 0.0f) { return __LINE__; } + c32.c = conjf(c32.c); /* ensure that fneg is skipped for +0.0f */ + if (c32.f[0] != 0.0f) { return __LINE__; } + if (c32.f[1] != 0.0f) { return __LINE__; } /* fails if c32.f[1] == -0.0f */ + if (T_crealf(c32.c) != 0.0f) { return __LINE__; } + if (T_cimagf(c32.c) != 0.0f) { return __LINE__; } + c32.c = T_conjf(T_CMPLXF(T_cimagf(c32.c), T_crealf(c32.c))); + if (T_crealf(c32.c) != 0.0f) { return __LINE__; } + if (T_cimagf(c32.c) != 0.0f) { return __LINE__; } + } + + /* test if Clang handles float _Complex correctly */ + { + CF32_pun c32; + c32.c = CMPLXF(CF32_RE, CF32_IM); + if (c32.f[0] != CF32_RE) { return __LINE__; } + if (c32.f[1] != CF32_IM) { return __LINE__; } + if (crealf(c32.c) != CF32_RE) { return __LINE__; } + if (cimagf(c32.c) != CF32_IM) { return __LINE__; } + c32.c = conjf(c32.c); + if (c32.f[0] != CF32_RE) { return __LINE__; } + if (c32.f[1] != -CF32_IM) { return __LINE__; } + if (crealf(c32.c) != CF32_RE) { return __LINE__; } + if (cimagf(c32.c) != -CF32_IM) { return __LINE__; } + c32.c = conjf(CMPLXF(cimagf(c32.c), crealf(c32.c))); + if (crealf(c32.c) != -CF32_IM) { return __LINE__; } + if (cimagf(c32.c) != -CF32_RE) { return __LINE__; } + } + + /* test if Clang handles double _Complex correctly */ + { + CD32_pun c32; + c32.c = CMPLX(CD32_RE, CD32_IM); + if (c32.f[0] != CD32_RE) { return __LINE__; } + if (c32.f[1] != CD32_IM) { return __LINE__; } + if (creal(c32.c) != CD32_RE) { return __LINE__; } + if (cimag(c32.c) != CD32_IM) { return __LINE__; } + c32.c = conj(c32.c); + if (c32.f[0] != CD32_RE) { return __LINE__; } + if (c32.f[1] != -CD32_IM) { return __LINE__; } + if (creal(c32.c) != CD32_RE) { return __LINE__; } + if (cimag(c32.c) != -CD32_IM) { return __LINE__; } + c32.c = conj(CMPLX(cimag(c32.c), creal(c32.c))); + if (creal(c32.c) != -CD32_IM) { return __LINE__; } + if (cimag(c32.c) != -CD32_RE) { return __LINE__; } + } + + /* test if Clang handles long double _Complex correctly */ + { + CF64_pun c64; + c64.c = CMPLXL(CF64_RE, CF64_IM); + if (c64.f[0] != CF64_RE) { return __LINE__; } + if (c64.f[1] != CF64_IM) { return __LINE__; } + if (creall(c64.c) != CF64_RE) { return __LINE__; } + if (cimagl(c64.c) != CF64_IM) { return __LINE__; } + c64.c = conjl(c64.c); + if (c64.f[0] != CF64_RE) { return __LINE__; } + if (c64.f[1] != -CF64_IM) { return __LINE__; } + if (creall(c64.c) != CF64_RE) { return __LINE__; } + if (cimagl(c64.c) != -CF64_IM) { return __LINE__; } + c64.c = conjl(CMPLXL(cimagl(c64.c), creall(c64.c))); + if (creall(c64.c) != -CF64_IM) { return __LINE__; } + if (cimagl(c64.c) != -CF64_RE) { return __LINE__; } + } + + /* passed all */ + return SIZE_MAX; +} + +int main(void) { + os_ClrHome(); + size_t fail_index = run_test(); + if (fail_index == SIZE_MAX) { + printf("All tests passed"); + } else { + printf("Failed test: L%zu\n", fail_index); + } + + while (!os_GetCSC()); + + return 0; +}