* fixed location_free() for locations consisting of multiple

physical registers
  * free the physical return registers at the caller side for 64 bit
    systems
  * make sure that we do not double-free registers in case a return
    value is not used (mantis #13536)

git-svn-id: trunk@13023 -
This commit is contained in:
Jonas Maebe 2009-04-20 18:57:49 +00:00
parent 24ce200737
commit a4bf91001e
4 changed files with 188 additions and 38 deletions

1
.gitattributes vendored
View File

@ -8821,6 +8821,7 @@ tests/webtbs/tw13345x.pp svneol=native#text/plain
tests/webtbs/tw13456.pp svneol=native#text/plain tests/webtbs/tw13456.pp svneol=native#text/plain
tests/webtbs/tw1348.pp svneol=native#text/plain tests/webtbs/tw1348.pp svneol=native#text/plain
tests/webtbs/tw1351.pp svneol=native#text/plain tests/webtbs/tw1351.pp svneol=native#text/plain
tests/webtbs/tw13536.pp svneol=native#text/plain
tests/webtbs/tw1364.pp svneol=native#text/plain tests/webtbs/tw1364.pp svneol=native#text/plain
tests/webtbs/tw1365.pp svneol=native#text/plain tests/webtbs/tw1365.pp svneol=native#text/plain
tests/webtbs/tw1374.pp svneol=native#text/plain tests/webtbs/tw1374.pp svneol=native#text/plain

View File

@ -538,11 +538,22 @@ implementation
{$ifdef x86} {$ifdef x86}
tcgx86(cg).inc_fpu_stack; tcgx86(cg).inc_fpu_stack;
{$else x86} {$else x86}
if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then { Do not move the physical register to a virtual one in case
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register); the return value is not used, because if the virtual one is
hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size); then mapped to the same register as the physical one, we will
cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister); end up with two deallocs of this register (one inserted here,
location.register:=hregister; one inserted by the register allocator), which unbalances the
register allocation information. The return register(s) will
be freed by location_free() in release_unused_return_value
(mantis #13536). }
if (cnf_return_value_used in callnodeflags) then
begin
if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister);
location.register:=hregister;
end;
{$endif x86} {$endif x86}
end; end;
@ -556,12 +567,25 @@ implementation
structs with up to 16 bytes are returned in registers } structs with up to 16 bytes are returned in registers }
if cgsize in [OS_128,OS_S128] then if cgsize in [OS_128,OS_S128] then
begin begin
tg.GetTemp(current_asmdata.CurrAsmList,16,8,tt_normal,ref); retloc:=procdefinition.funcretloc[callerside];
location_reset_ref(location,LOC_REFERENCE,OS_NO,0); if retloc.loc<>LOC_REGISTER then
location.reference:=ref; internalerror(2009042001);
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].register,ref); { See #13536 comment above. }
inc(ref.offset,8); if (cnf_return_value_used in callnodeflags) then
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].registerhi,ref); begin
tg.GetTemp(current_asmdata.CurrAsmList,16,8,tt_normal,ref);
location_reset_ref(location,LOC_REFERENCE,OS_NO,0);
location.reference:=ref;
if getsupreg(retloc.register)<first_int_imreg then
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,retloc.register,ref);
inc(ref.offset,8);
if getsupreg(retloc.registerhi)<first_int_imreg then
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.registerhi);
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,retloc.registerhi,ref);
end
else
location:=retloc;
end end
else else
{$else cpu64bitaddr} {$else cpu64bitaddr}
@ -570,15 +594,21 @@ implementation
retloc:=procdefinition.funcretloc[callerside]; retloc:=procdefinition.funcretloc[callerside];
if retloc.loc<>LOC_REGISTER then if retloc.loc<>LOC_REGISTER then
internalerror(200409141); internalerror(200409141);
{ the function result registers are already allocated } { See #13536 comment above. }
if getsupreg(retloc.register64.reglo)<first_int_imreg then if (cnf_return_value_used in callnodeflags) then
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo); begin
location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32); { the function result registers are already allocated }
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo); if getsupreg(retloc.register64.reglo)<first_int_imreg then
if getsupreg(retloc.register64.reghi)<first_int_imreg then cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi); location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32); cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi); if getsupreg(retloc.register64.reghi)<first_int_imreg then
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
end
else
location:=retloc;
end end
else else
{$endif not cpu64bitaddr} {$endif not cpu64bitaddr}
@ -588,19 +618,25 @@ implementation
def_cgsize(resultdef) is used here because def_cgsize(resultdef) is used here because
it could be a constructor call } it could be a constructor call }
if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then { See #13536 comment above. }
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register); if (cnf_return_value_used in callnodeflags) then
begin
if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
{ but use def_size only if it returns something valid because in { but use def_size only if it returns something valid because in
case of odd sized structured results in registers def_cgsize(resultdef) case of odd sized structured results in registers def_cgsize(resultdef)
could return OS_NO } could return OS_NO }
if def_cgsize(resultdef)<>OS_NO then if def_cgsize(resultdef)<>OS_NO then
tmpcgsize:=def_cgsize(resultdef) tmpcgsize:=def_cgsize(resultdef)
else
tmpcgsize:=cgsize;
location.register:=cg.getintregister(current_asmdata.CurrAsmList,tmpcgsize);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,tmpcgsize,procdefinition.funcretloc[callerside].register,location.register);
end
else else
tmpcgsize:=cgsize; location:=procdefinition.funcretloc[callerside];
location.register:=cg.getintregister(current_asmdata.CurrAsmList,tmpcgsize);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,tmpcgsize,procdefinition.funcretloc[callerside].register,location.register);
end; end;
{$ifdef arm} {$ifdef arm}
if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
@ -618,11 +654,17 @@ implementation
LOC_MMREGISTER: LOC_MMREGISTER:
begin begin
location_reset(location,LOC_MMREGISTER,cgsize); { See #13536 comment above. }
if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then if (cnf_return_value_used in callnodeflags) then
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register); begin
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize); location_reset(location,LOC_MMREGISTER,cgsize);
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar); if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize);
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
end
else
location:=procdefinition.funcretloc[callerside];
end; end;
else else

View File

@ -185,8 +185,28 @@ implementation
LOC_REGISTER, LOC_REGISTER,
LOC_CREGISTER: LOC_CREGISTER:
begin begin
if getsupreg(location.register)<first_int_imreg then {$ifdef cpu64bitaddr}
cg.ungetcpuregister(list,location.register); { x86-64 system v abi:
structs with up to 16 bytes are returned in registers }
if location.size in [OS_128,OS_S128] then
begin
if getsupreg(location.register)<first_int_imreg then
cg.ungetcpuregister(list,location.register);
if getsupreg(location.registerhi)<first_int_imreg then
cg.ungetcpuregister(list,location.registerhi);
end
{$else cpu64bitaddr}
if location.size in [OS_64,OS_S64] then
begin
if getsupreg(location.register64.reglo)<first_int_imreg then
cg.ungetcpuregister(list,location.register64.reglo);
if getsupreg(location.register64.reghi)<first_int_imreg then
cg.ungetcpuregister(list,location.register64.reghi);
end
{$endif}
else
if getsupreg(location.register)<first_int_imreg then
cg.ungetcpuregister(list,location.register);
end; end;
LOC_FPUREGISTER, LOC_FPUREGISTER,
LOC_CFPUREGISTER: LOC_CFPUREGISTER:

87
tests/webtbs/tw13536.pp Normal file
View File

@ -0,0 +1,87 @@
// without -O3 prints 0002020200010101
// with -O3 prints 0001010100010101
{$mode objfpc}{$H+}
uses sysutils;
Const
MAXDWORD = $FFFFFFFF;
Type
Filetime=longint;
tchar=char;
XWIN32_FIND_DATA = record
dwFileAttributes : DWORD;
ftLastWriteTime : FILETIME;
nFileSizeHigh : DWORD;
nFileSizeLow : DWORD;
cFileName : array[0..(MAX_PATH)-1] of TCHAR;
end;
Type
TMySearchRec = Record
Time : Longint;
Size : Int64;
Attr : Longint;
Name : TFileName;
ExcludeAttr : Longint;
FindHandle : THandle;
FindData : XWIN32_FIND_DATA;
end;
function getlasterror:integer;
begin
end;
function aFindNextFile (F:thandle;fd:XWIN32_FIND_DATA):boolean;
begin
end;
function WinToDosTime( Var Wtime : FileTime;var DTime:longint):longbool;
begin
end;
Function aFindMatch(var f: TMySearchRec) : Longint;
begin
// commenting code before the f.size:= line seems to alter the behaviour
{ Find file with correct attribute }
While (F.FindData.dwFileAttributes and cardinal(F.ExcludeAttr))<>0 do
begin
if not aFindNextFile (F.FindHandle,F.FindData) then
begin
Result:=GetLastError;
exit;
end;
end;
{ Convert some attributes back }
WinToDosTime(F.FindData.ftLastWriteTime,F.Time);
f.size:=F.FindData.NFileSizeLow+(qword(maxdword)+1)*F.FindData.NFileSizeHigh;
f.attr:=F.FindData.dwFileAttributes;
f.Name:=StrPas(@F.FindData.cFileName[0]);
Result:=0;
end;
var n : TMySearchRec;
begin
// make sure it gets past the while loop.
n.finddata.dwfileattributes:=1;
n.excludeattr:=0;
n.FindData.NFileSizeLow:=$10101;
n.FindData.NFileSizehigh:=$20202;
// attempt to avoid problems with strpas.
n.finddata.cfilename:='bla'#0;
aFindMatch(n);
writeln(n.size);
writeln(inttohex(n.size,16));
if (n.size<>$0002020200010101) then
halt(1);
end.