diff --git a/CGC.asm b/CGC.asm index a70587e..a446c93 100644 --- a/CGC.asm +++ b/CGC.asm @@ -252,3 +252,24 @@ maxLabel equ 3200 stz intLabel intLabel := 0; rtl end + datachk on + +**************************************************************** +* +* function SignBit (val: extended): integer; +* +* returns the sign bit of a floating-point number +* (0 for positive, 1 for negative) +* +**************************************************************** +* +SignBit start cg + + subroutine (10:val),0 + + asl val+8 + stz val + rol val + + return 2:val + end diff --git a/CGC.pas b/CGC.pas index 23970df..da4b3a5 100644 --- a/CGC.pas +++ b/CGC.pas @@ -107,6 +107,12 @@ procedure InitLabels; extern; { } { Note: also defined in CGI.pas } + +function SignBit (val: extended): integer; extern; + +{ returns the sign bit of a floating-point number } +{ (0 for positive, 1 for negative) } + {-- These routines are defined in the compiler, but used from cg --} function Calloc (bytes: integer): ptr; extern; diff --git a/CGI.pas b/CGI.pas index 92b1e7b..cc2fccf 100644 --- a/CGI.pas +++ b/CGI.pas @@ -327,6 +327,7 @@ var debugFlag: boolean; {generate debugger calls?} debugStrFlag: boolean; {gsbug/niftylist debug names?} dataBank: boolean; {save, restore data bank?} + fastMath: boolean; {do FP math opts that break IEEE rules?} floatCard: integer; {0 -> SANE; 1 -> FPE} floatSlot: integer; {FPE slot} loopOptimizations: boolean; {do loop optimizations?} @@ -817,6 +818,7 @@ volatile := false; {no volatile qualifiers found} registers := cLineOptimize; {don't do register optimizations} peepHole := cLineOptimize; {not doing peephole optimization (yet)} npeepHole := cLineOptimize; +fastMath := cLineOptimize; commonSubexpression := cLineOptimize; {not doing common subexpression elimination} loopOptimizations := cLineOptimize; {not doing loop optimizations, yet} diff --git a/DAG.pas b/DAG.pas index f969e3b..3e9721a 100644 --- a/DAG.pas +++ b/DAG.pas @@ -198,7 +198,9 @@ else if (op1 <> nil) and (op2 <> nil) then CodesMatch := true; cgReal, cgDouble, cgComp, cgExtended: if op1^.rval = op2^.rval then - CodesMatch := true; + if (SignBit(op1^.rval) = SignBit(op2^.rval)) + or fastMath then + CodesMatch := true; cgString: CodesMatch := LongStrCmp(op1^.str, op2^.str); cgVoid, ccPointer: @@ -899,8 +901,9 @@ case op^.opcode of {check for optimizations of this node} if op^.left^.opcode = pc_ldc then ReverseChildren(op); if op^.right^.opcode = pc_ldc then begin - if op^.right^.rval = 0.0 then - opv := op^.left; + if fastMath then + if op^.right^.rval = 0.0 then + opv := op^.left; end; {if} end; {else} end; {case pc_adr} @@ -2069,8 +2072,9 @@ case op^.opcode of {check for optimizations of this node} if rval = 1.0 then opv := op^.left else if rval = 0.0 then - if not SideEffects(op^.left) then - opv := op^.right; + if fastMath then + if not SideEffects(op^.left) then + opv := op^.right; end; {if} end; {else} end; {case pc_mpr} @@ -2346,15 +2350,17 @@ case op^.opcode of {check for optimizations of this node} op^.left^.rval := op^.left^.rval - op^.right^.rval; opv := op^.left; end {if} - else if op^.left^.rval = 0.0 then begin - op^.opcode := pc_ngr; - op^.left := op^.right; - op^.right := nil; - end; {else if} + else if op^.left^.rval = 0.0 then + if fastMath then begin + op^.opcode := pc_ngr; + op^.left := op^.right; + op^.right := nil; + end; {if} end {if} else if op^.right^.opcode = pc_ldc then begin - if op^.right^.rval = 0.0 then - opv := op^.left; + if fastMath then + if op^.right^.rval = 0.0 then + opv := op^.left; end; {if} end; {case pc_sbr} diff --git a/Header.pas b/Header.pas index 38637c7..494dc27 100644 --- a/Header.pas +++ b/Header.pas @@ -18,7 +18,7 @@ uses CCommon, MM, Scanner, Symbol, CGI; {$segment 'SCANNER'} const - symFileVersion = 18; {version number of .sym file format} + symFileVersion = 19; {version number of .sym file format} var inhibitHeader: boolean; {should .sym includes be blocked?} @@ -845,7 +845,8 @@ procedure EndInclude {chPtr: ptr}; | (ord(saveStack) << 3) | (ord(commonSubexpression) << 4) | (ord(loopOptimizations) << 5) - | (ord(strictVararg) << 6)); + | (ord(strictVararg) << 6) + | (ord(fastMath) << 7)); p_stacksize: WriteWord(stackSize); @@ -1508,6 +1509,7 @@ var commonSubexpression := odd(val >> 4); loopOptimizations := odd(val >> 5); strictVararg := odd(val >> 6); + fastMath := odd(val >> 7); end; p_stacksize: stackSize := ReadWord; diff --git a/Scanner.pas b/Scanner.pas index 86a78ab..ced48dc 100644 --- a/Scanner.pas +++ b/Scanner.pas @@ -3139,6 +3139,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin { 16 - common subexpression elimination } { 32 - loop invariant removal } { 64 - remove stack checks for vararg calls} + { 128 - fp math opts that break IEEE rules } FlagPragmas(p_optimize); NumericDirective; if expressionType^.kind = scalarType then @@ -3152,6 +3153,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin commonSubexpression := odd(val >> 4); loopOptimizations := odd(val >> 5); strictVararg := not odd(val >> 6); + fastMath := odd(val >> 7); if saveStack then npeepHole := false; if token.kind <> eolsy then diff --git a/cc.notes b/cc.notes index cb374f7..e0772d7 100644 --- a/cc.notes +++ b/cc.notes @@ -492,6 +492,14 @@ Using the extended format provides greater precision and range than the float or If you want to get a value strictly in a certain type with no extra range or precision, you can store it in a variable of that type or explicitly cast it to that type. (In older versions of ORCA/C, floating-point casts did not remove extra range or precision, but now they do, as required by the C standards.) +Floating-Point Optimizations +---------------------------- + +ORCA/C can perform certain optimizations on floating-point computations based on properties that are true for real numbers but are not always true in the IEEE floating-point arithmetic system. In particular, these optimizations can occasionally cause behavior that differs from the IEEE standard in regard to infinities, NaNs, or the sign of zero. Historically, these optimizations were performed mainly as part of intermediate code peephole optimization and in some cases also as part of common subexpression elimination. + +A new #pragma optimize bit has now been introduced to control this behavior. Setting bit 7 (a value of 128) allows floating-point math optimizations that may violate the IEEE standard. It currently only has an effect if #pragma optimize bit 0 or bit 4 is also set. If bit 7 is not set, these floating-point optimizations will not be performed. This allows most aspects of intermediate code peephole optimization and common subexpression elimination to be used while preserving IEEE floating-point behavior. + + Additions to #pragma ignore --------------------------- Several additional #pragma ignore bits are now supported.