[fpc-devel] Code generation in function with absolute Result construct and $O+
Arnstein Prytz
arnstein at balagorang.com
Mon Jun 13 03:46:34 CEST 2022
I have come across what appears to be a code-generation bug when
using 'absolute' to reference the 'Result' variable in a function
with compiler directive $O+.
Free Pascal Compiler version 3.2.2 [2021/07/09] for x86_64
Running under Linux Mint.
The following program illustrates the problem, with failing
calls indicated by '<FAIL' in the output. Changing $O+ to $O-
results in the program running correctly.
Looking at the assembler code generated by fpc -a shows that
xmm0 is not updated with the modified Result variable after the
sign has been modified. Of course, I am assuming that even under
$O+ the function result is passed back to the caller in xmm0.
I know that there is a better way to calculate |Mth_Sign| than
the below; this is older code which I have ported from Delphi
to fpc on Linux only recently and my own standard tests found
this failure.
{$MODE Delphi}
{$O+}
program tmp;
type
Int8 = System.ShortInt; {|-128..127|}
UInt8 = System.Byte; {|0..255|}
Int16 = System.SmallInt; {|-32768..32767|}
UInt16 = System.Word; {|0..65535|}
Int32 = System.LongInt; {|-2147483648..2147483647|}
integer = Int32;
Extended = Double;
Extended_Record =
packed record
case integer of
1: (rx_Real: Extended);
2: (rx_UInt8: array [1..SizeOf(Extended)] of UInt8);
3: (rx_ULow8: array [1..SizeOf(Extended) - SizeOf(Int8)] of UInt8;
rx_Sign8: Int8);
4: (rx_UInt16: array [1..SizeOf(Extended) div SizeOf(UInt16)] of UInt16);
5: (rx_ULow16: array [1..(SizeOf(Extended) - SizeOf(Int16)) div SizeOf(UInt16)] of UInt16;
rx_Sign16: Int16);
6: (rx_UInt32: array [1..SizeOf(Extended) div SizeOf(UInt32)] of UInt32);
7: (rx_Pad16: array [1..(SizeOf(Extended) - SizeOf(Int32)) div SizeOf(UInt16)] of UInt16;
rx_Sign32: Int32);
8: (rx_Set: set of 0..8*SizeOf(Extended) - 1);
end;
function Mth_Sign(
const _value: Extended;
const _sign: integer): Extended;
var
v: Extended_Record absolute _value;
r: Extended_Record absolute Result;
begin
Mth_Sign := _value;
if _sign < 0
then r.rx_Sign8 := v.rx_Sign8 or $80
else r.rx_Sign8 := v.rx_Sign8 and $7F;
end;
procedure test_sign;
type
i_index = 1..3;
r_index = 1..4;
const
i_list: array [i_index] of integer = (-23456, 0, 12976644);
i_signs: array [i_index] of integer = (-1, 1, 1);
r_list: array [r_index] of real = (-23.456E+22, 0, -0.0, 1297.6644E-19);
var
j, k: Cardinal;
m: integer;
p, r: real;
begin
for j := Low(r_list) to High(r_list)
do begin
p := r_list[j];
for k := Low(i_list) to High(i_list)
do begin
m := i_list[k];
write('Mth_Sign(', p:15, ',', m:8, ')=');
r := Mth_Sign(p, m);
write(r:15);
if r <> abs(p)*i_signs[k]
then write('<FAIL');
writeln;
end;
end;
end;
begin
test_sign;
end.
--
Arnstein.
More information about the fpc-devel
mailing list