fpPS4/spirv/srFlow.pas
2022-11-05 17:48:13 +03:00

442 lines
7.9 KiB
ObjectPascal

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.