* force pointer-based self parameters of inlined routines in temps for LLVM

to ensure that their type gets updated

git-svn-id: trunk@40631 -
This commit is contained in:
Jonas Maebe 2018-12-24 22:09:55 +00:00
parent 3ccc3e329b
commit eb769e3859
2 changed files with 110 additions and 89 deletions

View File

@ -27,7 +27,7 @@ interface
uses
parabase,
ncgcal,
ncal,ncgcal,
cgutils;
type
@ -38,6 +38,7 @@ interface
tllvmcallnode = class(tcgcallnode)
protected
function paraneedsinlinetemp(para: tcallparanode; const pushconstaddr, complexpara: boolean): boolean; override;
function can_call_ref(var ref: treference): boolean; override;
procedure pushparas; override;
end;
@ -47,7 +48,7 @@ implementation
uses
verbose,
ncal;
symconst,symdef;
{*****************************************************************************
TLLVMCALLPARANODE
@ -64,6 +65,25 @@ implementation
TLLVMCALLNODE
*****************************************************************************}
function tllvmcallnode.paraneedsinlinetemp(para: tcallparanode; const pushconstaddr, complexpara: boolean): boolean;
begin
{ We don't insert type conversions for self node trees to the type of
the self parameter (and doing so is quite hard due to all kinds of
ugly hacks with this parameter). This means that if we pass on a
self parameter through multiple levels of inlining, it may no
longer match the actual type of the parameter it has been passed to
-> always store in a temp which by definition will have the right
type (if it's a pointer-like type) }
if (vo_is_self in para.parasym.varoptions) and
(is_class_or_interface_or_dispinterface(para.parasym.vardef) or
is_classhelper(para.parasym.vardef) or
((para.parasym.vardef.typ=classrefdef) and
is_class(tclassrefdef(para.parasym.vardef).pointeddef))) then
result:=true
else
result:=inherited;
end;
function tllvmcallnode.can_call_ref(var ref: treference): boolean;
begin
result:=false;

View File

@ -108,6 +108,7 @@ interface
it's not strictly necessary) for speed and code size reasons.
Returns true if the temp creation has been handled, false otherwise
}
function paraneedsinlinetemp(para: tcallparanode; const pushconstaddr, complexpara: boolean): boolean; virtual;
function maybecreateinlineparatemp(para: tcallparanode; out complexpara: boolean): boolean;
procedure createinlineparas;
procedure wrapcomplexinlinepara(para: tcallparanode); virtual;
@ -4624,14 +4625,7 @@ implementation
end;
function tcallnode.maybecreateinlineparatemp(para: tcallparanode; out complexpara: boolean): boolean;
var
tempnode: ttempcreatenode;
realtarget: tnode;
paracomplexity: longint;
pushconstaddr: boolean;
function needtemp: boolean;
function tcallnode.paraneedsinlinetemp(para: tcallparanode; const pushconstaddr, complexpara: boolean): boolean;
begin
{ We need a temp if the passed value will not be in memory, while
the parameter inside the routine must be in memory }
@ -4716,6 +4710,13 @@ implementation
result:=false;
end;
function tcallnode.maybecreateinlineparatemp(para: tcallparanode; out complexpara: boolean): boolean;
var
tempnode: ttempcreatenode;
realtarget: tnode;
paracomplexity: longint;
pushconstaddr: boolean;
begin
result:=false;
{ determine how a parameter is passed to the inlined body
@ -4773,7 +4774,7 @@ implementation
{ check if we have to create a temp, assign the parameter's
contents to that temp and then substitute the parameter
with the temp everywhere in the function }
if needtemp then
if paraneedsinlinetemp(para,pushconstaddr,complexpara) then
begin
tempnode:=ctempcreatenode.create(para.parasym.vardef,para.parasym.vardef.size,
tt_persistent,tparavarsym(para.parasym).is_regvar(false));