Sign in Join

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

Mailing lists / fpc-devel / 2018-05

Re: Broken frac functionin FPC3.1.1 / Windows x86_64

13 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

J. Gareth Moreton

I reopened the bug ticket to attach a patch with the new function. It also contains some code for "Int" that passes through the input unchanged if its magnitude is greater than 2^52 (at this point, the precision means it can't have a fractional component).  I've set it to "feedback" currently so Sven can determine if the patch is satisfactory.

https://bugs.freepascal.org/view.php?id=33635

Gareth aka. Kit

On Mon 30/04/18 02:12 , "Thorsten Engler" sent:

Show quoted text 10 lines
-----Original Message----- From: fpc-devel On Behalf Of Florian Klaempfl Sent: Monday, 30 April 2018 04:28 > That ended up making things worse in some cases. Can you take a look at the generated machine code if delphi uses proper multi byte nops. If not, the align might make things indeed worse.

It does.

The problem was not the time required by the nops, but that for certain entry point alignments (among them the 16 byte alignments) the presence of this .align triggered the 3-4 times increase in processing time. I didn't look any closer into it as the version that J. Gareth worked out is faster and isn't alignment sensitive.

Reply by email

J. Gareth Moreton

As Sven pointed out, there are still
faults in our functions in that they don't
honour NaNs. It's an easy enough fix, but
will just need an extra bit of code.

I asked about the rules regarding
infinities, but going by what happens with
the old floating-point stack, an exception
is raised, so returning zero is probably
okay, but Frac(NaN) is definitely not
okay!

Reply by email

J. Gareth Moreton

On Tue 01/05/18 20:11 , Jonas Maebe
sent:

On 01/05/18 21:06, J. Gareth Moreton
> I asked about the rules regarding > infinities, but going by what happens

with

> the old floating-point stack, an

exception

Show quoted text 6 lines
> is raised, The code also has to work if exceptions

are disabled.

Show quoted text 7 lines
Jonas

The easiest and fastest solution would be
to return infinity of the same sign, as
that allows inf, -inf and NaN to be
checked with a single comparison (all the
exponent bits equal 1). Since infinity is
such an abnormal value to get the
fractional component for, this is an
acceptable return in my opinion.

Gareth aka. Kit

Reply by email

J. Gareth Moreton

It turns out I did over-engineer the solution somewhat - this version is far more efficient, honours NaNs and triggers SIGFPE if infinity is passed in (subsd triggers it), hence there are no regressions.

****

function fpc_frac_real(d: ValReal): ValReal; compilerproc; assembler; nostackframe;
  asm
    movq      %xmm0,  %rax
    movapd    %xmm0,  %xmm4
    shr       $48,    %rax
    and       $0x7ff0,%ax
    cmp       $0x4330,%ax
    jge       .L0
    cvttsd2si %xmm0,  %rax
    cvtsi2sd  %rax,   %xmm4
.L0:
    subsd     %xmm4,  %xmm0
  end;

****

This is effectively "x - Int(x)" with some opcode reordering to take advantage of the multiple SSE ports present in a processor (hence the positioning of "movapd %xmm0,%xmm4" in between "movq %xmm0,%rax" and "shr $48,%rax") - it is generally equal in speed to my last routine and is faster when dealing with numbers that don't have fractional components.  It is also only 38 bytes in size.

New patch coming soon once I test it properly.

Gareth aka. Kit

Reply by email

Sven Barth
to J. Gareth Moreton

J. Gareth Moreton schrieb am Di., 1. Mai 2018,
23:39:

Show quoted text 30 lines
It turns out I did over-engineer the solution somewhat - this version is far more efficient, honours NaNs and triggers SIGFPE if infinity is passed in (subsd triggers it), hence there are no regressions. **** function fpc_frac_real(d: ValReal): ValReal; compilerproc; assembler; nostackframe; asm movq %xmm0, %rax movapd %xmm0, %xmm4 shr $48, %rax and $0x7ff0,%ax cmp $0x4330,%ax jge .L0 cvttsd2si %xmm0, %rax cvtsi2sd %rax, %xmm4 .L0: subsd %xmm4, %xmm0 end; **** This is effectively "x - Int(x)" with some opcode reordering to take advantage of the multiple SSE ports present in a processor (hence the positioning of "movapd %xmm0,%xmm4" in between "movq %xmm0,%rax" and "shr $48,%rax") - it is generally equal in speed to my last routine and is faster when dealing with numbers that don't have fractional components. It is also only 38 bytes in size.

Thank you for the work so far. Does it also work correctly when exceptions are disabled?

Regards,
Sven

Reply by email

Sven Barth

J. Gareth Moreton schrieb am Mi., 2. Mai 2018,
11:10:

Show quoted text 17 lines
On Wed 02/05/18 06:55 , Sven Barth sent: ... Thank you for the work so far. Does it also work correctly when exceptions are disabled? Regards, Sven I confess I haven't tested that - I know it involves setting the FPU control word, but what should I expect?

I suspect that NaN should be returned if Infinity is passed in, but I haven't tested that either.

Regards,
Sven

PS: you didn't include the mailing list in your answer ;)

Reply by email

J. Gareth Moreton

On Wed 02/05/18 06:55 , Sven Barth sent:
...
Thank you for the work so far. Does it also work correctly when exceptions are disabled?
Regards, Sven

I confess I haven't tested that - I know it involves setting the FPU control word, but what should I expect?

Gareth aka. Kit

Reply by email

J. Gareth Moreton

Hi guys,

I've been having difficulties disabling floating-point and SSE exceptions. Either the exceptions are still raised, or an exception is raised elsewhere... sometimes within the function, and in one instance, in the WriteLn routine!  Does anyone have any advice as to how to get around this and properly disable the exceptions? I haven't had much luck with SetExceptionMask or Set8087CW so far.

Outside of that, manual data flow analysis shows that XMM0 is invariant up until the point that SUBSD is called, which is the operation that raises an exception if XMM0 contains plus or minus infinity.  Logically, being the last operation in the function, if SUBSD doesn't do anything if exceptions are suppressed, then XMM0 will still contain plus or minus infinity and this will be the return value; unusual for a function that returns x where -1 < x < 1, but considering infinity is an abnormal value to pass, this is sort of permissible, I think.

Gareth

On Wed 02/05/18 10:16 , "J. Gareth Moreton"
sent:
On Wed 02/05/18 06:55 , Sven Barth sent:
...
Thank you for the work so far. Does it also work correctly when exceptions are disabled?
Regards, Sven

I confess I haven't tested that - I know it involves setting the FPU control word, but what should I expect?

Gareth aka. Kit _______________________________________________ fpc-devel maillist -
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel [1]">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Links:
------
[1] http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

J. Gareth Moreton

I'll keep working on it though, because it seems that some routines may return placeholder values if exceptions are masked.

Gareth aka. Kit

On Thu 03/05/18 02:35 , "J. Gareth Moreton"
sent:
Hi guys,

I've been having difficulties disabling floating-point and SSE exceptions. Either the exceptions are still raised, or an exception is raised elsewhere... sometimes within the function, and in one instance, in the WriteLn routine!  Does anyone have any advice as to how to get around this and properly disable the exceptions? I haven't had much luck with SetExceptionMask or Set8087CW so far.

Outside of that, manual data flow analysis shows that XMM0 is invariant up until the point that SUBSD is called, which is the operation that raises an exception if XMM0 contains plus or minus infinity.  Logically, being the last operation in the function, if SUBSD doesn't do anything if exceptions are suppressed, then XMM0 will still contain plus or minus infinity and this will be the return value; unusual for a function that returns x where -1 < x < 1, but considering infinity is an abnormal value to pass, this is sort of permissible, I think.

Gareth

...

Reply by email

J. Gareth Moreton

Tests complete! It turns out that I was using SetExceptionMask wrong and subtracting rather than adding exInvalidOp.

When exceptions are disabled, this new Frac function returns NaN when you pass in plus or minus infinity.  This is consistent with the specification as listed in Chapter 11, Section 11.5.2.1 of the Intel® 64 and IA-32 Architectures Software Developer's Manual which dicates that if the cause is "Addition of opposite signed infinities or subtraction of like-signed infinities" (the last line in the procedure is SUBSD that effectively performs "x - Int(x)"), the result is to "Return the QNaN floating-point Indefinite".

Gareth aka. Kit

Reply by email

Sven Barth
to J. Gareth Moreton

J. Gareth Moreton schrieb am Do., 3. Mai 2018,
04:55:

Show quoted text 12 lines
Tests complete! It turns out that I was using SetExceptionMask wrong and subtracting rather than adding exInvalidOp. When exceptions are disabled, this new Frac function returns NaN when you pass in plus or minus infinity. This is consistent with the specification as listed in Chapter 11, Section 11.5.2.1 of the Intel® 64 and IA-32 Architectures Software Developer's Manual which dicates that if the cause is "Addition of opposite signed infinities or subtraction of like-signed infinities" (the last line in the procedure is SUBSD that effectively performs "x - Int(x)"), the result is to "Return the QNaN floating-point Indefinite".

Great! If you haven't done so, would you please make sure that your patch is attached to the bug report so that I can find it? :)

Regards,
Sven

Reply by email

J. Gareth Moreton

It's already there. I deleted the faulty one and included a new copy with the fix.  It's probably not the best approach, but I didn't want a long list of patches like I've ended up with before.

Gareth aka. Kit

On Thu 03/05/18 06:56 , "Sven Barth" sent:
J. Gareth Moreton schrieb am Do., 3. Mai 2018, 04:55: Tests complete! It turns out that I was using SetExceptionMask wrong and subtracting rather than adding exInvalidOp.

When exceptions are disabled, this new Frac function returns NaN when you pass in plus or minus infinity.  This is consistent with the specification as listed in Chapter 11, Section 11.5.2.1 of the Intel® 64 and IA-32 Architectures Software Developer's Manual which dicates that if the cause is "Addition of opposite signed infinities or subtraction of like-signed infinities" (the last line in the procedure is SUBSD that effectively performs "x - Int(x)"), the result is to "Return the QNaN floating-point Indefinite".

Great! If you haven't done so, would you please make sure that your patch is attached to the bug report so that I can find it? :)  Regards, Sven 

Reply by email