FPPS4/spirv/emit_post_op.pas

3048 lines
61 KiB
Plaintext

unit emit_post_op;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
bittype,
Half16,
spirv,
srCFGLabel,
srNode,
srType,
srTypes,
srRefId,
srConst,
srReg,
srPrivate,
srOp,
srOpInternal,
srOpUtils,
emit_fetch;
type
TEmitPostOp=class(TEmitFetch)
function PostForward1(node:TSpirvOp):Integer;
function PostForward2(node:TSpirvOp):Integer;
//
function OpConvert1(node:TSpirvOp):Integer;
function OnCompositeExtract1(node:TSpirvOp):Integer;
function OnFDiv1(node:TSpirvOp):Integer;
function OnIAdd1(node:TSpirvOp):Integer;
function OnISub1(node:TSpirvOp):Integer;
function OnShr1(node:TSpirvOp):Integer;
function _OnShr_ext1(node,pOp:TSpirvOp;pShrVal:TsrConst):Integer;
function _OnShr_ext_and(node:TSpirvOp;pShrVal,pAndVal:TsrConst):Integer;
function _OnShr_ext_add(node,pOp0,pOp1:TSpirvOp;pShrVal:TsrConst):Integer;
function OnAbsDiff1(node:TSpirvOp):Integer;
function OnWQM32__1(node:TSpirvOp):Integer;
function OnPackOfs1(node:TSpirvOp):Integer;
function _Fetch_PackAnc(node:TsrRegNode;index,count:Byte):TsrRegNode;
function OnBFE_32_1(node:TSpirvOp):Integer;
function OnBFIB32_1(node:TSpirvOp):Integer;
function OnMakeCub1(node:TSpirvOp):Integer;
//
function OnBitwiseAnd1(node:TSpirvOp):Integer;
function OnLogicalAnd1(node:TSpirvOp):Integer;
function OnBitwiseOr1(node:TSpirvOp):Integer;
function OnLogicalOr1(node:TSpirvOp):Integer;
function OnNot1(node:TSpirvOp):Integer;
function OnLogicalNot1(node:TSpirvOp):Integer;
function OnBranchConditional1(node:TSpirvOp):Integer;
//
function OpBitCount1(node:TSpirvOp):Integer;
function OpBitReverse1(node:TSpirvOp):Integer;
//
function OnSelect1(node:TSpirvOp):Integer;
//
procedure MakeVecConst(rtype:TsrDataType;dst:TsrRegNode;src:PPsrRegNode);
procedure MakeVecOne(dst:TsrRegNode;src:PPsrRegNode);
function MakeVecComp(pLine:TSpirvOp;rtype:TsrDataType;dst:TsrRegNode;src:PPsrRegNode):TSpirvOp;
//
function OnMakeVec2(node:TSpirvOp):Integer;
function OnReturn_2(node:TSpirvOp):Integer;
function OnMakeExp2(node:TSpirvOp):Integer;
function OnIAddExt2(node:TSpirvOp):Integer;
function OnISubExt2(node:TSpirvOp):Integer;
function OnPackAnc2(node:TSpirvOp):Integer;
//
function OnCUBEID2(node:TSpirvOp):Integer;
function OnCUBESC2(node:TSpirvOp):Integer;
function OnCUBETC2(node:TSpirvOp):Integer;
function OnCUBEMA2(node:TSpirvOp):Integer;
end;
implementation
function TEmitPostOp.PostForward1(node:TSpirvOp):Integer;
begin
Result:=0;
Case node.OpId of
Op.OpFConvert,
Op.OpConvertFToU,
Op.OpConvertFToS,
Op.OpConvertSToF,
Op.OpConvertUToF :Result:=OpConvert1(node);
Op.OpCompositeExtract :Result:=OnCompositeExtract1(node);
Op.OpFDiv :Result:=OnFDiv1(node);
Op.OpIAdd :Result:=OnIAdd1(node);
Op.OpISub :Result:=OnISub1(node);
Op.OpShiftRightLogical,
Op.OpShiftRightArithmetic:Result:=OnShr1(node);
srOpInternal.OpAbsDiff :Result:=OnAbsDiff1(node);
srOpInternal.OpWQM32 :Result:=OnWQM32__1(node);
srOpInternal.OpPackOfs :Result:=OnPackOfs1(node);
srOpInternal.OpBFE_32 :Result:=OnBFE_32_1(node);
srOpInternal.OpBFIB32 :Result:=OnBFIB32_1(node);
srOpInternal.OpMakeCub :Result:=OnMakeCub1(node);
Op.OpSelect :Result:=OnSelect1(node);
Op.OpBitwiseAnd :Result:=OnBitwiseAnd1(node);
Op.OpLogicalAnd :Result:=OnLogicalAnd1(node);
Op.OpBitwiseOr :Result:=OnBitwiseOr1(node);
Op.OpLogicalOr :Result:=OnLogicalOr1(node);
Op.OpNot :Result:=OnNot1(node);
Op.OpLogicalNot :Result:=OnLogicalNot1(node);
Op.OpBranchConditional:Result:=OnBranchConditional1(node);
Op.OpBitCount :Result:=OpBitCount1(node);
Op.OpBitReverse :Result:=OpBitReverse1(node);
else;
end;
end;
function TEmitPostOp.PostForward2(node:TSpirvOp):Integer;
begin
Result:=0;
Case node.OpId of
srOpInternal.OpIAddExt:Result:=OnIAddExt2(node);
srOpInternal.OpISubExt:Result:=OnISubExt2(node);
srOpInternal.OpMakeVec:Result:=OnMakeVec2(node);
srOpInternal.OpPackAnc:Result:=OnPackAnc2(node);
Op.OpReturn:Result:=OnReturn_2(node);
OpMakeExp :Result:=OnMakeExp2(node);
OpCUBEID:OnCUBEID2(node);
OpCUBESC:OnCUBESC2(node);
OpCUBETC:OnCUBETC2(node);
OpCUBEMA:OnCUBEMA2(node);
srOpInternal.OpMakeCub:Assert(false,'OpMakeCub');
end;
end;
function _classif_const(dtype:TsrDataType;value:QWORD):Integer;
begin
if (value=0) then //always false
begin
Result:=0;
end else
if (value=dtype.High) then //always true
begin
Result:=1;
end else
begin
Result:=-1;
end;
end;
function _classif_const(p:TsrConst):Integer;
begin
Result:=_classif_const(p.dtype,p.GetData);
end;
function BinType(t:TsrDataType):TsrDataType;
begin
Case t of
dtBool :Result:=dtBool;
dtInt32,
dtUint32:Result:=dtUint32;
else
Result:=dtUnknow;
end;
end;
function TEmitPostOp.OnBitwiseAnd1(node:TSpirvOp):Integer;
var
dtype:TsrDataType;
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetOpType(OpId:DWORD;dtype:TsrDataType);
begin
Result:=0;
if (node.OpId<>OpId) then
begin
node.OpId:=OpId;
Inc(Result);
end;
//
dst:=node.pDst.specialize AsType<ntReg>;
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
//
dtype:=dst.dtype;
if (dtype=dtBool) then dst.dweak:=False;
node.pType:=TypeList.Fetch(dtype);
end;
procedure _SetType(dtype:TsrDataType);
begin
dst:=node.pDst.specialize AsType<ntReg>;
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
//
dtype:=dst.dtype;
//if (dtype=dtBool) then dst.dweak:=False;
node.pType:=TypeList.Fetch(dtype);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if src[0].is_const and src[1].is_const then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
dtype:=LazyType3(dst.dtype,src[0].dtype,src[1].dtype);
dtype:=LazyType2(dtype,dtUint32);
_SetConst(dtype,data[0] and data[1]);
Exit;
end;
if (dst.is_bool) or ((src[0].is_bool_or_const_bool) and (src[1].is_bool_or_const_bool)) then
begin
if (src[0].is_const) then
begin
Case src[0].AsConst.AsBool of
True :_SetReg(src[1]);
False:_SetConst(dtBool,0);
end;
Exit;
end;
if (src[1].is_const) then
begin
Case src[1].AsConst.AsBool of
True :_SetReg(src[0]);
False:_SetConst(dtBool,0);
end;
Exit;
end;
_SetOpType(Op.OpLogicalAnd,dtBool);
end else
begin
dtype:=LazyType3(BinType(dst.dtype),BinType(src[0].dtype),BinType(src[1].dtype));
dtype:=LazyType2(dtype,dtUint32);
if (src[0].is_const) then
begin
case _classif_const(src[0].AsConst) of
0:_SetConst(dtype,0); //always false
1:_SetReg(src[1]); //always true
end;
end;
if (src[1].is_const) then
begin
case _classif_const(src[1].AsConst) of
0:_SetConst(dtype,0); //always false
1:_SetReg(src[0]); //always true
end;
end;
if (Result<>0) then Exit; //_SetConst/_SetReg
_SetType(dtype);
end;
Result:=Result+PrepTypeParam(node.ParamNode(0),dst.dtype);
Result:=Result+PrepTypeParam(node.ParamNode(1),dst.dtype);
end;
Function _FindNest_LAnd(node,src:TsrRegNode):Boolean;
var
p:TSpirvOp;
tmp:TsrRegNode;
begin
Result:=False;
if (node=nil) or (src=nil) then Exit;
repeat
p:=node.pWriter.specialize AsType<ntOp>;
if (p<>nil) then
if (p.OpId=Op.OpLogicalAnd) then
begin
tmp:=RegDown(p.ParamNode(0).AsReg);
if (tmp=src) then Exit(True);
Result:=_FindNest_LAnd(tmp,src); //recursion
if Result then Exit(True);
tmp:=RegDown(p.ParamNode(1).AsReg);
if (tmp=src) then Exit(True);
node:=tmp;
Continue; //cycle
end;
Exit;
until false;
end;
function TEmitPostOp.OnLogicalAnd1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
Assert(dst.dtype=dtBool);
if src[0].is_const and src[1].is_const then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
_SetConst(dtBool,data[0] and data[1]);
Exit;
end;
if (src[0].is_const) then
begin
Case src[0].AsConst.AsBool of
True :_SetReg(src[1]);
False:_SetConst(dtBool,0);
end;
Exit;
end;
if (src[1].is_const) then
begin
Case src[1].AsConst.AsBool of
True :_SetReg(src[0]);
False:_SetConst(dtBool,0);
end;
Exit;
end;
if _FindNest_LAnd(src[1],src[0]) then //Find src[0] in src[1]
begin
_SetReg(src[1]);
Exit;
end;
if _FindNest_LAnd(src[0],src[1]) then //Find src[1] in src[0]
begin
_SetReg(src[0]);
Exit;
end;
Result:=Result+PrepTypeParam(node.ParamNode(0),dtBool);
Result:=Result+PrepTypeParam(node.ParamNode(1),dtBool);
end;
function _Fetch_BitwiseOr_Const(node:TsrRegNode):TsrConst;
var
pLine:TSpirvOp;
src:array[0..1] of TsrRegNode;
begin
Result:=nil;
if (node=nil) then Exit;
pLine:=node.pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit;
if (pLine.OpId<>Op.OpBitwiseOr) then Exit;
src[0]:=RegDown(pLine.ParamNode(0).AsReg);
src[1]:=RegDown(pLine.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
if src[0].is_const and src[1].is_const then Exit;
if src[0].is_const then
begin
Result:=src[0].AsConst;
end else
if src[1].is_const then
begin
Result:=src[1].AsConst;
end;
end;
function _Fetch_BitwiseOr_Value(node:TsrRegNode):TsrRegNode;
var
pLine:TSpirvOp;
src:array[0..1] of TsrRegNode;
begin
Result:=nil;
if (node=nil) then Exit;
pLine:=node.pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit;
if (pLine.OpId<>Op.OpBitwiseOr) then Exit;
src[0]:=RegDown(pLine.ParamNode(0).AsReg);
src[1]:=RegDown(pLine.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
if src[0].is_const and src[1].is_const then Exit;
if src[0].is_const then
begin
Result:=src[1];
end else
if src[1].is_const then
begin
Result:=src[0];
end;
end;
//
function TEmitPostOp.OnBitwiseOr1(node:TSpirvOp):Integer;
var
dtype:TsrDataType;
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
pConst:TsrConst;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetOpType(OpId:DWORD;dtype:TsrDataType);
begin
Result:=0;
if (node.OpId<>OpId) then
begin
node.OpId:=OpId;
Inc(Result);
end;
//
dst:=node.pDst.specialize AsType<ntReg>;
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
//
dtype:=dst.dtype;
if (dtype=dtBool) then dst.dweak:=False;
node.pType:=TypeList.Fetch(dtype);
end;
procedure _SetType(dtype:TsrDataType);
begin
dst:=node.pDst.specialize AsType<ntReg>;
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
//
dtype:=dst.dtype;
//if (dtype=dtBool) then dst.dweak:=False;
node.pType:=TypeList.Fetch(dtype);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if src[0].is_const and src[1].is_const then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
dtype:=LazyType3(dst.dtype,src[0].dtype,src[1].dtype);
dtype:=LazyType2(dtype,dtUint32);
_SetConst(dtype,data[0] or data[1]);
Exit;
end;
if (dst.is_bool) or ((src[0].is_bool_or_const_bool) and (src[1].is_bool_or_const_bool)) then
begin
if (src[0].is_const) then
begin
Case src[0].AsConst.AsBool of
True :_SetConst(dtBool,1);
False:_SetReg(src[1]);
end;
Exit;
end;
if (src[1].is_const) then
begin
Case src[1].AsConst.AsBool of
True :_SetConst(dtBool,1);
False:_SetReg(src[0]);
end;
Exit;
end;
_SetOpType(Op.OpLogicalOr,dtBool);
Result:=Result+PrepTypeParam(node.ParamNode(0),dst.dtype);
Result:=Result+PrepTypeParam(node.ParamNode(1),dst.dtype);
Exit;
end;
//
pConst:=_Fetch_BitwiseOr_Const(src[0]);
if (pConst<>nil) and src[1].is_const then
begin
//need a const calc
data[0]:= pConst.GetData;
data[1]:=src[1].AsConst.GetData;
dtype:=LazyType3(dst.dtype,src[0].dtype,src[1].dtype);
src[1]:=NewImm_q(dtype,data[0] or data[1],node);
src[0]:=_Fetch_BitwiseOr_Value(src[0]);
Assert(src[0]<>nil);
node.ParamNode(0).Value:=src[0];
node.ParamNode(1).Value:=src[1];
end;
//
pConst:=_Fetch_BitwiseOr_Const(src[1]);
if src[0].is_const and (pConst<>nil) then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:= pConst.GetData;
dtype:=LazyType3(dst.dtype,src[0].dtype,src[1].dtype);
src[0]:=NewImm_q(dtype,data[0] or data[1],node);
src[1]:=_Fetch_BitwiseOr_Value(src[1]);
Assert(src[1]<>nil);
node.ParamNode(0).Value:=src[0];
node.ParamNode(1).Value:=src[1];
end;
//else
begin
dtype:=LazyType3(BinType(dst.dtype),BinType(src[0].dtype),BinType(src[1].dtype));
dtype:=LazyType2(dtype,dtUint32);
if (src[0].is_const) then
begin
case _classif_const(src[0].AsConst) of
0:_SetReg(src[1]);
1:_SetConst(dtype,dtype.High); //is high
end;
end;
if (src[1].is_const) then
begin
case _classif_const(src[1].AsConst) of
0:_SetReg(src[0]);
1:_SetConst(dtype,dtype.High); //is high
end;
end;
if (Result<>0) then Exit; //_SetConst/_SetReg
_SetType(dtype);
end;
Result:=Result+PrepTypeParam(node.ParamNode(0),dst.dtype);
Result:=Result+PrepTypeParam(node.ParamNode(1),dst.dtype);
end;
function TEmitPostOp.OnLogicalOr1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
Assert(dst.dtype=dtBool);
if src[0].is_const and src[1].is_const then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
_SetConst(dtBool,data[0] or data[1]);
Exit;
end;
if (src[0].is_const) then
begin
Case src[0].AsConst.AsBool of
True :_SetConst(dtBool,1);
False:_SetReg(src[1]);
end;
Exit;
end;
if (src[1].is_const) then
begin
Case src[1].AsConst.AsBool of
True :_SetConst(dtBool,1);
False:_SetReg(src[0]);
end;
Exit;
end;
Result:=Result+PrepTypeParam(node.ParamNode(0),dtBool);
Result:=Result+PrepTypeParam(node.ParamNode(1),dtBool);
end;
function TEmitPostOp.OnNot1(node:TSpirvOp):Integer;
var
dtype:TsrDataType;
dst:TsrRegNode;
src:TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetOpType(OpId:DWORD;dtype:TsrDataType);
begin
Result:=0;
if (node.OpId<>OpId) then
begin
node.OpId:=OpId;
Inc(Result);
end;
//
dst:=node.pDst.specialize AsType<ntReg>;
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
//
dtype:=dst.dtype;
if (dtype=dtBool) then dst.dweak:=False;
node.pType:=TypeList.Fetch(dtype);
end;
procedure _SetType(dtype:TsrDataType);
begin
dst:=node.pDst.specialize AsType<ntReg>;
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
//
dtype:=dst.dtype;
//if (dtype=dtBool) then dst.dweak:=False;
node.pType:=TypeList.Fetch(dtype);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=RegDown(node.ParamNode(0).AsReg);
if (dst=nil) or (src=nil) then Exit;
if src.is_const then
begin
dtype:=LazyType2(dst.dtype,src.dtype);
dtype:=LazyType2(dtype,dtUint32);
//need a const calc
data[0]:=src.AsConst.GetData;
data[1]:=dtype.High;
_SetConst(dtype,(not data[0]) and data[1]);
Exit;
end;
if (dst.is_bool) or (src.is_bool_or_const_bool) then
begin
if (src.is_const) then
begin
Case src.AsConst.AsBool of
True :_SetConst(dtBool,0);
False:_SetConst(dtBool,1);
end;
Exit;
end;
_SetOpType(Op.OpLogicalNot,dtBool);
end else
begin
dtype:=LazyType2(BinType(dst.dtype),BinType(src.dtype));
dtype:=LazyType2(dtype,dtUint32);
_SetType(dtype);
end;
Result:=Result+PrepTypeParam(node.ParamNode(0),dst.dtype);
end;
function TEmitPostOp.OnLogicalNot1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
dst2:TsrRegNode;
srp:array[0..1] of TsrRegNode;
pop:TSpirvOp;
cmp:DWORD;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=RegDown(node.ParamNode(0).AsReg);
if (dst=nil) or (src=nil) then Exit;
Assert(dst.dtype=dtBool);
if (src.read_count>1) then Exit;
pop:=src.pWriter.specialize AsType<ntOp>;
if (pop=nil) then Exit;
cmp:=pop.OpId;
cmp:=get_inverse_not_cmp_op(cmp);
if (cmp=0) then Exit;
srp[0]:=pop.ParamNode(0).AsReg;
srp[1]:=pop.ParamNode(1).AsReg;
if (srp[0]=nil) or (srp[1]=nil) then Exit;
dst2:=NewReg(dtBool);
_Op2(pop,cmp,dst2,srp[0],srp[1]);
_SetReg(dst2);
end;
Procedure mark_not_used_branch_op(pBlock:TsrOpBlock);
var
node:TSpirvOp;
begin
node:=pBlock.First;
While (node<>nil) do
begin
if node.IsType(ntOp) then
begin
//
Case node.OpId of
Op.OpLabel,
Op.OpSelectionMerge,
Op.OpBranch,
Op.OpBranchConditional:node.mark_not_used(True);
else;
end;
//
end;
node:=node.Next;
end;
end;
procedure _restore(var vctx:TsrVolatileContext);
var
node:TsrVolatileNode;
V:TsrVolatile;
N:TsrRegNode;
begin
node:=vctx.FList.pHead;
while (node<>nil) do
begin
V:=TsrVolatile(node.V);
N:=TsrRegNode(node.N);
if (N.pWriter<>V) then
begin
Assert(false,'_restore:1');
end;
if (V.FBase=nil) then
begin
Assert(false,'_restore:2');
end;
//Preventing circular markings
V.mark_read(nil);
N.pWriter:=V.FBase;
N.pWriter.PrepType(ord(N.dtype));
V.mark_unread(nil);
//
node:=node.pNext;
end;
end;
function TEmitPostOp.OnBranchConditional1(node:TSpirvOp):Integer;
var
src,prv:TsrRegNode;
pOpNot:TSpirvOp;
pLabel:array[0..1] of TsrRefNode;
pCond:TsrOpBlock;
pMerg:TsrOpBlock;
cst :TsrConst;
begin
Result:=0;
src:=RegDown(node.ParamNode(0).AsReg);
if (src=nil) then Exit;
if (src.is_const) then
begin
cst:=src.AsConst;
if (cst<>nil) then
begin
pCond:=TsrOpBlock(node.Parent).FindUpCond;
if (pCond<>nil) then
if (pCond.pElse=nil) then //no else
if (RegDown(pCond.Cond.pReg)=src) then
if ((cst.AsBool=True) and (pCond.Cond.FNormalOrder=True )) or //if (true)
((cst.AsBool=False) and (pCond.Cond.FNormalOrder=False)) then //if (!false)
begin
//Remove the condition block
//Clear ref in BranchConditional
node.ParamNode(0).Value:=nil;
//Get merge block
pMerg:=pCond.Parent;
Assert(pMerg.Block.bType=btMerg);
//set type
pMerg.Block.bType:=btOther;
_restore(pCond.vctx);
//simplification of connections
//PrivateList.build_volatile_ctrue(pCond.pAfter,pCond.Regs.orig,pCond.Regs.prev,pCond.Regs.next);
//set type
pCond.Block.bType:=btOther;
//clear instructions
mark_not_used_branch_op(pMerg);
mark_not_used_branch_op(pCond);
Exit(1);
end;
end;
end;
pOpNot:=src.pWriter.specialize AsType<ntOp>;
if (pOpNot=nil) then Exit;
Case pOpNot.OpId of
Op.OpLogicalNot:;
else
Exit;
end;
prv:=pOpNot.ParamNode(0).AsReg;
if (prv=nil) then Exit;
node.ParamNode(0).Value:=prv; //set new
pLabel[0]:=node.ParamNode(1).Value.specialize AsType<ntRefId>; //read
pLabel[1]:=node.ParamNode(2).Value.specialize AsType<ntRefId>; //read
node.ParamNode(1).Value:=pLabel[1]; //swap
node.ParamNode(2).Value:=pLabel[0]; //swap
pCond:=TsrOpBlock(node.Parent).FindUpCond;
if (pCond<>nil) then
if (RegDown(pCond.Cond.pReg)=src) then
begin
//broken?
//set new
pCond.Cond.pReg:=prv;
//invert mark
pCond.Cond.FNormalOrder:=not pCond.Cond.FNormalOrder;
end;
Exit(1);
end;
function TEmitPostOp.OpBitCount1(node:TSpirvOp):Integer;
var
dst,src:TsrRegNode;
data:QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=RegDown(node.ParamNode(0).AsReg);
if (dst=nil) or (src=nil) then Exit;
if src.is_const then
begin
//need a const calc
data:=src.AsConst.GetData;
data:=PopCnt(data); //BitCount
_SetConst(dst.dtype,data);
Exit;
end;
end;
Function ReverseBits(src:QWORD;count:Byte):QWORD;
var
v:QWORD;
i:Byte;
begin
Result:=0;
Assert(count<>0);
dec(count);
For i:=0 to count do
begin
v:=((src shr i) and 1); //get
Result:=Result or (v shl (count-i)); //set
end;
end;
function TEmitPostOp.OpBitReverse1(node:TSpirvOp):Integer;
var
dst,src:TsrRegNode;
data:QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=RegDown(node.ParamNode(0).AsReg);
if (dst=nil) or (src=nil) then Exit;
if src.is_const then
begin
//need a const calc
data:=src.AsConst.GetData;
data:=ReverseBits(data,src.dtype.BitSize);
_SetConst(dst.dtype,data);
Exit;
end;
end;
function try_get_comp_bridge(var src:TsrRegNode):Integer; forward;
function TEmitPostOp.OpConvert1(node:TSpirvOp):Integer;
var
i:Int64;
dst,src,tmp:TsrRegNode;
pc:TsrConst;
pLine:TSpirvOp;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetConst_s(dtype:TsrDataType;value:Single);
begin
Assert(dtype=dtFloat32);
dst.pWriter:=NewImm_s(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
function minz(i:Int64):QWORD;
begin
if (i>0) then Result:=i else Result:=0;
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=RegDown(node.ParamNode(0).AsReg);
if (dst=nil) or (src=nil) then Exit;
tmp:=src;
While try_get_comp_bridge(tmp)<>0 do
begin
tmp:=RegDown(tmp);
end;
if (tmp<>src) then
begin
node.ParamNode(0).Value:=tmp;
src:=tmp;
Inc(Result);
end;
i:=0;
if src.is_const then
begin
pc:=src.AsConst;
Case node.OpId of
Op.OpFConvert:
case src.dtype of
dtFloat32:
case dst.dtype of
dtHalf16:_SetConst(dst.dtype,WORD(THalf16(pc.AsFloat32)));
else;
end;
dtHalf16:
case dst.dtype of
dtFloat32:_SetConst_s(dst.dtype,Single(pc.AsHalf16));
else;
end;
else;
end;
Op.OpConvertFToU:
case src.dtype of
dtFloat32:
if TryTruncInt64(pc.AsFloat32,i) then
begin
_SetConst(dst.dtype,minz(i));
end;
else;
end;
Op.OpConvertFToS:
case src.dtype of
dtFloat32:
if TryTruncInt64(pc.AsFloat32,i) then
begin
_SetConst(dst.dtype,i);
end;
else;
end;
Op.OpConvertSToF:
case src.dtype of
dtInt32 :_SetConst_s(dst.dtype,pc.AsInt32);
dtUint32:_SetConst_s(dst.dtype,pc.AsInt32);
dtInt64 :_SetConst_s(dst.dtype,pc.AsInt64);
dtUint64:_SetConst_s(dst.dtype,pc.AsInt64);
else;
end;
Op.OpConvertUToF:
case src.dtype of
dtInt32 :_SetConst_s(dst.dtype,pc.AsUint32);
dtUint32:_SetConst_s(dst.dtype,pc.AsUint32);
dtInt64 :_SetConst_s(dst.dtype,pc.AsUint64);
dtUint64:_SetConst_s(dst.dtype,pc.AsUint64);
else;
end;
end;
end else
begin
pLine:=src.pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit;
Case pLine.OpId of
Op.OpFConvert:
begin
tmp:=RegDown(pLine.ParamNode(0).AsReg);
Case node.OpId of
Op.OpFConvert:
if (tmp.dtype=dst.dtype) then
begin
_SetReg(tmp);
end;
else;
end;
end;
else;
end;
end;
end;
function TEmitPostOp.OnCompositeExtract1(node:TSpirvOp):Integer;
var
pc:TsrConst;
dst,org,src:TsrRegNode;
pos:PtrUint;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
org:=node.ParamNode(0).AsReg;
src:=RegDown(org);
if (dst=nil) or (src=nil) then Exit;
pos:=0;
if not node.ParamNode(1).TryGetValue(pos) then Exit;
if not src.is_const then Exit;
pc:=src.AsConst;
pc:=ConstList.Bitcast(org.dtype,pc);
if (pos>=pc.Count) then Exit;
pc:=pc.GetConst(pos);
if (pc=nil) then Exit;
dst.pWriter:=pc;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
{
function TEmitPostOp.OnSAbs(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst^.SetConst(FConsts.Fetch(dtype,value));
node^.OpId:=OpLinks; //mark remove
node^.dst:=Default(TOpParamSingle);
Inc(Result);
end;
begin
Result:=0;
dst:=node^.dst.pData;
src:=node^.Param(2).pData;
if src^.is_const then
begin
Case dst^.dtype of
dtInt32,
dtUint32:_SetConst(dtUint32,Abs(src^.AsConst^.AsInt));
dtInt64,
dtUint64:_SetConst(dtUint64,Abs(src^.AsConst^.AsInt64));
else;
end;
end;
end;
}
function TEmitPostOp.OnSelect1(node:TSpirvOp):Integer;
var
dtype:TsrDataType;
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
cst:array[0..1] of TsrConst;
pLine:TSpirvOp;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=node.ParamNode(1).AsReg;
src[1]:=node.ParamNode(2).AsReg;
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
cst[0]:=RegDown(src[0]).AsConst;
cst[1]:=RegDown(src[1]).AsConst;
if (cst[0]<>nil) and (cst[1]<>nil) then
begin
if (cst[0].GetData=cst[1].GetData) then
begin
_SetConst(dst.dtype,cst[0].GetData);
Exit;
end;
if (dst.dtype=dtBool) and
(cst[0].dtype=dtBool) and
(cst[1].dtype=dtBool) then
begin
if (cst[0].AsBool=True) and (cst[1].AsBool=False) then
begin
src[0]:=node.ParamNode(0).AsReg;
_SetReg(src[0]);
Exit;
end else
if (cst[0].AsBool=False) and (cst[1].AsBool=True) then
begin
src[0]:=node.ParamNode(0).AsReg;
pLine:=src[0].pLine;
src[1]:=OpNotTo(src[0],@pLine);
src[1].PrepType(ord(dtBool));
_SetReg(src[1]);
Exit;
end;
end;
end;
dtype:=LazyType3(dst.dtype,src[0].dtype,src[1].dtype);
if (dtype<>dtUnknow) and (node.pType.dtype<>dtype) then
begin
node.pType:=TypeList.Fetch(dtype);
if (node.pType.dtype=dtype) then
begin
Inc(Result);
end;
end;
if (dtype<>dtUnknow) and (dst.dtype<>dtype) then
begin
Result:=Result+PrepTypeDst(dst,dtype,False);
node.pDst:=dst;
end;
Result:=Result+PrepTypeParam(node.ParamNode(1),dst.dtype);
Result:=Result+PrepTypeParam(node.ParamNode(2),dst.dtype);
end;
function TEmitPostOp.OnFDiv1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
pCon:array[0..1] of TsrConst;
procedure _SetConst_s(dtype:TsrDataType;value:Single);
begin
Assert(dtype=dtFloat32);
dst.pWriter:=NewImm_s(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if (src[0].is_const) and (src[1].is_const) then
if (src[0].dtype=src[1].dtype) then
begin
//need a const calc
pCon[0]:=src[0].AsConst;
pCon[1]:=src[1].AsConst;
Case src[0].dtype of
dtFloat32:
begin
_SetConst_s(dst.dtype,pCon[0].AsFloat32/pCon[1].AsFloat32);
end;
else;
end;
end;
end;
function TEmitPostOp.OnIAdd1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if (src[0].is_const) and (src[1].is_const) then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
_SetConst(dst.dtype,data[0]+data[1]);
end else
if (src[0].is_const) then
begin
if (src[0].AsConst.GetData=0) then
begin
_SetReg(src[1]);
end;
end else
if (src[1].is_const) then
begin
if (src[1].AsConst.GetData=0) then
begin
_SetReg(src[0]);
end;
end;
end;
function TEmitPostOp.OnISub1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if src[0].is_const and src[1].is_const then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
_SetConst(dst.dtype,data[0]-data[1]);
end;
end;
function TEmitPostOp.OnShr1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
mask:Byte;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if (src[0].is_const) and (src[1].is_const) then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
case src[0].dtype.BitSize of
32:mask:=31;
64:mask:=63;
else
Assert(false);
end;
Case node.OpId of
Op.OpShiftRightLogical :_SetConst(dst.dtype,data[0] shr (data[1] and mask));
Op.OpShiftRightArithmetic:_SetConst(dst.dtype,SarInt64(Int64(data[0]),(data[1] and mask)));
else
Assert(false);
end;
end else
if (src[1].is_const) then
begin
Result:=0;
//TODO: Restrict optimizations
//Result:=_OnShr_ext1(node,src[0].pWriter.specialize AsType<ntOp>,src[1].AsConst);
end;
end;
function TEmitPostOp._OnShr_ext1(node,pOp:TSpirvOp;pShrVal:TsrConst):Integer;
var
src:array[0..1] of TsrRegNode;
begin
Result:=0;
if (pOp=nil) then Exit;
Case pOp.OpId of
Op.OpBitwiseAnd:
begin
src[0]:=RegDown(pOp.ParamNode(0).AsReg);
src[1]:=RegDown(pOp.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
if (src[0].is_const) then
begin
Result:=_OnShr_ext_and(node,pShrVal,src[0].AsConst);
end else
if (src[1].is_const) then
begin
Result:=_OnShr_ext_and(node,pShrVal,src[1].AsConst);
end;
end;
Op.OpIAdd:
begin
src[0]:=RegDown(pOp.ParamNode(0).AsReg);
src[1]:=RegDown(pOp.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
Result:=_OnShr_ext_add(node,src[0].pWriter.specialize AsType<ntOp>,src[1].pWriter.specialize AsType<ntOp>,pShrVal);
end;
else;
end;
end;
function TEmitPostOp._OnShr_ext_and(node:TSpirvOp;pShrVal,pAndVal:TsrConst):Integer;
var
dst:TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
data[0]:=pShrVal.GetData;
data[1]:=pAndVal.GetData;
data[0]:=High(QWORD) shl data[0];
if (data[0] and data[1]=0) then
begin
dst:=node.pDst.specialize AsType<ntReg>;
_SetConst(dst.dtype,0);
end;
end;
function isPowerOfTwo(x:QWORD):Boolean; inline;
begin
Result:=((x-1) and x)=0;
end;
function fastIntLog2(i:QWORD):QWORD; inline;
begin
Result:=BsfQWord(i);
end;
function _OpCanBeShrOpt(pOp:TSpirvOp;ShrVal:QWORD;var Delta:QWORD):Boolean;
var
src:array[0..1] of TsrRegNode;
data:QWORD;
begin
Result:=False;
if (pOp=nil) then Exit;
Case pOp.OpId of
Op.OpIMul:
begin
src[0]:=RegDown(pOp.ParamNode(0).AsReg);
src[1]:=RegDown(pOp.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
if (src[0].is_const) then
begin
data:=src[0].AsConst.GetData;
end else
if (src[1].is_const) then
begin
data:=src[1].AsConst.GetData;
end else
begin
Exit;
end;
if isPowerOfTwo(data) then
begin
data:=fastIntLog2(data);
Result:=(data>=ShrVal);
Delta:=data-ShrVal;
end;
end;
Op.OpShiftLeftLogical:
begin
src[0]:=RegDown(pOp.ParamNode(0).AsReg);
src[1]:=RegDown(pOp.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
if (src[1].is_const) then
begin
data:=src[1].AsConst.GetData;
Result:=(data>=ShrVal);
Delta:=data-ShrVal;
end;
end;
else;
end;
end;
function _GetShrOptReg(pOp:TSpirvOp):TsrRegNode;
var
src:array[0..1] of TsrRegNode;
begin
Result:=nil;
if (pOp=nil) then Exit;
Case pOp.OpId of
Op.OpIMul:
begin
src[0]:=RegDown(pOp.ParamNode(0).AsReg);
src[1]:=RegDown(pOp.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
if (src[0].is_const) then
begin
Result:=src[1];
end else
if (src[1].is_const) then
begin
Result:=src[0];
end;
end;
Op.OpShiftLeftLogical:
begin
src[0]:=RegDown(pOp.ParamNode(0).AsReg);
src[1]:=RegDown(pOp.ParamNode(1).AsReg);
if (src[0]=nil) or (src[1]=nil) then Exit;
Result:=src[0];
end;
else;
end;
end;
function TEmitPostOp._OnShr_ext_add(node,pOp0,pOp1:TSpirvOp;pShrVal:TsrConst):Integer;
var
dst,src:TsrRegNode;
dst_shr:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
data[0]:=0;
data[1]:=0;
if (not _OpCanBeShrOpt(pOp0,pShrVal.GetData,data[0])) and
(not _OpCanBeShrOpt(pOp1,pShrVal.GetData,data[1])) then Exit;
if (data[0]=0) then
begin
dst_shr[0]:=_GetShrOptReg(pOp0);
end else
begin
dst:=pOp0.pDst.specialize AsType<ntReg>;
src:=_GetShrOptReg(pOp0);
PrepTypeNode(src,dtUInt32);
dst_shr[0]:=OpShlTo(src,data[0],@pOp0)
end;
if (data[1]=0) then
begin
dst_shr[1]:=_GetShrOptReg(pOp1);
end else
begin
dst:=pOp1.pDst.specialize AsType<ntReg>;
src:=_GetShrOptReg(pOp1);
PrepTypeNode(src,dtUInt32);
dst_shr[1]:=OpShlTo(src,data[1],@pOp0)
end;
dst:=node.pDst.specialize AsType<ntReg>;
pOp0:=dst.pWriter.specialize AsType<ntOp>; //OpIAdd
PrepTypeNode(dst_shr[0],dtUInt32);
PrepTypeNode(dst_shr[1],dtUInt32);
src:=OpIAddTo(dst_shr[0],dst_shr[1],@pOp0);
_SetReg(src);
//Writeln(data[0],' ',data[1]);
//writeln;
Result:=1;
end;
function TEmitPostOp.OnAbsDiff1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..1] of TsrRegNode;
data:array[0..1] of QWORD;
rmax,rmin:TsrRegNode;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src[0]:=RegDown(node.ParamNode(0).AsReg);
src[1]:=RegDown(node.ParamNode(1).AsReg);
if (dst=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if src[0].is_const and src[1].is_const then
begin
//need a const calc
data[0]:=src[0].AsConst.GetData;
data[1]:=src[1].AsConst.GetData;
if (data[0]>data[1]) then
_SetConst(dst.dtype,data[0]-data[1])
else
_SetConst(dst.dtype,data[1]-data[0]);
Exit;
end else
if src[0].is_const then
begin
if src[0].AsConst.isZeroVal then
begin
//src[1]-0
src[1]:=node.ParamNode(1).AsReg; //get original
_SetReg(src[1]);
Exit;
end;
end else
if src[1].is_const then
begin
if src[1].AsConst.isZeroVal then
begin
//src[0]-0
src[0]:=node.ParamNode(0).AsReg; //get original
_SetReg(src[0]);
Exit;
end;
end;
//else
node.mark_not_used;
node.pDst:=nil;
rmax:=OpUMaxTo(src[0],src[1],@node); //update line
rmin:=OpUMinTo(src[0],src[1],@node); //update line
_Op2(node,Op.OpISub,dst,rmax,rmin);
end;
function F_WQM_32(D:DWORD):DWORD;
var
i:Byte;
begin
Result:=0;
if (D=0) then Exit;
For i:=0 to 7 do
begin
if (((D shr (i*4)) and 15)<>0) then
begin
Result:=Result or ($F shl (i*4));
end;
end;
end;
function TEmitPostOp.OnWQM32__1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
data:QWORD;
procedure _SetConst(dtype:TsrDataType;value:QWORD);
begin
dst.pWriter:=NewImm_q(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=RegDown(node.ParamNode(0).AsReg);
if (dst=nil) or (src=nil) then Exit;
if src.is_const then
begin
//need a const calc
data:=src.AsConst.GetData;
data:=F_WQM_32(data);
_SetConst(dst.dtype,data);
end else
if (src.dtype=dtBool) then
begin
_SetReg(src);
end else
begin
//TODO: WQM32
_SetReg(src);
end;
end;
type
Ppacked_offset=^Tpacked_offset;
Tpacked_offset=bitpacked record
x:bit6; //0..5 (int6)
a1:bit2;
y:bit6; //8..13 (int6)
a2:bit2;
z:bit6; //16..21 (int6)
a3:bit10;
end;
function int6(b:Byte):Integer; inline;
const
shift=BitSizeOf(Integer)-6;
begin
Result:=SarLongint((Integer(b) shl shift),shift);
end;
function TEmitPostOp.OnPackOfs1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
data:QWORD;
P:Ppacked_offset;
count:PtrUint;
cret:TsrConst;
cvec:array[0..2] of TsrConst;
pLine:TSpirvOp;
vint6:TsrRegNode;
rvec:array[0..2] of TsrRegNode;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
count:=0;
if not node.ParamNode(0).TryGetValue(count) then Exit;
src:=RegDown(node.ParamNode(1).AsReg);
if (src=nil) then Exit;
if src.is_const then
begin
//need a const calc
data:=src.AsConst.GetData;
P:=@data;
cret:=nil;
Case count of
1:
begin
cret:=ConstList.Fetch_i(dtInt32,int6(P^.x));
end;
2:
begin
cvec[0]:=ConstList.Fetch_i(dtInt32,int6(P^.x));
cvec[1]:=ConstList.Fetch_i(dtInt32,int6(P^.y));
cret:=ConstList.FetchVector(dtVec2i,@cvec,true);
end;
3:
begin
cvec[0]:=ConstList.Fetch_i(dtInt32,int6(P^.x));
cvec[1]:=ConstList.Fetch_i(dtInt32,int6(P^.y));
cvec[2]:=ConstList.Fetch_i(dtInt32,int6(P^.z));
cret:=ConstList.FetchVector(dtVec3i,@cvec,true);
end;
else
Assert(False);
end;
dst.pWriter:=cret;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end else
begin
pLine:=src.pLine;
vint6:=NewImm_i(dtInt32,6);
Case count of
1:
begin
rvec[0]:=NewReg(dtInt32);
pLine:=_Op3(pLine,Op.OpBitFieldSExtract,rvec[0],src,NewImm_i(dtInt32, 0),vint6);
src:=rvec[0];
end;
2:
begin
rvec[0]:=NewReg(dtInt32);
rvec[1]:=NewReg(dtInt32);
pLine:=_Op3(pLine,Op.OpBitFieldSExtract,rvec[0],src,NewImm_i(dtInt32, 0),vint6);
pLine:=_Op3(pLine,Op.OpBitFieldSExtract,rvec[1],src,NewImm_i(dtInt32, 8),vint6);
src:=NewReg(dtVec2i);
pLine:=OpMakeCon(pLine,src,@rvec);
end;
3:
begin
rvec[0]:=NewReg(dtInt32);
rvec[1]:=NewReg(dtInt32);
rvec[2]:=NewReg(dtInt32);
pLine:=_Op3(pLine,Op.OpBitFieldSExtract,rvec[0],src,NewImm_i(dtInt32, 0),vint6);
pLine:=_Op3(pLine,Op.OpBitFieldSExtract,rvec[1],src,NewImm_i(dtInt32, 8),vint6);
pLine:=_Op3(pLine,Op.OpBitFieldSExtract,rvec[2],src,NewImm_i(dtInt32,16),vint6);
src:=NewReg(dtVec3i);
pLine:=OpMakeCon(pLine,src,@rvec);
end;
else
Assert(False);
end;
dst.dtype :=src.dtype;
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
end;
////////
function TEmitPostOp._Fetch_PackAnc(node:TsrRegNode;index,count:Byte):TsrRegNode;
var
pLine:TSpirvOp;
src:array[0..2] of TsrRegNode;
prim,smid,rtid:Boolean;
begin
Result:=nil;
if (node=nil) then Exit;
if (count=0) then Exit;
pLine:=node.pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit;
if (pLine.OpId<>srOpInternal.OpPackAnc) then Exit;
src[0]:=pLine.ParamNode(0).AsReg;
src[1]:=pLine.ParamNode(1).AsReg;
src[2]:=pLine.ParamNode(2).AsReg;
if (src[0]=nil) or (src[1]=nil) or (src[2]=nil) then Exit;
prim:= (index+count<= 2); //[ 1: 0]
smid:=(index>= 8) and (index+count<=12); //[11: 8]
rtid:=(index>=16) and (index+count<=27); //[26:16]
count:=ord(prim)+ord(smid)+ord(rtid);
if (count=0) then
begin
Result:=NewImm_q(node.dtype,0,node);
end else
if (count=1) then
begin
if prim then
begin
Result:=src[0];
end else
if smid then
begin
Result:=src[1];
end else
if rtid then
begin
Result:=src[2];
end;
end;
end;
function TEmitPostOp.OnBFE_32_1(node:TSpirvOp):Integer;
var
pLine:TSpirvOp;
dst:TsrRegNode;
rBase,rIndex,rCount:TsrRegNode;
rsl:TsrRegNode;
num_31:TsrRegNode;
data:array[0..1] of QWORD;
index,count:Byte;
dtype:TsrDataType;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
rBase :=node.ParamNode(0).AsReg;
rIndex:=RegDown(node.ParamNode(1).AsReg);
rCount:=RegDown(node.ParamNode(2).AsReg);
if (rBase=nil) or (rIndex=nil) or (rCount=nil) then Exit;
dtype:=rBase.dtype;
//else
pLine:=node;
if (rIndex.is_const) and (rCount.is_const) then
begin
data[0]:=rIndex.AsConst.GetData;
data[1]:=rCount.AsConst.GetData;
//
index:=Byte(data[0] and 31);
count:=Byte(data[1] and 31);
//
rsl:=_Fetch_PackAnc(rBase,index,count);
if (rsl<>nil) then
begin
pLine:=rsl.pLine;
rBase:=RegDown(rsl);
if (rBase.is_const) then
begin
data[0]:=rBase.AsConst.GetData;
data[1]:=(1 shl count)-1;
data[0]:=data[0] and data[1];
//
if (data[0]<>rBase.AsConst.GetData) then
begin
rsl:=NewImm_q(dtUInt32,data[0],pLine);
end;
end else
begin
data[1]:=(1 shl count)-1;
num_31:=NewImm_q(dtUInt32,data[1],pLine);
//
PrepTypeNode(rsl,dtype);
rsl:=OpAndTo(rsl,num_31,@pLine);
rsl.PrepType(ord(dtype));
end;
dst.pWriter:=rsl;
node.mark_not_used;
node.pDst:=nil;
Exit;
end;
end;
num_31:=nil;
//
if (rIndex.is_const) then
begin
data[0]:=rIndex.AsConst.GetData;
data[0]:=data[0] and 31;
//
if (data[0]<>rIndex.AsConst.GetData) then
begin
rIndex:=NewImm_q(dtUInt32,data[0],pLine);
end else
begin
rIndex:=node.ParamNode(1).AsReg; //orig
end;
end else
begin
num_31:=NewImm_q(dtUInt32,31,pLine);
//
rIndex:=node.ParamNode(1).AsReg; //orig
PrepTypeNode(rIndex,dtUInt32);
rIndex:=OpAndTo(rIndex,num_31,@pLine);
end;
//
if (rCount.is_const) then
begin
data[1]:=rCount.AsConst.GetData;
data[1]:=data[1] and 31;
//
if (data[1]<>rCount.AsConst.GetData) then
begin
rCount:=NewImm_q(dtUInt32,data[1],pLine);
end else
begin
rCount:=node.ParamNode(2).AsReg; //orig
end;
end else
begin
if (num_31<>nil) then
begin
num_31:=NewImm_q(dtUInt32,31,pLine);
end;
//
rCount:=node.ParamNode(2).AsReg; //orig
PrepTypeNode(rCount,dtUInt32);
rCount:=OpAndTo(rCount,num_31,@pLine);
end;
PrepTypeNode(rIndex,dtUInt32);
PrepTypeNode(rCount,dtUInt32);
case dtype of
dtUint32:_Op3(pLine,Op.OpBitFieldUExtract,dst,rBase,rIndex,rCount);
dtInt32 :_Op3(pLine,Op.OpBitFieldSExtract,dst,rBase,rIndex,rCount);
else
Assert(False);
end;
node.mark_not_used;
node.pDst:=nil;
end;
function TEmitPostOp.OnBFIB32_1(node:TSpirvOp):Integer;
var
pLine:TSpirvOp;
dst:TsrRegNode;
bitmsk:TsrRegNode;
src:array[0..1] of TsrRegNode;
rIndex,rCount:TsrRegNode;
data:array[0..1] of QWORD;
index,count:DWORD;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
pLine:=node;
bitmsk:=RegDown(node.ParamNode(0).AsReg);
src[0]:=node.ParamNode(1).AsReg;
src[1]:=node.ParamNode(2).AsReg;
if (bitmsk=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
if bitmsk.is_const then
begin
data[0]:=bitmsk.AsConst.GetData;
index:=BsfQWord(data[0]);
count:=PopCnt (data[0]);
data[1]:=((1 shl count)-1) shl index;
if (data[0]=data[1]) then
begin
rIndex:=NewImm_q(dtUint32,index,pLine);
rCount:=NewImm_q(dtUint32,count,pLine);
_Op4(pLine,Op.OpBitFieldInsert,dst,src[1],src[0],rIndex,rCount);
node.mark_not_used;
node.pDst:=nil;
Exit;
end;
end;
//else
src[0]:=OpAndTo(src[0],bitmsk,@pLine);
src[0].PrepType(ord(dtUInt32));
bitmsk:=OpNotTo(bitmsk,@pLine);
bitmsk.PrepType(ord(dtUInt32));
src[1]:=OpAndTo(src[1],bitmsk,@pLine);
src[1].PrepType(ord(dtUInt32));
_Op2(pLine,Op.OpBitwiseOr,dst,src[0],src[1]);
node.mark_not_used;
node.pDst:=nil;
end;
function _IsFma(node:TSpirvOp):Boolean;
var
OpId:PtrUint;
begin
Result:=False;
if (node=nil) then Exit;
if (node.OpId<>Op.OpExtInst) then Exit;
OpId:=0;
node.ParamNode(1).TryGetValue(OpId);
if (OpId<>GlslOp.Fma) then Exit;
Result:=True;
end;
function _GetMadLegacyFma(node:TSpirvOp):TSpirvOp;
var
reg:TsrRegNode;
fma:TSpirvOp;
begin
Result:=node;
if (node=nil) then Exit;
if (node.OpId<>Op.OpSelect) then Exit;
reg:=RegDown(node.ParamNode(1).AsReg);
fma:=reg.pWriter.specialize AsType<ntOp>;
if _IsFma(fma) then
begin
Exit(fma);
end;
reg:=RegDown(node.ParamNode(2).AsReg);
fma:=reg.pWriter.specialize AsType<ntOp>;
if _IsFma(fma) then
begin
Exit(fma);
end;
end;
function _IsOp(node:TSpirvOp;OpId:DWORD):Boolean;
begin
Result:=False;
if (node=nil) then Exit;
Result:=(node.OpId=OpId);
end;
function _IsConstFloat_1_0(pReg:TsrRegNode):Boolean;
var
pConst:TsrConst;
begin
Result:=False;
if (pReg=nil) then Exit;
pConst:=pReg.AsConst;
if (pConst=nil) then Exit;
if (pConst.dtype<>dtFloat32) then Exit;
Result:=(Round(pConst.AsFloat32*10)=10);
end;
function _IsConstFloat_1_5(pReg:TsrRegNode):Boolean;
var
pConst:TsrConst;
begin
Result:=False;
if (pReg=nil) then Exit;
pConst:=pReg.AsConst;
if (pConst=nil) then Exit;
if (pConst.dtype<>dtFloat32) then Exit;
Result:=(Round(pConst.AsFloat32*10)=15);
end;
function _Fetch_FAbs_Value(node:TSpirvOp):TSpirvOp;
var
OpId:PtrUint;
pReg:TsrRegNode;
begin
Result:=nil;
if (node=nil) then Exit;
if (node.OpId<>Op.OpExtInst) then Exit;
OpId:=0;
node.ParamNode(1).TryGetValue(OpId);
if (OpId<>GlslOp.FAbs) then Exit;
pReg:=RegDown(node.ParamNode(2).AsReg);
if (pReg=nil) then Exit;
Result:=pReg.pWriter.specialize AsType<ntOp>;
end;
function _cmp_src_cube_op3(node0,node1:TSpirvOp):Boolean;
var
src0:TsrRegNode;
src1:TsrRegNode;
i:Byte;
begin
Result:=False;
if (node0=nil) or (node1=nil) then Exit;
For i:=0 to 2 do
begin
src0:=RegDown(node0.ParamNode(i).AsReg);
src1:=RegDown(node1.ParamNode(i).AsReg);
if (src0<>src1) then Exit(False);
end;
Result:=True;
end;
function is_all_const(src:PPsrRegNode;count:byte):Boolean;
var
i:Byte;
begin
Result:=True;
For i:=0 to count-1 do
if not src[i].is_const then Exit(false);
end;
function is_all_in_one_comp(src:PPsrRegNode;rtype:TsrDataType;count:byte):Boolean;
var
i:Byte;
pos:PtrUint;
pLine:TSpirvOp;
pReg,tmp:TsrRegNode;
begin
pReg:=nil;
Result:=True;
For i:=0 to count-1 do
begin
pLine:=src[i].pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit(false);
if (pLine.OpId<>Op.OpCompositeExtract) then Exit(false);
pos:=0;
if not pLine.ParamNode(1).TryGetValue(pos) then Exit;
if (pos<>i) then Exit(false);
tmp:=RegDown(pLine.ParamNode(0).AsReg);
if (tmp=nil) then Exit(false);
if (tmp.dtype<>rtype) then Exit(false);
if (i=0) then
begin
pReg:=tmp;
end else
begin
if (pReg<>tmp) then Exit(false);
end;
end;
end;
function try_get_comp_bridge(var src:TsrRegNode):Integer;
var
pLine:TSpirvOp;
pos:PtrUint;
pReg:TsrRegNode;
begin
Result:=0;
pLine:=src.pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit;
if (pLine.OpId<>Op.OpCompositeExtract) then Exit;
pos:=0;
if not pLine.ParamNode(1).TryGetValue(pos) then Exit;
pReg:=RegDown(pLine.ParamNode(0).AsReg);
if (pReg=nil) then Exit;
pLine:=pReg.pWriter.specialize AsType<ntOp>;
if (pLine=nil) then Exit;
if (pLine.OpId<>Op.OpCompositeConstruct) then Exit;
pReg:=RegDown(pLine.ParamNode(pos).AsReg);
if (pReg=nil) then Exit;
src:=pReg;
Result:=1;
end;
{
float3 __GetCubemapUv(float3 uv)
{
float faceId = __v_cubeid_f32(uv.x, uv.y, uv.z);
float sc = __v_cubesc_f32(uv.x, uv.y, uv.z);
float tc = __v_cubetc_f32(uv.x, uv.y, uv.z);
float ima = 1.f / abs( __v_cubema_f32(uv.x, uv.y, uv.z) );
return float3(sc * ima + 1.5f, tc * ima + 1.5f, faceId);
}
float4 __GetCubemapArrayUv(float4 uv)
{
float3 cuv = __GetCubemapUv(uv.xyz);
cuv.z = cuv.z + (uv.w * 8.f);
return float4(cuv, uv.w);
}
}
function TEmitPostOp.OnMakeCub1(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..2] of TsrRegNode;
m_CUBE_SC:TSpirvOp;
m_CUBE_TC:TSpirvOp;
m_CUBE_ID:TSpirvOp;
m_x_CUBE_MA:TSpirvOp;
m_y_CUBE_MA:TSpirvOp;
m_x,m_y,m_f:TSpirvOp;
pReg:TsrRegNode;
pOp:TSpirvOp;
rtype:TsrDataType;
i:Byte;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
rtype:=dst.dtype;
if (rtype.Child<>dtFloat32) then Assert(false,'TODO');
if (rtype.Count=4) then Assert(false,'TODO');
m_x:=RegDown(node.ParamNode(0).AsReg).pWriter.specialize AsType<ntOp>; //param1
m_y:=RegDown(node.ParamNode(1).AsReg).pWriter.specialize AsType<ntOp>; //param2
m_f:=RegDown(node.ParamNode(2).AsReg).pWriter.specialize AsType<ntOp>; //param3
m_x:=_GetMadLegacyFma(m_x);
m_y:=_GetMadLegacyFma(m_y);
if not _IsFma(m_x) then Exit;
if not _IsFma(m_y) then Exit;
if not _IsOp(m_f,OpCUBEID) then Exit;
m_CUBE_ID:=m_f;
//m_x
pReg:=RegDown(m_x.ParamNode(2).AsReg); //param1
pOp:=pReg.pWriter.specialize AsType<ntOp>;
if not _IsOp(pOp,OpCUBESC) then Exit;
m_CUBE_SC:=pOp;
pReg:=RegDown(m_x.ParamNode(3).AsReg); //param2
pOp:=pReg.pWriter.specialize AsType<ntOp>;
if not _IsOp(pOp,Op.OpFDiv) then Exit;
pReg:=RegDown(pOp.ParamNode(0).AsReg); //div
if not _IsConstFloat_1_0(pReg) then Exit; //1.0
pReg:=RegDown(pOp.ParamNode(1).AsReg);
pOp:=_Fetch_FAbs_Value(pReg.pWriter.specialize AsType<ntOp>);
if not _IsOp(pOp,OpCUBEMA) then Exit;
m_x_CUBE_MA:=pOp;
pReg:=RegDown(m_x.ParamNode(4).AsReg); //param3
if not _IsConstFloat_1_5(pReg) then Exit; //1.5
//m_y
pReg:=RegDown(m_y.ParamNode(2).AsReg); //param1
pOp:=pReg.pWriter.specialize AsType<ntOp>;
if not _IsOp(pOp,OpCUBETC) then Exit;
m_CUBE_TC:=pOp;
pReg:=RegDown(m_x.ParamNode(3).AsReg); //param2
pOp:=pReg.pWriter.specialize AsType<ntOp>;
if not _IsOp(pOp,Op.OpFDiv) then Exit;
pReg:=RegDown(pOp.ParamNode(0).AsReg); //div
if not _IsConstFloat_1_0(pReg) then Exit; //1.0
pReg:=RegDown(pOp.ParamNode(1).AsReg);
pOp:=_Fetch_FAbs_Value(pReg.pWriter.specialize AsType<ntOp>);
if not _IsOp(pOp,OpCUBEMA) then Exit;
m_y_CUBE_MA:=pOp;
pReg:=RegDown(m_y.ParamNode(4).AsReg); //param3
if not _IsConstFloat_1_5(pReg) then Exit; //1.5
//
if not _cmp_src_cube_op3(m_CUBE_SC,m_CUBE_TC ) then Exit;
if not _cmp_src_cube_op3(m_CUBE_SC,m_CUBE_ID ) then Exit;
if not _cmp_src_cube_op3(m_CUBE_SC,m_x_CUBE_MA) then Exit;
if not _cmp_src_cube_op3(m_CUBE_SC,m_y_CUBE_MA) then Exit;
For i:=0 to 2 do
begin
src[i]:=RegDown(m_CUBE_SC.ParamNode(i).AsReg);
end;
MakeVecComp(node,dtVec3f,dst,@src);
node.mark_not_used;
node.pDst:=nil;
Result:=1;
end;
function TEmitPostOp.OnCUBEID2(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=node.ParamNode(2).AsReg;
if (dst=nil) or (src=nil) then Exit;
_SetReg(src); //fake out
end;
function TEmitPostOp.OnCUBESC2(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=node.ParamNode(0).AsReg;
if (dst=nil) or (src=nil) then Exit;
_SetReg(src); //fake out
end;
function TEmitPostOp.OnCUBETC2(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:TsrRegNode;
procedure _SetReg(src:TsrRegNode);
begin
dst.pWriter:=src;
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
src:=node.ParamNode(1).AsReg;
if (dst=nil) or (src=nil) then Exit;
_SetReg(src); //fake out
end;
function TEmitPostOp.OnCUBEMA2(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
procedure _SetConst_s(dtype:TsrDataType;value:Single);
begin
Assert(dtype=dtFloat32);
dst.pWriter:=NewImm_s(dtype,value,node);
node.mark_not_used;
node.pDst:=nil;
Inc(Result);
end;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
_SetConst_s(dtFloat32,1); //fake out
end;
procedure TEmitPostOp.MakeVecConst(rtype:TsrDataType;dst:TsrRegNode;src:PPsrRegNode);
var
nodes:array[0..3] of TsrConst;
h:TsrConst;
i:Byte;
begin
For i:=0 to rtype.Count-1 do
begin
nodes[i]:=src[i].AsConst;
end;
h:=ConstList.FetchVector(rtype,@nodes,true);
dst.pWriter:=h;
end;
procedure TEmitPostOp.MakeVecOne(dst:TsrRegNode;src:PPsrRegNode);
var
pLine:TSpirvOp;
rsrc:TsrRegNode;
begin
pLine:=src[0].pWriter.specialize AsType<ntOp>;
rsrc:=RegDown(pLine.ParamNode(0).AsReg);
dst.pWriter:=rsrc;
end;
function TEmitPostOp.MakeVecComp(pLine:TSpirvOp;rtype:TsrDataType;dst:TsrRegNode;src:PPsrRegNode):TSpirvOp;
var
r:Integer;
i:Byte;
begin
Result:=pLine;
repeat
r:=0;
For i:=0 to rtype.Count-1 do
begin
r:=r+try_get_comp_bridge(src[i]);
end;
if is_all_const(src,rtype.Count) then
begin
MakeVecConst(rtype,dst,src);
Exit; //
end;
if is_all_in_one_comp(src,rtype,rtype.Count) then
begin
MakeVecOne(dst,src);
Exit; //
end;
until (r=0);
Result:=OpMakeCon(pLine,dst,src);
end;
function TEmitPostOp.OnMakeVec2(node:TSpirvOp):Integer;
var
pParam:POpParamNode;
dst:TsrRegNode;
src:array[0..3] of TsrRegNode;
rtype:TsrDataType;
i:Byte;
begin
Result:=1;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
pParam:=node.ParamFirst;
rtype:=dst.dtype;
For i:=0 to rtype.Count-1 do
begin
src[i]:=pParam.AsReg;
pParam:=pParam.Next;
if (src[i]=nil) then Assert(false,'OnMakeVec2');
end;
MakeVecComp(node,rtype,dst,@src);
node.mark_not_used;
node.pDst:=nil;
end;
function TEmitPostOp.OnReturn_2(node:TSpirvOp):Integer;
begin
Result:=0;
if is_term_op(flow_down_prev_up(node)) then
begin
node.mark_not_used;
Inc(Result);
end;
end;
function TEmitPostOp.OnMakeExp2(node:TSpirvOp):Integer;
var
pLine:TSpirvOp;
pOpBlock:TsrOpBlock;
pChild:TsrOpBlock;
pBegOp,pEndOp,pMrgOp:TspirvOp;
exc:TsrRegNode;
b_adr:TSrcAdr;
begin
Result:=1;
pOpBlock:=node.Parent;
exc:=RegDown(node.ParamNode(0).AsReg);
if (exc=nil) then Exit;
if exc.is_const then
begin
node.mark_not_used;
Case exc.AsConst.AsBool of
True : //is always store
begin
pLine:=node.Next;
if (pLine<>nil) then
begin
pChild:=pLine.specialize AsType<ntOpBlock>;
if (pChild<>nil) then
begin
//up
pOpBlock.Remove(pChild);
pLine:=pOpBlock;
pLine.InsertAfter(pChild);
pChild.UpdateLevel;
end;
end;
end;
False: //is always kill
begin
AddSpirvOp(pOpBlock.dummy,Op.OpKill); //add kill
//clear all
node:=pOpBlock.First;
While (node<>nil) do
begin
if node.IsType(ntOpBlock) then
begin
pChild:=node.specialize AsType<ntOpBlock>;
node:=pChild.First;
Continue;
end else
begin
Case node.OpId of
Op.OpNop:;
Op.OpKill:;
else
node.mark_not_used(True);
end;
end;
node:=node.Next;
end;
end;
end;
Exit;
end else
begin
//reread
exc:=node.ParamNode(0).AsReg;
node.mark_not_used;
b_adr:=pOpBlock.Block.b_adr;
pLine:=node.Next;
if (pLine=nil) then //kill or nop
begin
pBegOp:=NewLabelOp(False); //current
pEndOp:=NewLabelOp(False); //end
pMrgOp:=pEndOp; //merge
pBegOp.Adr:=b_adr;
pEndOp.Adr:=b_adr;
pOpBlock.SetLabels(pBegOp,pEndOp,pMrgOp);
pOpBlock.Block.bType:=btCond;
pOpBlock.SetCond(exc,false); //reverse
pLine:=node;
pLine:=OpCondMerge (pLine,pMrgOp);
pLine:=OpBranchCond(pLine,pEndOp,pBegOp,exc); //reverse
pLine:=AddSpirvOp (pLine,pBegOp);
pChild:=AllocBlockOp; //create new
pChild.SetInfo(btOther,b_adr,b_adr);
pChild.dummy.OpId:=Op.OpKill; //set kill to dummy
pOpBlock.pBody:=pChild;
pLine:=InsertBlockOp(pLine,pChild);
//OpBranch not need from kill
pLine:=AddSpirvOp(pLine,pMrgOp);
end else
begin //kill or store
Assert(pLine.IsType(ntOpBlock));
pBegOp:=NewLabelOp(False); //current
pEndOp:=NewLabelOp(False); //end
pMrgOp:=NewLabelOp(False); //merge
pBegOp.Adr:=b_adr;
pEndOp.Adr:=b_adr;
pMrgOp.Adr:=b_adr;
pOpBlock.SetLabels(pBegOp,pEndOp,pMrgOp);
pOpBlock.Block.bType:=btCond;
pOpBlock.SetCond(exc,false); //reverse
pOpBlock.pElse.Block.bType:=btElse;
pLine:=node;
pLine:=OpCondMerge (pLine,pMrgOp);
pLine:=OpBranchCond(pLine,pEndOp,pBegOp,exc); //reverse
pLine:=AddSpirvOp (pLine,pBegOp);
pChild:=AllocBlockOp; //create new
pChild.SetInfo(btOther,b_adr,b_adr);
pChild.dummy.OpId:=Op.OpKill; //set kill to dummy
pOpBlock.pBody:=pChild;
pLine:=InsertBlockOp(pLine,pChild);
//OpBranch not need from kill
pLine:=AddSpirvOp(pLine,pEndOp);
//OpStore child
pLine:=pOpBlock.Last;
pLine:=OpBranch (pLine,pMrgOp);
pLine:=AddSpirvOp(pLine,pMrgOp); //end
end;
end;
end;
function TEmitPostOp.OnIAddExt2(node:TSpirvOp):Integer;
var
rsl:TsrRegPair;
dst,car:TsrRegNode;
src:array[0..1] of TsrRegNode;
begin
Result:=1;
rsl:=node.pDst.specialize AsType<ntRegPair>;
if (rsl=nil) then Exit;
dst:=rsl.pDst0.specialize AsType<ntReg>;
car:=rsl.pDst1.specialize AsType<ntReg>;
if (dst=nil) or (car=nil) then Exit;
src[0]:=node.ParamNode(0).AsReg;
src[1]:=node.ParamNode(1).AsReg;
if (src[0]=nil) or (src[1]=nil) then Exit;
node.mark_not_used;
node.pDst:=nil;
if (car.IsUsed) then //carry is use
begin
OpIAddCar(node,dst,car,src[0],src[1]);
end else
begin
_Op2(node,Op.OpIAdd,dst,src[0],src[1]);
end;
end;
function TEmitPostOp.OnISubExt2(node:TSpirvOp):Integer;
var
rsl:TsrRegPair;
dst,bor:TsrRegNode;
src:array[0..1] of TsrRegNode;
begin
Result:=1;
rsl:=node.pDst.specialize AsType<ntRegPair>;
if (rsl=nil) then Exit;
dst:=rsl.pDst0.specialize AsType<ntReg>;
bor:=rsl.pDst1.specialize AsType<ntReg>;
if (dst=nil) or (bor=nil) then Exit;
src[0]:=node.ParamNode(0).AsReg;
src[1]:=node.ParamNode(1).AsReg;
if (src[0]=nil) or (src[1]=nil) then Exit;
node.mark_not_used;
node.pDst:=nil;
if (bor.IsUsed) then //borrow is use
begin
OpISubBor(node,dst,bor,src[0],src[1]);
end else
begin
_Op2(node,Op.OpISub,dst,src[0],src[1]);
end;
end;
function TEmitPostOp.OnPackAnc2(node:TSpirvOp):Integer;
var
dst:TsrRegNode;
src:array[0..2] of TsrRegNode;
num4 :TsrRegNode;
num8 :TsrRegNode;
num11:TsrRegNode;
num16:TsrRegNode;
begin
Result:=0;
dst:=node.pDst.specialize AsType<ntReg>;
if (dst=nil) then Exit;
src[0]:=node.ParamNode(0).AsReg; //prim
src[1]:=node.ParamNode(1).AsReg; //smid
src[2]:=node.ParamNode(2).AsReg; //rtid
if (src[0]=nil) or (src[0]=nil) or (src[1]=nil) then Exit;
node.mark_not_used;
node.pDst:=nil;
num4 :=NewImm_q(dtUint32, 4,node);
num8 :=NewImm_q(dtUint32, 8,node);
num11:=NewImm_q(dtUint32,11,node);
num16:=NewImm_q(dtUint32,16,node);
//Base,Insert,Offset,Count
src[0]:=OpBFITo(src[0],src[1],num8 ,num4 ,@node);
src[0]:=OpBFITo(src[0],src[2],num16,num11,@node);
dst.pWriter:=src[0];
end;
//
end.