mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 10:09:20 +02:00
* parameter passing support for AIX:
o the last bytes of records passed by value whose size is not a multiple of the register size must be passed in the upper (leftmost) bytes of a register git-svn-id: trunk@20804 -
This commit is contained in:
parent
273b90fc37
commit
dc70db9402
@ -899,6 +899,8 @@ implementation
|
|||||||
begin
|
begin
|
||||||
cgpara.check_simple_location;
|
cgpara.check_simple_location;
|
||||||
paramanager.alloccgpara(list,cgpara);
|
paramanager.alloccgpara(list,cgpara);
|
||||||
|
if cgpara.location^.shiftval<0 then
|
||||||
|
a_op_const_reg(list,OP_SHL,cgpara.location^.size,-cgpara.location^.shiftval,r);
|
||||||
case cgpara.location^.loc of
|
case cgpara.location^.loc of
|
||||||
LOC_REGISTER,LOC_CREGISTER:
|
LOC_REGISTER,LOC_CREGISTER:
|
||||||
a_load_reg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register);
|
a_load_reg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register);
|
||||||
@ -974,6 +976,8 @@ implementation
|
|||||||
begin
|
begin
|
||||||
cgpara.check_simple_location;
|
cgpara.check_simple_location;
|
||||||
a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
|
a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
|
||||||
|
if location^.shiftval<0 then
|
||||||
|
a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
|
||||||
end
|
end
|
||||||
{ there's a lot more data left, and the current paraloc's
|
{ there's a lot more data left, and the current paraloc's
|
||||||
register is entirely filled with part of that data }
|
register is entirely filled with part of that data }
|
||||||
@ -987,6 +991,8 @@ implementation
|
|||||||
else if (sizeleft in [1,2{$ifndef cpu16bitalu},4{$endif}{$ifdef cpu64bitalu},8{$endif}]) then
|
else if (sizeleft in [1,2{$ifndef cpu16bitalu},4{$endif}{$ifdef cpu64bitalu},8{$endif}]) then
|
||||||
begin
|
begin
|
||||||
a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
|
a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
|
||||||
|
if location^.shiftval<0 then
|
||||||
|
a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
|
||||||
end
|
end
|
||||||
{ we're at the end of the data, and we need multiple loads
|
{ we're at the end of the data, and we need multiple loads
|
||||||
to get it in the register because it's an irregular size }
|
to get it in the register because it's an irregular size }
|
||||||
@ -1047,6 +1053,8 @@ implementation
|
|||||||
a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
|
a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
|
||||||
inc(tmpref.offset);
|
inc(tmpref.offset);
|
||||||
end;
|
end;
|
||||||
|
if location^.shiftval<0 then
|
||||||
|
a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
|
||||||
{ the loop will already adjust the offset and sizeleft }
|
{ the loop will already adjust the offset and sizeleft }
|
||||||
dec(tmpref.offset,orgsizeleft);
|
dec(tmpref.offset,orgsizeleft);
|
||||||
sizeleft:=orgsizeleft;
|
sizeleft:=orgsizeleft;
|
||||||
@ -1128,15 +1136,28 @@ implementation
|
|||||||
procedure tcg.a_load_cgparaloc_ref(list : TAsmList;const paraloc : TCGParaLocation;const ref : treference;sizeleft : tcgint;align : longint);
|
procedure tcg.a_load_cgparaloc_ref(list : TAsmList;const paraloc : TCGParaLocation;const ref : treference;sizeleft : tcgint;align : longint);
|
||||||
var
|
var
|
||||||
href : treference;
|
href : treference;
|
||||||
|
hreg : tregister;
|
||||||
|
cgsize: tcgsize;
|
||||||
begin
|
begin
|
||||||
case paraloc.loc of
|
case paraloc.loc of
|
||||||
LOC_REGISTER :
|
LOC_REGISTER :
|
||||||
begin
|
begin
|
||||||
{$IFDEF POWERPC64}
|
hreg:=paraloc.register;
|
||||||
if (paraloc.shiftval <> 0) then
|
cgsize:=paraloc.size;
|
||||||
a_op_const_reg_reg(list, OP_SHL, OS_INT, paraloc.shiftval, paraloc.register, paraloc.register);
|
if paraloc.shiftval>0 then
|
||||||
{$ENDIF POWERPC64}
|
a_op_const_reg_reg(list,OP_SHL,OS_INT,paraloc.shiftval,paraloc.register,paraloc.register)
|
||||||
a_load_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref);
|
else if (paraloc.shiftval<0) and
|
||||||
|
(sizeleft in [1,2,4]) then
|
||||||
|
begin
|
||||||
|
a_op_const_reg_reg(list,OP_SHR,OS_INT,-paraloc.shiftval,paraloc.register,paraloc.register);
|
||||||
|
{ convert to a register of 1/2/4 bytes in size, since the
|
||||||
|
original register had to be made larger to be able to hold
|
||||||
|
the shifted value }
|
||||||
|
cgsize:=int_cgsize(tcgsize2size[OS_INT]-(-paraloc.shiftval div 8));
|
||||||
|
hreg:=getintregister(list,cgsize);
|
||||||
|
a_load_reg_reg(list,OS_INT,cgsize,paraloc.register,hreg);
|
||||||
|
end;
|
||||||
|
a_load_reg_ref(list,paraloc.size,cgsize,hreg,ref);
|
||||||
end;
|
end;
|
||||||
LOC_MMREGISTER :
|
LOC_MMREGISTER :
|
||||||
begin
|
begin
|
||||||
@ -1175,6 +1196,8 @@ implementation
|
|||||||
case paraloc.loc of
|
case paraloc.loc of
|
||||||
LOC_REGISTER :
|
LOC_REGISTER :
|
||||||
begin
|
begin
|
||||||
|
if paraloc.shiftval<0 then
|
||||||
|
a_op_const_reg_reg(list,OP_SHR,OS_INT,-paraloc.shiftval,paraloc.register,paraloc.register);
|
||||||
case getregtype(reg) of
|
case getregtype(reg) of
|
||||||
R_INTREGISTER:
|
R_INTREGISTER:
|
||||||
a_load_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);
|
a_load_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);
|
||||||
|
@ -48,7 +48,11 @@ unit parabase;
|
|||||||
LOC_CMMREGISTER,
|
LOC_CMMREGISTER,
|
||||||
LOC_REGISTER,
|
LOC_REGISTER,
|
||||||
LOC_CREGISTER : (
|
LOC_CREGISTER : (
|
||||||
{ The number of bits the value in the register must be shifted to the left before
|
{
|
||||||
|
|
||||||
|
* If shiftval > 0:
|
||||||
|
|
||||||
|
The number of bits the value in the register must be shifted to the left before
|
||||||
it can be stored to memory in the function prolog.
|
it can be stored to memory in the function prolog.
|
||||||
This is used for passing OS_NO memory blocks less than register size and of "odd"
|
This is used for passing OS_NO memory blocks less than register size and of "odd"
|
||||||
(3, 5, 6, 7) size on big endian machines, so that small memory blocks passed via
|
(3, 5, 6, 7) size on big endian machines, so that small memory blocks passed via
|
||||||
@ -56,8 +60,15 @@ unit parabase;
|
|||||||
|
|
||||||
E.g. the value $5544433 is passed in bits 40-63 of the register (others are zero),
|
E.g. the value $5544433 is passed in bits 40-63 of the register (others are zero),
|
||||||
but they should actually be stored in the first bits of the stack location reserved
|
but they should actually be stored in the first bits of the stack location reserved
|
||||||
for this value. So they have to be shifted left by this amount of bits before. }
|
for this value. So they have to be shifted left by this amount of bits before.
|
||||||
{$IFDEF POWERPC64}shiftval : byte;{$ENDIF POWERPC64}
|
|
||||||
|
* if shiftval < 0:
|
||||||
|
|
||||||
|
Similar as above, but the shifting must always be done and
|
||||||
|
1) for all parameter sizes < regsize
|
||||||
|
2) on the caller side
|
||||||
|
}
|
||||||
|
shiftval : shortint;
|
||||||
register : tregister);
|
register : tregister);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -281,9 +292,7 @@ implementation
|
|||||||
LOC_REGISTER,
|
LOC_REGISTER,
|
||||||
LOC_CREGISTER :
|
LOC_CREGISTER :
|
||||||
begin
|
begin
|
||||||
{$ifdef powerpc64}
|
|
||||||
ppufile.putbyte(hparaloc^.shiftval);
|
ppufile.putbyte(hparaloc^.shiftval);
|
||||||
{$endif}
|
|
||||||
ppufile.putlongint(longint(hparaloc^.register));
|
ppufile.putlongint(longint(hparaloc^.register));
|
||||||
end;
|
end;
|
||||||
{ This seems to be required for systems using explicitparaloc (eg. MorphOS)
|
{ This seems to be required for systems using explicitparaloc (eg. MorphOS)
|
||||||
@ -331,9 +340,7 @@ implementation
|
|||||||
LOC_REGISTER,
|
LOC_REGISTER,
|
||||||
LOC_CREGISTER :
|
LOC_CREGISTER :
|
||||||
begin
|
begin
|
||||||
{$ifdef powerpc64}
|
|
||||||
hparaloc^.shiftval:=ppufile.getbyte;
|
hparaloc^.shiftval:=ppufile.getbyte;
|
||||||
{$endif}
|
|
||||||
hparaloc^.register:=tregister(ppufile.getlongint);
|
hparaloc^.register:=tregister(ppufile.getlongint);
|
||||||
end;
|
end;
|
||||||
{ This seems to be required for systems using explicitparaloc (eg. MorphOS)
|
{ This seems to be required for systems using explicitparaloc (eg. MorphOS)
|
||||||
|
@ -366,6 +366,7 @@ implementation
|
|||||||
len:=tcgsize2size[paraloc^.size];
|
len:=tcgsize2size[paraloc^.size];
|
||||||
newparaloc:=cgpara.add_location;
|
newparaloc:=cgpara.add_location;
|
||||||
newparaloc^.size:=paraloc^.size;
|
newparaloc^.size:=paraloc^.size;
|
||||||
|
newparaloc^.shiftval:=paraloc^.shiftval;
|
||||||
{ $warning maybe release this optimization for all targets? }
|
{ $warning maybe release this optimization for all targets? }
|
||||||
{ released for all CPUs:
|
{ released for all CPUs:
|
||||||
i386 isn't affected anyways because it uses the stack to push parameters
|
i386 isn't affected anyways because it uses the stack to push parameters
|
||||||
|
@ -137,9 +137,10 @@ unit cpupara;
|
|||||||
else
|
else
|
||||||
result:=LOC_REFERENCE;
|
result:=LOC_REFERENCE;
|
||||||
recorddef:
|
recorddef:
|
||||||
if (target_info.abi<>abi_powerpc_aix) or
|
if not(target_info.system in systems_aix) and
|
||||||
((p.size >= 3) and
|
((target_info.abi<>abi_powerpc_aix) or
|
||||||
((p.size mod 4) <> 0)) then
|
((p.size >= 3) and
|
||||||
|
((p.size mod 4) <> 0))) then
|
||||||
result:=LOC_REFERENCE
|
result:=LOC_REFERENCE
|
||||||
else
|
else
|
||||||
result:=LOC_REGISTER;
|
result:=LOC_REGISTER;
|
||||||
@ -501,6 +502,15 @@ unit cpupara;
|
|||||||
paraloc^.size := OS_INT
|
paraloc^.size := OS_INT
|
||||||
else
|
else
|
||||||
paraloc^.size := paracgsize;
|
paraloc^.size := paracgsize;
|
||||||
|
{ aix requires that record data stored in parameter
|
||||||
|
registers is left-aligned }
|
||||||
|
if (target_info.system in systems_aix) 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;
|
||||||
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
|
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
|
||||||
inc(nextintreg);
|
inc(nextintreg);
|
||||||
dec(paralen,tcgsize2size[paraloc^.size]);
|
dec(paralen,tcgsize2size[paraloc^.size]);
|
||||||
@ -561,9 +571,11 @@ unit cpupara;
|
|||||||
tppcprocinfo(current_procinfo).needs_frame_pointer := true;
|
tppcprocinfo(current_procinfo).needs_frame_pointer := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if (target_info.abi = abi_powerpc_aix) and
|
if not((target_info.system in systems_aix) and
|
||||||
|
(paradef.typ=recorddef)) and
|
||||||
|
(target_info.abi = abi_powerpc_aix) and
|
||||||
(hp.paraloc[side].intsize < 3) then
|
(hp.paraloc[side].intsize < 3) then
|
||||||
paraloc^.reference.offset:=stack_offset+(4-paralen)
|
paraloc^.reference.offset:=stack_offset+(4-paralen)
|
||||||
else
|
else
|
||||||
paraloc^.reference.offset:=stack_offset;
|
paraloc^.reference.offset:=stack_offset;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user