mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 21:48:09 +02:00
* fixed llvm handling of routines that are normally declared in the
interface of a unit, or forward declared, and then the implementation turns out to be external. We now properly generate a wrapper routine at the Pascal level for the original declaration that calls through to the external routine git-svn-id: trunk@31285 -
This commit is contained in:
parent
1cdaf8e332
commit
a58504990a
@ -1060,13 +1060,13 @@ implementation
|
||||
|
||||
|
||||
procedure thlcgllvm.handle_external_proc(list: TAsmList; pd: tprocdef; const importname: TSymStr);
|
||||
var
|
||||
asmsym: tasmsymbol;
|
||||
begin
|
||||
{ Windows-style import names are not yet supported -> ignore
|
||||
importname for now }
|
||||
asmsym:=current_asmdata.RefAsmSymbol(tllvmprocdef(pd).external_mangledname,AT_FUNCTION);
|
||||
list.concat(taillvmalias.create(asmsym,pd.mangledname,pd,llv_default,lll_internal));
|
||||
{ don't do anything, because at this point we can't know yet for certain
|
||||
whether the aliased routine is internal to the current routine or not.
|
||||
If it's internal, we would have to generate an llvm alias, while if it's
|
||||
external, we would have to generate a declaration. Additionally, aliases
|
||||
cannot refer to declarations, so always creating aliases doesn't work
|
||||
either -> handle in llvmtype }
|
||||
end;
|
||||
|
||||
|
||||
|
@ -76,16 +76,7 @@ type
|
||||
tllvmprocvardef = class(tcpuprocvardef)
|
||||
end;
|
||||
|
||||
{ tllvmprocdef }
|
||||
|
||||
tllvmprocdef = class(tcpuprocdef)
|
||||
protected
|
||||
external_decl_mangled_name: TSymStr;
|
||||
public
|
||||
{ overried the mangled name of external functions }
|
||||
function mangledname: TSymStr; override;
|
||||
{ provide access to the original mangled name of external functions }
|
||||
function external_mangledname: TSymStr;
|
||||
end;
|
||||
|
||||
tllvmstringdef = class(tcpustringdef)
|
||||
@ -149,38 +140,6 @@ implementation
|
||||
uses
|
||||
symconst,symdef,symsym;
|
||||
|
||||
{ tllvmprocdef }
|
||||
|
||||
function tllvmprocdef.mangledname: TSymStr;
|
||||
begin
|
||||
{ External declarations are handled separately for the LLVM target and need
|
||||
a different mangled name than on other targets, because we have to
|
||||
create a declaration based on the declared name that redirects to the
|
||||
external name in order to deal with potential different signatures between
|
||||
the external declaration the symbol that's referred.
|
||||
|
||||
There's no need to store the external_decl_mangled_name in the ppu file,
|
||||
since it can always be regenerated on the fly. }
|
||||
if not(po_external in procoptions) then
|
||||
result:=inherited
|
||||
else
|
||||
begin
|
||||
if external_decl_mangled_name='' then
|
||||
begin
|
||||
result:=defaultmangledname;
|
||||
external_decl_mangled_name:=result;
|
||||
end
|
||||
else
|
||||
result:=external_decl_mangled_name;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tllvmprocdef.external_mangledname: TSymStr;
|
||||
begin
|
||||
result:=inherited mangledname;
|
||||
end;
|
||||
|
||||
begin
|
||||
{ used tdef classes }
|
||||
cfiledef:=tllvmfiledef;
|
||||
|
@ -2158,13 +2158,28 @@ implementation
|
||||
if tf_has_dllscanner in target_info.flags then
|
||||
current_module.dllscannerinputlist.Add(proc_get_importname(pd),pd);
|
||||
end;
|
||||
|
||||
create_hlcodegen;
|
||||
hlcg.handle_external_proc(
|
||||
current_asmdata.asmlists[al_procedures],
|
||||
pd,
|
||||
proc_get_importname(pd));
|
||||
destroy_hlcodegen;
|
||||
{$ifdef cpuhighleveltarget}
|
||||
{ it's hard to factor this out in a virtual method, because the
|
||||
generic version (the one inside this ifdef) doesn't fit in
|
||||
hlcgobj but in symcreat or here, while the other version
|
||||
doesn't fit in symcreat (since it uses the code generator).
|
||||
Maybe we need another class for this kind of code that could
|
||||
either be symcreat- or hlcgobj-based
|
||||
}
|
||||
if (not pd.forwarddef) and
|
||||
(pd.hasforward) and
|
||||
(proc_get_importname(pd)<>'') then
|
||||
call_through_new_name(pd,proc_get_importname(pd))
|
||||
else
|
||||
{$endif cpuhighleveltarget}
|
||||
begin
|
||||
create_hlcodegen;
|
||||
hlcg.handle_external_proc(
|
||||
current_asmdata.asmlists[al_procedures],
|
||||
pd,
|
||||
proc_get_importname(pd));
|
||||
destroy_hlcodegen;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -114,13 +114,18 @@ interface
|
||||
created staticvarsym that is responsible for allocating the global storage }
|
||||
function make_field_static(recst: tsymtable; fieldvs: tfieldvarsym): tstaticvarsym;
|
||||
|
||||
{ create a new procdef with the signature of orgpd and (mangled) name
|
||||
newname, and change the implementation of orgpd so that it calls through
|
||||
to this new procedure }
|
||||
procedure call_through_new_name(orgpd: tprocdef; const newname: TSymStr);
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
cutils,cclasses,globals,verbose,systems,comphook,fmodule,
|
||||
symtable,defutil,
|
||||
pbase,pdecobj,pdecsub,psub,ptconst,
|
||||
pbase,pdecobj,pdecsub,psub,ptconst,pparautl,
|
||||
{$ifdef jvm}
|
||||
pjvm,jvmdef,
|
||||
{$endif jvm}
|
||||
@ -1324,5 +1329,39 @@ implementation
|
||||
result:=hstaticvs;
|
||||
end;
|
||||
|
||||
|
||||
procedure call_through_new_name(orgpd: tprocdef; const newname: TSymStr);
|
||||
var
|
||||
newpd: tprocdef;
|
||||
begin
|
||||
{ we have a forward declaration like
|
||||
procedure test; (in the unit interface or "forward")
|
||||
and then an implementation like
|
||||
procedure test; external name 'something';
|
||||
|
||||
To solve this, we create a new external procdef for the
|
||||
implementation, and then generate a procedure body for the original
|
||||
one that calls through to the external procdef. This is necessary
|
||||
because there may already be references to the mangled name for the
|
||||
non-external "test".
|
||||
}
|
||||
newpd:=tprocdef(orgpd.getcopyas(procdef,pc_bareproc));
|
||||
insert_funcret_para(newpd);
|
||||
newpd.procoptions:=newpd.procoptions+orgpd.procoptions*[po_external,po_has_importname,po_has_importdll];
|
||||
newpd.import_name:=orgpd.import_name;
|
||||
orgpd.import_name:=nil;
|
||||
newpd.import_dll:=orgpd.import_dll;
|
||||
newpd.import_dll:=nil;
|
||||
newpd.import_nr:=orgpd.import_nr;
|
||||
orgpd.import_nr:=0;
|
||||
newpd.setmangledname(newname);
|
||||
finish_copied_procdef(newpd,'__FPC_IMPL_EXTERNAL_REDIRECT_'+newname,current_module.localsymtable,nil);
|
||||
newpd.forwarddef:=false;
|
||||
orgpd.skpara:=newpd;
|
||||
orgpd.synthetickind:=tsk_callthrough;
|
||||
orgpd.procoptions:=orgpd.procoptions-[po_external,po_has_importname,po_has_importdll];
|
||||
orgpd.forwarddef:=true;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user