unit srOp; {$mode objfpc}{$H+} interface uses sysutils, spirv, srOpInternal, ginodes, srNode, srCFGParser, srCFGCursor, srLiteral, srType, srTypes, srRefId, srReg; type TspirvOp=class; PPspirvOp=^TspirvOp; TOpParamNode=class public pNext:TOpParamNode; private pParent:TspirvOp; pValue:TsrNode; function GetValue:TsrNode; procedure SetValue(v:TsrNode); public property Next:TOpParamNode read pNext; property Parent:TspirvOp read pParent; property Value:TsrNode read GetValue write SetValue; function AsReg:TsrRegNode; function TryGetValue(var V:PtrUint):Boolean; end; POpParamNode=TOpParamNode; TOpParamQueue=specialize TNodeQueueClass; TsrOpCustom=class(TsrNode) public pPrev,pNext:TsrOpCustom; private pParent:TsrOpCustom; //TsrOpBlock; public function _Next :TsrNode; override; function _Prev :TsrNode; override; function _Parent:TsrNode; override; end; ntOpCustom=TsrOpCustom; TsrOpList=specialize TNodeListClass; TsoFlags=(soClear,soNotUsed,soForce,soPost); TsoSetFlags=Set of TsoFlags; TspirvOp=class(TsrOpCustom) private pParam:TOpParamQueue; FType :TsrType; Fdst :TsrNode; flags :TsoSetFlags; procedure SetType(t:TsrType); Procedure SetDst(r:TsrNode); Procedure UnClear; public //Adr :TSrcAdr; OpId:DWORD; // Procedure _zero_read; override; Procedure _PrepType(node:PPrepTypeNode); override; Function _GetPline:TsrNode; override; Function _GetPtype:TsrNode; override; function _GetIndexCount:DWORD; override; // property pType:TsrType read FType write SetType; property pDst:TsrNode read Fdst write SetDst; procedure Init(_OpId:DWORD); inline; procedure InsertAfter(new:TspirvOp); procedure InsertBefore(new:TspirvOp); procedure Remove; function ParamFirst:POpParamNode; function ParamLast:POpParamNode; function ParamNode(i:Byte):POpParamNode; procedure AddParam(p:TsrNode); procedure AddParamAfter(__prev:POpParamNode;p:TsrNode); procedure AddLiteral(Value:PtrUint;const name:RawByteString=''); procedure AddString(const name:RawByteString); function is_cleared:Boolean; function is_force:Boolean; function is_post:Boolean; function Clear:Boolean; procedure mark(f:TsoSetFlags); function can_clear:Boolean; end; ntOp=TspirvOp; TsrVolMark=(vmNone,vmEndpg,vmBreak,vmConti,vmMixed); TsrOpBlockCustom=class(TsrOpCustom) private FList :TsrOpList; FIndex:DWORD; FLevel:DWORD; procedure AddIndex(d:DWORD); procedure SubIndex(d:DWORD); public // function _First :TsrNode; override; function _Last :TsrNode; override; function _GetIndexCount:DWORD; override; // property Level:DWORD read FLevel; procedure InsertAfter(node,new:TsrOpCustom); procedure InsertBefore(node,new:TsrOpCustom); procedure Remove(node:TsrOpCustom); procedure UpdateLevel; function NewSpirvOp(OpId:DWORD):TspirvOp; function AddSpirvOp(node:TspirvOp):TspirvOp; function AddSpirvOp(OpId:DWORD):TspirvOp; function line:TsrNode; end; ntOpBlock=TsrOpBlockCustom; TsrOpBlock=packed class(TsrOpBlockCustom) public bType:TsrBlockType; Labels:record pBegOp:TspirvOp; pEndOp:TspirvOp; pMrgOp:TspirvOp; pBcnOp:TspirvOp; end; pBody :TsrOpBlock; pIf :TsrOpBlock; pElse :TsrOpBlock; vctx :TsrVolatileContext; FCursor:TsrCursor; Regs:record orig:PsrRegsSnapshot; prev:PsrRegsSnapshot; next:PsrRegsSnapshot; end; Cond:record pReg :TsrRegNode; FNormalOrder:Boolean; FUseCont :Boolean; FExcMerg :Boolean; end; FVolMark:TsrVolMark; dummy:TspirvOp; procedure Init; procedure SetInfo(_bType:TsrBlockType); procedure SetLabels(pBegOp,pEndOp,pMrgOp:TspirvOp); procedure SetCond(pReg:TsrRegNode;FNormalOrder:Boolean); function FindUpLoop:TsrOpBlock; function FindUpCond:TsrOpBlock; function FindUpCondByReg(pReg:TsrRegNode;rDown:Boolean;var Invert:Boolean):TsrOpBlock; end; TSpirvFunc=class(TsrNode) public pPrev,pNext,pLeft,pRight:TSpirvFunc; class function c(n1,n2:PRawByteString):Integer; static; private key:RawByteString; FTop:TsrOpBlock; FBlock:TsrOpBlock; ID:TsrRefId; //post id public // function _First :TsrNode; override; function _Last :TsrNode; override; function _GetRef :Pointer; override; function _GetPrintName:RawByteString; override; // property Name:RawByteString read key; property pBlock:TsrOpBlock read FBlock write FBlock; Function pTop:TsrOpBlock; Procedure PushBlock(New:TsrOpBlock); function PopBlock:Boolean; function line:TspirvOp; Procedure Init(const _name:RawByteString); function NewSpirvOp(OpId:DWORD):TspirvOp; function AddSpirvOp(node:TspirvOp):TspirvOp; function AddSpirvOp(OpId:DWORD):TspirvOp; function GetPrintName:RawByteString; end; ntFunc=TSpirvFunc; PsrFuncList=^TsrFuncList; TsrFuncList=object type TNodeList=specialize TNodeListClass; TNodeTree=specialize TNodeTreeClass; var FList:TNodeList; FTree:TNodeTree; function Search(const name:RawByteString):TSpirvFunc; procedure Insert(new:TSpirvFunc); function First:TSpirvFunc; inline; end; Function classif_rw_op(OpId:DWORD):Byte; function OpGetStrDebug(pLine:TSpirvOp):RawByteString; operator := (i:TsrNode):TspirvOp; inline; operator := (i:TsrNode):TsrOpBlock; inline; operator := (i:TsrNode):TSpirvFunc; inline; implementation operator := (i:TsrNode):TspirvOp; inline; begin Result:=TspirvOp(Pointer(i)); //typecast hack end; operator := (i:TsrNode):TsrOpBlock; inline; begin Result:=TsrOpBlock(Pointer(i)); //typecast hack end; operator := (i:TsrNode):TSpirvFunc; inline; begin Result:=TSpirvFunc(Pointer(i)); //typecast hack end; // function TsrOpCustom._Next:TsrNode; begin Result:=pNext; end; function TsrOpCustom._Prev:TsrNode; begin Result:=pPrev; end; function TsrOpCustom._Parent:TsrNode; begin Result:=pParent; end; // function OpGetStrDebug(pLine:TSpirvOp):RawByteString; var V:PtrUint; begin Result:=''; if (pLine=nil) then Exit; if (pLine.OpId=Op.OpExtInst) then begin V:=0; if pLine.ParamNode(1).TryGetValue(V) then begin Result:=GlslOp.GetStr(V); end; end else begin Result:=OpGetStrInternal(pLine.OpId); end; end; // Procedure TspirvOp._zero_read; begin UnClear; end; Function TspirvOp._GetPline:TsrNode; begin Result:=Self; end; Function TspirvOp._GetPtype:TsrNode; begin Result:=FType; end; function TspirvOp._GetIndexCount:DWORD; begin Result:=1; end; Procedure TspirvOp._PrepType(node:PPrepTypeNode); var new:TsrDataType; pNode:POpParamNode; pTypeList:PsrTypeList; begin new:=TsrDataType(node^.rtype); if (new=dtUnknow) then Exit; Case OpId of Op.OpLoad: begin pNode:=ParamNode(0); if (pNode<>nil) then begin //change? pTypeList:=pParent.Emit.GetTypeList; pType:=pTypeList^.Fetch(new); //next node^.dnode:=pNode.pValue; Exit; end; end; else; end; node^.dnode:=nil; end; // function TsrOpBlockCustom._First:TsrNode; begin Result:=FList.pHead; end; function TsrOpBlockCustom._Last:TsrNode; begin Result:=FList.pTail; end; function TsrOpBlockCustom._GetIndexCount:DWORD; begin Result:=FIndex; end; // function TSpirvFunc._First:TsrNode; begin Result:=FTop.FList.pHead; end; function TSpirvFunc._Last:TsrNode; begin Result:=FTop.FList.pTail; end; function TSpirvFunc._GetPrintName:RawByteString; begin Result:=GetPrintName; end; function TSpirvFunc._GetRef:Pointer; begin Result:=@ID; end; // function TOpParamNode.GetValue:TsrNode; begin if (Self=nil) then Exit(nil); Result:=pValue; end; procedure TOpParamNode.SetValue(v:TsrNode); var b:Byte; begin if (Self=nil) then Exit; if (pValue=v) then Exit; // Assert(pParent<>nil); // if not pParent.is_cleared then begin if (pParent.ParamFirst=Self) then begin b:=classif_rw_op(pParent.OpId); end else begin b:=1; end; // if (b and 2)<>0 then begin v.mark_write (pParent); pValue.mark_unwrite(pParent); end; // if (b and 1)<>0 then begin v.mark_read (pParent); pValue.mark_unread(pParent); end; end; // pValue:=v; end; function TOpParamNode.AsReg:TsrRegNode; begin Result:=nil; if (Self=nil) then Exit; Result:=pValue.specialize AsType; end; function TOpParamNode.TryGetValue(var V:PtrUint):Boolean; begin Result:=False; if (Self=nil) then Exit; if pValue.IsType(ntLiteral) then begin V:=TsrLiteral(pValue).Value; Result:=True; end; end; // procedure TspirvOp.Init(_OpId:DWORD); inline; begin OpId:=_OpId; end; procedure TspirvOp.InsertAfter(new:TspirvOp); begin Assert(new<>nil); Assert(pParent<>nil); TsrOpBlock(pParent).InsertAfter(Self,new); end; procedure TspirvOp.InsertBefore(new:TspirvOp); begin Assert(new<>nil); Assert(pParent<>nil); TsrOpBlock(pParent).InsertBefore(Self,new); end; procedure TspirvOp.Remove; begin Assert(pParent<>nil); TsrOpBlock(pParent).Remove(Self); end; function TspirvOp.ParamFirst:POpParamNode; begin Result:=pParam.pHead; end; function TspirvOp.ParamLast:POpParamNode; begin Result:=pParam.pTail; end; function TspirvOp.ParamNode(i:Byte):POpParamNode; var node:POpParamNode; begin Result:=nil; node:=pParam.pHead; While (node<>nil) do begin if (i=0) then Exit(node); Dec(i); node:=node.pNext; end; end; procedure TspirvOp.AddParam(p:TsrNode); var node:POpParamNode; begin node:=Emit.specialize New; node.pParent:=Self; // pParam.Push_tail(node); // node.Value:=p; //mark_read/mark_write end; procedure TspirvOp.AddParamAfter(__prev:POpParamNode;p:TsrNode); var node:POpParamNode; begin node:=Emit.specialize New; node.pParent:=Self; // pParam.InsertAfter(__prev,node); // node.Value:=p; //mark_read/mark_write end; procedure TspirvOp.AddLiteral(Value:PtrUint;const name:RawByteString=''); var pLiterals:PsrLiteralList; Literal:TsrLiteral; begin pLiterals:=Emit.GetLiteralList; Literal:=pLiterals^.FetchLiteral(Value,Pchar(name)); AddParam(Literal); end; procedure TspirvOp.AddString(const name:RawByteString); var pLiterals:PsrLiteralList; Literal:TsrLiteralString; begin pLiterals:=Emit.GetLiteralList; Literal:=pLiterals^.FetchString(Pchar(name)); AddParam(Literal); end; procedure TspirvOp.SetType(t:TsrType); begin if (FType=t) then Exit; if not is_cleared then begin t.mark_read (Self); FType.mark_unread(Self); end; FType:=t; end; Procedure TspirvOp.SetDst(r:TsrNode); begin if (Fdst=r) then Exit; Fdst.ResetWriter(Self); Fdst:=r; Fdst.SetWriter(Self,Self); end; function TspirvOp.is_cleared:Boolean; begin Result:=(soClear in flags); end; function TspirvOp.is_force:Boolean; begin Result:=(soForce in flags); end; function TspirvOp.is_post:Boolean; begin Result:=(soPost in flags); end; function TspirvOp.Clear:Boolean; var node:POpParamNode; b:Byte; begin Result:=False; if not can_clear then Exit; if (read_count<>0) then if not is_force then begin can_clear; Assert(false,'Wrong read_count on:'+OpGetStrDebug(Self)); end; FType.mark_unread(Self); node:=pParam.pHead; While (node<>nil) do begin // if (pParam.pHead=node) then begin b:=classif_rw_op(OpId); end else begin b:=1; end; // if (b and 2)<>0 then begin node.pValue.mark_unwrite(Self); end; // if (b and 1)<>0 then begin node.pValue.mark_unread(Self); end; // node:=node.pNext; end; flags:=flags-[soNotUsed]; flags:=flags+[soClear]; Result:=True; end; Procedure TspirvOp.UnClear; var node:POpParamNode; b:Byte; begin if not is_cleared then Exit; FType.mark_read(Self); node:=pParam.pHead; While (node<>nil) do begin // if (pParam.pHead=node) then begin b:=classif_rw_op(OpId); end else begin b:=1; end; // if (b and 2)<>0 then begin node.pValue.mark_write(Self); end; // if (b and 1)<>0 then begin node.pValue.mark_read(Self); end; // node:=node.pNext; end; flags:=flags-[soClear]; end; procedure TspirvOp.mark(f:TsoSetFlags); begin flags:=flags+f; end; function TspirvOp.can_clear:Boolean; begin if (soClear in flags) then Exit(False); if (soNotUsed in flags) then Exit(True); if (OpId=Op.OpNop) then Exit(True); if (Fdst=nil) then Exit(False); Result:=not Fdst.IsUsed; end; // procedure TsrOpBlock.Init; begin dummy:=Emit.specialize New; dummy.Init(Op.OpNop); AddSpirvOp(dummy); // vctx.Emit :=Emit; vctx.block:=Self; end; procedure TsrOpBlock.SetInfo(_bType:TsrBlockType); begin bType:=_bType; end; procedure TsrOpBlock.SetLabels(pBegOp,pEndOp,pMrgOp:TspirvOp); begin Labels.pBegOp:=pBegOp; Labels.pEndOp:=pEndOp; Labels.pMrgOp:=pMrgOp; end; procedure TsrOpBlock.SetCond(pReg:TsrRegNode;FNormalOrder:Boolean); begin Cond.pReg :=pReg; Cond.FNormalOrder:=FNormalOrder; end; function TsrOpBlock.FindUpLoop:TsrOpBlock; var node:TsrOpBlock; begin Result:=nil; node:=Self; While (node<>nil) do begin if (node.bType=btLoop) then Exit(node); node:=node.pParent; end; end; function TsrOpBlock.FindUpCond:TsrOpBlock; var node:TsrOpBlock; begin Result:=nil; node:=Self; While (node<>nil) do begin if (node.bType=btCond) then Exit(node); node:=node.pParent; end; end; function TsrOpBlock.FindUpCondByReg(pReg:TsrRegNode;rDown:Boolean;var Invert:Boolean):TsrOpBlock; var node:TsrOpBlock; pCond:TsrRegNode; begin Result:=nil; if (pReg=nil) then Exit; if rDown then begin pReg:=RegDown(pReg); end; if pReg.is_const then Exit; node:=Self; While (node<>nil) do begin if (node.bType=btCond) then begin // pCond:=node.Cond.pReg; if rDown then begin pCond:=RegDown(pCond); end; // if (pReg=pCond) then begin Exit(node); end; end else if (node.bType=btElse) then begin Assert(node.pIf<>nil); node:=node.pIf; // pCond:=node.Cond.pReg; if rDown then begin pCond:=RegDown(pCond); end; // if (pReg=pCond) then begin Invert:=not Invert; //reverse Exit(node); end; end; node:=node.pParent; end; end; class function TSpirvFunc.c(n1,n2:PRawByteString):Integer; var count1,count2:sizeint; begin Count1:=Length(n1^); Count2:=Length(n2^); Result:=ord(Count1>Count2)-ord(Count1nil) then begin Result:=FBlock.FList.pTail; end; end; Procedure TSpirvFunc.Init(const _name:RawByteString); begin key:=_name; FTop:=Emit.specialize New; FTop.Init; FBlock:=FTop; FBlock.Init(); end; function TSpirvFunc.NewSpirvOp(OpId:DWORD):TspirvOp; begin Result:=Emit.specialize New; Result.Init(OpId); end; function TSpirvFunc.AddSpirvOp(node:TspirvOp):TspirvOp; begin Result:=node; if (node=nil) then Exit; FBlock.AddSpirvOp(node); end; function TSpirvFunc.AddSpirvOp(OpId:DWORD):TspirvOp; begin Result:=AddSpirvOp(NewSpirvOp(OpId)); end; function TSpirvFunc.GetPrintName:RawByteString; begin if (name<>'') then begin Result:=name; end else begin Assert(ID.Alloc); Result:='f'+IntToStr(ID.ID); end; end; // procedure TsrOpBlockCustom.AddIndex(d:DWORD); var node:TsrOpBlock; begin node:=TsrOpBlock(Self); While (node<>nil) do begin node.FIndex:=node.FIndex+d; node:=node.pParent; end; end; procedure TsrOpBlockCustom.SubIndex(d:DWORD); var node:TsrOpBlock; begin node:=TsrOpBlock(Self); While (node<>nil) do begin Assert(node.FIndex>=d); node.FIndex:=node.FIndex-d; node:=node.pParent; end; end; procedure TsrOpBlockCustom.InsertAfter(node,new:TsrOpCustom); begin FList.InsertAfter(node,new); new.pParent:=Self; AddIndex(new.GetIndexCount); mark_read(new); end; procedure TsrOpBlockCustom.InsertBefore(node,new:TsrOpCustom); begin FList.InsertBefore(node,new); new.pParent:=Self; AddIndex(new.GetIndexCount); mark_read(new); end; procedure TsrOpBlockCustom.Remove(node:TsrOpCustom); begin Assert(node.pParent=Self); FList.Remove(node); node.pParent:=nil; SubIndex(node.GetIndexCount); mark_unread(node); end; procedure TsrOpBlockCustom.UpdateLevel; begin if (pParent=nil) then begin FLevel:=0; end else begin FLevel:=TsrOpBlockCustom(pParent).FLevel+1; end; end; function TsrOpBlockCustom.NewSpirvOp(OpId:DWORD):TspirvOp; begin Result:=Emit.specialize New; Result.Init(OpId); end; function TsrOpBlockCustom.AddSpirvOp(node:TspirvOp):TspirvOp; begin Result:=node; if (node=nil) then Exit; FList.Push_tail(node); node.pParent:=Self; AddIndex(node.GetIndexCount); mark_read(node); end; function TsrOpBlockCustom.AddSpirvOp(OpId:DWORD):TspirvOp; begin Result:=AddSpirvOp(NewSpirvOp(OpId)); end; function TsrOpBlockCustom.line:TsrNode; begin Result:=nil; if (Self<>nil) then begin Result:=FList.pTail; end; end; // function TsrFuncList.Search(const name:RawByteString):TSpirvFunc; begin Result:=FTree.Find(@name); end; procedure TsrFuncList.Insert(new:TSpirvFunc); begin FTree.Insert(new); FList.Push_head(new); end; function TsrFuncList.First:TSpirvFunc; inline; begin Result:=FList.pHead; end; //-- Function classif_rw_op(OpId:DWORD):Byte; begin Case OpId of Op.OpStore, Op.OpImageWrite, Op.OpAtomicStore: Result:=2; //w Op.OpAtomicExchange, Op.OpAtomicCompareExchange, Op.OpAtomicCompareExchangeWeak, Op.OpAtomicIIncrement, Op.OpAtomicIDecrement, Op.OpAtomicIAdd, Op.OpAtomicISub, Op.OpAtomicSMin, Op.OpAtomicUMin, Op.OpAtomicSMax, Op.OpAtomicUMax, Op.OpAtomicAnd, Op.OpAtomicOr, Op.OpAtomicXor: Result:=3; //rw else Result:=1; end; end; end.