浏览代码

+ 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 11 年之前
父节点
当前提交
1df3039424
共有 7 个文件被更改,包括 185 次插入4 次删除
  1. 1 0
      .gitattributes
  2. 3 1
      compiler/cgbase.pas
  3. 7 0
      compiler/cgobj.pas
  4. 8 0
      compiler/hlcgobj.pas
  5. 163 0
      compiler/llvm/tgllvm.pas
  6. 1 1
      compiler/tgobj.pas
  7. 2 2
      compiler/x86/aasmcpu.pas

+ 1 - 0
.gitattributes

@@ -314,6 +314,7 @@ compiler/jvm/rjvmsup.inc svneol=native#text/plain
 compiler/jvm/tgcpu.pas svneol=native#text/plain
 compiler/jvm/tgcpu.pas svneol=native#text/plain
 compiler/ldscript.pas svneol=native#text/plain
 compiler/ldscript.pas svneol=native#text/plain
 compiler/link.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/aasmcpu.pas svneol=native#text/plain
 compiler/m68k/ag68kgas.pas svneol=native#text/plain
 compiler/m68k/ag68kgas.pas svneol=native#text/plain
 compiler/m68k/aoptcpu.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_MMXREGISTER,     { = 3 }
         R_MMREGISTER,      { = 4 }
         R_MMREGISTER,      { = 4 }
         R_SPECIALREGISTER, { = 5 }
         R_SPECIALREGISTER, { = 5 }
-        R_ADDRESSREGISTER  { = 6 }
+        R_ADDRESSREGISTER, { = 6 }
+        { used on llvm, every temp gets its own "base register" }
+        R_TEMPREGISTER     { = 7 }
       );
       );
 
 
       { Sub registers }
       { Sub registers }

+ 7 - 0
compiler/cgobj.pas

@@ -85,6 +85,7 @@ unit cgobj;
           function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
           function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
           function getmmregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
           function getmmregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
           function getflagregister(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
           {Does the generic cg need SIMD registers, like getmmxregister? Or should
            the cpu specific child cg object have such a method?}
            the cpu specific child cg object have such a method?}
 
 
@@ -661,6 +662,12 @@ implementation
       end;
       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;
     function Tcg.makeregsize(list:TAsmList;reg:Tregister;size:Tcgsize):Tregister;
       var
       var
         subreg:Tsubregister;
         subreg:Tsubregister;

+ 8 - 0
compiler/hlcgobj.pas

@@ -72,6 +72,7 @@ unit hlcgobj;
           { warning: only works correctly for fpu types currently }
           { warning: only works correctly for fpu types currently }
           function getmmregister(list:TAsmList;size:tdef):Tregister;virtual;
           function getmmregister(list:TAsmList;size:tdef):Tregister;virtual;
           function getflagregister(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;
           function getregisterfordef(list: TAsmList;size:tdef):Tregister;virtual;
           {Does the generic cg need SIMD registers, like getmmxregister? Or should
           {Does the generic cg need SIMD registers, like getmmxregister? Or should
            the cpu specific child cg object have such a method?}
            the cpu specific child cg object have such a method?}
@@ -615,6 +616,13 @@ implementation
       result:=cg.getflagregister(list,def_cgsize(size));
       result:=cg.getflagregister(list,def_cgsize(size));
     end;
     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;
     function thlcgobj.getregisterfordef(list: TAsmList; size: tdef): Tregister;
       begin
       begin
         case def2regtyp(size) of
         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
              The freed space can later be reallocated and reused. If this reference
              is not in the temporary memory, it is simply not freed.
              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 }
           { Allocate space for a local }
           procedure getlocal(list: TAsmList; size : longint;def:tdef;var ref : treference);
           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);
           (0, 1, 2, 3, 6, 7, 5, 4);
         maxsupreg: array[tregistertype] of tsuperregister=
         maxsupreg: array[tregistertype] of tsuperregister=
 {$ifdef x86_64}
 {$ifdef x86_64}
-          (0, 16, 9, 8, 16, 32, 0);
+          (0, 16, 9, 8, 16, 32, 0, 0);
 {$else x86_64}
 {$else x86_64}
-          (0,  8, 9, 8,  8, 32, 0);
+          (0,  8, 9, 8,  8, 32, 0, 0);
 {$endif x86_64}
 {$endif x86_64}
       var
       var
         rs: tsuperregister;
         rs: tsuperregister;