fpPS4/spirv/srReg.pas
2022-11-05 17:48:13 +03:00

924 lines
17 KiB
ObjectPascal

unit srReg;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ginodes,
srNode,
srRefId,
srType,
srConst;
type
ntReg=class(TsrNodeVmt)
class Procedure add_read (node,src:PsrNode); override;
class Procedure rem_read (node,src:PsrNode); override;
class Procedure SetWriter (node,w,line:PsrNode); override;
class Procedure ResetWriter (node,w:PsrNode); override;
class function Down (node:PsrNode):Pointer; override;
class function Next (node:PsrNode):Pointer; override;
class function Prev (node:PsrNode):Pointer; override;
class Procedure PrepType (node:PPrepTypeNode); override;
class function GetPrintName(node:PsrNode):RawByteString; override;
class function GetRef (node:PsrNode):Pointer; override;
end;
ntRegPair=class(TsrNodeVmt)
class function Down (node:PsrNode):Pointer; override;
class Procedure SetWriter (node,w,line:PsrNode); override;
class Procedure ResetWriter(node,w:PsrNode); override;
end;
PPsrRegSlot=^PsrRegSlot;
PsrRegSlot=^TsrRegSlot;
PPsrRegNode=^PsrRegNode;
PsrRegNode=^TsrRegNode;
PRegDNode=^TRegDNode;
TRegDNode=record
pNext:PRegDNode;
pNode:PsrNode;
end;
TRegDNodeList=specialize TNodeStack<PRegDNode>;
TsrRegNode=packed object(TsrNode)
private
pPrev,pNext:PsrRegNode;
//
ID:TsrRefId; //post id
F:bitpacked record
dtype:TsrDataType;
weak:Boolean;
end;
FSlot:PsrRegSlot;
FWriter:PsrNode; //ntReg,ntConst,ntOp,ntVolatile
FDList:TRegDNodeList;
Procedure AddDep(t:PsrNode);
Procedure RemDep(t:PsrNode);
function GetDtype:TsrDataType;
Procedure SetDtype(t:TsrDataType);
function GetWeak:Boolean;
Procedure SetWeak(t:Boolean);
Procedure SetWriter(t:PsrNode);
Function GetWriter:PsrNode;
public
pLine:Pointer; //PspirvOp;
property pSlot :PsrRegSlot read FSlot;
property dtype :TsrDataType read GetDtype write SetDtype;
property Weak :Boolean read GetWeak write SetWeak;
property pWriter:PsrNode read GetWriter write SetWriter;
Procedure Init; inline;
function FirstDep:PRegDNode;
function GetName:RawByteString;
function AsConst:PsrConst;
function AsReg:PsrRegNode;
function is_const:Boolean;
function is_bool:Boolean;
function is_bool_or_const_bool:Boolean;
function is_unknow:Boolean;
function GetPrintName:RawByteString;
end;
PsrRegPair=^TsrRegPair;
TsrRegPair=object(TsrNode)
private
FWriter:PsrNode;
FDst0:PsrNode;
FDst1:PsrNode;
Procedure SetWriter(t:PsrNode);
Procedure SetDst0(r:PsrNode);
Procedure SetDst1(r:PsrNode);
public
property pLine:PsrNode read FWriter;
property pWriter:PsrNode read FWriter write SetWriter;
property pDst0:PsrNode read FDst0 write SetDst0;
property pDst1:PsrNode read FDst1 write SetDst1;
Procedure Init; inline;
end;
TRegStory=specialize TNodeList<PsrRegNode>;
TString5=string[5];
TsrRegSlot=object
private
FEmit:TCustomEmit;
pStory:TRegStory;
Frid:TString5;
public
current:PsrRegNode;
property Emit:TCustomEmit read FEmit;
property rid :TString5 read Frid;
Procedure Init(e:TCustomEmit;const n:TString5);
function first:PsrRegNode;
function last :PsrRegNode;
function isBoolOnly:Boolean;
function New(pLine:Pointer;rtype:TsrDataType):PsrRegNode;
function NewAfter(rtype:TsrDataType;r:PsrRegNode):PsrRegNode;
function NewBefore(rtype:TsrDataType;r:PsrRegNode):PsrRegNode;
procedure Insert(r:PsrRegNode);
procedure Remove(r:PsrRegNode);
end;
PsrRegsSnapshot=^TsrRegsSnapshot;
TsrRegsSnapshot=object
SGRP:array[0..103] of PsrRegNode;
VCC:array[0..1] of PsrRegNode;
M0:PsrRegNode;
EXEC:array[0..1] of PsrRegNode;
SCC:PsrRegNode;
VGRP:array[0..255] of PsrRegNode;
end;
TForEachSlot=procedure(pSlot:PsrRegSlot) of object;
TForEachSnap=procedure(pSlot:PsrRegSlot;var old:PsrRegNode) of object;
PsrRegsStory=^TsrRegsStory;
TsrRegsStory=object
SGRP:array[0..103] of TsrRegSlot;
VCC:array[0..1] of TsrRegSlot;
M0:TsrRegSlot;
EXEC:array[0..1] of TsrRegSlot;
SCC:TsrRegSlot;
VGRP:array[0..255] of TsrRegSlot;
FUnattach:TsrRegSlot;
//
FDList:TRegDNodeList;
//
Procedure Init(Emit:TCustomEmit);
//
Function AllocDep:PRegDNode;
Procedure FreeDep(node:PRegDNode);
//
function get_sdst7(SDST:Byte):PsrRegSlot;
function get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
function get_ssrc8(SSRC:Byte):PsrRegSlot;
function get_ssrc9(SSRC:Word):PsrRegSlot;
function get_ssrc9_pair(SSRC:Word;src:PPsrRegSlot):Boolean;
function get_vsrc8(VSRC:Byte):PsrRegSlot;
function get_vdst8(VDST:Byte):PsrRegSlot;
function get_sbase(SBASE,count:Byte;src:PPsrRegSlot):Boolean;
function get_srsrc(SRSRC,count:Byte;src:PPsrRegSlot):Boolean;
//
function get_snapshot:TsrRegsSnapshot;
procedure ForEachSlot(cb:TForEachSlot);
procedure ForEachSnap(cb:TForEachSnap;old:PsrRegsSnapshot);
end;
function RegDown(node:PsrRegNode):PsrRegNode;
function RegDownSlot(node:PsrRegNode):PsrRegNode;
function CompareReg(r1,r2:PsrRegNode):Boolean;
implementation
//
class Procedure ntReg.add_read(node,src:PsrNode);
begin
inherited;
PsrRegNode(node)^.AddDep(src);
end;
class Procedure ntReg.rem_read(node,src:PsrNode);
begin
inherited;
PsrRegNode(node)^.RemDep(src);
end;
class Procedure ntReg.SetWriter(node,w,line:PsrNode);
begin
With PsrRegNode(node)^ do
begin
SetWriter(w);
pLine:=line;
end;
end;
class Procedure ntReg.ResetWriter(node,w:PsrNode);
begin
With PsrRegNode(node)^ do
if (FWriter=w) then
begin
SetWriter(nil);
pLine:=nil;
end;
end;
class function ntReg.Down(node:PsrNode):Pointer;
begin
Result:=PsrRegNode(node)^.FWriter;
end;
class function ntReg.Next(node:PsrNode):Pointer;
begin
Result:=PsrRegNode(node)^.pNext;
end;
class function ntReg.Prev(node:PsrNode):Pointer;
begin
Result:=PsrRegNode(node)^.pPrev;
end;
class Procedure ntReg.PrepType(node:PPrepTypeNode);
var
new:TsrDataType;
pConstList:PsrConstList;
begin
With PsrRegNode(node^.dnode)^ do
begin
new:=TsrDataType(node^.rtype);
if (new=dtUnknow) then
begin
node^.dnode:=nil;
Exit;
end;
if FSlot^.isBoolOnly then
begin
//next
node^.rtype:=ord(dtBool);
node^.dnode:=pWriter;
Exit;
end else
if is_unprep_type(dtype,new,Weak) then
begin
dtype:=new;
Weak:=True;
if is_const then
begin
pConstList:=FSlot^.FEmit.GetConstList;
pWriter:=pConstList^.Bitcast(new,pWriter^.AsType(ntConst));
end else
begin
//next
node^.dnode:=pWriter;
Exit;
end;
end;
end;
node^.dnode:=nil;
end;
class function ntReg.GetPrintName(node:PsrNode):RawByteString;
begin
Result:=PsrRegNode(node)^.GetPrintName;
end;
class function ntReg.GetRef(node:PsrNode):Pointer;
begin
With PsrRegNode(node)^ do
begin
if is_const then
begin
Result:=AsConst^.GetRef;
end else
begin
Result:=@ID;
end;
end;
end;
//
class function ntRegPair.Down(node:PsrNode):Pointer;
begin
Result:=PsrRegPair(node)^.FWriter;
end;
class Procedure ntRegPair.SetWriter(node,w,line:PsrNode);
begin
With PsrRegPair(node)^ do
begin
SetWriter(w);
end;
end;
class Procedure ntRegPair.ResetWriter(node,w:PsrNode);
begin
With PsrRegPair(node)^ do
if (FWriter=w) then
begin
SetWriter(nil);
end;
end;
//
Procedure TsrRegsStory.Init(Emit:TCustomEmit);
var
i:Word;
n:TString5;
begin
FillChar(Self,SizeOf(TsrRegsStory),0);
For i:=0 to 103 do
begin
Str(i,n);
SGRP[i].Init(Emit,'S'+n);
end;
VCC[0].Init(Emit,'VCCL');
VCC[1].Init(Emit,'VCCH');
M0.Init(Emit,'M0');
EXEC[0].Init(Emit,'EXECL');
EXEC[1].Init(Emit,'EXECH');
SCC.Init(Emit,'SCC');
For i:=0 to 255 do
begin
Str(i,n);
VGRP[i].Init(Emit,'V'+n);
end;
FUnattach.Init(Emit,'UNATT');
end;
Function TsrRegsStory.AllocDep:PRegDNode;
begin
Result:=FDList.Pop_head;
if (Result=nil) then
begin
Result:=FUnattach.FEmit.Alloc(SizeOf(TRegDNode));
end;
end;
Procedure TsrRegsStory.FreeDep(node:PRegDNode);
begin
if (node=nil) then Exit;
node^:=Default(TRegDNode);
FDList.Push_head(node);
end;
function TsrRegsStory.get_sdst7(SDST:Byte):PsrRegSlot;
begin
Case SDST of
0..103:Result:=@SGRP[SDST];
106:Result:=@VCC[0];
107:Result:=@VCC[1];
124:Result:=@M0;
126:Result:=@EXEC[0];
127:Result:=@EXEC[1];
else
Result:=nil;
end;
end;
function TsrRegsStory.get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
begin
Result:=True;
if (dst=nil) then Exit(false);
Case SDST of
0..102:
begin
dst[0]:=@SGRP[SDST];
dst[1]:=@SGRP[SDST+1];
end;
106:
begin
dst[0]:=@VCC[0];
dst[1]:=@VCC[1];
end;
126:
begin
dst[0]:=@EXEC[0];
dst[1]:=@EXEC[1];
end;
else
Result:=False;
end;
end;
function TsrRegsStory.get_ssrc8(SSRC:Byte):PsrRegSlot;
begin
Case SSRC of
0..103:Result:=@SGRP[SSRC];
106:Result:=@VCC[0];
107:Result:=@VCC[1];
124:Result:=@M0;
126:Result:=@EXEC[0];
127:Result:=@EXEC[1];
//251:Result:=@VCC[0]; //VCCZ
//252:Result:=@EXEC[0]; //EXECZ
253:Result:=@SCC;
//254:Write('LDS_DIRECT');
else
Result:=nil;
end;
end;
function TsrRegsStory.get_ssrc9(SSRC:Word):PsrRegSlot;
begin
Case SSRC of
0..103:Result:=@SGRP[SSRC];
106:Result:=@VCC[0];
107:Result:=@VCC[1];
124:Result:=@M0;
126:Result:=@EXEC[0];
127:Result:=@EXEC[1];
//251:Result:=@VCC[0]; //VCCZ
//252:Result:=@EXEC[0]; //EXECZ
253:Result:=@SCC;
//254:Write('LDS_DIRECT');
256..511:Result:=@VGRP[SSRC-256];
else
Result:=nil;
end;
end;
function TsrRegsStory.get_ssrc9_pair(SSRC:Word;src:PPsrRegSlot):Boolean;
begin
Result:=True;
if (src=nil) then Exit(False);
Case SSRC of
0..102:
begin
src[0]:=@SGRP[SSRC];
src[1]:=@SGRP[SSRC+1];
end;
106:
begin
src[0]:=@VCC[0];
src[1]:=@VCC[1];
end;
126:
begin
src[0]:=@EXEC[0];
src[1]:=@EXEC[1];
end;
256..510:
begin
src[0]:=@VGRP[SSRC-256];
src[1]:=@VGRP[SSRC-255];
end;
else
Result:=False;
end;
end;
function TsrRegsStory.get_vsrc8(VSRC:Byte):PsrRegSlot;
begin
Result:=@VGRP[VSRC];
end;
function TsrRegsStory.get_vdst8(VDST:Byte):PsrRegSlot;
begin
Result:=@VGRP[VDST];
end;
//SBASE 0..63
//SGRP:array[0..103] of TpsslRegSlot;
function TsrRegsStory.get_sbase(SBASE,count:Byte;src:PPsrRegSlot):Boolean;
var
i,p:Byte;
begin
Result:=True;
if (SBASE>63) or (count=0) or (src=nil) then Exit(False);
p:=SBASE*2;
if ((p+count)>104) then Exit(False);
For i:=0 to count-1 do
begin
src[i]:=@SGRP[p+i];
end;
end;
//SRSRC 0..31
function TsrRegsStory.get_srsrc(SRSRC,count:Byte;src:PPsrRegSlot):Boolean;
var
i,p:Byte;
begin
Result:=True;
if (SRSRC>31) or (count=0) or (src=nil) then Exit(False);
p:=SRSRC*4;
if ((p+count)>104) then Exit(False);
For i:=0 to count-1 do
begin
src[i]:=@SGRP[p+i];
end;
end;
//
function TsrRegsStory.get_snapshot:TsrRegsSnapshot;
var
i:Word;
begin
Result:=Default(TsrRegsSnapshot);
For i:=0 to 103 do
begin
Result.SGRP[i]:=SGRP[i].current;
end;
For i:=0 to 1 do
begin
Result.VCC[i] :=VCC[i].current;
end;
Result.M0 :=M0.current;
For i:=0 to 1 do
begin
Result.EXEC[i]:=EXEC[i].current;
end;
Result.SCC :=SCC.current;
For i:=0 to 255 do
begin
Result.VGRP[i]:=VGRP[i].current;
end;
end;
procedure TsrRegsStory.ForEachSlot(cb:TForEachSlot);
var
i:Word;
begin
if (cb=nil) then Exit;
For i:=0 to 103 do
begin
cb(@SGRP[i]);
end;
For i:=0 to 1 do
begin
cb(@VCC[i]);
end;
cb(@M0);
For i:=0 to 1 do
begin
cb(@EXEC[i]);
end;
cb(@SCC);
For i:=0 to 255 do
begin
cb(@VGRP[i]);
end;
end;
procedure TsrRegsStory.ForEachSnap(cb:TForEachSnap;old:PsrRegsSnapshot);
var
i:Word;
begin
if (cb=nil) or (old=nil) then Exit;
For i:=0 to 103 do
begin
cb(@SGRP[i],Old^.SGRP[i]);
end;
For i:=0 to 1 do
begin
cb(@VCC[i],Old^.VCC[i]);
end;
cb(@M0,Old^.M0);
For i:=0 to 1 do
begin
cb(@EXEC[i],Old^.EXEC[i]);
end;
cb(@SCC,Old^.SCC);
For i:=0 to 255 do
begin
cb(@VGRP[i],Old^.VGRP[i]);
end;
end;
//--
Procedure TsrRegNode.Init; inline;
begin
fntype:=ntReg;
end;
function TsrRegNode.GetName:RawByteString;
begin
Result:='';
if (FSlot<>nil) then Result:=FSlot^.rid;
end;
Procedure TsrRegNode.AddDep(t:PsrNode);
var
pRegsStory:PsrRegsStory;
node:PRegDNode;
begin
if (t=nil) or (@Self=nil) then Exit;
pRegsStory:=FSlot^.FEmit.GetRegsStory;
node:=pRegsStory^.AllocDep;
node^.pNode:=t;
FDList.Push_head(node);
end;
Procedure TsrRegNode.RemDep(t:PsrNode);
var
pRegsStory:PsrRegsStory;
node,_prev:PRegDNode;
begin
if (t=nil) or (@Self=nil) then Exit;
node:=FDList.pHead;
_prev:=nil;
While (node<>nil) do
begin
if (node^.pNode=t) then
begin
if (_prev=nil) then
begin
FDList.pHead:=node^.pNext;
end else
begin
_prev^.pNext:=node^.pNext;
end;
pRegsStory:=FSlot^.FEmit.GetRegsStory;
pRegsStory^.FreeDep(node);
Exit;
end;
_prev:=node;
node:=node^.pNext;
end;
Assert(false,'not found!');
end;
function TsrRegNode.FirstDep:PRegDNode;
begin
Result:=nil;
if (@Self=nil) then Exit;
Result:=FDList.pHead;
end;
function TsrRegNode.GetDtype:TsrDataType;
begin
Result:=F.dtype;
end;
Procedure TsrRegNode.SetDtype(t:TsrDataType);
begin
F.dtype:=t;
end;
function TsrRegNode.GetWeak:Boolean;
begin
Result:=F.weak;
end;
Procedure TsrRegNode.SetWeak(t:Boolean);
begin
F.weak:=t;
end;
Procedure TsrRegNode.SetWriter(t:PsrNode);
begin
if (@Self=nil) then Exit;
if (FWriter=t) then Exit;
Assert(RegDown(t^.AsType(ntReg))<>@Self,'Circular reference');
if isUsed then
begin
t^.mark_read (@Self);
FWriter^.mark_unread(@Self);
end;
FWriter:=t;
end;
Function TsrRegNode.GetWriter:PsrNode;
begin
Result:=nil;
if (@Self=nil) then Exit;
Result:=FWriter;
end;
function TsrRegNode.AsConst:PsrConst;
begin
if (@Self=nil) then Exit(nil);
Result:=PsrConst(FWriter^.AsType(ntConst));
end;
function TsrRegNode.AsReg:PsrRegNode;
begin
if (@Self=nil) then Exit(nil);
Result:=PsrRegNode(FWriter^.AsType(ntReg));
end;
function TsrRegNode.is_const:Boolean;
begin
if (@Self=nil) then Exit(False);
Result:=FWriter^.IsType(ntConst);
end;
function TsrRegNode.is_bool:Boolean;
begin
if (@Self=nil) then Exit(False);
Result:=(dtype=dtBool);
end;
function TsrRegNode.is_bool_or_const_bool:Boolean;
begin
if (@Self=nil) then Exit(False);
Result:=is_bool or
(is_const and AsConst^.isBoolVal);
end;
function TsrRegNode.is_unknow:Boolean;
begin
if (@Self=nil) then Exit(True);
Result:=(dtype=dtUnknow);
end;
function TsrRegNode.GetPrintName:RawByteString;
begin
if is_const then
begin
Result:=AsConst^.GetPrintName;
end else
begin
Assert(ID.Alloc);
Result:='r'+IntToStr(ID.ID);
end;
end;
//
Procedure TsrRegPair.SetWriter(t:PsrNode);
begin
if (FWriter=t) then Exit;
if isUsed then
begin
t^.mark_read (@Self);
FWriter^.mark_unread(@Self);
end;
FWriter:=t;
end;
Procedure TsrRegPair.SetDst0(r:PsrNode);
begin
if (FDst0=r) then Exit;
FDst0^.ResetWriter(@Self);
FDst0:=r;
FDst0^.SetWriter(@Self,pLine);
end;
Procedure TsrRegPair.SetDst1(r:PsrNode);
begin
if (FDst1=r) then Exit;
FDst1^.ResetWriter(@Self);
FDst1:=r;
FDst1^.SetWriter(@Self,pLine);
end;
Procedure TsrRegPair.Init; inline;
begin
fntype:=ntRegPair;
end;
//--
Procedure TsrRegSlot.Init(e:TCustomEmit;const n:TString5);
begin
FEmit:=e;
Frid :=n;
end;
function TsrRegSlot.first:PsrRegNode;
begin
Result:=pStory.pHead;
end;
function TsrRegSlot.last:PsrRegNode;
begin
Result:=pStory.pTail;
end;
function TsrRegSlot.isBoolOnly:Boolean;
begin
Result:=(rid='SCC');
end;
function TsrRegSlot.New(pLine:Pointer;rtype:TsrDataType):PsrRegNode;
var
node:PsrRegNode;
begin
if isBoolOnly then
begin
rtype:=dtBool;
end;
node:=FEmit.Alloc(SizeOf(TsrRegNode));
node^.Init;
node^.FSlot:=@Self;
node^.dtype:=rtype;
node^.pLine:=pLine;
pStory.Push_tail(node);
Result:=node;
//update
current:=pStory.pTail;
end;
function TsrRegSlot.NewAfter(rtype:TsrDataType;r:PsrRegNode):PsrRegNode;
var
node:PsrRegNode;
begin
if isBoolOnly then
begin
rtype:=dtBool;
end;
node:=FEmit.Alloc(SizeOf(TsrRegNode));
node^.Init;
node^.FSlot:=@Self;
node^.dtype:=rtype;
node^.pLine:=r^.pLine;
pStory.InsertAfter(r,node);
Result:=node;
//update
if (r=pStory.pTail) then
begin
current:=pStory.pTail;
end;
end;
function TsrRegSlot.NewBefore(rtype:TsrDataType;r:PsrRegNode):PsrRegNode;
var
node:PsrRegNode;
begin
if isBoolOnly then
begin
rtype:=dtBool;
end;
node:=FEmit.Alloc(SizeOf(TsrRegNode));
node^.Init;
node^.FSlot:=@Self;
node^.dtype:=rtype;
node^.pLine:=r^.pLine;
pStory.InsertBefore(r,node);
Result:=node;
//update
if (r=pStory.pTail) then
begin
current:=pStory.pTail;
end;
end;
procedure TsrRegSlot.Insert(r:PsrRegNode);
begin
if (r=nil) then Exit;
pStory.Push_tail(r);
//update
current:=pStory.pTail;
end;
procedure TsrRegSlot.Remove(r:PsrRegNode);
begin
if (r=nil) then Exit;
pStory.Remove(r);
//update
if (r=current) then
begin
current:=pStory.pTail;
end;
end;
//
function RegDown(node:PsrRegNode):PsrRegNode;
var
tmp:PsrRegNode;
begin
//backtrace
Result:=node;
While (Result<>nil) do
begin
tmp:=Result^.AsReg; //next
if (tmp=nil) then Break;
Assert(tmp<>Result);
Result:=tmp;
end;
end;
function RegDownSlot(node:PsrRegNode):PsrRegNode;
var
tmp:PsrRegNode;
begin
//backtrace
Result:=node;
While (Result<>nil) do
begin
tmp:=Result^.AsReg; //next
if (tmp=nil) then Break;
Assert(tmp<>Result);
if (tmp^.pSlot<>Result^.pSlot) then Break;
Result:=tmp;
end;
end;
function CompareReg(r1,r2:PsrRegNode):Boolean;
begin
r1:=RegDownSlot(r1);
r2:=RegDownSlot(r2);
Result:=(r1=r2);
if not Result then
begin
Result:=CompareConst(r1^.AsConst,r2^.AsConst);
end;
end;
end.