fpPS4/spirv/emit_sopp.pas

390 lines
8.1 KiB
ObjectPascal
Raw Normal View History

2022-05-31 07:17:14 +00:00
unit emit_SOPP;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srParser,
srLabel,
srCFG,
srReg,
srOp,
srOpUtils,
spirv,
SprvEmit,
emit_op;
type
TEmit_SOPP=object(TEmitOp)
procedure _emit_SOPP;
procedure _emit_S_BRANCH_COND(pSlot:PsrRegSlot;n:Boolean);
procedure _emit_S_BRANCH;
function IsBegLoop(Adr:TSrcAdr):Boolean;
function IsEndLoop(Adr:TSrcAdr):Boolean;
2022-06-30 09:59:08 +00:00
function IsUnknow(Adr:TSrcAdr):Boolean;
2022-05-31 07:17:14 +00:00
procedure emit_cond_block(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr);
2022-06-30 09:59:08 +00:00
procedure emit_block_unknow(adr:TSrcAdr);
2022-05-31 07:17:14 +00:00
procedure UpBuildVol(last:PsrOpBlock);
procedure emit_loop(adr:TSrcAdr);
2022-07-01 12:53:39 +00:00
procedure emit_loop_cond(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr);
2022-05-31 07:17:14 +00:00
end;
implementation
uses
srVolatile;
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;
pOpLabel[1]:=NewLabelOp;
pLBlock:=FCursor.pCode^.FTop.DownBlock(adr);
Assert(pLBlock<>@FCursor.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:=FCursor.Adr;
Info[0].e_adr:=FCursor.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(FRegsStory.get_snapshot);
pOpBlock^.SetLabels(pOpLabel[0],pOpLabel[1],nil);
pOpBlock^.SetInfo(Info[0]);
pOpBlock^.SetCond(src,not n);
PushBlockOp(line,pOpBlock,pLBlock);
emit_OpCondMerge(line,pOpLabel[1]);
Case n of
True :emit_OpBranchCond(line,pOpLabel[1],pOpLabel[0],src);
False:emit_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:=FMain^.pBlock;
While (node<>nil) do
begin
Case node^.Block.bType of
btCond:TEmitVolatile(Self).build_volatile_cur(node^.Regs.pSnap);
btLoop:TEmitVolatile(Self).build_volatile_old(node^.Regs.pSnap);
else;
end;
if (node=last) then Break;
node:=node^.pParent;
end;
end;
procedure TEmit_SOPP.emit_loop(adr:TSrcAdr);
var
node,pOpBlock:PsrOpBlock;
pOpLabel:array[0..1] of PspirvOp;
FVolMark:TsrVolMark;
bnew:Boolean;
begin
node:=FMain^.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);
bnew:=true;
if FCursor.pBlock^.IsEndOf(FCursor.Adr) then //is last
begin
Assert(node^.Block.e_adr.get_pc=FCursor.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
emit_OpBranch(line,pOpLabel[0]);
if bnew then
begin
pOpLabel[1]:=NewLabelOp;
AddSpirvOp(line,pOpLabel[1]);
end;
end;
2022-07-01 12:53:39 +00:00
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:=FMain^.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;
UpBuildVol(pOpBlock);
node^.Regs.FVolMark:=FVolMark; //mark end of
emit_OpCondMerge(line,pOpLabel[1]);
Case n of
True :emit_OpBranchCond(line,pOpLabel[0],pOpLabel[1],src);
False:emit_OpBranchCond(line,pOpLabel[1],pOpLabel[0],src);
end;
AddSpirvOp(line,pOpLabel[1]);
end;
2022-05-31 07:17:14 +00:00
function TEmit_SOPP.IsBegLoop(Adr:TSrcAdr):Boolean;
var
node:PsrCFGBlock;
begin
Result:=false;
node:=FCursor.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:=FCursor.pBlock^.FindUpLoop;
if (node<>nil) then
begin
Result:=node^.pELabel^.Adr.get_pc=Adr.get_pc;
end;
end;
2022-06-30 09:59:08 +00:00
function TEmit_SOPP.IsUnknow(Adr:TSrcAdr):Boolean;
var
pLabel:PsrLabel;
begin
pLabel:=FindLabel(Adr);
Assert(pLabel<>nil);
Result:=pLabel^.IsType(ltUnknow);
end;
2022-05-31 07:17:14 +00:00
procedure TEmit_SOPP._emit_S_BRANCH_COND(pSlot:PsrRegSlot;n:Boolean);
var
c_adr,b_adr:TSrcAdr;
pLabel:PsrLabel;
begin
c_adr:=FCursor.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');
2022-07-01 12:53:39 +00:00
emit_loop_cond(pSlot,n,b_adr);
2022-05-31 07:17:14 +00:00
end else
begin //down
if FCursor.pBlock^.IsBigOf(b_adr) then
begin //break?
if not IsEndLoop(b_adr) then Assert(false,'Unknow');
2022-07-01 12:53:39 +00:00
emit_loop_cond(pSlot,n,b_adr);
2022-05-31 07:17:14 +00:00
end else
begin //cond
emit_cond_block(pSlot,n,c_adr);
end;
end;
end;
2022-06-30 09:59:08 +00:00
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:=FCursor.Adr; //get current
SetPtr(adr.get_pc,btAdr); //set new
e_adr:=FCursor.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:=btAdr;
//down group
pOpChild:=AllocBlockOp;
pOpChild^.SetInfo(Info);
PushBlockOp(line,pOpChild,nil);
SetPtr(adr.get_pc,btAdr);
end;
2022-05-31 07:17:14 +00:00
procedure TEmit_SOPP._emit_S_BRANCH;
var
c_adr,b_adr:TSrcAdr;
begin
c_adr:=FCursor.Adr;
b_adr:=c_adr;
b_adr.Offdw:=get_branch_offset(FSPI);
2022-06-30 09:59:08 +00:00
if IsUnknow(b_adr) then
begin
emit_block_unknow(b_adr);
end else
2022-05-31 07:17:14 +00:00
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._emit_SOPP;
begin
Case FSPI.SOPP.OP of
S_NOP,
S_WAITCNT:;
S_ENDPGM:
begin
if not is_term_op(line) then
begin
AddSpirvOp(Op.OpReturn);
end;
FMain^.pBlock^.Regs.FVolMark:=vmEnd; //mark end of
end;
S_CBRANCH_SCC0 :_emit_S_BRANCH_COND(@FRegsStory.SCC,false);
S_CBRANCH_SCC1 :_emit_S_BRANCH_COND(@FRegsStory.SCC,true);
S_CBRANCH_VCCZ :_emit_S_BRANCH_COND(@FRegsStory.VCC[0],false);
S_CBRANCH_VCCNZ :_emit_S_BRANCH_COND(@FRegsStory.VCC[0],true);
S_CBRANCH_EXECZ :_emit_S_BRANCH_COND(@FRegsStory.EXEC[0],false);
S_CBRANCH_EXECNZ:_emit_S_BRANCH_COND(@FRegsStory.EXEC[0],true);
S_BRANCH :_emit_S_BRANCH;
else
Assert(false,'SOPP?'+IntToStr(FSPI.SOPP.OP));
end;
end;
end.