Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2024-09

softfloat: sizeOf( floatx80 )

8 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

Is there any indention in

   floatx80 = record
     case byte of
       1: (low : qword;high : word);
       // force the record to be aligned like a double
       // else *_to_double will fail for cpus like sparc
       // and avoid expensive unpacking/packing operations
       2: (dummy : extended);
   end;

NOT being a packed record?

If it was packed, it should have the same size as an actual extended: 80 bits / 10 bytes.

Possible similar issues for other softfloat types

Reply by email

Pierre Muller
to Martin Frb

I think that the big endian version (see grep below) would suffer if you would use packed
because the high field of size 2,
would put the low field of size 8 at offset 2,
which would trigger unaligned access to this field.

For the little endian definition,
it doesn't change anything, does it?

Pierre

See this grep result:

grep -inA9 "floatx80 *=" *
softfpu.pp:139: floatx80 = record
softfpu.pp-140- case byte of
softfpu.pp-141- // force the record to be aligned like a double softfpu.pp-142- // else *_to_double will fail for cpus like sparc softfpu.pp-143- // and avoid expensive unpacking/packing operations softfpu.pp-144- 1: (dummy : extended);
softfpu.pp-145- 2: (low : qword;high : word); softfpu.pp-146- end;
softfpu.pp-147-
softfpu.pp-148- float128 = record

softfpu.pp:167: floatx80 = record softfpu.pp-168- case byte of softfpu.pp-169- // force the record to be aligned like a double softfpu.pp-170- // else *_to_double will fail for cpus like sparc softfpu.pp-171- // and avoid expensive unpacking/packing operations softfpu.pp-172- 1: (dummy : qword); softfpu.pp-173- 2: (high : word;low : qword); softfpu.pp-174- end; softfpu.pp-175- softfpu.pp-176- float128 = record -- ufloatx80.pp:32: floatx80 = {$IFDEF FPC_DOTTEDUNITS}System.SoftFpuX80{$ELSE}sfpux80{$ENDIF}.floatx80; ufloatx80.pp-33- Le 27/09/2024 à 20:00, Martin Frb via fpc-devel a écrit : > Is there any indention in > >   floatx80 = record >     case byte of >       1: (low : qword;high : word); >       // force the record to be aligned like a double >       // else *_to_double will fail for cpus like sparc >       // and avoid expensive unpacking/packing operations >       2: (dummy : extended); >   end; > > > NOT being a packed record? > > If it was packed, it should have the same size as an actual extended: 80 > bits / 10 bytes. > > Possible similar issues for other softfloat types > _______________________________________________ > fpc-devel maillist - > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Florian Klämpfl
to Pierre Muller
Show quoted text 10 lines
Am 28.09.2024 um 09:24 schrieb Pierre Muller via fpc-devel : I think that the big endian version (see grep below) would suffer if you would use packed because the high field of size 2, would put the low field of size 8 at offset 2, which would trigger unaligned access to this field. For the little endian definition, it doesn't change anything, does it?

Yes, the record wouldn’t be aligned anymore like a real extended and on some platforms it would be accessed only bytewise.

Show quoted text 53 lines
Pierre See this grep result: grep -inA9 "floatx80 *=" * softfpu.pp:139: floatx80 = record softfpu.pp-140- case byte of softfpu.pp-141- // force the record to be aligned like a double softfpu.pp-142- // else *_to_double will fail for cpus like sparc softfpu.pp-143- // and avoid expensive unpacking/packing operations softfpu.pp-144- 1: (dummy : extended); softfpu.pp-145- 2: (low : qword;high : word); softfpu.pp-146- end; softfpu.pp-147- softfpu.pp-148- float128 = record -- softfpu.pp:167: floatx80 = record softfpu.pp-168- case byte of softfpu.pp-169- // force the record to be aligned like a double softfpu.pp-170- // else *_to_double will fail for cpus like sparc softfpu.pp-171- // and avoid expensive unpacking/packing operations softfpu.pp-172- 1: (dummy : qword); softfpu.pp-173- 2: (high : word;low : qword); softfpu.pp-174- end; softfpu.pp-175- softfpu.pp-176- float128 = record -- ufloatx80.pp:32: floatx80 = {$IFDEF FPC_DOTTEDUNITS}System.SoftFpuX80{$ELSE}sfpux80{$ENDIF}.floatx80; ufloatx80.pp-33- > Le 27/09/2024 à 20:00, Martin Frb via fpc-devel a écrit : > Is there any indention in > floatx80 = record > case byte of > 1: (low : qword;high : word); > // force the record to be aligned like a double > // else *_to_double will fail for cpus like sparc > // and avoid expensive unpacking/packing operations > 2: (dummy : extended); > end; > NOT being a packed record? > If it was packed, it should have the same size as an actual extended: 80 > bits / 10 bytes. > Possible similar issues for other softfloat types > _______________________________________________ > fpc-devel maillist - > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Martin Frb
to Pierre Muller: I think that the big endian version (see grep below) would suffer if you would use packed…
Pierre Muller wrote 8 lines
I think that the big endian version (see grep below) would suffer if you would use packed because the high field of size 2, would put the low field of size 8 at offset 2, which would trigger unaligned access to this field. For the little endian definition, it doesn't change anything, does it?

It's not to important (for my case ).
I have a case where the data comes from another process (just 10 bytes, that are an extended in a 32bit process (Win), and get loaded by a 64bit process into the softfloat.)

I was comparing; SizeOf(MyVAr) = 10
and that failed.
So now I had to hardcode everywhere that a floatx80 can take those 10 bytes.

If I had wanted to put that in a generic and specialize with floatx80, double and single, then I had a problem because sizeOf would not work. I don't currently need it as generic.

About the big endian issue: That means it is not memory compatible with a native "extended" because it has a gap. So if you load data from a file/stream that has been written with native (gap free) extended, then it wont work.

I don't know if floatx80 promises such compatibility. But it would be very useful if it did.
On little endian, tests have shown that it can be used that way.

Reply by email

Martin Frb
to Martin Frb
Martin Frb wrote 16 lines
On 28/09/2024 09:34, Pierre Muller via fpc-devel wrote: > I think that the big endian version (see grep below) > would suffer if you would use packed > because the high field of size 2, > would put the low field of size 8 at offset 2, > which would trigger unaligned access to this field. > About the big endian issue: That means it is not memory compatible with a native "extended" because it has a gap. So if you load data from a file/stream that has been written with native (gap free) extended, then it wont work. I don't know if floatx80 promises such compatibility. But it would be very useful if it did. On little endian, tests have shown that it can be used that way.

Just for my understanding.... As I haven't really looked deeply into the representation of those numbers.

My current understanding starts of with the DWARF spec. That simply specifies
- type: float
- size (in bytes or bit): ... e.g. 8/64 or 10/80.

In addition, now googled, on wikipedia there is only one format for 80bits? (unless I missed something). But it's in a paragraph referring to x86...
https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format

From that any debugger on any platform seems to be able to read such a float. So I presumed that for a given length there is a standard how the number should be represented in memory?

I haven't tested if e.g. gdb would on a big endian be able to read an 80bit float. Or if it would just say that is an invalid size for the platform.

But given that floats (like any other data) can be streamed to files and other media, I would expect that the existence does not change by the features of the CPU.
Of course the byte order may change. (I don't know if bytes or bits for extended are in a diff order on a big endian? But if they are the reader of a stream would know to fix that). But I wouldn't expect gaps in the data, that is assuming the data can exist.

Now all of the above are just conclusions from one rather small starting point. So I may well be wrong. If I am, I would like to know where?

Reply by email

Jonas Maebe
to Martin Frb
Martin Frb wrote 14 lines
In addition, now googled, on wikipedia there is only one format for 80bits? (unless I missed something). But it's in a paragraph referring to x86... https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format From that any debugger on any platform seems to be able to read such a float. So I presumed that for a given length there is a standard how the number should be represented in memory? I haven't tested if e.g. gdb would on a big endian be able to read an 80bit float. Or if it would just say that is an invalid size for the platform.

Some ABIs require aligning and padding the value in memory to 16 bytes (maybe some also to 12 bytes).

On trunk, it could be solved with packing + an align directive, although then you'd still have to hard-code the alignment per platform using ifdefs (or add an "alignof" intrinsic).

Jonas

Reply by email

Karoly Balogh
to Martin Frb: It's not to important (for my case ). I have a case where the data comes from another…

Hi,

Martin Frb wrote
About the big endian issue: That means it is not memory compatible with a native "extended" because it has a gap.

Fromt the top of my head, I only know one example of a big endian system which has an 80 bit extended type in hardware, and it's the Motorola 68000 family. Which actually stores exteded in a 96 bit format in memory, with a gap. :) (See: Motorola 68000 Family Reference manual, Page 5-110)

So if you load data from a file/stream that has been written with native (gap free) extended, then it wont work.

Well, 1., see above 2., if you _really_ want to have this compatible among all systems, you need to decide on an on-disk format, including actual endianness, then just properly serialize-deserialize it to match that. Anything else is in the "might work" territory for a certain combination of systems, but otherwise it will break.

I don't know if floatx80 promises such compatibility. But it would be very useful if it did.

No, I don't think promises anything like that. I'd say it is primarily an internal structure, and using it for I/O might simplify your use case, but changing it globally to packed will be a massive performance penalty on some systems where you need this performance the most. So we can't change it globally in the compiler/RTL.

On little endian, tests have shown that it can be used that way.

Yeah, the world is full such of little endian "shortcuts", for example some JIT Javascript engines by design access the same address to get the lower byte/word/etc of dwords, which just can't work on a big endian system. I get it - it simplifies the engine and the code generation, but this still doesn't make it a good practice or design.

Charlie

Reply by email

Martin Frb
to Karoly Balogh
Karoly Balogh wrote
Fromt the top of my head, I only know one example of a big endian system which has an 80 bit extended type in hardware, and it's the Motorola 68000 family. Which actually stores exteded in a 96 bit format in memory, with a gap. :) (See: Motorola 68000 Family Reference manual, Page 5-110)

Ok, so then on that platform the gap should probably also exist in the record.

Well, 1., see above 2., if you _really_ want to have this compatible among all systems, you need to decide on an on-disk format, including actual endianness, then just properly serialize-deserialize it to match that.

Yes, that would have to be deserialised to the gap format, for a platform that has the gap.

I would assume that e.g. gdb (if it supports the format at all) would expect the gap on that platform.

Show quoted text 8 lines
> I don't know if floatx80 promises such compatibility. But it would be very > useful if it did. No, I don't think promises anything like that. I'd say it is primarily an internal structure, and using it for I/O might simplify your use case, but changing it globally to packed will be a massive performance penalty on some systems where you need this performance the most. So we can't change it globally in the compiler/RTL.

Ok, well...

Currently it is only needed on Win-64. For FpDebug. So the 64bit debugger can cross debug a 32 bit target and show "extended" values from the 32 bit target.

I have test case  that will detect if FPC changes anything. If that happens, I will simply have to add a copy of the current working version to FpDebug.

Technically, I agree it would then be FpDebug's task to translate the format. But that would require that the format of floatx80 is documented in such a way that it can (and is meant to be) written by 3rd party code. And of course, if I where cross debugging from Intel to M68000 the adaption would certainly be my duty.

Maybe the softfloat libraries can provide some routine that takes memory in the native format and store it correctly into the record? On Intel:  array[0..9] of byte
On M68000: array[0..11] of byte

Or a record of the correct size, or .... As long as it is documented. Or does such a doc already exist?

Reply by email