* 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); 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

View File

@ -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;

View File

@ -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