Ver Fonte

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

Jonas Maebe há 10 anos atrás
pai
commit
a58504990a
4 ficheiros alterados com 68 adições e 55 exclusões
  1. 6 6
      compiler/llvm/hlcgllvm.pas
  2. 0 41
      compiler/llvm/symllvm.pas
  3. 22 7
      compiler/psub.pas
  4. 40 1
      compiler/symcreat.pas

+ 6 - 6
compiler/llvm/hlcgllvm.pas

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

+ 0 - 41
compiler/llvm/symllvm.pas

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

+ 22 - 7
compiler/psub.pas

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

+ 40 - 1
compiler/symcreat.pas

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