The MASM Forum

Specialised Projects => Compiler Based Assembler => Topic started by: jj2007 on July 21, 2017, 06:42:35 PM

Title: GCC libquadmath
Post by: jj2007 on July 21, 2017, 06:42:35 PM
Anybody able to compile that without errors?

Code: [Select]
#include <conio.h>
#include <C:\MinGW\lib\gcc\mingw32\4.8.1\include\quadmath.h>
// OPT_Linker C:\MinGW\lib\gcc\mingw32\4.8.1\libquadmath.a

int main ()
{
  __float128 r;

  r = strtoflt128("1.2345678", NULL); // undefined reference to `strtoflt128'
  r = 123.456; // OK

  _getch();
}

See How to output 128 bits to the screen? (http://masm32.com/board/index.php?topic=6407.0)
Title: Re: GCC libquadmath
Post by: GoneFishing on July 21, 2017, 08:55:04 PM
Hi Johen,

I was able to compile this on Ubuntu 14.04 :

Code: [Select]
#include <stdio.h>
#include <quadmath.h>
// gcc ./quadmath.c  -o quadmath -lquadmath

int main ()
{
  __float128 r;

  r = strtoflt128("1.2345678", NULL); // undefined reference to `strtoflt128'
  r = 123.456; // OK

  getchar();
}
Title: Re: GCC libquadmath
Post by: jj2007 on July 21, 2017, 09:24:55 PM
Thanks :icon14:
No luck on Windows, though.
Title: Re: GCC libquadmath
Post by: TWell on July 21, 2017, 10:46:27 PM
Code: [Select]
#include <stdio.h>
#include <quadmath.h>
// gcc ./quadmath.c  -o quadmath -lquadmath
// gcc quadmath.c -o quadmath -Wl,-Bstatic -lquadmath

int main ()
{
  __float128 r;
  char buf[128];

  r = strtoflt128("1.2345678", NULL); // undefined reference to `strtoflt128'
  r = 123.456; // OK
//  quadmath_snprintf (buf, sizeof buf, "%Qa", r);
  quadmath_snprintf (buf, sizeof buf, "%Qf\n", r);
  printf(buf);
  getchar();
  return 0;
}
Code: [Select]
123.456000
Title: Re: GCC libquadmath
Post by: jj2007 on July 21, 2017, 10:58:51 PM
Thanks, Tim, and congrats :icon_mrgreen:

So are these your linker options?

gcc quadmath.c -o quadmath -Wl,-Bstatic -lquadmath

My results:
Code: [Select]
C:\TDM-GCC-32\bin\gcc.exe -Wl,-Bstatic -lquadmath -o tmp.exe "Tmp.cpp"
Code: [Select]
C:\Users\Jochen\AppData\Local\Temp\cceeec7X.o:Tmp.cpp:(.text+0x29): undefined reference to `strtoflt128'
C:\Users\Jochen\AppData\Local\Temp\cceeec7X.o:Tmp.cpp:(.text+0xc9): undefined reference to `quadmath_snprintf'
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/4.9.2/../../../../mingw32/bin/ld.exe: C:\Users\Jochen\AppData\Local\Temp\cceeec7X.o: bad reloc address 0x7 in section `.text$getchar[_getchar]'
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/4.9.2/../../../../mingw32/bin/ld.exe: final link failed: Invalid operation
collect2.exe: error: ld returned 1 exit status

If I remove the comma (-Wl -Bstatic), it tells me unrecognized command line option '-Wl', so I assume the comma has a meaning.

My installation is less than three years old. Most of the time C/C++ code compiles and runs fine, but this one gives me the creeps :(

C:\MinGW\mingw32\lib\gcc\mingw32\4.8.1\libquadmath.a 570236 bytes, 5.10.2013
C:\MinGW\mingw32\lib\gcc\mingw32\4.8.1\include\quadmath.h 9030 bytes, 5.10.2013

P.S.: I love passing hours and hours on the Internet watching how others despair :t

But in the end, own trial and error may advance humanity more quickly :biggrin:
Code: [Select]
#include <stdio.h>
#include <quadmath.h>
// gcc ./quadmath.c  -o quadmath -lquadmath
// gcc quadmath.c -o quadmath
// OxPT_Linker -Wl,-Bstatic -lquadmath
// OxPT_Linker -Wl,-Bdynamic -lquadmath
// OxPT_Linker -Wl,-Bstatic "C:\MinGW\mingw32\lib\gcc\mingw32\4.8.1\libquadmath.a"
// OxPT_Linker -Wl,-Bdynamic C:\TDM-GCC-32\bin\libquadmath-0.dll
// OPT_Linker C:\TDM-GCC-32\bin\libquadmath-0.dll ; HEY, THIS ONE WORKS!!!!
int main ()
{
  __float128 r;
  char buf[128];
  for (int i=0;i<128;i++) buf[i]=0;
  // __asm("int $3");
  r = strtoflt128("1.2345678", NULL); // undefined reference to `strtoflt128'
  // __asm("nop");
  // r = 123.456; // OK
  quadmath_snprintf (buf, sizeof buf, "%Qa", r);
  quadmath_snprintf (buf, sizeof buf, "%Qf\n", r);
  printf("Buffer: [%s]", buf);
  getchar();
  return 0;
}

Output: Buffer: [0x1.3c0ca2a5b1d5d0818d3359c99ff2p+0]

Not yet the expected result, but since I've seen some similar results in desperate posts on the web (e.g. That code produced -3.8518598887744717061119558851698546e-34 error on my box (http://grumpyoldprogrammer.blogspot.it/2015/04/gcc-quad-precision-math-library-example.html)), it can only be a question of weeks until I find the magic trick :icon_mrgreen:
Title: Re: GCC libquadmath
Post by: qWord on July 22, 2017, 12:08:20 AM
The order of modules and libraries must match the dependency order:
Quote from: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
-l library
    [...]
    It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded.

Conclusion: put -lquadmath to the end.
Also note that gcc use the file extension to get the language and c++ is maybe not what you want in general.
Title: Re: GCC libquadmath
Post by: jj2007 on July 22, 2017, 12:28:00 AM
Miracles happen :greenclp:
Code: [Select]
#include <stdio.h> // HEY, THIS ONE WORKS!!!!
#include <quadmath.h> // OPT_Linker C:\TDM-GCC-32\bin\libquadmath-0.dll
int main ()
{
  char buf[128];
  __float128 r = strtoflt128("1234567890.123456789012345678901234567890", NULL);
  quadmath_snprintf (buf, sizeof buf, "%#*.40Qe", 30, r);
  printf("expected:\t[1.2345678901234567890123456789012345678901e+09]\n", buf);
  printf("result:  \t[%s]\n", buf);
  getchar();
  return 0;
}
// Output
// expected:       [1.2345678901234567890123456789012345678901e+09]
// result:         [1.2345678901234567890123456789012345331810e+09]

@qWord: Thanks, your suggestion to put -lquadmath as last option works, too :t
Title: Re: GCC libquadmath
Post by: jj2007 on July 29, 2017, 01:09:14 AM
Work in progress:

  PrintLine "Two numbers: ", CrLf$, Quad$(numSmall), " and ", CrLf$, Quad$(numBig)
  Inkey Quad$(QuadMath(fminq, numSmall, numBig)), " is the smaller one"


Code: [Select]
Two numbers:
1.2345678901234567890294135408477e+40 and
1.2345678901234567891474727029195e+40
1.2345678901234567890294135408477e+40 is the smaller one

The interface works, but there is a big problem: simple arithmetics like adding and multiplying numbers :(
Title: Re: GCC libquadmath
Post by: jack on July 30, 2017, 08:28:17 PM
I found two symbols that have add in it: ___quadmath_mpn_addmul_1 and ___quadmath_mpn_add_n
for subtract: ___quadmath_mpn_submul_1 and ___quadmath_mpn_sub_n
for divide: ___quadmath_mpn_divrem
for multiply: ___quadmath_mpn_mul_1, ___quadmath_mpn_impn_mul_n_basecase, ___quadmath_mpn_impn_mul_n and ___quadmath_mpn_mul
Title: Re: GCC libquadmath
Post by: jj2007 on July 30, 2017, 09:27:02 PM
Thanks, Jack :t

There are quite a number of them:
Code: [Select]
__quadmath_do_pad
__quadmath_fpioconst_pow10
__quadmath_isinf_nsq
__quadmath_kernel_cosq
__quadmath_kernel_sincosq
__quadmath_kernel_sinq
__quadmath_mpn_add_n
__quadmath_mpn_addmul_1
__quadmath_mpn_cmp
__quadmath_mpn_construct_float128
__quadmath_mpn_divrem
__quadmath_mpn_extract_flt128
__quadmath_mpn_impn_mul_n
__quadmath_mpn_impn_mul_n_basecase
__quadmath_mpn_lshift
__quadmath_mpn_mul
__quadmath_mpn_mul_1
__quadmath_mpn_rshift
__quadmath_mpn_sub_n
__quadmath_mpn_submul_1
__quadmath_printf_fp
__quadmath_printf_fphex
__quadmath_rem_pio2q
__quadmath_tens
__quadmath_tens_in_limb
__quadmath_x2y2m1q

Problem is that they are not documented. There is a doc on Low-level Functions (http://web.mit.edu/gnu/doc/html/gmp_6.html), but it concerns general GCC functions.

It would be great if we could decipher them, i.e. find out which paras they expect, and how they are passed. So far I have been successful with quite a number of the documented functions, and added conversion REAL10 <---> REAL16, printing etc:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals REAL16:quadPI
  Init quad
  PrintLine "real PI:", Tb$, "3.14159265358979323846264338327950"
  MovVal quadPI, "3.14159265358979323846264338327950"   ; string to REAL16
  PrintLine "quadPI=   ", Tb$, Quad$(quadPI)
  FpuPush quadPI                        ; REAL16 -> REAL10
  PrintLine "FpuPush=", Tb$, Str$(ST(0)v)
  fldpi                                 ; same with built-in FPU opcode
  Inkey "fldpi  =", Tb$, Str$(ST(0)v)
EndOfCode


Output:
Code: [Select]
real PI:        3.14159265358979323846264338327950
quadPI=         3.14159265358979323846264338327950e+00
FpuPush=        3.141592653589793238
fldpi  =        3.141592653589793238

When the package is ready, I'll update the MovVal (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1203) and FpuPush (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1189) documentation asap.
Title: Re: GCC libquadmath
Post by: qWord on July 30, 2017, 10:01:50 PM
The __float128-type is build-in thus the common operators can be used. Write your own functions to make the basic arithmetic available as lib.
Title: Re: GCC libquadmath
Post by: jack on July 30, 2017, 10:17:02 PM
jj2007, may I suggest you try the C explorer at https://godbolt.org
choose gcc as the compiler with compiler option -O3 and paste the following C code
Code: [Select]
#include <quadmath.h>
#include <stdlib.h>
#include <stdio.h>

int main ()
{
  __float128 a, b, r;
  char buf[128];
 
  printf("enter first 128-bit float ");
  scanf("%s", buf);
  a = strtoflt128 (buf, NULL);
  printf("enter second 128-bit float ");
  scanf("%s", buf);
  b = strtoflt128 (buf, NULL);
  r=a+b;
  quadmath_snprintf (buf, sizeof buf, "%+-#46.*Qe", r);
  return 0;
}
you will see that it calls __addtf3, which is part of libgcc, see https://github.com/gcc-mirror/gcc/tree/master/libgcc/soft-fp
Title: Re: GCC libquadmath
Post by: jj2007 on July 31, 2017, 12:42:50 AM
you will see that it calls __addtf3, which is part of libgcc, see https://github.com/gcc-mirror/gcc/tree/master/libgcc/soft-fp

Yep, that does the trick, thanks a lot :t

@qword: "Write your own functions"?
Title: Re: GCC libquadmath
Post by: nidud on July 31, 2017, 02:30:42 AM
@qword: "Write your own functions"?

The FPU handles up to REAL10.

Floats above must be emulated.
Title: Re: GCC libquadmath
Post by: qWord on July 31, 2017, 03:41:02 AM
e.g.

void myAdd(__float128 *const r, __float128 const *const a, __float128 const *const b) { *r = *a + *b; }

Has the advantage to rely only on GCC's public interface.
Title: Re: GCC libquadmath
Post by: jj2007 on July 31, 2017, 04:56:15 AM
The FPU handles up to REAL10.

Floats above must be emulated.

Compliments, you read the manual :t

void myAdd(__float128 *const r, __float128 const *const a, __float128 const *const b) { *r = *a + *b; }

Good. Now the same from assembler, and we can have some fun :biggrin:

Attached the beta version, MasmBasic version 1 August (http://masm32.com/board/index.php?topic=94.0) is needed to build this example:

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals REAL16 quadPI, Num1, Num2
  Init quad
  PrintLine "real PI:", Tb$, "3.14159265358979323846264338327950"
  MovVal quadPI, "3.1415926535897932384626433832795028841971"   ; string to REAL16
  PrintLine "quadPI=   ", Tb$, Quad$(quadPI)
  FpuPush quadPI                        ; REAL16 -> REAL10
  PrintLine Str$("FpuPush=\t%Jf", ST(0)v)
  fldpi                                 ; same with built-in FPU opcode
  PrintLine Str$("fldpi  =\t%Jf", ST(0)v)
  MovVal Num1, "1.234567890123456789012345678901234567890"      ; string to REAL16
  MovVal Num2, "2.222222222222222222222222222222222222222"      ; string to REAL16
  PrintLine "Num1=", Tb$, Tb$, Quad$(Num1)
  PrintLine "Num2=", Tb$, Tb$, Quad$(Num2)
  PrintLine "Num1+Num2=", Tb$, Quad$(QuadMath(__addtf3, Num1, Num2))
  PrintLine "Num1-Num2=", Tb$, Quad$(QuadMath(__subtf3, Num1, Num2))
  PrintLine "Num1*Num2=", Tb$, Quad$(QuadMath(__multf3, Num1, Num2))
  Inkey "Num1/Num2=", Tb$, Quad$(QuadMath(__divtf3, Num1, Num2))
EndOfCode


Output:
Code: [Select]
real PI:        3.14159265358979323846264338327950
quadPI=         3.14159265358979323846264338327950e+00
FpuPush=        3.141592653589793238
fldpi  =        3.141592653589793238
Num1=           1.23456789012345678901234567890123e+00
Num2=           2.22222222222222222222222222222222e+00
Num1+Num2=      3.45679011234567901123456790112346e+00
Num1-Num2=      -9.87654332098765433209876543320988e-01
Num1*Num2=      2.74348420027434842002743484200274e+00
Num1/Num2=      5.55555550555555555055555555505556e-01

As mentioned earlier, it needs C:\TDM-GCC-32\bin\libquadmath-0.dll

If your GCC is elsewhere, use ...
Code: [Select]
QuadLib$ equ <yourpath\bin\libquadmath-0>
GccLib$ equ <yourpath\bin\libgcc_s_dw2-1>

... shortly before Init (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1009).
Title: Re: GCC libquadmath
Post by: nidud on July 31, 2017, 05:46:17 AM
Compliments, you read the manual :t

 :biggrin:

Yep, I do.

These EMU functions are called by the C compilers so they need to be supplied by the library (https://github.com/nidud/asmc/blob/master/source/libc/crtl/CC/_FLDA.asm).

What qword was hinting (I assume) was that if you write the emulation yourself you don't need to use the GCC-libs.
Title: Re: GCC libquadmath
Post by: jj2007 on July 31, 2017, 06:41:53 AM
if you write the emulation yourself you don't need to use the GCC-libs.

Sure, but why reinvent the wheel if GCC has already 100 REAL16 functions? Many people have a GCC installation anyway, and it works just fine. Why should an assembler programmer not use the wealth of libraries that are the only real advantage of C/C++?

I attach an update of the Printing a sinus via the FPU, the CRT, the GSL, and Python (http://masm32.com/board/index.php?topic=94.msg43801#msg43801) source. Requires Python 3, the Gnu Scientific Library (http://gnuwin32.sourceforge.net/packages/gsl.htm), and GCC QuadMath.

Code: [Select]
Printing the sinus of 3.0 in various languages:
Sinus(3)= 0.1411200080598672    Python 3.4.3
Sinus(3)= 0.1411200080598672135 GSL, global var
Sinus(3)= 0.1411200080598672135 GSL, immediate
Sinus(3)= 0.1411200080598672135 CRT, global var
Sinus(3)= 0.1411200080598672135 CRT, immediate
Sinus(3)= 0.1411200080598672221 Assembler/Fpu
Sinus(3)= 0.14112000805986722210074480280811      QuadMath
Exact:    0.1411200080598672221007448028081103... Wolfram Alpha

EDIT:
What qword was hinting (I assume) was that if you write the emulation yourself you don't need to use the GCC-libs.

Reading his post again, it seems he means we could write a DLL or LIB in GCC that exports the 128 bit arithmetic functions. Not a bad idea, actually:
+: no GCC installation needed
-: but the DLL or LIB would bloat the MB package beyond this forum's 512k limit ;)

EDIT(2): On Win10, Python may not run properly. If it hangs, press Ctrl C.
Title: Re: GCC libquadmath
Post by: jack on August 01, 2017, 05:53:29 AM
hello jj2007
I am trying to use the function __addtf3 in FreeBasic but the result is wrong, how do you call the function in asm?
Title: Re: GCC libquadmath
Post by: jj2007 on August 01, 2017, 06:03:30 AM
Put an int 3 and launch olly. Check what happens in qmP proc. Can't do more now, no access to my computer.

In version 1 August 17 of MasmBasic (http://masm32.com/board/index.php?topic=94.0), the QuadMath interface is now implemented. To test it, click in RichMasm File/New Masm source, then QuadMath in the lower left corner.
Title: Re: GCC libquadmath
Post by: jj2007 on August 03, 2017, 09:12:23 AM
Minor bugfix in version 3 August, details here (http://masm32.com/board/index.php?topic=94.msg69033#msg69033).
Title: Re: GCC libquadmath
Post by: jj2007 on August 05, 2017, 02:51:02 AM
A QuadMath array demo:

include \masm32\MasmBasic\MasmBasic.inc     ; download (http://masm32.com/board/index.php?topic=94.0)
  Init quad
  PrintCpu 0
  NanoTimer()
  Dim MyQ() As REAL16               ; ** demo showing how to use a float128 array **
  Loops=1000000                     ; create one Million elements
  For_ ecx=0 To Loops-1
        push Rand64()               ; returns eax
        push edx                    ; and edx
        movlps xmm0, qword ptr stack
        void Str$("%Jf", xmm0)      ; assign a random value
        ; deb 10, "ct", ecx, $eax   ; activate to debug the first 10 iterations
        MovVal MyQ(ecx), eax        ; string to quad
        add esp, QWORD              ; correct the stack
        ; no good: MovVal MyQ(ecx), Str$("%Jf", number)  ; chokes
  Next
  Print Str$("%i ms for creating one Million array elements\n", NanoTimer(ms))
  ; not possible: ArraySort (http://www.webalice.it/jj2006/MasmBasicQuickReference.htmMb1176) MyQ()    sorry but sorting quads is not implemented!

  PrintLine "digits", Tb$, "1.234567890123456789012"
  For_ ecx=0 To 9
        PrintLine Str$("%i\t", ecx), Quad$(MyQ(ecx), "%*.32Qg", 24)         ; see doc on format (https://gcc.gnu.org/onlinedocs/gcc-6.3.0/libquadmath/quadmath_005fsnprintf.htmlquadmath_005fsnprintf)
  Next

  Inkey "-- hit any key --"
EndOfCode


Output:
Code: [Select]
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz
657 ms for creating one Million array elements
digits  1.234567890123456789012
0      8334395503510177650.000
1      1329069443230085730.000
2      2521605505399485735.000
3      -2513648910981773731.00
4      -6348034448820748366.00
5      -3307815091408750516.00
6      4066175164584430395.000
7      -3922227355712582401.00
8      428641309453789440.0000
9      -8910786329316853516.00

Instead of fumbling the stack, this works, too:

                void Rand64()               ; create a random value
                void Str$("%Jf", edx::eax)  ; convert to a string
                MovVal MyQ(ecx), eax        ; convert to a float128