mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-30 10:01:14 +00:00
964 lines
20 KiB
ObjectPascal
964 lines
20 KiB
ObjectPascal
unit srLayout;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
ps4_shader,
|
|
spirv,
|
|
ginodes,
|
|
srNode,
|
|
srCFGParser,
|
|
srCFGCursor,
|
|
srType,
|
|
srTypes,
|
|
srReg,
|
|
srOp,
|
|
srVariable,
|
|
srBitcast,
|
|
srRefId,
|
|
srDecorate;
|
|
|
|
type
|
|
TsrResourceType=(
|
|
rtRoot,
|
|
rtBufPtr2,
|
|
rtFunPtr2,
|
|
rtVSharp4,
|
|
rtSSharp4,
|
|
rtTSharp4,
|
|
rtTSharp8
|
|
);
|
|
|
|
type
|
|
ntChain=class(TsrNodeVmt)
|
|
class Procedure zero_read (node:PsrNode); override;
|
|
class Procedure zero_unread (node:PsrNode); override;
|
|
class Function pwrite_count(node:PsrNode):PDWORD; 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 function Parent (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;
|
|
|
|
PsrDataLayout=^TsrDataLayout;
|
|
|
|
PsrChainLvl_1=^TsrChainLvl_1;
|
|
TsrChainLvl_1=object
|
|
pIndex:PsrRegNode;
|
|
stride:PtrUint;
|
|
function c(n1,n2:PsrChainLvl_1):Integer; static;
|
|
end;
|
|
|
|
PsrChainLvl_0=^TsrChainLvl_0;
|
|
TsrChainLvl_0=object
|
|
size :PtrUint;
|
|
offset:PtrUint;
|
|
function c(n1,n2:PsrChainLvl_0):Integer; static;
|
|
end;
|
|
|
|
PsrChain=^TsrChain;
|
|
TsrChain=object(TsrNode)
|
|
type
|
|
PVNode=^TVNode;
|
|
TVNode=record
|
|
pPrev,pNext:PVNode;
|
|
pLine:PspirvOp;
|
|
end;
|
|
TNodeList=specialize TNodeList<PVNode>;
|
|
private
|
|
pLeft,pRight:PsrChain;
|
|
//--
|
|
fwrite_count:DWORD;
|
|
//--
|
|
ID:TsrRefId; //post id
|
|
FParent:PsrDataLayout;
|
|
key:packed record
|
|
lvl_1:TsrChainLvl_1;
|
|
lvl_0:TsrChainLvl_0;
|
|
end;
|
|
FBuffer:PsrNode;
|
|
FWriter:PsrNode;
|
|
Fdtype:TsrDataType;
|
|
FList:TNodeList;
|
|
function c(n1,n2:PsrChain):Integer; static;
|
|
Procedure SetWriter(t:PsrNode);
|
|
Function GetWriter:PsrNode;
|
|
Procedure SetBuffer(t:PsrNode);
|
|
Function GetBuffer:PsrNode;
|
|
Procedure SetRegType(rtype:TsrDataType);
|
|
public
|
|
pField:Pointer;
|
|
property Parent:PsrDataLayout read FParent;
|
|
property pIndex:PsrRegNode read key.lvl_1.pIndex;
|
|
property stride:PtrUint read key.lvl_1.stride;
|
|
property size :PtrUint read key.lvl_0.size;
|
|
property offset:PtrUint read key.lvl_0.offset;
|
|
property dtype:TsrDataType read Fdtype write SetRegType;
|
|
property pWriter:PsrNode read GetWriter write SetWriter;
|
|
property pBuffer:PsrNode read GetBuffer write SetBuffer;
|
|
Procedure Init(L:PsrDataLayout);
|
|
function Emit:TCustomEmit;
|
|
Procedure UpdateRegType;
|
|
Procedure PrepType(new:TsrDataType);
|
|
procedure AddLine(pLine:PspirvOp);
|
|
function FirstLine:PspirvOp;
|
|
procedure FetchLoad(pLine:PspirvOp;dst:PsrRegNode);
|
|
Procedure FetchStore(pLine:PspirvOp;src:PsrRegNode);
|
|
function GetPrintName:RawByteString;
|
|
end;
|
|
|
|
TsrChains=array[0..7] of PsrChain;
|
|
|
|
TChainCb=function(node:PsrChain):Integer of object;
|
|
|
|
//----
|
|
|
|
TsrDataLayout=object
|
|
type
|
|
TChainFetch=specialize TNodeFetch<PsrChain,TsrChain>;
|
|
var
|
|
pLeft,pRight:PsrDataLayout;
|
|
//----
|
|
key:packed record
|
|
parent:PsrDataLayout;
|
|
offset:PtrUint;
|
|
rtype:TsrResourceType;
|
|
end;
|
|
pData:Pointer;
|
|
FID:Integer;
|
|
FEmit:TCustomEmit;
|
|
FList:TChainFetch;
|
|
function c(n1,n2:PsrDataLayout):Integer; static;
|
|
function Fetch(lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1):PsrChain;
|
|
Function First:PsrChain;
|
|
Function Last:PsrChain;
|
|
Function NextChain(node:PsrChain):PsrChain;
|
|
Function PrevChain(node:PsrChain):PsrChain;
|
|
function EnumChain(cb:TChainCb):Integer;
|
|
function GetData:Pointer;
|
|
function IsUserData:Boolean; inline;
|
|
function GetStride:PtrUint;
|
|
function GetTypeChar:Char;
|
|
function GetString:RawByteString;
|
|
function GetFuncString(LEN:DWORD):RawByteString;
|
|
end;
|
|
|
|
PsrDataLayoutList=^TsrDataLayoutList;
|
|
TsrDataLayoutList=object
|
|
type
|
|
TNodeFetch=specialize TNodeFetch<PsrDataLayout,TsrDataLayout>;
|
|
var
|
|
FTop:TsrDataLayout;
|
|
FNTree:TNodeFetch;
|
|
procedure Init(Emit:TCustomEmit);
|
|
procedure SetUserData(pData:Pointer);
|
|
function pRoot:PsrDataLayout;
|
|
function Fetch(p:PsrDataLayout;o:PtrUint;t:TsrResourceType):PsrDataLayout;
|
|
Function First:PsrDataLayout;
|
|
Function Next(node:PsrDataLayout):PsrDataLayout;
|
|
function Grouping(const chain:TsrChains;rtype:TsrResourceType):PsrDataLayout;
|
|
function EnumChain(cb:TChainCb):Integer;
|
|
Procedure AllocID;
|
|
procedure AllocSourceExtension;
|
|
procedure AllocFuncExt;
|
|
end;
|
|
|
|
//----
|
|
|
|
ntDescriptor=class(TsrNodeVmt)
|
|
class Procedure zero_read (node:PsrNode); override;
|
|
class Procedure zero_unread (node:PsrNode); override;
|
|
class Function GetPtype (node:PsrNode):PsrNode; override;
|
|
class Function GetStorageClass(node:PsrNode):DWORD; override;
|
|
end;
|
|
|
|
PsrDescriptor=^TsrDescriptor;
|
|
TsrDescriptor=packed object(TsrNode)
|
|
protected
|
|
FVar:PsrVariable;
|
|
FType:PsrType;
|
|
FStorage:DWORD;
|
|
FBinding:Integer;
|
|
procedure InitVar(Emit:TCustomEmit);
|
|
procedure InitType(rtype:TsrDataType;Emit:TCustomEmit);
|
|
procedure SetType(t:PsrType);
|
|
public
|
|
property pVar:PsrVariable read FVar;
|
|
property pType:PsrType read FType write SetType;
|
|
end;
|
|
|
|
function is_consistents(const chains:TsrChains;count:Byte):Boolean;
|
|
function is_no_index_chains(const chains:TsrChains;count:Byte):Boolean;
|
|
function is_userdata_chains(const chains:TsrChains;count:Byte):Boolean;
|
|
function GetResourceSizeDw(r:TsrResourceType):Byte;
|
|
|
|
implementation
|
|
|
|
class Procedure ntChain.zero_read(node:PsrNode);
|
|
begin
|
|
With PsrChain(node)^ do
|
|
begin
|
|
key.lvl_1.pIndex^.mark_read(node);
|
|
FBuffer^.mark_read(node);
|
|
end;
|
|
end;
|
|
|
|
class Procedure ntChain.zero_unread(node:PsrNode);
|
|
begin
|
|
With PsrChain(node)^ do
|
|
begin
|
|
key.lvl_1.pIndex^.mark_unread(node);
|
|
FBuffer^.mark_unread(node);
|
|
end;
|
|
end;
|
|
|
|
class Function ntChain.pwrite_count(node:PsrNode):PDWORD;
|
|
begin
|
|
Result:=@PsrChain(node)^.fwrite_count;
|
|
end;
|
|
|
|
class Procedure ntChain.SetWriter(node,w,line:PsrNode);
|
|
begin
|
|
With PsrChain(node)^ do
|
|
begin
|
|
SetWriter(w);
|
|
end;
|
|
end;
|
|
|
|
class Procedure ntChain.ResetWriter(node,w:PsrNode);
|
|
begin
|
|
With PsrChain(node)^ do
|
|
if (FWriter=w) then
|
|
begin
|
|
SetWriter(nil);
|
|
end;
|
|
end;
|
|
|
|
class function ntChain.Down(node:PsrNode):Pointer;
|
|
begin
|
|
Result:=PsrChain(node)^.FWriter;
|
|
end;
|
|
|
|
class function ntChain.Next(node:PsrNode):Pointer;
|
|
begin
|
|
Result:=PsrChain(node)^.FParent^.NextChain(PsrChain(node));
|
|
end;
|
|
|
|
class function ntChain.Prev(node:PsrNode):Pointer;
|
|
begin
|
|
Result:=PsrChain(node)^.FParent^.PrevChain(PsrChain(node));
|
|
end;
|
|
|
|
class function ntChain.Parent(node:PsrNode):Pointer;
|
|
begin
|
|
Result:=PsrChain(node)^.FParent;
|
|
end;
|
|
|
|
class Procedure ntChain.PrepType(node:PPrepTypeNode);
|
|
begin
|
|
PsrChain(node^.dnode)^.PrepType(TsrDataType(node^.rtype));
|
|
node^.dnode:=nil;
|
|
end;
|
|
|
|
class function ntChain.GetPrintName(node:PsrNode):RawByteString;
|
|
begin
|
|
Result:=PsrChain(node)^.GetPrintName;
|
|
end;
|
|
|
|
class function ntChain.GetRef(node:PsrNode):Pointer;
|
|
begin
|
|
Result:=@PsrChain(node)^.ID;
|
|
end;
|
|
|
|
//
|
|
|
|
class Procedure ntDescriptor.zero_read(node:PsrNode);
|
|
begin
|
|
With PsrDescriptor(node)^ do
|
|
begin
|
|
pType^.mark_read(node);
|
|
end;
|
|
end;
|
|
|
|
class Procedure ntDescriptor.zero_unread(node:PsrNode);
|
|
begin
|
|
With PsrDescriptor(node)^ do
|
|
begin
|
|
pType^.mark_unread(node);
|
|
end;
|
|
end;
|
|
|
|
class Function ntDescriptor.GetPtype(node:PsrNode):PsrNode;
|
|
begin
|
|
Result:=PsrDescriptor(node)^.FType;
|
|
end;
|
|
|
|
class Function ntDescriptor.GetStorageClass(node:PsrNode):DWORD;
|
|
begin
|
|
Result:=PsrDescriptor(node)^.FStorage;
|
|
end;
|
|
|
|
//
|
|
|
|
function TsrDataLayout.c(n1,n2:PsrDataLayout):Integer;
|
|
begin
|
|
//first parent
|
|
Result:=Integer(n1^.key.parent>n2^.key.parent)-Integer(n1^.key.parent<n2^.key.parent);
|
|
if (Result<>0) then Exit;
|
|
//second offset
|
|
Result:=Integer(n1^.key.offset>n2^.key.offset)-Integer(n1^.key.offset<n2^.key.offset);
|
|
if (Result<>0) then Exit;
|
|
//third rtype
|
|
Result:=Integer(n1^.key.rtype>n2^.key.rtype)-Integer(n1^.key.rtype<n2^.key.rtype);
|
|
end;
|
|
|
|
function TsrDataLayout.Fetch(lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1):PsrChain;
|
|
var
|
|
node:TsrChain;
|
|
begin
|
|
node:=Default(TsrChain);
|
|
if (lvl_0<>nil) then
|
|
begin
|
|
node.key.lvl_0:=lvl_0^;
|
|
end;
|
|
if (lvl_1<>nil) then
|
|
begin
|
|
node.key.lvl_1:=lvl_1^;
|
|
end;
|
|
|
|
Result:=FList.Find(@node);
|
|
if (Result=nil) then
|
|
begin
|
|
Result:=FEmit.Alloc(SizeOf(TsrChain));
|
|
Move(node,Result^,SizeOf(TsrChain));
|
|
|
|
Result^.Init(@Self);
|
|
|
|
FList.Insert(Result);
|
|
end;
|
|
end;
|
|
|
|
Function TsrDataLayout.First:PsrChain;
|
|
begin
|
|
Result:=FList.Min;
|
|
end;
|
|
|
|
Function TsrDataLayout.Last:PsrChain;
|
|
begin
|
|
Result:=FList.Max;
|
|
end;
|
|
|
|
Function TsrDataLayout.NextChain(node:PsrChain):PsrChain;
|
|
begin
|
|
Result:=FList.Next(node);
|
|
end;
|
|
|
|
Function TsrDataLayout.PrevChain(node:PsrChain):PsrChain;
|
|
begin
|
|
Result:=FList.Prev(node);
|
|
end;
|
|
|
|
function TsrDataLayout.EnumChain(cb:TChainCb):Integer;
|
|
var
|
|
node:PsrChain;
|
|
begin
|
|
Result:=0;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed then
|
|
begin
|
|
Result:=Result+cb(node);
|
|
end;
|
|
node:=node^.Next;
|
|
end;
|
|
end;
|
|
|
|
function TsrDataLayout.GetData:Pointer;
|
|
begin
|
|
Result:=nil;
|
|
if (pData<>nil) then
|
|
Case key.rtype of
|
|
rtRoot,
|
|
rtBufPtr2,
|
|
rtFunPtr2:Result:=pData;
|
|
rtVSharp4:Result:={%H-}Pointer(PVSharpResource4(pData)^.base);
|
|
rtTSharp4,
|
|
rtTSharp8:Result:={%H-}Pointer(PTSharpResource4(pData)^.base shl 8);
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function TsrDataLayout.GetStride:PtrUint;
|
|
begin
|
|
Result:=0;
|
|
if (pData<>nil) then
|
|
Case key.rtype of
|
|
rtRoot,
|
|
rtBufPtr2:Result:=4;
|
|
rtVSharp4:Result:=PVSharpResource4(pData)^.stride;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function TsrDataLayout.IsUserData:Boolean; inline;
|
|
begin
|
|
Result:=(key.rtype=rtRoot);
|
|
end;
|
|
|
|
function TsrDataLayout.GetTypeChar:Char;
|
|
begin
|
|
Result:=#0;
|
|
case key.rtype of
|
|
rtRoot :Result:='R';
|
|
rtBufPtr2:Result:='B';
|
|
rtFunPtr2:Result:='F';
|
|
rtVSharp4:Result:='V';
|
|
rtSSharp4:Result:='S';
|
|
rtTSharp4:Result:='t';
|
|
rtTSharp8:Result:='T';
|
|
end;
|
|
end;
|
|
|
|
function TsrDataLayout.GetString:RawByteString;
|
|
var
|
|
PID:DWORD;
|
|
begin
|
|
PID:=0;
|
|
if (key.parent<>nil) then
|
|
begin
|
|
PID:=key.parent^.FID;
|
|
end;
|
|
Result:='#'+GetTypeChar+
|
|
';PID='+HexStr(PID,8)+
|
|
';OFS='+HexStr(key.offset,8);
|
|
end;
|
|
|
|
function TsrDataLayout.GetFuncString(LEN:DWORD):RawByteString;
|
|
begin
|
|
Result:='FF'+
|
|
';PID='+HexStr(FID,8)+
|
|
';LEN='+HexStr(LEN,8);
|
|
end;
|
|
|
|
procedure TsrDataLayoutList.Init(Emit:TCustomEmit);
|
|
begin
|
|
FTop.FEmit:=Emit;
|
|
FNTree.Insert(@FTop);
|
|
end;
|
|
|
|
procedure TsrDataLayoutList.SetUserData(pData:Pointer);
|
|
begin
|
|
FTop.pData:=pData;
|
|
end;
|
|
|
|
function TsrDataLayoutList.pRoot:PsrDataLayout;
|
|
begin
|
|
Result:=@FTop;
|
|
end;
|
|
|
|
function TsrDataLayoutList.Fetch(p:PsrDataLayout;o:PtrUint;t:TsrResourceType):PsrDataLayout;
|
|
var
|
|
node:TsrDataLayout;
|
|
pData:Pointer;
|
|
begin
|
|
Assert(p<>nil);
|
|
node:=Default(TsrDataLayout);
|
|
node.FEmit:=FTop.FEmit;
|
|
node.key.parent:=p;
|
|
node.key.offset:=o;
|
|
node.key.rtype :=t;
|
|
Result:=FNTree.Find(@node);
|
|
if (Result=nil) then
|
|
begin
|
|
Result:=FTop.FEmit.Alloc(SizeOf(TsrDataLayout));
|
|
Move(node,Result^,SizeOf(TsrDataLayout));
|
|
FNTree.Insert(Result);
|
|
|
|
Result^.FID:=-1;
|
|
|
|
pData:=p^.GetData;
|
|
if (pData<>nil) then
|
|
case t of
|
|
rtRoot,
|
|
rtBufPtr2,
|
|
rtFunPtr2:Result^.pData:={%H-}Pointer(PPtrUint(pData+o)^ and (not 3));
|
|
rtVSharp4,
|
|
rtSSharp4,
|
|
rtTSharp4,
|
|
rtTSharp8:Result^.pData:=pData+o;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
Function TsrDataLayoutList.First:PsrDataLayout;
|
|
begin
|
|
Result:=FNTree.Min;
|
|
end;
|
|
|
|
Function TsrDataLayoutList.Next(node:PsrDataLayout):PsrDataLayout;
|
|
begin
|
|
Result:=FNTree.Next(node);
|
|
end;
|
|
|
|
function GetResourceSizeDw(r:TsrResourceType):Byte;
|
|
begin
|
|
Result:=0;
|
|
Case r of
|
|
rtRoot :Result:=2;
|
|
rtBufPtr2:Result:=2;
|
|
rtFunPtr2:Result:=2;
|
|
rtVSharp4:Result:=4;
|
|
rtSSharp4:Result:=4;
|
|
rtTSharp4:Result:=4;
|
|
rtTSharp8:Result:=8;
|
|
end;
|
|
end;
|
|
|
|
function TsrDataLayoutList.Grouping(const chain:TsrChains;rtype:TsrResourceType):PsrDataLayout;
|
|
begin
|
|
Result:=nil;
|
|
|
|
if not is_consistents(chain,GetResourceSizeDw(rtype)) then
|
|
begin
|
|
Assert(False,'inconsistent resources not supported');
|
|
end;
|
|
|
|
if not is_no_index_chains(chain,GetResourceSizeDw(rtype)) then
|
|
begin
|
|
Assert(False,'indexed chain not support');
|
|
end;
|
|
|
|
Result:=Fetch(chain[0]^.Parent,chain[0]^.offset,rtype);
|
|
end;
|
|
|
|
function TsrDataLayoutList.EnumChain(cb:TChainCb):Integer;
|
|
var
|
|
node:PsrDataLayout;
|
|
begin
|
|
Result:=0;
|
|
if (cb=nil) then Exit;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
Result:=Result+node^.EnumChain(cb);
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
Procedure TsrDataLayoutList.AllocID;
|
|
var
|
|
node:PsrDataLayout;
|
|
FID:Integer;
|
|
begin
|
|
FID:=1;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.FID=-1) then
|
|
begin
|
|
node^.FID:=FID;
|
|
Inc(FID);
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrDataLayoutList.AllocSourceExtension;
|
|
var
|
|
pDebugInfoList:PsrDebugInfoList;
|
|
node:PsrDataLayout;
|
|
begin
|
|
pDebugInfoList:=FTop.FEmit.GetDebugInfoList;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
pDebugInfoList^.OpSource(node^.GetString);
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrDataLayoutList.AllocFuncExt;
|
|
var
|
|
pDebugInfoList:PsrDebugInfoList;
|
|
pHeap:PsrCodeHeap;
|
|
node:PsrDataLayout;
|
|
block:PsrCodeBlock;
|
|
begin
|
|
pDebugInfoList:=FTop.FEmit.GetDebugInfoList;
|
|
pHeap:=FTop.FEmit.GetCodeHeap;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.key.rtype=rtFunPtr2) then
|
|
begin
|
|
block:=pHeap^.FindByPtr(node^.pData);
|
|
if (block<>nil) then
|
|
begin
|
|
pDebugInfoList^.OpSource(node^.GetFuncString(block^.Size));
|
|
end;
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
Procedure TsrChain.Init(L:PsrDataLayout);
|
|
begin
|
|
fntype:=ntChain;
|
|
FParent:=L;
|
|
end;
|
|
|
|
function TsrChainLvl_1.c(n1,n2:PsrChainLvl_1):Integer;
|
|
begin
|
|
//first pIndex backward
|
|
Result:=Integer(n1^.pIndex<n2^.pIndex)-Integer(n1^.pIndex>n2^.pIndex);
|
|
if (Result<>0) then Exit;
|
|
|
|
//second stride forward
|
|
Result:=Integer(n1^.stride>n2^.stride)-Integer(n1^.stride<n2^.stride);
|
|
end;
|
|
|
|
function TsrChainLvl_0.c(n1,n2:PsrChainLvl_0):Integer;
|
|
begin
|
|
//first size backward
|
|
Result:=Integer(n1^.size<n2^.size)-Integer(n1^.size>n2^.size);
|
|
if (Result<>0) then Exit;
|
|
|
|
//second offset forward
|
|
Result:=Integer(n1^.offset>n2^.offset)-Integer(n1^.offset<n2^.offset);
|
|
end;
|
|
|
|
function TsrChain.c(n1,n2:PsrChain):Integer;
|
|
begin
|
|
//first lvl_1
|
|
Result:=TsrChainLvl_1.c(@n1^.key.lvl_1,@n2^.key.lvl_1);
|
|
if (Result<>0) then Exit;
|
|
|
|
//second lvl_0
|
|
Result:=TsrChainLvl_0.c(@n1^.key.lvl_0,@n2^.key.lvl_0);
|
|
end;
|
|
|
|
function TsrChain.Emit:TCustomEmit;
|
|
begin
|
|
Result:=FParent^.FEmit;
|
|
end;
|
|
|
|
Procedure TsrChain.SetWriter(t:PsrNode);
|
|
begin
|
|
if (@Self=nil) then Exit;
|
|
if (FWriter=t) then Exit;
|
|
|
|
if isUsed then
|
|
begin
|
|
t^.mark_read (@Self);
|
|
FWriter^.mark_unread(@Self);
|
|
end;
|
|
FWriter:=t;
|
|
end;
|
|
|
|
Function TsrChain.GetWriter:PsrNode;
|
|
begin
|
|
Result:=nil;
|
|
if (@Self=nil) then Exit;
|
|
Result:=FWriter;
|
|
end;
|
|
|
|
Procedure TsrChain.SetBuffer(t:PsrNode);
|
|
begin
|
|
if (@Self=nil) then Exit;
|
|
if (FBuffer=t) then Exit;
|
|
|
|
if isUsed then
|
|
begin
|
|
t^.mark_read (@Self);
|
|
FBuffer^.mark_unread(@Self);
|
|
end;
|
|
FBuffer:=t;
|
|
end;
|
|
|
|
Function TsrChain.GetBuffer:PsrNode;
|
|
begin
|
|
Result:=nil;
|
|
if (@Self=nil) then Exit;
|
|
Result:=FBuffer;
|
|
end;
|
|
|
|
Procedure TsrChain.SetRegType(rtype:TsrDataType);
|
|
var
|
|
pTypeList:PsrTypeList;
|
|
FType:PsrType;
|
|
node:PVNode;
|
|
pLine:PspirvOp;
|
|
begin
|
|
Fdtype:=rtype;
|
|
|
|
pTypeList:=Emit.GetTypeList;
|
|
FType:=pTypeList^.Fetch(rtype);
|
|
|
|
node:=FList.pHead;
|
|
While (node<>nil) do
|
|
begin
|
|
pLine:=node^.pLine;
|
|
|
|
Case pLine^.OpId of
|
|
|
|
Op.OpLoad:
|
|
begin
|
|
pLine^.pDst^.PrepType(ord(rtype));
|
|
pLine^.pType:=Ftype;
|
|
end;
|
|
|
|
Op.OpStore:
|
|
begin
|
|
pLine^.ParamFirst^.Value^.PrepType(ord(rtype));
|
|
end;
|
|
|
|
else;
|
|
end;
|
|
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
Procedure TsrChain.UpdateRegType;
|
|
var
|
|
pTypeList:PsrTypeList;
|
|
pBitcastList:PsrBitcastList;
|
|
FType:PsrType;
|
|
node:PVNode;
|
|
pLine:PspirvOp;
|
|
dst:PsrRegNode;
|
|
old,rtype:TsrDataType;
|
|
begin
|
|
rtype:=Fdtype;
|
|
|
|
pTypeList:=Emit.GetTypeList;
|
|
FType:=pTypeList^.Fetch(rtype);
|
|
|
|
pBitcastList:=Emit.GetBitcastList;
|
|
|
|
node:=FList.pHead;
|
|
While (node<>nil) do
|
|
begin
|
|
pLine:=node^.pLine;
|
|
|
|
Case pLine^.OpId of
|
|
|
|
Op.OpLoad:
|
|
begin
|
|
pLine^.pDst^.PrepType(ord(rtype));
|
|
pLine^.pType:=Ftype;
|
|
|
|
dst:=pLine^.pDst^.AsType(ntReg);
|
|
if (dst<>nil) then
|
|
begin
|
|
old:=dst^.dtype;
|
|
if (old<>dtUnknow) and (not CompareType(rtype,old)) then
|
|
begin
|
|
//OpLoad -> new -> dst
|
|
pBitcastList:=Emit.GetBitcastList;
|
|
dst:=pBitcastList^.FetchDstr(rtype,dst);
|
|
pLine^.pDst:=dst;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Op.OpStore:
|
|
begin
|
|
pLine^.ParamFirst^.Value^.PrepType(ord(rtype));
|
|
|
|
dst:=pLine^.ParamFirst^.Value^.AsType(ntReg);
|
|
if (dst<>nil) then
|
|
begin
|
|
old:=dst^.dtype;
|
|
if (old<>dtUnknow) and (rtype<>old) then
|
|
begin
|
|
//OpStore <- new <- dst
|
|
pBitcastList:=Emit.GetBitcastList;
|
|
dst:=pBitcastList^.FetchRead(rtype,dst);
|
|
pLine^.ParamFirst^.Value:=dst;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
else;
|
|
end;
|
|
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
Procedure TsrChain.PrepType(new:TsrDataType);
|
|
var
|
|
old:TsrDataType;
|
|
begin
|
|
if (new=dtUnknow) then Exit;
|
|
old:=Fdtype;
|
|
if is_unprep_type(old,new,True) then
|
|
begin
|
|
old:=StoreType(new);
|
|
SetRegType(old);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrChain.AddLine(pLine:PspirvOp);
|
|
var
|
|
node:PVNode;
|
|
begin
|
|
node:=Emit.Alloc(SizeOf(TVNode));
|
|
node^.pLine:=pLine;
|
|
FList.Push_tail(node);
|
|
end;
|
|
|
|
function TsrChain.FirstLine:PspirvOp;
|
|
var
|
|
node:PVNode;
|
|
begin
|
|
Result:=nil;
|
|
node:=FList.pHead;
|
|
if (node<>nil) then
|
|
begin
|
|
Result:=node^.pLine;
|
|
end;
|
|
end;
|
|
|
|
procedure TsrChain.FetchLoad(pLine:PspirvOp;dst:PsrRegNode);
|
|
var
|
|
pTypeList:PsrTypeList;
|
|
begin
|
|
Assert(dst<>nil);
|
|
|
|
PrepType(dst^.dtype);
|
|
|
|
pTypeList:=Emit.GetTypeList;
|
|
pLine:=PspirvOp(Emit.OpLoad(pLine,pTypeList^.Fetch(Fdtype),dst,@Self));
|
|
|
|
AddLine(pLine);
|
|
end;
|
|
|
|
Procedure TsrChain.FetchStore(pLine:PspirvOp;src:PsrRegNode);
|
|
begin
|
|
if (src=nil) then Exit;
|
|
|
|
PrepType(src^.dtype);
|
|
|
|
pLine:=PspirvOp(Emit.OpStore(pLine,@Self,src));
|
|
|
|
AddLine(pLine);
|
|
end;
|
|
|
|
function TsrChain.GetPrintName:RawByteString;
|
|
begin
|
|
Assert(ID.Alloc);
|
|
Result:='ac'+IntToStr(ID.ID);
|
|
end;
|
|
|
|
//
|
|
|
|
procedure TsrDescriptor.InitVar(Emit:TCustomEmit);
|
|
var
|
|
pVariableList:PsrVariableList;
|
|
begin
|
|
if (Emit=nil) then Exit;
|
|
if (FVar<>nil) then Exit;
|
|
//
|
|
pVariableList:=Emit.GetVariableList;
|
|
//
|
|
FVar:=pVariableList^.Fetch;
|
|
FVar^.pSource:=@Self;
|
|
end;
|
|
|
|
procedure TsrDescriptor.InitType(rtype:TsrDataType;Emit:TCustomEmit);
|
|
var
|
|
pTypeList:PsrTypeList;
|
|
begin
|
|
if (Emit=nil) then Exit;
|
|
if (FType<>nil) then Exit;
|
|
//
|
|
pTypeList:=Emit.GetTypeList;
|
|
//
|
|
SetType(pTypeList^.Fetch(rtype));
|
|
end;
|
|
|
|
procedure TsrDescriptor.SetType(t:PsrType);
|
|
begin
|
|
if (FType=t) then Exit;
|
|
|
|
if isUsed then
|
|
begin
|
|
t^.mark_read (@Self);
|
|
FType^.mark_unread(@Self);
|
|
end;
|
|
FType:=t;
|
|
end;
|
|
|
|
function is_consistents(const chains:TsrChains;count:Byte):Boolean;
|
|
var
|
|
parent:PsrDataLayout;
|
|
offset,t:PtrUint;
|
|
i:Byte;
|
|
begin
|
|
offset:=0;
|
|
t:=0;
|
|
if (count<2) then Exit(True);
|
|
Result:=False;
|
|
if (chains[0]=nil) then Exit;
|
|
parent:=chains[0]^.parent;
|
|
offset:=chains[0]^.offset;
|
|
For i:=1 to count-1 do
|
|
begin
|
|
t:=chains[i-1]^.size;
|
|
offset:=offset+t;
|
|
if (chains[i]=nil) then Exit;
|
|
if (chains[i]^.parent<>parent) then Exit;
|
|
t:=chains[i]^.offset;
|
|
if (offset<>t) then Exit;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
function is_no_index_chains(const chains:TsrChains;count:Byte):Boolean;
|
|
var
|
|
i:Byte;
|
|
begin
|
|
Result:=False;
|
|
if (count=0) then Exit;
|
|
For i:=0 to count-1 do
|
|
begin
|
|
if (chains[i]=nil) then Exit;
|
|
if (chains[i]^.key.lvl_1.pIndex<>nil) then Exit;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
function is_userdata_chains(const chains:TsrChains;count:Byte):Boolean;
|
|
var
|
|
parent:PsrDataLayout;
|
|
i:Byte;
|
|
begin
|
|
Result:=False;
|
|
if (count=0) then Exit;
|
|
For i:=0 to count-1 do
|
|
begin
|
|
if (chains[i]=nil) then Exit;
|
|
parent:=chains[i]^.parent;
|
|
if (parent=nil) then Exit;
|
|
if (parent^.key.parent<>nil) then Exit;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
end.
|
|
|