mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-13 13:59:28 +01:00
+ Implemented IEEE 754-compliant checking for unordered results of floating-point compares on x86 targets. Mantis #9362.
git-svn-id: trunk@27581 -
This commit is contained in:
parent
5eae80ebb0
commit
07e90aaa24
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -12316,6 +12316,7 @@ tests/test/units/fpwidestring/twide2fpwidestring.pp svneol=native#text/pascal
|
|||||||
tests/test/units/fpwidestring/twide6fpwidestring.pp svneol=native#text/pascal
|
tests/test/units/fpwidestring/twide6fpwidestring.pp svneol=native#text/pascal
|
||||||
tests/test/units/fpwidestring/twide7fpwidestring.pp svneol=native#text/pascal
|
tests/test/units/fpwidestring/twide7fpwidestring.pp svneol=native#text/pascal
|
||||||
tests/test/units/lineinfo/tlininfo.pp svneol=native#text/plain
|
tests/test/units/lineinfo/tlininfo.pp svneol=native#text/plain
|
||||||
|
tests/test/units/math/tcmpnan.pp svneol=native#text/plain
|
||||||
tests/test/units/math/tdivmod.pp svneol=native#text/plain
|
tests/test/units/math/tdivmod.pp svneol=native#text/plain
|
||||||
tests/test/units/math/tmask.inc svneol=native#text/plain
|
tests/test/units/math/tmask.inc svneol=native#text/plain
|
||||||
tests/test/units/math/tmask.pp svneol=native#text/plain
|
tests/test/units/math/tmask.pp svneol=native#text/plain
|
||||||
|
|||||||
@ -2116,23 +2116,75 @@ unit cgx86;
|
|||||||
procedure tcgx86.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
|
procedure tcgx86.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
|
||||||
var
|
var
|
||||||
ai : taicpu;
|
ai : taicpu;
|
||||||
|
hl : tasmlabel;
|
||||||
|
f2 : tresflags;
|
||||||
begin
|
begin
|
||||||
|
hl:=nil;
|
||||||
|
f2:=f;
|
||||||
|
case f of
|
||||||
|
F_FNE:
|
||||||
|
begin
|
||||||
|
ai:=Taicpu.op_sym(A_Jcc,S_NO,l);
|
||||||
|
ai.SetCondition(C_P);
|
||||||
|
ai.is_jmp:=true;
|
||||||
|
list.concat(ai);
|
||||||
|
f2:=F_NE;
|
||||||
|
end;
|
||||||
|
F_FE,F_FA,F_FAE,F_FB,F_FBE:
|
||||||
|
begin
|
||||||
|
{ JP before JA/JAE is redundant, but it must be generated here
|
||||||
|
and left for peephole optimizer to remove. }
|
||||||
|
current_asmdata.getjumplabel(hl);
|
||||||
|
ai:=Taicpu.op_sym(A_Jcc,S_NO,hl);
|
||||||
|
ai.SetCondition(C_P);
|
||||||
|
ai.is_jmp:=true;
|
||||||
|
list.concat(ai);
|
||||||
|
f2:=FPUFlags2Flags[f];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
ai := Taicpu.op_sym(A_Jcc,S_NO,l);
|
ai := Taicpu.op_sym(A_Jcc,S_NO,l);
|
||||||
ai.SetCondition(flags_to_cond(f));
|
ai.SetCondition(flags_to_cond(f2));
|
||||||
ai.is_jmp := true;
|
ai.is_jmp := true;
|
||||||
list.concat(ai);
|
list.concat(ai);
|
||||||
|
if assigned(hl) then
|
||||||
|
a_label(list,hl);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tcgx86.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
|
procedure tcgx86.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
|
||||||
var
|
var
|
||||||
ai : taicpu;
|
ai : taicpu;
|
||||||
hreg : tregister;
|
f2 : tresflags;
|
||||||
|
hreg,hreg2 : tregister;
|
||||||
|
op: tasmop;
|
||||||
begin
|
begin
|
||||||
|
hreg2:=NR_NO;
|
||||||
|
op:=A_AND;
|
||||||
|
f2:=f;
|
||||||
|
case f of
|
||||||
|
F_FE,F_FNE,F_FB,F_FBE:
|
||||||
|
begin
|
||||||
|
hreg2:=getintregister(list,OS_8);
|
||||||
|
ai:=Taicpu.op_reg(A_SETcc,S_B,hreg2);
|
||||||
|
if (f=F_FNE) then { F_FNE means "PF or (not ZF)" }
|
||||||
|
begin
|
||||||
|
ai.setcondition(C_P);
|
||||||
|
op:=A_OR;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ai.setcondition(C_NP);
|
||||||
|
list.concat(ai);
|
||||||
|
f2:=FPUFlags2Flags[f];
|
||||||
|
end;
|
||||||
|
F_FA,F_FAE: { These do not need PF check }
|
||||||
|
f2:=FPUFlags2Flags[f];
|
||||||
|
end;
|
||||||
hreg:=makeregsize(list,reg,OS_8);
|
hreg:=makeregsize(list,reg,OS_8);
|
||||||
ai:=Taicpu.op_reg(A_SETcc,S_B,hreg);
|
ai:=Taicpu.op_reg(A_SETcc,S_B,hreg);
|
||||||
ai.setcondition(flags_to_cond(f));
|
ai.setcondition(flags_to_cond(f2));
|
||||||
list.concat(ai);
|
list.concat(ai);
|
||||||
|
if (hreg2<>NR_NO) then
|
||||||
|
list.concat(taicpu.op_reg_reg(op,S_B,hreg2,hreg));
|
||||||
if reg<>hreg then
|
if reg<>hreg then
|
||||||
a_load_reg_reg(list,OS_8,size,hreg,reg);
|
a_load_reg_reg(list,OS_8,size,hreg,reg);
|
||||||
end;
|
end;
|
||||||
@ -2142,13 +2194,24 @@ unit cgx86;
|
|||||||
var
|
var
|
||||||
ai : taicpu;
|
ai : taicpu;
|
||||||
tmpref : treference;
|
tmpref : treference;
|
||||||
|
f2 : tresflags;
|
||||||
begin
|
begin
|
||||||
|
f2:=f;
|
||||||
|
case f of
|
||||||
|
F_FE,F_FNE,F_FB,F_FBE:
|
||||||
|
begin
|
||||||
|
inherited g_flags2ref(list,size,f,ref);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
F_FA,F_FAE:
|
||||||
|
f2:=FPUFlags2Flags[f];
|
||||||
|
end;
|
||||||
tmpref:=ref;
|
tmpref:=ref;
|
||||||
make_simple_ref(list,tmpref);
|
make_simple_ref(list,tmpref);
|
||||||
if not(size in [OS_8,OS_S8]) then
|
if not(size in [OS_8,OS_S8]) then
|
||||||
a_load_const_ref(list,size,0,tmpref);
|
a_load_const_ref(list,size,0,tmpref);
|
||||||
ai:=Taicpu.op_ref(A_SETcc,S_B,tmpref);
|
ai:=Taicpu.op_ref(A_SETcc,S_B,tmpref);
|
||||||
ai.setcondition(flags_to_cond(f));
|
ai.setcondition(flags_to_cond(f2));
|
||||||
list.concat(ai);
|
list.concat(ai);
|
||||||
{$ifndef cpu64bitalu}
|
{$ifndef cpu64bitalu}
|
||||||
if size in [OS_S64,OS_64] then
|
if size in [OS_S64,OS_64] then
|
||||||
|
|||||||
@ -247,8 +247,16 @@ uses
|
|||||||
type
|
type
|
||||||
TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,
|
TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,
|
||||||
F_A,F_AE,F_B,F_BE,
|
F_A,F_AE,F_B,F_BE,
|
||||||
F_S,F_NS,F_O,F_NO);
|
F_S,F_NS,F_O,F_NO,
|
||||||
|
{ For IEEE-compliant floating-point compares,
|
||||||
|
same as normal counterparts but additionally check PF }
|
||||||
|
F_FE,F_FNE,F_FA,F_FAE,F_FB,F_FBE);
|
||||||
|
|
||||||
|
const
|
||||||
|
FPUFlags = [F_FE,F_FNE,F_FA,F_FAE,F_FB,F_FBE];
|
||||||
|
FPUFlags2Flags: array[F_FE..F_FBE] of TResFlags = (
|
||||||
|
F_E,F_NE,F_A,F_AE,F_B,F_BE
|
||||||
|
);
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
Constants
|
Constants
|
||||||
@ -478,7 +486,8 @@ implementation
|
|||||||
inv_flags: array[TResFlags] of TResFlags =
|
inv_flags: array[TResFlags] of TResFlags =
|
||||||
(F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
|
(F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
|
||||||
F_BE,F_B,F_AE,F_A,
|
F_BE,F_B,F_AE,F_A,
|
||||||
F_NS,F_S,F_NO,F_O);
|
F_NS,F_S,F_NO,F_O,
|
||||||
|
F_FNE,F_FE,F_FBE,F_FB,F_FAE,F_FA);
|
||||||
begin
|
begin
|
||||||
f:=inv_flags[f];
|
f:=inv_flags[f];
|
||||||
end;
|
end;
|
||||||
@ -487,9 +496,12 @@ implementation
|
|||||||
function flags_to_cond(const f: TResFlags) : TAsmCond;
|
function flags_to_cond(const f: TResFlags) : TAsmCond;
|
||||||
const
|
const
|
||||||
flags_2_cond : array[TResFlags] of TAsmCond =
|
flags_2_cond : array[TResFlags] of TAsmCond =
|
||||||
(C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE,C_S,C_NS,C_O,C_NO);
|
(C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE,C_S,C_NS,C_O,C_NO,
|
||||||
|
C_None,C_None,C_None,C_None,C_None,C_None);
|
||||||
begin
|
begin
|
||||||
result := flags_2_cond[f];
|
result := flags_2_cond[f];
|
||||||
|
if (result=C_None) then
|
||||||
|
InternalError(2014041301);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ unit nx86add;
|
|||||||
tx86addnode = class(tcgaddnode)
|
tx86addnode = class(tcgaddnode)
|
||||||
protected
|
protected
|
||||||
function getresflags(unsigned : boolean) : tresflags;
|
function getresflags(unsigned : boolean) : tresflags;
|
||||||
|
function getfpuresflags : tresflags;
|
||||||
procedure left_must_be_reg(opdef: tdef; opsize:TCGSize;noswap:boolean);
|
procedure left_must_be_reg(opdef: tdef; opsize:TCGSize;noswap:boolean);
|
||||||
procedure force_left_and_right_fpureg;
|
procedure force_left_and_right_fpureg;
|
||||||
procedure prepare_x87_locations(out refnode: tnode);
|
procedure prepare_x87_locations(out refnode: tnode);
|
||||||
@ -400,6 +401,32 @@ unit nx86add;
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function tx86addnode.getfpuresflags : tresflags;
|
||||||
|
begin
|
||||||
|
if (nodetype=equaln) then
|
||||||
|
result:=F_FE
|
||||||
|
else if (nodetype=unequaln) then
|
||||||
|
result:=F_FNE
|
||||||
|
else if (nf_swapped in flags) then
|
||||||
|
case nodetype of
|
||||||
|
ltn : result:=F_FA;
|
||||||
|
lten : result:=F_FAE;
|
||||||
|
gtn : result:=F_FB;
|
||||||
|
gten : result:=F_FBE;
|
||||||
|
else
|
||||||
|
internalerror(2014031402);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
case nodetype of
|
||||||
|
ltn : result:=F_FB;
|
||||||
|
lten : result:=F_FBE;
|
||||||
|
gtn : result:=F_FA;
|
||||||
|
gten : result:=F_FAE;
|
||||||
|
else
|
||||||
|
internalerror(2014031403);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
AddSmallSet
|
AddSmallSet
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
@ -1093,7 +1120,7 @@ unit nx86add;
|
|||||||
internalerror(200402223);
|
internalerror(200402223);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
location.resflags:=getresflags(true);
|
location.resflags:=getfpuresflags;
|
||||||
location_freetemp(current_asmdata.CurrAsmList,left.location);
|
location_freetemp(current_asmdata.CurrAsmList,left.location);
|
||||||
location_freetemp(current_asmdata.CurrAsmList,right.location);
|
location_freetemp(current_asmdata.CurrAsmList,right.location);
|
||||||
end;
|
end;
|
||||||
@ -1259,7 +1286,7 @@ unit nx86add;
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
location_reset(location,LOC_FLAGS,OS_NO);
|
location_reset(location,LOC_FLAGS,OS_NO);
|
||||||
location.resflags:=getresflags(true);
|
location.resflags:=getfpuresflags;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
62
tests/test/units/math/tcmpnan.pp
Normal file
62
tests/test/units/math/tcmpnan.pp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{ Tests unordered comparison results. This is a basic codegeneration test, but it needs
|
||||||
|
Math unit to silence exceptions. }
|
||||||
|
uses math;
|
||||||
|
|
||||||
|
const
|
||||||
|
kNan = Sqrt(-1);
|
||||||
|
kX = 5.8E-7;
|
||||||
|
var
|
||||||
|
vNan, vX: real;
|
||||||
|
code: longint;
|
||||||
|
b: boolean;
|
||||||
|
begin
|
||||||
|
code:=0;
|
||||||
|
SetExceptionMask( [exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
|
||||||
|
if kNan = kX then code:=1;
|
||||||
|
if kNan < kX then code:=code or 2;
|
||||||
|
if kNan <= kX then code:=code or 4;
|
||||||
|
if kNan > kX then code:=code or 8;
|
||||||
|
if kNan >= kX then code:=code or 16;
|
||||||
|
code:=code or 32;
|
||||||
|
if kX <> kNan then code:=code and (not 32);
|
||||||
|
|
||||||
|
vNan:= kNan;
|
||||||
|
vX:= kX;
|
||||||
|
|
||||||
|
{ Test g_flag2reg/ref }
|
||||||
|
b:=(vNan = vX);
|
||||||
|
if b then code:=code or 64;
|
||||||
|
b:=(vNan < vX);
|
||||||
|
if b then code:=code or 128;
|
||||||
|
b:=(vNan <= vX);
|
||||||
|
if b then code:=code or 256;
|
||||||
|
b:=(vNan > vX);
|
||||||
|
if b then code:=code or 512;
|
||||||
|
b:=(vNan >= vX);
|
||||||
|
if b then code:=code or 1024;
|
||||||
|
b:=(vNan <> vX);
|
||||||
|
if (not b) then code:=code or 2048;
|
||||||
|
|
||||||
|
{ Test a_jmp_flags }
|
||||||
|
if vNan = vX then
|
||||||
|
code:=code or 4096;
|
||||||
|
if vNan < vX then
|
||||||
|
code:=code or 8192;
|
||||||
|
if vNan <= vX then
|
||||||
|
code:=code or 16384;
|
||||||
|
if vNan > vX then
|
||||||
|
code:=code or 32768;
|
||||||
|
if vNan >= vX then
|
||||||
|
code:=code or 65536;
|
||||||
|
|
||||||
|
code:=code or 131072;
|
||||||
|
if vNan <> vX then
|
||||||
|
code:=code and (not 131072);
|
||||||
|
|
||||||
|
if code=0 then
|
||||||
|
writeln('ok')
|
||||||
|
else
|
||||||
|
writeln('error: ',hexstr(code,8));
|
||||||
|
Halt(code);
|
||||||
|
end.
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user