+ 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 -
This commit is contained in:
Jonas Maebe 2013-11-11 11:14:59 +00:00
parent 9573160c1a
commit 1df3039424
7 changed files with 185 additions and 4 deletions

1
.gitattributes vendored
View File

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

View File

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

View File

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

View File

@ -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
compiler/llvm/tgllvm.pas Normal file
View File

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

View File

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

View File

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