mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-17 05:19:49 +02:00
* moved use_fixed_stack from cgutils to a method in paramgr so it can
be used outside the code generator * renamed tabstractprocdef.requiredargarea into callerargareasize, and also added calleeargareasize field; added init_paraloc_info(side) method to init the parameter locations and init those size fields and replaced all "if not procdef.has_paraloc_info then ..." blocks with procdef.init_paraloc_info(callersize)" * moved detection of stack tainting parameters from psub to symdef/tabstractprocdef + added tcallparanode.contains_stack_tainting_call(), which detects whether a parameter contains a call that makes use of stack paramters * record for each parameter whether or not any following parameter contains a call with stack parameters; if not, in case the current parameter itself is a stack parameter immediately place it in its final location also for use_fixed_stack platforms rather than first putting it in a temporary location (part of mantis #17442) * on use_fixed_stack platforms, always first evaluate parameters containing a stack tainting call, since those force any preceding stack parameters of the current call to be stored in a temp location and copied to the final location afterwards git-svn-id: trunk@16050 -
This commit is contained in:
parent
27948a5f06
commit
f13f6627c4
@ -2140,11 +2140,7 @@ unit cgcpu;
|
||||
shift : byte;
|
||||
begin
|
||||
{ calculate the parameter info for the procdef }
|
||||
if not procdef.has_paraloc_info then
|
||||
begin
|
||||
procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
|
||||
procdef.has_paraloc_info:=true;
|
||||
end;
|
||||
procdef.init_paraloc_info(callerside);
|
||||
hsym:=tsym(procdef.parast.Find('self'));
|
||||
if not(assigned(hsym) and
|
||||
(hsym.typ=paravarsym)) then
|
||||
|
@ -4124,11 +4124,7 @@ implementation
|
||||
paraloc : Pcgparalocation;
|
||||
begin
|
||||
{ calculate the parameter info for the procdef }
|
||||
if not procdef.has_paraloc_info then
|
||||
begin
|
||||
procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
|
||||
procdef.has_paraloc_info:=true;
|
||||
end;
|
||||
procdef.init_paraloc_info(callerside);
|
||||
hsym:=tsym(procdef.parast.Find('self'));
|
||||
if not(assigned(hsym) and
|
||||
(hsym.typ=paravarsym)) then
|
||||
|
@ -148,10 +148,6 @@ unit cgutils;
|
||||
procedure location_copy(var destloc:tlocation; const sourceloc : tlocation);
|
||||
procedure location_swap(var destloc,sourceloc : tlocation);
|
||||
|
||||
|
||||
{ allocate room for parameters on the stack in the entry code? }
|
||||
function use_fixed_stack: boolean;
|
||||
|
||||
{ returns r with the given alignment }
|
||||
function setalignment(const r : treference;b : byte) : treference;
|
||||
|
||||
@ -248,18 +244,5 @@ uses
|
||||
end;
|
||||
|
||||
|
||||
function use_fixed_stack: boolean;
|
||||
begin
|
||||
{$ifdef i386}
|
||||
result := (target_info.system in [system_i386_darwin,system_x86_64_darwin]);
|
||||
{$else i386}
|
||||
{$ifdef cputargethasfixedstack}
|
||||
result := true;
|
||||
{$else cputargethasfixedstack}
|
||||
result := false;
|
||||
{$endif cputargethasfixedstack}
|
||||
{$endif i386}
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
@ -75,7 +75,7 @@ unit cgcpu;
|
||||
|
||||
function use_push(const cgpara:tcgpara):boolean;
|
||||
begin
|
||||
result:=(not use_fixed_stack) and
|
||||
result:=(not paramanager.use_fixed_stack) and
|
||||
assigned(cgpara.location) and
|
||||
(cgpara.location^.loc=LOC_REFERENCE) and
|
||||
(cgpara.location^.reference.index=NR_STACK_POINTER_REG);
|
||||
@ -325,7 +325,7 @@ unit cgcpu;
|
||||
end
|
||||
{ Routines with the poclearstack flag set use only a ret }
|
||||
else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
|
||||
(not use_fixed_stack) then
|
||||
(not paramanager.use_fixed_stack) then
|
||||
begin
|
||||
{ complex return values are removed from stack in C code PM }
|
||||
{ but not on win32 }
|
||||
@ -361,7 +361,7 @@ unit cgcpu;
|
||||
again,ok : tasmlabel;
|
||||
{$endif}
|
||||
begin
|
||||
if use_fixed_stack then
|
||||
if paramanager.use_fixed_stack then
|
||||
begin
|
||||
inherited g_copyvaluepara_openarray(list,ref,lenloc,elesize,destreg);
|
||||
exit;
|
||||
@ -471,7 +471,7 @@ unit cgcpu;
|
||||
|
||||
procedure tcg386.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
|
||||
begin
|
||||
if use_fixed_stack then
|
||||
if paramanager.use_fixed_stack then
|
||||
begin
|
||||
inherited g_releasevaluepara_openarray(list,l);
|
||||
exit;
|
||||
@ -482,7 +482,7 @@ unit cgcpu;
|
||||
|
||||
procedure tcg386.g_exception_reason_save(list : TAsmList; const href : treference);
|
||||
begin
|
||||
if not use_fixed_stack then
|
||||
if not paramanager.use_fixed_stack then
|
||||
list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
|
||||
else
|
||||
inherited g_exception_reason_save(list,href);
|
||||
@ -491,7 +491,7 @@ unit cgcpu;
|
||||
|
||||
procedure tcg386.g_exception_reason_save_const(list : TAsmList;const href : treference; a: aint);
|
||||
begin
|
||||
if not use_fixed_stack then
|
||||
if not paramanager.use_fixed_stack then
|
||||
list.concat(Taicpu.op_const(A_PUSH,tcgsize2opsize[OS_INT],a))
|
||||
else
|
||||
inherited g_exception_reason_save_const(list,href,a);
|
||||
@ -500,7 +500,7 @@ unit cgcpu;
|
||||
|
||||
procedure tcg386.g_exception_reason_load(list : TAsmList; const href : treference);
|
||||
begin
|
||||
if not use_fixed_stack then
|
||||
if not paramanager.use_fixed_stack then
|
||||
begin
|
||||
cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
|
||||
list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
|
||||
|
@ -48,7 +48,7 @@ unit cpupara;
|
||||
procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
|
||||
function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
|
||||
function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
|
||||
procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);override;
|
||||
procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
|
||||
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; def: tdef): TCGPara;override;
|
||||
private
|
||||
procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
|
||||
@ -735,19 +735,16 @@ unit cpupara;
|
||||
end;
|
||||
|
||||
|
||||
procedure ti386paramanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
|
||||
procedure ti386paramanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
|
||||
var
|
||||
paraloc : pcgparalocation;
|
||||
begin
|
||||
paraloc:=parasym.paraloc[callerside].location;
|
||||
{ No need for temps when value is pushed }
|
||||
if not(use_fixed_stack) and
|
||||
assigned(paraloc) and
|
||||
(paraloc^.loc=LOC_REFERENCE) and
|
||||
(paraloc^.reference.index=NR_STACK_POINTER_REG) then
|
||||
duplicateparaloc(list,calloption,parasym,cgpara)
|
||||
else
|
||||
inherited createtempparaloc(list,calloption,parasym,cgpara);
|
||||
{ Never a need for temps when value is pushed (calls inside parameters
|
||||
will simply allocate even more stack space for their parameters) }
|
||||
if not(use_fixed_stack) then
|
||||
can_use_final_stack_loc:=true;
|
||||
inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
|
||||
end;
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ unit cpupi;
|
||||
uses
|
||||
cutils,
|
||||
systems,globals,globtype,
|
||||
cgobj,tgobj,
|
||||
cgobj,tgobj,paramgr,
|
||||
cpubase,
|
||||
cgutils,
|
||||
symconst;
|
||||
@ -59,7 +59,7 @@ unit cpupi;
|
||||
|
||||
procedure ti386procinfo.set_first_temp_offset;
|
||||
begin
|
||||
if use_fixed_stack then
|
||||
if paramanager.use_fixed_stack then
|
||||
begin
|
||||
if not(po_assembler in procdef.procoptions) and
|
||||
(tg.direction > 0) then
|
||||
@ -85,7 +85,7 @@ unit cpupi;
|
||||
{ Para_stack_size is only used to determine how many bytes to remove }
|
||||
{ from the stack at the end of the procedure (in the "ret $xx"). }
|
||||
{ If the stack is fixed, nothing has to be removed by the callee }
|
||||
if use_fixed_stack then
|
||||
if paramanager.use_fixed_stack then
|
||||
para_stack_size := 0;
|
||||
end;
|
||||
|
||||
|
@ -69,7 +69,7 @@ implementation
|
||||
var
|
||||
hreg : tregister;
|
||||
begin
|
||||
if (use_fixed_stack) then
|
||||
if (paramanager.use_fixed_stack) then
|
||||
begin
|
||||
{ very weird: in this case the callee does a "ret $4" and the }
|
||||
{ caller immediately a "subl $4,%esp". Possibly this is for }
|
||||
|
@ -206,7 +206,7 @@ unit cgcpu;
|
||||
|
||||
function use_push(const cgpara:tcgpara):boolean;
|
||||
begin
|
||||
result:=(not use_fixed_stack) and
|
||||
result:=(not paramanager.use_fixed_stack) and
|
||||
assigned(cgpara.location) and
|
||||
(cgpara.location^.loc=LOC_REFERENCE) and
|
||||
(cgpara.location^.reference.index=NR_STACK_POINTER_REG);
|
||||
|
@ -45,7 +45,7 @@ unit cpupara;
|
||||
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; def: tdef): tcgpara;override;
|
||||
procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);override;
|
||||
procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
|
||||
procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
|
||||
private
|
||||
procedure init_values(var curintreg, curfloatreg: tsuperregister; var cur_stack_offset: aword);
|
||||
@ -565,22 +565,18 @@ unit cpupara;
|
||||
end;
|
||||
|
||||
|
||||
procedure tm68kparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
|
||||
procedure tm68kparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
|
||||
var
|
||||
paraloc : pcgparalocation;
|
||||
begin
|
||||
paraloc:=parasym.paraloc[callerside].location;
|
||||
{ No need for temps when value is pushed }
|
||||
if not(use_fixed_stack) and
|
||||
assigned(paraloc) and
|
||||
(paraloc^.loc=LOC_REFERENCE) and
|
||||
(paraloc^.reference.index=NR_STACK_POINTER_REG) then
|
||||
duplicateparaloc(list,calloption,parasym,cgpara)
|
||||
else
|
||||
inherited createtempparaloc(list,calloption,parasym,cgpara);
|
||||
{ Never a need for temps when value is pushed (calls inside parameters
|
||||
will simply allocate even more stack space for their parameters) }
|
||||
if not(use_fixed_stack) then
|
||||
can_use_final_stack_loc:=true;
|
||||
inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
paramanager:=tm68kparamanager.create;
|
||||
end.
|
||||
|
@ -174,6 +174,9 @@ interface
|
||||
tcallparaflags = set of tcallparaflag;
|
||||
|
||||
tcallparanode = class(ttertiarynode)
|
||||
private
|
||||
fcontains_stack_tainting_call_cached,
|
||||
ffollowed_by_stack_tainting_call_cached : boolean;
|
||||
public
|
||||
callparaflags : tcallparaflags;
|
||||
parasym : tparavarsym;
|
||||
@ -199,6 +202,21 @@ interface
|
||||
|
||||
property nextpara : tnode read right write right;
|
||||
property parametername : tnode read third write third;
|
||||
|
||||
{ returns whether the evaluation of this parameter involves a
|
||||
stack tainting call }
|
||||
function contains_stack_tainting_call: boolean;
|
||||
{ initialises the fcontains_stack_tainting_call_cached field with the
|
||||
result of contains_stack_tainting_call so that it can be quickly
|
||||
accessed via the contains_stack_tainting_call_cached property }
|
||||
procedure init_contains_stack_tainting_call_cache;
|
||||
{ returns result of contains_stack_tainting_call cached during last
|
||||
call to init_contains_stack_tainting_call_cache }
|
||||
property contains_stack_tainting_call_cached: boolean read fcontains_stack_tainting_call_cached;
|
||||
{ returns whether this parameter is followed by at least one other
|
||||
parameter whose evaluation involves a stack tainting parameter
|
||||
(result is only valid after order_parameters has been called) }
|
||||
property followed_by_stack_tainting_call_cached: boolean read ffollowed_by_stack_tainting_call_cached;
|
||||
end;
|
||||
tcallparanodeclass = class of tcallparanode;
|
||||
|
||||
@ -962,6 +980,28 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function check_contains_stack_tainting_call(var n: tnode; arg: pointer): foreachnoderesult;
|
||||
begin
|
||||
if (n.nodetype=calln) and
|
||||
tcallnode(n).procdefinition.stack_tainting_parameter(callerside) then
|
||||
result:=fen_norecurse_true
|
||||
else
|
||||
result:=fen_false;
|
||||
end;
|
||||
|
||||
|
||||
function tcallparanode.contains_stack_tainting_call: boolean;
|
||||
begin
|
||||
result:=foreachnodestatic(pm_postprocess,left,@check_contains_stack_tainting_call,nil);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcallparanode.init_contains_stack_tainting_call_cache;
|
||||
begin
|
||||
fcontains_stack_tainting_call_cached:=contains_stack_tainting_call;
|
||||
end;
|
||||
|
||||
|
||||
function tcallparanode.docompare(p: tnode): boolean;
|
||||
begin
|
||||
docompare :=
|
||||
@ -2998,6 +3038,14 @@ implementation
|
||||
begin
|
||||
hpfirst:=nil;
|
||||
hpcurr:=tcallparanode(left);
|
||||
{ cache all info about parameters containing stack tainting calls,
|
||||
since we will need it a lot below and calculting it can be expensive }
|
||||
while assigned(hpcurr) do
|
||||
begin
|
||||
hpcurr.init_contains_stack_tainting_call_cache;
|
||||
hpcurr:=tcallparanode(hpcurr.right);
|
||||
end;
|
||||
hpcurr:=tcallparanode(left);
|
||||
while assigned(hpcurr) do
|
||||
begin
|
||||
{ pull out }
|
||||
@ -3030,8 +3078,17 @@ implementation
|
||||
currloc:=hpcurr.parasym.paraloc[callerside].location^.loc;
|
||||
hpprev:=nil;
|
||||
hp:=hpfirst;
|
||||
{ on fixed_stack targets, always evaluate parameters containing
|
||||
a call with stack parameters before all other parameters,
|
||||
because they will prevent any other parameters from being put
|
||||
in their final place; if both the current and the next para
|
||||
contain a stack tainting call, don't do anything to prevent
|
||||
them from keeping on chasing eachother's tail }
|
||||
while assigned(hp) do
|
||||
begin
|
||||
if paramanager.use_fixed_stack and
|
||||
hpcurr.contains_stack_tainting_call_cached then
|
||||
break;
|
||||
case currloc of
|
||||
LOC_REFERENCE :
|
||||
begin
|
||||
@ -3050,8 +3107,11 @@ implementation
|
||||
{$ifdef i386}
|
||||
{ the i386 code generator expects all reference }
|
||||
{ parameter to be in this order so it can use }
|
||||
{ pushes }
|
||||
if (hpcurr.parasym.paraloc[callerside].location^.reference.offset>hp.parasym.paraloc[callerside].location^.reference.offset) then
|
||||
{ pushes in case of no fixed stack }
|
||||
if (not paramanager.use_fixed_stack and
|
||||
(hpcurr.parasym.paraloc[callerside].location^.reference.offset>hp.parasym.paraloc[callerside].location^.reference.offset)) or
|
||||
(paramanager.use_fixed_stack and
|
||||
(node_complexity(hpcurr)<node_complexity(hp))) then
|
||||
{$else i386}
|
||||
if (node_complexity(hpcurr)<node_complexity(hp)) then
|
||||
{$endif i386}
|
||||
@ -3084,6 +3144,30 @@ implementation
|
||||
hpcurr:=hpnext;
|
||||
end;
|
||||
left:=hpfirst;
|
||||
{ now mark each parameter that is followed by a stack-tainting call,
|
||||
to determine on use_fixed_stack targets which ones can immediately be
|
||||
put in their final destination. Unforunately we can never put register
|
||||
parameters immediately in their final destination (even on register-
|
||||
rich architectures such as the PowerPC), because the code generator
|
||||
can still insert extra calls that only make use of register
|
||||
parameters (fpc_move() etc. }
|
||||
hpcurr:=hpfirst;
|
||||
while assigned(hpcurr) do
|
||||
begin
|
||||
if hpcurr.contains_stack_tainting_call_cached then
|
||||
begin
|
||||
{ all parameters before this one are followed by a stack
|
||||
tainting call }
|
||||
hp:=hpfirst;
|
||||
while hp<>hpcurr do
|
||||
begin
|
||||
hp.ffollowed_by_stack_tainting_call_cached:=true;
|
||||
hp:=tcallparanode(hp.right);
|
||||
end;
|
||||
hpfirst:=hpcurr;
|
||||
end;
|
||||
hpcurr:=tcallparanode(hpcurr.right);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -3206,17 +3290,13 @@ implementation
|
||||
result:=nil;
|
||||
|
||||
{ calculate the parameter info for the procdef }
|
||||
if not procdefinition.has_paraloc_info then
|
||||
begin
|
||||
procdefinition.requiredargarea:=paramanager.create_paraloc_info(procdefinition,callerside);
|
||||
procdefinition.has_paraloc_info:=true;
|
||||
end;
|
||||
procdefinition.init_paraloc_info(callerside);
|
||||
|
||||
{ calculate the parameter size needed for this call include varargs if they are available }
|
||||
if assigned(varargsparas) then
|
||||
pushedparasize:=paramanager.create_varargs_paraloc_info(procdefinition,varargsparas)
|
||||
else
|
||||
pushedparasize:=procdefinition.requiredargarea;
|
||||
pushedparasize:=procdefinition.callerargareasize;
|
||||
|
||||
{ record maximum parameter size used in this proc }
|
||||
current_procinfo.allocate_push_parasize(pushedparasize);
|
||||
|
@ -170,7 +170,7 @@ implementation
|
||||
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
|
||||
end;
|
||||
|
||||
paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
|
||||
paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
|
||||
|
||||
{ handle varargs first, because parasym is not valid }
|
||||
if (cpf_varargs_para in callparaflags) then
|
||||
@ -485,6 +485,7 @@ implementation
|
||||
href : treference;
|
||||
calleralignment,
|
||||
tmpalignment: longint;
|
||||
skipmemloc: boolean;
|
||||
begin
|
||||
{ copy all resources to the allocated registers }
|
||||
ppn:=tcgcallparanode(left);
|
||||
@ -504,6 +505,10 @@ implementation
|
||||
(calleralignment=0) then
|
||||
internalerror(2009020701);
|
||||
callerparaloc:=ppn.parasym.paraloc[callerside].location;
|
||||
skipmemloc:=
|
||||
(not paramanager.use_fixed_stack or
|
||||
not(ppn.followed_by_stack_tainting_call_cached)) and
|
||||
paramanager.is_simple_stack_paraloc(callerparaloc);
|
||||
while assigned(callerparaloc) do
|
||||
begin
|
||||
{ Every paraloc must have a matching tmpparaloc }
|
||||
@ -540,7 +545,7 @@ implementation
|
||||
end;
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
if use_fixed_stack then
|
||||
if not skipmemloc then
|
||||
begin
|
||||
{ Can't have a data copied to the stack, every location
|
||||
must contain a valid size field }
|
||||
@ -624,7 +629,7 @@ implementation
|
||||
{$endif x86_64}
|
||||
begin
|
||||
if not assigned(procdefinition) or
|
||||
not procdefinition.has_paraloc_info then
|
||||
not(procdefinition.has_paraloc_info in [callerside,callbothsides]) then
|
||||
internalerror(200305264);
|
||||
|
||||
if assigned(callinitblock) then
|
||||
@ -852,7 +857,7 @@ implementation
|
||||
{ frame pointer parameter is popped by the caller when it's passed the
|
||||
Delphi way }
|
||||
else if (po_delphi_nested_cc in procdefinition.procoptions) and
|
||||
not use_fixed_stack then
|
||||
not paramanager.use_fixed_stack then
|
||||
pop_parasize(sizeof(pint));
|
||||
{ Release registers, but not the registers that contain the
|
||||
function result }
|
||||
|
@ -235,7 +235,7 @@ implementation
|
||||
LOC_REFERENCE,
|
||||
LOC_CREFERENCE :
|
||||
begin
|
||||
if use_fixed_stack then
|
||||
if paramanager.use_fixed_stack then
|
||||
location_freetemp(list,location);
|
||||
end;
|
||||
else
|
||||
@ -805,7 +805,7 @@ implementation
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
size:=align(locintsize,cgpara.alignment);
|
||||
if (not use_fixed_stack) and
|
||||
if (not paramanager.use_fixed_stack) and
|
||||
(cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
|
||||
begin
|
||||
cg.g_stackpointer_alloc(list,size);
|
||||
@ -850,7 +850,7 @@ implementation
|
||||
{ can't use TCGSize2Size[l.size], because the size of an
|
||||
80 bit extended parameter can be either 10 or 12 bytes }
|
||||
size:=align(locintsize,cgpara.alignment);
|
||||
if (not use_fixed_stack) and
|
||||
if (not paramanager.use_fixed_stack) and
|
||||
(cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
|
||||
begin
|
||||
cg.g_stackpointer_alloc(list,size);
|
||||
@ -878,7 +878,7 @@ implementation
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
size:=align(locintsize,cgpara.alignment);
|
||||
if (not use_fixed_stack) and
|
||||
if (not paramanager.use_fixed_stack) and
|
||||
(cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
|
||||
cg.a_load_ref_cgpara(list,locsize,l.reference,cgpara)
|
||||
else
|
||||
@ -2347,7 +2347,7 @@ implementation
|
||||
parasize:=current_procinfo.para_stack_size;
|
||||
{ the parent frame pointer para has to be removed by the caller in
|
||||
case of Delphi-style parent frame pointer passing }
|
||||
if not use_fixed_stack and
|
||||
if not paramanager.use_fixed_stack and
|
||||
(po_delphi_nested_cc in current_procinfo.procdef.procoptions) then
|
||||
dec(parasize,sizeof(pint));
|
||||
end;
|
||||
|
@ -205,11 +205,7 @@ end;
|
||||
begin
|
||||
result:='';
|
||||
totalsize:=0;
|
||||
if not pd.has_paraloc_info then
|
||||
begin
|
||||
pd.requiredargarea:=paramanager.create_paraloc_info(pd,callerside);
|
||||
pd.has_paraloc_info:=true;
|
||||
end;
|
||||
pd.init_paraloc_info(callerside);
|
||||
{$if defined(powerpc) and defined(dummy)}
|
||||
{ Disabled, because neither Clang nor gcc does this, and the ObjC
|
||||
runtime contains an explicit fix to detect this error. }
|
||||
|
@ -38,6 +38,9 @@ unit paramgr;
|
||||
{# This class defines some methods to take care of routine
|
||||
parameters. It should be overriden for each new processor
|
||||
}
|
||||
|
||||
{ tparamanager }
|
||||
|
||||
tparamanager = class
|
||||
{ true if the location in paraloc can be reused as localloc }
|
||||
function param_use_paraloc(const cgpara:tcgpara):boolean;virtual;
|
||||
@ -121,11 +124,15 @@ unit paramgr;
|
||||
}
|
||||
function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;virtual;abstract;
|
||||
|
||||
procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);virtual;
|
||||
function is_simple_stack_paraloc(paraloc: pcgparalocation): boolean;
|
||||
procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);virtual;
|
||||
procedure duplicateparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
|
||||
|
||||
function parseparaloc(parasym : tparavarsym;const s : string) : boolean;virtual;
|
||||
function parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;virtual;
|
||||
|
||||
{ allocate room for parameters on the stack in the entry code? }
|
||||
function use_fixed_stack: boolean;
|
||||
end;
|
||||
|
||||
|
||||
@ -320,13 +327,31 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure tparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
|
||||
function tparamanager.is_simple_stack_paraloc(paraloc: pcgparalocation): boolean;
|
||||
begin
|
||||
result:=
|
||||
assigned(paraloc) and
|
||||
(paraloc^.loc=LOC_REFERENCE) and
|
||||
(paraloc^.reference.index=NR_STACK_POINTER_REG) and
|
||||
not assigned(paraloc^.next);
|
||||
end;
|
||||
|
||||
|
||||
procedure tparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
|
||||
var
|
||||
href : treference;
|
||||
len : aint;
|
||||
paraloc,
|
||||
newparaloc : pcgparalocation;
|
||||
begin
|
||||
paraloc:=parasym.paraloc[callerside].location;
|
||||
if can_use_final_stack_loc and
|
||||
is_simple_stack_paraloc(paraloc) then
|
||||
begin
|
||||
duplicateparaloc(list,calloption,parasym,cgpara);
|
||||
exit;
|
||||
end;
|
||||
|
||||
cgpara.reset;
|
||||
cgpara.size:=parasym.paraloc[callerside].size;
|
||||
cgpara.intsize:=parasym.paraloc[callerside].intsize;
|
||||
@ -334,7 +359,6 @@ implementation
|
||||
{$ifdef powerpc}
|
||||
cgpara.composite:=parasym.paraloc[callerside].composite;
|
||||
{$endif powerpc}
|
||||
paraloc:=parasym.paraloc[callerside].location;
|
||||
while assigned(paraloc) do
|
||||
begin
|
||||
if paraloc^.size=OS_NO then
|
||||
@ -398,8 +422,8 @@ implementation
|
||||
function tparamanager.create_inline_paraloc_info(p : tabstractprocdef):longint;
|
||||
begin
|
||||
{ We need to return the size allocated }
|
||||
create_paraloc_info(p,callerside);
|
||||
result:=create_paraloc_info(p,calleeside);
|
||||
p.init_paraloc_info(callbothsides);
|
||||
result:=p.calleeargareasize;
|
||||
end;
|
||||
|
||||
|
||||
@ -416,6 +440,21 @@ implementation
|
||||
internalerror(200807236);
|
||||
end;
|
||||
|
||||
|
||||
function tparamanager.use_fixed_stack: boolean;
|
||||
begin
|
||||
{$ifdef i386}
|
||||
result := (target_info.system in [system_i386_darwin,system_x86_64_darwin]);
|
||||
{$else i386}
|
||||
{$ifdef cputargethasfixedstack}
|
||||
result := true;
|
||||
{$else cputargethasfixedstack}
|
||||
result := false;
|
||||
{$endif cputargethasfixedstack}
|
||||
{$endif i386}
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
;
|
||||
finalization
|
||||
|
@ -699,7 +699,7 @@ implementation
|
||||
|
||||
if explicit_paraloc then
|
||||
begin
|
||||
pd.has_paraloc_info:=true;
|
||||
pd.has_paraloc_info:=callerside;
|
||||
include(pd.procoptions,po_explicitparaloc);
|
||||
end;
|
||||
{ remove parasymtable from stack }
|
||||
|
@ -704,26 +704,6 @@ unit cpupara;
|
||||
result:=true;
|
||||
end;
|
||||
|
||||
{
|
||||
|
||||
breaks e.g. tests/test/cg/tpara1
|
||||
|
||||
procedure tppcparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
|
||||
var
|
||||
paraloc : pcgparalocation;
|
||||
begin
|
||||
paraloc:=parasym.paraloc[callerside].location;
|
||||
{ No need for temps when value is pushed }
|
||||
if assigned(paraloc) and
|
||||
(paraloc^.loc=LOC_REFERENCE) and
|
||||
(paraloc^.reference.index=NR_STACK_POINTER_REG) then
|
||||
duplicateparaloc(list,calloption,parasym,cgpara)
|
||||
else
|
||||
inherited createtempparaloc(list,calloption,parasym,cgpara);
|
||||
end;
|
||||
}
|
||||
|
||||
|
||||
begin
|
||||
paramanager:=tppcparamanager.create;
|
||||
end.
|
||||
|
@ -520,25 +520,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{
|
||||
|
||||
breaks e.g. tests/test/cg/tpara1
|
||||
|
||||
procedure tppcparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
|
||||
var
|
||||
paraloc : pcgparalocation;
|
||||
begin
|
||||
paraloc:=parasym.paraloc[callerside].location;
|
||||
{ Do not create a temporary if the value is pushed }
|
||||
if assigned(paraloc) and
|
||||
(paraloc^.loc=LOC_REFERENCE) and
|
||||
(paraloc^.reference.index=NR_STACK_POINTER_REG) then
|
||||
duplicateparaloc(list,calloption,parasym,cgpara)
|
||||
else
|
||||
inherited createtempparaloc(list,calloption,parasym,cgpara);
|
||||
end;
|
||||
}
|
||||
|
||||
begin
|
||||
paramanager := tppcparamanager.create;
|
||||
end.
|
||||
|
@ -68,7 +68,7 @@ unit procinfo;
|
||||
exitswitches : tlocalswitches;
|
||||
|
||||
{ Size of the parameters on the stack }
|
||||
para_stack_size : longint;
|
||||
para_stack_size : pint;
|
||||
|
||||
{ Offset of temp after para/local are allocated }
|
||||
tempstart : longint;
|
||||
@ -195,9 +195,10 @@ implementation
|
||||
|
||||
procedure tprocinfo.generate_parameter_info;
|
||||
begin
|
||||
{ generate callee paraloc register info, it returns the size that
|
||||
{ generate callee paraloc register info, it initialises the size that
|
||||
is allocated on the stack }
|
||||
para_stack_size:=paramanager.create_paraloc_info(procdef,calleeside);
|
||||
procdef.init_paraloc_info(calleeside);
|
||||
para_stack_size:=procdef.calleeargareasize;
|
||||
end;
|
||||
|
||||
|
||||
|
@ -57,7 +57,6 @@ interface
|
||||
procedure remove_from_symtablestack;
|
||||
procedure parse_body;
|
||||
|
||||
function stack_tainting_parameter : boolean;
|
||||
function has_assembler_child : boolean;
|
||||
end;
|
||||
|
||||
@ -784,29 +783,6 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure check_for_stack(p:TObject;arg:pointer);
|
||||
begin
|
||||
if tsym(p).typ=paravarsym then
|
||||
begin
|
||||
{ check if there no parameter of the current procedure is stack dependend }
|
||||
if is_open_array(tparavarsym(p).vardef) or
|
||||
is_array_of_const(tparavarsym(p).vardef) then
|
||||
pboolean(arg)^:=true;
|
||||
if assigned(p) and
|
||||
assigned(tparavarsym(p).paraloc[calleeside].location) and
|
||||
(tparavarsym(p).paraloc[calleeside].location^.loc=LOC_REFERENCE) then
|
||||
pboolean(arg)^:=true;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tcgprocinfo.stack_tainting_parameter : boolean;
|
||||
begin
|
||||
result:=false;
|
||||
procdef.parast.SymList.ForEachCall(@check_for_stack,@result);
|
||||
end;
|
||||
|
||||
|
||||
function tcgprocinfo.has_assembler_child : boolean;
|
||||
var
|
||||
hp : tcgprocinfo;
|
||||
@ -1006,9 +982,10 @@ implementation
|
||||
parameters on the stack
|
||||
|
||||
calling generate_parameter_info doesn't hurt but it costs time
|
||||
(necessary to init para_stack_size)
|
||||
}
|
||||
generate_parameter_info;
|
||||
if not(stack_tainting_parameter) and
|
||||
if not(procdef.stack_tainting_parameter(calleeside)) and
|
||||
not(has_assembler_child) and (para_stack_size=0) then
|
||||
begin
|
||||
{ Only need to set the framepointer }
|
||||
@ -1049,11 +1026,7 @@ implementation
|
||||
|
||||
{ caller paraloc info is also necessary in the stackframe_entry
|
||||
code of the ppc (and possibly other processors) }
|
||||
if not procdef.has_paraloc_info then
|
||||
begin
|
||||
procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
|
||||
procdef.has_paraloc_info:=true;
|
||||
end;
|
||||
procdef.init_paraloc_info(callerside);
|
||||
|
||||
{ generate code for the node tree }
|
||||
do_secondpass(code);
|
||||
|
@ -225,7 +225,7 @@ type
|
||||
vt_normalvariant,vt_olevariant
|
||||
);
|
||||
|
||||
tcallercallee = (callerside,calleeside);
|
||||
tcallercallee = (callnoside,callerside,calleeside,callbothsides);
|
||||
|
||||
{ basic type for tprocdef and tprocvardef }
|
||||
tproctypeoption=(potype_none,
|
||||
|
@ -403,7 +403,8 @@ interface
|
||||
proctypeoption : tproctypeoption;
|
||||
proccalloption : tproccalloption;
|
||||
procoptions : tprocoptions;
|
||||
requiredargarea : aint;
|
||||
callerargareasize,
|
||||
calleeargareasize: pint;
|
||||
{ number of user visibile parameters }
|
||||
maxparacount,
|
||||
minparacount : byte;
|
||||
@ -411,7 +412,7 @@ interface
|
||||
exp_funcretloc : tregister; { explicit funcretloc for AmigaOS }
|
||||
{$endif}
|
||||
funcretloc : array[tcallercallee] of TCGPara;
|
||||
has_paraloc_info : boolean; { paraloc info is available }
|
||||
has_paraloc_info : tcallercallee; { paraloc info is available }
|
||||
constructor create(dt:tdeftyp;level:byte);
|
||||
constructor ppuload(dt:tdeftyp;ppufile:tcompilerppufile);
|
||||
destructor destroy;override;
|
||||
@ -424,6 +425,8 @@ interface
|
||||
function is_addressonly:boolean;virtual;
|
||||
function no_self_node:boolean;
|
||||
procedure check_mark_as_nested;
|
||||
procedure init_paraloc_info(side: tcallercallee);
|
||||
function stack_tainting_parameter(side: tcallercallee): boolean;
|
||||
private
|
||||
procedure count_para(p:TObject;arg:pointer);
|
||||
procedure insert_para(p:TObject;arg:pointer);
|
||||
@ -2760,8 +2763,9 @@ implementation
|
||||
procoptions:=[];
|
||||
returndef:=voidtype;
|
||||
savesize:=sizeof(pint);
|
||||
requiredargarea:=0;
|
||||
has_paraloc_info:=false;
|
||||
callerargareasize:=0;
|
||||
calleeargareasize:=0;
|
||||
has_paraloc_info:=callnoside;
|
||||
funcretloc[callerside].init;
|
||||
funcretloc[calleeside].init;
|
||||
check_mark_as_nested;
|
||||
@ -2885,7 +2889,8 @@ implementation
|
||||
funcretloc[callerside].ppuload(ppufile);
|
||||
|
||||
savesize:=sizeof(pint);
|
||||
has_paraloc_info:=(po_explicitparaloc in procoptions);
|
||||
if (po_explicitparaloc in procoptions) then
|
||||
has_paraloc_info:=callerside;
|
||||
end;
|
||||
|
||||
|
||||
@ -3035,6 +3040,53 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure tabstractprocdef.init_paraloc_info(side: tcallercallee);
|
||||
begin
|
||||
if (side in [callerside,callbothsides]) and
|
||||
not(has_paraloc_info in [callerside,callbothsides]) then
|
||||
begin
|
||||
callerargareasize:=paramanager.create_paraloc_info(self,callerside);
|
||||
if has_paraloc_info in [calleeside,callbothsides] then
|
||||
has_paraloc_info:=callbothsides
|
||||
else
|
||||
has_paraloc_info:=callerside;
|
||||
end;
|
||||
if (side in [calleeside,callbothsides]) and
|
||||
not(has_paraloc_info in [calleeside,callbothsides]) then
|
||||
begin
|
||||
calleeargareasize:=paramanager.create_paraloc_info(self,calleeside);
|
||||
if has_paraloc_info in [callerside,callbothsides] then
|
||||
has_paraloc_info:=callbothsides
|
||||
else
|
||||
has_paraloc_info:=calleeside;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tabstractprocdef.stack_tainting_parameter(side: tcallercallee): boolean;
|
||||
var
|
||||
p: tparavarsym;
|
||||
i: longint;
|
||||
begin
|
||||
result:=false;
|
||||
init_paraloc_info(side);
|
||||
for i:=0 to parast.SymList.Count-1 do
|
||||
if tsym(parast.SymList[i]).typ=paravarsym then
|
||||
begin
|
||||
p:=tparavarsym(parast.SymList[i]);
|
||||
{ check if no parameter is located on the stack }
|
||||
if is_open_array(p.vardef) or
|
||||
is_array_of_const(p.vardef) then
|
||||
result:=true;
|
||||
if assigned(p.paraloc[side].location) and
|
||||
(p.paraloc[side].location^.loc=LOC_REFERENCE) then
|
||||
result:=true;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
{***************************************************************************
|
||||
TPROCDEF
|
||||
***************************************************************************}
|
||||
@ -3760,7 +3812,8 @@ implementation
|
||||
tprocvardef(result).proctypeoption:=proctypeoption;
|
||||
tprocvardef(result).proccalloption:=proccalloption;
|
||||
tprocvardef(result).procoptions:=procoptions;
|
||||
tprocvardef(result).requiredargarea:=requiredargarea;
|
||||
tprocvardef(result).callerargareasize:=callerargareasize;
|
||||
tprocvardef(result).calleeargareasize:=calleeargareasize;
|
||||
tprocvardef(result).maxparacount:=maxparacount;
|
||||
tprocvardef(result).minparacount:=minparacount;
|
||||
for i:=low(tcallercallee) to high(tcallercallee) do
|
||||
|
@ -159,7 +159,8 @@ begin
|
||||
On 64bit systems, page zero is 4GB by default, so no problems
|
||||
there.
|
||||
}
|
||||
ExeCmd[1]:='ld $PRTOBJ $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -pagezero_size 0x10000 -multiply_defined suppress -L. -o $EXE `cat $RES`';
|
||||
// ExeCmd[1]:='ld $PRTOBJ $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -pagezero_size 0x10000 -multiply_defined suppress -L. -o $EXE `cat $RES`';
|
||||
ExeCmd[1]:='ld $PRTOBJ $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -multiply_defined suppress -L. -o $EXE `cat $RES`';
|
||||
{$else ndef cpu64bitaddr}
|
||||
ExeCmd[1]:='ld $PRTOBJ $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -multiply_defined suppress -L. -o $EXE `cat $RES`';
|
||||
{$endif ndef cpu64bitaddr}
|
||||
|
Loading…
Reference in New Issue
Block a user