unit srOpUtils; {$mode objfpc}{$H+} interface uses spirv, srNode, srOp, srReg, srLayout, srVariable, srCFGLabel; const OpIAddExt=DWORD(-1); OpISubExt=DWORD(-2); OpAbsDiff=DWORD(-3); OpWQM32 =DWORD(-4); OpBFEU32 =DWORD(-5); OpBFIB32 =DWORD(-6); OpPackAnc=DWORD(-7); OpPackOfs=DWORD(-8); OpMakeExp=DWORD(-9); OpMakeVec=DWORD(-10); OpMakeCub=DWORD(-11); OpCUBEID =DWORD(-12); OpCUBESC =DWORD(-13); OpCUBETC =DWORD(-14); OpCUBEMA =DWORD(-15); function InsSpirvOp(pLine,pNew:PspirvOp):PspirvOp; Function get_inverse_cmp_op(OpId:DWORD):DWORD; Function is_term_op(OpId:DWORD):Boolean; Function is_merge_op(OpId:DWORD):Boolean; Function is_term_op(pLine:PspirvOp):Boolean; procedure up_merge_line(var pLine:PspirvOp); function FindUpSameOp(pLine,node:PspirvOp):PspirvOp; function IsDominUp(pNodeUp,pLine:PspirvOp):Boolean; function GetGlobalIndex(pLine:PspirvOp):DWORD; function GetGlobalIndexA(pLine:PspirvOp):DWORD; function MaxLine(p1,p2:PspirvOp):PspirvOp; function MinLine(p1,p2:PspirvOp):PspirvOp; Function IsParentOf(pLine,pCurr:PsrOpBlock):Boolean; Function IsParentOfLine(pLine,pCurr:PSpirvOp):Boolean; function GetMaxPlace(pLine:PSpirvOp;count:Byte;src:PPsrRegNode):PSpirvOp; function GetChainRegNode(node:PsrRegNode):PsrChain; function GetSourceRegNode(node:PsrRegNode):PsrNode; function flow_down_next_up(pLine:PspirvOp):PspirvOp; function flow_down_prev_up(pLine:PspirvOp):PspirvOp; function flow_prev_up(pLine:PspirvOp):PspirvOp; implementation //-- function flow_down_next_up(pLine:PspirvOp):PspirvOp; begin Result:=pLine^.First; //down if (Result=nil) then begin repeat //up Result:=pLine^.Next; pLine:=pLine^.Parent; until (pLine=nil) or (Result<>nil); end; end; function flow_down_prev_up(pLine:PspirvOp):PspirvOp; begin Result:=pLine^.Last; //down if (Result=nil) then begin repeat //up Result:=pLine^.Prev; pLine:=pLine^.Parent; until (pLine=nil) or (Result<>nil); end; end; function flow_prev_up(pLine:PspirvOp):PspirvOp; function _last(p:PspirvOp):PspirvOp; begin Result:=nil; if (p<>nil) then if p^.IsType(ntOpBlock) then if not (PsrOpBlock(p)^.Block.bType in [btCond,btLoop]) then begin Result:=p^.Last; end; end; begin Result:=_last(pLine); //down if (Result=nil) then begin repeat //up Result:=pLine^.Prev; pLine:=pLine^.Parent; until (pLine=nil) or (Result<>nil); end; end; function InsSpirvOp(pLine,pNew:PspirvOp):PspirvOp; var tmp:PspirvOp; begin Result:=nil; Assert(pLine<>nil); if (pLine=nil) or (pNew=nil) then Exit; if (pLine^.Next<>nil) then if pNew^.IsType(ntOp) then begin tmp:=pLine; while (not tmp^.IsType(ntOp)) do begin tmp:=flow_down_prev_up(tmp); Assert(tmp<>nil); end; pNew^.Adr:=tmp^.Adr; end; pLine^.InsertAfter(pNew); Result:=pNew; end; function GetCurrentIndex(pLine:PspirvOp):DWORD; var pParent:PsrOpBlock; node:PspirvOp; begin Result:=0; if (pLine=nil) then Exit; pParent:=pLine^.Parent; if (pParent=nil) then Exit; node:=pParent^.First; While (node<>nil) and (node<>pLine) do begin Result:=Result+node^.GetIndexCount; node:=node^.Next; end; end; function GetGlobalIndex(pLine:PspirvOp):DWORD; var pParent:PsrOpBlock; node:PspirvOp; begin Result:=0; if (pLine=nil) then Exit; node:=pLine; pParent:=node^.Parent; While (pParent<>nil) do begin Result:=Result+GetCurrentIndex(node); node:=PspirvOp(pParent); pParent:=node^.Parent; end; end; function GetGlobalIndexA(pLine:PspirvOp):DWORD; begin Result:=pLine^.GetIndexCount+GetGlobalIndex(pLine); end; function isGTLine(p1,p2:PspirvOp):Boolean; //(p1>p2) begin Result:=False; p2:=p2^.Next; While (p2<>nil) do begin if (p1=p2) then Exit(True); p2:=p2^.Next; end; end; Function IsGTLevel(p1,p2:PspirvOp):Boolean; //(p1>p2) var pParent1:PsrOpBlock; pParent2:PsrOpBlock; begin Result:=False; pParent1:=p1^.Parent; pParent2:=p2^.Parent; Result:=(pParent1^.Level>pParent2^.Level); end; function MaxLine(p1,p2:PspirvOp):PspirvOp; var pParent:PsrOpBlock; node:PspirvOp; i,w:DWORD; begin Result:=nil; if (p1=nil) then Exit(p2); if (p2=nil) or (p1=p2) then Exit(p1); if IsGTLevel(p2,p1) then //(p2>p1) begin //swap node:=p1; p1:=p2; p2:=node; end; i:=0; node:=p1; pParent:=node^.Parent; While (pParent<>nil) do begin if (pParent=p2^.Parent) then begin if isGTLine(node,p2) then //(node>p2) begin //Assert(not isGTLine(p2,node)); Exit(p1); end else begin //Assert(isGTLine(p2,node)); Exit(p2); end; end; i:=i+GetCurrentIndex(node); node:=PspirvOp(pParent); pParent:=node^.Parent; end; w:=GetGlobalIndex(p2); if (i>w) then begin Result:=p1; end else begin Result:=p2; end; end; function MinLine(p1,p2:PspirvOp):PspirvOp; begin if (MaxLine(p1,p2)=p1) then begin Result:=p2; end else begin Result:=p1; end; end; Function IsParentOf(pLine,pCurr:PsrOpBlock):Boolean; begin Result:=False; if not pLine^.IsType(ntOpBlock) then Exit; if not pCurr^.IsType(ntOpBlock) then Exit; While (pLine<>nil) do begin if (pLine=pCurr) then Exit(True); pLine:=pLine^.Parent; end; end; Function IsParentOfLine(pLine,pCurr:PSpirvOp):Boolean; begin Result:=IsParentOf(pLine^.Parent,pCurr^.Parent); end; function GetMaxPlace(pLine:PSpirvOp;count:Byte;src:PPsrRegNode):PSpirvOp; var m:PSpirvOp; i:Byte; begin Result:=pLine; if (count=0) or (src=nil) then Exit; m:=nil; For i:=0 to count-1 do begin if (not src[i]^.is_const) then if IsParentOfLine(pLine,src[i]^.pLine) then begin m:=MaxLine(m,src[i]^.pLine); end; end; if (m<>nil) then begin Result:=m; end; end; Function get_inverse_cmp_op(OpId:DWORD):DWORD; begin Result:=0; Case OpId of Op.OpFOrdLessThan :Result:=Op.OpFOrdGreaterThan ; Op.OpFOrdEqual :Result:=Op.OpFOrdEqual ; Op.OpFOrdLessThanEqual :Result:=Op.OpFOrdGreaterThanEqual ; Op.OpFOrdGreaterThan :Result:=Op.OpFOrdLessThan ; Op.OpFOrdNotEqual :Result:=Op.OpFOrdNotEqual ; Op.OpFOrdGreaterThanEqual :Result:=Op.OpFOrdLessThanEqual ; Op.OpOrdered :Result:=Op.OpOrdered ; Op.OpUnordered :Result:=Op.OpUnordered ; Op.OpFUnordLessThan :Result:=Op.OpFUnordGreaterThan ; Op.OpFUnordEqual :Result:=Op.OpFUnordEqual ; Op.OpFUnordLessThanEqual :Result:=Op.OpFUnordGreaterThanEqual; Op.OpFUnordGreaterThan :Result:=Op.OpFUnordLessThan ; Op.OpFUnordNotEqual :Result:=Op.OpFUnordNotEqual ; Op.OpFUnordGreaterThanEqual:Result:=Op.OpFUnordLessThanEqual ; Op.OpSLessThan :Result:=Op.OpSGreaterThan ; Op.OpIEqual :Result:=Op.OpIEqual ; Op.OpSLessThanEqual :Result:=Op.OpSGreaterThanEqual ; Op.OpSGreaterThan :Result:=Op.OpSLessThan ; Op.OpINotEqual :Result:=Op.OpINotEqual ; Op.OpSGreaterThanEqual :Result:=Op.OpSLessThanEqual ; Op.OpULessThan :Result:=Op.OpUGreaterThan ; Op.OpULessThanEqual :Result:=Op.OpUGreaterThanEqual ; Op.OpUGreaterThan :Result:=Op.OpULessThan ; Op.OpUGreaterThanEqual :Result:=Op.OpULessThanEqual ; else Assert(false); end; end; Function is_term_op(OpId:DWORD):Boolean; begin Case OpId of Op.OpBranch, Op.OpBranchConditional, Op.OpSwitch, Op.OpReturn, Op.OpReturnValue, Op.OpKill, Op.OpTerminateInvocation, Op.OpDemoteToHelperInvocation, Op.OpUnreachable:Result:=True; else Result:=False; end; end; Function is_merge_op(OpId:DWORD):Boolean; begin Case OpId of Op.OpSelectionMerge, Op.OpLoopMerge:Result:=True; else Result:=False; end; end; Function is_term_op(pLine:PspirvOp):Boolean; begin Result:=False; if (pLine=nil) then Exit; repeat //up if pLine^.IsType(ntOpBlock) then begin // end else if pLine^.IsType(ntOp) then begin if not pLine^.is_cleared then begin Case pLine^.OpId of Op.OpNop:; // else Break; end; end; end else begin Exit; end; pLine:=flow_down_prev_up(pLine); until false; Result:=is_term_op(pLine^.OpId); end; procedure up_merge_line(var pLine:PspirvOp); var node:PspirvOp; begin repeat if pLine^.IsType(ntOp) then begin if pLine^.is_cleared or is_merge_op(pLine^.OpId) then begin node:=pLine^.Prev; if (node<>nil) then begin pLine:=node; Continue; end; end; end; Break; until false; end; function CompareParam(p1,p2:POpParamNode):Boolean; begin Result:=(p1^.Value=p2^.Value); end; function CompareOp(p1,p2:PspirvOp):Boolean; var n1,n2:POpParamNode; begin Result:=False; if not p1^.IsType(ntOp) then Exit; if not p2^.IsType(ntOp) then Exit; if (p1^.OpId<>p2^.OpId) then Exit; if (p1^.pDst<>p2^.pDst) then Exit; n1:=p1^.ParamNode(0); n2:=p2^.ParamNode(0); While (n1<>nil) do begin if (n2=nil) then Exit; if not CompareParam(n1,n2) then Exit; n1:=n1^.Next; n2:=n2^.Next; end; Result:=(n2=nil); end; function FindUpSameOp(pLine,node:PspirvOp):PspirvOp; begin Result:=nil; if (pLine=nil) or (node=nil) then Exit; While (pLine<>nil) do begin if not pLine^.is_cleared then begin if CompareOp(pLine,node) then Exit(pLine); end; pLine:=flow_prev_up(pLine); end; end; function IsDominUp(pNodeUp,pLine:PspirvOp):Boolean; begin Result:=False; if (pNodeUp=nil) or (pLine=nil) then Exit; While (pLine<>nil) do begin if (pNodeUp=pLine) then Exit(True); pLine:=flow_prev_up(pLine); end; end; function GetChainRegNode(node:PsrRegNode):PsrChain; var pOp:PSpirvOp; begin Result:=nil; node:=RegDown(node); pOp:=node^.pWriter^.AsType(ntOp); if (pOp=nil) then Exit; if (pOp^.OpId<>Op.OpLoad) then Exit; Result:=pOp^.ParamNode(0)^.Value^.AsType(ntChain); end; function GetSourceRegNode(node:PsrRegNode):PsrNode; var pOp:PSpirvOp; pVar:PsrVariable; begin Result:=nil; node:=RegDown(node); pOp:=node^.pWriter^.AsType(ntOp); if (pOp=nil) then Exit; if (pOp^.OpId<>Op.OpLoad) then Exit; pVar:=pOp^.ParamNode(0)^.Value^.AsType(ntVariable); if (pVar=nil) then Exit; Result:=pVar^.pSource; end; end.