mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-12-02 11:26:33 +00:00
1000 lines
20 KiB
ObjectPascal
1000 lines
20 KiB
ObjectPascal
unit emit_post;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
spirv,
|
|
srNode,
|
|
srType,
|
|
srTypes,
|
|
srConst,
|
|
srReg,
|
|
srVariable,
|
|
srLayout,
|
|
srBuffer,
|
|
srBitcast,
|
|
srPrivate,
|
|
srOp,
|
|
srOpUtils,
|
|
emit_fetch;
|
|
|
|
type
|
|
TPostCb=function(node:PSpirvOp):Integer of object;
|
|
TRegsCb=function(pLine:PspirvOp;var node:PsrRegNode):Integer of object;
|
|
|
|
TSprvEmit_post=class(TEmitFetch)
|
|
function PostStage:Integer;
|
|
|
|
function RegFindCond(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegCollapse(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegVResolve(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegWResolve(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegTypecast(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegSTStrict(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegVTStrict(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
|
|
//function NodeOpSameOp(node:PSpirvOp):Integer;
|
|
function NodeOpStrict(node:PSpirvOp):Integer;
|
|
|
|
function OnOpStep1(node:PSpirvOp):Integer; //backward
|
|
function OnOpStep2(node:PSpirvOp):Integer; //forward
|
|
function OnOpStep3(node:PSpirvOp):Integer; //forward
|
|
function OnOpStep4(node:PSpirvOp):Integer; //forward
|
|
function OnOpStep5(node:PSpirvOp):Integer; //backward
|
|
function OnOpStep6(node:PSpirvOp):Integer; //backward
|
|
function OnOpStep7(node:PSpirvOp):Integer; //backward
|
|
|
|
function PostFuncAnalize:Integer;
|
|
|
|
function OnChainUpdate(node:PsrChain):Integer;
|
|
|
|
function PostDataLayoutAnalize1:Integer;
|
|
function PostDataLayoutAnalize2:Integer;
|
|
function FetchField(var pChain:PsrChain;dtype:TsrDataType):PsrField;
|
|
function OnChainField(node:PsrChain):Integer;
|
|
function OnChainAlloc(node:PsrChain):Integer;
|
|
procedure OnFieldType(node:PsrField);
|
|
function PostConstAnalize:Integer;
|
|
function PostVariableAnalize:Integer;
|
|
function PostTypeAnalize:Integer;
|
|
end;
|
|
|
|
function EnumLineRegs(cb:TRegsCb;pLine:PSpirvOp):Integer;
|
|
function EnumBlockOpForward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
function EnumBlockOpBackward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
emit_post_op;
|
|
|
|
function TSprvEmit_post.PostStage:Integer;
|
|
begin
|
|
Result:=0;
|
|
InputList.Test;
|
|
Result:=Result+PostFuncAnalize;
|
|
Result:=Result+PostVariableAnalize;
|
|
Result:=Result+PostConstAnalize;
|
|
Result:=Result+PostTypeAnalize;
|
|
end;
|
|
|
|
function EnumLineRegs(cb:TRegsCb;pLine:PSpirvOp):Integer;
|
|
var
|
|
node:POpParamNode;
|
|
pReg:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (cb=nil) or (pLine=nil) then Exit;
|
|
node:=pLine^.ParamFirst;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.Value^.IsType(ntReg) then
|
|
begin
|
|
pReg:=node^.AsReg;
|
|
Result:=Result+cb(pLine,pReg);
|
|
node^.Value:=pReg;
|
|
end;
|
|
node:=node^.Next;
|
|
end;
|
|
end;
|
|
|
|
function EnumBlockOpForward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
var
|
|
node,prev:PSpirvOp;
|
|
begin
|
|
Result:=0;
|
|
if (pBlock=nil) or (cb=nil) then Exit;
|
|
node:=pBlock^.First;
|
|
While (node<>nil) do
|
|
begin
|
|
prev:=node;
|
|
node:=flow_down_next_up(node);
|
|
if prev^.IsType(ntOp) then
|
|
begin
|
|
Result:=Result+cb(prev);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function EnumBlockOpBackward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
var
|
|
node,prev:PSpirvOp;
|
|
begin
|
|
Result:=0;
|
|
if (pBlock=nil) or (cb=nil) then Exit;
|
|
node:=pBlock^.Last;
|
|
While (node<>nil) do
|
|
begin
|
|
prev:=node;
|
|
node:=flow_down_prev_up(node);
|
|
if prev^.IsType(ntOp) then
|
|
begin
|
|
Result:=Result+cb(prev);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegFindCond(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
pBlock:PsrOpBlock;
|
|
tmp:PsrOpBlock;
|
|
src:PsrRegNode;
|
|
p:PspirvOp;
|
|
n:Boolean;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
|
|
pBlock:=pLine^.Parent;
|
|
src:=RegDown(node);
|
|
n:=false;
|
|
|
|
repeat
|
|
if src^.is_const then Exit;
|
|
|
|
tmp:=pBlock^.FindUpCond(src);
|
|
if (tmp<>nil) then
|
|
begin
|
|
if (tmp=pBlock) and (pLine^.OpId=Op.OpBranchConditional) then Exit;
|
|
|
|
node:=NewReg_b(n xor tmp^.Cond.FVal,@pLine);
|
|
Exit(1);
|
|
end;
|
|
|
|
p:=src^.pWriter^.AsType(ntOp);
|
|
if (p=nil) then Exit;
|
|
|
|
Case p^.OpId of
|
|
Op.OpLogicalNot:;
|
|
Op.OpNot:;
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
src:=p^.ParamFirst^.AsReg;
|
|
if (src=nil) then Exit;
|
|
src:=RegDown(src);
|
|
n:=not n;
|
|
|
|
until false;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegCollapse(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
if (node^.dtype=dtUnknow) then Exit;
|
|
|
|
old:=node;
|
|
node:=RegDown(old);
|
|
|
|
if (old<>node) then //is change?
|
|
begin
|
|
if (node^.dtype=dtUnknow) or CompareType(node^.dtype,old^.dtype) then
|
|
begin
|
|
Inc(Result);
|
|
end else
|
|
begin //save to another step
|
|
old^.pWriter:=node;
|
|
node:=old;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegVResolve(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
|
|
old:=node;
|
|
|
|
node:=RegDown(old);
|
|
if node^.pWriter^.IsType(ntVolatile) then
|
|
begin
|
|
//create load/store
|
|
//use forward only
|
|
node:=PrivateList.PrepVolatile(pLine,node);
|
|
Inc(Result);
|
|
end;
|
|
|
|
if (old<>node) then //is change?
|
|
begin
|
|
if (node^.dtype=dtUnknow) or (node^.dtype=old^.dtype) then
|
|
begin
|
|
Inc(Result);
|
|
end else
|
|
begin //save to another step
|
|
old^.pWriter:=node;
|
|
node:=old;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetDepType(src:PsrRegNode):TsrDataType;
|
|
var
|
|
node:PRegDNode;
|
|
pReg:PsrRegNode;
|
|
pLine:PspirvOp;
|
|
|
|
Function CmpType(var ret:TsrDataType;dtype:TsrDataType):Boolean;
|
|
begin
|
|
Result:=False;
|
|
if (dtype=dtUnknow) then Exit;
|
|
if (ret=dtUnknow) then
|
|
begin
|
|
ret:=dtype;
|
|
end else
|
|
begin
|
|
if (ret<>dtype) then
|
|
begin
|
|
ret:=dtUnknow;
|
|
Result:=True; //Exit
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result:=dtUnknow;
|
|
node:=src^.FirstDep;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.pNode^.IsType(ntReg) then
|
|
begin
|
|
pReg:=node^.pNode^.AsType(ntReg);
|
|
if (pReg<>nil) then
|
|
begin
|
|
if CmpType(Result,pReg^.dtype) then Exit;
|
|
end;
|
|
end else
|
|
if node^.pNode^.IsType(ntOp) then
|
|
begin
|
|
pLine:=node^.pNode^.AsType(ntOp);
|
|
Case pLine^.OpId of
|
|
|
|
Op.OpStore:
|
|
begin
|
|
//ignore?
|
|
end;
|
|
|
|
else
|
|
begin
|
|
if CmpType(Result,src^.dtype) then Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
function ResolveWeak(new:PsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
begin
|
|
Result:=0;
|
|
While (new<>nil) do
|
|
begin
|
|
|
|
if new^.Weak then
|
|
begin
|
|
dtype:=GetDepType(new);
|
|
if (dtype<>dtUnknow) then
|
|
begin
|
|
if (new^.dtype<>dtype) then
|
|
begin
|
|
new^.dtype:=dtype;
|
|
new^.Weak :=False;
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
new^.Weak :=False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
new:=new^.AsReg; //next
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegWResolve(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
Result:=Result+ResolveWeak(node);
|
|
end;
|
|
|
|
function TSprvEmit_post.RegTypecast(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
|
|
old:=node;
|
|
node:=RegDown(old);
|
|
|
|
if (old<>node) then //is change?
|
|
begin
|
|
if (node^.dtype=dtUnknow) or (node^.dtype=old^.dtype) then
|
|
begin
|
|
Inc(Result);
|
|
end else
|
|
begin //bitcast
|
|
node:=BitcastList.FetchCast(old^.dtype,node);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegSTStrict(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
dst:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node^.dtype=dtBool) then Exit;
|
|
dst:=pLine^.pDst^.AsType(ntReg);
|
|
if (dst=nil) then Exit;
|
|
|
|
dtype:=dst^.dtype;
|
|
if (dtype<>node^.dtype) then
|
|
begin
|
|
node:=BitcastList.FetchCast(dtype,node); //strict type
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegVTStrict(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
dst:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
dst:=pLine^.pDst^.AsType(ntReg);
|
|
if (dst=nil) then Exit;
|
|
|
|
dtype:=dst^.dtype.Child;
|
|
if (dtype<>node^.dtype) then
|
|
begin
|
|
node:=BitcastList.FetchCast(dtype,node); //strict type
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
{
|
|
function TSprvEmit_post.NodeOpSameOp(node:PSpirvOp):Integer;
|
|
var
|
|
tmp:PspirvOp;
|
|
dst,src:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node^.dst.ntype<>ntReg) then Exit; //is reg
|
|
|
|
Case node^.OpId of
|
|
Op.OpLoad:;
|
|
Op.OpCompositeConstruct:;
|
|
OpMakeExp:;
|
|
OpMakeVec:;
|
|
OpPackOfs:;
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
tmp:=FindUpSameOp(node^.pPrev,node);
|
|
if (tmp=nil) then Exit;
|
|
|
|
src:=tmp^.dst.AsReg;
|
|
dst:=node^.dst.AsReg;
|
|
|
|
if (src=nil) or (dst=nil) then Exit;
|
|
|
|
dst^.SetReg(src);
|
|
|
|
node^.OpId:=OpLinks; //mark remove
|
|
node^.dst:=Default(TOpParamSingle);
|
|
|
|
Result:=1;
|
|
end;
|
|
}
|
|
|
|
function TSprvEmit_post.NodeOpStrict(node:PSpirvOp):Integer;
|
|
begin
|
|
Result:=0;
|
|
if not node^.pDst^.IsType(ntReg) then Exit; //is reg
|
|
|
|
Case node^.OpId of
|
|
Op.OpBitFieldUExtract ,
|
|
Op.OpSelect :Result:=EnumLineRegs(@RegSTStrict,node);
|
|
Op.OpIAddCarry ,
|
|
Op.OpISubBorrow ,
|
|
Op.OpCompositeConstruct:Result:=EnumLineRegs(@RegVTStrict,node);
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep1(node:PSpirvOp):Integer; //backward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then Exit;
|
|
|
|
if node^.can_clear then
|
|
begin
|
|
if node^.Clear then Inc(Result);
|
|
end else
|
|
begin
|
|
//Result:=Result+NodeOpSameOp(node);
|
|
Result:=Result+EnumLineRegs(@RegCollapse,node);
|
|
Result:=Result+EnumLineRegs(@RegFindCond,node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep2(node:PSpirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then Exit;
|
|
|
|
if node^.can_clear then
|
|
begin
|
|
if node^.Clear then Inc(Result);
|
|
end else
|
|
begin
|
|
Result:=Result+TEmitPostOp(TObject(Self)).PostForward1(node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep3(node:PSpirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then Exit;
|
|
|
|
if node^.can_clear then
|
|
begin
|
|
if node^.Clear then Inc(Result);
|
|
end else
|
|
begin
|
|
Result:=Result+TEmitPostOp(TObject(Self)).PostForward2(node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep4(node:PSpirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then Exit;
|
|
|
|
if node^.can_clear then
|
|
begin
|
|
if node^.Clear then Inc(Result);
|
|
end else
|
|
begin
|
|
Result:=Result+EnumLineRegs(@RegVResolve,node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep5(node:PSpirvOp):Integer; //backward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then Exit;
|
|
|
|
if node^.can_clear then
|
|
begin
|
|
if node^.Clear then Inc(Result);
|
|
end else
|
|
begin
|
|
Result:=Result+EnumLineRegs(@RegWResolve,node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep6(node:PSpirvOp):Integer; //backward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then Exit;
|
|
|
|
if node^.can_clear then
|
|
begin
|
|
if node^.Clear then Inc(Result);
|
|
end else
|
|
begin
|
|
Result:=Result+EnumLineRegs(@RegTypecast,node);
|
|
Result:=Result+NodeOpStrict(node);
|
|
Result:=Result+EnumLineRegs(@RegFindCond,node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep7(node:PSpirvOp):Integer; //backward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node^.is_cleared then
|
|
begin
|
|
Assert(node^.read_count=0);
|
|
node^.Remove;
|
|
Inc(Result);
|
|
end else
|
|
if node^.can_clear then
|
|
begin
|
|
node^.Clear;
|
|
node^.Remove;
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostFuncAnalize:Integer;
|
|
var
|
|
pFunc:PSpirvFunc;
|
|
data_layout:Boolean;
|
|
i,r4:Integer;
|
|
begin
|
|
Result:=0;
|
|
data_layout:=false;
|
|
//backward analize
|
|
pFunc:=FuncList.FList.pTail;
|
|
While (pFunc<>nil) do
|
|
begin
|
|
|
|
data_layout:=(Main=pFunc);
|
|
|
|
repeat //OnOpStep5
|
|
|
|
repeat //OnOpStep3
|
|
|
|
repeat //OnOpStep2
|
|
|
|
repeat //OnOpStep1
|
|
i:=EnumBlockOpBackward(@OnOpStep1,pFunc^.pTop); //OnOpStep1 Reg Collapse
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
i:=EnumBlockOpForward(@OnOpStep2,pFunc^.pTop); //OnOpStep2 PostForward1
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
i:=EnumBlockOpForward(@OnOpStep3,pFunc^.pTop); //OnOpStep3 PostForward2
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
if data_layout then
|
|
begin
|
|
Result:=Result+PostDataLayoutAnalize1;
|
|
data_layout:=false;
|
|
end;
|
|
|
|
repeat //OnOpStep4 Volatile Reslove
|
|
i:=EnumBlockOpForward(@OnOpStep4,pFunc^.pTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
r4:=0;
|
|
repeat //OnOpStep5 Weak Reslove
|
|
i:=EnumBlockOpBackward(@OnOpStep5,pFunc^.pTop);
|
|
if (i=0) then Break;
|
|
r4:=r4+i;
|
|
until false;
|
|
|
|
if (r4=0) then Break;
|
|
Result:=Result+r4;
|
|
until false;
|
|
|
|
PrivateList.RemoveAllStore;
|
|
|
|
data_layout:=(Main=pFunc);
|
|
if data_layout then
|
|
begin
|
|
Result:=Result+PostDataLayoutAnalize2;
|
|
end;
|
|
|
|
//UpdateRegType OpLoad/OpStore
|
|
DataLayoutList.EnumChain(@OnChainUpdate);
|
|
PrivateList.Post;
|
|
|
|
repeat //OnOpStep6 Typecast
|
|
i:=EnumBlockOpBackward(@OnOpStep6,pFunc^.pTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
Result:=Result+EnumBlockOpBackward(@OnOpStep7,pFunc^.pTop); //OnOpStep7 Remove Lines
|
|
|
|
pFunc:=pFunc^.Prev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainUpdate(node:PsrChain):Integer;
|
|
begin
|
|
Result:=0;
|
|
node^.UpdateRegType;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostDataLayoutAnalize1:Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
DataLayoutList.AllocID;
|
|
|
|
Result:=Result+DataLayoutList.EnumChain(@OnChainField);
|
|
end;
|
|
|
|
function TSprvEmit_post.PostDataLayoutAnalize2:Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
BufferList.ApplyBufferType;
|
|
BufferList.AlignOffset;
|
|
BufferList.FillSpace;
|
|
BufferList.AllocID;
|
|
BufferList.EnumAllField(@OnFieldType);
|
|
|
|
Result:=Result+DataLayoutList.EnumChain(@OnChainAlloc);
|
|
end;
|
|
|
|
function TSprvEmit_post.FetchField(var pChain:PsrChain;dtype:TsrDataType):PsrField;
|
|
var
|
|
buf:PsrBuffer;
|
|
F:TFieldFetchValue;
|
|
_offset,_stride:PtrUint;
|
|
_count:PtrUint;
|
|
//ext:TsrChainExt;
|
|
//pNew:PsrChain;
|
|
fset_index:Boolean;
|
|
begin
|
|
_count:=0;
|
|
_stride:=0;
|
|
|
|
if (pChain^.pIndex<>nil) then
|
|
begin
|
|
//RuntimeArray
|
|
|
|
//Writeln('RA:',HexStr(pChain^.parent),':',pChain^.offset);
|
|
|
|
buf:=BufferList.Fetch(pChain^.parent,0);
|
|
repeat
|
|
|
|
_offset:=pChain^.offset;
|
|
F:=buf^.FTop.FetchRuntimeArray(_offset,pChain^.stride);
|
|
repeat
|
|
|
|
Case F.fValue of
|
|
frNotFit :Break;
|
|
frIdent :Exit(F.pField);
|
|
frVectorAsValue:Exit(F.pField);
|
|
frValueInVector:_offset:=_offset-F.pField^.offset;
|
|
frValueInArray :_offset:=_offset-F.pField^.offset;
|
|
end;
|
|
F:=F.pField^.FetchValue(_offset,pChain^.size,dtype);
|
|
|
|
until (F.fValue<>frNotFit);
|
|
if (F.fValue<>frNotFit) then Break;
|
|
|
|
buf:=BufferList.NextAlias(buf);
|
|
until false;
|
|
|
|
end else
|
|
begin
|
|
//Value/Vector
|
|
|
|
//Writeln('VV:',HexStr(pChain^.parent),':',pChain^.offset);
|
|
|
|
buf:=BufferList.Fetch(pChain^.parent,0);
|
|
fset_index:=False;
|
|
repeat
|
|
|
|
_offset:=pChain^.offset;
|
|
F.pField:=@buf^.FTop;
|
|
repeat
|
|
|
|
F:=F.pField^.FetchValue(_offset,pChain^.size,dtype);
|
|
Case F.fValue of
|
|
frNotFit :Break;
|
|
frIdent,
|
|
frVectorAsValue:
|
|
begin
|
|
if fset_index then
|
|
begin
|
|
Break;
|
|
{
|
|
Assert(pChain^.key.ext.pIndex=nil);
|
|
|
|
ext:=Default(TsrChainExt);
|
|
ext.pIndex:=NewReg_i(dtUint32,_count);
|
|
ext.stride:=_stride;
|
|
pNew:=pChain^.FParent^.Fetch(_offset,pChain^.key.size,@ext);
|
|
|
|
pNew^.read_count :=pChain^.read_count ;
|
|
pNew^.write_count:=pChain^.write_count;
|
|
pNew^.rSlot :=pChain^.rSlot ;
|
|
|
|
pChain^.read_count :=0;
|
|
pChain^.write_count:=0;
|
|
pChain^.rSlot :=Default(TsrRegSlot);
|
|
|
|
pChain:=pNew;
|
|
}
|
|
end;
|
|
Exit(F.pField);
|
|
end;
|
|
frValueInVector:_offset:=_offset-F.pField^.offset;
|
|
frValueInArray :
|
|
begin
|
|
Assert(not fset_index);
|
|
_offset:=_offset-F.pField^.offset;
|
|
_stride:=F.pField^.stride;
|
|
_count :=_offset div _stride;
|
|
_offset:=_offset mod _stride;
|
|
fset_index:=true;
|
|
end;
|
|
end;
|
|
|
|
until (F.fValue<>frNotFit);
|
|
if (F.fValue<>frNotFit) then Break;
|
|
|
|
buf:=BufferList.NextAlias(buf);
|
|
fset_index:=False;
|
|
until false;
|
|
|
|
end;
|
|
|
|
Result:=F.pField;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainField(node:PsrChain):Integer;
|
|
var
|
|
pField:PsrField;
|
|
dtype:TsrDataType;
|
|
begin
|
|
Result:=1;
|
|
dtype:=node^.dtype;
|
|
//Writeln('OnChainsField:',dtype,':',node^.key.offset);
|
|
pField:=FetchField(node,dtype);
|
|
Assert(pField<>nil);
|
|
node^.pField:=pField;
|
|
if (pField^.dtype<>dtype) then
|
|
begin
|
|
node^.dtype:=pField^.dtype;
|
|
end;
|
|
//pField^.pBuffer^.TakeChain(node);
|
|
node^.pBuffer:=pField^.pBuffer;
|
|
end;
|
|
|
|
procedure TSprvEmit_post.OnFieldType(node:PsrField);
|
|
var
|
|
count:PtrUint;
|
|
|
|
items:PPsrType;
|
|
sType,pType:PsrType;
|
|
|
|
child:PsrField;
|
|
begin
|
|
if (node^.pType<>nil) then Exit;
|
|
|
|
if (node^.dtype in [dtTypeStruct,dtTypeArray,dtTypeRuntimeArray]) then
|
|
begin
|
|
if node^.IsStructNotUsed then
|
|
begin
|
|
child:=node^.First;
|
|
Assert(child<>nil);
|
|
Assert(child^.pType<>nil);
|
|
sType:=child^.pType;
|
|
end else
|
|
begin
|
|
count:=node^.FCount;
|
|
Assert(count<>0);
|
|
items:=Alloc(SizeOf(Pointer)*count);
|
|
|
|
count:=0;
|
|
child:=node^.First;
|
|
While (child<>nil) do
|
|
begin
|
|
Assert(child^.pType<>nil);
|
|
items[count]:=child^.pType;
|
|
Inc(count);
|
|
child:=node^.Next(child);
|
|
end;
|
|
|
|
if node^.IsTop then
|
|
begin
|
|
sType:=TypeList.InsertStruct(count,items,False,node^.GetSize); //unique
|
|
end else
|
|
begin
|
|
sType:=TypeList.FetchStruct (count,items,False,node^.GetSize);
|
|
end;
|
|
|
|
end;
|
|
|
|
Case node^.dtype of
|
|
dtTypeArray:
|
|
begin
|
|
count:=node^.GetSize div node^.stride;
|
|
pType:=TypeList.FetchArray(sType,count);
|
|
end;
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
pType:=TypeList.FetchRuntimeArray(sType);
|
|
end;
|
|
else
|
|
begin
|
|
pType:=sType;
|
|
end;
|
|
end;
|
|
|
|
node^.sType:=sType;
|
|
node^.pType:=pType;
|
|
|
|
if node^.IsTop then
|
|
begin
|
|
//Alloc Type Var
|
|
node^.pBuffer^.pType:=pType;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
node^.sType:=nil;
|
|
node^.pType:=TypeList.Fetch(node^.dtype);
|
|
end;
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainAlloc(node:PsrChain):Integer;
|
|
var
|
|
pLine:PspirvOp;
|
|
pIndex:PsrRegNode;
|
|
pReg:PsrRegNode;
|
|
pField:PsrField;
|
|
Parent:PsrField;
|
|
src:PsrVariable;
|
|
pParam:POpParamNode;
|
|
//dtype:TsrDataType;
|
|
begin
|
|
Result:=1;
|
|
|
|
pIndex:=RegDown(node^.pIndex);
|
|
if (pIndex=nil) or (pIndex^.is_const) then
|
|
begin
|
|
pLine:=init_line;
|
|
end else
|
|
begin
|
|
pLine:=node^.FirstLine;
|
|
Assert(pLine<>nil);
|
|
pLine:=pLine^.Prev;
|
|
Assert(pLine<>nil);
|
|
end;
|
|
pField:=node^.pField;
|
|
Assert(pField<>nil);
|
|
src:=pField^.pBuffer^.pVar;
|
|
Assert(src<>nil);
|
|
pLine:=OpAccessChain(pLine,pField^.pType,node,src);
|
|
|
|
//dtype:=node^.GetRegType;
|
|
//if (pField^.dtype<>dtype) then
|
|
//begin
|
|
// Writeln(pField^.dtype,'<>',dtype);
|
|
// Assert(false,'TODO');
|
|
//end;
|
|
|
|
pParam:=pLine^.ParamLast;
|
|
repeat
|
|
|
|
Parent:=pField^.pParent;
|
|
if (Parent<>nil) then
|
|
Case Parent^.dtype of
|
|
dtTypeStruct:
|
|
begin
|
|
pReg:=NewReg_i(dtUint32,pField^.FID,@pLine);
|
|
pLine^.AddParamAfter(pParam,pReg);
|
|
end;
|
|
dtTypeArray,
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
if not Parent^.IsStructNotUsed then
|
|
begin
|
|
pReg:=NewReg_i(dtUint32,pField^.FID,@pLine);
|
|
pLine^.AddParamAfter(pParam,pReg);
|
|
end;
|
|
Assert(pIndex<>nil);
|
|
pLine^.AddParamAfter(pParam,pIndex);
|
|
end;
|
|
else
|
|
if Parent^.dtype.isVector then
|
|
begin
|
|
pReg:=NewReg_i(dtUint32,pField^.FID,@pLine);
|
|
pLine^.AddParamAfter(pParam,pReg);
|
|
end;
|
|
end;
|
|
|
|
pField:=Parent;
|
|
until (pField=nil);
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.PostConstAnalize:Integer;
|
|
var
|
|
node:PsrConst;
|
|
begin
|
|
Result:=0;
|
|
node:=ConstList.FList.pTail;
|
|
While (node<>nil) do
|
|
begin
|
|
if (not node^.IsUsed) then
|
|
begin
|
|
ConstList.FList.Remove(node); //remove?
|
|
Inc(Result);
|
|
end;
|
|
node:=node^.Prev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostVariableAnalize:Integer;
|
|
var
|
|
node:PsrVariable;
|
|
begin
|
|
Result:=0;
|
|
node:=VariableList.FList.pTail;
|
|
While (node<>nil) do
|
|
begin
|
|
if (not node^.IsUsed) then
|
|
begin
|
|
VariableList.FList.Remove(node); //remove?
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
node^.UpdateType(Self);
|
|
end;
|
|
node:=node^.Prev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostTypeAnalize:Integer;
|
|
var
|
|
node:PsrType;
|
|
begin
|
|
Result:=0;
|
|
node:=TypeList.FList.pTail;
|
|
While (node<>nil) do
|
|
begin
|
|
if (not node^.IsUsed) then
|
|
begin
|
|
TypeList.FList.Remove(node); //remove?
|
|
Inc(Result);
|
|
end;
|
|
node:=node^.Prev;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|