mirror of https://github.com/red-prig/fpPS4.git
1380 lines
26 KiB
Plaintext
1380 lines
26 KiB
Plaintext
unit emit_post;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
spirv,
|
|
srNode,
|
|
srType,
|
|
srTypes,
|
|
srConst,
|
|
srReg,
|
|
srVariable,
|
|
srLayout,
|
|
srBuffer,
|
|
srBitcast,
|
|
srPrivate,
|
|
srOutput,
|
|
srOp,
|
|
srOpUtils,
|
|
srDecorate,
|
|
emit_fetch;
|
|
|
|
type
|
|
TPostCb=function(node:TSpirvOp):Integer of object;
|
|
TRegsCb=function(pLine:TspirvOp;var node:TsrRegNode):Integer of object;
|
|
|
|
TSprvEmit_post=class(TEmitFetch)
|
|
function PostStage:Integer;
|
|
|
|
function RegFindCond(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
function RegCollapse(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
function RegVResolve(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
function RegWResolve(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
function RegTypecast(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
function RegSTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
function RegVTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
|
|
//function NodeOpSameOp(node:TspirvOp):Integer;
|
|
|
|
function NodeOpStrict(node:TspirvOp):Integer;
|
|
|
|
function OnOpStep1(node:TspirvOp):Integer; //backward
|
|
function OnOpStep2(node:TspirvOp):Integer; //forward
|
|
function OnOpStep3(node:TspirvOp):Integer; //forward
|
|
function OnOpStep4(node:TspirvOp):Integer; //forward
|
|
function OnOpStep5(node:TspirvOp):Integer; //backward
|
|
function OnOpStep6(node:TspirvOp):Integer; //backward
|
|
function OnOpStep7(node:TspirvOp):Integer; //backward
|
|
|
|
function OnDecorate(node:TspirvOp):Integer;
|
|
|
|
function PostFuncAnalize:Integer;
|
|
|
|
function OnChainUpdate(node:TsrChain):Integer;
|
|
|
|
function PostAllocField:Integer;
|
|
function PostAllocBuffer:Integer;
|
|
procedure ShiftIndex(pChain:TsrChain;const F:TFieldFetchValue;var _offset:PtrUint);
|
|
function FetchField(pChain:TsrChain):TsrField;
|
|
function OnChainField(node:TsrChain):Integer;
|
|
procedure AdjustMaxSize(tbuf:TsrBuffer);
|
|
function LinkBitcast(pBuffer:TsrBuffer):TsrNode;
|
|
function OnChainAlloc(node:TsrChain):Integer;
|
|
procedure OnFieldType(node:TsrField);
|
|
function PostConstAnalize:Integer;
|
|
function PostVariableAnalize:Integer;
|
|
function PostTypeAnalize:Integer;
|
|
end;
|
|
|
|
function EnumLineRegs(cb:TRegsCb;pLine:TspirvOp):Integer;
|
|
function EnumFirstReg(cb:TRegsCb;pLine:TspirvOp):Integer;
|
|
function EnumBlockOpForward(cb:TPostCb;pBlock:TsrOpBlock):Integer;
|
|
function EnumBlockOpBackward(cb:TPostCb;pBlock:TsrOpBlock):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:TspirvOp):Integer;
|
|
var
|
|
node:POpParamNode;
|
|
pReg:TsrRegNode;
|
|
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 EnumFirstReg(cb:TRegsCb;pLine:TspirvOp):Integer;
|
|
var
|
|
node:POpParamNode;
|
|
pReg:TsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (cb=nil) or (pLine=nil) then Exit;
|
|
node:=pLine.ParamFirst;
|
|
if (node<>nil) then
|
|
begin
|
|
if node.Value.IsType(ntReg) then
|
|
begin
|
|
pReg:=node.AsReg;
|
|
Result:=Result+cb(pLine,pReg);
|
|
node.Value:=pReg;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function EnumBlockOpForward(cb:TPostCb;pBlock:TsrOpBlock):Integer;
|
|
var
|
|
node,prev:TspirvOp;
|
|
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:TsrOpBlock):Integer;
|
|
var
|
|
node,prev:TspirvOp;
|
|
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:TspirvOp;var node:TsrRegNode):Integer;
|
|
var
|
|
old:TsrRegNode;
|
|
pBlock:TsrOpBlock;
|
|
pCond :TsrOpBlock;
|
|
pIf :TsrOpBlock;
|
|
src:TsrRegNode;
|
|
pOpNot:TspirvOp;
|
|
Invert:Boolean;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
|
|
old:=node;
|
|
src:=RegDown(node);
|
|
Invert:=false;
|
|
|
|
pBlock:=pLine.Parent;
|
|
|
|
if (pLine.OpId=Op.OpBranchConditional) then
|
|
begin
|
|
//move to parent of current "If" block
|
|
pIf :=pBlock.FindUpCond;
|
|
pBlock:=pBlock.Parent;
|
|
//
|
|
if (pIf<>nil) then
|
|
if (RegDown(pIf.Cond.pReg)<>src) then
|
|
begin
|
|
//non cond
|
|
pIf:=nil;
|
|
end;
|
|
end else
|
|
begin
|
|
pIf:=nil;
|
|
end;
|
|
|
|
repeat
|
|
if src.is_const then Exit;
|
|
|
|
pCond:=pBlock.FindUpCondByReg(src,True,Invert);
|
|
if (pCond<>nil) then
|
|
begin
|
|
//Exit(0);
|
|
|
|
//Writeln(OpGetStr(pLine));
|
|
|
|
//FNormalOrder=true Invert=false : result=true
|
|
//FNormalOrder=true Invert=true : result=false
|
|
//FNormalOrder=false Invert=false : result=false
|
|
//FNormalOrder=false Invert=true : result=true
|
|
|
|
Invert:=Invert xor pCond.Cond.FNormalOrder;
|
|
|
|
node:=NewImm_q(old.dtype,ord(Invert),pLine);
|
|
|
|
if (pIf<>nil) then
|
|
begin
|
|
//replace cond
|
|
pIf.Cond.pReg:=node;
|
|
end;
|
|
|
|
Exit(1);
|
|
end;
|
|
|
|
pOpNot:=src.pWriter.specialize AsType<ntOp>;
|
|
if (pOpNot=nil) then Exit;
|
|
|
|
Case pOpNot.OpId of
|
|
Op.OpLogicalNot:;
|
|
Op.OpNot:;
|
|
else
|
|
Exit;
|
|
end;
|
|
|
|
src:=pOpNot.ParamFirst.AsReg;
|
|
if (src=nil) then Exit;
|
|
src:=RegDown(src);
|
|
Invert:=not Invert;
|
|
|
|
until false;
|
|
end;
|
|
|
|
function CompareTypeOp(OpId:DWORD;rtype1,rtype2:TsrDataType):Boolean;
|
|
var
|
|
relax:Boolean;
|
|
begin
|
|
Case OpId of
|
|
Op.OpLoad ,
|
|
Op.OpImageRead ,
|
|
Op.OpImageWrite ,
|
|
Op.OpBitFieldSExtract ,
|
|
Op.OpBitFieldUExtract ,
|
|
Op.OpSelect ,
|
|
Op.OpIAddCarry ,
|
|
Op.OpISubBorrow ,
|
|
Op.OpUMulExtended ,
|
|
Op.OpSMulExtended ,
|
|
Op.OpCompositeConstruct:relax:=False;
|
|
else
|
|
relax:=True;
|
|
end;
|
|
|
|
Case relax of
|
|
True :Result:=CompareType(rtype1,rtype2);
|
|
False:Result:=(rtype1=rtype2);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegCollapse(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
var
|
|
rold,rnew:TsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
if (node.dtype=dtUnknow) then Exit;
|
|
|
|
rold:=node;
|
|
rnew:=RegDown(rold);
|
|
|
|
if (rold<>rnew) then //is change?
|
|
begin
|
|
if (rnew.dtype=dtUnknow) or CompareTypeOp(pLine.OpId,rnew.dtype,rold.dtype) then
|
|
begin
|
|
rnew.PrepType(ord(rold.dtype));
|
|
if (rnew.dtype<>dtUnknow) then
|
|
begin
|
|
node:=rnew;
|
|
Inc(Result);
|
|
end;
|
|
end else
|
|
begin //save to another step
|
|
rold.pWriter:=rnew;
|
|
node:=rold;
|
|
end;
|
|
end;
|
|
|
|
{
|
|
if (rold.dtype<>dtUnknow) and (node.dtype=dtUnknow) then
|
|
begin
|
|
writeln;
|
|
assert(false);
|
|
end;
|
|
}
|
|
end;
|
|
|
|
function TSprvEmit_post.RegVResolve(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
var
|
|
old:TsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
|
|
//if not (node.IsUsed) 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;
|
|
|
|
{
|
|
if (old.dtype<>dtUnknow) and (node.dtype=dtUnknow) then
|
|
begin
|
|
writeln;
|
|
assert(false);
|
|
end;
|
|
}
|
|
end;
|
|
|
|
function GetDepType(src:TsrRegNode):TsrDataType;
|
|
var
|
|
node:TDependenceNode;
|
|
pReg:TsrRegNode;
|
|
pLine:TspirvOp;
|
|
|
|
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.FirstDependence;
|
|
//
|
|
While (node<>nil) do
|
|
begin
|
|
if node.pNode.IsType(ntReg) then
|
|
begin
|
|
pReg:=node.pNode.specialize 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.specialize AsType<ntOp>;
|
|
|
|
if (classif_rw_op(pLine.OpId) and 2)<>0 then
|
|
begin
|
|
//ignore?
|
|
end else
|
|
begin
|
|
if CmpType(Result,src.dtype) then Exit;
|
|
end;
|
|
|
|
end;
|
|
//
|
|
node:=src.NextDependence(node);
|
|
end;
|
|
end;
|
|
|
|
function ResolveWeak(new:TsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
begin
|
|
Result:=0;
|
|
While (new<>nil) do
|
|
begin
|
|
|
|
if new.dweak then
|
|
begin
|
|
dtype:=GetDepType(new);
|
|
if (dtype<>dtUnknow) then
|
|
begin
|
|
if (new.dtype<>dtype) then
|
|
begin
|
|
new.dtype:=dtype;
|
|
new.dweak:=False;
|
|
Inc(Result);
|
|
end else
|
|
begin
|
|
new.dweak:=False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
new:=new.AsReg; //next
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegWResolve(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
begin
|
|
Result:=0;
|
|
if (node=nil) then Exit;
|
|
Result:=Result+ResolveWeak(node);
|
|
end;
|
|
|
|
function TSprvEmit_post.RegTypecast(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
var
|
|
old:TsrRegNode;
|
|
cst:TsrConst;
|
|
dtype:TsrDataType;
|
|
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 else
|
|
if node.pWriter.IsType(ntConst) then
|
|
begin
|
|
cst:=node.pWriter.specialize AsType<TsrConst>;
|
|
//
|
|
dtype:=LazyType3(old.dtype,node.dtype,cst.dtype);
|
|
//
|
|
if (dtype<>dtUnknow) then
|
|
if not CompareType(cst.dtype,dtype) then
|
|
begin
|
|
cst:=ConstList.Bitcast(dtype,cst);
|
|
old.pWriter:=cst;
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
{
|
|
if (old.dtype<>dtUnknow) and (node.dtype=dtUnknow) then
|
|
begin
|
|
writeln;
|
|
assert(false);
|
|
end;
|
|
}
|
|
end;
|
|
|
|
function TSprvEmit_post.RegSTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
dst:TsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
if (node.dtype=dtBool) then Exit;
|
|
dst:=pLine.pDst.specialize AsType<ntReg>;
|
|
if (dst=nil) then Exit;
|
|
|
|
dtype:=dst.dtype;
|
|
if (dtype<>dtUnknow) and
|
|
(node.dtype<>dtUnknow) and
|
|
(dtype<>node.dtype) then
|
|
begin
|
|
node:=BitcastList.FetchCast(dtype,node); //strict type
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.RegVTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer;
|
|
var
|
|
dtype:TsrDataType;
|
|
dst:TsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
dst:=pLine.pDst.specialize AsType<ntReg>;
|
|
if (dst=nil) then Exit;
|
|
|
|
dtype:=dst.dtype.Child;
|
|
if (dtype<>dtUnknow) and
|
|
(node.dtype<>dtUnknow) and
|
|
(dtype<>node.dtype) then
|
|
begin
|
|
node:=BitcastList.FetchCast(dtype,node); //strict type
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
{
|
|
function TSprvEmit_post.NodeOpSameOp(node:TspirvOp):Integer;
|
|
var
|
|
tmp:TspirvOp;
|
|
dst,src:TsrRegNode;
|
|
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:TspirvOp):Integer;
|
|
begin
|
|
Result:=0;
|
|
if not node.pDst.IsType(ntReg) then Exit; //is reg
|
|
|
|
Case node.OpId of
|
|
Op.OpBitFieldSExtract ,
|
|
Op.OpBitFieldUExtract :Result:=EnumFirstReg(@RegSTStrict,node);
|
|
Op.OpSelect :Result:=EnumLineRegs(@RegSTStrict,node);
|
|
Op.OpIAddCarry ,
|
|
Op.OpISubBorrow ,
|
|
Op.OpUMulExtended ,
|
|
Op.OpSMulExtended ,
|
|
Op.OpCompositeConstruct:Result:=EnumLineRegs(@RegVTStrict,node);
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
|
|
//
|
|
|
|
function TSprvEmit_post.OnOpStep1(node:TspirvOp):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:TspirvOp):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:TspirvOp):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:TspirvOp):Integer; //forward
|
|
begin
|
|
Result:=0;
|
|
|
|
{
|
|
//prior
|
|
if node.is_post then
|
|
begin
|
|
Result:=Result+EnumLineRegs(@RegVResolve,node);
|
|
Exit;
|
|
end;
|
|
}
|
|
|
|
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:TspirvOp):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:TspirvOp):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:TspirvOp):Integer; //backward
|
|
begin
|
|
Result:=0;
|
|
|
|
if node.is_cleared then
|
|
begin
|
|
//
|
|
if (node.read_count<>0) then
|
|
if not node.is_force then
|
|
begin
|
|
Assert(false,'Wrong read_count on:'+OpGetStrDebug(node));
|
|
end;
|
|
//
|
|
node.Remove;
|
|
Inc(Result);
|
|
end else
|
|
if node.can_clear then
|
|
begin
|
|
node.Clear;
|
|
node.Remove;
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnDecorate(node:TspirvOp):Integer;
|
|
var
|
|
r:TsrRegNode;
|
|
begin
|
|
Result:=0;
|
|
|
|
case node.OpId of
|
|
Op.OpFAdd,
|
|
Op.OpFSub,
|
|
Op.OpFMul,
|
|
Op.OpFDiv,
|
|
Op.OpFRem,
|
|
Op.OpFMod:
|
|
if (node.pDst<>nil) then
|
|
begin
|
|
DecorateList.OpDecorate(node.pDst,Decoration.NoContraction,0);
|
|
end;
|
|
Op.OpImageQuerySizeLod,
|
|
Op.OpImageQueryLod:
|
|
begin
|
|
AddCapability(Capability.ImageQuery);
|
|
end;
|
|
Op.OpGroupNonUniformShuffle:
|
|
begin
|
|
//upgrade version to 1.3
|
|
Config.UpgradeVersion($10300);
|
|
AddCapability(Capability.GroupNonUniformShuffle);
|
|
end;
|
|
Op.OpGroupNonUniformQuadBroadcast:
|
|
begin
|
|
r:=node.ParamNode(2).Value;
|
|
r:=RegDown(r);
|
|
//
|
|
if r.is_const then
|
|
begin
|
|
//upgrade version to 1.3
|
|
Config.UpgradeVersion($10300);
|
|
end else
|
|
begin
|
|
//upgrade version to 1.5
|
|
Config.UpgradeVersion($10500);
|
|
end;
|
|
//
|
|
AddCapability(Capability.GroupNonUniformQuad);
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.PostFuncAnalize:Integer;
|
|
label
|
|
_pass;
|
|
var
|
|
pFunc:TSpirvFunc;
|
|
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);
|
|
|
|
_pass:
|
|
|
|
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+PostAllocField;
|
|
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;
|
|
|
|
if data_layout then
|
|
begin
|
|
Result:=Result+PostAllocBuffer;
|
|
end;
|
|
|
|
//UpdateRegType OpLoad/OpStore
|
|
DataLayoutList.EnumChain(@OnChainUpdate);
|
|
PrivateList.Post;
|
|
|
|
if data_layout then
|
|
begin
|
|
OutputList.Post;
|
|
end;
|
|
|
|
{
|
|
//pass agian
|
|
if data_layout then
|
|
begin
|
|
data_layout:=false;
|
|
goto _pass;
|
|
end;
|
|
}
|
|
|
|
repeat //OnOpStep6 Typecast
|
|
i:=EnumBlockOpBackward(@OnOpStep6,pFunc.pTop);
|
|
if (i=0) then Break;
|
|
Result:=Result+i;
|
|
until false;
|
|
|
|
//pass agian
|
|
if data_layout or (i<>0) then
|
|
begin
|
|
data_layout:=false;
|
|
goto _pass;
|
|
end;
|
|
|
|
PrivateList.RemoveAllStore;
|
|
|
|
Result:=Result+EnumBlockOpBackward(@OnOpStep7,pFunc.pTop); //OnOpStep7 Remove Lines
|
|
|
|
EnumBlockOpForward(@OnDecorate,pFunc.pTop); //NoContraction
|
|
|
|
pFunc:=pFunc.Prev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainUpdate(node:TsrChain):Integer;
|
|
var
|
|
pField:TsrField;
|
|
begin
|
|
Result:=0;
|
|
//
|
|
pField:=node.pField;
|
|
if (pField<>nil) then
|
|
if (pField.Fdtype<>dtUnknow) then
|
|
if (node.dtype=dtUnknow) then
|
|
begin
|
|
node.dtype:=pField.Fdtype; //update type
|
|
end;
|
|
//
|
|
node.UpdateRegType;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostAllocField:Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
DataLayoutList.AllocID;
|
|
|
|
Result:=Result+DataLayoutList.EnumChain(@OnChainField);
|
|
end;
|
|
|
|
function TSprvEmit_post.PostAllocBuffer:Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
BufferList.ApplyBufferType;
|
|
BufferList.AlignOffset;
|
|
BufferList.FillSpace;
|
|
BufferList.AllocID;
|
|
BufferList.EnumAllField(@OnFieldType);
|
|
|
|
Result:=Result+DataLayoutList.EnumChain(@OnChainAlloc);
|
|
end;
|
|
|
|
procedure TSprvEmit_post.ShiftIndex(pChain:TsrChain;const F:TFieldFetchValue;var _offset:PtrUint);
|
|
var
|
|
_stride,_count:PtrUint;
|
|
pIndex:TsrRegNode;
|
|
pLine:TsrNode;
|
|
begin
|
|
_offset:=_offset-F.pField.offset;
|
|
//stride relative
|
|
_stride:=F.pField.stride;
|
|
_count :=_offset div _stride;
|
|
_offset:=_offset mod _stride;
|
|
//
|
|
if (_count<>0) or (pChain.pIndex=nil) then
|
|
begin
|
|
//save
|
|
pChain.FUndoIndex :=pChain.pIndex;
|
|
pChain.FUndoOffset:=pChain.offset;
|
|
//shift
|
|
pIndex:=pChain.pIndex;
|
|
if (pIndex<>nil) then
|
|
begin
|
|
pLine :=pIndex.pLine;
|
|
pIndex:=OpIAddTo(pIndex,_count,@pLine);
|
|
end else
|
|
begin
|
|
pLine :=init_line;
|
|
pIndex:=NewImm_q(dtUint32,_count,pLine);
|
|
end;
|
|
pChain.pIndex:=pIndex;
|
|
pChain.stride:=_stride;
|
|
pChain.offset:=pChain.offset-(_count*_stride);
|
|
end;
|
|
end;
|
|
|
|
procedure UndoIndex(pChain:TsrChain);
|
|
begin
|
|
if (pChain.FUndoIndex<>nil) then
|
|
begin
|
|
//undo
|
|
pChain.pIndex:=pChain.FUndoIndex;
|
|
pChain.offset:=pChain.FUndoOffset;
|
|
//clear
|
|
pChain.FUndoIndex :=nil;
|
|
pChain.FUndoOffset:=0;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.FetchField(pChain:TsrChain):TsrField;
|
|
label
|
|
_start,
|
|
_resolve,
|
|
_exit;
|
|
var
|
|
buf:TsrBuffer;
|
|
F:TFieldFetchValue;
|
|
_offset:PtrUint;
|
|
dtype:TsrDataType;
|
|
|
|
max:DWORD;
|
|
begin
|
|
buf:=nil;
|
|
|
|
_start:
|
|
|
|
dtype:=pChain.dtype;
|
|
|
|
if (buf=nil) then
|
|
begin
|
|
buf:=BufferList.Fetch(pChain.parent,0,pChain.Flags.GLC,pChain.Flags.SLC);
|
|
end else
|
|
begin
|
|
buf:=BufferList.NextAlias(buf,pChain.Flags.GLC,pChain.Flags.SLC);
|
|
end;
|
|
|
|
UndoIndex(pChain);
|
|
_offset:=pChain.offset;
|
|
|
|
if (pChain.pIndex<>nil) then
|
|
begin
|
|
//TODO: interval analize
|
|
|
|
if pChain.Parent.IsLocalDataShare or
|
|
pChain.Parent.IsGlobalDataShare then
|
|
begin
|
|
//fixed to 64KB
|
|
|
|
//FLDS_SIZE
|
|
|
|
max:=0;
|
|
case pChain.Parent.key.rtype of
|
|
rtLDS:
|
|
begin
|
|
max:=32*1024;
|
|
if (max>FLDS_SIZE) then max:=FLDS_SIZE;
|
|
end;
|
|
rtGDS:max:=64*1024;
|
|
end;
|
|
|
|
if (max=0) then
|
|
begin
|
|
Assert(false,'Access to LDS/GDS and the maximum is 0?');
|
|
end;
|
|
|
|
if (Align(_offset,pChain.stride)>max) then
|
|
begin
|
|
Assert(false,'LDS/GDS big addresing?');
|
|
end;
|
|
|
|
Assert(pChain.stride<>0);
|
|
F:=buf.FTop.FetchArray(_offset,(max-_offset),pChain.stride);
|
|
end else
|
|
begin
|
|
Assert(pChain.stride<>0);
|
|
F:=buf.FTop.FetchRuntimeArray(_offset,pChain.stride);
|
|
end;
|
|
|
|
goto _resolve;
|
|
end else
|
|
begin
|
|
F.pField:=buf.FTop;
|
|
end;
|
|
|
|
repeat
|
|
|
|
F:=F.pField.FetchValue(_offset,pChain.size,dtype,pChain.dweak);
|
|
|
|
_resolve:
|
|
Case F.fValue of
|
|
frNotFit :goto _start; //next alias
|
|
frIdent :goto _exit;
|
|
frVectorAsValue:goto _exit;
|
|
frValueInVector:
|
|
begin
|
|
_offset:=_offset-F.pField.offset;
|
|
//patch dtype
|
|
dtype:=F.pField.Fdtype.Child;
|
|
end;
|
|
frValueInArray :
|
|
begin
|
|
ShiftIndex(pChain,F,_offset);
|
|
end;
|
|
end;
|
|
|
|
until false;
|
|
|
|
_exit:
|
|
|
|
Result:=F.pField;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainField(node:TsrChain):Integer;
|
|
var
|
|
pField:TsrField;
|
|
begin
|
|
Result:=1;
|
|
//Writeln('OnChainsField:',dtype,':',node^.key.offset);
|
|
pField:=FetchField(node);
|
|
Assert(pField<>nil);
|
|
node.pField :=pField; //save link
|
|
node.dtype :=pField.Fdtype; //update type
|
|
node.pBuffer:=pField.pBuffer; //save buffer
|
|
end;
|
|
|
|
procedure TSprvEmit_post.OnFieldType(node:TsrField);
|
|
var
|
|
count:PtrUint;
|
|
|
|
items:PPsrType;
|
|
sType,vType:TsrType;
|
|
|
|
child:TsrField;
|
|
begin
|
|
if (node.vType<>nil) then Exit;
|
|
|
|
if (node.Fdtype in [dtTypeStruct,dtTypeArray,dtTypeRuntimeArray]) then
|
|
begin
|
|
if node.IsStructNotUsed then
|
|
begin
|
|
child:=node.First;
|
|
Assert(child<>nil);
|
|
Assert(child.vType<>nil);
|
|
sType:=child.vType;
|
|
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.vType<>nil);
|
|
items[count]:=child.vType;
|
|
Inc(count);
|
|
child:=node.Next(child);
|
|
end;
|
|
|
|
if node.IsTop then
|
|
begin
|
|
//on top level stride is unknow
|
|
sType:=TypeList.InsertStruct(count,items,False,node.Size); //unique
|
|
end else
|
|
begin
|
|
sType:=TypeList.FetchStruct (count,items,False,node.stride);
|
|
end;
|
|
|
|
end;
|
|
|
|
Case node.Fdtype of
|
|
dtTypeArray:
|
|
begin
|
|
count:=node.count;
|
|
vType:=TypeList.FetchArray(sType,count);
|
|
end;
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
vType:=TypeList.FetchRuntimeArray(sType);
|
|
end;
|
|
else
|
|
begin
|
|
vType:=sType;
|
|
end;
|
|
end;
|
|
|
|
node.sType:=sType;
|
|
node.vType:=vType;
|
|
|
|
if node.IsTop then
|
|
begin
|
|
//Alloc Type Var
|
|
node.pBuffer.pType:=vType;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
node.sType:=nil;
|
|
node.vType:=TypeList.Fetch(node.Fdtype);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TSprvEmit_post.AdjustMaxSize(tbuf:TsrBuffer);
|
|
var
|
|
node:TsrBuffer;
|
|
max,size:Ptruint;
|
|
begin
|
|
node:=tbuf;
|
|
max:=0;
|
|
while (node<>nil) do
|
|
begin
|
|
size:=node.GetSize;
|
|
if (size>max) then
|
|
begin
|
|
max:=size;
|
|
end;
|
|
//
|
|
node:=node.pNextAlias;
|
|
end;
|
|
//
|
|
size:=tbuf.GetSize;
|
|
if (max>size) then
|
|
begin
|
|
if (max>=High(WORD)) then
|
|
begin
|
|
//runtime array fill
|
|
tbuf.FTop.FetchRuntimeArray(size,4);
|
|
end else
|
|
begin
|
|
//fixed fill
|
|
tbuf.FTop.FillNode(size,max-size);
|
|
end;
|
|
//
|
|
tbuf.EnumAllField(@OnFieldType);
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.LinkBitcast(pBuffer:TsrBuffer):TsrNode;
|
|
var
|
|
pLine:TspirvOp;
|
|
|
|
tbuf:TsrBuffer;
|
|
tref:TsrNode;
|
|
pType:TsrType;
|
|
begin
|
|
Result:=pBuffer.pVar; //direct
|
|
|
|
if pBuffer.pLayout.UseBitcast then
|
|
if pBuffer.Flags.Aliased then
|
|
if (pBuffer.AliasId<>0) then
|
|
begin
|
|
pLine:=init_line;
|
|
|
|
//zero alias
|
|
tbuf:=BufferList.Fetch(pBuffer.pLayout,0,False,False);
|
|
|
|
tref:=tbuf.tRef;
|
|
if (tref=nil) then
|
|
begin
|
|
//calc max size
|
|
AdjustMaxSize(tbuf);
|
|
|
|
Assert(tbuf.FTop.vType<>nil);
|
|
Assert(tbuf.pVar<>nil);
|
|
|
|
//OpAccessChain storage class link
|
|
tref:=specialize New<TsrChain>;
|
|
TsrChain(tref).pBuffer:=tbuf;
|
|
|
|
//self ref
|
|
pLine:=OpAccessChain(pLine,tbuf.FTop.vType,tref,tbuf.pVar);
|
|
//cache
|
|
tbuf.tRef:=tref;
|
|
tbuf.Flags.Bitcast:=True;
|
|
end;
|
|
|
|
Result:=pBuffer.tRef;
|
|
if (Result=nil) then
|
|
begin
|
|
Assert(pBuffer.FTop.vType<>nil);
|
|
Assert(pBuffer.pVar<>nil);
|
|
|
|
//OpAccessChain storage class link
|
|
Result:=specialize New<TsrChain>;
|
|
TsrChain(Result).pBuffer:=pBuffer;
|
|
|
|
//bitcast pointer to this alias
|
|
pType:=TypeList.FetchPointer(pBuffer.FTop.vType,pBuffer.pVar.GetStorageClass);
|
|
pLine:=OpBitcast(pLine,pType,Result,tref);
|
|
//cache
|
|
pBuffer.tRef:=Result;
|
|
pBuffer.Flags.Bitcast:=True;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.OnChainAlloc(node:TsrChain):Integer;
|
|
var
|
|
pLine:TspirvOp;
|
|
pIndex:TsrRegNode;
|
|
pReg:TsrRegNode;
|
|
pField:TsrField;
|
|
Parent:TsrField;
|
|
src:TsrNode;
|
|
pParam:POpParamNode;
|
|
begin
|
|
Result:=1;
|
|
|
|
pField:=node.pField;
|
|
Assert(pField<>nil);
|
|
|
|
//Make Bitcast type or directly
|
|
src:=LinkBitcast(pField.pBuffer);
|
|
Assert(src<>nil);
|
|
//
|
|
|
|
//get line after LinkBitcast
|
|
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;
|
|
|
|
//restore
|
|
pIndex:=node.pIndex;
|
|
|
|
pLine:=OpAccessChain(pLine,pField.vType,node,src);
|
|
|
|
pParam:=pLine.ParamLast;
|
|
repeat
|
|
|
|
Parent:=pField.pParent;
|
|
if (Parent<>nil) then
|
|
Case Parent.Fdtype of
|
|
dtTypeStruct:
|
|
begin
|
|
pReg:=NewImm_i(dtUint32,pField.FID,pLine);
|
|
pLine.AddParamAfter(pParam,pReg);
|
|
end;
|
|
dtTypeArray,
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
if not Parent.IsStructNotUsed then
|
|
begin
|
|
pReg:=NewImm_i(dtUint32,pField.FID,pLine);
|
|
pLine.AddParamAfter(pParam,pReg);
|
|
end;
|
|
Assert(pIndex<>nil);
|
|
pLine.AddParamAfter(pParam,pIndex);
|
|
end;
|
|
else
|
|
if Parent.Fdtype.isVector then
|
|
begin
|
|
pReg:=NewImm_i(dtUint32,pField.FID,pLine);
|
|
pLine.AddParamAfter(pParam,pReg);
|
|
end;
|
|
end;
|
|
|
|
pField:=Parent;
|
|
until (pField=nil);
|
|
|
|
end;
|
|
|
|
function TSprvEmit_post.PostConstAnalize:Integer;
|
|
var
|
|
node:TsrConst;
|
|
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:TsrVariable;
|
|
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();
|
|
end;
|
|
node:=node.Prev;
|
|
end;
|
|
end;
|
|
|
|
function TSprvEmit_post.PostTypeAnalize:Integer;
|
|
var
|
|
node:TsrType;
|
|
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.
|
|
|