* MIPS: fixed parameter management to properly align records smaller than 32 bits on big-endian targets.

* Also changed parameter management to allocate a single LOC_REFERENCE location for any parameter (or part of a parameter) passed on stack. Such locations can now be handled by generic code. As a consequence, TGMIPS.a_load_const_cgpara and a_load_ref_cgpara methods are no longer necessary (moreover they were ignoring parameter shifting).
* a_loadfpu_ref_cgpara patched to handle 64-bit location, which are now possible.

* This change eliminates code generation madness where each word of a record was copied individually, thus passing by value a 32K-word sized record was bloating into 64K instructions, multiply this number by 2 for larger records due to limited immediate offsets, and by another 2 for global record in PIC mode :/

git-svn-id: trunk@23575 -
This commit is contained in:
sergei 2013-02-05 22:21:09 +00:00
parent c6c67dc182
commit d82387ff72
2 changed files with 26 additions and 61 deletions

View File

@ -49,8 +49,6 @@ type
procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
{ parameter }
procedure a_load_const_cgpara(list: tasmlist; size: tcgsize; a: tcgint; const paraloc: TCGPara); override;
procedure a_load_ref_cgpara(list: tasmlist; sz: tcgsize; const r: TReference; const paraloc: TCGPara); override;
procedure a_loadaddr_ref_cgpara(list: tasmlist; const r: TReference; const paraloc: TCGPara); override;
procedure a_loadfpu_reg_cgpara(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); override;
procedure a_loadfpu_ref_cgpara(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara); override;
@ -543,60 +541,6 @@ begin
end;
procedure TCGMIPS.a_load_const_cgpara(list: tasmlist; size: tcgsize; a: tcgint; const paraloc: TCGPara);
var
Ref: TReference;
begin
paraloc.check_simple_location;
paramanager.allocparaloc(list,paraloc.location);
case paraloc.location^.loc of
LOC_REGISTER, LOC_CREGISTER:
a_load_const_reg(list, size, a, paraloc.location^.Register);
LOC_REFERENCE:
begin
with paraloc.location^.Reference do
begin
if (Index = NR_SP) and (Offset < 0) then
InternalError(2002081104);
reference_reset_base(ref, index, offset, sizeof(aint));
end;
a_load_const_ref(list, size, a, ref);
end;
else
InternalError(2002122200);
end;
end;
procedure TCGMIPS.a_load_ref_cgpara(list: tasmlist; sz: TCgSize; const r: TReference; const paraloc: TCGPara);
var
href, href2: treference;
hloc: pcgparalocation;
begin
href := r;
hloc := paraloc.location;
while assigned(hloc) do
begin
paramanager.allocparaloc(list,hloc);
case hloc^.loc of
LOC_REGISTER,LOC_CREGISTER:
a_load_ref_reg(list, hloc^.size, hloc^.size, href, hloc^.Register);
LOC_FPUREGISTER,LOC_CFPUREGISTER :
a_loadfpu_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
LOC_REFERENCE:
begin
reference_reset_base(href2, hloc^.reference.index, hloc^.reference.offset, sizeof(aint));
a_load_ref_ref(list, hloc^.size, hloc^.size, href, href2);
end
else
internalerror(200408241);
end;
Inc(href.offset, tcgsize2size[hloc^.size]);
hloc := hloc^.Next;
end;
end;
procedure TCGMIPS.a_loadaddr_ref_cgpara(list: tasmlist; const r: TReference; const paraloc: TCGPara);
var
Ref: TReference;
@ -630,6 +574,9 @@ var
href, href2: treference;
hloc: pcgparalocation;
begin
{ TODO: inherited cannot deal with individual locations for each of OS_32 registers.
Must change parameter management to allocate a single 64-bit register pair,
then this method can be removed. }
href := ref;
hloc := paraloc.location;
while assigned(hloc) do
@ -642,8 +589,10 @@ begin
a_loadfpu_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
LOC_REFERENCE:
begin
reference_reset_base(href2, hloc^.reference.index, hloc^.reference.offset, sizeof(aint));
a_load_ref_ref(list, hloc^.size, hloc^.size, href, href2);
paraloc.check_simple_location;
reference_reset_base(href2,paraloc.location^.reference.index,paraloc.location^.reference.offset,paraloc.alignment);
{ concatcopy should choose the best way to copy the data }
g_concatcopy(list,ref,href2,tcgsize2size[size]);
end;
else
internalerror(200408241);

View File

@ -384,6 +384,17 @@ implementation
paraloc^.size:=OS_32
else
paraloc^.size:=paracgsize;
{ big-endian targets require that record data stored in parameter
registers is left-aligned }
if (target_info.endian=endian_big) and
(paradef.typ = recorddef) and
(tcgsize2size[paraloc^.size] <> sizeof(aint)) then
begin
paraloc^.shiftval := (sizeof(aint)-tcgsize2size[paraloc^.size])*(-8);
paraloc^.size := OS_INT;
end;
{ ret in param? }
if (vo_is_funcret in hp.varoptions) and
is_abi_record(hp.vardef) then
@ -393,7 +404,7 @@ implementation
begin
TMIPSProcInfo(current_procinfo).register_used[0]:=true;
TMIPSProcInfo(current_procinfo).register_name[0]:='result';
TMIPSProcInfo(current_procinfo).register_size[0]:=paracgsize;
TMIPSProcInfo(current_procinfo).register_size[0]:=paraloc^.size;
TMIPSProcInfo(current_procinfo).register_offset[0]:=0;
end;
//if (intparareg<>1) then
@ -453,7 +464,7 @@ implementation
begin
TMIPSProcInfo(current_procinfo).register_used[intparareg]:=true;
TMIPSProcInfo(current_procinfo).register_name[intparareg]:=hp.prettyname;
TMIPSProcInfo(current_procinfo).register_size[intparareg]:=paracgsize;
TMIPSProcInfo(current_procinfo).register_size[intparareg]:=paraloc^.size;
TMIPSProcInfo(current_procinfo).register_offset[intparareg]:=intparareg*mips_sizeof_register_param;
end;
if side=callerside then
@ -481,14 +492,18 @@ implementation
else
begin
paraloc^.loc:=LOC_REFERENCE;
paraloc^.size:=int_cgsize(paralen);
{ Force size to multiple of 4 for records passed by value,
to obtain correct memory layout for big endian }
(*
if (paradef.typ = recorddef) and
(tcgsize2size[paraloc^.size] < tcgsize2size[OS_32]) then
begin
inc(paralen,tcgsize2size[OS_32]-tcgsize2size[paraloc^.size]);
paraloc^.size := OS_32;
end;
*)
if side=callerside then
begin
paraloc^.reference.index := NR_STACK_POINTER_REG;
@ -506,7 +521,8 @@ implementation
end;
paraloc^.reference.offset:=intparasize;
end;
inc(intparasize,align(tcgsize2size[paraloc^.size],mips_sizeof_register_param));
inc(intparasize,align(paralen,mips_sizeof_register_param));
paralen:=0;
end;
dec(paralen,tcgsize2size[paraloc^.size]);
end;