Ver Fonte

+ LLVM temp allocator based on new R_TEMPREGISTER register class. For every
temp we allocate, we set the base register to a newly allocated
R_TEMPREGISTER. This allows for uniquely identifying a temp even if its
offset is modified.

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

Jonas Maebe há 11 anos atrás
pai
commit
1df3039424

+ 1 - 0
.gitattributes

@@ -314,6 +314,7 @@ compiler/jvm/rjvmsup.inc svneol=native#text/plain
 compiler/jvm/tgcpu.pas svneol=native#text/plain
 compiler/ldscript.pas svneol=native#text/plain
 compiler/link.pas svneol=native#text/plain
+compiler/llvm/tgllvm.pas svneol=native#text/plain
 compiler/m68k/aasmcpu.pas svneol=native#text/plain
 compiler/m68k/ag68kgas.pas svneol=native#text/plain
 compiler/m68k/aoptcpu.pas svneol=native#text/plain

+ 3 - 1
compiler/cgbase.pas

@@ -171,7 +171,9 @@ interface
         R_MMXREGISTER,     { = 3 }
         R_MMREGISTER,      { = 4 }
         R_SPECIALREGISTER, { = 5 }
-        R_ADDRESSREGISTER  { = 6 }
+        R_ADDRESSREGISTER, { = 6 }
+        { used on llvm, every temp gets its own "base register" }
+        R_TEMPREGISTER     { = 7 }
       );
 
       { Sub registers }

+ 7 - 0
compiler/cgobj.pas

@@ -85,6 +85,7 @@ unit cgobj;
           function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
           function getmmregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
           function getflagregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
+          function gettempregister(list:TAsmList):Tregister;virtual;
           {Does the generic cg need SIMD registers, like getmmxregister? Or should
            the cpu specific child cg object have such a method?}
 
@@ -661,6 +662,12 @@ implementation
       end;
 
 
+    function tcg.gettempregister(list: TAsmList): Tregister;
+      begin
+        result:=rg[R_TEMPREGISTER].getregister(list,R_SUBWHOLE);
+      end;
+
+
     function Tcg.makeregsize(list:TAsmList;reg:Tregister;size:Tcgsize):Tregister;
       var
         subreg:Tsubregister;

+ 8 - 0
compiler/hlcgobj.pas

@@ -72,6 +72,7 @@ unit hlcgobj;
           { warning: only works correctly for fpu types currently }
           function getmmregister(list:TAsmList;size:tdef):Tregister;virtual;
           function getflagregister(list:TAsmList;size:tdef):Tregister;virtual;
+          function gettempregister(list:TAsmList;size:tdef):Tregister;virtual;
           function getregisterfordef(list: TAsmList;size:tdef):Tregister;virtual;
           {Does the generic cg need SIMD registers, like getmmxregister? Or should
            the cpu specific child cg object have such a method?}
@@ -615,6 +616,13 @@ implementation
       result:=cg.getflagregister(list,def_cgsize(size));
     end;
 
+  function thlcgobj.gettempregister(list: TAsmList; size: tdef): Tregister;
+    begin
+      { doesn't make sense to try to translate this size to tcgsize, temps
+        can have any size }
+      result:=cg.gettempregister(list);
+    end;
+
     function thlcgobj.getregisterfordef(list: TAsmList; size: tdef): Tregister;
       begin
         case def2regtyp(size) of

+ 163 - 0
compiler/llvm/tgllvm.pas

@@ -0,0 +1,163 @@
+{
+    Copyright (c) 1998-2002,2012 by Florian Klaempfl, Jonas Maebe
+
+    This unit implements the LLVM-specific temp. generator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit tgllvm;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      cclasses,
+      globals,globtype,
+      symtype,
+      cpubase,cpuinfo,cgbase,cgutils,
+      aasmbase,aasmtai,aasmdata,
+      tgobj;
+
+    type
+
+      { LLVM temp manager: in LLVM, you allocate every temp separately using
+        the "alloca" instrinsic. Every such temp is a separate stack slot, but
+        can be turned into a regvar (or be decomposed) by LLVM. To avoid
+        problems with turning stack slots into regvars, we don't allocate one
+        big blob of memory that we manage ourselves using the regular temp
+        manager. Instead, we just allocate a new "stack pointer register"
+        (R_TEMPREGISTER) every time we need a new temp. This allows for having
+        the generic code generator modify the offset without interfering with
+        our ability to determine which temp the reference points to.
+
+        Temps are currently not reused, but that should probably be added in
+        the future (except if adding liveness information for the temps enables
+        llvm to do so by itself and we don't run out of temp registers).
+      }
+
+      { ttgllvm }
+
+      ttgllvm = class(ttgobj)
+       protected
+        procedure alloctemp(list: TAsmList; size,alignment : longint; temptype : ttemptype; def:tdef; out ref: treference); override;
+       public
+        alloclist: tasmlist;
+
+        constructor create; override;
+        destructor destroy; override;
+        procedure setfirsttemp(l : longint); override;
+        function istemp(const ref: treference): boolean; override;
+        procedure getlocal(list: TAsmList; size: longint; alignment: shortint; def: tdef; var ref: treference); override;
+        procedure gethltemp(list: TAsmList; def: tdef; forcesize: aint; temptype: ttemptype; out ref: treference); override;
+        procedure gethltemptyped(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference); override;
+        procedure ungetiftemp(list: TAsmList; const ref: treference); override;
+      end;
+
+implementation
+
+    uses
+       cutils,
+       systems,verbose,
+       procinfo,
+       llvmbase,aasmllvm,
+       symconst,
+       cgobj
+       ;
+
+
+    { ttgllvm }
+
+    procedure ttgllvm.alloctemp(list: TAsmList; size, alignment: longint; temptype: ttemptype; def: tdef; out ref: treference);
+      var
+        tl: ptemprecord;
+      begin
+        reference_reset_base(ref,cg.gettempregister(list),0,alignment);
+        new(tl);
+
+        tl^.temptype:=temptype;
+        tl^.def:=def;
+        tl^.pos:=getsupreg(ref.base);
+        tl^.size:=size;
+        tl^.next:=templist;
+        tl^.nextfree:=nil;
+        templist:=tl;
+        list.concat(tai_tempalloc.alloc(tl^.pos,tl^.size));
+        { TODO: add llvm.lifetime.start() for this allocation and afterwards
+            llvm.lifetime.end() for freetemp (if the llvm version supports it) }
+        inc(lasttemp);
+        { allocation for the temp }
+        alloclist.concat(taillvm.op_ref_size(la_alloca,ref,def));
+      end;
+
+
+    function ttgllvm.istemp(const ref: treference): boolean;
+      begin
+        result:=getregtype(ref.base)=R_TEMPREGISTER;
+      end;
+
+
+    constructor ttgllvm.create;
+      begin
+        inherited create;
+        direction:=1;
+        alloclist:=TAsmList.create;
+      end;
+
+
+    destructor ttgllvm.destroy;
+      begin
+        alloclist.free;
+        inherited destroy;
+      end;
+
+
+    procedure ttgllvm.setfirsttemp(l: longint);
+      begin
+        firsttemp:=l;
+        lasttemp:=l;
+      end;
+
+
+    procedure ttgllvm.getlocal(list: TAsmList; size: longint; alignment: shortint; def: tdef; var ref: treference);
+      begin
+        gethltemp(list,def,size,tt_persistent,ref);
+      end;
+
+
+    procedure ttgllvm.gethltemp(list: TAsmList; def: tdef; forcesize: aint; temptype: ttemptype; out ref: treference);
+      begin
+        alloctemp(list,def.size,def.alignment,temptype,def,ref);
+      end;
+
+
+    procedure ttgllvm.gethltemptyped(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
+      begin
+        inherited gethltemptyped(list, def, temptype, ref);
+      end;
+
+
+    procedure ttgllvm.ungetiftemp(list: TAsmList; const ref: treference);
+      begin
+        if istemp(ref) then
+          FreeTemp(list,getsupreg(ref.base),[tt_normal]);
+      end;
+
+begin
+  tgobjclass:=ttgllvm;
+end.

+ 1 - 1
compiler/tgobj.pas

@@ -112,7 +112,7 @@ unit tgobj;
              The freed space can later be reallocated and reused. If this reference
              is not in the temporary memory, it is simply not freed.
           }
-          procedure ungetiftemp(list: TAsmList; const ref : treference);
+          procedure ungetiftemp(list: TAsmList; const ref : treference); virtual;
 
           { Allocate space for a local }
           procedure getlocal(list: TAsmList; size : longint;def:tdef;var ref : treference);

+ 2 - 2
compiler/x86/aasmcpu.pas

@@ -1568,9 +1568,9 @@ implementation
           (0, 1, 2, 3, 6, 7, 5, 4);
         maxsupreg: array[tregistertype] of tsuperregister=
 {$ifdef x86_64}
-          (0, 16, 9, 8, 16, 32, 0);
+          (0, 16, 9, 8, 16, 32, 0, 0);
 {$else x86_64}
-          (0,  8, 9, 8,  8, 32, 0);
+          (0,  8, 9, 8,  8, 32, 0, 0);
 {$endif x86_64}
       var
         rs: tsuperregister;