unit srCFGParser; {$mode ObjFPC}{$H+} interface uses sysutils, ps4_pssl, ginodes, srNode, srConfig; type TsrCodeRegion=class; PSrcAdr=^TSrcAdr; TSrcAdr=object pCode :TsrCodeRegion; Offset:PtrUInt; function get_code_ptr:PDWORD; function get_dmem_ptr:PDWORD; end; TsrSourceNode=class; TsrSourceNodeType=class of TsrSourceNode; TsrSourceBlock=class; TsrSourceNode=class pParent:TsrSourceBlock; pPrev,pNext:TsrSourceNode; // order:PtrUint; // function ntype:TsrSourceNodeType; inline; function First:TsrSourceNode; virtual; function Last :TsrSourceNode; virtual; function get_level:DWORD; end; TsrSourceNodeList=specialize TNodeListClass; // TsrSourceAdr=class(TsrSourceNode) key :TSrcAdr; //b_adr e_adr:TSrcAdr; property b_adr:TSrcAdr read key write key; class function c(n1,n2:PSrcAdr):Integer; static; end; TsrSourceLabel=class(TsrSourceAdr) pLeft,pRight:TsrSourceLabel; links_count:PtrUint; end; TsrSourceLabelTree=specialize TNodeTreeClass; TsrSourceInstruction=class(TsrSourceAdr) pLeft,pRight:TsrSourceInstruction; // FSPI:TSPI; // used:Boolean; end; TsrSourceInstructionTree=specialize TNodeTreeClass; // TsrCondition=( cNone, cFalse, cTrue, cScc0, cScc1, cVccz, cVccnz, cExecz, cExecnz, cTidz, cTidnz ); TsrStatementType=( sCond, sCopy, sVar, sStore, sBreak, sNot, sOr, sAnd ); //sCond TsrCondition //sCopy [self] [false]:sCond/sCopy/sNot/sOr/sAnd //sVar id //sStore [var]:sVar [false]:sCond/sCopy/sNot/sOr/sAnd //sBreak //sNot [cond]:sCond/sCopy/sNot/sOr //sOr [cond]:sCond/sCopy/sNot/sOr/sAnd [cond]:sCond/sLoad/sNot/sOr/sAnd //sAnd [cond]:sCond/sCopy/sNot/sOr/sAnd [cond]:sCond/sLoad/sNot/sOr/sAnd TsrStatement=class(TsrSourceNode) sType:TsrStatementType; pSrc :TsrStatement; pDst :TsrStatement; // pCache:TObject; u:record Case Byte of 0:(id :PtrUint); 1:(cond:TsrCondition); end; end; TsrSourceGoto=class(TsrSourceNode) FGoto:record pParent:Pointer; pPrev,pNext:TsrSourceGoto; end; // pCond :TsrStatement; pLabel:TsrSourceLabel; end; TsrGotoList=object pHead,pTail:TsrSourceGoto; //pMiddle:TsrSourceGoto; procedure Push_head(Node:TsrSourceGoto); procedure Push_tail(Node:TsrSourceGoto); procedure InsertAfter (node,new:TsrSourceGoto); procedure InsertBefore(node,new:TsrSourceGoto); function Pop_tail:TsrSourceGoto; procedure Remove(node:TsrSourceGoto); end; // TsrBlockType=(btMain,btSetpc,btCond,btElse,btLoop,btMerg,btInline,btOther); TsrSourceBlock=class(TsrSourceNode) FList:TsrSourceNodeList; FInit:TsrSourceNodeList; pCond:TsrStatement; bType:TsrBlockType; // pIf :TsrSourceBlock; pElse:TsrSourceBlock; // function pReal:TsrSourceBlock; function First:TsrSourceNode; override; function Last :TsrSourceNode; override; procedure Push_head(Node:TsrSourceNode); procedure Push_tail(Node:TsrSourceNode); function Pop_head:TsrSourceNode; function Pop_tail:TsrSourceNode; procedure InsertAfter(node,new:TsrSourceNode); procedure InsertBefore(node,new:TsrSourceNode); procedure Remove(node:TsrSourceNode); Procedure splice(node_first,node_last:TsrSourceNode); end; // TsrCodeRegion=class pNext :TsrCodeRegion; // FEmit :TCustomEmit; Body :Pointer; DMem :Pointer; Size :PtrUint; // FTop :TsrSourceBlock; // function FindByPtr(base:Pointer):TsrSourceNode; end; function get_branch_offset(var FSPI:TSPI):ptrint; function IsReal(b:TsrBlockType):Boolean; function parse_code_cfg2(var pCode:TsrCodeRegion;bType:TsrBlockType;Body,Dmem:Pointer;FEmit:TCustomEmit):Integer; implementation type TsrCFGParser2=object FEmit:TCustomEmit; pCode:TsrCodeRegion; pCurr:TsrSourceNode; order:PtrUint; VarId:Ptruint; mode :Integer; hits :Integer; // FLabelTree:TsrSourceLabelTree; FInstructionTree:TsrSourceInstructionTree; FGotoList:TsrGotoList; FGotoFree:TsrGotoList; // Function NewInstruction(b_adr,e_adr:TSrcAdr;var FSPI:TSPI):TsrSourceInstruction; Function NewLabel (Adr:TSrcAdr):TsrSourceLabel; Function NewGoto (Cond:TsrCondition;Adr:TSrcAdr):TsrSourceGoto; Function NewGoto (pCond:TsrStatement;pLabel:TsrSourceLabel):TsrSourceGoto; procedure FreeGoto (node:TsrSourceGoto); procedure RestoreGoto (node:TsrSourceGoto); Function NewBlock (bType:TsrBlockType):TsrSourceBlock; // Function NewCond (cond:TsrCondition):TsrStatement; Function NewCopy (pCond:TsrStatement):TsrStatement; Function NewVar :TsrStatement; Function NewStore(pVar,pCond:TsrStatement):TsrStatement; Function NewBreak:TsrStatement; Function NewNot (pCond:TsrStatement):TsrStatement; Function NewOr (pCond1,pCond2:TsrStatement):TsrStatement; Function NewAnd (pCond1,pCond2:TsrStatement):TsrStatement; // procedure EmitGoto(instr:TsrSourceInstruction;Adr:TSrcAdr); function Parse:Integer; procedure EmitLabels; procedure GotoPass; procedure InitMovePass; procedure RemoveGoto(goto_stmt:TsrSourceGoto); procedure EliminateAsConditional(goto_stmt:TsrSourceGoto); procedure EliminateAsLoop (goto_stmt:TsrSourceGoto); function MoveOutward (goto_stmt:TsrSourceGoto):TsrSourceGoto; function MoveOutwardIf (goto_stmt:TsrSourceGoto):TsrSourceGoto; function MoveOutwardElse (goto_stmt:TsrSourceGoto):TsrSourceGoto; function MoveOutwardElseElse (goto_stmt:TsrSourceGoto):TsrSourceGoto; function MoveOutwardLoop (goto_stmt:TsrSourceGoto):TsrSourceGoto; function MoveOutwardSwitch (goto_stmt:TsrSourceGoto):TsrSourceGoto; function MoveInward (goto_stmt:TsrSourceGoto):TsrSourceGoto; function Lift (goto_stmt:TsrSourceGoto):TsrSourceGoto; procedure ExecPass; procedure Print; end; function get_branch_offset(var FSPI:TSPI):ptrint; begin Result:=FSPI.OFFSET_DW+Smallint(FSPI.SOPP.SIMM)+1; end; function IsReal(b:TsrBlockType):Boolean; begin case b of btMain, btSetpc, btCond, btElse, btLoop:Result:=True; else Result:=False; end; end; function TsrSourceNode.ntype:TsrSourceNodeType; inline; begin Result:=TsrSourceNodeType(ClassType); end; function TsrSourceNode.First:TsrSourceNode; begin Result:=nil; end; function TsrSourceNode.Last:TsrSourceNode; begin Result:=nil; end; function TsrSourceNode.get_level:DWORD; var node:TsrSourceBlock; begin node:=pParent; Result:=0; While (node<>nil) do begin if isReal(node.bType) then begin Inc(Result); end; node:=node.pParent; end; end; /// class function TsrSourceAdr.c(n1,n2:PSrcAdr):Integer; var ptr1,ptr2:Pointer; begin ptr1:=n1^.get_code_ptr; ptr2:=n2^.get_code_ptr; Result:=ord(ptr1>ptr2)-ord(ptr1nil) do begin if IsReal(Result.bType) then Break; Result:=Result.pParent; end; end; function TsrSourceBlock.First:TsrSourceNode; begin Result:=FList.pHead; end; function TsrSourceBlock.Last:TsrSourceNode; begin Result:=FList.pTail; end; procedure TsrSourceBlock.Push_head(Node:TsrSourceNode); begin Assert(Node.pParent=nil); FList.Push_head(Node); Node.pParent:=Self; end; procedure TsrSourceBlock.Push_tail(Node:TsrSourceNode); begin Assert(Node.pParent=nil); FList.Push_tail(Node); Node.pParent:=Self; end; function TsrSourceBlock.Pop_head:TsrSourceNode; begin Result:=FList.Pop_head; if (Result<>nil) then begin Result.pParent:=nil; end; end; function TsrSourceBlock.Pop_tail:TsrSourceNode; begin Result:=FList.Pop_tail; if (Result<>nil) then begin Result.pParent:=nil; end; end; procedure TsrSourceBlock.InsertAfter(node,new:TsrSourceNode); begin Assert(node<>nil); Assert(node.pParent=Self); Assert(new.pParent=nil); // FList.InsertAfter(Node,new); new.pParent:=Self; end; procedure TsrSourceBlock.InsertBefore(node,new:TsrSourceNode); begin Assert(node<>nil); Assert(node.pParent=Self); Assert(new.pParent=nil); // FList.InsertBefore(Node,new); new.pParent:=Self; end; procedure TsrSourceBlock.Remove(node:TsrSourceNode); begin Assert(node<>nil); Assert(node.pParent=Self); // FList.Remove(node); node.pParent:=nil; node.pPrev :=nil; node.pNext :=nil; end; Procedure TsrSourceBlock.splice(node_first,node_last:TsrSourceNode); //[node_first..node_last) var node:TsrSourceNode; next:TsrSourceNode; parent:TsrSourceBlock; begin Assert(node_first<>nil); if (node_last<>nil) then begin Assert(node_first.pParent=node_last.pParent); end; parent:=node_first.pParent; node:=node_first; While (node<>nil) and (node<>node_last) do begin Assert(parent=node.pParent); next:=node.pNext; parent.Remove(node); Push_tail(node); node:=next; end; end; /// Function TsrCFGParser2.NewInstruction(b_adr,e_adr:TSrcAdr;var FSPI:TSPI):TsrSourceInstruction; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.b_adr:=b_adr; Result.e_adr:=e_adr; Result.FSPI :=FSPI; Result.used :=True; end; Function TsrCFGParser2.NewLabel(Adr:TSrcAdr):TsrSourceLabel; begin Result:=FLabelTree.Find(@Adr); if (Result=nil) then begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.b_adr:=Adr; Result.e_adr:=Adr; // FLabelTree.Insert(Result); end; Inc(Result.links_count); end; Function TsrCFGParser2.NewGoto(Cond:TsrCondition;Adr:TSrcAdr):TsrSourceGoto; begin Result:=FGotoFree.Pop_tail; if (Result=nil) then begin Result:=FEmit.specialize New; end; Inc(order); Result.order :=order; Result.pCond :=NewCond(Cond); Result.pLabel:=NewLabel(Adr); end; Function TsrCFGParser2.NewGoto(pCond:TsrStatement;pLabel:TsrSourceLabel):TsrSourceGoto; begin Result:=FGotoFree.Pop_tail; if (Result=nil) then begin Result:=FEmit.specialize New; end; Inc(order); Result.order :=order; Result.pCond :=pCond; Result.pLabel:=pLabel; end; procedure TsrCFGParser2.FreeGoto(node:TsrSourceGoto); begin if (node.FGoto.pParent<>nil) then begin FGotoList.Remove(node); end; if (node.pParent<>nil) then begin node.pParent.Remove(node); end; FGotoFree.Push_tail(node); end; procedure TsrCFGParser2.RestoreGoto(node:TsrSourceGoto); begin if (node.FGoto.pParent=nil) then begin FGotoList.Push_tail(node); end; end; Function TsrCFGParser2.NewBlock(bType:TsrBlockType):TsrSourceBlock; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.bType:=bType; end; Function TsrCFGParser2.NewCond(cond:TsrCondition):TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order :=order; Result.sType :=sCond; Result.u.cond:=cond; end; Function TsrCFGParser2.NewCopy(pCond:TsrStatement):TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sCopy; Result.pDst :=Result; Result.pSrc :=pCond; Result.u.id :=VarId; Inc(VarId); end; Function TsrCFGParser2.NewVar:TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sVar; Result.u.id :=VarId; Inc(VarId); end; Function TsrCFGParser2.NewStore(pVar,pCond:TsrStatement):TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sStore; Result.pDst :=pVar; Result.pSrc :=pCond; end; Function TsrCFGParser2.NewBreak:TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sBreak; end; const InvertCond:array[TsrCondition] of TsrCondition=( cNone, //cNone, cTrue, //cFalse, cFalse, //cTrue, cScc1, //cScc0, cScc0, //cScc1, cVccnz, //cVccz, cVccz, //cVccnz, cExecnz, //cExecz, cExecz, //cExecnz, cTidnz, //cTidz, cTidz //cTidnz ); Function TsrCFGParser2.NewNot(pCond:TsrStatement):TsrStatement; begin case pCond.sType of sCond:Result:=NewCond(InvertCond[pCond.u.cond]); else begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sNot; Result.pSrc :=pCond; end; end; end; Function TsrCFGParser2.NewOr(pCond1,pCond2:TsrStatement):TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sOr; Result.pSrc :=pCond1; Result.pDst :=pCond2; end; Function TsrCFGParser2.NewAnd(pCond1,pCond2:TsrStatement):TsrStatement; begin Result:=FEmit.specialize New; Inc(order); Result.order:=order; Result.sType:=sAnd; Result.pSrc :=pCond1; Result.pDst :=pCond2; end; /// function TSrcAdr.get_code_ptr:PDWORD; begin if (pCode=nil) then begin Result:=nil; end else begin Result:=pCode.Body; end; // Result:=Pointer(Result)+Offset; end; function TSrcAdr.get_dmem_ptr:PDWORD; begin if (pCode=nil) then begin Result:=nil end else begin Result:=pCode.DMem; end; // Result:=Pointer(Result)+Offset; end; /// function ToAdr(pCode:TsrCodeRegion;Offset:PtrUInt):TSrcAdr; inline; begin Result.pCode :=pCode ; Result.Offset:=Offset; end; procedure TsrCFGParser2.EmitGoto(instr:TsrSourceInstruction;Adr:TSrcAdr); var node:TsrSourceGoto; begin instr.used:=False; // Adr.Offset:=Adr.Offset+(Smallint(instr.FSPI.SOPP.SIMM)*SizeOf(DWORD)); // Case instr.FSPI.SOPP.OP of S_CBRANCH_SCC0 :node:=NewGoto(cScc0 ,Adr); S_CBRANCH_SCC1 :node:=NewGoto(cScc1 ,Adr); S_CBRANCH_VCCZ :node:=NewGoto(cVccz ,Adr); S_CBRANCH_VCCNZ :node:=NewGoto(cVccnz ,Adr); S_CBRANCH_EXECZ :node:=NewGoto(cExecz ,Adr); S_CBRANCH_EXECNZ:node:=NewGoto(cExecnz,Adr); S_BRANCH :node:=NewGoto(cTrue ,Adr); else Assert(false); end; // pCurr.pParent.Push_tail(node); pCurr:=node; // if (Smallint(instr.FSPI.SOPP.SIMM)<0) then begin //prior to cycles in revers FGotoList.Push_head(node); // { if (FGotoList.pMiddle=nil) then begin FGotoList.pMiddle:=node; end; } end else if (node.pCond.u.cond=cTrue) then begin FGotoList.Push_tail(node); { //middle unconditional in revers if (FGotoList.pMiddle=nil) then begin FGotoList.pMiddle:=node; // FGotoList.Push_head(node); end else begin //FGotoList.InsertBefore(FGotoList.pMiddle,node); FGotoList.InsertAfter(FGotoList.pMiddle,node); end; } end else begin FGotoList.Push_tail(node); end; end; function TsrCFGParser2.Parse:Integer; var FCursor:TShaderParser; b_adr,e_adr:TSrcAdr; FSPI:TSPI; node:TsrSourceInstruction; begin if (pCode=nil) then Exit(4); //init first label pCurr:=NewLabel(ToAdr(pCode,0)); pCode.FTop.Push_tail(pCurr); FCursor:=Default(TShaderParser); FCursor.Body:=pCode.Dmem; FSPI:=Default(TSPI); repeat b_adr:=ToAdr(pCode,FCursor.OFFSET_DW*SizeOf(DWORD)); // Result:=FCursor.Next(FSPI); if (Result=-1) then Break; // e_adr:=ToAdr(pCode,FCursor.OFFSET_DW*SizeOf(DWORD)); // node:=NewInstruction(b_adr,e_adr,FSPI); // pCurr.pParent.Push_tail(node); pCurr:=node; // FInstructionTree.Insert(node); // Case FSPI.CMD.EN of W_SOP1: Case FSPI.SOP1.OP of S_SETPC_B64: if (pCurr.pParent.bType=btSetpc) then begin Result:=1; Break; end; end; W_SOPP: Case FSPI.SOPP.OP of S_CBRANCH_SCC0 :EmitGoto(node,e_adr); S_CBRANCH_SCC1 :EmitGoto(node,e_adr); S_CBRANCH_VCCZ :EmitGoto(node,e_adr); S_CBRANCH_VCCNZ :EmitGoto(node,e_adr); S_CBRANCH_EXECZ :EmitGoto(node,e_adr); S_CBRANCH_EXECNZ:EmitGoto(node,e_adr); S_BRANCH :EmitGoto(node,e_adr); else; end; end; // if (Result<>0) then Break; // until false; // pCode.Size:=FCursor.OFFSET_DW*SizeOf(DWORD); end; function flow_down_next_up(node:TsrSourceNode):TsrSourceNode; begin Result:=node.First; //down if (Result=nil) then begin repeat //up Result:=node.pNext; node:=node.pParent; until (node=nil) or (Result<>nil); end; end; procedure TsrCFGParser2.EmitLabels; var node:TsrSourceGoto; inst:TsrSourceInstruction; begin node:=FGotoList.pHead; // while (node<>nil) do begin inst:=FInstructionTree.Find(@node.pLabel.key); Assert(inst<>nil); // if (node.pLabel.pParent=nil) then //if not inserted begin inst.pParent.InsertBefore(inst,node.pLabel); end; // node:=node.FGoto.pNext; end; end; function Level(stmt:TsrSourceNode):DWORD; inline; begin Result:=stmt.get_level; end; function IsDirectlyRelated(goto_stmt,label_stmt:TsrSourceNode):Boolean; var goto_level,label_level:DWORD; min_level,max_level:DWORD; min,max:TsrSourceNode; begin goto_level :=Level(goto_stmt); label_level:=Level(label_stmt); if (label_level < goto_level) then begin min_level:=label_level; max_level:=goto_level; min:=label_stmt; max:=goto_stmt; end else begin // goto_level < label_level min_level:=goto_level; max_level:=label_level; min:=goto_stmt; max:=label_stmt; end; while (max_level > min_level) do begin Dec(max_level); max:=max.pParent.pReal; end; Result:=(min.pParent.pReal=max.pParent.pReal); end; function IsIndirectlyRelated(goto_stmt,label_stmt:TsrSourceNode):Boolean; begin Result:=(goto_stmt.pParent.pReal <> label_stmt.pParent.pReal) and (not IsDirectlyRelated(goto_stmt, label_stmt)); end; function AreSiblings(goto_stmt,label_stmt:TsrSourceNode):Boolean; inline; begin Result:=(goto_stmt.pParent.pReal=label_stmt.pParent.pReal); end; function SiblingFromNephew(uncle,nephew:TsrSourceNode;up:Boolean):TsrSourceNode; var parent,it,it_up:TsrSourceNode; begin parent:=uncle.pParent.pReal; it :=nephew; it_up :=it.pParent.pReal; while (it_up <> nil) and (it_up <> parent) do begin it :=it_up; it_up:=it.pParent.pReal; end; if up then if (it.pParent<>nil) then if (it.pParent.bType=btMerg) then begin it:=it.pParent; end; Result:=it; end; function AreOrdered(left_sibling,right_sibling:TsrSourceNode):Boolean; var it:TsrSourceNode; begin if AreSiblings(left_sibling,right_sibling) then begin it:=right_sibling; while (it<>nil) do begin if (it=left_sibling) then Exit(False); // it:=it.pNext; end; Result:=True; end else begin Result:=False; end; end; function NeedsLift(goto_stmt,label_stmt:TsrSourceNode):Boolean; var sibling:TsrSourceNode; begin sibling:=SiblingFromNephew(goto_stmt,label_stmt,True); Result:=AreOrdered(sibling,goto_stmt); end; Function IsUnconditional(cond:TsrStatement):Boolean; inline; begin Result:=(cond.sType=sCond) and (cond.u.cond=cTrue) end; Function IsUnreachable(cond:TsrStatement):Boolean; inline; begin Result:=(cond.sType=sCond) and (cond.u.cond=cFalse) end; procedure TsrCFGParser2.GotoPass; var node,next:TsrSourceGoto; begin mode:=0; hits:=0; // node:=FGotoList.pHead; // while (node<>nil) do begin next:=node.FGoto.pNext; // RemoveGoto(node); // node:=next; end; // repeat mode:=1; hits:=0; // node:=FGotoList.pHead; // while (node<>nil) do begin next:=node.FGoto.pNext; // RemoveGoto(node); // node:=next; end; // until (hits=0); // mode:=2; // node:=FGotoList.pHead; // while (node<>nil) do begin next:=node.FGoto.pNext; // RemoveGoto(node); // node:=next; end; end; procedure MoveListBefore(var List:TsrSourceNodeList;before:TsrSourceNode); var node:TsrSourceNode; begin while (List.pHead<>nil) do begin node:=List.Pop_head; before.pParent.InsertBefore(before,node); end; end; procedure TsrCFGParser2.InitMovePass; var node,next:TsrSourceNode; begin node:=pCode.FTop.First; while (node<>nil) do begin next:=flow_down_next_up(node); if (node.ntype=TsrSourceBlock) then begin MoveListBefore(TsrSourceBlock(node).FInit,node); end; node:=next; end; end; Function NextUsed(node:TsrSourceNode):TsrSourceNode; begin Result:=node.pNext; while (Result<>nil) do begin if (Result.ntype=TsrSourceInstruction) then begin if not TsrSourceInstruction(Result).used then begin Result:=Result.pNext; Continue; end; end; Break; end; end; Function NextUsedFlowUp(node:TsrSourceNode):TsrSourceNode; function flow_next_up(node:TsrSourceNode):TsrSourceNode; begin repeat //up Result:=node.pNext; node:=node.pParent; //exclude "else" if (Result<>nil) then if (node<>nil) then if (node.ntype=TsrSourceBlock) then if (TsrSourceBlock(node).bType=btMerg) then begin Result:=nil; end; // until (node=nil) or (Result<>nil); end; begin Result:=flow_next_up(node); while (Result<>nil) do begin if (Result.ntype=TsrSourceInstruction) then begin if not TsrSourceInstruction(Result).used then begin Result:=flow_next_up(Result); Continue; end; end; Break; end; end; Function NextUsedFlowDown(node:TsrSourceNode):TsrSourceNode; function flow_down_next(node:TsrSourceNode):TsrSourceNode; begin Result:=node.First; //down if (Result=nil) then begin //next Result:=node.pNext; end; end; begin Result:=flow_down_next(node); while (Result<>nil) do begin if (Result.ntype=TsrSourceInstruction) then begin if not TsrSourceInstruction(Result).used then begin Result:=flow_down_next(Result); Continue; end; end; Break; end; end; procedure TsrCFGParser2.RemoveGoto(goto_stmt:TsrSourceGoto); var label_stmt:TsrSourceLabel; label_level,goto_level:DWORD; begin // Force goto_stmt and label_stmt to be directly related label_stmt:=goto_stmt.pLabel; if (IsIndirectlyRelated(goto_stmt, label_stmt)) then begin if (mode=0) then Exit; // Move goto_stmt out using outward-movement transformation until it becomes // directly related to label_stmt while (not IsDirectlyRelated(goto_stmt, label_stmt)) do begin goto_stmt:=MoveOutward(goto_stmt); //deffered if (goto_stmt=nil) then Exit; end end; // Force goto_stmt and label_stmt to be siblings if (IsDirectlyRelated(goto_stmt, label_stmt)) then begin label_level:=Level(label_stmt); goto_level :=Level(goto_stmt); if (goto_level > label_level) then begin if (mode=0) then Exit; // Move goto_stmt out of its level using outward-movement transformations while (goto_level > label_level) do begin goto_stmt:=MoveOutward(goto_stmt); //deffered if (goto_stmt=nil) then Exit; //Dec(goto_level); goto_level:=Level(goto_stmt); end; end else if (goto_level < label_level) then begin if (mode<2) then Exit; // if (NeedsLift(goto_stmt, label_stmt)) then begin // Lift goto_stmt to above stmt containing label_stmt using goto-lifting // transformations goto_stmt:=Lift(goto_stmt); end; // Move goto_stmt into label_stmt's level using inward-movement transformation while (goto_level < label_level) do begin goto_stmt:=MoveInward(goto_stmt); Inc(goto_level); end; end; end; // if (not AreSiblings(goto_stmt, label_stmt)) then begin Assert(false,'Goto is not a sibling with the label'); end; // goto_stmt and label_stmt are guaranteed to be siblings, eliminate if (NextUsed(goto_stmt) = label_stmt) then begin // Simply eliminate the goto if the label is next to it FreeGoto(goto_stmt); end else if (AreOrdered(goto_stmt, label_stmt)) then begin // Eliminate goto_stmt with a conditional EliminateAsConditional(goto_stmt); end else begin // Eliminate goto_stmt with a loop EliminateAsLoop(goto_stmt); end; end; procedure InsertAfter(node,new:TsrSourceNode); var parent:TsrSourceBlock; begin parent:=node.pParent; if (parent.bType=btMerg) then begin node:=parent; parent:=node.pParent; end; parent.InsertAfter(node,new); end; procedure InsertBefore(node,new:TsrSourceNode); var parent:TsrSourceBlock; begin parent:=node.pParent; if (parent.bType=btMerg) then begin node:=parent; parent:=node.pParent; end; parent.InsertBefore(node,new); end; procedure TsrCFGParser2.EliminateAsConditional(goto_stmt:TsrSourceGoto); var label_stmt:TsrSourceLabel; cond :TsrStatement; neg_cond :TsrStatement; if_stmt :TsrSourceBlock; if_merg :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; if_merg:=NewBlock(btMerg); if_stmt:=NewBlock(btCond); if_merg.Push_tail(if_stmt); if_stmt.splice(goto_stmt.pNext,label_stmt); InsertAfter(goto_stmt,if_merg); cond:=goto_stmt.pCond; neg_cond:=NewNot(cond); if_merg.FInit.Push_tail(neg_cond); if_stmt.pCond:=neg_cond; Inc(hits); // FreeGoto(goto_stmt); end; function SanitizeNoBreaks(node_first,node_last:TsrSourceNode):Boolean; var node,next:TsrSourceNode; begin Result:=True; node:=node_first; while (node<>nil) and (node<>node_last) do begin if (node.ntype=TsrStatement) then begin if (TsrStatement(node).sType=sBreak) then begin Exit(False); end; end; next:=node.First; //down if (next<>nil) then if (TsrSourceBlock(node).bType=btLoop) then begin next:=nil; end; if (next=nil) then begin repeat //up next:=node.pNext; node:=node.pParent; until (node=nil) or (next<>nil) or (node=node_last); end; node:=next; end; end; procedure TsrCFGParser2.EliminateAsLoop(goto_stmt:TsrSourceGoto); var label_stmt:TsrSourceLabel; cond :TsrStatement; loop_stmt :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; if not SanitizeNoBreaks(label_stmt, goto_stmt) then begin Assert(false,'SanitizeNoBreaks:EliminateAsLoop'); end; loop_stmt:=NewBlock(btLoop); loop_stmt.splice(label_stmt,goto_stmt); InsertBefore(goto_stmt,loop_stmt); cond:=goto_stmt.pCond; loop_stmt.pCond:=cond; Inc(hits); // FreeGoto(goto_stmt); end; function FindUpLoop(node:TsrSourceBlock):TsrSourceBlock; begin Result:=nil; While (node<>nil) do begin if (node.bType=btLoop) then Exit(node); node:=node.pParent; end; end; function IsBreakLoop(goto_stmt:TsrSourceGoto):Boolean; var loop:TsrSourceBlock; node:TsrSourceNode; begin Result:=False; loop:=FindUpLoop(goto_stmt.pParent); if (loop<>nil) then begin node:=goto_stmt.pLabel; while (node<>nil) do begin if (node=loop) then begin //label inside loop Exit(False); end; // node:=node.pParent; end; // Result:=True; end; end; { if (eval) { break-------\ } | ... | <------------/ } function IsBreakElse(goto_stmt:TsrSourceGoto):Boolean; var parent:TsrSourceBlock; begin Result:=False; parent:=goto_stmt.pParent; if (parent=nil) then Exit; if (parent.bType=btCond) then if IsUnconditional(goto_stmt.pCond) then if (NextUsed(goto_stmt)=nil) then begin parent:=parent.pParent; if (parent<>nil) then if (parent.bType=btMerg) then begin Result:=True; end; end; end; function IsBreakSwitch(goto_stmt:TsrSourceGoto):Boolean; var label_stmt:TsrSourceLabel; parent:TsrSourceBlock; begin Result:=False; label_stmt:=goto_stmt.pLabel; //if IsUnconditional(goto_stmt.pCond) then //if (NextUsed(goto_stmt)=nil) then if (goto_stmt.pParent<>nil) then if (goto_stmt.pParent.bType=btCond) then if (label_stmt.links_count>1) then begin parent:=goto_stmt.pParent; parent:=parent.pParent; if (NextUsedFlowUp(parent)<>label_stmt) then while (parent<>nil) do begin if (parent.bType=btLoop) then begin Exit(False); end else if AreSiblings(parent,label_stmt) then begin if (parent.pParent<>nil) then if (parent.pParent.bType=btMerg) then begin parent:=parent.pParent; end; if (NextUsedFlowUp(parent)=label_stmt) then begin Exit(False); end else if SanitizeNoBreaks(parent,label_stmt) then begin Exit(True); end else begin Exit(False); end; end; parent:=parent.pParent; end; end; end; function TsrCFGParser2.MoveOutward(goto_stmt:TsrSourceGoto):TsrSourceGoto; var parent:TsrSourceBlock; begin if (NextUsed(goto_stmt)=goto_stmt.pLabel) then begin Exit(goto_stmt); end; if IsBreakElse(goto_stmt) then begin Exit(MoveOutwardElse(goto_stmt)); end; if (mode=2) then if IsBreakSwitch(goto_stmt) then begin Exit(MoveOutwardSwitch(goto_stmt)); end; if IsBreakLoop(goto_stmt) then begin Exit(MoveOutwardLoop(goto_stmt)); end; parent:=goto_stmt.pParent.pReal; case parent.bType of btCond:Result:=MoveOutwardIf (goto_stmt); btElse:Result:=MoveOutwardIf (goto_stmt); btLoop:Result:=MoveOutwardLoop(goto_stmt); else begin Writeln(stderr,'Invalid outward movement:',parent.bType); Assert(false,'Invalid outward movement'); end; end; end; { .... if (expr) { stmt_1; .... if (cond) goto L1; .... stmt_i; } .... L1: stmt_n; } //--> normal { .... goto_L1 = false; if (expr) { stmt_1; .... goto_L1 = cond; if (!cond) { stmt_2; .... stmt_i; } } if (goto_L1) goto L1; .... L1: stmt_n; } //--> no body { .... goto_L1 = false; if (expr) { stmt_1; .... goto_L1 = cond; } if (goto_L1) goto L1; .... L1: stmt_n; } //--> no body, no cond, "if" body -> "else" { .... if (expr) { stmt_1; .... ---- } if (expr) goto L1; .... L1: stmt_n; } function TsrCFGParser2.MoveOutwardIf(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt:TsrSourceLabel; parent :TsrSourceBlock; pmerge :TsrSourceBlock; new_var :TsrStatement; set_var :TsrStatement; cond :TsrStatement; neg_cond :TsrStatement; new_goto :TsrSourceGoto; if_stmt :TsrSourceBlock; if_merg :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; parent:=goto_stmt.pParent; pmerge:=parent.pParent; Assert(pmerge<>nil); Assert(pmerge.bType=btMerg); cond:=goto_stmt.pCond; if (NextUsedFlowUp(pmerge)<>label_stmt) then begin if (mode<>2) then begin RestoreGoto(goto_stmt); Exit(nil); end; //backup action if (parent.bType=btCond) and (IsUnconditional(goto_stmt.pCond)) and (NextUsed(goto_stmt)=nil) then begin //else is detect Exit(MoveOutwardElse(goto_stmt)); end; //else goto up if (parent.bType=btElse) and (IsUnconditional(goto_stmt.pCond)) and (NextUsed(goto_stmt)=nil) then begin //else in else Exit(MoveOutwardElseElse(goto_stmt)); end; new_var:=NewVar; end else begin Inc(hits); //simplification new_var:=nil; end; if (new_var<>nil) then begin //goto_L1 = false; set_var:=NewStore(new_var,NewCond(cFalse)); pmerge.FInit.Push_tail(set_var); end; if (NextUsed(goto_stmt)=nil) then begin //empty body if (new_var<>nil) then begin //goto_L1 = cond; set_var:=NewStore(new_var,cond); parent.Push_tail(set_var); end; end else begin if_merg:=NewBlock(btMerg); if_stmt:=NewBlock(btCond); if_merg.Push_tail(if_stmt); if_stmt.splice(goto_stmt.pNext,nil); InsertAfter(goto_stmt,if_merg); if (new_var<>nil) then begin //goto_L1 = cond; set_var:=NewStore(new_var,cond); if_merg.FInit.Push_tail(set_var); end; neg_cond:=NewNot(cond); if_merg.FInit.Push_tail(neg_cond); if_stmt.pCond:=neg_cond; // end; // FreeGoto(goto_stmt); // if (new_var=nil) then begin if IsUnconditional(Cond) then begin new_var:=Cond; end else begin new_var:=NewCond(cTrue); end; end; new_goto:=NewGoto(new_var,label_stmt); InsertAfter(pmerge,new_goto); Result:=new_goto; end; { .... if (expr) { stmt_1; .... goto L1; } stmt_2; { .... L1: .... } stmt_n; } //--> { .... if (expr) { stmt_1; .... ---- } else { stmt_2; } if (expr) goto L1; { .... L1: .... } stmt_n; } function TsrCFGParser2.MoveOutwardElse(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt:TsrSourceLabel; pmerge :TsrSourceBlock; cond :TsrStatement; new_goto :TsrSourceGoto; if_stmt :TsrSourceBlock; if_else :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; if_stmt:=goto_stmt.pParent; Assert(if_stmt<>nil); pmerge:=if_stmt.pParent; Assert(pmerge<>nil); Assert(pmerge.bType=btMerg); cond:=goto_stmt.pCond; Assert(IsUnconditional(cond)); if (mode<>2) then begin if not AreOrdered(pmerge,label_stmt) then begin if (NextUsedFlowUp(pmerge.pParent.Last)<>label_stmt) then begin RestoreGoto(goto_stmt); Exit(nil); end; end; Inc(hits); end; if (NextUsed(pmerge)=nil) or (NextUsedFlowUp(pmerge)=label_stmt) then begin //no else body end else begin if_else:=NewBlock(btElse); if_else.pIf :=if_stmt; if_stmt.pElse:=if_else; pmerge.InsertAfter(if_stmt,if_else); if AreOrdered(pmerge,label_stmt) then begin if_else.splice(pmerge.pNext,label_stmt); end else begin if_else.splice(pmerge.pNext,nil); end; end; // FreeGoto(goto_stmt); // //if (expr) cond:=if_stmt.pCond; if (NextUsedFlowUp(pmerge)<>label_stmt) then begin cond:=NewCopy(cond); pmerge.FInit.Push_tail(cond); end else begin //simplification Exit(nil); end; new_goto:=NewGoto(cond,label_stmt); InsertAfter(pmerge,new_goto); Result:=new_goto; end; //--> no body, no cond, "else" body { .... goto_L1 = false; if (expr) { stmt_1; .... } else { .... ---- } if (!expr) goto L1; .... L1: stmt_n; } function TsrCFGParser2.MoveOutwardElseElse(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt:TsrSourceLabel; pmerge :TsrSourceBlock; cond :TsrStatement; new_goto :TsrSourceGoto; if_else :TsrSourceBlock; if_stmt :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; if_else:=goto_stmt.pParent; Assert(if_else<>nil); pmerge:=if_else.pParent; Assert(pmerge<>nil); Assert(pmerge.bType=btMerg); if_stmt:=if_else.pIf; Assert(if_stmt<>nil); cond:=goto_stmt.pCond; Assert(IsUnconditional(cond)); if (mode<>2) then begin if (NextUsedFlowUp(pmerge)<>label_stmt) then begin RestoreGoto(goto_stmt); Exit(nil); end; Inc(hits); end; // FreeGoto(goto_stmt); // //if (expr) else {} cond:=if_stmt.pCond; Assert(cond<>nil); if (NextUsedFlowUp(pmerge)<>label_stmt) then begin //(!expr) cond:=NewNot(cond); pmerge.FInit.Push_tail(cond); cond:=NewCopy(cond); pmerge.FInit.Push_tail(cond); end else begin //simplification Exit(nil); end; new_goto:=NewGoto(cond,label_stmt); InsertAfter(pmerge,new_goto); Result:=new_goto; end; { .... do { stmt_1; .... if (expr) { if (cond) goto L1; } .... stmt_i; } while (expr) .... L1: stmt_n; } //--> { .... goto_L1 = false; do { stmt_1; .... if (expr) { if (cond) { goto_L1 = true; break; } } .... stmt_i; } while (expr) if (goto_L1) goto L1; .... L1: stmt_n; } function TsrCFGParser2.MoveOutwardLoop(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt :TsrSourceLabel; loop_parent:TsrSourceBlock; cond :TsrStatement; new_var :TsrStatement; set_var :TsrStatement; new_goto :TsrSourceGoto; if_stmt :TsrSourceBlock; if_merg :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; loop_parent:=FindUpLoop(goto_stmt.pParent); cond:=goto_stmt.pCond; if (NextUsedFlowUp(loop_parent)<>label_stmt) then begin if (mode<>2) then begin RestoreGoto(goto_stmt); Exit(nil); end; new_var:=NewVar; //goto_L1 = false; set_var:=NewStore(new_var,NewCond(cFalse)); loop_parent.FInit.Push_tail(set_var); end else begin Inc(hits); //simplification new_var:=nil; end; //Unconditional if IsUnconditional(cond) then begin if (new_var<>nil) then begin //goto_L1 = true; set_var:=NewStore(new_var,NewCond(cTrue)); InsertBefore(goto_stmt,set_var); end; //break; InsertBefore(goto_stmt,NewBreak); end else begin //if (cond) { if_merg:=NewBlock(btMerg); if_stmt:=NewBlock(btCond); if_merg.Push_tail(if_stmt); InsertBefore(goto_stmt,if_merg); if_stmt.pCond:=cond; if (new_var<>nil) then begin //goto_L1 = true; set_var:=NewStore(new_var,NewCond(cTrue)); if_stmt.Push_tail(set_var); end; //break; if_stmt.Push_tail(NewBreak); end; // FreeGoto(goto_stmt); // if (new_var=nil) then begin if IsUnconditional(Cond) then begin new_var:=Cond; end else begin new_var:=NewCond(cTrue); end; end; new_goto:=NewGoto(new_var,label_stmt); InsertAfter(loop_parent,new_goto); Result:=new_goto; end; { if (expr) { if (cond) goto L1; } ... L1: ... } function TsrCFGParser2.MoveOutwardSwitch(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt :TsrSourceLabel; nested_stmt:TsrSourceNode; loop_stmt :TsrSourceBlock; begin label_stmt :=goto_stmt.pLabel; nested_stmt:=SiblingFromNephew(label_stmt,goto_stmt,True); if not SanitizeNoBreaks(nested_stmt, label_stmt) then begin Assert(false,'SanitizeNoBreaks:MoveOutwardSwitch'); end; loop_stmt:=NewBlock(btLoop); loop_stmt.pCond:=NewCond(cFalse); loop_stmt.splice(nested_stmt, label_stmt); InsertBefore(label_stmt,loop_stmt); Result:=MoveOutwardLoop(goto_stmt); end; { ... if (cond) goto L1; stmt_1; ... stmt_i; if (expr) { stmt_k; L1: ... stmt_n; } } //--> [Cond] { ... goto_L1 = cond; if (!cond) { stmt_1; ... stmt_i; } if (goto_L1 || expr) { if (goto_L1) goto L1; stmt_k; L1: ... stmt_n; } } //--> [Else] { ... goto_L1 = cond; if (!cond) { stmt_1; ... stmt_i; } if (!goto_L1 && expr) { ... stmt_j; ... } else { if (goto_L1) goto L1; stmt_k; L1: ... stmt_n; } } //--> [Loop] { ... goto_L1 = cond; if (!cond) { stmt_1; ... stmt_i; } do { if (goto_L1) goto L1; stmt_j; ... L1: ... stmt_n; } while (expr) } function TsrCFGParser2.MoveInward(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt :TsrSourceLabel; nested_stmt:TsrSourceBlock; nested_real:TsrSourceBlock; new_copy :TsrStatement; cond :TsrStatement; neg_cond :TsrStatement; new_op :TsrStatement; new_goto :TsrSourceGoto; if_stmt :TsrSourceBlock; if_merg :TsrSourceBlock; begin label_stmt:=goto_stmt.pLabel; nested_stmt:=TsrSourceBlock(SiblingFromNephew(goto_stmt,label_stmt,False)); Assert(nested_stmt.ntype=TsrSourceBlock); nested_real:=nested_stmt; if (nested_stmt.pParent<>nil) then if (nested_stmt.pParent.bType=btMerg) then begin nested_real:=nested_stmt.pParent; end; cond:=goto_stmt.pCond; if (NextUsed(goto_stmt)=nested_real) then begin //empty body //goto_L1 = cond; if (cond.sType<>sCond) then begin new_copy:=cond; end else begin new_copy:=NewCopy(cond); nested_real.FInit.Push_tail(new_copy); end; end else begin if_merg:=NewBlock(btMerg); if_stmt:=NewBlock(btCond); if_merg.Push_tail(if_stmt); if_stmt.splice(goto_stmt.pNext,nested_real); InsertAfter(goto_stmt,if_merg); //goto_L1 = cond; if (cond.sType<>sCond) then begin new_copy:=cond; end else begin new_copy:=NewCopy(cond); if_merg.FInit.Push_tail(new_copy); end; neg_cond:=NewNot(cond); if_merg.FInit.Push_tail(neg_cond); if_stmt.pCond:=neg_cond; // end; case TsrSourceBlock(nested_stmt).bType of btCond: begin Assert(nested_stmt.pCond<>nil); //load before if IsUnreachable(nested_stmt.pCond) then begin new_op:=new_copy; end else begin //(goto_L1 || expr) new_op:=NewOr(new_copy,nested_stmt.pCond); // nested_real.FInit.Push_tail(new_op); end; // Update nested if condition nested_stmt.pCond:=new_op; end; btElse: begin if_stmt:=nested_stmt.pIf; Assert(if_stmt<>nil); Assert(nested_stmt.pCond<>nil); //load before if IsUnreachable(nested_stmt.pCond) then begin new_op:=nested_stmt.pCond; end else begin //!goto_L1 neg_cond:=NewNot(new_copy); nested_real.FInit.Push_tail(neg_cond); //(!goto_L1 && expr) new_op:=NewAnd(neg_cond,nested_stmt.pCond); // nested_real.FInit.Push_tail(new_op); end; // Update nested if condition nested_stmt.pCond:=new_op; end; btLoop: begin // end; else begin Writeln(stderr,'Invalid inward movement:',nested_stmt.bType); Assert(false,'Invalid inward movement'); end; end; // FreeGoto(goto_stmt); // new_goto:=NewGoto(new_copy,label_stmt); nested_stmt.Push_head(new_goto); Result:=new_goto; end; { .... stmt_1; stmt_2; .... stmt_lab; /*contains L1*/ .... if (cond) goto L1; .... stmt_n; } //--> { .... stmt_1; stmt_2; .... goto_L1 = false; do { if (goto_L1) goto L1; stmt_lab; /*contains L1*/ .... goto_L1 = cond; } while (cond); .... stmt_n; } function TsrCFGParser2.Lift(goto_stmt:TsrSourceGoto):TsrSourceGoto; var label_stmt :TsrSourceLabel; nested_stmt:TsrSourceNode; loop_stmt :TsrSourceBlock; cond :TsrStatement; new_var :TsrStatement; set_var :TsrStatement; new_goto :TsrSourceGoto; begin label_stmt:=goto_stmt.pLabel; nested_stmt:=SiblingFromNephew(goto_stmt,label_stmt,True); if not SanitizeNoBreaks(nested_stmt, goto_stmt) then begin Assert(false,'SanitizeNoBreaks:Lift'); end; loop_stmt:=NewBlock(btLoop); loop_stmt.splice(nested_stmt, goto_stmt); InsertBefore(goto_stmt,loop_stmt); new_var:=NewVar; cond :=goto_stmt.pCond; loop_stmt.pCond:=cond; // goto_L1 = cond; set_var:=NewStore(new_var,cond); loop_stmt.Push_tail(set_var); //goto_L1 = false; set_var:=NewStore(new_var,NewCond(cFalse)); loop_stmt.FInit.Push_tail(set_var); // FreeGoto(goto_stmt); // new_goto:=NewGoto(new_var,label_stmt); loop_stmt.Push_head(new_goto); Result:=new_goto; end; /// type TsrExecFlow=( efNone, efFalse, efTrue ); function is_cmp_x(i:Integer):Boolean; inline; begin case i of V_CMPX_F_F32 ..V_CMPX_T_F32, V_CMPX_F_F64 ..V_CMPX_T_F64, V_CMPSX_F_F32..V_CMPSX_T_F32, V_CMPSX_F_F64..V_CMPSX_T_F64, V_CMPX_F_I32 ..V_CMPX_T_I32, V_CMPX_F_I64 ..V_CMPX_T_I64, V_CMPX_F_U32 ..V_CMPX_T_U32, V_CMPX_F_U64 ..V_CMPX_T_U64, V_CMPX_CLASS_F32, V_CMPX_CLASS_F64: Result:=True; else Result:=False; end; end; function GetExecFlow(var FSPI:TSPI):TsrExecFlow; begin Case FSPI.CMD.EN of W_VOP1 : Case FSPI.VOP1.OP of V_NOP :Result:=efNone; V_READFIRSTLANE_B32:Result:=efFalse; else Result:=efTrue; end; //-> The result is given in a scalar register, so it needs to be processed separately W_VOPC :Result:=efFalse; W_VOP3 : Case FSPI.VOP3a.OP of //-> The result is given in a scalar register, so it needs to be processed separately 0..255 :Result:=efFalse; //VOP3c 384+V_NOP :Result:=efNone; 256+V_READLANE_B32 :Result:=efFalse; 256+V_WRITELANE_B32 :Result:=efFalse; 384+V_READFIRSTLANE_B32:Result:=efFalse; else Result:=efTrue; end; W_DS : Case FSPI.DS.OP of DS_NOP:Result:=efNone; else Result:=efTrue; end; W_MUBUF :Result:=efTrue; W_MTBUF :Result:=efTrue; W_EXP :Result:=efFalse; //-> processed separately W_MIMG :Result:=efTrue; W_VOP2 : Case FSPI.VOP2.OP of V_READLANE_B32 :Result:=efFalse; V_WRITELANE_B32:Result:=efFalse; else Result:=efTrue; end; W_SOPP : Case FSPI.SOPP.OP of S_NOP :Result:=efNone; S_WAITCNT:Result:=efNone; else Result:=efFalse; end; else Result:=efFalse; end; end; function GetExecFlow(node:TsrSourceNode):TsrExecFlow; begin if (node.ntype=TsrSourceInstruction) then begin Result:=GetExecFlow(TsrSourceInstruction(node).FSPI); end else if (node.ntype=TsrSourceNode) then begin Result:=efNone; end else if (node.ntype=TsrSourceLabel) then begin Result:=efNone; end else begin Result:=efFalse; end; end; procedure TsrCFGParser2.ExecPass; var node :TsrSourceNode; next :TsrSourceNode; parent :TsrSourceNode; exec :TsrSourceBlock; if_stmt:TsrSourceBlock; if_merg:TsrSourceBlock; begin node:=pCode.FTop.First; exec:=nil; while (node<>nil) do begin parent:=node.pParent; next:=flow_down_next_up(node); case GetExecFlow(node) of efNone: begin if (exec<>nil) then begin exec.splice(node,node.pNext); end; end; efFalse: begin exec:=nil; end; efTrue: begin if (exec=nil) then begin if_merg:=NewBlock(btMerg); if_stmt:=NewBlock(btCond); if_stmt.pCond:=NewCond(cTidnz); if_merg.Push_tail(if_stmt); InsertBefore(node,if_merg); exec:=if_stmt; end; exec.splice(node,node.pNext); end; end; if (next<>nil) then if (parent<>next.pParent) then begin exec:=nil; end; node:=next; end; end; /// function Vertical(node:TsrSourceNode):RawByteString; var i:Integer; tmp:TsrSourceBlock; begin i:=node.get_level; // Result:=''; SetLength(Result,i); tmp:=node.pParent; While (tmp<>nil) do begin if isReal(tmp.bType) then begin if (tmp.bType=btLoop) then begin Result[i]:='!'; end else begin Result[i]:='|'; end; Dec(i); end; tmp:=tmp.pParent; end; // if (i<>0) and (node.ntype=TsrSourceBlock) then begin Result[i]:='+'; end; end; function get_str_prefix(count:Byte;node:TsrSourceNode):RawByteString; begin if (node.ntype=TsrSourceInstruction) then begin Result:=' '+HexStr(TsrSourceInstruction(node).b_adr.Offset,count)+Vertical(node); end else if (node.ntype=TsrSourceLabel) then begin Result:=' '+Space(count)+Space(node.get_level); end else begin Result:=' '+Space(count)+Vertical(node); end; end; function get_str_label(count:Byte;node:TsrSourceLabel):RawByteString; begin Result:='_label_'+HexStr(node.b_adr.Offset,count); end; const CondStr:array[TsrCondition] of RawByteString=( 'None', 'False', 'True', 'Scc0', 'Scc1', 'Vccz', 'Vccnz', 'Execz', 'Execnz', 'Tidz', 'Tidnz' ); function GetCondStr(node:TsrStatement):RawByteString; begin Result:=''; while (node<>nil) do begin case node.sType of sCond :begin Result:=Result+CondStr[node.u.cond]; Break; end; sCopy :begin Result:=Result+'C'+IntToStr(node.u.id); Break; end; sVar :begin Result:=Result+'U'+IntToStr(node.u.id); Break; end; //sStore:; //sBreak:; sNot :begin Result:='!'+Result; node:=node.pSrc; end; sOr :begin Result:=Result+'('+GetCondStr(node.pSrc)+' || '+GetCondStr(node.pDst)+')'; Break; end; sAnd :begin Result:=Result+'('+GetCondStr(node.pSrc)+' && '+GetCondStr(node.pDst)+')'; Break; end; else Break; end; end; end; function GetStatmentStr(node:TsrStatement):RawByteString; begin Result:=''; case node.sType of //sCond :' sCopy :Result:=GetCondStr(node.pDst)+' = '+GetCondStr(node.pSrc)+'; //#'+IntToStr(node.order); //sVar :' sStore:Result:=GetCondStr(node.pDst)+' = '+GetCondStr(node.pSrc)+'; //#'+IntToStr(node.order); sBreak:Result:='break; //#'+IntToStr(node.order); //sNot :; //sOr :; //sAnd :; else; end; end; procedure PrintStatmentList(const prefix:RawByteString;List:TsrSourceNodeList); var node:TsrStatement; s:RawByteString; begin node:=TsrStatement(List.pHead); while (node<>nil) do begin case node.sType of sCond:; //skip sNot :; //skip sOr :; //skip sAnd :; //skip else begin s:=GetStatmentStr(node); if (s<>'') then begin Writeln(prefix+s); end; end; end; // node:=TsrStatement(node.pNext); end; end; function get_str_goto(count:Byte;node:TsrSourceGoto):RawByteString; begin Result:='if ('+GetCondStr(node.pCond)+') goto '+get_str_label(count,node.pLabel)+'; //#'+IntToStr(node.order); end; function get_down_str(node:TsrSourceBlock):RawByteString; begin Result:=''; case node.bType of btCond:Result:='if ('+GetCondStr(node.pCond)+') { //#'+IntToStr(node.order); btLoop:Result:='do { //#'+IntToStr(node.order); //btMerg:Result:='merge { //#'+IntToStr(node.order); else; end; end; function get_up_str(node:TsrSourceBlock):RawByteString; begin Result:=''; case node.bType of btCond:begin if (node.pElse=nil) then begin Result:='}; //if #'+IntToStr(node.order);; end else begin Result:='} else { //#'+IntToStr(node.order)+'-#'+IntToStr(node.pElse.order); end; end; btElse:Result:='}; //else #'+IntToStr(node.order); btLoop:Result:='} while ('+GetCondStr(node.pCond)+'); //#'+IntToStr(node.order); //btMerg:Result:='} //merge #'+IntToStr(node.order); else; end; end; procedure TsrCFGParser2.Print; var count:Byte; prefix,s:RawByteString; node,next:TsrSourceNode; begin count:=BsrQWord(pCode.Size); if (count=$FF) then count:=0; count:=(count+4) div 4; node:=pCode.FTop.First; while (node<>nil) do begin prefix:=get_str_prefix(count,node); if (node.ntype=TsrSourceInstruction) then begin Writeln(prefix+get_str_spi(TsrSourceInstruction(node).FSPI)); end else if (node.ntype=TsrSourceLabel) then begin Writeln(prefix+get_str_label(count,TsrSourceLabel(node))+': //#'+IntToStr(node.order)); end else if (node.ntype=TsrSourceGoto) then begin Writeln(prefix+get_str_goto(count,TsrSourceGoto(node))); end else if (node.ntype=TsrSourceBlock) then begin // PrintStatmentList(prefix,TsrSourceBlock(node).FInit); //down s:=get_down_str(TsrSourceBlock(node)); if (s<>'') then begin Writeln(prefix+s); end; //up if (node.First=nil) then begin s:=get_up_str(TsrSourceBlock(node)); if (s<>'') then begin Writeln(prefix+s); end; end; // end else if (node.ntype=TsrStatement) then begin s:=GetStatmentStr(TsrStatement(node)); if (s<>'') then begin Writeln(prefix+s); end; end else begin //Writeln(prefix+node.ntype.ClassName); end; next:=node.First; //down if (next=nil) then begin repeat //up next:=node.pNext; node:=node.pParent; // if (node<>nil) and (next=nil) then begin s:=get_up_str(TsrSourceBlock(node)); if (s<>'') then begin prefix:=get_str_prefix(count,node); Writeln(prefix+s); end; end else begin Break; end; // until false; end; node:=next; end; end; /// function parse_code_cfg2(var pCode:TsrCodeRegion;bType:TsrBlockType;Body,Dmem:Pointer;FEmit:TCustomEmit):Integer; var parser:TsrCFGParser2; begin pCode:=FEmit.specialize New; // parser:=Default(TsrCFGParser2); parser.FEmit:=FEmit; parser.pCode:=pCode; // pCode.FEmit:=FEmit; pCode.Body :=Body; pCode.Dmem :=Dmem; pCode.FTop :=parser.NewBlock(bType); Result:=parser.Parse; if (Result>1) then Exit; parser.EmitLabels; parser.GotoPass; parser.InitMovePass; parser.ExecPass; if PsrConfig(pCode.FEmit.GetConfig)^.PrintCfg then begin parser.Print; end; Result:=0; end; // function TsrCodeRegion.FindByPtr(base:Pointer):TsrSourceNode; var node:TsrSourceNode; begin Result:=nil; node:=FTop.First; while (node<>nil) do begin if node.InheritsFrom(TsrSourceAdr) then with TsrSourceAdr(node) do begin if (b_adr.get_code_ptr=base) then begin Exit(node); end else if (e_adr.get_code_ptr=base) then begin Exit(node); end; end; node:=flow_down_next_up(node); end; end; /// end.