unit emit_SOPP; {$mode objfpc}{$H+} interface uses sysutils, ps4_pssl, srType, srCFGParser, srCFGLabel, srCFGCursor, srFlow, srReg, srOp, srOpUtils, spirv, emit_fetch; type TEmit_SOPP=class(TEmitFetch) procedure emit_SOPP; procedure emit_S_BRANCH_COND(pSlot:PsrRegSlot;n:Boolean); procedure emit_S_BRANCH; procedure mark_end_of; function IsBegLoop(Adr:TSrcAdr):Boolean; function IsEndLoop(Adr:TSrcAdr):Boolean; function IsUnknow(Adr:TSrcAdr):Boolean; procedure emit_cond_block(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr); procedure emit_block_unknow(adr:TSrcAdr); procedure UpBuildVol(last:PsrOpBlock); procedure emit_loop(adr:TSrcAdr); procedure emit_loop_cond(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr); end; implementation procedure TEmit_SOPP.emit_cond_block(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr); var src:PsrRegNode; pOpBlock:PsrOpBlock; pOpChild:PsrOpBlock; pOpLabel:array[0..1] of PspirvOp; pLBlock:PsrCFGBlock; Info:array[0..1] of TsrBlockInfo; begin src:=MakeRead(pSlot,dtBool); //get before OpBranchConditional pOpLabel[0]:=NewLabelOp(False); pOpLabel[1]:=NewLabelOp(False); pLBlock:=Cursor.pCode^.FTop.DownBlock(adr); Assert(pLBlock<>@Cursor.pCode^.FTop,'not found'); Info[0]:=Default(TsrBlockInfo); Info[1]:=Default(TsrBlockInfo); Case pLBlock^.bType of btAdr: //set new adr begin Info[0].b_adr:=Cursor.Adr; Info[0].e_adr:=Cursor.Adr; Info[0].bType:=btCond; // Info[1].b_adr:=pLBlock^.pBLabel^.Adr; Info[1].e_adr:=pLBlock^.pELabel^.Adr; Info[1].bType:=btAdr; end; btCond: //normal cond begin Info[0].b_adr:=pLBlock^.pBLabel^.Adr; Info[0].e_adr:=pLBlock^.pELabel^.Adr; Info[0].bType:=btCond; // Info[1].b_adr:=Info[0].b_adr; Info[1].e_adr:=Info[0].e_adr; Info[1].bType:=btOther; end; else Assert(false,'emit_cond_block'); end; pOpLabel[0]^.Adr:=Info[0].b_adr; pOpLabel[1]^.Adr:=Info[0].e_adr; pOpBlock:=NewBlockOp(get_snapshot); pOpBlock^.SetLabels(pOpLabel[0],pOpLabel[1],nil); pOpBlock^.SetInfo(Info[0]); pOpBlock^.SetCond(src,not n); PushBlockOp(line,pOpBlock,pLBlock); OpCondMerge(line,pOpLabel[1]); Case n of True :OpBranchCond(line,pOpLabel[1],pOpLabel[0],src); False:OpBranchCond(line,pOpLabel[0],pOpLabel[1],src); end; AddSpirvOp(line,pOpLabel[0]); //down group pOpChild:=AllocBlockOp; pOpChild^.SetInfo(Info[1]); PushBlockOp(line,pOpChild,nil); if (pLBlock^.bType=btAdr) then //set new adr begin SetPtr(adr.get_pc,btAdr); end; end; procedure TEmit_SOPP.UpBuildVol(last:PsrOpBlock); var node:PsrOpBlock; begin node:=Main^.pBlock; While (node<>nil) do begin Case node^.Block.bType of btCond:PrivateList.build_volatile_cur(node^.Regs.pSnap_cur); btLoop:PrivateList.build_volatile_brk(node^.Regs.pSnap_cur); else; end; if (node=last) then Break; node:=node^.Parent; end; end; procedure TEmit_SOPP.emit_loop(adr:TSrcAdr); var node,pOpBlock:PsrOpBlock; pOpLabel:PspirvOp; FVolMark:TsrVolMark; bnew:Boolean; begin node:=Main^.pBlock; pOpBlock:=node^.FindUpLoop; Assert(pOpBlock<>nil,'not found'); pOpLabel:=nil; FVolMark:=vmNone; if (pOpBlock^.Block.b_adr.get_pc=adr.get_pc) then //is continue? begin pOpLabel:=pOpBlock^.Labels.pMrgOp; //-> OpLoopMerge end -> OpLoopMerge before pOpBlock^.Cond.FUseCont:=True; FVolMark:=vmCont; end else if (pOpBlock^.Block.b_adr.get_pc=adr.get_pc) then //is break? begin pOpLabel:=pOpBlock^.Labels.pEndOp; FVolMark:=vmBreak; end else begin Assert(false,'emit_loop'); end; Assert(pOpLabel<>nil); bnew:=true; if Cursor.pBlock^.IsEndOf(Cursor.Adr) then //is last begin //Assert(node^.Block.e_adr.get_pc=Cursor.Adr.get_pc); Case node^.Block.bType of btSetpc:; else begin bnew:=false; end; end; end; UpBuildVol(pOpBlock); node^.Regs.FVolMark:=FVolMark; //mark end of OpBranch(line,pOpLabel); if bnew then begin AddSpirvOp(line,NewLabelOp(True)); end; end; procedure TEmit_SOPP.emit_loop_cond(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr); var src:PsrRegNode; node,pOpBlock:PsrOpBlock; pOpLabel:array[0..1] of PspirvOp; FVolMark:TsrVolMark; begin src:=MakeRead(pSlot,dtBool); node:=Main^.pBlock; pOpBlock:=node^.FindUpLoop; Assert(pOpBlock<>nil,'not found'); pOpLabel[0]:=nil; FVolMark:=vmNone; if (pOpBlock^.Block.b_adr.get_pc=adr.get_pc) then //is continue? begin pOpLabel[0]:=pOpBlock^.Labels.pMrgOp; //-> OpLoopMerge end -> OpLoopMerge before pOpBlock^.Cond.FUseCont:=True; FVolMark:=vmCont; end else if (pOpBlock^.Block.b_adr.get_pc=adr.get_pc) then //is break? begin pOpLabel[0]:=pOpBlock^.Labels.pEndOp; FVolMark:=vmBreak; end else begin Assert(false,'emit_loop'); end; Assert(pOpLabel[0]<>nil); pOpLabel[1]:=NewLabelOp(False); UpBuildVol(pOpBlock); node^.Regs.FVolMark:=FVolMark; //mark end of OpCondMerge(line,pOpLabel[1]); Case n of True :OpBranchCond(line,pOpLabel[0],pOpLabel[1],src); False:OpBranchCond(line,pOpLabel[1],pOpLabel[0],src); end; AddSpirvOp(line,pOpLabel[1]); end; function TEmit_SOPP.IsBegLoop(Adr:TSrcAdr):Boolean; var node:PsrCFGBlock; begin Result:=false; node:=Cursor.pBlock^.FindUpLoop; if (node<>nil) then begin Result:=node^.pBLabel^.Adr.get_pc=Adr.get_pc; end; end; function TEmit_SOPP.IsEndLoop(Adr:TSrcAdr):Boolean; var node:PsrCFGBlock; begin Result:=false; node:=Cursor.pBlock^.FindUpLoop; if (node<>nil) then begin Result:=node^.pELabel^.Adr.get_pc=Adr.get_pc; end; end; function TEmit_SOPP.IsUnknow(Adr:TSrcAdr):Boolean; var pLabel:PsrLabel; begin pLabel:=FindLabel(Adr); Assert(pLabel<>nil); Result:=pLabel^.IsType(ltUnknow); end; procedure TEmit_SOPP.emit_S_BRANCH_COND(pSlot:PsrRegSlot;n:Boolean); var c_adr,b_adr:TSrcAdr; pLabel:PsrLabel; begin c_adr:=Cursor.Adr; b_adr:=c_adr; b_adr.Offdw:=get_branch_offset(FSPI); pLabel:=FindLabel(b_adr); Assert(pLabel<>nil); //Assert(not pLabel^.IsType(ltUnknow)); if pLabel^.IsType(ltBegAdr) then //adr begin emit_cond_block(pSlot,n,b_adr); end else if (SmallInt(FSPI.SOPP.SIMM)<0) then //up begin //continue? if not IsBegLoop(b_adr) then Assert(false,'Unknow'); emit_loop_cond(pSlot,n,b_adr); end else begin //down if Cursor.pBlock^.IsBigOf(b_adr) then begin //break? if not IsEndLoop(b_adr) then Assert(false,'Unknow'); emit_loop_cond(pSlot,n,b_adr); end else begin //cond emit_cond_block(pSlot,n,c_adr); end; end; end; procedure TEmit_SOPP.emit_block_unknow(adr:TSrcAdr); var c_adr:TSrcAdr; e_adr:TSrcAdr; pOpChild:PsrOpBlock; Info:TsrBlockInfo; begin Info:=Default(TsrBlockInfo); c_adr:=Cursor.Adr; //get current SetPtr(adr.get_pc,btAdrBranch); //set new e_adr:=Cursor.pCode^.FTop.pELabel^.Adr; //get end of code SetPtr(c_adr.get_pc,btMain); //ret current Info.b_adr:=adr; Info.e_adr:=e_adr; Info.bType:=btAdrBranch; //down group pOpChild:=AllocBlockOp; pOpChild^.SetInfo(Info); PushBlockOp(line,pOpChild,nil); SetPtr(adr.get_pc,btAdrBranch); end; procedure TEmit_SOPP.emit_S_BRANCH; var c_adr,b_adr:TSrcAdr; begin c_adr:=Cursor.Adr; b_adr:=c_adr; b_adr.Offdw:=get_branch_offset(FSPI); if IsUnknow(b_adr) then begin emit_block_unknow(b_adr); end else if (SmallInt(FSPI.SOPP.SIMM)<0) then //up begin //continue? if not IsBegLoop(b_adr) then Assert(false,'Unknow'); emit_loop(b_adr); end else //down begin //break? if not IsEndLoop(b_adr) then Assert(false,'Unknow'); emit_loop(b_adr); end; end; procedure TEmit_SOPP.mark_end_of; begin Main^.pBlock^.Regs.FVolMark:=vmEnd; //mark end of end; procedure TEmit_SOPP.emit_SOPP; begin Case FSPI.SOPP.OP of S_NOP, S_WAITCNT:; S_TTRACEDATA:; //write_thread_trace_data(M0[31:0]) S_ENDPGM: begin if not is_term_op(line) then begin AddSpirvOp(Op.OpReturn); end; mark_end_of; end; S_CBRANCH_SCC0 :emit_S_BRANCH_COND(get_scc ,false); S_CBRANCH_SCC1 :emit_S_BRANCH_COND(get_scc ,true); S_CBRANCH_VCCZ :emit_S_BRANCH_COND(get_vcc0 ,false); S_CBRANCH_VCCNZ :emit_S_BRANCH_COND(get_vcc0 ,true); S_CBRANCH_EXECZ :emit_S_BRANCH_COND(get_exec0,false); S_CBRANCH_EXECNZ:emit_S_BRANCH_COND(get_exec0,true); S_BRANCH :emit_S_BRANCH; else Assert(false,'SOPP?'+IntToStr(FSPI.SOPP.OP)); end; end; end.