FPPS4/spirv/SprvEmit.pas

1751 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

unit SprvEmit;
{$mode objfpc}{$H+}
interface
uses
sysutils,
si_ci_vi_merged_registers,
ps4_pssl,
srAllocator,
srNodes,
srBitcast,
srLabel,
srCFG,
srParser,
srTypes,
srConst,
srReg,
srOp,
srOpUtils,
srCap,
srRefId,
srDecorate,
srLayout,
srVertLayout,
srFragLayout,
srBuffer,
srVariable,
srInput,
srOutput,
srUniform,
spirv;
type
TLocalSize=packed record
x,y,z:DWORD;
end;
PSprvEmit=^TSprvEmit;
TSprvEmit=object
FAllocator:TsrAllocator;
FCodeHeap:TsrCodeHeap;
FCursor:TsrCursor;
FLocalSize:TLocalSize;
FExecutionModel:Word;
FRegsStory:TsrRegsStory;
FVolatileID:SizeUint;
FInputs:TsrInputList;
FDataLayouts:TsrDataLayoutList;
FVertLayouts:TsrVertLayoutList;
FFragLayouts:TsrFragLayoutList;
FBuffers:TsrBufferList;
FOutputs:TsrOutputList;
FVariables:TsrVariableList;
FUniforms:TsrUniformList;
FCacheOps:TsrCacheOpList;
FConsts:TsrConstList;
FBitcast:TsrBitcastList;
FSpirvIdAlloc:TsrRefIdAlloc;
FSpirvTypes:TsrTypeList;
FSpirvFuncs:TsrFuncList;
FSpirvCaps:TsrCapList;
FDebugInfo:TsrDebugInfoList;
FDecorates:TsrDecorateList;
FMain:PSpirvFunc;
FInitLine:PsrOpBlock;
FGLSL_std_450:PSpirvOp;
FHeader:TsrOpBlockSimple;
FSPI:TSPI;
FPrintAsm:Boolean;
FUseVertexInput:Boolean;
FUseTexelBuffer:Boolean;
FUseOutput16:Boolean;
function Alloc(Size:ptruint):Pointer;
procedure SetPtr(base:Pointer;bType:TsrBlockType);
function Parse(base:Pointer):Byte;
function NextParse:Byte;
function IsFinalize:Boolean;
function FindLabel(Adr:TSrcAdr):PsrLabel;
function CheckBlockBeg:Boolean;
function CheckBlockEnd:Boolean;
procedure Finalize;
function NewLabelOp:PSpirvOp;
function NewMain:PSpirvFunc;
procedure AddCap(ID:DWORD);
function AllocBlockOp:PsrOpBlock;
function NewBlockOp(Snap:TsrRegsSnapshot):PsrOpBlock;
function InsertBlockOp(pLine:PspirvOp;pChild:PsrOpBlock):PspirvOp;
Procedure PushBlockOp(pLine:PspirvOp;pOpBlock:PsrOpBlock;pLBlock:PsrCFGBlock);
function PopBlockOp:Boolean;
function NewSpirvOp(OpId:DWORD):PSpirvOp;
function AddSpirvOp(OpId:DWORD):PSpirvOp;
function AddSpirvOp(pLine:PspirvOp;OpId:DWORD):PSpirvOp;
function AddSpirvOp(pLine,pNew:PspirvOp):PSpirvOp;
function line:PSpirvOp;
function init_line:PSpirvOp;
procedure PostLink(ntype:TsrNodeType;Data:Pointer);
procedure PostReg(pReg:PsrRegNode);
function NewRefId:PsrRefId;
function NewVariable:PsrVariable;
function AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):PsrRegNode;
function AllocDescVar(p:Pointer;_ntype:TsrNodeType;rtype:TsrDataType):PsrVariable;
function AddVertLayout(pLayout:PsrDataLayout;rtype:TsrDataType):PsrRegNode;
function AddFragLayout(itype:TpsslInputType;rtype:TsrDataType;location:DWORD):PsrRegNode;
function FetchLoad(pChain:PsrChain;rtype:TsrDataType):PsrRegNode;
Procedure FetchStore(pChain:PsrChain;src:PsrRegNode);
procedure AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
function FetchChain(grp:PsrDataLayout;offset,size:DWORD;ext:PsrChainExt):PsrRegNode;
function MakeChain(pSlot:PsrRegSlot;grp:PsrDataLayout;offset,size:PtrUint;ext:PsrChainExt):PsrRegNode;
Procedure AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
function FetchUniform(src:PsrDataLayout;pType:PsrType):PsrRegNode;
function FetchImage(src:PsrDataLayout;dtype:TsrDataType;info:TsrTypeImageInfo):PsrRegNode;
function FetchSampler(src:PsrDataLayout):PsrRegNode;
function FetchOutput(etype:TpsslExportType;rtype:TsrDataType):PsrVariable;
Procedure Init;
procedure SetUserData(pData:Pointer);
Procedure InitVs(RSRC2:TSPI_SHADER_PGM_RSRC2_VS;instance:Byte);
Procedure InitPs(RSRC2:TSPI_SHADER_PGM_RSRC2_PS;ENA:TSPI_PS_INPUT_ENA);
Procedure InitCs(RSRC2:TCOMPUTE_PGM_RSRC2;NTX:TCOMPUTE_NUM_THREAD_X;NTY:TCOMPUTE_NUM_THREAD_Y;NTZ:TCOMPUTE_NUM_THREAD_Z);
Function NewReg(rtype:TsrDataType):PsrRegNode;
Function FetchReg(pConst:PsrConst):PsrRegNode;
Procedure SetConst(pSlot:PsrRegSlot;pConst:PsrConst);
Procedure SetConst(pSlot:PsrRegSlot;dtype:TsrDataType;value:QWORD);
function fetch_soffset(SOFFSET:Word;rtype:TsrDataType):PsrRegNode;
function fetch_ssrc9(SSRC:Word;rtype:TsrDataType):PsrRegNode;
function fetch_ssrc9_pair(src:PPsrRegNode;SSRC:Word;rtype:TsrDataType):Boolean;
function fetch_vsrc8(VSRC:Word;rtype:TsrDataType):PsrRegNode;
function fetch_vdst8(VDST:Word;rtype:TsrDataType):PsrRegNode;
procedure fetch_vsrc8_vec2h(VSRC:Word;var dst0,dst1:PsrRegNode);
procedure _MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
procedure MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
function GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):PsrDataLayout;
procedure PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType);
function MakeRead(pSlot:PsrRegSlot;rtype:TsrDataType):PsrRegNode;
procedure LoadPrepType(node:PsrRegNode;p:PspirvOp;rtype:TsrDataType);
procedure RegPrepType(node:PsrRegNode;rtype:TsrDataType);
procedure _emit_spi;
procedure _emit_DS;
procedure _emit_SOPK;
end;
function RegDown(node:PsrRegNode):PsrRegNode;
function RegDownSlot(node:PsrRegNode):PsrRegNode;
Procedure mark_read(const node:TOpParamSingle);
Procedure mark_write(const node:TOpParamSingle);
function GetChainRegNode(node:PsrRegNode):PsrChain;
function GetSourceRegNode(node:PsrRegNode):TOpParamSingle;
function GetInputRegNode(node:PsrRegNode):PsrInput;
implementation
uses
srVolatile,
emit_op,
emit_SOP1,
emit_SOP2,
emit_SOPC,
emit_SOPP,
emit_VOP1,
emit_VOP2,
emit_VOP3,
emit_VOPC,
emit_MUBUF,
emit_MTBUF,
emit_EXP,
emit_VINTRP,
emit_SMRD,
emit_MIMG;
function TSprvEmit.Alloc(Size:ptruint):Pointer;
begin
Result:=FAllocator.Alloc(Size);
end;
procedure TSprvEmit.SetPtr(base:Pointer;bType:TsrBlockType);
begin
if (FCursor.Adr.get_pc=base) then Exit;
FCursor:=FCodeHeap.FetchByPtr(base,bType);
end;
function TSprvEmit.Parse(base:Pointer):Byte;
begin
SetPtr(base,btMain);
FMain^.FTop.SetCFGBlock(FCursor.pBlock);
While (CheckBlockBeg) do;
repeat
Result:=NextParse;
Case Result of
0:;
1:Break;
else
Break;
end;
until false;
end;
function TSprvEmit.NextParse:Byte;
var
FLevel:DWORD;
begin
if (FCursor.pCode=nil) then Exit(2);
if (FCursor.pBlock=nil) then Exit(3);
if (FMain=nil) then Exit(4);
if (FMain^.pBlock=nil) then Exit(5);
if FPrintAsm then
begin
Write(HexStr(FCursor.OFFSET_DW*4,4));
FLevel:=0;
if (FMain<>nil) then
if (FMain^.pBlock<>nil) then
begin
FLevel:=FMain^.pBlock^.FLevel;
end;
Write(Space(FLevel+1));
end;
Result:=FCursor.Next(FSPI);
if (Result>1) then Exit;
if FPrintAsm 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 TSprvEmit.IsFinalize:Boolean;
begin
Result:=False;
if (FMain^.pBlock^.pParent=nil) then
if FCursor.pBlock^.IsEndOf(FCursor.Adr) then
begin
Result:=True;
end;
end;
function TSprvEmit.FindLabel(Adr:TSrcAdr):PsrLabel;
begin
Result:=nil;
if (FCursor.pCode=nil) then Exit;
Result:=FCursor.pCode^.FindLabel(Adr);
end;
function TSprvEmit.CheckBlockBeg:Boolean;
var
pLBlock:PsrCFGBlock;
pOpLabel:array[0..3] of PspirvOp;
pOpBlock:PsrOpBlock;
pOpChild:PsrOpBlock;
adr:TSrcAdr;
Info:TsrBlockInfo;
begin
Result:=False;
adr:=FCursor.Adr;
if (FindLabel(adr)=nil) then Exit;
pLBlock:=FCursor.pBlock^.FindBlock(adr);
if (pLBlock<>nil) then
Case pLBlock^.bType of
btLoop:
begin
TEmitVolatile(Self).make_copy_all;
Info:=Default(TsrBlockInfo);
Info.b_adr:=pLBlock^.pBLabel^.Adr;
Info.e_adr:=pLBlock^.pELabel^.Adr;
Info.bType:=btLoop;
pOpLabel[0]:=NewLabelOp; //continue
pOpLabel[1]:=NewLabelOp; //end
pOpLabel[2]:=NewLabelOp; //cond
pOpLabel[3]:=NewLabelOp; //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(FRegsStory.get_snapshot);
pOpBlock^.SetLabels(pOpLabel[0],pOpLabel[1],pOpLabel[2]);
pOpBlock^.SetInfo(Info);
PushBlockOp(line,pOpBlock,pLBlock);
TEmitOp(Self).emit_OpBranch(line,pOpLabel[0]);
AddSpirvOp(line,pOpLabel[0]); //continue loop
TEmitOp(Self).emit_OpLoopMerge(line,pOpLabel[1],pOpLabel[2]);
TEmitOp(Self).emit_OpBranch(line,pOpLabel[3]);
AddSpirvOp(line,pOpLabel[3]);
//down group
Info.bType:=btOther;
pOpChild:=AllocBlockOp;
pOpChild^.SetInfo(Info);
PushBlockOp(line,pOpChild,nil);
end;
btAdr: //skip
begin
adr:=pLBlock^.pELabel^.Adr;
FCursor.Adr:=adr;
end;
else;
end;
end;
function TSprvEmit.CheckBlockEnd:Boolean;
begin
Result:=False;
if (FMain=nil) then Exit;
if (FMain^.pBlock=nil) then Exit;
if (FMain^.pBlock^.pParent<>nil) and
FMain^.pBlock^.IsEndOf(FCursor.Adr) then
begin
Result:=PopBlockOp;
end;
end;
procedure TSprvEmit.Finalize;
begin
if (FMain=nil) then Exit;
if (FMain^.pBlock<>nil) then
While (FMain^.pBlock^.pParent<>nil) do
begin
PopBlockOp;
end;
AddSpirvOp(Op.OpFunctionEnd);
end;
//%void = OpTypeVoid;
//%f_void = OpTypeFunction %void;
//%f_main = OpFunction %void None %f_void;
//%l_main = OpLabel;
function TSprvEmit.NewLabelOp:PSpirvOp;
Var
node:PSpirvOp;
begin
node:=NewSpirvOp(Op.OpLabel);
node^.dst.SetParam(ntRefId,NewRefId);
Result:=node;
end;
function TSprvEmit.NewMain:PSpirvFunc;
var
tvoid,tftype:PsrType;
node:PspirvOp;
begin
FMain:=Alloc(SizeOf(TSpirvFunc));
FMain^.Init('main',@Alloc);
FMain^.mark_read;
//OpTypeVoid
tvoid:=FSpirvTypes.Fetch(dtTypeVoid);
//OpTypeFunction
tftype:=FSpirvTypes.FetchFunction(tvoid);
//OpFunction
node:=@FMain^.FTop.dummy;
node^.OpId:=Op.OpFunction;
node^.dst_type:=tvoid;
node^.dst.SetParam(ntFunc,FMain); //self
node^.AddLiteral(FunctionControl.None,'None');
node^.AddParam(ntType,tftype);
//OpLabel
node:=NewLabelOp;
FMain^.AddSpirvOp(node);
Result:=FMain;
end;
procedure TSprvEmit.AddCap(ID:DWORD);
begin
FSpirvCaps.Add(ID);
end;
function TSprvEmit.AllocBlockOp:PsrOpBlock;
begin
Result:=Alloc(SizeOf(TsrOpBlock));
Result^.Alloc:=@Alloc;
Result^.dummy.pParent:=Result;
Result^.Push_head(@Result^.dummy);
end;
function TSprvEmit.NewBlockOp(Snap:TsrRegsSnapshot):PsrOpBlock;
begin
Result:=AllocBlockOp;
Result^.Regs.pSnap :=Alloc(SizeOf(TsrRegsSnapshot));
Result^.Regs.pSnap^:=Snap;
Result^.Regs.FVolMark:=vmNone;
Result^.Cond.FUseCont:=false;
end;
function TSprvEmit.InsertBlockOp(pLine:PspirvOp;pChild:PsrOpBlock):PspirvOp;
begin
pLine:=AddSpirvOp(pLine,OpBlock);
pLine^.dst.SetParam(ntBlock,pChild);
pChild^.pParent:=pLine^.pParent;
pChild^.pUpLine:=pLine;
pChild^.FLevel :=pLine^.pParent^.FLevel+1;
Result:=pLine;
end;
Procedure TSprvEmit.PushBlockOp(pLine:PspirvOp;pOpBlock:PsrOpBlock;pLBlock:PsrCFGBlock);
var
node:PSpirvOp;
begin
pOpBlock^.FCursor:=FCursor; //prev
node:=AddSpirvOp(pLine,OpBlock);
node^.dst.SetParam(ntBlock,pOpBlock);
pOpBlock^.pUpLine:=node;
FMain^.PushBlock(pOpBlock);
if (pLBlock<>nil) then
begin
FCursor.pBlock:=pLBlock; //push
end;
end;
procedure UpdateVolMark(pBlock:PsrOpBlock);
var
pLine:PspirvOp;
pChild:PsrOpBlock;
begin
if (pBlock=nil) then Exit;
if (pBlock^.Regs.FVolMark<>vmNone) then Exit;
pLine:=pBlock^.line;
if (pLine=nil) then Exit;
if (pLine^.OpId<>OpBlock) then Exit;
pChild:=pLine^.dst.AsBlock;
if (pChild=nil) then Exit;
Case pChild^.Block.bType of
btAdr,
btOther:;
else
Exit;
end;
pBlock^.Regs.FVolMark:=pChild^.Regs.FVolMark;
end;
function TSprvEmit.PopBlockOp:Boolean;
var
pOpBlock:PsrOpBlock;
pOpChild:PsrOpBlock;
pOpLabel:array[0..2] of PspirvOp;
begin
Result:=False;
if (FMain=nil) then Exit;
if (FMain^.pBlock=nil) then Exit;
pOpBlock:=FMain^.pBlock;
UpdateVolMark(pOpBlock);
pOpLabel[0]:=pOpBlock^.Labels.pBegOp;
pOpLabel[1]:=pOpBlock^.Labels.pEndOp;
pOpLabel[2]:=pOpBlock^.Labels.pMrgOp;
Case pOpBlock^.Block.bType of
btCond:
begin
Assert(pOpLabel[1]<>nil);
Case pOpBlock^.Regs.FVolMark of
vmNone:TEmitVolatile(Self).build_volatile_cur(pOpBlock^.Regs.pSnap);
vmEnd :TEmitVolatile(Self).build_volatile_dis(pOpBlock^.Regs.pSnap);
else;
end;
if not is_term_op(line) then
begin
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]);
end;
AddSpirvOp(line,pOpLabel[1]); //end
end;
btLoop:
begin
//add OpLoopMerge continue
Assert(pOpLabel[0]<>nil);
Assert(pOpLabel[1]<>nil);
Assert(pOpLabel[2]<>nil);
Case pOpBlock^.Regs.FVolMark of
vmNone:TEmitVolatile(Self).build_volatile_old(pOpBlock^.Regs.pSnap);
else;
end;
if pOpBlock^.Cond.FUseCont then //use continue
begin
if not is_term_op(line) then
begin
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]); //break
end;
AddSpirvOp(line,pOpLabel[2]); //OpLoopMerge end
pOpChild:=AllocBlockOp;
pOpChild^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,pOpChild,nil);
TEmitOp(Self).emit_OpBranch(line,pOpLabel[0]); //continue
FMain^.PopBlock;
AddSpirvOp(line,pOpLabel[1]); //end
end else //dont used continue
begin
if not is_term_op(line) then
begin
AddSpirvOp(line,NewLabelOp); //devide
end;
AddSpirvOp(line,pOpLabel[2]); //OpLoopMerge end
pOpChild:=AllocBlockOp;
pOpChild^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,pOpChild,nil);
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]); //break
FMain^.PopBlock;
AddSpirvOp(line,pOpLabel[1]); //end
end;
end;
else
if (pOpLabel[1]<>nil) then
begin
if not is_term_op(line) then
begin
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]);
end;
AddSpirvOp(line,pOpLabel[1]);
end;
end;
Case pOpBlock^.Block.bType of
btAdr:
begin
FCursor:=pOpBlock^.FCursor;
end;
btOther:; //nop
else
begin
FCursor.PopBlock;
end;
end;
Result:=FMain^.PopBlock;
end;
function TSprvEmit.NewSpirvOp(OpId:DWORD):PSpirvOp;
begin
Result:=Alloc(SizeOf(TSpirvOp));
Result^.adr :=FCursor.Adr;
Result^.OpId :=OpId;
end;
function TSprvEmit.AddSpirvOp(OpId:DWORD):PSpirvOp;
begin
Result:=AddSpirvOp(line,OpId);
end;
function TSprvEmit.AddSpirvOp(pLine:PspirvOp;OpId:DWORD):PSpirvOp;
begin
Result:=InsSpirvOp(pLine,NewSpirvOp(OpId));
end;
function TSprvEmit.AddSpirvOp(pLine,pNew:PspirvOp):PSpirvOp;
begin
Result:=InsSpirvOp(pLine,pNew);
end;
function TSprvEmit.line:PSpirvOp;
begin
Result:=nil;
if (FMain<>nil) then
begin
Result:=FMain^.line;
end;
end;
function TSprvEmit.init_line:PSpirvOp;
begin
Assert(FInitLine<>nil);
if (FInitLine^.dummy.pParent=nil) then
begin
FInitLine^.Alloc:=@Alloc;
FInitLine^.dummy.pParent:=FInitLine;
FInitLine^.Push_head(@FInitLine^.dummy);
end;
Result:=FInitLine^.line;
Assert(Result<>nil);
end;
procedure TSprvEmit.PostLink(ntype:TsrNodeType;Data:Pointer);
var
node:PspirvOp;
begin
node:=line;
if (node=nil) or (node^.OpId<>OpLinks) then
begin
node:=AddSpirvOp(OpLinks);
end;
node^.AddParam(ntype,Data);
end;
procedure TSprvEmit.PostReg(pReg:PsrRegNode);
begin
PostLink(ntReg,pReg);
end;
function TSprvEmit.NewRefId:PsrRefId;
begin
Result:=Alloc(SizeOf(TsrRefId));
end;
function TSprvEmit.NewVariable:PsrVariable;
begin
Result:=Alloc(SizeOf(TsrVariable));
FVariables.Push_tail(Result);
end;
function TSprvEmit.AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):PsrRegNode;
var
i:PsrInput;
v:PsrVariable;
r:PsrRegNode;
begin
i:=FInputs.Fetch(itype,id);
v:=i^.pVar;
r:=i^.pReg;
if (v=nil) then
begin
v:=NewVariable;
v^.dtype:=rtype;
v^.pSource.SetParam(ntInput,i);
i^.pVar:=v;
end;
if (r=nil) then
begin
r:=dst^.New(line,rtype);
i^.pReg :=r;
v^.mark_read;
TEmitOp(Self).emit_OpLoad(init_line,r,v); //one in any scope
end else
if (dst^.current<>r) then
begin
MakeCopy(dst,r);
end;
Result:=r;
end;
function TSprvEmit.AllocDescVar(p:Pointer;_ntype:TsrNodeType;rtype:TsrDataType):PsrVariable;
var
d:PsrDescriptor;
begin
Result:=nil;
if (p=nil) then Exit;
d:=p;
if (d^.pVar=nil) then
begin
d^.pVar:=NewVariable;
d^.pVar^.dtype:=rtype;
d^.pVar^.pSource.SetParam(_ntype,p);
end;
Result:=d^.pVar;
end;
function TSprvEmit.AddVertLayout(pLayout:PsrDataLayout;rtype:TsrDataType):PsrRegNode;
var
i:PsrVertLayout;
v:PsrVariable;
dst:PsrRegNode;
begin
i:=FVertLayouts.Fetch(pLayout);
v:=AllocDescVar(i,ntVertLayout,rtype);
dst:=i^.pReg;
if (dst=nil) then
begin
dst:=NewReg(rtype);
i^.pReg:=dst;
v^.mark_read;
TEmitOp(Self).emit_OpLoad(init_line,dst,v); //one in any scope
end;
Result:=dst;
end;
function TSprvEmit.AddFragLayout(itype:TpsslInputType;rtype:TsrDataType;location:DWORD):PsrRegNode;
var
i:PsrFragLayout;
v:PsrVariable;
dst:PsrRegNode;
begin
i:=FFragLayouts.Fetch(itype,location);
v:=AllocDescVar(i,ntFragLayout,rtype);
dst:=i^.pReg;
if (dst=nil) then
begin
dst:=NewReg(rtype);
i^.pReg:=dst;
v^.mark_read;
TEmitOp(Self).emit_OpLoad(init_line,dst,v); //one in any scope
end;
Result:=dst;
end;
function TSprvEmit.FetchLoad(pChain:PsrChain;rtype:TsrDataType):PsrRegNode;
var
dtype:TsrDataType;
src:TOpParamSingle;
begin
Result:=nil;
if (pChain=nil) then Exit;
dtype:=pChain^.GetRegType;
if (dtype=dtUnknow) and (rtype<>dtUnknow) then
begin
dtype:=rtype;
pChain^.SetRegType(dtype);
end;
Result:=pChain^.rSlot.New(line,dtype);
pChain^.mark_read;
src:=Default(TOpParamSingle);
src.SetParam(ntChain,pChain);
TEmitOp(Self).emit_OpLoad(line,FSpirvTypes.Fetch(dtype),Result,src);
if not CompareType(dtype,rtype) then
begin
MakeCopy(@FRegsStory.FUnattach,Result);
Result:=FRegsStory.FUnattach.current;
Result^.dtype:=rtype;
end;
end;
Procedure TSprvEmit.FetchStore(pChain:PsrChain;src:PsrRegNode);
var
dtype:TsrDataType;
dst:TOpParamSingle;
pReg:PsrRegNode;
begin
if (pChain=nil) or (src=nil) then Exit;
dtype:=pChain^.GetRegType;
if (dtype=dtUnknow) and (src^.dtype<>dtUnknow) then
begin
dtype:=src^.dtype;
pChain^.SetRegType(dtype);
end;
pReg:=pChain^.rSlot.New(line,dtype);
pReg^.mark_read;
pChain^.mark_write;
dst:=Default(TOpParamSingle);
dst.SetParam(ntChain,pChain);
TEmitOp(Self).emit_OpStore(line,dst,pReg);
pReg^.pLine:=line; //update line
pReg^.pWriter.SetParam(ntReg,src);
end;
procedure TSprvEmit.AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
var
pLayout:PsrDataLayout;
pChain:PsrChain;
pReg:PsrRegNode;
begin
pLayout:=FDataLayouts.Fetch(nil,0,rtBufPtr2);
pChain:=pLayout^.Fetch(offset_dw*4,4,nil);
pReg:=FetchLoad(pChain,dtUnknow);
MakeCopy(dst,pReg);
end;
function TSprvEmit.FetchChain(grp:PsrDataLayout;offset,size:DWORD;ext:PsrChainExt):PsrRegNode;
var
pChain:PsrChain;
begin
pChain:=grp^.Fetch(offset,size,ext);
Result:=FetchLoad(pChain,dtUnknow);
end;
function TSprvEmit.MakeChain(pSlot:PsrRegSlot;grp:PsrDataLayout;offset,size:PtrUint;ext:PsrChainExt):PsrRegNode;
var
pChain:PsrChain;
pReg:PsrRegNode;
begin
pChain:=grp^.Fetch(offset,size,ext);
pReg:=FetchLoad(pChain,dtUnknow);
MakeCopy(pSlot,pReg);
Result:=pSlot^.current;
end;
Procedure TSprvEmit.AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
var
rsl:PsrRegNode;
begin
rsl:=AddInput(@FRegsStory.FUnattach,vtype,itype,0);
rsl^.mark_read;
dst^.New(line,rtype);
TEmitOp(Self).emit_OpCompExtract(init_line,dst^.current,rsl,id);
end;
////
function TSprvEmit.FetchUniform(src:PsrDataLayout;pType:PsrType):PsrRegNode;
var
pUniform:PsrUniform;
v:PsrVariable;
dst:PsrRegNode;
p:TOpParamSingle;
begin
pUniform:=FUniforms.Fetch(src,pType);
v:=AllocDescVar(pUniform,ntUniform,pType^.dtype);
if (v^.pType=nil) then
begin
v^.pType:=FSpirvTypes.FetchPointer(pType,pUniform^.FStorage);
end;
dst:=pUniform^.pReg;
if (dst=nil) then
begin
dst:=NewReg(pType^.dtype);
pUniform^.pReg:=dst;
v^.mark_read;
pType^.mark_read;
p.SetParam(ntVar,v);
TEmitOp(Self).emit_OpLoad(init_line,pType,dst,p); //one in any scope
end;
Result:=dst;
end;
function TSprvEmit.FetchImage(src:PsrDataLayout;dtype:TsrDataType;info:TsrTypeImageInfo):PsrRegNode;
var
pType:PsrType;
begin
pType:=FSpirvTypes.FetchImage(FSpirvTypes.Fetch(dtype),info);
Result:=FetchUniform(src,pType);
end;
function TSprvEmit.FetchSampler(src:PsrDataLayout):PsrRegNode;
var
pType:PsrType;
begin
pType:=FSpirvTypes.Fetch(dtTypeSampler);
Result:=FetchUniform(src,pType);
end;
function TSprvEmit.FetchOutput(etype:TpsslExportType;rtype:TsrDataType):PsrVariable;
var
o:PsrOutput;
begin
o:=FOutputs.Fetch(etype);
if (o^.pVar=nil) then
begin
o^.pVar:=NewVariable;
o^.pVar^.dtype:=rtype;
o^.pVar^.pSource.SetParam(ntOutput,o);
end;
o^.pVar^.mark_read;
Result:=o^.pVar;
end;
Procedure TSprvEmit.Init;
begin
FillChar(Self,SizeOf(TSprvEmit),0);
FUseVertexInput:=True;
FRegsStory .Init(@Alloc);
FOutputs .Init;
FCodeHeap .Alloc:=@Alloc;
FInputs .Init(@Alloc);
FDataLayouts.Init(@Alloc);
FVertLayouts.Init(@Alloc);
FFragLayouts.Alloc:=@Alloc;
FBuffers .Init(@Alloc);
FUniforms .Alloc:=@Alloc;
FCacheOps .Alloc:=@Alloc;
FConsts .Alloc:=@Alloc;
FBitcast .pRoot:=@Self;
FSpirvTypes .Alloc:=@Alloc;
FSpirvCaps .Alloc:=@Alloc;
FDebugInfo .Init(@Alloc);
FDecorates .Init(@Alloc);
FHeader .Init(@Alloc);
FSpirvFuncs.Insert(NewMain);
SetConst(@FRegsStory.VCC[0] ,dtBool,0);
SetConst(@FRegsStory.VCC[1] ,dtBool,0);
SetConst(@FRegsStory.EXEC[0],dtBool,1);
SetConst(@FRegsStory.EXEC[1],dtBool,0);
FInitLine:=AllocBlockOp;
FInitLine^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,FInitLine,nil);
FMain^.PopBlock;
end;
procedure TSprvEmit.SetUserData(pData:Pointer);
begin
FDataLayouts.SetUserData(pData);
end;
Procedure TSprvEmit.InitVs(RSRC2:TSPI_SHADER_PGM_RSRC2_VS;instance:Byte);
var
p:Byte;
begin
Init;
FExecutionModel:=ExecutionModel.Vertex;
//sgrp
p:=0;
if (RSRC2.USER_SGPR<>0) then
For p:=p to RSRC2.USER_SGPR-1 do
begin
AddUserdata(@FRegsStory.SGRP[p],p);
end;
p:=RSRC2.USER_SGPR;
if (RSRC2.SO_EN<>0) or
(RSRC2.OC_LDS_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itVsState);
p:=p+1;
//s_vs_state
// stream_id[1:0], is_offchip[2],
// streamout_vtx_count[6:0],
// streamout_enable[15:0]}
end;
if (RSRC2.SO_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itWriteIndex);
p:=p+1;
//s_so_write_index
// streamout_write_index[31:0]
end;
if (RSRC2.SO_BASE0_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,0);
p:=p+1;
//s_so_base_offset0
// streamout_offset0[31:0]
end;
if (RSRC2.SO_BASE1_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,1);
p:=p+1;
//s_so_base_offset1
// streamout_offset1[31:0]
end;
if (RSRC2.SO_BASE2_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,2);
p:=p+1;
//s_so_base_offset2
// streamout_offset2[31:0]
end;
if (RSRC2.SO_BASE3_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,3);
p:=p+1;
//s_so_base_offset3
// streamout_offset3[31:0]
end;
Assert(RSRC2.OC_LDS_EN=0);
if (RSRC2.DISPATCH_DRAW_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itWaveId);
p:=p+1;
//s_wave_id
// wave_id [11:0] (dispatch draw term)
end;
if (RSRC2.SCRATCH_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itScratch);
p:=p+1;
//s_scratch
// scratch offset (in bytes)
end;
//vgrp
p:=1;
AddInput(@FRegsStory.VGRP[0],dtUint32,itVIndex);
if (instance>=1) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itVInstance,1);
p:=p+1;
end;
if (instance>=2) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itVInstance,2);
p:=p+1;
end;
if (instance>=3) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itVInstance,0);
end;
AddCap(Capability.Shader);
end;
Procedure TSprvEmit.InitPs(RSRC2:TSPI_SHADER_PGM_RSRC2_PS;ENA:TSPI_PS_INPUT_ENA);
var
p:Byte;
begin
Init;
FExecutionModel:=ExecutionModel.Fragment;
//sgrp
p:=0;
if (RSRC2.USER_SGPR<>0) then
For p:=p to RSRC2.USER_SGPR-1 do
begin
AddUserdata(@FRegsStory.SGRP[p],p);
end;
p:=RSRC2.USER_SGPR;
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itPsState);
p:=p+1;
//s_ps_state
// {bc_optimize, prim_mask[14:0],
// lds_offset[15:0]}
end;
if (RSRC2.WAVE_CNT_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itWaveCnt);
p:=p+1;
//(s_wave_cnt)
// {ps_wave_id[9:0], ps_strap_id,
// ps_pkr_id}
end;
if (RSRC2.SCRATCH_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itScratch);
p:=p+1;
//s_scratch
// scratch offset (in bytes)
end;
//vgrp
p:=0;
if (ENA.PERSP_SAMPLE_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspSample,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspSample,1);
p:=p+1;
end;
if (ENA.PERSP_CENTER_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCenter,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCenter,1);
p:=p+1;
end;
if (ENA.PERSP_CENTROID_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCentroid,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCentroid,1);
p:=p+1;
end;
if (ENA.PERSP_PULL_MODEL_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspW,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspW,1);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspW,2);
p:=p+1;
end;
if (ENA.LINEAR_SAMPLE_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearSample,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearSample,1);
p:=p+1;
end;
if (ENA.LINEAR_CENTER_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCenter,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCenter,1);
p:=p+1;
end;
if (ENA.LINEAR_CENTROID_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCentroid,0);
p:=p+1;
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCentroid,1);
p:=p+1;
end;
if (ENA.POS_X_FLOAT_ENA<>0) then
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,0);
p:=p+1;
end;
if (ENA.POS_Y_FLOAT_ENA<>0) then
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,1);
p:=p+1;
end;
if (ENA.POS_Z_FLOAT_ENA<>0) then
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,2);
p:=p+1;
end;
if (ENA.POS_W_FLOAT_ENA<>0) then
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,3);
p:=p+1;
end;
if (ENA.FRONT_FACE_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itFrontFace);
p:=p+1;
end;
if (ENA.ANCILLARY_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itAncillary);
p:=p+1;
//Render target array index[26:16], Iterated sample number[11:8], Primitive type[1:0]
end;
if (ENA.SAMPLE_COVERAGE_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itSampleCoverage);
p:=p+1;
end;
if (ENA.POS_FIXED_PT_ENA<>0) then
begin
AddInput(@FRegsStory.VGRP[p],dtUint32,itPosFixed);
p:=p+1;
//Per-pixel fixed point position Y[31:16], X[15:0]
end;
AddCap(Capability.Shader);
end;
Procedure TSprvEmit.InitCs(RSRC2:TCOMPUTE_PGM_RSRC2;NTX:TCOMPUTE_NUM_THREAD_X;NTY:TCOMPUTE_NUM_THREAD_Y;NTZ:TCOMPUTE_NUM_THREAD_Z);
var
p:Byte;
begin
Init;
FExecutionModel:=ExecutionModel.GLCompute;
p:=0;
if (RSRC2.USER_SGPR<>0) then
For p:=p to RSRC2.USER_SGPR-1 do
begin
AddUserdata(@FRegsStory.SGRP[p],p);
end;
p:=RSRC2.USER_SGPR;
if (RSRC2.TGID_X_EN<>0) then
begin
AddVecInput(@FRegsStory.SGRP[p],dtVec3u,dtUint32,itTgid,0);
p:=p+1;
//(s_tgid_x) threadgroup_id0[31:0] computePgmRsrc2.tgid_x_en;tgid_x_en(1) //gl_WorkGroupID
end;
if (RSRC2.TGID_Y_EN<>0) then
begin
AddVecInput(@FRegsStory.SGRP[p],dtVec3u,dtUint32,itTgid,1);
p:=p+1;
//(s_tgid_y) threadgroup_id1[31:0] computePgmRsrc2.tgid_y_en;tgid_y_en(1) //gl_WorkGroupID
end;
if (RSRC2.TGID_Z_EN<>0) then
begin
AddVecInput(@FRegsStory.SGRP[p],dtVec3u,dtUint32,itTgid,2);
p:=p+1;
//(s_tgid_z) threadgroup_id2[31:0] computePgmRsrc2.tgid_z_en;tgid_z_en(1) //gl_WorkGroupID
end;
if (RSRC2.TG_SIZE_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itTgSize);
p:=p+1;
//(s_tg_size) //gl_NumWorkGroups ???
{first_wave, 14b0,
ordered_append_term[10:0],
threadgroup_size_in_waves[5:0]} //computePgmRsrc2.tg_size_en;tg_size_en(1)
end;
if (RSRC2.SCRATCH_EN<>0) then
begin
AddInput(@FRegsStory.SGRP[p],dtUint32,itScratch);
p:=p+1;
//s_scratch
// scratch offset (in bytes)
end;
//vgrp
p:=0;
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec3u,dtUint32,itThreadId,0);
p:=p+1;
//(v_thread_id_x) Thread ID in group 0 //gl_LocalInvocationID
end;
if (RSRC2.TIDIG_COMP_CNT>=1) then
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec3u,dtUint32,itThreadId,1);
p:=p+1;
//(v_thread_id_y) Thread ID in group 1 //gl_LocalInvocationID
end;
if (RSRC2.TIDIG_COMP_CNT>=2) then
begin
AddVecInput(@FRegsStory.VGRP[p],dtVec3u,dtUint32,itThreadId,2);
p:=p+1;
//(v_thread_id_z) Thread ID in group 2 //gl_LocalInvocationID
end;
FLocalSize.x:=NTX.NUM_THREAD_FULL+NTX.NUM_THREAD_PARTIAL;
FLocalSize.y:=NTY.NUM_THREAD_FULL+NTY.NUM_THREAD_PARTIAL;
FLocalSize.z:=NTZ.NUM_THREAD_FULL+NTZ.NUM_THREAD_PARTIAL;
if (FLocalSize.x=0) then FLocalSize.x:=1;
if (FLocalSize.y=0) then FLocalSize.y:=1;
if (FLocalSize.z=0) then FLocalSize.z:=1;
AddCap(Capability.Shader);
end;
Function TSprvEmit.NewReg(rtype:TsrDataType):PsrRegNode;
begin
Result:=FRegsStory.FUnattach.New(line,rtype);
end;
Function TSprvEmit.FetchReg(pConst:PsrConst):PsrRegNode;
begin
if (pConst=nil) then Exit(nil);
Result:=NewReg(pConst^.key.dtype);
Result^.SetConst(pConst);
Result^.mark_read;
end;
Procedure TSprvEmit.SetConst(pSlot:PsrRegSlot;pConst:PsrConst);
var
dst:PsrRegNode;
begin
dst:=pSlot^.New(line,pConst^.key.dtype);
dst^.SetConst(pConst);
dst^.mark_read;
PostReg(dst); //post processing
end;
Procedure TSprvEmit.SetConst(pSlot:PsrRegSlot;dtype:TsrDataType;value:QWORD);
begin
SetConst(pSlot,FConsts.Fetch(dtype,value));
end;
function TSprvEmit.fetch_soffset(SOFFSET:Word;rtype:TsrDataType):PsrRegNode;
Var
src:PsrRegSlot;
pConst:PsrConst;
begin
if is_const_ssrc8(SOFFSET) then
begin
pConst:=FConsts.Fetch_ssrc8_const(SOFFSET,0,rtype);
Result:=FetchReg(pConst);
end else
begin
src:=FRegsStory.get_ssrc8(SOFFSET);
Result:=MakeRead(src,rtype);
end;
end;
function TSprvEmit.fetch_ssrc9(SSRC:Word;rtype:TsrDataType):PsrRegNode;
Var
src:PsrRegSlot;
pConst:PsrConst;
begin
if is_const_ssrc9(SSRC) then
begin
pConst:=FConsts.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype);
Result:=FetchReg(pConst);
end else
begin
src:=FRegsStory.get_ssrc9(SSRC);
Result:=MakeRead(src,rtype);
end;
end;
function TSprvEmit.fetch_ssrc9_pair(src:PPsrRegNode;SSRC:Word;rtype:TsrDataType):Boolean;
Var
pSlot:array[0..1] of PsrRegSlot;
begin
if is_const_ssrc9(SSRC) then
begin
src[0]:=FetchReg(FConsts.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype));
src[1]:=FetchReg(FConsts.Fetch(dtUnknow,0));
Result:=True;
end else
begin
pSlot[0]:=nil;
pSlot[1]:=nil;
Result:=FRegsStory.get_ssrc9_pair(SSRC,pSlot);
if not Result then Exit;
src[0]:=MakeRead(pSlot[0],rtype);
src[1]:=MakeRead(pSlot[1],rtype);
end;
end;
function TSprvEmit.fetch_vsrc8(VSRC:Word;rtype:TsrDataType):PsrRegNode;
var
src:PsrRegSlot;
begin
src:=FRegsStory.get_vsrc8(VSRC);
Result:=MakeRead(src,rtype);
end;
function TSprvEmit.fetch_vdst8(VDST:Word;rtype:TsrDataType):PsrRegNode;
var
src:PsrRegSlot;
begin
src:=FRegsStory.get_vdst8(VDST);
Result:=MakeRead(src,rtype);
end;
procedure TSprvEmit.fetch_vsrc8_vec2h(VSRC:Word;var dst0,dst1:PsrRegNode);
var
pSlot:PsrRegSlot;
dst:PsrRegNode;
begin
pSlot:=FRegsStory.get_vsrc8(VSRC);
dst:=MakeRead(pSlot,dtVec2h);
dst^.mark_read;
dst0:=NewReg(dtHalf16);
dst1:=NewReg(dtHalf16);
dst0^.mark_read;
dst1^.mark_read;
TEmitOp(Self).emit_OpCompExtract(line,dst0,dst,0);
TEmitOp(Self).emit_OpCompExtract(line,dst1,dst,1);
end;
procedure TSprvEmit._MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
var
node:PsrRegNode;
begin
node:=dst^.New(line,src^.dtype);
node^.pWriter.SetParam(ntReg,src);
dst^.current^.mark_read;
PostReg(dst^.current); //post processing
end;
procedure TSprvEmit.MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
begin
src^.mark_read;
_MakeCopy(dst,src);
end;
function GetChainRegNode(node:PsrRegNode):PsrChain;
var
pOp:PSpirvOp;
begin
Result:=nil;
node:=RegDown(node);
pOp:=node^.AsOp;
if (pOp=nil) then Exit;
if (pOp^.OpId<>Op.OpLoad) then Exit;
Result:=pOp^.pParam.pHead^.AsChain;
end;
function GetSourceRegNode(node:PsrRegNode):TOpParamSingle;
var
pOp:PSpirvOp;
pVar:PsrVariable;
begin
Result:=Default(TOpParamSingle);
node:=RegDown(node);
pOp:=node^.AsOp;
if (pOp=nil) then Exit;
if (pOp^.OpId<>Op.OpLoad) then Exit;
pVar:=pOp^.pParam.pHead^.AsVar;
if (pVar=nil) then Exit;
Result:=pVar^.pSource;
end;
function GetInputRegNode(node:PsrRegNode):PsrInput;
var
pSource:TOpParamSingle;
begin
pSource:=GetSourceRegNode(node);
Result:=pSource.AsInput;
end;
//
function TSprvEmit.GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):PsrDataLayout;
var
i,n:Byte;
chain:TsrChains;
begin
Result:=nil;
chain:=Default(TsrChains);
n:=GetResourceSizeDw(rtype);
For i:=0 to n-1 do
begin
chain[i]:=GetChainRegNode(src[i]^.current);
end;
Result:=FDataLayouts.Grouping(chain,rtype);
end;
procedure TSprvEmit.PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType);
var
node:PsrRegNode;
begin
if (pSlot=nil) then Exit;
if (pSlot^.current=nil) then
begin
pSlot^.New(line,rtype); //Unresolve
Exit;
end;
if (rtype=dtUnknow) then Exit;
node:=pSlot^.current;
if (node^.dtype=dtUnknow) then
begin
RegPrepType(node,rtype);
end;
end;
function TSprvEmit.MakeRead(pSlot:PsrRegSlot;rtype:TsrDataType):PsrRegNode;
var
node:PsrRegNode;
begin
Result:=nil;
if (pSlot=nil) then Exit;
PrepTypeSlot(pSlot,rtype);
node:=pSlot^.current;
if (rtype<>dtUnknow) and (not CompareType(node^.dtype,rtype)) then
begin
Result:=FBitcast.FetchRead(rtype,node);
end else
begin
Result:=node;
Result^.mark_read;
end;
end;
procedure TSprvEmit.LoadPrepType(node:PsrRegNode;p:PspirvOp;rtype:TsrDataType);
var
pVar:PsrVariable;
pChain:PsrChain;
ctype:TsrDataType;
pReg:PsrRegNode;
begin
if (p^.pParam.pHead^.pData<>nil) then
Case p^.pParam.pHead^.ntype of
ntVar:
begin
pVar:=p^.pParam.pHead^.AsVar;
if (pVar^.dtype=dtUnknow) then
begin
pVar^.dtype:=rtype;
end;
end;
ntChain:
begin
pChain:=p^.pParam.pHead^.AsChain;
ctype:=pChain^.GetRegType;
if (ctype=dtUnknow) then
begin
pChain^.SetRegType(rtype);
end else
if (ctype<>rtype) then
begin
pChain^.SetRegType(rtype);
pReg:=NewReg(rtype);
pReg^.pLine :=node^.pLine;
pReg^.pWriter:=node^.pWriter;
pReg^.mark_read;
node^.pWriter.SetParam(ntReg,pReg);
rtype:=ctype;
end;
end;
else;
end;
if (p^.dst_type=nil) then
begin
p^.dst_type:=FSpirvTypes.Fetch(rtype);
end;
end;
procedure TSprvEmit.RegPrepType(node:PsrRegNode;rtype:TsrDataType);
var
n:PsrRegNode;
pConst:PsrConst;
pOp:PspirvOp;
begin
if (rtype<>dtUnknow) and (node^.dtype=dtUnknow) then
begin
node^.dtype:=rtype;
//backtrace
While (true) do
begin
Case node^.pWriter.ntype of
ntVolatile:Break; //ignore
ntReg:
begin
n:=node^.pWriter.pData; //next
if (n^.dtype=dtUnknow) then
begin
n^.dtype:=rtype;
end else
begin
Break;
end;
node:=n;
end;
ntConst:
begin
pConst:=node^.pWriter.pData;
pConst^.mark_unread;
pConst:=FConsts.Bitcast(rtype,pConst);
node^.pWriter.pData:=pConst;
Break;
end;
ntOp:
begin
pOp:=node^.AsOp;
if (pOp<>nil) then
Case pOp^.OpId of
Op.OpLoad:
begin
LoadPrepType(node,pOp,rtype);
end;
else;
end;
Break;
end;
else
Assert(false,'RegPrepType');
end;
end;
end;
end;
function RegDown(node:PsrRegNode):PsrRegNode;
var
tmp:PsrRegNode;
begin
//backtrace
Result:=node;
While (Result<>nil) do
begin
tmp:=Result^.AsReg; //next
if (tmp=nil) then Break;
Result:=tmp;
end;
end;
function RegDownSlot(node:PsrRegNode):PsrRegNode;
var
tmp:PsrRegNode;
begin
//backtrace
Result:=node;
While (Result<>nil) do
begin
tmp:=Result^.AsReg; //next
if (tmp=nil) then Break;
if (tmp^.pSlot<>Result^.pSlot) then Break;
Result:=tmp;
end;
end;
Procedure mark_read(const node:TOpParamSingle);
begin
Case node.ntype of
ntConst:PsrConst (node.pData)^.mark_read;
ntType :PsrType (node.pData)^.mark_read;
ntFunc :PSpirvFunc (node.pData)^.mark_read;
ntVar :PsrVariable(node.pData)^.mark_read;
ntReg :PsrRegNode (node.pData)^.mark_read;
ntChain:PsrChain (node.pData)^.mark_read;
else
Assert(false,'mark_read');
end;
end;
Procedure mark_write(const node:TOpParamSingle);
begin
Case node.ntype of
ntConst:PsrConst (node.pData)^.mark_read;
ntType :PsrType (node.pData)^.mark_read;
ntFunc :PSpirvFunc (node.pData)^.mark_read;
ntVar :PsrVariable(node.pData)^.mark_write;
ntReg :PsrRegNode (node.pData)^.mark_read;
ntChain:PsrChain (node.pData)^.mark_write;
else
Assert(false,'mark_write');
end;
end;
procedure TSprvEmit._emit_spi;
begin
Case FSPI.CMD.EN of
W_SOP1 :TEmit_SOP1(Self)._emit_SOP1;
W_SOPC :TEmit_SOPC(Self)._emit_SOPC;
W_SOPP :TEmit_SOPP(Self)._emit_SOPP;
W_VOP1 :TEmit_VOP1(Self)._emit_VOP1;
W_VOPC :TEmit_VOPC(Self)._emit_VOPC;
W_VOP3 :Case FSPI.VOP3a.OP of
0..255:TEmit_VOP3(Self)._emit_VOP3c;
293..298,
365..366:TEmit_VOP3(Self)._emit_VOP3b;
else
TEmit_VOP3(Self)._emit_VOP3a;
end;
W_DS :_emit_DS;
W_MUBUF :TEmit_MUBUF(Self)._emit_MUBUF;
W_MTBUF :TEmit_MTBUF(Self)._emit_MTBUF;
W_EXP :TEmit_EXP(Self)._emit_EXP;
W_VINTRP:TEmit_VINTRP(Self)._emit_VINTRP;
W_MIMG :TEmit_MIMG(Self)._emit_MIMG;
W_SMRD :TEmit_SMRD(Self)._emit_SMRD;
W_SOPK :_emit_SOPK;
W_SOP2 :TEmit_SOP2(Self)._emit_SOP2;
W_VOP2 :TEmit_VOP2(Self)._emit_VOP2;
else
Assert(false);
end;
end;
procedure TSprvEmit._emit_DS;
begin
Assert(false,'DS?'+IntToStr(FSPI.DS.OP));
end;
procedure TSprvEmit._emit_SOPK;
begin
Assert(false,'SOPK?'+IntToStr(FSPI.SOPK.OP));
end;
end.