[C] [UTIL] Efficient 64 bit support

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sometimes you need more accuracy and thus want to use 64 bit variables.
Unfortunately the AVR-GCC implementation was very huge and slow.

On the web you can found several code examples with work arounds, which tells, that there was a real interest on a better solution.
Unfortunately the compiler experts are not interested on it.
But the users, which are interested, are unable to touch and rebuild the AVR-GCC in this manner.
This was the annoying state over years.

Yesterday an expert tells me casually, that it was possible to replace the library functions with your own functions,
without touching the compiler or understanding all the compiler secrets.

The trick was very simple.
The hard thing was only, that you must know the trick!

You compile a piece of code, which contain the function, which you want to improve.
And then look on the assembler list file, how this function was named and how the parameters are passed.
Maybe it's obvious for all the compiler experts, but it wasn't obvious for me. :x

The rest was quite simple.
I put assembler division and multiplication in an assembler source, used the magic names for it and compiled again.
The result was absolutely amazing:

    without dannis64bit.S
    ===================================
    4.3.3
    AVR Memory Usage
    ----------------
    Device: atmega8

    Program: 7872 bytes (96.1% Full)
    (.text + .data + .bootloader)

    Data: 280 bytes (27.3% Full)
    (.data + .bss + .noinit)

    with dannis64bit.S
    ====================================
    4.3.3
    AVR Memory Usage
    ----------------
    Device: atmega8

    Program: 596 bytes (7.3% Full)
    (.text + .data + .bootloader)

    Data: 24 bytes (2.3% Full)
    (.data + .bss + .noinit)

On the assembler source there is nothing special.
It contain the straightforward routines expanded to 64 bit.
Since you need some temporary register, these must be saved and restored.
That's all.

On the attachment you can see the example code.
You can furthermore use 64bit without huge code wasting.
Simple insert the "dannis64bit.S" into your project.

The multiplication instruction was not used, so it runs from the ATtiny13 until ATmega2560.
Maybe on the ATtiny13 was no real need for 64 bit, but it fits. :D

To see the attachment, you must be logged in :!:

Peter

Attachment(s): 

Last Edited: Wed. Nov 9, 2011 - 10:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice code, Peter . :D

Some people won't know how to call the asm functions from the C file where they're used . For the div(), for example, do :

some_64bit_var = __udivdi3( A, B ); // 'B' will be the divisor .

To suppress a warning, you also need to do this is the C file :

extern  uint64_t  __udivdi3( uint64_t , uint64_t  );

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Wed. Nov 9, 2011 - 12:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
Some people won't know how to call the asm functions from the C file where they're used . For the div(), for example, do :

some_64bit_var = __udivdi3( A, B ); // 'B' will be the divisor .

To suppress a warning, you also need to do this is the C file :

extern  uint64_t  __udivdi3( uint64_t , uint64_t  );

No, you simply do:

X = A / B;

The call of a function of that specific name is inserted by the compiler to perform a 64 bit division.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh ok, but why doesn't the compiler/ optimizer then call the regular routines since just the regular math operators '/' etc, can be used ?

Thanks for the trick, Peter !

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Wed. Nov 9, 2011 - 12:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
Oh ok, but why doesn't the compiler/ optimizer then call the regular routines since just the regular math operators '/' etc, can be used ?
Sorry, I have problems to understand that sentence.
__udivdi3 is the regular function. Peter's assembler source simply "replaces" the generic one provided somewhere in the compiler libraries.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I saw this __udivdi3_1 originally and missed the std. name that he used in

.global __udivdi3

for that routine . So then the compiler sees __udivdi3 from the *.S and then 'knows' it doesn't have to call it 'again' ?

Sternst, my unclear question was how did GCC know to pull Danni's routine's since the '/' can be used, and not done as function call . Which is partly answered in your last post .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
So then the compiler sees __udivdi3 from the *.S and then 'knows' it doesn't have to call it 'again' ?
No.
The compiler translates the "A/B" into code that contains a call of __udivdi3 (to actually perform the division). And that's all (regarding the compiler).

Then the linker resolves that symbol with the first definition it finds. Normally from some library. But if the linker finds a definition in your code first, then that is taken.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IJ,

It's the same reason you put -lm on the end of linker invocation. It will resolve symbols from the first link object it comes to that provides them.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In __muldi3 you are pushing t6, but popping t5.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
In __muldi3 you are pushing t6, but popping t5.

Thank you.
It's corrected now.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If this is significantly better than the current implementation, is there a way we can push to get it upstream in the newer avr-libc releases? I realize that 64-bit math isn't a common use-case, but I also can't see the harm in optimizing everything where we can.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now it's clear, thanks Sternst & Clawson .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

This is _awesome_ danni!!! I've been wanting efficient 64-bit support for so long!!

Thanks,

Alan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow thanks you!! This should go into the next avr-gcc!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
is there a way we can push to get it upstream in the newer avr-libc releases?
The functions are inside avr-libgcc (part of avr-gcc not avr-libc project)
AFAIR, theese functions have common default C-implementation and not replaced by specialised AVR asm implementation at all

wbr, ReAl

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The functions are inside avr-libgcc (part of avr-gcc not avr-libc project)
AFAIR, theese functions have common default C-implementation and not replaced by specialised AVR asm implementation at all

Then perhaps the solution is for AVR-LibC to provide something like libmath64.a which, like libm.a, it's left to the user to use -lmath64 if they want the improved support?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ReAlAl wrote:
The functions are inside avr-libgcc (part of avr-gcc not avr-libc project)
AFAIR, theese functions have common default C-implementation and not replaced by specialised AVR asm implementation at all
That depends. There are 3 flavours of functions in libgcc:
  1. Functions written in C. This is the default. As the functions are written in C, they comply to the ABI. Hand-optimized assembler doesn't fall from the sky...
  2. Functions written in assembler that comply to the ABI. An example is __mulsi3 for devices that have no MUL instrustion.
  3. Functions written in assembler that come with their own ABI. Plenty of examples here, just to mention some:
    • No MUL: __mulqi3, __mulhi3
    • With MUL: __mulsi3, __[u]mulhisi3, __mul[u]hisi3
    • __[u]divmodqi4, __[u]divmodhi4, __[u]divmodpsi4, __parityhi2, __popcountqi2, __fmul[s[u]]
This list is incomplete and might change as the compiler evolves. So you must know exactly what you are doing. If you touch the wrong function in the wrong way, you will run into problems.

clawson wrote:
Then perhaps the solution is for AVR-LibC to provide something like libmath64.a which, like libm.a, it's left to the user to use -lmath64 if they want the improved support?
No, that's no good solution. It's up to the compiler so supply base arithmetic and other stuff that belong to the language core. There are already too much functions that are implemented both in libgcc (C) and in avr-libc (assembler) and that actually belong into libgcc. __mulsf3 is an example.

libcc contains code that is too complex to be expanded inline and that belongs to the core of the language. For example, __divmodsi4 which implements signed 32-bit quotient and remainder is just an internal support function called by the compiler and thus belongs into libgcc, whereas printf is not a part of the core and is typically implemented in libc.

abcminiuser wrote:
..., is there a way we can push to get it upstream in the newer avr-libc releases?
Everybody can contribute to GCC. As just explained, that is the right place for such improvements.

And if you feel like "me=dummy, they=expert", read this post and you see I didn't even know where's top and where's bottom...

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

today i found in [1] the avr gcc lib1funcs.S with some new and fast 64Bit libs for the Atmel µP family.

I extract the parts that i need for my 'reciprocal frequency counter' and test it by the way. They work !

You can download these files at the end of this msg.

links:
[1] http://gcc.gnu.org/viewcvs/trunk...

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DE0508 wrote:
You can download these files at the end of this msg.

links:
[1] http://gcc.gnu.org/viewcvs/trunk/libgcc/config/avr/lib1funcs.S

Please notice that if you include sources from libgcc (or parts of it) in your project, the project must be licensed under a GPL-compatible license. Please read the copyright notice in the header of the file in think about the impace copy-pasting GPLed software into your projects might have.

Moreover, notice that this restriction does not apply if you use the routines from libgcc that are shipped with a GCC distribution like WinAVR because of the GCC Runtime Library Exception (RLE).

avrfreaks does not support Opera. Profile inactive.