mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-17 23:19:29 +02:00
+ 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:
parent
9573160c1a
commit
1df3039424
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
|
||||
|
@ -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 }
|
||||
|
@ -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;
|
||||
|
@ -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
163
compiler/llvm/tgllvm.pas
Normal 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.
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user