* 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:
sergei 2014-06-27 06:58:39 +00:00
parent 140ce2a880
commit acd3ea8750
3 changed files with 57 additions and 66 deletions

View File

@ -815,17 +815,14 @@ unit cgcpu;
procedure tcg68k.a_load_reg_ref(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);
var
href : treference;
size : tcgsize;
href : treference;
begin
href := ref;
fixref(list,href);
if tcgsize2size[fromsize]<tcgsize2size[tosize] then
size:=fromsize
else
size:=tosize;
a_load_reg_reg(list,fromsize,tosize,register,register);
{ 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;
@ -1506,7 +1503,6 @@ unit cgcpu;
hp2 : treference;
hl : tasmlabel;
srcref,dstref : treference;
alignsize : tcgsize;
orglen : tcgint;
begin
hregister := getintregister(list,OS_INT);
@ -1530,14 +1526,7 @@ unit cgcpu;
{ move a word }
if len>1 then
begin
if (orglen<sizeof(aint)) and
(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_ref_reg(list,OS_16,OS_16,srcref,hregister);
a_load_reg_ref(list,OS_16,OS_16,hregister,dstref);
inc(srcref.offset,2);
inc(dstref.offset,2);
@ -1546,14 +1535,7 @@ unit cgcpu;
{ move a single byte }
if len>0 then
begin
if (orglen<sizeof(aint)) and
(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_ref_reg(list,OS_8,OS_8,srcref,hregister);
a_load_reg_ref(list,OS_8,OS_8,hregister,dstref);
end
end

View File

@ -39,7 +39,8 @@ unit cpupara;
rtl are used.
}
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 push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
@ -80,35 +81,24 @@ unit cpupara;
end;
procedure tm68kparamanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
function tm68kparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
var
paraloc : pcgparalocation;
psym: tparavarsym;
pdef: tdef;
begin
if nr<1 then
internalerror(2002070801);
psym:=tparavarsym(pd.paras[nr-1]);
pdef:=psym.vardef;
if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
pdef:=getpointerdef(pdef);
cgpara.reset;
cgpara.size:=def_cgsize(pdef);
cgpara.intsize:=tcgsize2size[cgpara.size];
cgpara.alignment:=std_param_align;
cgpara.def:=pdef;
paraloc:=cgpara.add_location;
with paraloc^ do
begin
{ 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;
if not assigned(cgpara.location) then
internalerror(200410102);
result:=true;
{ All locations are LOC_REFERENCE }
paraloc:=cgpara.location;
while assigned(paraloc) do
begin
if (paraloc^.loc<>LOC_REFERENCE) then
begin
result:=false;
exit;
end;
paraloc:=paraloc^.next;
end;
end;
@ -127,7 +117,7 @@ unit cpupara;
formaldef :
result:=true;
recorddef:
result:=true;
result:=false;
arraydef:
result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
is_open_array(def) or
@ -140,7 +130,8 @@ unit cpupara;
stringdef :
result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
procvardef :
result:=po_methodpointer in tprocvardef(def).procoptions;
{ Handling of methods must match that of records }
result:=false;
end;
end;
@ -151,6 +142,24 @@ unit cpupara;
curfloatreg:=RS_FP0;
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;
var
paraloc : pcgparalocation;
@ -286,7 +295,7 @@ unit cpupara;
paracgsize:=def_cgsize(paradef);
{ for things like formaldef }
if (paracgsize=OS_NO) then
if (paracgsize=OS_NO) and (paradef.typ<>recorddef) then
begin
paracgsize:=OS_ADDR;
paralen := tcgsize2size[OS_ADDR];
@ -314,17 +323,21 @@ unit cpupara;
paraloc^.loc:=LOC_REFERENCE;
paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
if paradef.typ<>orddef then
paracgsize:=int_cgsize(paralen);
if paracgsize=OS_NO then
paraloc^.size:=OS_INT
if (paradef.typ=floatdef) then
paraloc^.size:=int_float_cgsize(paralen)
else
paraloc^.size:=paracgsize;
paraloc^.size:=int_cgsize(paralen);
paraloc^.reference.offset:=stack_offset;
if (side = callerside) then
paraloc^.reference.index:=NR_STACK_POINTER_REG
else
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
paraloc^.reference.offset:=stack_offset;
begin
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));
paralen := 0;

View File

@ -91,9 +91,7 @@ procedure FillChar(var x; count : longint; value : byte); assembler;
asm
move.l x, a0 { destination }
move.l count, d1 { number of bytes to fill }
{ FIXME: this should be move.b, but everything is pushed as long on
the stack ATM (KB) }
move.l value, d0 { fill data }
move.b value, d0 { fill data }
tst.l d1 { anything to fill at all? }
ble @LMEMSET5
{$ifdef CPUM68K_HAS_DBRA}
@ -321,9 +319,7 @@ procedure FillWord(var x; count : longint; value : word); assembler;
asm
move.l x, a0 { destination }
move.l count, d1 { number of bytes to fill }
{ FIXME: this should be move.w, but everything is pushed as long on
the stack ATM (KB) }
move.l value, d0 { fill data }
move.w value, d0 { fill data }
tst.l d1 { anything to fill at all? }
ble @LMEMSET3
bra @LMEMSET21