Browse Source

* reworked and fixed llvm procdef handling (except for variadic C functions):
o handle parameters and function results divided over multiple paralocs,
including generating fake recorddefs that represent
o fixed zero/sign extension handling
o properly handle difference between procdefs as printed for the
implementation, an alias declaration or a procvar definition

git-svn-id: branches/hlcgllvm@27009 -

Jonas Maebe 11 năm trước cách đây
mục cha
commit
02ca215272

+ 13 - 0
compiler/fmodule.pas

@@ -144,6 +144,9 @@ interface
         symlist       : TFPObjectList;
         ptrdefs       : THashSet; { list of pointerdefs created in this module so we can reuse them (not saved/restored) }
         arraydefs     : THashSet; { list of single-element-arraydefs created in this module so we can reuse them (not saved/restored) }
+{$ifdef llvm}
+        llvmdefs      : THashSet; { defs added for llvm-specific reasons (not saved/restored) }
+{$endif llvm}
         ansistrdef    : tobject; { an ansistring def redefined for the current module }
         wpoinfo       : tunitwpoinfobase; { whole program optimization-related information that is generated during the current run for this unit }
         globalsymtable,           { pointer to the global symtable of this unit }
@@ -548,6 +551,9 @@ implementation
         symlist:=TFPObjectList.Create(false);
         ptrdefs:=THashSet.Create(64,true,false);
         arraydefs:=THashSet.Create(64,true,false);
+{$ifdef llvm}
+        llvmdefs:=THashSet.Create(64,true,false);
+{$endif llvm}
         ansistrdef:=nil;
         wpoinfo:=nil;
         checkforwarddefs:=TFPObjectList.Create(false);
@@ -662,6 +668,9 @@ implementation
         symlist.free;
         ptrdefs.free;
         arraydefs.free;
+{$ifdef llvm}
+        llvmdefs.free;
+{$endif llvm}
         ansistrdef:=nil;
         wpoinfo.free;
         checkforwarddefs.free;
@@ -726,6 +735,10 @@ implementation
         ptrdefs:=THashSet.Create(64,true,false);
         arraydefs.free;
         arraydefs:=THashSet.Create(64,true,false);
+{$ifdef llvm}
+        llvmdefs.free;
+        llvmdefs:=THashSet.Create(64,true,false);
+{$endif llvm}
         wpoinfo.free;
         wpoinfo:=nil;
         checkforwarddefs.free;

+ 2 - 2
compiler/llvm/agllvm.pas

@@ -601,7 +601,7 @@ implementation
            ait_llvmprocdef:
              begin
                asmwrite('define ');
-               asmwrite(llvmencodeproctype(taillvmprocdef(hp).procdef,true,true));
+               asmwrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def),'',lpd_decl));
                asmwriteln(' {');
              end;
            ait_llvmvarsym:
@@ -633,7 +633,7 @@ implementation
                    asmwrite(copy(s,length('llv_'),255));
                    asmwrite(' ');
                  end;
-               asmwrite(llvmencodetype(taillvmalias(hp).def));
+               asmwrite(llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def),'',lpd_alias));
                asmwrite('* ');
                asmwriteln(taillvmalias(hp).oldsym.name);
              end;

+ 6 - 0
compiler/llvm/llvmbase.pas

@@ -69,11 +69,17 @@ interface
       la_type { type definition }
     );
 
+    tllvmvalueextension = (lve_none, lve_zeroext, lve_signext);
+
   const
     llvmterminatoropcodes = [la_ret, la_br, la_switch, la_indirectbr,
       la_invoke, la_resume,
       la_unreachable];
 
+    llvmvalueextension2str: array[tllvmvalueextension] of TSymStr = ('',
+      ' zeroext',' signext');
+
+
   type
     tllvmfpcmp = (
       lfc_false,

+ 231 - 89
compiler/llvm/llvmdef.pas

@@ -27,8 +27,23 @@ unit llvmdef;
 interface
 
     uses
-      globtype,
-      symbase,symtype,symdef;
+      cclasses,globtype,
+      parabase,
+      symbase,symtype,symdef,
+      llvmbase;
+
+   type
+     { there are three different circumstances in which procdefs are used:
+        a) definition of a procdef that's implemented in the current module or
+           declaration of an external routine that's called in the current one
+        b) alias declaration of a procdef implemented in the current module
+        c) defining a procvar type
+       The main differences between the contexts are:
+        a) information about sign extension of result type, proc name, parameter names & types
+        b) no information about sign extension of result type, proc name, no parameter names, parameter types
+        c) information about sign extension of result type, no proc name, no parameter names, parameter types
+      }
+     tllvmprocdefdecltype = (lpd_decl,lpd_alias,lpd_procvar);
 
     { Encode a type into the internal format used by LLVM. }
     function llvmencodetype(def: tdef): TSymStr;
@@ -38,8 +53,42 @@ interface
       aggregate type (array, record, ...) }
     procedure llvmaddencodedtype(def: tdef; inaggregate: boolean; var encodedstr: TSymStr);
 
-    function llvmencodeproctype(def: tabstractprocdef; withprocname, withparanames: boolean): TSymStr;
-    procedure llvmaddencodedproctype(def: tabstractprocdef; withprocname, withparanames: boolean; var encodedstr: TSymStr);
+    { encode a procdef/procvardef into the internal format used by LLVM }
+    function llvmencodeproctype(def: tabstractprocdef; const customname: TSymStr; pddecltype: tllvmprocdefdecltype): TSymStr;
+    { incremental version of the above }
+    procedure llvmaddencodedproctype(def: tabstractprocdef; const customname: TSymStr; pddecltype: tllvmprocdefdecltype; var encodedstr: TSymStr);
+
+    { function result types may have to be represented differently, e.g. a
+      record consisting of 4 longints must be returned as a record consisting of
+      two int64's on x86-64. This function is used to create (and reuse)
+      temporary recorddefs for such purposes.}
+    function llvmgettemprecorddef(fieldtypes: tfplist; packrecords: shortint): trecorddef;
+
+    { get the llvm type corresponding to a parameter, e.g. a record containing
+      two integer int64 for an arbitrary record split over two individual int64
+      parameters, or an int32 for an int16 parameter on a platform that requires
+      such parameters to be zero/sign extended. The second parameter can be used
+      to get the type before zero/sign extension, as e.g. required to generate
+      function declarations. }
+    function llvmgetcgparadef(const cgpara: tcgpara; beforevalueext: boolean): tdef;
+
+    { can be used to extract the value extension info from acgpara. Pass in
+      the def of the cgpara as first parameter and a local variable holding
+      a copy of the def of the location (value extension only makes sense for
+      ordinal parameters that are smaller than a single location). The routine
+      will return the def of the location without sign extension (if applicable)
+      and the kind of sign extension that was originally performed in the
+      signext parameter }
+    procedure llvmextractvalueextinfo(paradef: tdef; var paralocdef: tdef; out signext: tllvmvalueextension);
+
+    { returns whether a paraloc should be translated into an llvm "byval"
+      parameter. These are declared as pointers to a particular type, but
+      usually turned into copies onto the stack. The exact behaviour for
+      parameters that should be passed in registers is undefined and depends on
+      the platform, and furthermore this modifier sometimes inhibits
+      optimizations.  As a result,we only use it for aggregate parameters of
+      which we know that they should be passed on the stack }
+    function llvmbyvalparaloc(paraloc: pcgparalocation): boolean;
 
     { returns whether a def is representated by an aggregate type in llvm
       (struct, array) }
@@ -49,12 +98,13 @@ interface
 implementation
 
   uses
-    cutils,cclasses,constexp,
+    cutils,constexp,
     verbose,systems,
     fmodule,
     symtable,symconst,symsym,
     llvmsym,
-    defutil,cgbase,parabase,paramgr;
+    defutil,cgbase,paramgr;
+
 
 {******************************************************************
                           Type encoding
@@ -75,6 +125,23 @@ implementation
     end;
 
 
+  function llvmbyvalparaloc(paraloc: pcgparalocation): boolean;
+    begin
+      { "byval" is broken for register paras on several platforms in llvm
+        (search for "byval" in llvm's bug tracker). Additionally, it should only
+        be used to pass aggregate parameters on the stack, because it reportedly
+        inhibits llvm's midlevel optimizers.
+
+        Exception (for now?): parameters that have special shifting
+          requirements, because modelling those in llvm is not easy (and clang
+          nor llvm-gcc seem to do so either) }
+      result:=
+        ((paraloc^.loc=LOC_REFERENCE) and
+         llvmaggregatetype(paraloc^.def)) or
+        (paraloc^.shiftval<>0)
+    end;
+
+
     procedure llvmaddencodedabstractrecordtype(def: tabstractrecorddef; var encodedstr: TSymStr); forward;
 
     procedure llvmaddencodedtype_intern(def: tdef; inaggregate, noimplicitderef: boolean; var encodedstr: TSymStr);
@@ -210,7 +277,7 @@ implementation
                 end
               else if is_dynamic_array(def) then
                 begin
-                  llvmaddencodedtype_intern(tarraydef(def).elementdef,false,false,encodedstr);
+                  llvmaddencodedtype_intern(tarraydef(def).elementdef,inaggregate,false,encodedstr);
                   encodedstr:=encodedstr+'*';
                 end
               else if is_packed_array(def) then
@@ -232,14 +299,14 @@ implementation
             begin
               if tprocvardef(def).is_addressonly then
                 begin
-                  llvmaddencodedproctype(tprocdef(def),false,false,encodedstr);
+                  llvmaddencodedproctype(tprocdef(def),'',lpd_procvar,encodedstr);
                   encodedstr:=encodedstr+'*';
                 end
               else
                 begin
                   encodedstr:=encodedstr+'{';
                   { code pointer }
-                  llvmaddencodedproctype(tprocvardef(def),false,false,encodedstr);
+                  llvmaddencodedproctype(tprocvardef(def),'',lpd_procvar,encodedstr);
                   { data pointer (maybe todo: generate actual layout if
                     available) }
                   encodedstr:=encodedstr+'*, i8*}';
@@ -276,7 +343,8 @@ implementation
             internalerror(2013100604);
           procdef :
             begin
-              llvmaddencodedproctype(tprocdef(def),true,false,encodedstr);
+              { should be handled via llvmencodeproctype/llvmaddencodedproctype }
+              internalerror(2014012601);
             end;
         else
           internalerror(2013100603);
@@ -329,7 +397,7 @@ implementation
       end;
 
 
-    procedure llvmrefineordinaldef(paradef, paralocdef: tdef; out usedef: tdef; out signextstr: TSymStr);
+    procedure llvmextractvalueextinfo(paradef: tdef; var paralocdef: tdef; out signext: tllvmvalueextension);
       begin
         { implicit zero/sign extension for ABI compliance? (yes, if the size
           of a paraloc is larger than the size of the entire parameter) }
@@ -337,79 +405,28 @@ implementation
            is_ordinal(paralocdef) and
            (paradef.size<paralocdef.size) then
           begin
-            usedef:=paradef;
+            paralocdef:=paradef;
             if is_signed(paradef) then
-              signextstr:='signext '
+              signext:=lve_signext
             else
-              signextstr:='zeroext '
+              signext:=lve_zeroext
           end
         else
-          begin
-            usedef:=paralocdef;
-            signextstr:='';
-          end;
+          signext:=lve_none;
       end;
 
 
-    procedure llvmaddencodedparaloctype(hp: tparavarsym; const para: tcgpara; proccalloption: tproccalloption; withparaname: boolean; var first: boolean; var encodedstr: TSymStr);
-
-      { the default for llvm is to pass aggregates in integer registers or
-        on the stack (as the ABI prescribes). Records that require special
-        handling, e.g. (partly) passing in fpu registers, have to be handled
-        explicitly. This function returns whether an aggregate is handled
-        specially }
-      function hasnondefaultparaloc: boolean;
-        var
-          loc: PCGParaLocation;
-        begin
-          loc:=para.Location;
-          result:=true;
-          while assigned(loc) do
-            begin
-              if not(loc^.loc in [LOC_REGISTER,LOC_REFERENCE]) then
-                exit;
-            end;
-          result:=false;
-        end;
-
+    procedure llvmaddencodedparaloctype(hp: tparavarsym; proccalloption: tproccalloption; withparaname: boolean; var first: boolean; var encodedstr: TSymStr);
       var
         paraloc: PCGParaLocation;
-        signextstr: TSymStr;
+        signext: tllvmvalueextension;
         usedef: tdef;
-        closestruct: boolean;
       begin
-        { byval: a pointer to a type that should actually be passed by
-            value (e.g. a record that should be passed on the stack) }
-         if assigned(hp) and
-            (hp.vardef.typ in [arraydef,recorddef,objectdef]) and
-            not paramanager.push_addr_param(hp.varspez,hp.vardef,proccalloption) and
-            not hasnondefaultparaloc then
-          begin
-            llvmaddencodedtype(hp.vardef,false,encodedstr);
-            encodedstr:=encodedstr+'* byval';
-            if withparaname then
-              encodedstr:=encodedstr+' '+para.location^.llvmloc.name;
-            exit;
-          end;
-
-        closestruct:=false;
-        paraloc:=para.location;
-        if not assigned(hp) then
-          begin
-            { if a function returns a composite value (e.g. 2 sse register),
-              those are represented as a struct }
-            if assigned(paraloc^.next) then
-              begin
-                encodedstr:=encodedstr+'{';
-                closestruct:=true;
-              end;
-          end;
+        paraloc:=hp.paraloc[calleeside].location;
         repeat
           usedef:=paraloc^.def;
-          llvmrefineordinaldef(para.def,paraloc^.def,usedef,signextstr);
+          llvmextractvalueextinfo(hp.vardef,usedef,signext);
           { implicit zero/sign extension for ABI compliance? }
-          if not assigned(hp) then
-            encodedstr:=encodedstr+signextstr;
           if not first then
              encodedstr:=encodedstr+', '
           else
@@ -418,60 +435,185 @@ implementation
           { in case signextstr<>'', there should be only one paraloc -> no need
             to clear (reason: it means that the paraloc is larger than the
             original parameter) }
-          if assigned(hp) then
-            encodedstr:=encodedstr+signextstr;
-          if assigned(hp) then
+          encodedstr:=encodedstr+llvmvalueextension2str[signext];
+          { sret: hidden pointer for structured function result }
+          if vo_is_funcret in hp.varoptions then
+            encodedstr:=encodedstr+' sret'
+          else if not paramanager.push_addr_param(hp.varspez,hp.vardef,proccalloption) and
+             llvmbyvalparaloc(paraloc) then
+            encodedstr:=encodedstr+'* byval';
+          if withparaname then
             begin
-              { sret: hidden pointer for structured function result }
-              if vo_is_funcret in hp.varoptions then
-                encodedstr:=encodedstr+' sret'
+              if paraloc^.llvmloc.loc<>LOC_REFERENCE then
+                internalerror(2014010803);
+              encodedstr:=encodedstr+' '+paraloc^.llvmloc.sym.name;
             end;
-          if withparaname then
-            encodedstr:=encodedstr+' '+paraloc^.llvmloc.name;
           paraloc:=paraloc^.next;
         until not assigned(paraloc);
-        if closestruct then
-          encodedstr:=encodedstr+'}'
       end;
 
 
-    function llvmencodeproctype(def: tabstractprocdef; withprocname, withparanames: boolean): TSymStr;
+    function llvmencodeproctype(def: tabstractprocdef; const customname: TSymStr; pddecltype: tllvmprocdefdecltype): TSymStr;
       begin
         result:='';
-        llvmaddencodedproctype(def,withprocname,withparanames,result);
+        llvmaddencodedproctype(def,customname,pddecltype,result);
       end;
 
 
-    procedure llvmaddencodedproctype(def: tabstractprocdef; withprocname, withparanames: boolean; var encodedstr: TSymStr);
+    procedure llvmaddencodedproctype(def: tabstractprocdef; const customname: TSymStr; pddecltype: tllvmprocdefdecltype; var encodedstr: TSymStr);
       var
+        usedef: tdef;
         paranr: longint;
-        para: tcgpara;
         hp: tparavarsym;
+        signext: tllvmvalueextension;
         first: boolean;
       begin
         def.init_paraloc_info(calleeside);
         first:=true;
         { function result (return-by-ref is handled explicitly) }
         if not paramanager.ret_in_param(def.returndef,def) then
-          llvmaddencodedparaloctype(nil,def.funcretloc[calleeside],def.proccalloption,false,first,encodedstr)
+          begin
+            usedef:=llvmgetcgparadef(def.funcretloc[calleeside],false);
+            llvmextractvalueextinfo(def.returndef,usedef,signext);
+            { specifying result sign extention information for an alias causes
+              an error for some reason }
+            if pddecltype in [lpd_decl,lpd_procvar] then
+              encodedstr:=encodedstr+llvmvalueextension2str[signext];
+            encodedstr:=encodedstr+' ';
+            llvmaddencodedtype_intern(usedef,false,false,encodedstr);
+          end
         else
-          llvmaddencodedtype(voidtype,false,encodedstr);
+          begin
+            encodedstr:=encodedstr+' ';
+            llvmaddencodedtype(voidtype,false,encodedstr);
+          end;
         encodedstr:=encodedstr+' ';
-        if withprocname and
+        { add procname? }
+        if (pddecltype in [lpd_decl]) and
            (def.typ=procdef) then
-          encodedstr:=encodedstr+tprocdef(def).mangledname;
+          if customname='' then
+            encodedstr:=encodedstr+tprocdef(def).mangledname
+          else
+            encodedstr:=encodedstr+customname;
         encodedstr:=encodedstr+'(';
         { parameters }
         first:=true;
         for paranr:=0 to def.paras.count-1 do
           begin
             hp:=tparavarsym(def.paras[paranr]);
-            llvmaddencodedparaloctype(hp,hp.paraloc[calleeside],def.proccalloption,withparanames,first,encodedstr);
+            llvmaddencodedparaloctype(hp,def.proccalloption,pddecltype in [lpd_decl],first,encodedstr);
           end;
         encodedstr:=encodedstr+')'
       end;
 
 
+    function llvmgettemprecorddef(fieldtypes: tfplist; packrecords: shortint): trecorddef;
+      var
+        i: longint;
+        res: PHashSetItem;
+        oldsymtablestack: tsymtablestack;
+        hrecst: trecordsymtable;
+        hdef: tdef;
+        hrecdef: trecorddef;
+        sym: tfieldvarsym;
+        typename: string;
+      begin
+        typename:='$llvmstruct_';
+        for i:=0 to fieldtypes.count-1 do
+          begin
+            hdef:=tdef(fieldtypes[i]);
+            case hdef.typ of
+              orddef:
+                case torddef(hdef).ordtype of
+                  s8bit,
+                  u8bit:
+                    typename:=typename+'i8';
+                  s16bit,
+                  u16bit:
+                    typename:=typename+'i16';
+                  s32bit,
+                  u32bit:
+                    typename:=typename+'i32';
+                  s64bit,
+                  u64bit:
+                    typename:=typename+'i64';
+                  else
+                    { other types should not appear currently, add as needed }
+                    internalerror(2014012001);
+                end;
+              floatdef:
+                case tfloatdef(hdef).floattype of
+                  s32real:
+                    typename:=typename+'f32';
+                  s64real:
+                    typename:=typename+'f64';
+                  else
+                    { other types should not appear currently, add as needed }
+                    internalerror(2014012008);
+                  end;
+              else
+                { other types should not appear currently, add as needed }
+                internalerror(2014012009);
+            end;
+          end;
+        if not assigned(current_module) then
+          internalerror(2014012002);
+        res:=current_module.llvmdefs.FindOrAdd(@typename[1],length(typename));
+        if not assigned(res^.Data) then
+          begin
+            oldsymtablestack:=symtablestack;
+            { do not simply push/pop current_module.localsymtable, because
+              that can have side-effects (e.g., it removes helpers) }
+            symtablestack:=nil;
+
+            hrecst:=trecordsymtable.create(typename,packrecords);
+            hrecdef:=trecorddef.create(typename,hrecst);
+            for i:=0 to fieldtypes.count-1 do
+              begin
+                sym:=tfieldvarsym.create('$f'+tostr(i),vs_value,tdef(fieldtypes[i]),[]);
+                hrecst.insert(sym);
+                hrecst.addfield(sym,vis_hidden);
+              end;
+
+            res^.Data:=hrecdef;
+            if assigned(current_module.localsymtable) then
+              current_module.localsymtable.insertdef(tdef(res^.Data))
+            else
+              current_module.globalsymtable.insertdef(tdef(res^.Data));
+            symtablestack:=oldsymtablestack;
+          end;
+        result:=trecorddef(res^.Data);
+      end;
+
+
+    function llvmgetcgparadef(const cgpara: tcgpara; beforevalueext: boolean): tdef;
+      var
+        retdeflist: tfplist;
+        retloc: pcgparalocation;
+        usedef: tdef;
+        valueext: tllvmvalueextension;
+      begin
+        { single location }
+        if not assigned(cgpara.location^.next) then
+          begin
+            { def of the location, except in case of zero/sign-extension }
+            usedef:=cgpara.location^.def;
+            if beforevalueext then
+              llvmextractvalueextinfo(cgpara.def,usedef,valueext);
+            result:=usedef;
+            exit
+          end;
+        { multiple locations -> create temp record }
+        retdeflist:=tfplist.create;
+        retloc:=cgpara.location;
+        repeat
+          retdeflist.add(retloc^.def);
+          retloc:=retloc^.next;
+        until not assigned(retloc);
+        result:=llvmgettemprecorddef(retdeflist,C_alignment);
+      end;
+
+
     function llvmencodetype(def: tdef): TSymStr;
       begin
         result:='';

+ 36 - 78
compiler/llvm/llvmpara.pas

@@ -58,11 +58,11 @@ unit llvmpara;
   implementation
 
     uses
+      verbose,
       aasmbase,
       llvmsym,
-      paramgr,
-      cgbase,hlcgobj;
-
+      paramgr,defutil,llvmdef,
+      cgbase,cgutils,tgobj,hlcgobj;
 
   { tllvmparamanager }
 
@@ -93,102 +93,60 @@ unit llvmpara;
         add_llvm_callee_paraloc_names(p)
     end;
 
+
+  function tllvmparamanager.get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+    var
+      paraloc: pcgparalocation;
+    begin
+      result:=inherited;
+      paraloc:=result.location;
+      repeat
+        paraloc^.llvmvalueloc:=true;
+        paraloc:=paraloc^.next;
+      until not assigned(paraloc);
+    end;
+
+
   { hp non-nil: parasym to check
     hp nil: function result
   }
   procedure tllvmparamanager.set_llvm_paraloc_name(p: tabstractprocdef; hp: tparavarsym; var para: tcgpara);
-
-    { the default for llvm is to pass aggregates in integer registers or
-      on the stack (as the ABI prescribes). Records that require special
-      handling, e.g. (partly) passing in fpu registers, have to be handled
-      explicitly. This function returns whether an aggregate is handled
-      specially }
-    function has_non_default_paraloc: boolean;
-      var
-        loc: PCGParaLocation;
-      begin
-        loc:=para.Location;
-        result:=true;
-        while assigned(loc) do
-          begin
-            if not(loc^.loc in [LOC_REGISTER,LOC_REFERENCE]) then
-              exit;
-          end;
-        result:=false;
-      end;
-
     var
       paraloc: PCGParaLocation;
-      signextstr: TSymStr;
-      usedef: tdef;
       paralocnr: longint;
     begin
-      { byval: a pointer to a type that should actually be passed by
-          value (e.g. a record that should be passed on the stack) }
-       if (assigned(hp) and
-           (hp.vardef.typ in [arraydef,recorddef,objectdef]) and
-           not paramanager.push_addr_param(hp.varspez,hp.vardef,p.proccalloption) and
-           not has_non_default_paraloc) or
-          (not assigned(hp) and
-           ret_in_param(para.def,p)) then
-        begin
-          { the first location is the name of the "byval" parameter }
-          paraloc:=para.location;
-          if assigned(hp) then
-             begin
-              paraloc^.llvmloc:=current_asmdata.DefineAsmSymbol(llvmparaname(hp,0),AB_LOCAL,AT_DATA);
-              paraloc^.llvmvalueloc:=false;
-             end
-          else
-            begin
-              paraloc^.llvmloc:=current_asmdata.DefineAsmSymbol('%f.result',AB_LOCAL,AT_DATA);
-              paraloc^.llvmvalueloc:=true;
-            end;
-          { the other locations, if any, are not represented individually; llvm
-            takes care of them behind the scenes }
-          while assigned(paraloc^.next) do
-            begin
-              paraloc:=paraloc^.next;
-              paraloc^.llvmloc:=nil;
-            end;
-          exit;
-        end;
       paraloc:=hp.paraloc[calleeside].location;
       paralocnr:=0;
       repeat
-        paraloc^.llvmloc:=current_asmdata.DefineAsmSymbol(llvmparaname(hp,paralocnr),AB_LOCAL,AT_DATA);
-        paraloc^.llvmvalueloc:=true;
+        paraloc^.llvmloc.loc:=LOC_REFERENCE;
+        paraloc^.llvmloc.sym:=current_asmdata.DefineAsmSymbol(llvmparaname(hp,paralocnr),AB_LOCAL,AT_DATA);
+        { byval: a pointer to a type that should actually be passed by
+            value (e.g. a record that should be passed on the stack) }
+        paraloc^.llvmvalueloc:=
+          paramanager.push_addr_param(hp.varspez,hp.vardef,p.proccalloption) or
+          not llvmbyvalparaloc(paraloc);
         paraloc:=paraloc^.next;
         inc(paralocnr);
       until not assigned(paraloc);
     end;
 
 
-  function tllvmparamanager.get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+  procedure tllvmparamanager.add_llvm_callee_paraloc_names(p: tabstractprocdef);
+    var
+      paranr: longint;
+      hp: tparavarsym;
     begin
-      result:=inherited;
-      { TODO: initialise result.llvmloc }
+      for paranr:=0 to p.paras.count-1 do
+        begin
+          hp:=tparavarsym(p.paras[paranr]);
+          set_llvm_paraloc_name(p,hp,hp.paraloc[calleeside]);
+        end;
     end;
 
-    procedure tllvmparamanager.add_llvm_callee_paraloc_names(p: tabstractprocdef);
-      var
-        paranr: longint;
-        para: tcgpara;
-        hp: tparavarsym;
-        first: boolean;
-      begin
-        first:=true;
-        for paranr:=0 to p.paras.count-1 do
-          begin
-            hp:=tparavarsym(p.paras[paranr]);
-            set_llvm_paraloc_name(p,hp,hp.paraloc[calleeside]);
-          end;
-      end;
-
 begin
-  { replace the native code generator. Maybe this has to be moved to a procedure
-    like the creations of the code generators, but possibly not since we still
-    call the original paramanager }
+  { replace the native parameter manager. Maybe this has to be moved to a
+    procedure like the creations of the code generators, but possibly not since
+    we still call the original paramanager }
   paramanager.free;
   paramanager:=tllvmparamanager.create;
 end.

+ 11 - 2
compiler/parabase.pas

@@ -50,8 +50,17 @@ unit parabase;
          { true if the llvmloc symbol is the value itself, rather than a
            pointer to the value (~ named register) }
          llvmvalueloc: boolean;
-         { nil if none corresponding to this particular paraloc }
-         llvmloc: tasmsymbol;
+         llvmloc: record
+           case loc: TCGLoc of
+             { nil if none corresponding to this particular paraloc }
+             LOC_REFERENCE: (sym: tasmsymbol);
+             { if llvmvalueloc=true: the value is stored in the "register"
+                (anonymous temp, can be any register type and can also be e.g.
+                 a struct)
+               if llvmvalueloc=false: must be a tempreg. Means that the value is
+               stored in a temp with this register as base address }
+             LOC_REGISTER:  (reg: tregister);
+         end;
 {$endif llvm}
          case TCGLoc of
            LOC_REFERENCE : (reference : TCGParaReference);