mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-22 13:29:21 +02:00
* m68k: Fixed parameter passing to conform to ABI:
* records are passed by value * records with size of 1,2 or 4 are returned in registers * parameters with size<4 are justified on the stack according to big-endian target Now everything except floating-point parameters is compatible with C code compiled with "-malign-int -mrtd". Compatibility with "-mno-align-int" is achievable by changing target_info.maxCrecordalign to 2, but doings so causes a lot more troubles because RTL (incorrectly) assumes that records declared with {$PACKRECORDS C} are aligned to pointer size. + Reuse parameter locations. Since everything is passed on stack, it reduces code size quite a bit. - tm68kparamanager.getintparaloc removed, generic implementation has been tested and works as expected. git-svn-id: trunk@28083 -
This commit is contained in:
parent
140ce2a880
commit
acd3ea8750
@ -815,17 +815,14 @@ unit cgcpu;
|
|||||||
|
|
||||||
procedure tcg68k.a_load_reg_ref(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);
|
procedure tcg68k.a_load_reg_ref(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);
|
||||||
var
|
var
|
||||||
href : treference;
|
href : treference;
|
||||||
size : tcgsize;
|
|
||||||
begin
|
begin
|
||||||
href := ref;
|
href := ref;
|
||||||
fixref(list,href);
|
fixref(list,href);
|
||||||
if tcgsize2size[fromsize]<tcgsize2size[tosize] then
|
if tcgsize2size[fromsize]<tcgsize2size[tosize] then
|
||||||
size:=fromsize
|
a_load_reg_reg(list,fromsize,tosize,register,register);
|
||||||
else
|
|
||||||
size:=tosize;
|
|
||||||
{ move to destination reference }
|
{ move to destination reference }
|
||||||
list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[size],register,href));
|
list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[tosize],register,href));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1506,7 +1503,6 @@ unit cgcpu;
|
|||||||
hp2 : treference;
|
hp2 : treference;
|
||||||
hl : tasmlabel;
|
hl : tasmlabel;
|
||||||
srcref,dstref : treference;
|
srcref,dstref : treference;
|
||||||
alignsize : tcgsize;
|
|
||||||
orglen : tcgint;
|
orglen : tcgint;
|
||||||
begin
|
begin
|
||||||
hregister := getintregister(list,OS_INT);
|
hregister := getintregister(list,OS_INT);
|
||||||
@ -1530,14 +1526,7 @@ unit cgcpu;
|
|||||||
{ move a word }
|
{ move a word }
|
||||||
if len>1 then
|
if len>1 then
|
||||||
begin
|
begin
|
||||||
if (orglen<sizeof(aint)) and
|
a_load_ref_reg(list,OS_16,OS_16,srcref,hregister);
|
||||||
(source.base=NR_FRAME_POINTER_REG) and
|
|
||||||
(source.offset>0) then
|
|
||||||
{ copy of param to local location }
|
|
||||||
alignsize:=OS_INT
|
|
||||||
else
|
|
||||||
alignsize:=OS_16;
|
|
||||||
a_load_ref_reg(list,alignsize,alignsize,srcref,hregister);
|
|
||||||
a_load_reg_ref(list,OS_16,OS_16,hregister,dstref);
|
a_load_reg_ref(list,OS_16,OS_16,hregister,dstref);
|
||||||
inc(srcref.offset,2);
|
inc(srcref.offset,2);
|
||||||
inc(dstref.offset,2);
|
inc(dstref.offset,2);
|
||||||
@ -1546,14 +1535,7 @@ unit cgcpu;
|
|||||||
{ move a single byte }
|
{ move a single byte }
|
||||||
if len>0 then
|
if len>0 then
|
||||||
begin
|
begin
|
||||||
if (orglen<sizeof(aint)) and
|
a_load_ref_reg(list,OS_8,OS_8,srcref,hregister);
|
||||||
(source.base=NR_FRAME_POINTER_REG) and
|
|
||||||
(source.offset>0) then
|
|
||||||
{ copy of param to local location }
|
|
||||||
alignsize:=OS_INT
|
|
||||||
else
|
|
||||||
alignsize:=OS_8;
|
|
||||||
a_load_ref_reg(list,alignsize,alignsize,srcref,hregister);
|
|
||||||
a_load_reg_ref(list,OS_8,OS_8,hregister,dstref);
|
a_load_reg_ref(list,OS_8,OS_8,hregister,dstref);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -39,7 +39,8 @@ unit cpupara;
|
|||||||
rtl are used.
|
rtl are used.
|
||||||
}
|
}
|
||||||
tm68kparamanager = class(tparamanager)
|
tm68kparamanager = class(tparamanager)
|
||||||
procedure getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
|
function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
|
||||||
|
function param_use_paraloc(const cgpara:tcgpara):boolean;override;
|
||||||
function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
|
function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
|
||||||
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
|
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
|
||||||
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
|
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
|
||||||
@ -80,35 +81,24 @@ unit cpupara;
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tm68kparamanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
|
function tm68kparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
|
||||||
var
|
var
|
||||||
paraloc : pcgparalocation;
|
paraloc : pcgparalocation;
|
||||||
psym: tparavarsym;
|
|
||||||
pdef: tdef;
|
|
||||||
begin
|
begin
|
||||||
if nr<1 then
|
if not assigned(cgpara.location) then
|
||||||
internalerror(2002070801);
|
internalerror(200410102);
|
||||||
psym:=tparavarsym(pd.paras[nr-1]);
|
result:=true;
|
||||||
pdef:=psym.vardef;
|
{ All locations are LOC_REFERENCE }
|
||||||
if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
|
paraloc:=cgpara.location;
|
||||||
pdef:=getpointerdef(pdef);
|
while assigned(paraloc) do
|
||||||
cgpara.reset;
|
begin
|
||||||
cgpara.size:=def_cgsize(pdef);
|
if (paraloc^.loc<>LOC_REFERENCE) then
|
||||||
cgpara.intsize:=tcgsize2size[cgpara.size];
|
begin
|
||||||
cgpara.alignment:=std_param_align;
|
result:=false;
|
||||||
cgpara.def:=pdef;
|
exit;
|
||||||
paraloc:=cgpara.add_location;
|
end;
|
||||||
with paraloc^ do
|
paraloc:=paraloc^.next;
|
||||||
begin
|
end;
|
||||||
{ warning : THIS ONLY WORKS WITH INTERNAL ROUTINES,
|
|
||||||
WHICH MUST ALWAYS PASS 4-BYTE PARAMETERS!!
|
|
||||||
}
|
|
||||||
loc:=LOC_REFERENCE;
|
|
||||||
reference.index:=NR_STACK_POINTER_REG;
|
|
||||||
reference.offset:=target_info.first_parm_offset+nr*4;
|
|
||||||
size:=def_cgsize(pdef);
|
|
||||||
def:=pdef;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -127,7 +117,7 @@ unit cpupara;
|
|||||||
formaldef :
|
formaldef :
|
||||||
result:=true;
|
result:=true;
|
||||||
recorddef:
|
recorddef:
|
||||||
result:=true;
|
result:=false;
|
||||||
arraydef:
|
arraydef:
|
||||||
result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
|
result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
|
||||||
is_open_array(def) or
|
is_open_array(def) or
|
||||||
@ -140,7 +130,8 @@ unit cpupara;
|
|||||||
stringdef :
|
stringdef :
|
||||||
result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
|
result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
|
||||||
procvardef :
|
procvardef :
|
||||||
result:=po_methodpointer in tprocvardef(def).procoptions;
|
{ Handling of methods must match that of records }
|
||||||
|
result:=false;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -151,6 +142,24 @@ unit cpupara;
|
|||||||
curfloatreg:=RS_FP0;
|
curfloatreg:=RS_FP0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function tm68kparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
|
||||||
|
begin
|
||||||
|
if handle_common_ret_in_param(def,pd,result) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
case def.typ of
|
||||||
|
recorddef:
|
||||||
|
if def.size in [1,2,4] then
|
||||||
|
begin
|
||||||
|
result:=false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
result:=inherited ret_in_param(def,pd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tm68kparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
|
function tm68kparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
|
||||||
var
|
var
|
||||||
paraloc : pcgparalocation;
|
paraloc : pcgparalocation;
|
||||||
@ -286,7 +295,7 @@ unit cpupara;
|
|||||||
|
|
||||||
paracgsize:=def_cgsize(paradef);
|
paracgsize:=def_cgsize(paradef);
|
||||||
{ for things like formaldef }
|
{ for things like formaldef }
|
||||||
if (paracgsize=OS_NO) then
|
if (paracgsize=OS_NO) and (paradef.typ<>recorddef) then
|
||||||
begin
|
begin
|
||||||
paracgsize:=OS_ADDR;
|
paracgsize:=OS_ADDR;
|
||||||
paralen := tcgsize2size[OS_ADDR];
|
paralen := tcgsize2size[OS_ADDR];
|
||||||
@ -314,17 +323,21 @@ unit cpupara;
|
|||||||
|
|
||||||
paraloc^.loc:=LOC_REFERENCE;
|
paraloc^.loc:=LOC_REFERENCE;
|
||||||
paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
|
paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
|
||||||
if paradef.typ<>orddef then
|
if (paradef.typ=floatdef) then
|
||||||
paracgsize:=int_cgsize(paralen);
|
paraloc^.size:=int_float_cgsize(paralen)
|
||||||
if paracgsize=OS_NO then
|
|
||||||
paraloc^.size:=OS_INT
|
|
||||||
else
|
else
|
||||||
paraloc^.size:=paracgsize;
|
paraloc^.size:=int_cgsize(paralen);
|
||||||
|
|
||||||
|
paraloc^.reference.offset:=stack_offset;
|
||||||
if (side = callerside) then
|
if (side = callerside) then
|
||||||
paraloc^.reference.index:=NR_STACK_POINTER_REG
|
paraloc^.reference.index:=NR_STACK_POINTER_REG
|
||||||
else
|
else
|
||||||
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
begin
|
||||||
paraloc^.reference.offset:=stack_offset;
|
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
||||||
|
{ M68K is a big-endian target }
|
||||||
|
if (paralen<tcgsize2size[OS_INT]) then
|
||||||
|
inc(paraloc^.reference.offset,4-paralen);
|
||||||
|
end;
|
||||||
inc(stack_offset,align(paralen,4));
|
inc(stack_offset,align(paralen,4));
|
||||||
paralen := 0;
|
paralen := 0;
|
||||||
|
|
||||||
|
@ -91,9 +91,7 @@ procedure FillChar(var x; count : longint; value : byte); assembler;
|
|||||||
asm
|
asm
|
||||||
move.l x, a0 { destination }
|
move.l x, a0 { destination }
|
||||||
move.l count, d1 { number of bytes to fill }
|
move.l count, d1 { number of bytes to fill }
|
||||||
{ FIXME: this should be move.b, but everything is pushed as long on
|
move.b value, d0 { fill data }
|
||||||
the stack ATM (KB) }
|
|
||||||
move.l value, d0 { fill data }
|
|
||||||
tst.l d1 { anything to fill at all? }
|
tst.l d1 { anything to fill at all? }
|
||||||
ble @LMEMSET5
|
ble @LMEMSET5
|
||||||
{$ifdef CPUM68K_HAS_DBRA}
|
{$ifdef CPUM68K_HAS_DBRA}
|
||||||
@ -321,9 +319,7 @@ procedure FillWord(var x; count : longint; value : word); assembler;
|
|||||||
asm
|
asm
|
||||||
move.l x, a0 { destination }
|
move.l x, a0 { destination }
|
||||||
move.l count, d1 { number of bytes to fill }
|
move.l count, d1 { number of bytes to fill }
|
||||||
{ FIXME: this should be move.w, but everything is pushed as long on
|
move.w value, d0 { fill data }
|
||||||
the stack ATM (KB) }
|
|
||||||
move.l value, d0 { fill data }
|
|
||||||
tst.l d1 { anything to fill at all? }
|
tst.l d1 { anything to fill at all? }
|
||||||
ble @LMEMSET3
|
ble @LMEMSET3
|
||||||
bra @LMEMSET21
|
bra @LMEMSET21
|
||||||
|
Loading…
Reference in New Issue
Block a user