long long is not supported

Bug reports (if you don't/won't have a Github account)
Post Reply
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

long long is not supported

Post by joaopa »

Eigenmath needs long long
This simple sample shows the problem (no problem with gcc):

#include <stdio.h>
int main(void)
{
long long a;

a= 10;
printf("%lld\n",a);
return 0;
}

zcc +zx -lndos toto.c
cp /home/joaopa/z88dk/lib/config//../..//lib/spec_crt0.opt /tmp/tmpXX7mfT1f.opt
cp /tmp/tmpXX7mfT1f.opt /tmp/tmpXX7mfT1f.asm
zcpp -I. -DZ80 -DSPECTRUM -D__SPECTRUM__ -D__SPECTRUM -DSCCZ80 -DSMALL_C -I/home/david/z88dk/lib/config//../..//include toto.c /tmp/tmpXXtHy3Df.i
sccz80 -asm=z80asm /tmp/tmpXXtHy3Df.i
sccz80:"toto.c" L:4 Warning:#17:Expected ';'
sccz80:"toto.c" L:4 Error:#42:Unknown symbol: a
sccz80:"toto.c" L:6 Error:#33:Must be lvalue
Compilation aborted
Last edited by joaopa on Sun Feb 21, 2016 4:47 am, edited 1 time in total.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

longlong is not supported in sccz80. It's a 64-bit integer. Can you get away with 32-bit?

If you really need 64-bit integers, you will have to use sdcc. 64-bit integers are rarely supported on 8-bit machines and as far as I know, only sdcc has some support for them among z80 compilers. If you do need it, we'll have to update the c lib with 64-bit math functions and add %lld to printf and scanf.
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

Post by joaopa »

After diving in the problem, the conclusion is that we need 64 bit-integers for Eigenmath. Otherwise, even a simple second degree can not be solved...
And all the computatin is limited to 2^32.

Can you port the 4-bit library?
Thanks in advance
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

joaopa wrote:After diving in the problem, the conclusion is that we need 64 bit-integers for Eigenmath. Otherwise, even a simple second degree can not be solved...
And all the computatin is limited to 2^32.
If you can limit computation to 32 bits, that would help in speed and program size.

I will look at 64-bit ints this weekend.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

It shouldn't take more than a day or two to add the first bit of longlong support to the library. The code that sdcc produces is very bloaty. 25 bytes to clear a longlong to zero. 72 bytes to add two longlongs together. Everything is inlined so I think once the longlong support is in, we should look at changing the compiler to produce subroutine calls to the library to carry out these operations. The library code is faster than the code sdcc is inlining and it would be a lot smaller. The same size issue arises with sdcc and longs but the code sdcc inlines for longs is usually faster after it has been processed by the aggressive peephole set.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

The first bit of longlong support will be present in the May 7 build.

Only sdcc supports longlong and for the moment on the new c library has the functionality.

You can add, subtract, multiply, divide and shift 64-bit integers. The following functions have been added: ffsll(long long i) [string.h], _lldiv_(), _lldivu_(), llabs(), lltoa() and ulltoa() [stdlib.h].

What's missing currently: strtoll(), strtoull(), float<->longlong conversion, type definitions in headers (eg uint64_t, etc), printf & scanf converters for longlong.

An example program compiled for the zx target:

Code: Select all

// zcc +zx -vn -SO3 -startup=4 -clib=sdcc_ix --reserve-regs-iy --max-allocs-per-node200000 lg.c -o lg --list

#include <stdio.h>
#include <input.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

struct long_s
{
   unsigned long ls32;
   unsigned long ms32;
};

union u64_s
{
   long long a;
   struct long_s b;
};

union u64_s x, y, z;
double_t d;

char buffer_0[100];
char buffer_1[100];
char buffer_2[100];

lldiv_t ld;

void main(void)
{
   in_wait_nokey();

   while(1)
   {
      fflush(stdin);
     
      printf("\n\n[#1] MS32 <space> LS32 in hex\n");
      scanf("%lx%lx", &x.b.ms32, &x.b.ls32);
   
      printf("\n[#2] MS32 <space> LS32 in hex\n");
      scanf("%lx%lx", &y.b.ms32, &y.b.ls32);
 
      lltoa(x.a, buffer_0, 10);
      lltoa(y.a, buffer_1, 10);
 
      z.a = x.a + y.a;
      lltoa(z.a, buffer_2, 10);
      printf("\n%s + %s = %s\n", buffer_0, buffer_1, buffer_2);

      z.a = x.a - y.a;
      lltoa(z.a, buffer_2, 10);
      printf("%s - %s = %s\n", buffer_0, buffer_1, buffer_2);

      z.a = x.a * y.a;
      lltoa(z.a, buffer_2, 10);
      printf("%s * %s = %s\n", buffer_0, buffer_1, buffer_2);

      z.a = x.a / y.a;
      lltoa(z.a, buffer_2, 10);
      printf("%s / %s = %s\n", buffer_0, buffer_1, buffer_2);

      z.a = x.a % y.a;
      lltoa(z.a, buffer_2, 10);
      printf("%s %% %s = %s\n", buffer_0, buffer_1, buffer_2);

      z.a = x.a >> y.a;
      lltoa(z.a, buffer_2, 10);
      printf("%s >> %s = %s\n", buffer_0, buffer_1, buffer_2);

      z.a = x.a << y.a;
      lltoa(z.a, buffer_2, 10);
      printf("%s << %s = %s\n", buffer_0, buffer_1, buffer_2);

      printf("ffsll(%s) = %u\n", buffer_0, ffsll(x.a));

      z.a = llabs(x.a);
      in_pause(200);
      lltoa(z.a, buffer_2, 10);
      printf("llabs(%s) = %s\n", buffer_0, buffer_2);
      
      _lldiv_(&ld, x.a, y.a);
      lltoa(ld.quot, buffer_0, 10);
      lltoa(ld.rem, buffer_1, 10);
      printf("lldiv: quotient = %s, remainder = %s\n\n", buffer_0, buffer_1);
   }
}
You'll note that lltoa() is used to generate a base 10 string from the longlong since there is no printf %lld yet. Because there is no scanf %lld yet, the 64-bit numbers are scanned in two 32-bit halves in hexadecimal.

I did come across a bug in sdcc which will hopefully be fixed soon:

https://sourceforge.net/p/sdcc/bugs/2501/

"in_pause(200);" is inserted into the code to eliminate the bug in this program.


If you're on windows, after the nightly build is installed, be sure to update your zsdcc executable in z88dk/bin from http://z88dk.cvs.sourceforge.net/viewvc ... _patch.zip . Everything else in the nightly will be up to date but the binary is less frequently updated. When sdcc fixes the aforementioned bug, I'll be updating that zip with a new build.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

64-bit long longs are now fully supported in the new c lib as of the May 11 night build.

http://www.z88dk.org/forum/viewtopic.ph ... 796#p13796

The 64-bit scan converters for printf and scanf are disabled by default so in order to use those you must reconfigure the library and rebuild. It's simple to do this so if you're not sure how, just ask.

example compile for zx:

zcc +zx -vn -SO3 -clib=sdcc_ix --reserve-regs-iy --max-allocs-per-node200000 test.c -o test --list

translate to assembly language only (useful to find errors without having to build a binary):

zcc +zx -vn -a -SO3 -clib=sdcc_ix --reserve-regs-iy --max-allocs-per-node200000 test.c
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

Post by joaopa »

I shall wait for sdcc being fixed before testing the 64-bit long long support. Eigenmath is already so complex without compiler bugs, that I do not want to mess up with sdcc bugs. Let's take care of zcc bugs only ;)
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

It is up to you but I think it's worthwhile to use now.

sdcc never generates incorrect code - what is happening is it bails out when there is a problem. And when that problem occurs, it's easy to spot where to insert a dummy "intrinsic_stub();" between the two offending statements to allow the compile to complete. The intrinsic_stub() function takes up no space in the output binary.

sdcc is looking to do a new release very soon so I'm not sure how long it will take to see a fix.
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

Post by joaopa »

I wanted to give a try to the 64-bit long support. So I downloaded the latest nighty build (this one, all is fine). When I compiled your example above in this thread, the compilation fails with
zcc +zx -vn -SO3 -startup=4 -clib=sdcc_ix --reserve-regs-iy --max-allocs-per-node200000 test.c -o test.exe --list
sh: 1: zsdcpp: not found

What must I do to fix this problem?
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

joaopa wrote:I wanted to give a try to the 64-bit long support. So I downloaded the latest nighty build (this one, all is fine). When I compiled your example above in this thread, the compilation fails with
zcc +zx -vn -SO3 -startup=4 -clib=sdcc_ix --reserve-regs-iy --max-allocs-per-node200000 test.c -o test.exe --list
sh: 1: zsdcpp: not found

What must I do to fix this problem?
The windows and mac packages include the sdcc binaries but for other platforms, the sdcc binaries have to be built separately.

Instructions are here:
http://www.z88dk.org/wiki/doku.php?id=temp:front#sdcc1

For programs containing 64-bit integers, using the --opt-code-size flag will significantly reduce code size, the compiler generated portion by about 50% in fact.

zcc +zx -vn -SO3 -startup=4 -clib=sdcc_ix --reserve-regs-iy --max-allocs-per-node200000 test.c -o test --list --opt-code-size

The output filename "test" will be the root name used for all the output binaries generated by a compile. The output binary in this case will be "test_CODE.bin" which you can run by entering "CLEAR 32768", load the binary to 32768, then "RAND USR 32768".

The final test program I was using was this, which mixes floats in along with some long long printf and scanf conversions:

Code: Select all

// zcc +zx -vn -SO3 -startup=4 -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test --list --opt-code-size

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <intrinsic.h>
#include <input.h>

double_t d;

char buffer_0[100];
char buffer_1[100];
char buffer_2[100];

lldiv_t ld;

long long x, z;

void main(void)
{
   long long y;

   intrinsic_di();
   in_wait_nokey();

   while(1)
   {
      fflush(stdin);
     
      printf("\n[#1] ");
      errno = 0;
      scanf("%lli", &x);
      if (errno) perror("scanf");
      sprintf(buffer_0, "%lld", x);
       
      fflush(stdin);
 
      printf("[#2] ");
      scanf("%s", buffer_1);
      errno = 0;
      y = strtoll(buffer_1, NULL, 0);
      if (errno) perror("strtoll");
      lltoa(y, buffer_1, 10);
 
      z = x + y;
      printf("\n%lld + %lld = %lld\n", x, y, z);

      z = x - y;
      lltoa(z, buffer_2, 10);
      printf("%s - %s = %s\n", buffer_0, buffer_1, buffer_2);

      z = x * y;
      lltoa(z, buffer_2, 10);
      printf("%s * %s = %s\n", buffer_0, buffer_1, buffer_2);

      z = x / y;
      lltoa(z, buffer_2, 10);
      printf("%s / %s = %s\n", buffer_0, buffer_1, buffer_2);

      z = x % y;
      lltoa(z, buffer_2, 10);
      printf("%s %% %s = %s\n", buffer_0, buffer_1, buffer_2);

      z = x >> y;
      lltoa(z, buffer_2, 10);
      printf("%s >> %s = %lld\n",buffer_0, buffer_1, z);

      z = x << y;
      lltoa(z, buffer_2, 10);
      printf("%s << %s = %s\n", buffer_0, buffer_1, buffer_2);

      printf("ffsll(%s) = %u\n", buffer_0, ffsll(x));

      z = llabs(x);
      lltoa(z, buffer_2, 10);
      printf("llabs(%s) = %s\n", buffer_0, buffer_2);

      d = x;
      printf("float(%lld) = %g\n", x, d);
      
      z = d;
      lltoa(z, buffer_0, 10);
      printf("longlong(%g) = %s\n", d, buffer_0);
      
      _lldiv_(&ld, x, y);
      lltoa(ld.quot, buffer_0, 10);
      lltoa(ld.rem, buffer_1, 10);
      printf("lldiv: quotient = %s, remainder = %s\n", buffer_0, buffer_1);
   }
}
You'll note -clib=sdcc_iy instead of -clib=sdcc_ix in the compile line. -clib=sdcc_iy is always preferred since it will lead to smaller code. The difference is in the -clib=sdcc_iy case, the library is allowed to use the IY register, which is a problem for the zx target if the rom interrupt routine is active. In this program, interrupts have been disabled so that IY can be used by the library.

The default zx library is built with float and long long printf / scanf converters disabled so before this program can be compiled, the zx library has to have those converters enabled and the library re-built.

You do this by editing the zx's clib configuration file: z88dk/libsrc/_DEVELOPMENT/target/zx/clib_cfg.asm
In that file there are a few binary words that define which % converters should be enabled for printf and scanf: __CLIB_OPT_PRINTF, __CLIB_OPT_PRINTF_2, __CLIB_OPT_SCANF, __CLIB_OPT_SCANF_2 . You can reduce code size by selecting which converters will be active but for this program, it's alright to activate them all by assigning $ffffffff to these constants. Comment out the old values and add a new line so that you can restore the defaults later.

After that file is saved, re-build the zx library by going to the z88dk/libsrc/_DEVELOPMENT directory and running "Winmake zx" (windows) or "make TARGET=zx" (other). It will take 5-10 mins to build the library.

Then you will be able to compile the program above.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

For that last program I forgot to link the floating point library in the compile line:

zcc +zx -vn -SO3 -startup=4 -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test -lm --list --opt-code-size

Once you are done playing with that, you may want to restore the clib configuration to its default (undo the changes to __CLIB_OPT_PRINTF, etc, and rebuild the libary). Otherwise eg, with printf's float converters enabled, compiles using printf will always need the float library linked and some float code will always make it into the final binary.
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

Post by joaopa »

I compiled sdcc with the patch. But since the build fails I can not say if everything was done fine. With the test programm, I obtain

zsdcc -v

ZSDCC is a modification of SDCC for Z88DK

sdcc website:
https://sourceforge.net/projects/sdcc/

patch details:
http://z88dk.cvs.sourceforge.net/viewvc ... _patch.zip

modification date:
Jun 16 2016

sdcc -v:
3.6.0 #9615 (Linux)
mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8

published under GNU General Public License (GPL)
joaopa@Carlitz:~$ zsdcpp --version
zsdcpp (SDCC) 4.6.3 (GNU cpp adapted for SDCC)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

joaopa@Carlitz:~$ zcc +zx -vn -SO3 -startup=4 -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test -lm --list --opt-code-size
Error at file '/tmp/tmpXXqr0evT.opt' line 835: symbol '____sdcc_ll_copy_src_de_dst_hlsp' not defined
Error at file '/tmp/tmpXXqr0evT.opt' line 841: symbol '____sdcc_ll_push_hlix' not defined
Error at file '/tmp/tmpXXqr0evT.opt' line 842: symbol '_lltoa_callee' not defined
Error at file '/tmp/tmpXXqr0evT.opt' line 845: symbol '____sdcc_ll_copy_src_de_dst_hlsp' not defined

and tons of such messages
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

Post by joaopa »

However, when I try to compile the sudoku example, everything works. Problem with the 64-bit library?
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

joaopa wrote:However, when I try to compile the sudoku example, everything works. Problem with the 64-bit library?
I think the problem is the source tarball is including the new c lib's z80 libraries from cvs, which are not updated daily and in fact probably haven't been updated in months. So you probably have outdated z80 libraries which won't contain the 64-bit code. This is an oversight in the build instructions so I will update that if this turns out to be the case.

Try to rebuild the new c lib's z80 libraries yourself****.

cd z88dk/libsrc/_DEVELOPMENT
make (windows is "Winmake all")

This will take 5-10 minutes to finish. After that's done the libraries in z88dk/libsrc/_DEVELOPMENT/lib should all be marked the current date.

**** Before you do that you may want to edit the zx spectrum's clib_cfg.asm file as mentioned in the post above to enable the long long and float converters for printf/scanf which are required by the test program I gave.
joaopa
Member
Posts: 46
Joined: Sat Mar 15, 2014 5:42 pm

Post by joaopa »

Thanks, that works for zx spectrum.
But my target is vg5000. What must I modify to printf long long? There is no file clib_cfg.asm in _Developpment for VG5000
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

joaopa wrote:Thanks, that works for zx spectrum.
But my target is vg5000. What must I modify to printf long long? There is no file clib_cfg.asm in _Developpment for VG5000
Long longs are only available through the new c library and the new c library only has three supported targets currently: cpm, zx, and embedded (which can be used for any z80 but it's necessarily generic).

So what needs to be done is to add a vg5000 target to the new c library and write simple device drivers attached to printf and scanf. There is a bit of a learning curve associated with doing this but if you enjoy that sort of challenge you can make a vg5000 target yourself and then submit it to us. Instructions for making a new target for the new c lib are here:

http://www.z88dk.org/wiki/doku.php?id=t ... g_a_target

Otherwise I can have a look and get one started.
User avatar
dom
Well known member
Posts: 2072
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I've added the long long crt code to classic now so it should work there. No printf handling yet though.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Added line to build.sh to build the new c lib z80 libraries for June 17 build.
Post Reply