mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-27 08:31:07 +00:00
1299 lines
27 KiB
ObjectPascal
1299 lines
27 KiB
ObjectPascal
unit emit_post;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
spirv,
|
|
srNodes,
|
|
srTypes,
|
|
srConst,
|
|
srReg,
|
|
srVariable,
|
|
srVolatile,
|
|
srLayout,
|
|
srBuffer,
|
|
srOp,
|
|
srOpUtils,
|
|
SprvEmit,
|
|
emit_op;
|
|
|
|
type
|
|
TPostCb=function(node:PSpirvOp):Integer of object;
|
|
TRegsCb=function(pLine:PspirvOp;var node:PsrRegNode):Integer of object;
|
|
TChainCb=function(node:PsrChain):Integer of object;
|
|
|
|
TSprvEmit_post=object(TEmitOp)
|
|
function Post:Integer;
|
|
|
|
function PrepTypeNode(var node:PsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer;
|
|
function PrepTypeDst(var node:PsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer;
|
|
function PrepTypeParam(node:POpParamNode;rtype:TsrDataType;relax:Boolean=true):Integer;
|
|
|
|
function RegFindCond(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
function RegCollapse({%H-}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 PostFuncAnalize:Integer;
|
|
|
|
function EnumChain(p:PsrDataLayout;cb:TChainCb):Integer;
|
|
function EnumChain(cb:TChainCb):Integer;
|
|
|
|
function PostDataLayoutAnalize:Integer;
|
|
function FetchField(var pChain:PsrChain;dtype:TsrDataType):PsrField;
|
|
Procedure SetLoadType(pChain:PsrChain;rtype:TsrDataType);
|
|
function OnChainField(node:PsrChain):Integer;
|
|
function OnChainAlloc(node:PsrChain):Integer;
|
|
procedure OnFieldType(node:PsrField);
|
|
procedure AllocBufferVar(node:PsrBuffer);
|
|
function PostConstAnalize:Integer;
|
|
function PostVariableAnalize:Integer;
|
|
function PostTypeAnalize(first:Boolean):Integer;
|
|
end;
|
|
|
|
function DstIsClear(const node:TOpParamSingle):Boolean;
|
|
function EnumLineRegs(cb:TRegsCb;pLine:PSpirvOp):Integer;
|
|
function EnumBlockOpForward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
function EnumBlockOpBackward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
procedure RegUnmark(node:PsrRegNode);
|
|
Procedure NodeParamClear(node:POpParamNode);
|
|
function NodeOpClear(p:PSpirvOp):Integer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
emit_post_op;
|
|
|
|
function TSprvEmit_post.Post:Integer;
|
|
begin
|
|
Result:=0;
|
|
Result:=Result+PostFuncAnalize;
|
|
Result:=Result+PostConstAnalize;
|
|
Result:=Result+PostTypeAnalize(True); //1
|
|
Result:=Result+PostVariableAnalize;
|
|
Result:=Result+PostTypeAnalize(False); //2
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.PrepTypeNode(var node:PsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer;
|
|
var
|
|
old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
if (rtype=dtUnknow) then Exit;
|
|
|
|
if (node^.dtype=dtUnknow) then
|
|
begin
|
|
RegPrepType(node,rtype);
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
Case relax of
|
|
True :relax:=CompareType(node^.dtype,rtype);
|
|
False:relax:=(node^.dtype=rtype);
|
|
end;
|
|
if not relax then
|
|
begin
|
|
old:=node;
|
|
node:=FBitcast.FetchRead(rtype,old);
|
|
RegUnmark(old);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PrepTypeDst(var node:PsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer;
|
|
var
|
|
old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
if (rtype=dtUnknow) then Exit;
|
|
|
|
if (node^.dtype=dtUnknow) then
|
|
begin
|
|
RegPrepType(node,rtype);
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
Case relax of
|
|
True :relax:=CompareType(node^.dtype,rtype);
|
|
False:relax:=(node^.dtype=rtype);
|
|
end;
|
|
if not relax then
|
|
begin
|
|
old:=node;
|
|
node:=FBitcast.FetchDst(rtype,old);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.PrepTypeParam(node:POpParamNode;rtype:TsrDataType;relax:Boolean=true):Integer;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
if (rtype=dtUnknow) then Exit;
|
|
if (node^.ntype<>ntReg) then Exit;
|
|
Result:=PrepTypeNode(node^.pData,rtype,relax);
|
|
end;
|
|
|
|
function DstIsClear(const node:TOpParamSingle):Boolean;
|
|
var
|
|
pVar:PsrVariable;
|
|
pReg:PsrRegNode;
|
|
pFunc:PSpirvFunc;
|
|
pChain:PsrChain;
|
|
begin
|
|
Result:=False;
|
|
Case node.ntype of
|
|
ntUnknow:;//dst not used
|
|
ntBlock:;
|
|
ntRefId:;
|
|
ntVar:
|
|
begin
|
|
pVar:=node.pData;
|
|
Result:=(pVar^.read_count=0) and (pVar^.write_count=0);
|
|
end;
|
|
ntReg:
|
|
begin
|
|
pReg:=node.pData;
|
|
Result:=(pReg^.read_count=0);
|
|
end;
|
|
ntFunc:
|
|
begin
|
|
pFunc:=node.pData;
|
|
Result:=(pFunc^.read_count=0);
|
|
end;
|
|
ntChain:
|
|
begin
|
|
pChain:=node.pData;
|
|
Result:=(pChain^.read_count=0) and (pChain^.write_count=0);
|
|
end;
|
|
else
|
|
Assert(false,'DstIsClear');
|
|
end;
|
|
end;
|
|
|
|
function EnumLineRegs(cb:TRegsCb;pLine:PSpirvOp):Integer;
|
|
var
|
|
node:POpParamNode;
|
|
begin
|
|
Result:=0;
|
|
if (cb=nil) or (pLine=nil) then Exit;
|
|
node:=pLine^.pParam.pHead;
|
|
While (node<>nil) do
|
|
begin
|
|
Case node^.ntype of
|
|
ntReg:
|
|
begin
|
|
Result:=Result+cb(pLine,node^.pData);
|
|
end
|
|
else;
|
|
end;
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
function EnumBlockOpForward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
var
|
|
node:PSpirvOp;
|
|
begin
|
|
Result:=0;
|
|
if (pBlock=nil) or (cb=nil) then Exit;
|
|
node:=pBlock^.pHead;
|
|
repeat
|
|
While (node<>nil) do
|
|
begin
|
|
Case node^.OpId of
|
|
OpBlock:
|
|
begin
|
|
pBlock:=node^.dst.AsBlock; //down
|
|
if (pBlock<>nil) then
|
|
begin
|
|
pBlock^.pUpLine:=node;
|
|
node:=pBlock^.pHead;
|
|
Continue;
|
|
end;
|
|
end;
|
|
else
|
|
begin
|
|
Result:=Result+cb(node);
|
|
end;
|
|
end;
|
|
node:=node^.pNext;
|
|
end;
|
|
node:=pBlock^.pUpLine; //prev
|
|
if (node=nil) then Break;
|
|
pBlock:=node^.pParent; //up
|
|
if (pBlock=nil) then Break;
|
|
node:=node^.pNext;
|
|
until false;
|
|
end;
|
|
|
|
function EnumBlockOpBackward(cb:TPostCb;pBlock:PsrOpBlock):Integer;
|
|
var
|
|
node:PSpirvOp;
|
|
begin
|
|
Result:=0;
|
|
if (pBlock=nil) or (cb=nil) then Exit;
|
|
node:=pBlock^.pTail;
|
|
repeat
|
|
While (node<>nil) do
|
|
begin
|
|
Case node^.OpId of
|
|
OpBlock:
|
|
begin
|
|
pBlock:=node^.dst.AsBlock; //down
|
|
if (pBlock<>nil) then
|
|
begin
|
|
pBlock^.pUpLine:=node;
|
|
node:=pBlock^.pTail;
|
|
Continue;
|
|
end;
|
|
end;
|
|
else
|
|
begin
|
|
Result:=Result+cb(node);
|
|
end;
|
|
end;
|
|
node:=node^.pPrev;
|
|
end;
|
|
node:=pBlock^.pUpLine; //prev
|
|
if (node=nil) then Break;
|
|
pBlock:=node^.pParent; //up
|
|
if (pBlock=nil) then Break;
|
|
node:=node^.pPrev;
|
|
until false;
|
|
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^.pParent;
|
|
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;
|
|
RegUnmark(node);
|
|
node:=FetchReg(FConsts.Fetchb(n xor tmp^.Cond.FVal));
|
|
Exit(1);
|
|
end;
|
|
|
|
p:=src^.AsOp;
|
|
if (p=nil) then Exit;
|
|
|
|
Case p^.OpId of
|
|
Op.OpLogicalNot:;
|
|
Op.OpNot:;
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
src:=p^.ParamNode(0)^.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
|
|
new,old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
//backtrace
|
|
old:=node;
|
|
While (true) do
|
|
begin
|
|
Case old^.pWriter.ntype of
|
|
ntReg:
|
|
begin
|
|
new:=old^.pWriter.pData; //next
|
|
old^.mark_unread;
|
|
if (old^.read_count<>0) then
|
|
begin
|
|
new^.mark_read;
|
|
end;
|
|
old:=new;
|
|
end;
|
|
else
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
if (old<>node) then //is change?
|
|
begin
|
|
if (node^.dtype=dtUnknow) or CompareType(node^.dtype,old^.dtype) then
|
|
begin
|
|
node:=old; //set new
|
|
Inc(Result);
|
|
end else
|
|
begin //save to another step
|
|
node^.mark_read;
|
|
node^.pWriter.SetParam(ntReg,old);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegTypecast(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
new,old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
//backtrace
|
|
old:=node;
|
|
While (true) do
|
|
begin
|
|
Case old^.pWriter.ntype of
|
|
ntReg:
|
|
begin
|
|
new:=old^.pWriter.pData; //next
|
|
old^.mark_unread;
|
|
if (old^.read_count<>0) then
|
|
begin
|
|
new^.mark_read;
|
|
end;
|
|
old:=new;
|
|
end;
|
|
ntVolatile:
|
|
begin //create load/store
|
|
TEmitVolatile(Self).PrepVolatile(pLine,old);
|
|
Inc(Result);
|
|
end
|
|
else
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
if (old<>node) then //is change?
|
|
begin
|
|
if (node^.dtype=dtUnknow) or CompareType(node^.dtype,old^.dtype) then
|
|
begin
|
|
node:=old; //set new
|
|
Inc(Result);
|
|
end else
|
|
begin //bitcast
|
|
old^.mark_unread;
|
|
node:=FBitcast.FetchCast(node^.dtype,old);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegSTStrict(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
dst,old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node^.dtype=dtBool) then Exit;
|
|
dst:=pLine^.dst.AsReg;
|
|
if (dst=nil) then Exit;
|
|
|
|
{pLine:=node^.pLine;
|
|
if (pLine^.dst_type^.key.dtype<>node^.dtype) then
|
|
begin
|
|
Writeln(Op.GetStr(pLine^.OpId),' ',pLine^.dst_type^.key.dtype,'<>',node^.dtype);
|
|
Assert(false);
|
|
end;}
|
|
|
|
dtype:=dst^.dtype;
|
|
if (dtype<>node^.dtype) then
|
|
begin
|
|
old:=node;
|
|
node:=FBitcast.FetchCast(dtype,old); //strict type
|
|
RegUnmark(old);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegVTStrict(pLine:PspirvOp;var node:PsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
dst,old:PsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
dst:=pLine^.dst.AsReg;
|
|
if (dst=nil) then Exit;
|
|
dtype:=GetVecChild(dst^.dtype);
|
|
if (dtype<>node^.dtype) then
|
|
begin
|
|
old:=node;
|
|
node:=FBitcast.FetchCast(dtype,old); //strict type
|
|
RegUnmark(old);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
procedure _RegUnmark(var st_lt:TsrVolatiles;node:PsrRegNode);
|
|
var
|
|
n:PsrRegNode;
|
|
pConst:PsrConst;
|
|
begin
|
|
node^.mark_unread;
|
|
//backtrace
|
|
While (node^.read_count=0) do
|
|
begin
|
|
Case node^.pWriter.ntype of
|
|
ntReg:
|
|
begin
|
|
n:=node^.pWriter.pData; //next
|
|
n^.mark_unread;
|
|
node:=n;
|
|
end;
|
|
ntVolatile:
|
|
begin
|
|
st_lt.Move_from(TsrVolatiles(node^.pWriter.pData));
|
|
n:=st_lt.pop_reg;
|
|
if (n=nil) then Break;
|
|
n^.mark_unread;
|
|
node:=n;
|
|
end;
|
|
ntConst:
|
|
begin
|
|
pConst:=node^.pWriter.pData;
|
|
pConst^.mark_unread;
|
|
Break;
|
|
end;
|
|
ntOp:Break;
|
|
ntUnknow:Break; //nop
|
|
else
|
|
Assert(false,'_RegUnmark');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure RegUnmark(node:PsrRegNode);
|
|
var
|
|
st_lt:TsrVolatiles;
|
|
begin
|
|
st_lt:=Default(TsrVolatiles);
|
|
While (node<>nil) do
|
|
begin
|
|
_RegUnmark(st_lt,node);
|
|
node:=st_lt.pop_reg;
|
|
end;
|
|
end;
|
|
|
|
Procedure NodeParamClear(node:POpParamNode);
|
|
begin
|
|
if (node=nil) then Exit;
|
|
Case node^.ntype of
|
|
ntLiteral:;
|
|
ntConst:PsrConst (node^.pData)^.mark_unread;
|
|
ntType :PsrType (node^.pData)^.mark_unread;
|
|
ntFunc :PSpirvFunc (node^.pData)^.mark_unread;
|
|
ntVar :PsrVariable(node^.pData)^.mark_unread;
|
|
ntRefId:;
|
|
ntReg :RegUnmark (node^.pData);
|
|
ntChain:PsrChain (node^.pData)^.mark_unread;
|
|
else
|
|
Assert(false,'NodeParamClear');
|
|
end;
|
|
end;
|
|
|
|
function NodeOpClear(p:PSpirvOp):Integer;
|
|
var
|
|
node:POpParamNode;
|
|
begin
|
|
Result:=0;
|
|
if (p=nil) then Exit;
|
|
if (p^.dst_type<>nil) then
|
|
begin
|
|
p^.dst_type^.mark_unread;
|
|
p^.dst_type:=nil;
|
|
Inc(Result);
|
|
end;
|
|
node:=p^.pParam.Pop_head;
|
|
While (node<>nil) do
|
|
begin
|
|
NodeParamClear(node);
|
|
node:=p^.pParam.Pop_head;
|
|
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;
|
|
|
|
src^.mark_read;
|
|
dst^.pWriter.SetParam(ntReg,src);
|
|
|
|
node^.OpId:=OpLinks; //mark remove
|
|
node^.dst:=Default(TOpParamSingle);
|
|
|
|
Result:=1;
|
|
end;
|
|
|
|
function TSprvEmit_post.NodeOpStrict(node:PSpirvOp):Integer;
|
|
begin
|
|
Result:=0;
|
|
if (node^.dst.ntype<>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;
|
|
Case node^.OpId of
|
|
Op.OpNop:; //ignore
|
|
OpLinks:
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.OpId:=Op.OpNop; //mark remove
|
|
Inc(Result);
|
|
end;
|
|
else
|
|
begin
|
|
if DstIsClear(node^.dst) then
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.OpId:=Op.OpNop; //mark remove
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
Result:=Result+NodeOpSameOp(node);
|
|
Result:=Result+EnumLineRegs(@RegCollapse,node);
|
|
Result:=Result+EnumLineRegs(@RegFindCond,node);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep2(node:PSpirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
Case node^.OpId of
|
|
Op.OpNop:; //ignore
|
|
OpLinks:
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.OpId:=Op.OpNop; //mark remove
|
|
Inc(Result);
|
|
end;
|
|
else
|
|
begin
|
|
if DstIsClear(node^.dst) then
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.OpId:=Op.OpNop; //mark remove
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
//Result:=Result+EnumLineRegs(@RegCond,node);
|
|
//Result:=Result+EnumLineRegs(@RegCuts,node);
|
|
Result:=Result+TEmitPostOp(Self).PostForward1(node);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep3(node:PSpirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
Case node^.OpId of
|
|
Op.OpNop:; //ignore
|
|
OpLinks:
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.OpId:=Op.OpNop; //mark remove
|
|
Inc(Result);
|
|
end;
|
|
else
|
|
begin
|
|
if DstIsClear(node^.dst) then
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.OpId:=Op.OpNop; //mark remove
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
//Result:=Result+EnumLineRegs(@RegCond,node);
|
|
//Result:=Result+EnumLineRegs(@RegCuts,node);
|
|
Result:=Result+TEmitPostOp(Self).PostForward2(node);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep4(node:PSpirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
Case node^.OpId of
|
|
Op.OpNop:; //ignore
|
|
OpLinks:; //ignore
|
|
else
|
|
begin
|
|
if not DstIsClear(node^.dst) then
|
|
begin
|
|
Result:=Result+EnumLineRegs(@RegTypecast,node);
|
|
Result:=Result+NodeOpStrict(node);
|
|
Result:=Result+EnumLineRegs(@RegFindCond,node);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnOpStep5(node:PSpirvOp):Integer; //backward
|
|
begin
|
|
Result:=0;
|
|
Case node^.OpId of
|
|
Op.OpNop,
|
|
OpLinks:
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.Remove; //remove
|
|
Inc(Result);
|
|
end;
|
|
else
|
|
begin
|
|
if DstIsClear(node^.dst) then
|
|
begin
|
|
Result:=Result+NodeOpClear(node); //delete links
|
|
node^.Remove; //remove
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostFuncAnalize:Integer;
|
|
var
|
|
pFunc:PSpirvFunc;
|
|
data_layout:Boolean;
|
|
i:Integer;
|
|
begin
|
|
Result:=0;
|
|
data_layout:=false;
|
|
//backward analize
|
|
pFunc:=FSpirvFuncs.FList.pTail;
|
|
While (pFunc<>nil) do
|
|
begin
|
|
|
|
data_layout:=(FMain=pFunc);
|
|
|
|
repeat
|
|
|
|
repeat
|
|
|
|
repeat
|
|
i:=EnumBlockOpBackward(@OnOpStep1,@pFunc^.FTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
i:=EnumBlockOpForward(@OnOpStep2,@pFunc^.FTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
i:=EnumBlockOpForward (@OnOpStep3,@pFunc^.FTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
if data_layout then
|
|
begin
|
|
Result:=Result+PostDataLayoutAnalize;
|
|
data_layout:=false;
|
|
end;
|
|
|
|
repeat
|
|
i:=EnumBlockOpForward (@OnOpStep4,@pFunc^.FTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
Result:=Result+EnumBlockOpBackward(@OnOpStep5,@pFunc^.FTop);
|
|
|
|
pFunc:=pFunc^.pPrev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.EnumChain(p:PsrDataLayout;cb:TChainCb):Integer;
|
|
var
|
|
node:PsrChain;
|
|
begin
|
|
Result:=0;
|
|
node:=p^.First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed then
|
|
begin
|
|
Result:=Result+cb(node);
|
|
end;
|
|
node:=p^.Next(node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.EnumChain(cb:TChainCb):Integer;
|
|
var
|
|
node:PsrDataLayout;
|
|
begin
|
|
Result:=0;
|
|
if (cb=nil) then Exit;
|
|
node:=FDataLayouts.First;
|
|
While (node<>nil) do
|
|
begin
|
|
Result:=Result+EnumChain(node,cb);
|
|
node:=FDataLayouts.Next(node);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostDataLayoutAnalize:Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
FDataLayouts.AllocID;
|
|
|
|
Result:=Result+EnumChain(@OnChainField);
|
|
|
|
FBuffers.ApplyBufferType;
|
|
FBuffers.AlignOffset;
|
|
FBuffers.FillSpace;
|
|
FBuffers.AllocID;
|
|
FBuffers.EnumAllField(@OnFieldType);
|
|
|
|
Result:=Result+EnumChain(@OnChainAlloc);
|
|
end;
|
|
|
|
function TSprvEmit_post.FetchField(var pChain:PsrChain;dtype:TsrDataType):PsrField;
|
|
var
|
|
buf:PsrBuffer;
|
|
F:TFieldFetchValue;
|
|
_offset,_count,_stride:PtrUint;
|
|
ext:TsrChainExt;
|
|
pNew:PsrChain;
|
|
fset_index:Boolean;
|
|
begin
|
|
_count:=0;
|
|
_stride:=0;
|
|
|
|
if (pChain^.key.ext.pIndex<>nil) then
|
|
begin
|
|
//RuntimeArray
|
|
|
|
buf:=FBuffers.Fetch(pChain^.parent,0);
|
|
repeat
|
|
|
|
_offset:=pChain^.key.offset;
|
|
F:=buf^.FTop.FetchRuntimeArray(_offset,pChain^.key.ext.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^.key.size,dtype);
|
|
|
|
until (F.fValue<>frNotFit);
|
|
if (F.fValue<>frNotFit) then Break;
|
|
|
|
buf:=FBuffers.NextCast(buf);
|
|
until false;
|
|
|
|
end else
|
|
begin
|
|
//Value/Vector
|
|
|
|
buf:=FBuffers.Fetch(pChain^.parent,0);
|
|
fset_index:=False;
|
|
repeat
|
|
|
|
_offset:=pChain^.key.offset;
|
|
F.pField:=@buf^.FTop;
|
|
repeat
|
|
|
|
F:=F.pField^.FetchValue(_offset,pChain^.key.size,dtype);
|
|
Case F.fValue of
|
|
frNotFit :Break;
|
|
frIdent,
|
|
frVectorAsValue:
|
|
begin
|
|
if fset_index then
|
|
begin
|
|
Assert(pChain^.key.ext.pIndex=nil);
|
|
|
|
ext:=Default(TsrChainExt);
|
|
ext.pIndex:=FetchReg(FConsts.Fetchi(dtUint32,_count));
|
|
ext.stride:=_stride;
|
|
pNew:=pChain^.parent^.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:=FBuffers.NextCast(buf);
|
|
fset_index:=False;
|
|
until false;
|
|
|
|
end;
|
|
|
|
Result:=F.pField;
|
|
end;
|
|
|
|
Procedure TSprvEmit_post.SetLoadType(pChain:PsrChain;rtype:TsrDataType);
|
|
var
|
|
node:PsrRegNode;
|
|
pLine:PspirvOp;
|
|
begin
|
|
node:=pChain^.rSlot.pStory.pHead;
|
|
While (node<>nil) do
|
|
begin
|
|
node^.dtype:=rtype;
|
|
pLine:=node^.pWriter.AsOp;
|
|
if (pLine<>nil) then
|
|
if (pLine=node^.pLine) then //is current load
|
|
if (pLine^.OpId=Op.OpLoad) then
|
|
begin
|
|
if (pLine^.dst_type<>nil) then
|
|
begin
|
|
pLine^.dst_type^.mark_unread;
|
|
end;
|
|
pLine^.dst_type:=FSpirvTypes.Fetch(rtype);
|
|
end;
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainField(node:PsrChain):Integer;
|
|
var
|
|
pField:PsrField;
|
|
dtype:TsrDataType;
|
|
begin
|
|
Result:=1;
|
|
dtype:=node^.GetRegType;
|
|
//Writeln('OnChainsField:',dtype,':',node^.key.offset);
|
|
pField:=FetchField(node,dtype);
|
|
node^.pField:=pField;
|
|
if (pField^.dtype<>dtype) then
|
|
begin
|
|
dtype:=pField^.dtype;
|
|
SetLoadType(node,dtype);
|
|
|
|
//Writeln(pField^.dtype,'<>',dtype);
|
|
//Assert(false,'TODO');
|
|
end;
|
|
FBuffers.UpdateStorage(node,pField^.pBuffer);
|
|
end;
|
|
|
|
procedure TSprvEmit_post.OnFieldType(node:PsrField);
|
|
var
|
|
count:PtrUint;
|
|
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;
|
|
sType^.mark_read;
|
|
end else
|
|
begin
|
|
count:=node^.FCount;
|
|
Assert(count<>0);
|
|
sType:=FSpirvTypes._New(count);
|
|
|
|
count:=0;
|
|
child:=node^.First;
|
|
While (child<>nil) do
|
|
begin
|
|
Assert(child^.pType<>nil);
|
|
child^.pType^.mark_read;
|
|
sType^.SetCompItem(count,child^.pType);
|
|
Inc(count);
|
|
child:=node^.Next(child);
|
|
end;
|
|
|
|
sType:=FSpirvTypes.FetchStructNode(sType,count,node);
|
|
end;
|
|
|
|
Case node^.dtype of
|
|
dtTypeArray:
|
|
begin
|
|
count:=node^.size div node^.stride;
|
|
pType:=FSpirvTypes.FetchArray(sType,count,node^.stride);
|
|
end;
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
pType:=FSpirvTypes.FetchRuntimeArray(sType,node^.stride);
|
|
end;
|
|
else
|
|
begin
|
|
pType:=sType;
|
|
end;
|
|
end;
|
|
|
|
node^.pType:=pType;
|
|
|
|
if (node^.parent=nil) then
|
|
begin
|
|
AllocBufferVar(node^.pBuffer);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
node^.pType:=FSpirvTypes.Fetch(node^.dtype);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TSprvEmit_post.AllocBufferVar(node:PsrBuffer);
|
|
var
|
|
pVar:PsrVariable;
|
|
pType:PsrType;
|
|
begin
|
|
pType:=node^.FTop.pType;
|
|
Assert(pType<>nil);
|
|
|
|
pVar:=node^.pVar;
|
|
if (pVar=nil) then
|
|
begin
|
|
pType^.mark_read;
|
|
pType:=FSpirvTypes.FetchPointer(pType,node^.FStorage);
|
|
|
|
pVar:=NewVariable;
|
|
pVar^.dtype:=dtTypeStruct;
|
|
pVar^.pType:=pType;
|
|
pVar^.pSource.SetParam(ntBuffer,node);
|
|
|
|
node^.pVar:=pVar;
|
|
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^.key.ext.pIndex);
|
|
if (pIndex=nil) or (pIndex^.is_const) then
|
|
begin
|
|
pLine:=init_line;
|
|
end else
|
|
begin
|
|
pLine:=node^.rSlot.first^.pLine;
|
|
Assert(pLine<>nil);
|
|
pLine:=pLine^.pPrev;
|
|
Assert(pLine<>nil);
|
|
end;
|
|
pField:=node^.pField;
|
|
Assert(pField<>nil);
|
|
src:=pField^.pBuffer^.pVar;
|
|
Assert(src<>nil);
|
|
src^.mark_read;
|
|
pLine:=TEmitOp(Self).emit_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^.pParam.pTail;
|
|
repeat
|
|
|
|
Parent:=pField^.parent;
|
|
if (Parent<>nil) then
|
|
Case Parent^.dtype of
|
|
dtTypeStruct:
|
|
begin
|
|
pReg:=FetchReg(FConsts.Fetchi(dtUint32,pField^.FID));
|
|
pLine^.AddParamAfter(pParam,ntReg,pReg);
|
|
end;
|
|
dtTypeArray,
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
if not Parent^.IsStructNotUsed then
|
|
begin
|
|
pReg:=FetchReg(FConsts.Fetchi(dtUint32,pField^.FID));
|
|
pLine^.AddParamAfter(pParam,ntReg,pReg);
|
|
end;
|
|
Assert(pIndex<>nil);
|
|
pIndex^.mark_read;
|
|
pLine^.AddParamAfter(pParam,ntReg,pIndex);
|
|
end;
|
|
else
|
|
if IsVector(Parent^.dtype) then
|
|
begin
|
|
pReg:=FetchReg(FConsts.Fetchi(dtUint32,pField^.FID));
|
|
pLine^.AddParamAfter(pParam,ntReg,pReg);
|
|
end;
|
|
end;
|
|
|
|
pField:=Parent;
|
|
until (pField=nil);
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.PostConstAnalize:Integer;
|
|
var
|
|
node:PsrConst;
|
|
begin
|
|
Result:=0;
|
|
node:=FConsts.FList.pTail;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.read_count=0) then
|
|
begin
|
|
node^.Clear; //delete links
|
|
FConsts.FList.Remove(node); //remove?
|
|
Inc(Result);
|
|
end else
|
|
if (node^.pType=nil) then
|
|
begin
|
|
node^.pType:=FSpirvTypes.Fetch(node^.key.dtype);
|
|
//Assert(node^.pTypeAlloc<>nil);
|
|
end;
|
|
node:=node^.pPrev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostVariableAnalize:Integer;
|
|
var
|
|
node:PsrVariable;
|
|
pType:PsrType;
|
|
begin
|
|
Result:=0;
|
|
node:=FVariables.pTail;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.read_count=0) and (node^.write_count=0) then
|
|
begin
|
|
node^.Clear; //delete links
|
|
FVariables.Remove(node); //remove?
|
|
Inc(Result);
|
|
end else
|
|
if (node^.pType=nil) then
|
|
begin
|
|
pType:=FSpirvTypes.Fetch(node^.dtype);
|
|
Assert(pType<>nil);
|
|
node^.pType:=FSpirvTypes.FetchPointer(pType,node^.GetStorageClass);
|
|
end;
|
|
node:=node^.pPrev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostTypeAnalize(first:Boolean):Integer;
|
|
var
|
|
node:PsrType;
|
|
begin
|
|
Result:=0;
|
|
node:=FSpirvTypes.FList.pTail;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.read_count=0) then
|
|
begin
|
|
node^.Clear; //delete links
|
|
FSpirvTypes.FList.Remove(node); //remove?
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
case node^.key.OpId of
|
|
|
|
Op.OpTypeFloat:
|
|
begin
|
|
case node^.key.ext.float_size of
|
|
16:AddCap(Capability.Float16);
|
|
64:AddCap(Capability.Float64);
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
Op.OpTypeInt:
|
|
begin
|
|
case node^.key.ext.int_size of
|
|
8:AddCap(Capability.Int8);
|
|
16:AddCap(Capability.Int16);
|
|
64:AddCap(Capability.Int64);
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
Op.OpTypeImage:
|
|
begin
|
|
|
|
Case node^.key.ext.image.Dim of
|
|
Dim.Dim1D:
|
|
Case node^.key.ext.image.Sampled of
|
|
0:; //runtime
|
|
1:AddCap(Capability.Sampled1D); //sampling
|
|
2:AddCap(Capability.Image1D); //read/write
|
|
else;
|
|
end;
|
|
Dim.Buffer:
|
|
Case node^.key.ext.image.Sampled of
|
|
0:; //runtime
|
|
1:AddCap(Capability.SampledBuffer); //sampling
|
|
2:AddCap(Capability.ImageBuffer); //read/write
|
|
else;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (node^.key.ext.image.Sampled=2) and
|
|
(node^.key.ext.image.Arrayed=1) then
|
|
begin
|
|
AddCap(Capability.ImageMSArray);
|
|
end;
|
|
|
|
Case node^.key.ext.image.Format of
|
|
ImageFormat.Unknown :AddCap(Capability.StorageImageReadWithoutFormat);
|
|
|
|
ImageFormat.Rg32f ,
|
|
ImageFormat.Rg16f ,
|
|
ImageFormat.R11fG11fB10f,
|
|
ImageFormat.R16f ,
|
|
ImageFormat.Rgba16 ,
|
|
ImageFormat.Rgb10A2 ,
|
|
ImageFormat.Rg16 ,
|
|
ImageFormat.Rg8 ,
|
|
ImageFormat.R16 ,
|
|
ImageFormat.R8 ,
|
|
ImageFormat.Rgba16Snorm ,
|
|
ImageFormat.Rg16Snorm ,
|
|
ImageFormat.Rg8Snorm ,
|
|
ImageFormat.R16Snorm ,
|
|
ImageFormat.R8Snorm ,
|
|
ImageFormat.Rg32i ,
|
|
ImageFormat.Rg16i ,
|
|
ImageFormat.Rg8i ,
|
|
ImageFormat.R16i ,
|
|
ImageFormat.R8i ,
|
|
ImageFormat.Rgb10a2ui ,
|
|
ImageFormat.Rg32ui ,
|
|
ImageFormat.Rg16ui ,
|
|
ImageFormat.Rg8ui ,
|
|
ImageFormat.R16ui ,
|
|
ImageFormat.R8ui :AddCap(Capability.StorageImageExtendedFormats);
|
|
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
Op.OpTypeArray:
|
|
if not first then
|
|
begin
|
|
//make a const of count
|
|
if (node^.key.ext.array_count=0) then Assert(False);
|
|
FConsts.Fetchi(dtUInt32,node^.key.ext.array_count); //just increment
|
|
end;
|
|
|
|
else;
|
|
end;
|
|
end;
|
|
node:=node^.pPrev;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|