From 1df3039424fe92cbde30f967bd495ea52e501a95 Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Mon, 11 Nov 2013 11:14:59 +0000 Subject: [PATCH] + 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 - --- .gitattributes | 1 + compiler/cgbase.pas | 4 +- compiler/cgobj.pas | 7 ++ compiler/hlcgobj.pas | 8 ++ compiler/llvm/tgllvm.pas | 163 +++++++++++++++++++++++++++++++++++++++ compiler/tgobj.pas | 2 +- compiler/x86/aasmcpu.pas | 4 +- 7 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 compiler/llvm/tgllvm.pas diff --git a/.gitattributes b/.gitattributes index a9ad8a2197..0e7da68fe2 100644 --- a/.gitattributes +++ b/.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 diff --git a/compiler/cgbase.pas b/compiler/cgbase.pas index 579853635f..5095d631d1 100644 --- a/compiler/cgbase.pas +++ b/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 } diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas index bda0b02b04..8b32922728 100644 --- a/compiler/cgobj.pas +++ b/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; diff --git a/compiler/hlcgobj.pas b/compiler/hlcgobj.pas index 535b3e6867..f8ebd71015 100644 --- a/compiler/hlcgobj.pas +++ b/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 diff --git a/compiler/llvm/tgllvm.pas b/compiler/llvm/tgllvm.pas new file mode 100644 index 0000000000..1273a34a72 --- /dev/null +++ b/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. diff --git a/compiler/tgobj.pas b/compiler/tgobj.pas index 30bcb55470..8e5e25a9df 100644 --- a/compiler/tgobj.pas +++ b/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); diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index 634ee52394..e6fc95355d 100644 --- a/compiler/x86/aasmcpu.pas +++ b/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;