unit srFlow; {$mode objfpc}{$H+} interface uses sysutils, ps4_pssl, spirv, srNode, srCFGLabel, srCFGParser, srCFGCursor, srReg, srOp, srOpUtils, srConfig, emit_op; type TEmitFlow=class(TEmitOp) // Procedure InitFlow; Procedure PushBlockOp(pLine:PspirvOp;pChild:PsrOpBlock;pLBlock:PsrCFGBlock); function PopBlockOp:Boolean; function CheckBlockBeg:Boolean; function CheckBlockEnd:Boolean; // function GetPtr:Pointer; procedure SetPtr(base:Pointer;bType:TsrBlockType); function IsFinalize:Boolean; function FindLabel(Adr:TSrcAdr):PsrLabel; // procedure Finalize; // function NextParse:Byte; function ParseStage(base:Pointer):Byte; end; implementation Procedure TEmitFlow.InitFlow; begin CodeHeap.Init(Self); // InitBlock:=AllocBlockOp; InitBlock^.SetInfo(btOther,Cursor.Adr,Cursor.Adr); PushBlockOp(line,InitBlock,nil); Main^.PopBlock; end; Procedure TEmitFlow.PushBlockOp(pLine:PspirvOp;pChild:PsrOpBlock;pLBlock:PsrCFGBlock); begin pChild^.FCursor:=Cursor; //prev InsSpirvOp(pLine,PspirvOp(pChild)); Main^.PushBlock(pChild); if (pLBlock<>nil) then begin Cursor.pBlock:=pLBlock; //push end; end; procedure UpdateVolMark(pBlock:PsrOpBlock); var pChild:PsrOpBlock; begin if (not pBlock^.IsType(ntOpBlock)) then Exit; if (pBlock^.Regs.FVolMark<>vmNone) then Exit; pChild:=pBlock^.line; //last if (not pChild^.IsType(ntOpBlock)) then Exit; Case pChild^.Block.bType of btCond, btLoop:Exit; else; end; pBlock^.Regs.FVolMark:=pChild^.Regs.FVolMark; end; function TEmitFlow.PopBlockOp:Boolean; var pOpBlock:PsrOpBlock; pOpChild:PsrOpBlock; pOpLabel:array[0..2] of PspirvOp; branch_up:Boolean; procedure pop_cond; begin Assert(pOpLabel[1]<>nil); if not is_term_op(line) then begin OpBranch(line,pOpLabel[1]); end; AddSpirvOp(line,pOpLabel[1]); //end end; procedure pop_cond_after; begin if (pOpBlock^.Regs.FVolMark<>vmEnd) then begin PrivateList.build_volatile_cur(pOpBlock^.Regs.pSnap_org); end else begin PrivateList.build_volatile_dis(pOpBlock^.Regs.pSnap_org); end; end; procedure pop_loop; begin //add OpLoopMerge continue Assert(pOpLabel[0]<>nil); Assert(pOpLabel[1]<>nil); Assert(pOpLabel[2]<>nil); if pOpBlock^.Cond.FUseCont then //use continue begin if not is_term_op(line) then begin OpBranch(line,pOpLabel[1]); //break end; AddSpirvOp(line,pOpLabel[2]); //OpLoopMerge end pOpChild:=AllocBlockOp; pOpChild^.SetInfo(btOther,Cursor.Adr,Cursor.Adr); PushBlockOp(line,pOpChild,nil); OpBranch(line,pOpLabel[0]); //continue Main^.PopBlock; AddSpirvOp(line,pOpLabel[1]); //end end else //dont used continue begin if not is_term_op(line) then begin AddSpirvOp(line,NewLabelOp(True)); //devide end; AddSpirvOp(line,pOpLabel[2]); //OpLoopMerge end pOpChild:=AllocBlockOp; pOpChild^.SetInfo(btOther,Cursor.Adr,Cursor.Adr); PushBlockOp(line,pOpChild,nil); OpBranch(line,pOpLabel[1]); //break Main^.PopBlock; AddSpirvOp(line,pOpLabel[1]); //end end; end; procedure pop_loop_after; begin PrivateList.build_volatile_old(pOpBlock^.Regs.pSnap_org); end; procedure pop_else; begin if (pOpLabel[1]<>nil) then begin if not is_term_op(line) then begin OpBranch(line,pOpLabel[1]); end; AddSpirvOp(line,pOpLabel[1]); end; end; begin Result:=False; if (Main=nil) then Exit; branch_up:=False; repeat pOpBlock:=Main^.pBlock; if (pOpBlock=nil) then Exit; UpdateVolMark(pOpBlock); pOpLabel[0]:=pOpBlock^.Labels.pBegOp; pOpLabel[1]:=pOpBlock^.Labels.pEndOp; pOpLabel[2]:=pOpBlock^.Labels.pMrgOp; Case pOpBlock^.Block.bType of btCond: begin pop_cond; branch_up:=False; end; btLoop: begin pop_loop; branch_up:=False; end; else pop_else; end; Case pOpBlock^.Block.bType of btAdr: begin Cursor:=pOpBlock^.FCursor; end; btAdrBranch: begin Cursor:=pOpBlock^.FCursor; branch_up:=True; end; btOther:; //nop else begin Cursor.PopBlock; end; end; Result:=Main^.PopBlock; Case pOpBlock^.Block.bType of btCond: begin pop_cond_after; //PrivateList.build_volatile_test; end; btLoop: begin pop_loop_after; //PrivateList.build_volatile_test; end; else begin //PrivateList.build_volatile_test; end; end; until (not branch_up) or (not Result); end; function TEmitFlow.CheckBlockBeg:Boolean; var pLBlock:PsrCFGBlock; pOpLabel:array[0..3] of PspirvOp; pOpBlock:PsrOpBlock; pOpChild:PsrOpBlock; adr:TSrcAdr; Info:TsrBlockInfo; begin Result:=False; adr:=Cursor.Adr; if (FindLabel(adr)=nil) then Exit; pLBlock:=Cursor.pBlock^.FindBlock(adr); if (pLBlock<>nil) then Case pLBlock^.bType of btLoop: begin PrivateList.make_copy_all; Info:=Default(TsrBlockInfo); Info.b_adr:=pLBlock^.pBLabel^.Adr; Info.e_adr:=pLBlock^.pELabel^.Adr; Info.bType:=btLoop; pOpLabel[0]:=NewLabelOp(False); //continue pOpLabel[1]:=NewLabelOp(False); //end pOpLabel[2]:=NewLabelOp(False); //cond pOpLabel[3]:=NewLabelOp(False); //start pOpLabel[0]^.Adr:=Info.b_adr; pOpLabel[1]^.Adr:=Info.e_adr; pOpLabel[2]^.Adr:=Info.e_adr; pOpLabel[3]^.Adr:=Info.b_adr; pOpBlock:=NewBlockOp(RegsStory.get_snapshot); pOpBlock^.SetLabels(pOpLabel[0],pOpLabel[1],pOpLabel[2]); pOpBlock^.SetInfo(Info); PushBlockOp(line,pOpBlock,pLBlock); OpBranch(line,pOpLabel[0]); AddSpirvOp(line,pOpLabel[0]); //continue loop OpLoopMerge(line,pOpLabel[1],pOpLabel[2]); OpBranch(line,pOpLabel[3]); AddSpirvOp(line,pOpLabel[3]); //down group Info.bType:=btOther; pOpChild:=AllocBlockOp; pOpChild^.SetInfo(Info); PushBlockOp(line,pOpChild,nil); end; btAdr, btAdrBranch: //skip begin adr:=pLBlock^.pELabel^.Adr; Cursor.Adr:=adr; end; else; end; end; function TEmitFlow.CheckBlockEnd:Boolean; begin Result:=False; if (Main=nil) then Exit; if (Main^.pBlock=nil) then Exit; if (Main^.pBlock^.Parent<>nil) and Main^.pBlock^.IsEndOf(Cursor.Adr) then begin Result:=PopBlockOp; end; end; // function TEmitFlow.GetPtr:Pointer; begin Result:=Cursor.Adr.get_pc; end; procedure TEmitFlow.SetPtr(base:Pointer;bType:TsrBlockType); begin if (Cursor.Adr.get_pc=base) then Exit; Cursor:=CodeHeap.FetchByPtr(base,bType); end; function TEmitFlow.IsFinalize:Boolean; begin Result:=False; if (Main^.pBlock^.Parent=nil) then if Cursor.pBlock^.IsEndOf(Cursor.Adr) then begin Result:=True; end; end; function TEmitFlow.FindLabel(Adr:TSrcAdr):PsrLabel; begin Result:=nil; if (Cursor.pCode=nil) then Exit; Result:=Cursor.pCode^.FindLabel(Adr); end; procedure TEmitFlow.Finalize; begin if (Main=nil) then Exit; if (Main^.pBlock<>nil) then While (Main^.pBlock^.Parent<>nil) do begin PopBlockOp; end; AddSpirvOp(Op.OpFunctionEnd); end; // function TEmitFlow.NextParse:Byte; var FLevel:DWORD; begin if (Cursor.pCode=nil) then Exit(2); if (Cursor.pBlock=nil) then Exit(3); if (Main=nil) then Exit(4); if (Main^.pBlock=nil) then Exit(5); if Config.PrintAsm then begin Write(HexStr(Cursor.OFFSET_DW*4,4)); //Write('(',GetGlobalIndex(line),')'); FLevel:=0; if (Main<>nil) then if (Main^.pBlock<>nil) then begin FLevel:=Main^.pBlock^.Level; end; Write(Space(FLevel+1)); end; Result:=Cursor.Next(FSPI); if (Result>1) then Exit; if Config.PrintAsm then begin print_spi(FSPI); end; emit_spi; While (CheckBlockBeg) do; While (CheckBlockEnd) do; Result:=0; if IsFinalize then begin Finalize; Result:=1; end; end; function TEmitFlow.ParseStage(base:Pointer):Byte; begin Result:=0; SetPtr(base,btMain); Main^.pTop^.SetCFGBlock(Cursor.pBlock); While (CheckBlockBeg) do; repeat Result:=NextParse; Case Result of 0:; 1:Break; else Break; end; until false; end; end.