add shader recompiler

This commit is contained in:
Pavel 2022-05-31 10:17:14 +03:00
parent 030ef0c198
commit d0f86ddcac
52 changed files with 27108 additions and 0 deletions

62
spirv/Half16.pas Normal file
View File

@ -0,0 +1,62 @@
unit Half16;
{$mode objfpc}{$H+}
interface
type
PHalf16=^THalf16;
THalf16=bitpacked record
man:0..1023;
exp:0..31;
sgn:0..1;
end;
operator := (i:THalf16):Single;
operator := (i:Single):THalf16;
implementation
operator := (i:THalf16):Single;
var
t1,t2,t3:DWORD;
begin
t1:=Word(i) and $7fff; // Non-sign bits
t2:=Word(i) and $8000; // Sign bit
t3:=Word(i) and $7c00; // Exponent
t1:=t1 shl 13; // Align mantissa on MSB
t2:=t2 shl 16; // Shift sign bit into position
t1:=t1+$38000000; // Adjust bias
if (t3=0) then t1:=0; // Denormals-as-zero
t1:=t1 or t2; // Re-insert sign bit
PDWORD(@Result)^:=t1;
end;
operator := (i:Single):THalf16;
var
t1,t2,t3:DWORD;
begin
t1:=PDWORD(@i)^ and $7fffffff; // Non-sign bits
t2:=PDWORD(@i)^ and $80000000; // Sign bit
t3:=PDWORD(@i)^ and $7f800000; // Exponent
t1:=t1 shr 13; // Align mantissa on MSB
t2:=t2 shr 16; // Shift sign bit into position
t1:=t1-$1c000; // Adjust bias
if (t3<$38800000) then t1:=0; // Flush-to-zero
if (t3>$47000000) then t1:=$7bff; // Clamp-to-max
t1:=t1 or t2; // Re-insert sign bit
Word(Result):=Word(t1);
end;
end.

1749
spirv/SprvEmit.pas Normal file

File diff suppressed because it is too large Load Diff

441
spirv/emit_alloc.pas Normal file
View File

@ -0,0 +1,441 @@
unit emit_alloc;
{$mode objfpc}{$H+}
interface
uses
sysutils,
spirv,
srNodes,
srTypes,
srConst,
srRefId,
srReg,
srLayout,
srBuffer,
srVariable,
srOp,
srOpUtils,
SprvEmit;
type
TSprvEmit_alloc=object(TSprvEmit)
procedure Alloc;
procedure AllocSpirvID(P:PsrRefId);
procedure AllocBinding;
procedure AllocTypeBinding;
procedure AllocSourceExtension;
procedure AllocTypeName;
Procedure AllocVarName;
procedure AllocEntryPoint;
procedure AllocHeader;
procedure AllocOpListId(node:PspirvOp);
procedure AllocHeaderId;
procedure AllocTypesId;
procedure AllocConstId;
procedure AllocVariableId;
procedure AllocOpSingle(const Param:TOpParamSingle);
procedure AllocOpParamNode(node:POpParamNode);
procedure AllocFuncId;
procedure AllocOpId(node:PSpirvOp);
procedure AllocOpBlock(pBlock:PsrOpBlock);
end;
implementation
procedure TSprvEmit_alloc.Alloc;
begin
AllocBinding;
AllocTypeBinding;
AllocHeader;
AllocSourceExtension;
AllocTypeName;
AllocVarName;
AllocHeaderId;
AllocTypesId;
AllocConstId;
AllocVariableId;
AllocFuncId;
end;
procedure TSprvEmit_alloc.AllocSpirvID(P:PsrRefId);
begin
FSpirvIdAlloc.FetchSpirvID(P);
end;
procedure TSprvEmit_alloc.AllocBinding;
var
FBinding:Integer;
begin
FInputs .AllocBinding(@FDecorates);
FOutputs .AllocBinding(@FDecorates);
FVertLayouts.AllocBinding(@FDecorates);
FFragLayouts.AllocBinding(@FDecorates);
FBinding:=0;
FUniforms.AllocBinding(FBinding,@FDecorates);
FBuffers .AllocBinding(FBinding,@FDecorates);
end;
procedure TSprvEmit_alloc.AllocTypeBinding;
var
node:PsrType;
pField:PsrField;
begin
node:=FSpirvTypes.FList.pHead;
While (node<>nil) do
begin
case node^.dtype of
dtTypeStruct:
begin
pField:=node^.key.ext.pField;
if (pField<>nil) then
begin
if (pField^.GetStructDecorate<>DWORD(-1)) then
begin
FDecorates.emit_decorate(ntType,node,pField^.GetStructDecorate,0);
end;
pField^.AllocBinding(node,@FDecorates);
end;
end;
dtTypeArray,
dtTypeRuntimeArray:
begin
FDecorates.emit_decorate(ntType,node,Decoration.ArrayStride,node^.key.ext.array_stride);
end;
else;
end;
node:=node^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocSourceExtension;
begin
FDataLayouts.AllocSourceExtension(@FDebugInfo);
FDataLayouts.AllocFuncExt(@FDebugInfo,FCodeHeap);
FVertLayouts.AllocSourceExtension(@FDebugInfo);
FUniforms .AllocSourceExtension(@FDebugInfo);
FBuffers .AllocSourceExtension(@FDebugInfo);
end;
procedure TSprvEmit_alloc.AllocTypeName;
var
node:PsrType;
pField:PsrField;
begin
node:=FSpirvTypes.FList.pHead;
While (node<>nil) do
begin
case node^.dtype of
dtTypeStruct:
begin
pField:=node^.key.ext.pField;
if (pField<>nil) and
(pField^.parent=nil) and
(pField^.pBuffer<>nil) then
begin
FDebugInfo.emit_name(ntType,node,pField^.pBuffer^.GetStructName);
end;
end;
else;
end;
node:=node^.pNext;
end;
end;
Procedure TSprvEmit_alloc.AllocVarName;
var
node:PsrVariable;
n:RawByteString;
begin
node:=FVariables.pHead;
While (node<>nil) do
begin
if (node^.pType<>nil) then
begin
n:=node^.GetName;
if (n<>'') then
begin
FDebugInfo.emit_name(ntVar,node,n);
end;
end;
node:=node^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocOpListId(node:PspirvOp);
begin
While (node<>nil) do
begin
AllocOpId(node);
node:=node^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocEntryPoint;
var
node:PSpirvOp;
begin
node:=FHeader.AddSpirvOp(Op.OpEntryPoint);
node^.AddLiteral(FExecutionModel,ExecutionModel.GetStr(FExecutionModel));
node^.AddParam(ntFunc,FMain);
node^.AddString(FMain^.name);
FInputs .AllocEntryPoint(node);
FVertLayouts.AllocEntryPoint(node);
FFragLayouts.AllocEntryPoint(node);
FOutputs .AllocEntryPoint(node);
end;
procedure TSprvEmit_alloc.AllocHeader;
var
node:PSpirvOp;
begin
node:=FHeader.AddSpirvOp(Op.OpMemoryModel);
node^.AddLiteral(AddressingModel.Logical,AddressingModel.GetStr(AddressingModel.Logical));
node^.AddLiteral(MemoryModel.GLSL450,MemoryModel.GetStr(MemoryModel.GLSL450));
AllocEntryPoint;
Case FExecutionModel of
ExecutionModel.Fragment:
begin
node:=FHeader.AddSpirvOp(Op.OpExecutionMode);
node^.AddParam(ntFunc,FMain);
node^.AddLiteral(ExecutionMode.OriginUpperLeft,ExecutionMode.GetStr(ExecutionMode.OriginUpperLeft));
end;
ExecutionModel.GLCompute:
begin
node:=FHeader.AddSpirvOp(Op.OpExecutionMode);
node^.AddParam(ntFunc,FMain);
node^.AddLiteral(ExecutionMode.LocalSize,ExecutionMode.GetStr(ExecutionMode.LocalSize));
node^.AddLiteral(FLocalSize.x);
node^.AddLiteral(FLocalSize.y);
node^.AddLiteral(FLocalSize.z);
end;
end;
end;
procedure TSprvEmit_alloc.AllocHeaderId;
begin
AllocOpListId(FHeader.pHead);
AllocOpListId(FDebugInfo.pHead);
AllocOpListId(FDecorates.pHead);
end;
procedure TSprvEmit_alloc.AllocTypesId;
var
node:PsrType;
pConst:PsrConst;
begin
node:=FSpirvTypes.FList.pHead;
While (node<>nil) do
begin
case node^.dtype of
dtTypeArray:
begin
//find a const
pConst:=FConsts.Fetchi(dtUInt32,node^.key.ext.array_count);
if (pConst^.pType=nil) then
begin
pConst^.pType:=FSpirvTypes.Fetch(pConst^.key.dtype);
AllocSpirvID(@pConst^.pType^.ID);
end;
FConsts.FList.Remove(pConst);
AllocSpirvID(@pConst^.ID);
end;
else;
end;
AllocSpirvID(@node^.ID);
node:=node^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocConstId;
var
node:PsrConst;
begin
node:=FConsts.FList.pHead;
While (node<>nil) do
begin
if (node^.key.dtype<>dtUnknow) then
begin
AllocSpirvID(@node^.ID)
end;
node:=node^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocVariableId;
var
node:PsrVariable;
begin
node:=FVariables.pHead;
While (node<>nil) do
begin
if (node^.pType<>nil) then
begin
AllocSpirvID(@node^.ID);
AllocSpirvID(@node^.pType^.ID);
end;
node:=node^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocOpSingle(const Param:TOpParamSingle);
var
pReg:PsrRegNode;
begin
Assert(Param.pData<>nil,'AllocOpSingle$1');
Case Param.ntype of
ntFunc:
begin
AllocSpirvID(@PSpirvFunc(Param.pData)^.ID);
end;
ntRefId:
begin
AllocSpirvID(Param.pData);
end;
ntType:
begin
AllocSpirvID(@PsrType(Param.pData)^.ID);
end;
ntReg:
begin
pReg:=Param.pData;
Case pReg^.pWriter.ntype of
ntConst:;
ntOp:AllocSpirvID(@pReg^.ID);
else
Assert(false,'AllocOpSingle$2');
end;
end;
ntVar:
begin
AllocSpirvID(@PsrVariable(Param.pData)^.ID);
end;
ntChain:
begin
AllocSpirvID(@PsrChain(Param.pData)^.ID);
end;
ntConst:
begin
AllocSpirvID(@PsrConst(Param.pData)^.ID)
end;
else
Assert(false,'AllocOpSingle$3');
end;
end;
procedure TSprvEmit_alloc.AllocOpParamNode(node:POpParamNode);
begin
Case node^.ntype of
ntLiteral:;
ntString :;
else
begin
AllocOpSingle(node^.AsParam);
end;
end;
end;
procedure TSprvEmit_alloc.AllocFuncId;
var
pFunc:PSpirvFunc;
begin
pFunc:=FSpirvFuncs.FList.pHead;
While (pFunc<>nil) do
begin
AllocOpBlock(@pFunc^.FTop);
pFunc:=pFunc^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocOpId(node:PSpirvOp);
var
Param:POpParamNode;
Info:Op.TOpInfo;
begin
if (node=nil) then Exit;
Info:=Op.GetInfo(node^.OpId);
if Info.result then //dst
begin
Assert(node^.dst.ntype<>ntUnknow,'AllocOp$1');
Assert(node^.dst.pData<>nil ,'AllocOp$2');
AllocOpSingle(node^.dst);
end else
begin //no dst
if (node^.dst.ntype<>ntUnknow) then
begin
Assert(node^.dst.pData<>nil,'AllocOp$3');
AllocOpSingle(node^.dst);
end;
end;
if Info.rstype then //dst type
begin
Assert(node^.dst_type<>nil,'AllocOp$4');
end;
Param:=node^.pParam.pHead;
While (Param<>nil) do
begin
AllocOpParamNode(Param);
Param:=Param^.pNext;
end;
end;
procedure TSprvEmit_alloc.AllocOpBlock(pBlock:PsrOpBlock);
var
node:PSpirvOp;
begin
if (pBlock=nil) then Exit;
node:=pBlock^.pHead;
While (node<>nil) do
begin
if (node^.OpId=OpBlock) then
begin
if (node^.dst.ntype=ntBlock) then
begin
AllocOpBlock(node^.dst.pData);
end;
end else
begin
AllocOpId(node);
end;
node:=node^.pNext;
end;
end;
end.

555
spirv/emit_bin.pas Normal file
View File

@ -0,0 +1,555 @@
unit emit_bin;
{$mode ObjFPC}{$H+}
interface
uses
SySutils,
Classes,
spirv,
srNodes,
srTypes,
srConst,
srReg,
srLayout,
srVariable,
srOp,
srOpUtils,
srCap,
srRefId,
SprvEmit;
type
TSPIRVHeader=packed record
MAGIC:DWORD;
VERSION:packed record
MINOR:WORD;
MAJOR:WORD;
end;
TOOL_VERSION:WORD;
TOOL_ID:WORD;
BOUND:DWORD;
RESERVED:DWORD;
end;
PSPIRVInstruction=^TSPIRVInstruction;
TSPIRVInstruction=packed record
OP:WORD;
COUNT:WORD;
end;
type
TSVInstrBuffer=object
Data:array of DWORD;
COUNT:DWORD;
Procedure AllocData;
Procedure NewOp(OpId:WORD);
Procedure Flush(Stream:TStream);
procedure AddParamId(P:DWORD);
procedure AddString(const name:PChar);
procedure AddRefId(P:PsrRefId);
procedure AddConstId(P:PsrConst);
procedure AddVarId(P:PsrVariable);
procedure AddTypeId(P:PsrType);
procedure AddFuncId(P:PSpirvFunc);
procedure AddChainId(P:PsrChain);
procedure AddRegId(P:PsrRegNode);
end;
TSprvEmit_bin=object(TSprvEmit)
procedure SaveToStream(Stream:TStream);
procedure SaveHeader(Stream:TStream;var Header:TSPIRVHeader);
procedure SaveCaps(Stream:TStream);
procedure SaveOpList(Stream:TStream;node:PspirvOp);
procedure SaveHeaderInfo(Stream:TStream);
procedure SaveTypes(Stream:TStream);
procedure SaveConst(var buf:TSVInstrBuffer;node:PsrConst);
procedure SaveConst(Stream:TStream);
procedure SaveVariable(Stream:TStream);
procedure SaveFunc(Stream:TStream);
procedure SaveOp(Stream:TStream;node:PSpirvOp);
procedure SaveOpBlock(Stream:TStream;pBlock:PsrOpBlock);
end;
implementation
Procedure TSVInstrBuffer.AllocData;
begin
if (Length(Data)<COUNT) then
begin
SetLength(Data,COUNT);
end;
end;
Procedure TSVInstrBuffer.NewOp(OpId:WORD);
var
I:TSPIRVInstruction;
begin
Assert(COUNT=0,'prev op not flushed');
COUNT:=1;
AllocData;
I.OP:=OpId;
I.COUNT:=0;
Data[0]:=DWORD(I);
end;
Procedure TSVInstrBuffer.Flush(Stream:TStream);
begin
if (Stream=nil) or (COUNT=0) then Exit;
TSPIRVInstruction(Data[0]).COUNT:=COUNT;
Stream.Write(Data[0],COUNT*SizeOf(DWORD));
COUNT:=0;
end;
procedure TSVInstrBuffer.AddParamId(P:DWORD);
var
I:DWORD;
begin
Assert(COUNT<>0,'new op not created');
I:=COUNT;
Inc(COUNT);
AllocData;
Data[i]:=P;
end;
procedure TSVInstrBuffer.AddString(const name:PChar);
var
I,L,D:DWORD;
begin
Assert(name<>nil);
Assert(COUNT<>0,'new op not created');
L:=StrLen(name);
D:=(L+SizeOf(DWORD)) div SizeOf(DWORD);
I:=COUNT;
COUNT:=COUNT+D;
AllocData;
FillDWord(Data[i],D,0);
Move(PChar(name)^,Data[i],L);
end;
procedure TSVInstrBuffer.AddRefId(P:PsrRefId);
begin
Assert(P<>nil ,'AddRefId$1');
Assert(P^.Alloc,'AddRefId$2');
AddParamId(P^.ID);
end;
procedure TSVInstrBuffer.AddConstId(P:PsrConst);
begin
Assert(P<>nil,'AddConstId');
AddRefId(@P^.ID);
end;
procedure TSVInstrBuffer.AddVarId(P:PsrVariable);
begin
Assert(P<>nil,'AddVarId');
AddRefId(@P^.ID);
end;
procedure TSVInstrBuffer.AddTypeId(P:PsrType);
begin
Assert(P<>nil,'AddTypeId');
AddRefId(@P^.ID);
end;
procedure TSVInstrBuffer.AddFuncId(P:PSpirvFunc);
begin
Assert(P<>nil,'AddFuncId');
AddRefId(@P^.ID);
end;
procedure TSVInstrBuffer.AddChainId(P:PsrChain);
begin
Assert(P<>nil,'AddChainId');
AddRefId(@P^.ID);
end;
procedure TSVInstrBuffer.AddRegId(P:PsrRegNode);
begin
Assert(P<>nil,'AddRegId$1');
Case P^.pWriter.ntype of
ntConst:
begin
AddConstId(P^.pWriter.pData);
end;
ntOp:
begin
AddRefId(@P^.ID);
end;
else
Assert(false,'AddRegId$2');
end;
end;
procedure TSprvEmit_bin.SaveToStream(Stream:TStream);
var
Header:TSPIRVHeader;
begin
if (Stream=nil) then Exit;
Header:=Default(TSPIRVHeader);
Header.MAGIC:=spirv.MagicNumber;
DWORD(Header.VERSION):=FBuffers.cfg.SpvVersion;
Header.TOOL_VERSION:=1;
Header.BOUND:=FSpirvIdAlloc.GetSpirvIDBound;
SaveHeader(Stream,Header);
SaveCaps(Stream);
SaveHeaderInfo(Stream);
SaveTypes(Stream);
SaveConst(Stream);
SaveVariable(Stream);
SaveFunc(Stream);
end;
procedure TSprvEmit_bin.SaveHeader(Stream:TStream;var Header:TSPIRVHeader);
begin
Stream.Write(Header,SizeOf(TSPIRVHeader));
end;
procedure TSprvEmit_bin.SaveCaps(Stream:TStream);
var
buf:TSVInstrBuffer;
node:PSpirvCap;
begin
buf:=Default(TSVInstrBuffer);
node:=FSpirvCaps.First;
While (node<>nil) do
begin
buf.NewOp(Op.OpCapability);
buf.AddParamId(node^.ID);
buf.Flush(Stream);
node:=FSpirvCaps.Next(node);
end;
end;
procedure TSprvEmit_bin.SaveOpList(Stream:TStream;node:PspirvOp);
begin
While (node<>nil) do
begin
SaveOp(Stream,node);
node:=node^.pNext;
end;
end;
procedure TSprvEmit_bin.SaveHeaderInfo(Stream:TStream);
begin
SaveOpList(Stream,FHeader.pHead);
SaveOpList(Stream,FDebugInfo.pHead);
SaveOpList(Stream,FDecorates.pHead);
end;
procedure TSprvEmit_bin.SaveTypes(Stream:TStream);
var
buf:TSVInstrBuffer;
node:PsrType;
pConst:PsrConst;
i:dword;
ie:Boolean;
begin
buf:=Default(TSVInstrBuffer);
node:=FSpirvTypes.FList.pHead;
While (node<>nil) do
begin
ie:=True;
pConst:=nil;
case node^.dtype of
dtTypeArray:
begin
//find a const
pConst:=FConsts.Fetchi(dtUInt32,node^.key.ext.array_count);
SaveConst(buf,pConst);
buf.Flush(Stream);
end;
else;
end;
buf.NewOp(node^.key.OpId);
buf.AddTypeId(node);
case node^.key.OpId of
Op.OpTypeFloat:
begin
buf.AddParamId(node^.key.ext.float_size);
end;
Op.OpTypeInt:
begin
buf.AddParamId(node^.key.ext.int_size);
buf.AddParamId(node^.key.ext.int_sign);
end;
Op.OpTypeVector:
begin
ie:=False;
buf.AddTypeId(node^.GetCompItem(0));
buf.AddParamId(node^.key.ext.array_count);
end;
Op.OpTypePointer:
begin
buf.AddParamId(node^.key.ext.Storage_Class);
end;
Op.OpTypeArray:
begin
ie:=False;
buf.AddTypeId(node^.GetCompItem(0));
buf.AddConstId(pConst);
end;
Op.OpTypeRuntimeArray:
begin
ie:=False;
buf.AddTypeId(node^.GetCompItem(0));
end;
Op.OpTypeImage:
begin
ie:=False;
buf.AddTypeId(node^.GetCompItem(0));
With node^.key.ext.image do
begin
buf.AddParamId(Dim);
buf.AddParamId(Depth);
buf.AddParamId(Arrayed);
buf.AddParamId(MS);
buf.AddParamId(Sampled);
buf.AddParamId(Format);
end;
end;
end;
if ie then
if (node^.key.count<>0) then
begin
For i:=0 to node^.key.count-1 do
begin
buf.AddTypeId(node^.GetCompItem(i));
end;
end;
buf.Flush(Stream);
node:=node^.pNext;
end;
end;
procedure TSprvEmit_bin.SaveConst(var buf:TSVInstrBuffer;node:PsrConst);
var
i:dword;
begin
if (node^.key.count=0) then
begin
if (node^.key.dtype=dtBool) then
begin
Case node^.AsBool of
True :buf.NewOp(Op.OpConstantTrue);
False:buf.NewOp(Op.OpConstantFalse);
end;
buf.AddTypeId(node^.pType);
buf.AddConstId(node);
end else
begin
buf.NewOp(Op.OpConstant);
buf.AddTypeId(node^.pType);
buf.AddConstId(node);
Case BitSizeType(node^.key.dtype) of
8:buf.AddParamId(node^.AsByte);
16:buf.AddParamId(node^.AsWord);
32:buf.AddParamId(node^.AsUint);
64:begin
buf.AddParamId(Lo(node^.AsUint64));
buf.AddParamId(Hi(node^.AsUint64));
end;
else
Assert(false,'SaveConst');
end;
end;
end else
begin
buf.NewOp(Op.OpConstantComposite);
buf.AddTypeId(node^.pType);
buf.AddConstId(node);
For i:=0 to node^.key.count-1 do
begin
buf.AddConstId(node^.GetCompItem(i));
end;
end;
end;
procedure TSprvEmit_bin.SaveConst(Stream:TStream);
var
buf:TSVInstrBuffer;
node:PsrConst;
begin
buf:=Default(TSVInstrBuffer);
node:=FConsts.FList.pHead;
While (node<>nil) do
begin
if (node^.key.dtype<>dtUnknow) then
begin
SaveConst(buf,node);
buf.Flush(Stream);
end;
node:=node^.pNext;
end;
end;
procedure TSprvEmit_bin.SaveVariable(Stream:TStream);
var
buf:TSVInstrBuffer;
node:PsrVariable;
begin
buf:=Default(TSVInstrBuffer);
node:=FVariables.pHead;
While (node<>nil) do
begin
if (node^.pType<>nil) then
begin
buf.NewOp(Op.OpVariable);
buf.AddTypeId(node^.pType);
buf.AddVarId(node);
buf.AddParamId(node^.GetStorageClass);
buf.Flush(Stream);
end;
node:=node^.pNext;
end;
end;
procedure SaveOpSingle(var buf:TSVInstrBuffer;const Param:TOpParamSingle);
begin
Assert(Param.pData<>nil,'SaveOpSingle$1');
Case Param.ntype of
ntFunc :buf.AddFuncId(Param.pData);
ntRefId:buf.AddRefId(Param.pData);
ntType :buf.AddTypeId(Param.pData);
ntReg :buf.AddRegId(Param.pData);
ntVar :buf.AddVarId(Param.pData);
ntChain:buf.AddChainId(Param.pData);
ntConst:buf.AddConstId(Param.pData);
else
Assert(false,'PrintOpSingle$3');
end;
end;
procedure SaveOpParamNode(var buf:TSVInstrBuffer;node:POpParamNode);
begin
Case node^.ntype of
ntLiteral:
begin
buf.AddParamId(node^.Value);
end;
ntString:
begin
buf.AddString(@node^.name);
end;
else
begin
SaveOpSingle(buf,node^.AsParam);
end;
end;
end;
procedure TSprvEmit_bin.SaveFunc(Stream:TStream);
var
pFunc:PSpirvFunc;
begin
pFunc:=FSpirvFuncs.FList.pHead;
While (pFunc<>nil) do
begin
SaveOpBlock(Stream,@pFunc^.FTop);
pFunc:=pFunc^.pNext;
end;
end;
procedure TSprvEmit_bin.SaveOp(Stream:TStream;node:PSpirvOp);
var
buf:TSVInstrBuffer;
Param:POpParamNode;
Info:Op.TOpInfo;
begin
if (node=nil) then Exit;
buf:=Default(TSVInstrBuffer);
Info:=Op.GetInfo(node^.OpId);
buf.NewOp(node^.OpId);
if Info.rstype then //dst type
begin
Assert(node^.dst_type<>nil,'SaveOp$4');
buf.AddTypeId(node^.dst_type);
end;
if Info.result then //dst
begin
Assert(node^.dst.ntype<>ntUnknow,'SaveOp$1');
Assert(node^.dst.pData<>nil,'SaveOp$2');
SaveOpSingle(buf,node^.dst);
end else
begin //no dst
if (node^.dst.ntype<>ntUnknow) then
begin
Assert(node^.dst.pData<>nil,'SaveOp$3');
SaveOpSingle(buf,node^.dst);
end;
end;
Param:=node^.pParam.pHead;
While (Param<>nil) do
begin
SaveOpParamNode(buf,Param);
Param:=Param^.pNext;
end;
buf.Flush(Stream);
end;
procedure TSprvEmit_bin.SaveOpBlock(Stream:TStream;pBlock:PsrOpBlock);
var
node:PSpirvOp;
begin
if (pBlock=nil) then Exit;
node:=pBlock^.pHead;
While (node<>nil) do
begin
if (node^.OpId=OpBlock) then
begin
if (node^.dst.ntype=ntBlock) then
begin
SaveOpBlock(Stream,node^.dst.pData);
end;
end else
begin
SaveOp(Stream,node);
end;
node:=node^.pNext;
end;
end;
end.

168
spirv/emit_exp.pas Normal file
View File

@ -0,0 +1,168 @@
unit emit_EXP;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srNodes,
srLabel,
srTypes,
srReg,
srVariable,
srOutput,
srOp,
srOpUtils,
SprvEmit,
emit_op;
type
TEmit_EXP=object(TEmitOp)
procedure _emit_EXP;
end;
implementation
procedure TEmit_EXP._emit_EXP;
Var
exc:PsrRegNode;
node:PSpirvOp;
pOpBlock:PsrOpBlock;
dout:PsrVariable;
dst:PsrRegNode;
src:array[0..3] of PsrRegNode;
rtype:TsrDataType;
f,i,p:Byte;
begin
//if (VM<>0) and (EXEC<>0) = set pixel else (if DONE=1) discard pixel /(PS only)
pOpBlock:=nil;
if (FSPI.EXP.VM<>0) and (FSPI.EXP.DONE<>0) then
begin
pOpBlock:=AllocBlockOp;
pOpBlock^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,pOpBlock,nil);
exc:=MakeRead(@FRegsStory.EXEC[0],dtBool);
node:=AddSpirvOp(OpMakeExp);
node^.AddParam(ntReg,exc); //<-fetch read
end;
//before
if (TpsslExportType(FSPI.EXP.TGT)=etNull) //only set kill mask
or (FSPI.EXP.EN=0) then //nop
begin
if (pOpBlock<>nil) then //is pushed
begin
FMain^.PopBlock;
end;
Exit;
end;
pOpBlock:=AllocBlockOp; //down
pOpBlock^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,pOpBlock,nil);
//output
src[0]:=nil;
src[1]:=nil;
src[2]:=nil;
src[3]:=nil;
f:=FSPI.EXP.EN;
if (FSPI.EXP.COMPR=0) then //float32
begin
p:=PopCnt(f);
if (p=1) then
begin
Case f of
$1:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC0,dtFloat32);
$2:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC1,dtFloat32);
$4:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC2,dtFloat32);
$8:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC3,dtFloat32);
else
Assert(false);
end;
dout:=FetchOutput(TpsslExportType(FSPI.EXP.TGT),dtFloat32); //output in FSPI.EXP.TGT
emit_OpStore(line,dout,src[0]);
end else
begin
Case p of
0:Assert(false);
2:rtype:=dtVec2f;
3:rtype:=dtVec3f;
4:rtype:=dtVec4f;
end;
i:=0;
if (f and $1<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC0,dtFloat32);
Inc(i);
end;
if (f and $2<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC1,dtFloat32);
Inc(i);
end;
if (f and $4<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC2,dtFloat32);
Inc(i);
end;
if (f and $8<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC3,dtFloat32);
Inc(i);
end;
dst:=emit_OpMakeVec(line,rtype,p,@src);
dst^.mark_read;
dout:=FetchOutput(TpsslExportType(FSPI.EXP.TGT),rtype); //output in FSPI.EXP.TGT
emit_OpStore(line,dout,dst);
end;
end else
begin //half16
Case f of
3,
$F:
begin
fetch_vsrc8_vec2h(FSPI.EXP.VSRC0,src[0],src[1]);
fetch_vsrc8_vec2h(FSPI.EXP.VSRC1,src[2],src[3]);
end;
$C:
begin
fetch_vsrc8_vec2h(FSPI.EXP.VSRC2,src[0],src[1]);
fetch_vsrc8_vec2h(FSPI.EXP.VSRC3,src[2],src[3]);
end;
else
Assert(false);
end;
dst:=emit_OpMakeVec(line,dtVec4h,4,@src);
dst^.mark_read;
dout:=FetchOutput(TpsslExportType(FSPI.EXP.TGT),dtVec4h); //output in FSPI.EXP.TGT
emit_OpStore(line,dout,dst);
end;
if (pOpBlock<>nil) then //is pushed
begin
FMain^.PopBlock;
FMain^.PopBlock;
end;
end;
end.

705
spirv/emit_mimg.pas Normal file
View File

@ -0,0 +1,705 @@
unit emit_MIMG;
{$mode objfpc}{$H+}
interface
uses
sysutils,
spirv,
si_ci_vi_merged_enum,
ps4_shader,
ps4_pssl,
srNodes,
srTypes,
srConst,
srReg,
srLayout,
srOp,
SprvEmit,
emit_op;
type
TEmit_MIMG=object(TEmitOp)
procedure _emit_MIMG;
procedure _DistribDmask(dst:PsrRegNode;telem:TsrDataType);
Function _GatherCoord_f(var offset:DWORD;dim_id:Byte):PsrRegNode;
Function _GatherCoord_u(var offset:DWORD;dim_id:Byte):PsrRegNode;
Function _Gather_packed_offset(var offset:DWORD;dim:Byte):PsrRegNode;
procedure _emit_image_sample(Tgrp:PsrRegNode;info:PsrImageInfo);
procedure _emit_image_load(Tgrp:PsrRegNode;info:PsrImageInfo);
end;
implementation
function GetImageFormat(PT:PTSharpResource4):Byte;
begin
Result:=ImageFormat.Unknown;
if (PT=nil) then Exit;
Case PT^.nfmt of
IMG_NUM_FORMAT_UNORM,
IMG_NUM_FORMAT_SRGB:
begin //R8, Rg8,Rg16, Rgba8,Rgba16,Rgb10A2
Case PT^.dfmt of
IMG_DATA_FORMAT_8 :Result:=ImageFormat.R8;
IMG_DATA_FORMAT_ETC2_R :Result:=ImageFormat.R8;
IMG_DATA_FORMAT_BC4 :Result:=ImageFormat.R8;
IMG_DATA_FORMAT_1 :Result:=ImageFormat.R8;
IMG_DATA_FORMAT_32_AS_8 :Result:=ImageFormat.R8;
IMG_DATA_FORMAT_8_8 :Result:=ImageFormat.Rg8;
IMG_DATA_FORMAT_16_16 :Result:=ImageFormat.Rg16;
IMG_DATA_FORMAT_ETC2_RG :Result:=ImageFormat.Rg8;
IMG_DATA_FORMAT_BC5 :Result:=ImageFormat.Rg8;
IMG_DATA_FORMAT_4_4 :Result:=ImageFormat.Rg8;
IMG_DATA_FORMAT_32_AS_8_8 :Result:=ImageFormat.Rg8;
IMG_DATA_FORMAT_10_11_11 :Result:=ImageFormat.Rgb10A2;
IMG_DATA_FORMAT_11_11_10 :Result:=ImageFormat.Rgb10A2;
IMG_DATA_FORMAT_5_6_5 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_ETC2_RGB :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_GB_GR :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_BG_RG :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_BC1 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_BC6 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_6_5_5 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_10_10_10_2 :Result:=ImageFormat.Rgb10A2;
IMG_DATA_FORMAT_2_10_10_10 :Result:=ImageFormat.Rgb10A2;
IMG_DATA_FORMAT_8_8_8_8 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_1_5_5_5 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_5_5_5_1 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_4_4_4_4 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_ETC2_RGBA :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_ETC2_RGBA1 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_5_9_9_9 :Result:=ImageFormat.Rgba16;
IMG_DATA_FORMAT_BC2 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_BC3 :Result:=ImageFormat.Rgba8;
IMG_DATA_FORMAT_BC7 :Result:=ImageFormat.Rgba8;
else;
end;
end;
IMG_NUM_FORMAT_SNORM:
begin //R8Snorm, Rg8Snorm,Rg16Snorm, Rgba8Snorm,Rgba16Snorm
Case PT^.dfmt of
IMG_DATA_FORMAT_8 :Result:=ImageFormat.R8Snorm;
IMG_DATA_FORMAT_ETC2_R :Result:=ImageFormat.R8Snorm;
IMG_DATA_FORMAT_BC4 :Result:=ImageFormat.R8Snorm;
IMG_DATA_FORMAT_1 :Result:=ImageFormat.R8Snorm;
IMG_DATA_FORMAT_32_AS_8 :Result:=ImageFormat.R8Snorm;
IMG_DATA_FORMAT_8_8 :Result:=ImageFormat.Rg8Snorm;
IMG_DATA_FORMAT_16_16 :Result:=ImageFormat.Rg16Snorm;
IMG_DATA_FORMAT_ETC2_RG :Result:=ImageFormat.Rg8Snorm;
IMG_DATA_FORMAT_BC5 :Result:=ImageFormat.Rg8Snorm;
IMG_DATA_FORMAT_4_4 :Result:=ImageFormat.Rg8Snorm;
IMG_DATA_FORMAT_32_AS_8_8 :Result:=ImageFormat.Rg8Snorm;
IMG_DATA_FORMAT_10_11_11 :Result:=ImageFormat.Rgba16Snorm;
IMG_DATA_FORMAT_11_11_10 :Result:=ImageFormat.Rgba16Snorm;
IMG_DATA_FORMAT_5_6_5 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_ETC2_RGB :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_GB_GR :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_BG_RG :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_BC1 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_BC6 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_6_5_5 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_10_10_10_2 :Result:=ImageFormat.Rgba16Snorm;
IMG_DATA_FORMAT_2_10_10_10 :Result:=ImageFormat.Rgba16Snorm;
IMG_DATA_FORMAT_8_8_8_8 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_1_5_5_5 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_5_5_5_1 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_4_4_4_4 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_ETC2_RGBA :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_ETC2_RGBA1 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_5_9_9_9 :Result:=ImageFormat.Rgba16Snorm;
IMG_DATA_FORMAT_BC2 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_BC3 :Result:=ImageFormat.Rgba8Snorm;
IMG_DATA_FORMAT_BC7 :Result:=ImageFormat.Rgba8Snorm;
else;
end;
end;
IMG_NUM_FORMAT_UINT:
begin //R8ui,R16ui,R32ui, Rg8ui,Rg16ui,Rg32ui, Rgba8ui,Rgba16ui,Rgba32ui,Rgb10a2ui
Case PT^.dfmt of
IMG_DATA_FORMAT_8 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_16 :Result:=ImageFormat.R16ui;
IMG_DATA_FORMAT_32 :Result:=ImageFormat.R32ui;
IMG_DATA_FORMAT_ETC2_R :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_BC4 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_1 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_32_AS_8 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_8_8 :Result:=ImageFormat.Rg8ui;
IMG_DATA_FORMAT_16_16 :Result:=ImageFormat.Rg16ui;
IMG_DATA_FORMAT_32_32 :Result:=ImageFormat.Rg32ui;
IMG_DATA_FORMAT_8_24 :Result:=ImageFormat.Rg32ui;
IMG_DATA_FORMAT_24_8 :Result:=ImageFormat.Rg32ui;
IMG_DATA_FORMAT_X24_8_32 :Result:=ImageFormat.Rg32ui;
IMG_DATA_FORMAT_ETC2_RG :Result:=ImageFormat.Rg8ui;
IMG_DATA_FORMAT_BC5 :Result:=ImageFormat.Rg8ui;
IMG_DATA_FORMAT_4_4 :Result:=ImageFormat.Rg8ui;
IMG_DATA_FORMAT_32_AS_8_8 :Result:=ImageFormat.Rg8ui;
IMG_DATA_FORMAT_10_11_11 :Result:=ImageFormat.Rgb10a2ui;
IMG_DATA_FORMAT_11_11_10 :Result:=ImageFormat.Rgb10a2ui;
IMG_DATA_FORMAT_32_32_32 :Result:=ImageFormat.Rgba32ui;
IMG_DATA_FORMAT_5_6_5 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_ETC2_RGB :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_GB_GR :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_BG_RG :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_BC1 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_BC6 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_6_5_5 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_10_10_10_2 :Result:=ImageFormat.Rgb10a2ui;
IMG_DATA_FORMAT_2_10_10_10 :Result:=ImageFormat.Rgb10a2ui;
IMG_DATA_FORMAT_8_8_8_8 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_16_16_16_16 :Result:=ImageFormat.Rgba16ui;
IMG_DATA_FORMAT_32_32_32_32 :Result:=ImageFormat.Rgba32ui;
IMG_DATA_FORMAT_1_5_5_5 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_5_5_5_1 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_4_4_4_4 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_ETC2_RGBA :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_ETC2_RGBA1 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_5_9_9_9 :Result:=ImageFormat.Rgba16ui;
IMG_DATA_FORMAT_BC2 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_BC3 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_BC7 :Result:=ImageFormat.Rgba8ui;
IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=ImageFormat.Rgba32ui;
IMG_DATA_FORMAT_FMASK8_S2_F1 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_FMASK8_S4_F1 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_FMASK8_S8_F1 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_FMASK8_S2_F2 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_FMASK8_S4_F2 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_FMASK8_S4_F4 :Result:=ImageFormat.R8ui;
IMG_DATA_FORMAT_FMASK16_S16_F1 :Result:=ImageFormat.R16ui;
IMG_DATA_FORMAT_FMASK16_S8_F2 :Result:=ImageFormat.R16ui;
IMG_DATA_FORMAT_FMASK32_S16_F2 :Result:=ImageFormat.R32ui;
IMG_DATA_FORMAT_FMASK32_S8_F4 :Result:=ImageFormat.R32ui;
IMG_DATA_FORMAT_FMASK32_S8_F8 :Result:=ImageFormat.R32ui;
IMG_DATA_FORMAT_FMASK64_S16_F4 :Result:=ImageFormat.R64ui;
IMG_DATA_FORMAT_FMASK64_S16_F8 :Result:=ImageFormat.R64ui;
else;
end;
end;
IMG_NUM_FORMAT_SINT:
begin //R8i,R16i,R32i, Rg8i,Rg16i,Rg32i, Rgba8i,Rgba16i,Rgba32i
Case PT^.dfmt of
IMG_DATA_FORMAT_8 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_16 :Result:=ImageFormat.R16i;
IMG_DATA_FORMAT_32 :Result:=ImageFormat.R32i;
IMG_DATA_FORMAT_ETC2_R :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_BC4 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_1 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_32_AS_8 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_8_8 :Result:=ImageFormat.Rg8i;
IMG_DATA_FORMAT_16_16 :Result:=ImageFormat.Rg16i;
IMG_DATA_FORMAT_32_32 :Result:=ImageFormat.Rg32i;
IMG_DATA_FORMAT_8_24 :Result:=ImageFormat.Rg32i;
IMG_DATA_FORMAT_24_8 :Result:=ImageFormat.Rg32i;
IMG_DATA_FORMAT_X24_8_32 :Result:=ImageFormat.Rg32i;
IMG_DATA_FORMAT_ETC2_RG :Result:=ImageFormat.Rg8i;
IMG_DATA_FORMAT_BC5 :Result:=ImageFormat.Rg8i;
IMG_DATA_FORMAT_4_4 :Result:=ImageFormat.Rg8i;
IMG_DATA_FORMAT_32_AS_8_8 :Result:=ImageFormat.Rg8i;
IMG_DATA_FORMAT_10_11_11 :Result:=ImageFormat.Rgba16i;
IMG_DATA_FORMAT_11_11_10 :Result:=ImageFormat.Rgba16i;
IMG_DATA_FORMAT_32_32_32 :Result:=ImageFormat.Rgba32i;
IMG_DATA_FORMAT_5_6_5 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_ETC2_RGB :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_GB_GR :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_BG_RG :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_BC1 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_BC6 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_6_5_5 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_10_10_10_2 :Result:=ImageFormat.Rgba16i;
IMG_DATA_FORMAT_2_10_10_10 :Result:=ImageFormat.Rgba16i;
IMG_DATA_FORMAT_8_8_8_8 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_16_16_16_16 :Result:=ImageFormat.Rgba16i;
IMG_DATA_FORMAT_32_32_32_32 :Result:=ImageFormat.Rgba32i;
IMG_DATA_FORMAT_1_5_5_5 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_5_5_5_1 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_4_4_4_4 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_ETC2_RGBA :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_ETC2_RGBA1 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_5_9_9_9 :Result:=ImageFormat.Rgba16i;
IMG_DATA_FORMAT_BC2 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_BC3 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_BC7 :Result:=ImageFormat.Rgba8i;
IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=ImageFormat.Rgba32i;
IMG_DATA_FORMAT_FMASK8_S2_F1 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_FMASK8_S4_F1 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_FMASK8_S8_F1 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_FMASK8_S2_F2 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_FMASK8_S4_F2 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_FMASK8_S4_F4 :Result:=ImageFormat.R8i;
IMG_DATA_FORMAT_FMASK16_S16_F1 :Result:=ImageFormat.R16i;
IMG_DATA_FORMAT_FMASK16_S8_F2 :Result:=ImageFormat.R16i;
IMG_DATA_FORMAT_FMASK32_S16_F2 :Result:=ImageFormat.R32i;
IMG_DATA_FORMAT_FMASK32_S8_F4 :Result:=ImageFormat.R32i;
IMG_DATA_FORMAT_FMASK32_S8_F8 :Result:=ImageFormat.R32i;
IMG_DATA_FORMAT_FMASK64_S16_F4 :Result:=ImageFormat.R64i;
IMG_DATA_FORMAT_FMASK64_S16_F8 :Result:=ImageFormat.R64i;
else;
end;
end;
IMG_NUM_FORMAT_USCALED,
IMG_NUM_FORMAT_SSCALED,
IMG_NUM_FORMAT_FLOAT:
begin //R16f,R32f, Rg16f,Rg32f, R11fG11fB10f, Rgba16f,Rgba32f
Case PT^.dfmt of
IMG_DATA_FORMAT_16 :Result:=ImageFormat.R16f;
IMG_DATA_FORMAT_32 :Result:=ImageFormat.R32f;
IMG_DATA_FORMAT_ETC2_R :Result:=ImageFormat.R16f;
IMG_DATA_FORMAT_BC4 :Result:=ImageFormat.R16f;
IMG_DATA_FORMAT_16_16 :Result:=ImageFormat.Rg16f;
IMG_DATA_FORMAT_32_32 :Result:=ImageFormat.Rg32f;
IMG_DATA_FORMAT_8_24 :Result:=ImageFormat.Rg32f;
IMG_DATA_FORMAT_24_8 :Result:=ImageFormat.Rg32f;
IMG_DATA_FORMAT_X24_8_32 :Result:=ImageFormat.Rg32f;
IMG_DATA_FORMAT_ETC2_RG :Result:=ImageFormat.Rg16f;
IMG_DATA_FORMAT_BC5 :Result:=ImageFormat.Rg16f;
IMG_DATA_FORMAT_10_11_11 :Result:=ImageFormat.R11fG11fB10f;
IMG_DATA_FORMAT_11_11_10 :Result:=ImageFormat.R11fG11fB10f;
IMG_DATA_FORMAT_32_32_32 :Result:=ImageFormat.Rgba32f;
IMG_DATA_FORMAT_ETC2_RGB :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_BC1 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_BC6 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_10_10_10_2 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_2_10_10_10 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_16_16_16_16 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_32_32_32_32 :Result:=ImageFormat.Rgba32f;
IMG_DATA_FORMAT_ETC2_RGBA :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_ETC2_RGBA1 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_BC2 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_BC3 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_BC7 :Result:=ImageFormat.Rgba16f;
IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=ImageFormat.Rgba32f;
else;
end;
end;
else;
end;
end;
function GetDimType(PT:PTSharpResource4):Byte;
begin
Result:=0;
if (PT=nil) then Exit;
Case PT^._type of
SQ_RSRC_IMG_1D,
SQ_RSRC_IMG_1D_ARRAY :Result:=Dim.Dim1D;
SQ_RSRC_IMG_2D,
SQ_RSRC_IMG_2D_ARRAY,
SQ_RSRC_IMG_2D_MSAA,
SQ_RSRC_IMG_2D_MSAA_ARRAY:Result:=Dim.Dim2D;
SQ_RSRC_IMG_3D :Result:=Dim.Dim3D;
SQ_RSRC_IMG_CUBE :Result:=Dim.Cube;
else;
end;
end;
function GetElemType(PT:PTSharpResource4):TsrDataType;
begin
Result:=dtFloat32;
if (PT=nil) then Exit;
Case PT^.nfmt of
IMG_NUM_FORMAT_UINT:Result:=dtUint32;
IMG_NUM_FORMAT_SINT:Result:=dtInt32;
else;
end;
end;
function GetDimCount(b:Byte):Byte;
begin
Result:=1;
Case b of
Dim.Dim2D:Result:=2;
Dim.Dim3D:Result:=3;
Dim.Cube :Result:=3;
end;
end;
function GetImageInfo(PT:PTSharpResource4):TsrImageInfo;
begin
Result:=Default(TsrImageInfo);
Result.dtype:=GetElemType(PT);
Result.tinfo.Dim :=GetDimType(PT);
Result.tinfo.Depth :=2;
Result.tinfo.Arrayed:=GetArrayedType(PT);
Result.tinfo.MS :=GetMsType(PT);
Result.tinfo.Format :=GetImageFormat(PT);
end;
procedure TEmit_MIMG._DistribDmask(dst:PsrRegNode;telem:TsrDataType); //result
var
pSlot:PsrRegSlot;
i,d:Byte;
begin
d:=0;
For i:=0 to 3 do
if Byte(FSPI.MIMG.DMASK).TestBit(i) then
begin
pSlot:=FRegsStory.get_vdst8(FSPI.MIMG.VDATA+d); Inc(d);
Assert(pSlot<>nil);
dst^.mark_read;
emit_OpCompExtract(line,pSlot^.New(line,telem),dst,i);
end;
end;
Function TEmit_MIMG._GatherCoord_f(var offset:DWORD;dim_id:Byte):PsrRegNode; //src
var
src:array[0..3] of PsrRegNode;
i,count:Byte;
begin
Result:=nil;
count:=GetDimCount(dim_id);
if (FSPI.MIMG.DA<>0) then Inc(count); //slice
if (dim_id=Dim.Cube) then
begin
//x,y,slice,(face_id+slice*8)
if (FSPI.MIMG.DA<>0) then //slice
begin
src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtFloat32); //x
src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtFloat32); //y
src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+3,dtFloat32); //face TODO: face-slice*8
src[3]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+2,dtFloat32); //slice
end else
begin
src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtFloat32); //x
src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtFloat32); //y
src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+2,dtFloat32); //face
end;
Result:=emit_OpMakeCube(line,GetVecType(dtFloat32,count),count,@src);
Result^.mark_read;
end else
begin
For i:=0 to count-1 do
begin
src[i]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+i,dtFloat32);
end;
if (count=1) then
begin
Result:=src[0];
end else
begin
Result:=emit_OpMakeVec(line,GetVecType(dtFloat32,count),count,@src);
Result^.mark_read;
end;
end;
offset:=offset+count;
end;
Function TEmit_MIMG._GatherCoord_u(var offset:DWORD;dim_id:Byte):PsrRegNode; //src
var
src:array[0..3] of PsrRegNode;
i,count:Byte;
begin
Result:=nil;
count:=GetDimCount(dim_id);
if (FSPI.MIMG.DA<>0) then Inc(count); //slice
if (dim_id=Dim.Cube) then
begin
//x,y,slice,(face_id+slice*8)
if (FSPI.MIMG.DA<>0) then //slice
begin
src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtInt32); //x
src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtInt32); //y
src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+3,dtInt32); //face TODO: face-slice*8
src[3]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+2,dtInt32); //slice
end else
begin
src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtInt32); //x
src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtInt32); //y
src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+2,dtInt32); //face
end;
Result:=emit_OpMakeCube(line,GetVecType(dtInt32,count),count,@src);
Result^.mark_read;
end else
begin
For i:=0 to count-1 do
begin
src[i]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+i,dtInt32);
end;
if (count=1) then
begin
Result:=src[0];
end else
begin
Result:=emit_OpMakeVec(line,GetVecType(dtInt32,count),count,@src);
Result^.mark_read;
end;
end;
offset:=offset+count;
end;
Function TEmit_MIMG._Gather_packed_offset(var offset:DWORD;dim:Byte):PsrRegNode;
var
src:PsrRegNode;
begin
Result:=nil;
src:=fetch_vsrc8(FSPI.MIMG.VADDR+offset,dtUint32);
Inc(offset);
Case dim of
1:Result:=emit_OpPackOfs(line,dtInt32,dim,src);
2:Result:=emit_OpPackOfs(line,dtVec2i,dim,src);
3:Result:=emit_OpPackOfs(line,dtVec3i,dim,src);
else
Assert(False);
end;
Result^.mark_read;
end;
procedure TEmit_MIMG._emit_image_sample(Tgrp:PsrRegNode;info:PsrImageInfo);
var
src:array[0..3] of PsrRegSlot;
pLayout:PsrDataLayout;
Sgrp:PsrRegNode;
dst,cmb,coord,lod,offset:PsrRegNode;
roffset:DWORD;
node:PSpirvOp;
begin
if not FRegsStory.get_srsrc(FSPI.MIMG.SSAMP,4,@src) then Assert(false);
pLayout:=GroupingSharp(src,rtSSharp4);
Sgrp:=FetchSampler(pLayout);
cmb:=emit_OpSampledImage(line,Tgrp,Sgrp,info^.dtype,info^.tinfo);
cmb^.mark_read;
dst:=NewReg(GetVecType(info^.dtype,4));
roffset:=0;
Case FSPI.MIMG.OP of
IMAGE_SAMPLE:
begin
coord:=_GatherCoord_f(roffset,info^.tinfo.Dim);
if (FExecutionModel=ExecutionModel.Fragment) then
begin
node:=emit_OpImageSampleImplicitLod(line,dst,cmb,coord);
end else
begin
node:=emit_OpImageSampleExplicitLod(line,dst,cmb,coord);
end;
end;
IMAGE_SAMPLE_LZ:
begin
coord:=_GatherCoord_f(roffset,info^.tinfo.Dim);
node:=emit_OpImageSampleExplicitLod(line,dst,cmb,coord);
node^.AddLiteral(ImageOperands.Lod,'Lod');
//0
lod:=FetchReg(FConsts.Fetchf(dtFloat32,0));
node^.AddParam(ntReg,lod);
end;
IMAGE_SAMPLE_LZ_O:
begin
offset:=_Gather_packed_offset(roffset,GetDimCount(info^.tinfo.Dim));
coord:=_GatherCoord_f(roffset,info^.tinfo.Dim);
node:=emit_OpImageSampleExplicitLod(line,dst,cmb,coord);
node^.AddLiteral(ImageOperands.Lod or ImageOperands.ConstOffset,'Lod|ConstOffset');
//0
lod:=FetchReg(FConsts.Fetchf(dtFloat32,0));
node^.AddParam(ntReg,lod);
//1
node^.AddParam(ntReg,offset);
end;
else
Assert(false);
end;
_DistribDmask(dst,info^.dtype);
end;
procedure TEmit_MIMG._emit_image_load(Tgrp:PsrRegNode;info:PsrImageInfo);
var
dst,coord,lod:PsrRegNode;
roffset:DWORD;
node:PSpirvOp;
begin
dst:=NewReg(GetVecType(info^.dtype,4));
roffset:=0;
Case FSPI.MIMG.OP of
IMAGE_LOAD:
begin
coord:=_GatherCoord_u(roffset,info^.tinfo.Dim);
node:=emit_OpImageFetch(line,Tgrp,dst,coord);
//fragid T# 2D MSAA
if (info^.tinfo.MS=1) then
begin
Assert(false,'TODO');
end;
end;
IMAGE_LOAD_MIP: //All except MSAA
begin
coord:=_GatherCoord_u(roffset,info^.tinfo.Dim);
node:=emit_OpImageFetch(line,Tgrp,dst,coord);
lod:=fetch_vsrc8(FSPI.MIMG.VADDR+roffset,dtUint32);
Inc(roffset);
node^.AddLiteral(ImageOperands.Lod,'Lod');
node^.AddParam(ntReg,lod);
end;
else
Assert(false);
end;
_DistribDmask(dst,info^.dtype);
end;
procedure TEmit_MIMG._emit_MIMG;
var
src:array[0..7] of PsrRegSlot;
pLayout:PsrDataLayout;
info:TsrImageInfo;
Tgrp:PsrRegNode;
begin
Assert(FSPI.MIMG.UNRM=0,'FSPI.MIMG.UNRM');
pLayout:=nil;
Case FSPI.MIMG.R128 of
0:
begin
if not FRegsStory.get_srsrc(FSPI.MIMG.SRSRC,8,@src) then Assert(false);
pLayout:=GroupingSharp(src,rtTSharp4);
//print_tsharp4(pLayout^.pData);
//Tgrp:=GroupingSharp(@src,rtTSharp8);
end;
1:
begin
if not FRegsStory.get_srsrc(FSPI.MIMG.SRSRC,4,@src) then Assert(false);
pLayout:=GroupingSharp(src,rtTSharp8);
//print_tsharp8(pLayout^.pData);
//Tgrp:=GroupingSharp(@src,rtTSharp4);
end;
end;
info:=GetImageInfo(pLayout^.pData);
Case FSPI.MIMG.OP of
IMAGE_SAMPLE..IMAGE_SAMPLE_C_LZ_O: //sampled
begin
info.tinfo.Sampled:=1;
Tgrp:=FetchImage(pLayout,info.dtype,info.tinfo);
_emit_image_sample(Tgrp,@info);
end;
IMAGE_LOAD..IMAGE_LOAD_MIP_PCK_SGN: //loaded
begin
info.tinfo.Sampled:=1;
Tgrp:=FetchImage(pLayout,info.dtype,info.tinfo);
_emit_image_load(Tgrp,@info);
end
else
Assert(false,'MIMG?'+IntToStr(FSPI.MIMG.OP));
end;
//Writeln('DMASK=',FSPI.MIMG.DMASK);
//Writeln('VADDR=',FSPI.MIMG.VADDR);
//Writeln('VDATA=',FSPI.MIMG.VDATA);
//Writeln('SRSRC=',FSPI.MIMG.SRSRC); //T#
//Writeln('SSAMP=',FSPI.MIMG.SSAMP); //S#
//writeln;
end;
end.

99
spirv/emit_mtbuf.pas Normal file
View File

@ -0,0 +1,99 @@
unit emit_MTBUF;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srReg,
srLayout,
SprvEmit,
srVBufInfo,
emit_vbuf_load,
emit_vbuf_store,
emit_op;
type
TEmit_MTBUF=object(TEmitOp)
procedure _emit_MTBUF;
procedure _emit_TBUFFER_LOAD_FORMAT(count:Byte);
procedure _emit_TBUFFER_STORE_FORMAT(count:Byte);
end;
implementation
procedure TEmit_MTBUF._emit_TBUFFER_LOAD_FORMAT(count:Byte);
var
src:array[0..3] of PsrRegSlot;
grp:PsrDataLayout;
begin
if not FRegsStory.get_srsrc(FSPI.MTBUF.SRSRC,4,@src) then Assert(false);
grp:=GroupingSharp(@src,rtVSharp4);
TEmit_vbuf_load(Self).buf_load(
Buf_info(grp,
dst_sel_identity,
FSPI.MTBUF.DFMT,
FSPI.MTBUF.NFMT,
count)
);
end;
procedure TEmit_MTBUF._emit_TBUFFER_STORE_FORMAT(count:Byte);
var
src:array[0..3] of PsrRegSlot;
grp:PsrDataLayout;
begin
if not FRegsStory.get_srsrc(FSPI.MTBUF.SRSRC,4,@src) then Assert(false);
grp:=GroupingSharp(@src,rtVSharp4);
TEmit_vbuf_store(Self).buf_store(
Buf_info(grp,
dst_sel_identity,
FSPI.MTBUF.DFMT,
FSPI.MTBUF.NFMT,
count)
);
end;
procedure TEmit_MTBUF._emit_MTBUF;
begin
case FSPI.MTBUF.OP of
TBUFFER_LOAD_FORMAT_X :_emit_TBUFFER_LOAD_FORMAT(1);
TBUFFER_LOAD_FORMAT_XY :_emit_TBUFFER_LOAD_FORMAT(2);
TBUFFER_LOAD_FORMAT_XYZ :_emit_TBUFFER_LOAD_FORMAT(3);
TBUFFER_LOAD_FORMAT_XYZW :_emit_TBUFFER_LOAD_FORMAT(4);
TBUFFER_STORE_FORMAT_X :_emit_TBUFFER_STORE_FORMAT(1);
TBUFFER_STORE_FORMAT_XY :_emit_TBUFFER_STORE_FORMAT(2);
TBUFFER_STORE_FORMAT_XYZ :_emit_TBUFFER_STORE_FORMAT(3);
TBUFFER_STORE_FORMAT_XYZW:_emit_TBUFFER_STORE_FORMAT(4);
end;
//OFFSET:bit12; //Unsigned byte offset.
//OFFEN:bit1; //enable offset in VADDR
//IDXEN:bit1; //enable index in VADDR
//GLC:bit1; //globally coherent.
//
//VADDR:Byte; //VGPR address source.
//VDATA:Byte; //Vector GPR to read/write result to.
//SRSRC:bit5; //Scalar GPR that specifies the resource constant, in units of four SGPRs
//SLC:bit1; //System Level Coherent.
//TFE:bit1; //Texture Fail Enable
//SOFFSET:Byte;
end;
end.

237
spirv/emit_mubuf.pas Normal file
View File

@ -0,0 +1,237 @@
unit emit_MUBUF;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_shader,
ps4_pssl,
srTypes,
srReg,
srLayout,
srInput,
spirv,
SprvEmit,
srVBufInfo,
emit_vbuf_load,
emit_vbuf_store,
emit_op;
type
TEmit_MUBUF=object(TEmitOp)
procedure _emit_MUBUF;
procedure _make_load_zero(dst:PsrRegSlot);
procedure _make_load_one(dst:PsrRegSlot);
procedure _make_load_comp(dst:PsrRegSlot;rsl:PsrRegNode;i:Byte);
function _emit_BUFFER_LOAD_VA(src:PPsrRegSlot;count:Byte):Boolean;
procedure _emit_BUFFER_LOAD_FORMAT(count:Byte);
procedure _emit_BUFFER_STORE_FORMAT(count:Byte);
end;
implementation
procedure TEmit_MUBUF._make_load_zero(dst:PsrRegSlot);
begin
SetConst(dst,FConsts.Fetchi(dtFloat32,0));
end;
procedure TEmit_MUBUF._make_load_one(dst:PsrRegSlot);
begin
SetConst(dst,FConsts.Fetchf(dtFloat32,1));
end;
procedure TEmit_MUBUF._make_load_comp(dst:PsrRegSlot;rsl:PsrRegNode;i:Byte);
begin
dst^.New(line,dtFloat32);
rsl^.mark_read;
emit_OpCompExtract(line,dst^.current,rsl,i);
end;
function TEmit_MUBUF._emit_BUFFER_LOAD_VA(src:PPsrRegSlot;count:Byte):Boolean;
var
dst:PsrRegSlot;
grp:PsrDataLayout;
PV:PVSharpResource4;
idx:PsrRegNode;
rsl:PsrRegNode;
inp_idx:PsrInput;
dsel:Tdst_sel;
i,d,elem_count:Byte;
begin
Result:=False;
idx:=FRegsStory.get_vsrc8(FSPI.MUBUF.VADDR+0)^.current;
inp_idx:=GetInputRegNode(idx);
if (inp_idx<>nil) then
if (inp_idx^.key.itype=itVIndex) then //is input attach
begin
grp:=GroupingSharp(src,rtVSharp4);
PV:=grp^.pData;
rsl:=AddVertLayout(grp,dtVec4f);
dsel:=dst_sel(PV^.dst_sel_x,
PV^.dst_sel_y,
PV^.dst_sel_z,
PV^.dst_sel_w);
elem_count:=GetElemCount(PV^.dfmt);
For i:=0 to count-1 do
begin
dst:=FRegsStory.get_vdst8(FSPI.MUBUF.VDATA+i);
if (dst=nil) then Assert(false);
//0=0, 1=1, 4=R, 5=G, 6=B, 7=A
Case dsel[i] of
0:begin //0
_make_load_zero(dst);
end;
1:begin //1
_make_load_one(dst);
end;
4..7:
begin //RGBA
d:=dsel[i]-4;
if (d<elem_count) then
begin
_make_load_comp(dst,rsl,d);
end else
begin //as zero
_make_load_zero(dst);
end;
end;
else
begin //as zero
_make_load_zero(dst);
end;
end;
end;
Result:=True;
end;
end;
procedure TEmit_MUBUF._emit_BUFFER_LOAD_FORMAT(count:Byte);
var
src:array[0..3] of PsrRegSlot;
grp:PsrDataLayout;
PV:PVSharpResource4;
begin
Assert(FSPI.MUBUF.LDS=0,'FSPI.MUBUF.LDS');
if not FRegsStory.get_srsrc(FSPI.MUBUF.SRSRC,4,@src) then Assert(false);
if FUseVertexInput then
if (FExecutionModel=ExecutionModel.Vertex) then //Vertex only
if (FSPI.MUBUF.IDXEN=1) and
(FSPI.MUBUF.OFFEN=0) and
(FSPI.MUBUF.SOFFSET=128) and
(FSPI.MUBUF.LDS=0) then
begin
if _emit_BUFFER_LOAD_VA(@src,count) then Exit;
end;
grp:=GroupingSharp(@src,rtVSharp4);
PV:=grp^.pData;
TEmit_vbuf_load(Self).buf_load(
Buf_info(grp,
dst_sel(PV^.dst_sel_x,
PV^.dst_sel_y,
PV^.dst_sel_z,
PV^.dst_sel_w),
PV^.dfmt,
PV^.nfmt,
count)
);
end;
procedure TEmit_MUBUF._emit_BUFFER_STORE_FORMAT(count:Byte);
var
src:array[0..3] of PsrRegSlot;
grp:PsrDataLayout;
PV:PVSharpResource4;
begin
Assert(FSPI.MUBUF.LDS=0,'FSPI.MUBUF.LDS');
if not FRegsStory.get_srsrc(FSPI.MUBUF.SRSRC,4,@src) then Assert(false);
grp:=GroupingSharp(@src,rtVSharp4);
PV:=grp^.pData;
TEmit_vbuf_store(Self).buf_store(
Buf_info(grp,
dst_sel(PV^.dst_sel_x,
PV^.dst_sel_y,
PV^.dst_sel_z,
PV^.dst_sel_w),
PV^.dfmt,
PV^.nfmt,
count)
);
end;
procedure TEmit_MUBUF._emit_MUBUF;
begin
case FSPI.MUBUF.OP of
BUFFER_LOAD_FORMAT_X:
begin
_emit_BUFFER_LOAD_FORMAT(1);
end;
BUFFER_LOAD_FORMAT_XY:
begin
_emit_BUFFER_LOAD_FORMAT(2);
end;
BUFFER_LOAD_FORMAT_XYZ:
begin
_emit_BUFFER_LOAD_FORMAT(3);
end;
BUFFER_LOAD_FORMAT_XYZW:
begin
_emit_BUFFER_LOAD_FORMAT(4);
end;
BUFFER_STORE_FORMAT_X:
begin
_emit_BUFFER_STORE_FORMAT(1);
end;
BUFFER_STORE_FORMAT_XY:
begin
_emit_BUFFER_STORE_FORMAT(2);
end;
BUFFER_STORE_FORMAT_XYZ:
begin
_emit_BUFFER_STORE_FORMAT(3);
end;
BUFFER_STORE_FORMAT_XYZW:
begin
_emit_BUFFER_STORE_FORMAT(4);
end;
else
Assert(false,'MUBUF?'+IntToStr(FSPI.MUBUF.OP));
end;
end;
end.

1240
spirv/emit_op.pas Normal file

File diff suppressed because it is too large Load Diff

1298
spirv/emit_post.pas Normal file

File diff suppressed because it is too large Load Diff

2306
spirv/emit_post_op.pas Normal file

File diff suppressed because it is too large Load Diff

772
spirv/emit_print.pas Normal file
View File

@ -0,0 +1,772 @@
unit emit_print;
{$mode objfpc}{$H+}
interface
uses
sysutils,
spirv,
srNodes,
srTypes,
srConst,
srReg,
srLayout,
srVariable,
srOp,
srOpUtils,
srCap,
srRefId,
Half16,
SprvEmit;
type
TSprvEmit_print=object(TSprvEmit)
procedure Print;
procedure PrintCaps;
procedure PrintOpList(node:PspirvOp);
procedure PrintHeaderInfo;
procedure PrintTypes;
procedure PrintConst(node:PsrConst);
procedure PrintConst;
procedure PrintVariable;
procedure PrintFunc;
procedure PrintOp(node:PSpirvOp;print_offset:Boolean);
procedure PrintOpBlock(pBlock:PsrOpBlock);
end;
implementation
procedure TSprvEmit_print.Print;
begin
PrintCaps;
Writeln;
PrintHeaderInfo;
Writeln;
PrintTypes;
Writeln;
PrintConst;
Writeln;
PrintVariable;
PrintFunc;
end;
procedure PrintRefId(P:PsrRefId);
begin
Assert(P<>nil ,'PrintRefId$1');
Assert(P^.Alloc,'PrintRefId$2');
Write('%',P^.ID);
end;
procedure PrintConstId(P:PsrConst);
var
s:Single;
i:Int64;
u:QWORD;
begin
Assert(P<>nil ,'PrintConstId$1');
Assert(P^.ID.Alloc,'PrintConstId$2');
Case P^.key.dtype of
dtBool:
begin
Case P^.AsBool of
true :Write('%true');
False:Write('%false');
end;
end;
dtHalf16:
begin
s:=Single(P^.AsHalf16);
i:=Trunc(s);
if (s=i) then
begin
Case i of
0..99:Write('%ch',i);
else
Write('%c',P^.ID.ID);
end;
end else
begin
Write('%c',P^.ID.ID);
end;
end;
dtFloat32:
begin
s:=P^.AsFloat32;
i:=Trunc(s);
if (s=i) then
begin
Case i of
0..99:Write('%cf',i);
-9..-1:Write('%cfm',abs(i));
else
Write('%c',P^.ID.ID);
end;
end else
begin
Write('%c',P^.ID.ID);
end;
end;
dtInt32 :
begin
i:=P^.AsInt;
Case i of
0..99:Write('%ci',i);
-9..-1:Write('%cim',abs(i));
else
Write('%c',P^.ID.ID);
end;
end;
dtUint32:
begin
u:=P^.AsUint;
Case u of
0..99:Write('%cu',u);
else
Write('%c',P^.ID.ID);
end;
end;
else
Write('%c',P^.ID.ID);
end;
end;
procedure PrintVar(P:PsrVariable);
Var
n:RawByteString;
begin
Assert(P<>nil ,'PrintVar$1');
Assert(P^.ID.Alloc,'PrintVar$2');
if (P^.pSource.pData<>nil) then
begin
n:=P^.GetName;
if (n<>'') then
begin
Write('%',n);
end else
begin
Write('%v',P^.ID.ID);
end;
end else
begin
Write('%v',P^.ID.ID);
end;
end;
function type_get_base_name(dtype:TsrDataType):RawByteString;
begin
Result:='';
case dtype of
dtBool :Result:='bool';
dtFloat32 :Result:='float';
dtHalf16 :Result:='half';
dtInt8 :Result:='int8';
dtUint8 :Result:='uint8';
dtInt16 :Result:='int16';
dtUint16 :Result:='uint16';
dtInt32 :Result:='int';
dtUint32 :Result:='uint';
dtInt64 :Result:='int64';
dtUint64 :Result:='uint64';
//Composite types
dtVec2b :Result:='bvec2';
dtVec3b :Result:='bvec3';
dtVec4b :Result:='bvec4';
dtStruct2u :Result:='rec2u';
dtVec2u8 :Result:='u8vec2';
dtVec4u8 :Result:='u8vec4';
dtVec2i8 :Result:='i8vec2';
dtVec4i8 :Result:='i8vec4';
dtVec2u16 :Result:='u16vec2';
dtVec4u16 :Result:='u16vec4';
dtVec2i16 :Result:='i16vec2';
dtVec4i16 :Result:='i16vec4';
dtVec2u :Result:='uvec2';
dtVec3u :Result:='uvec3';
dtVec4u :Result:='uvec4';
dtVec2i :Result:='ivec2';
dtVec3i :Result:='ivec3';
dtVec4i :Result:='ivec4';
dtVec2f :Result:='vec2';
dtVec3f :Result:='vec3';
dtVec4f :Result:='vec4';
dtVec2h :Result:='hvec2';
dtVec4h :Result:='hvec4';
dtTypeVoid :Result:='void';
dtTypeSampler:Result:='samp';
else;
end;
end;
function type_get_base_name(node:PsrType):RawByteString;
var
n:PsrType;
begin
Result:='';
case node^.dtype of
{dtTypeImage:
begin
if DWORD(node^.key.ext.image)=DWORD(ExtImgBuf) then
begin
Result:='buf';
end else
if DWORD(node^.key.ext.image)=DWORD(ExtImage2D) then
begin
Result:='img2D';
end;
end;}
dtTypeSampledImage:
begin
if (node^.key.count<>1) then Exit;
n:=node^.GetCompItem(0);
Result:=type_get_base_name(n);
if (Result='') then Exit;
Result:='sm'+Result;
end;
dtTypeArray:
begin
n:=node^.GetCompItem(0);
Result:=type_get_base_name(n);
if (Result='') then Exit;
Result:='ar'+IntToStr(node^.key.ext.array_count)+Result;
end;
dtTypeRuntimeArray:
begin
n:=node^.GetCompItem(0);
Result:=type_get_base_name(n);
if (Result='') then Exit;
Result:='ra'+Result;
end;
dtTypeStruct:
begin
if (node^.key.count<>1) then Exit;
n:=node^.GetCompItem(0);
Result:=type_get_base_name(n);
if (Result='') then Exit;
Result:='st'+Result;
end;
dtTypeFunction:
begin
if (node^.key.count<>1) then Exit;
n:=node^.GetCompItem(0);
Result:=type_get_base_name(n);
if (Result='') then Exit;
Result:='fn'+Result;
end;
else
Result:=type_get_base_name(node^.dtype);
end;
end;
procedure PrintTypeId(node:PsrType);
var
s:RawByteString;
n:PsrType;
begin
case node^.dtype of
dtTypePointer:
begin
n:=node^.GetCompItem(0);
S:=type_get_base_name(n);
if (S='') then
PrintRefId(@node^.ID)
else
begin
S:='p'+S;
Case node^.key.ext.storage_class of
StorageClass.UniformConstant :S:=S+'_uc';
StorageClass.Input :S:=S+'_in';
StorageClass.Uniform :S:=S+'_uf';
StorageClass.Output :S:=S+'_ot';
StorageClass.Workgroup :S:=S+'_wg';
StorageClass.CrossWorkgroup :S:=S+'_cw';
StorageClass.Private_ :S:=S+'_pv';
StorageClass.Function_ :S:=S+'_fc';
StorageClass.PushConstant :S:=S+'_pc';
StorageClass.Image :S:=S+'_im';
StorageClass.StorageBuffer :S:=S+'_sb';
else
S:='';
end;
if (S='') then
PrintRefId(@node^.ID)
else
Write('%',S);
end;
end;
else
begin
S:=type_get_base_name(node);
if (S='') then
PrintRefId(@node^.ID)
else
Write('%',S);
end;
end;
end;
procedure PrintChain(P:PsrChain);
begin
Assert(P<>nil ,'PrintChain$1');
Assert(P^.ID.Alloc,'PrintChain$2');
Write('%ac',P^.ID.ID);
end;
procedure PrintReg(P:PsrRegNode);
begin
Assert(P<>nil,'PrintReg$1');
Case P^.pWriter.ntype of
ntConst:
begin
PrintConstId(P^.pWriter.pData);
end;
ntOp:
begin
if (not P^.ID.Alloc) then Assert(false,'PrintReg$2');
Write('%r',P^.ID.ID);
//Write('(',P^.read_count,')');
end;
else
Assert(false,'PrintReg$3');
end;
end;
procedure TSprvEmit_print.PrintCaps;
var
node:PSpirvCap;
begin
node:=FSpirvCaps.First;
While (node<>nil) do
begin
Writeln(Op.GetStr(Op.OpCapability),' ',Capability.GetStr(node^.ID));
node:=FSpirvCaps.Next(node);
end;
end;
procedure TSprvEmit_print.PrintOpList(node:PspirvOp);
begin
While (node<>nil) do
begin
PrintOp(node,false);
node:=node^.pNext;
end;
end;
procedure TSprvEmit_print.PrintHeaderInfo;
begin
PrintOpList(FHeader.pHead);
Writeln;
PrintOpList(FDebugInfo.pHead);
if (FDebugInfo.pHead<>nil) then Writeln;
PrintOpList(FDecorates.pHead);
end;
function Dim_GetStr(w:Word):RawByteString;
begin
Result:='';
Case w of
Dim.Dim1D :Result:='1D';
Dim.Dim2D :Result:='2D';
Dim.Dim3D :Result:='3D';
Dim.Cube :Result:='Cube';
Dim.Rect :Result:='Rect';
Dim.Buffer :Result:='Buffer';
Dim.SubpassData:Result:='SubpassData';
else
Assert(False,'Dim_GetStr');
end;
end;
procedure TSprvEmit_print.PrintTypes;
var
node:PsrType;
pConst:PsrConst;
i:dword;
ie:Boolean;
begin
node:=FSpirvTypes.FList.pHead;
While (node<>nil) do
begin
ie:=True;
pConst:=nil;
case node^.dtype of
dtTypeArray:
begin
//find a const
pConst:=FConsts.Fetchi(dtUInt32,node^.key.ext.array_count);
PrintConst(pConst);
end;
else;
end;
PrintTypeId(node);
Write(' = ');
Write(Op.GetStr(node^.key.OpId));
case node^.key.OpId of
Op.OpTypeFloat:
begin
Write(' ',node^.key.ext.float_size);
end;
Op.OpTypeInt:
begin
Write(' ',node^.key.ext.int_size);
Write(' ',node^.key.ext.int_sign);
end;
Op.OpTypeVector:
begin
ie:=False;
Write(' ');
PrintTypeId(node^.GetCompItem(0));
Write(' ',node^.key.ext.array_count);
end;
Op.OpTypePointer:
begin
Write(' ',StorageClass.GetStr(node^.key.ext.Storage_Class));
end;
Op.OpTypeArray:
begin
ie:=False;
Write(' ');
PrintTypeId(node^.GetCompItem(0));
Write(' ');
PrintConstId(pConst);
end;
Op.OpTypeRuntimeArray:
begin
ie:=False;
Write(' ');
PrintTypeId(node^.GetCompItem(0));
end;
Op.OpTypeImage:
begin
ie:=False;
Write(' ');
PrintTypeId(node^.GetCompItem(0));
With node^.key.ext.image do
Write(' ',
Dim_GetStr(Dim),' ',
Depth,' ',
Arrayed,' ',
MS,' ',
Sampled,' ',
Spirv.ImageFormat.GetStr(Format));
end;
end;
if ie then
if (node^.key.count<>0) then
begin
For i:=0 to node^.key.count-1 do
begin
Write(' ');
PrintTypeId(node^.GetCompItem(i));
end;
end;
Writeln;
node:=node^.pNext;
end;
end;
const
DefaultFormatSettings : TFormatSettings = (
CurrencyFormat: 1;
NegCurrFormat: 5;
ThousandSeparator: ',';
DecimalSeparator: '.';
CurrencyDecimals: 2;
DateSeparator: '-';
TimeSeparator: ':';
ListSeparator: ',';
CurrencyString: '$';
ShortDateFormat: 'd/m/y';
LongDateFormat: 'dd" "mmmm" "yyyy';
TimeAMString: 'AM';
TimePMString: 'PM';
ShortTimeFormat: 'hh:nn';
LongTimeFormat: 'hh:nn:ss';
ShortMonthNames: ('Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec');
LongMonthNames: ('January','February','March','April','May','June',
'July','August','September','October','November','December');
ShortDayNames: ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
LongDayNames: ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
TwoDigitYearCenturyWindow: 50;
);
procedure TSprvEmit_print.PrintConst(node:PsrConst);
var
i:dword;
begin
PrintConstId(node);
Write(' = ');
if (node^.key.count=0) then
begin
if (node^.key.dtype=dtBool) then
begin
Case node^.AsBool of
True :Write(Op.GetStr(Op.OpConstantTrue));
False:Write(Op.GetStr(Op.OpConstantFalse));
end;
Write(' ');
PrintTypeId(node^.pType);
end else
begin
Write(Op.GetStr(Op.OpConstant));
Write(' ');
PrintTypeId(node^.pType);
Write(' ');
case node^.key.dtype of
dtFloat32:Write(FloatToStr(node^.AsFloat32,DefaultFormatSettings));
dtHalf16 :Write(FloatToStr(Single(node^.AsHalf16),DefaultFormatSettings));
dtInt32 :Write(node^.AsInt);
dtUint32 :Write(node^.AsUint);
dtInt64 :Write(node^.AsInt64);
dtUint64 :Write(node^.AsUint64);
else
Assert(false,'PrintConst');
end;
end;
end else
begin
Write(Op.GetStr(Op.OpConstantComposite));
Write(' ');
PrintTypeId(node^.pType);
For i:=0 to node^.key.count-1 do
begin
Write(' ');
PrintConstId(node^.GetCompItem(i));
end;
end;
Writeln;
end;
procedure TSprvEmit_print.PrintConst;
var
node:PsrConst;
begin
node:=FConsts.FList.pHead;
While (node<>nil) do
begin
//if not node^.is_first then
//begin
if (node^.key.dtype=dtUnknow) then
begin
Write('; ');
PrintConstId(node);
Writeln(' = dtUnknow: read_count=',node^.read_count,' value=',node^.Data);
end else
//Assert(node^.dtype<>dtUnknow);
PrintConst(node);
//end;
node:=node^.pNext;
end;
end;
procedure TSprvEmit_print.PrintVariable;
var
node:PsrVariable;
begin
node:=FVariables.pHead;
While (node<>nil) do
begin
if (node^.pType<>nil) then
begin
PrintVar(node);
Write(' = ',Op.GetStr(Op.OpVariable),' ');
PrintTypeId(node^.pType);
Writeln(' ',StorageClass.GetStr(node^.GetStorageClass));
end;
node:=node^.pNext;
end;
end;
procedure PrintFuncId(P:PSpirvFunc);
begin
Assert(P<>nil,'PrintFuncId');
if (P^.name<>'') then
begin
Write('%',P^.name);
end else
begin
PrintRefId(@P^.ID);
end;
end;
procedure PrintOpParamSingle(const Param:TOpParamSingle);
begin
Assert(Param.pData<>nil,'PrintOpParamSingle$1');
Case Param.ntype of
ntFunc :PrintFuncId(Param.pData);
ntRefId:PrintRefId(Param.pData);
ntType :PrintTypeId(Param.pData);
ntReg :PrintReg(Param.pData);
ntVar :PrintVar(Param.pData);
ntChain:PrintChain(Param.pData);
ntConst:PrintConstId(Param.pData);
else
Assert(false,'PrintOpParamSingle$2');
end;
end;
procedure PrintOpParamNode(node:POpParamNode);
begin
Case node^.ntype of
ntLiteral:
begin
if StrLen(@node^.name)=0 then
begin
Write(node^.Value);
end else
begin
Write(PChar(@node^.name));
end;
end;
ntString:
begin
Write('"',PChar(@node^.name),'"');
end;
else
begin
PrintOpParamSingle(node^.AsParam);
end;
end;
end;
procedure TSprvEmit_print.PrintFunc;
var
pFunc:PSpirvFunc;
begin
pFunc:=FSpirvFuncs.FList.pHead;
While (pFunc<>nil) do
begin
Writeln;
PrintOpBlock(@pFunc^.FTop);
pFunc:=pFunc^.pNext;
end;
end;
procedure TSprvEmit_print.PrintOp(node:PSpirvOp;print_offset:Boolean);
var
Param:POpParamNode;
Info:Op.TOpInfo;
begin
if (node=nil) then Exit;
Info:=Op.GetInfo(node^.OpId);
if Info.result then //dst
begin
Assert(node^.dst.ntype<>ntUnknow,'PrintOp$1');
Assert(node^.dst.pData<>nil,'PrintOp$2');
PrintOpParamSingle(node^.dst);
Write(' = ');
Write(Op.GetStr(node^.OpId));
end else
begin //no dst
Write(Op.GetStr(node^.OpId));
if (node^.dst.ntype<>ntUnknow) then
begin
Assert(node^.dst.pData<>nil,'PrintOp$3');
Write(' ');
PrintOpParamSingle(node^.dst);
end;
end;
if Info.rstype then //dst type
begin
Assert(node^.dst_type<>nil,'PrintOp$4');
Write(' ');
PrintTypeId(node^.dst_type);
end;
Param:=node^.pParam.pHead;
While (Param<>nil) do
begin
Write(' ');
PrintOpParamNode(Param);
Param:=Param^.pNext;
end;
if (node^.OpId=Op.OpLabel) then
begin
print_offset:=true;
end;
Case print_offset of
True :Writeln(' ;0x',HexStr(Node^.Adr.Offdw*4,4));
False:Writeln;
end;
end;
procedure TSprvEmit_print.PrintOpBlock(pBlock:PsrOpBlock);
var
node:PSpirvOp;
begin
if (pBlock=nil) then Exit;
node:=pBlock^.pHead;
While (node<>nil) do
begin
if (node^.OpId=OpBlock) then
begin
if (node^.dst.ntype=ntBlock) then
begin
PrintOpBlock(node^.dst.pData);
end;
end else
begin
Write(Space(pBlock^.FLevel));
PrintOp(node,false);
end;
node:=node^.pNext;
end;
end;
end.

155
spirv/emit_smrd.pas Normal file
View File

@ -0,0 +1,155 @@
unit emit_SMRD;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srReg,
srLayout,
SprvEmit,
emit_op;
type
TEmit_SMRD=object(TEmitOp)
procedure _emit_SMRD;
procedure _emit_LOAD_DWORDX(grp:PsrDataLayout;count:Byte);
procedure emit_LOAD_DWORDX(count:Byte);
procedure emit_BUFFER_LOAD_DWORDX(count:Byte);
end;
implementation
procedure TEmit_SMRD._emit_LOAD_DWORDX(grp:PsrDataLayout;count:Byte);
var
dst:PsrRegSlot;
ofs_r,idx_r:PsrRegNode;
dtype:TsrDataType;
ext:TsrChainExt;
i:Byte;
begin
if (FSPI.SMRD.IMM<>0) then
begin
For i:=0 to count-1 do
begin
dst:=FRegsStory.get_sdst7(FSPI.SMRD.SDST+i);
Assert(dst<>nil);
MakeChain(dst,grp,(FSPI.SMRD.OFFSET+i)*4,4,nil);
end;
end else
begin
ofs_r:=fetch_ssrc9(FSPI.SMRD.OFFSET,dtUint32);
dtype:=ofs_r^.dtype;
idx_r:=NewReg(dtype);
_emit_OpShr(line,idx_r,ofs_r,FetchReg(FConsts.Fetchi(dtype,2)));
For i:=0 to count-1 do
begin
dst:=FRegsStory.get_sdst7(FSPI.SMRD.SDST+i);
Assert(dst<>nil);
if (i=0) then
begin
ofs_r:=idx_r;
end else
begin
ofs_r:=NewReg(dtype);
idx_r^.mark_read;
_emit_OpIAdd(line,ofs_r,idx_r,FetchReg(FConsts.Fetchi(dtype,i)));
end;
ofs_r^.mark_read;
ext:=Default(TsrChainExt);
ext.pIndex:=ofs_r;
ext.stride:=4;
MakeChain(dst,grp,0,4,@ext);
end;
end;
end;
procedure TEmit_SMRD.emit_LOAD_DWORDX(count:Byte);
var
src:array[0..3] of PsrRegSlot;
grp:PsrDataLayout;
begin
if not FRegsStory.get_sbase(FSPI.SMRD.SBASE,2,@src) then Assert(false);
grp:=GroupingSharp(@src,rtBufPtr2);
_emit_LOAD_DWORDX(grp,count);
end;
procedure TEmit_SMRD.emit_BUFFER_LOAD_DWORDX(count:Byte);
var
src:array[0..3] of PsrRegSlot;
grp:PsrDataLayout;
begin
if not FRegsStory.get_sbase(FSPI.SMRD.SBASE,4,@src) then Assert(false);
grp:=GroupingSharp(@src,rtVSharp4);
_emit_LOAD_DWORDX(grp,count);
end;
procedure TEmit_SMRD._emit_SMRD;
begin
Case FSPI.SMRD.OP of
S_BUFFER_LOAD_DWORD:
begin
emit_BUFFER_LOAD_DWORDX(1);
end;
S_BUFFER_LOAD_DWORDX2:
begin
emit_BUFFER_LOAD_DWORDX(2);
end;
S_BUFFER_LOAD_DWORDX4:
begin
emit_BUFFER_LOAD_DWORDX(4);
end;
S_BUFFER_LOAD_DWORDX8:
begin
emit_BUFFER_LOAD_DWORDX(8);
end;
S_BUFFER_LOAD_DWORDX16:
begin
emit_BUFFER_LOAD_DWORDX(16);
end;
S_LOAD_DWORD:
begin
emit_LOAD_DWORDX(1);
end;
S_LOAD_DWORDX2:
begin
emit_LOAD_DWORDX(2);
end;
S_LOAD_DWORDX4:
begin
emit_LOAD_DWORDX(4);
end;
S_LOAD_DWORDX8:
begin
emit_LOAD_DWORDX(8);
end;
S_LOAD_DWORDX16:
begin
emit_LOAD_DWORDX(16);
end;
else
Assert(false,'SMRD?'+IntToStr(FSPI.SMRD.OP));
end;
end;
end.

245
spirv/emit_sop1.pas Normal file
View File

@ -0,0 +1,245 @@
unit emit_SOP1;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srLabel,
srTypes,
srConst,
srReg,
srLayout,
SprvEmit,
emit_op;
type
TEmit_SOP1=object(TEmitOp)
procedure _emit_SOP1;
Function _GetFuncPtr(src:PPsrRegSlot):Pointer;
procedure _emit_S_MOV_B32;
procedure _emit_S_MOV_B64;
procedure _emit_S_SWAPPC_B64;
procedure _emit_S_SETPC_B64;
procedure _emit_S_AND_SAVEEXEC_B64;
procedure _emit_S_WQM_B64;
end;
implementation
Function TEmit_SOP1._GetFuncPtr(src:PPsrRegSlot):Pointer;
var
chain:TsrChains;
pLayout:PsrDataLayout;
begin
Result:=nil;
chain:=Default(TsrChains);
chain[0]:=GetChainRegNode(src[0]^.current);
chain[1]:=GetChainRegNode(src[1]^.current);
pLayout:=FDataLayouts.Grouping(chain,rtFunPtr2);
Result:=pLayout^.pData;
Assert(Result<>nil);
end;
procedure TEmit_SOP1._emit_S_MOV_B32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP1.SDST);
src:=fetch_ssrc9(FSPI.SOP1.SSRC,dtUnknow);
_MakeCopy(dst,src);
end;
procedure TEmit_SOP1._emit_S_MOV_B64;
Var
dst:array[0..1] of PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst[0]:=FRegsStory.get_sdst7(FSPI.SOP1.SDST+0);
dst[1]:=FRegsStory.get_sdst7(FSPI.SOP1.SDST+1);
src[0]:=fetch_ssrc9(FSPI.SOP1.SSRC+0,dtUnknow);
src[1]:=fetch_ssrc9(FSPI.SOP1.SSRC+1,dtUnknow);
_MakeCopy(dst[0],src[0]);
_MakeCopy(dst[1],src[1]);
end;
procedure TEmit_SOP1._emit_S_SWAPPC_B64;
Var
dst:array[0..1] of PsrRegSlot;
src:array[0..1] of PsrRegSlot;
oldptr,newptr:Pointer;
begin
if not FRegsStory.get_sdst7_pair(FSPI.SOP1.SDST,@dst) then Assert(false);
Assert(not is_const_ssrc9(FSPI.SOP1.SSRC));
if not FRegsStory.get_ssrc9_pair(FSPI.SOP1.SSRC,@src) then Assert(false);
newptr:=_GetFuncPtr(@src);
Assert(newptr<>nil);
oldptr:=FCursor.Adr.get_pc;
SetConst(dst[0],dtUint32,{%H-}QWORD(oldptr));
SetConst(dst[1],dtUint32,{%H-}QWORD(oldptr) shr 32);
SetPtr(newptr,btSetpc);
end;
procedure TEmit_SOP1._emit_S_SETPC_B64;
Var
src:array[0..1] of PsrRegSlot;
node:array[0..1] of PsrRegNode;
pConst:array[0..1] of PsrConst;
newptr:Pointer;
begin
Assert(not is_const_ssrc9(FSPI.SOP1.SSRC));
if not FRegsStory.get_ssrc9_pair(FSPI.SOP1.SSRC,@src) then Assert(false);
node[0]:=RegDown(src[0]^.current);
node[1]:=RegDown(src[1]^.current);
Assert(node[0]<>nil);
Assert(node[1]<>nil);
if (node[0]^.is_const) and (node[1]^.is_const) then
begin
//ret of func
pConst[0]:=node[0]^.AsConst;
pConst[1]:=node[1]^.AsConst;
{%H-}QWORD(newptr):=QWORD(pConst[0]^.AsUint) or (QWORD(pConst[1]^.AsUint) shl 32);
SetPtr(newptr,btMain);
end else
begin
Assert(false);
end;
end;
procedure TEmit_SOP1._emit_S_AND_SAVEEXEC_B64; //sdst.du = EXEC;| EXEC = (ssrc.du & EXEC);| SCC = (sdst != 0)
Var
dst:array[0..1] of PsrRegSlot;
src:array[0..1] of PsrRegNode;
exc:array[0..1] of PsrRegNode;
begin
dst[0]:=FRegsStory.get_sdst7(FSPI.SOP1.SDST+0);
dst[1]:=FRegsStory.get_sdst7(FSPI.SOP1.SDST+1);
Assert(dst[0]<>nil);
Assert(dst[1]<>nil);
if not fetch_ssrc9_pair(@src,FSPI.SOP1.SSRC,dtUnknow) then Assert(False); //ssrc8
PrepTypeSlot(@FRegsStory.EXEC[0],dtUnknow);
PrepTypeSlot(@FRegsStory.EXEC[1],dtUnknow);
exc[0]:=FRegsStory.EXEC[0].current;
exc[1]:=FRegsStory.EXEC[1].current;
MakeCopy(dst[0],exc[0]);
MakeCopy(dst[1],exc[1]);
exc[0]^.mark_read;
exc[1]^.mark_read;
emit_OpBitwiseAnd(@FRegsStory.EXEC[0],src[0],exc[0]);
emit_OpBitwiseAnd(@FRegsStory.EXEC[1],src[1],exc[1]);
//SCC = ((exc[0] != 0) or ((exc[1] != 0))
exc[0]^.mark_read;
exc[1]^.mark_read;
emit_OpLogicalOr(@FRegsStory.SCC,exc[0],exc[1]); //implict cast (int != 0)
//SCC = (sdst != 0) SCC = ((exc[0] != 0) or ((exc[1] != 0))
end;
procedure TEmit_SOP1._emit_S_WQM_B64;
Var
dst:array[0..1] of PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
//S_WQM_B64 EXEC_LO, EXEC_LO //sdst.du = wholeQuadMode(ssrc.du); SCC = (sdst.du != 0)
//dst[q*4+3:q*4].du = (ssrc[4*q+3:4*q].du != 0) ? 0xF : 0
//dst[3:0].du = (ssrc[3:0].du != 0) ? 0xF : 0
//dst[63:60].du = (ssrc[63:60].du != 0) ? 0xF : 0
//if (ssrc[3:0].du != 0) then dst[63:60].du=0xF else dst[63:60].du=0
dst[0]:=FRegsStory.get_sdst7(FSPI.SOP1.SDST+0);
dst[1]:=FRegsStory.get_sdst7(FSPI.SOP1.SDST+1);
Assert(dst[0]<>nil);
Assert(dst[1]<>nil);
if not fetch_ssrc9_pair(@src,FSPI.SOP1.SSRC,dtUnknow) then Assert(False); //ssrc8
emit_WQM_32(dst[0],src[0]);
emit_WQM_32(dst[1],src[1]);
end;
procedure TEmit_SOP1._emit_SOP1;
begin
Case FSPI.SOP1.OP of
S_MOV_B32:
begin
_emit_S_MOV_B32;
end;
S_MOV_B64:
begin
_emit_S_MOV_B64;
end;
S_WQM_B64:
begin
_emit_S_WQM_B64;
end;
S_SWAPPC_B64:
begin
_emit_S_SWAPPC_B64;
end;
S_SETPC_B64:
begin
_emit_S_SETPC_B64;
end;
S_AND_SAVEEXEC_B64:
begin
_emit_S_AND_SAVEEXEC_B64;
end;
else
Assert(false,'SOP1?'+IntToStr(FSPI.SOP1.OP));
end;
end;
end.

345
spirv/emit_sop2.pas Normal file
View File

@ -0,0 +1,345 @@
unit emit_SOP2;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srConst,
srReg,
SprvEmit,
emit_op;
type
TEmit_SOP2=object(TEmitOp)
procedure _emit_SOP2;
procedure _emit_S_ADD_I32;
procedure _emit_S_MUL_I32;
procedure _emit_S_LSHL_B32;
procedure _emit_S_LSHR_B32;
procedure _emit_S_AND_B32;
procedure _emit_S_AND_B64;
procedure _emit_S_ANDN2_B64;
procedure _emit_S_OR_B64;
procedure _emit_S_NOR_B64;
procedure _emit_S_CSELECT_B32;
procedure _emit_S_BFE_U32;
end;
implementation
procedure TEmit_SOP2._emit_S_ADD_I32;
Var
dst,car:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
car:=@FRegsStory.SCC;
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtInt32);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtInt32);
emit_OpIAddExt(dst,car,src[0],src[1]);
end;
procedure TEmit_SOP2._emit_S_MUL_I32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtInt32);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtInt32);
emit_OpIMul(dst,src[0],src[1]);
end;
procedure TEmit_SOP2._emit_S_LSHL_B32; //SCC = (sdst.u != 0)
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtUInt32);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtUInt32);
src[2]:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[1],src[2]);
src[1]:=MakeRead(tmp,dtUInt32);
emit_OpShl(dst,src[0],src[1]);
//dst = dtUint32
tmp:=@FRegsStory.SCC;
MakeCopy(tmp,dst^.current);
tmp^.current^.dtype:=dtBool;
//dst^.current^.mark_read;
//emit_IntToBool(line,FRegsStory.SCC.New(dtBool),dst^.current);
end;
procedure TEmit_SOP2._emit_S_LSHR_B32; //SCC = (sdst.u != 0)
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtUInt32);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtUInt32);
src[2]:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[1],src[2]);
src[1]:=MakeRead(tmp,dtUInt32);
emit_OpShr(dst,src[0],src[1]);
tmp:=@FRegsStory.SCC;
MakeCopy(tmp,dst^.current);
tmp^.current^.dtype:=dtBool;
end;
procedure TEmit_SOP2._emit_S_AND_B32; //SCC = (sdst.u != 0)
Var
dst,tmp:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtUInt32);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtUInt32);
emit_OpBitwiseAnd(dst,src[0],src[1]);
tmp:=@FRegsStory.SCC;
MakeCopy(tmp,dst^.current);
tmp^.current^.dtype:=dtBool;
end;
procedure TEmit_SOP2._emit_S_AND_B64; //SCC = (sdst[2] != 0)
Var
dst:array[0..1] of PsrRegSlot;
src0,src1,src2:array[0..1] of PsrRegNode;
begin
if not FRegsStory.get_sdst7_pair(FSPI.SOP2.SDST,@dst) then Assert(False);
if not fetch_ssrc9_pair(@src0,FSPI.SOP2.SSRC0,dtUInt32) then Assert(False);
if not fetch_ssrc9_pair(@src1,FSPI.SOP2.SSRC1,dtUInt32) then Assert(False);
emit_OpBitwiseAnd(dst[0],src0[0],src1[0]);
emit_OpBitwiseAnd(dst[1],src0[1],src1[1]);
src2[0]:=dst[0]^.current;
src2[1]:=dst[1]^.current;
src2[0]^.mark_read;
src2[1]^.mark_read;
emit_OpLogicalOr(@FRegsStory.SCC,src2[0],src2[1]); //implict cast (int != 0)
end;
procedure TEmit_SOP2._emit_S_ANDN2_B64; //SCC = (sdst[2] != 0)
Var
dst:array[0..1] of PsrRegSlot;
tmp:PsrRegSlot;
src0,src1,src2:array[0..1] of PsrRegNode;
begin
if not FRegsStory.get_sdst7_pair(FSPI.SOP2.SDST,@dst) then Assert(False);
if not fetch_ssrc9_pair(@src0,FSPI.SOP2.SSRC0,dtUInt32) then Assert(False);
if not fetch_ssrc9_pair(@src1,FSPI.SOP2.SSRC1,dtUInt32) then Assert(False);
tmp:=@FRegsStory.FUnattach;
emit_OpNot(tmp,src1[0]);
src1[0]:=MakeRead(tmp,dtUnknow);
emit_OpNot(tmp,src1[1]);
src1[1]:=MakeRead(tmp,dtUnknow);
emit_OpBitwiseAnd(dst[0],src0[0],src1[0]);
emit_OpBitwiseAnd(dst[1],src0[1],src1[1]);
src2[0]:=dst[0]^.current;
src2[1]:=dst[1]^.current;
src2[0]^.mark_read;
src2[1]^.mark_read;
emit_OpLogicalOr(@FRegsStory.SCC,src2[0],src2[1]); //implict cast (int != 0)
end;
procedure TEmit_SOP2._emit_S_OR_B64; //SCC = (sdst[2] != 0)
Var
dst:array[0..1] of PsrRegSlot;
src0,src1,src2:array[0..1] of PsrRegNode;
begin
if not FRegsStory.get_sdst7_pair(FSPI.SOP2.SDST,@dst) then Assert(False);
if not fetch_ssrc9_pair(@src0,FSPI.SOP2.SSRC0,dtUInt32) then Assert(False);
if not fetch_ssrc9_pair(@src1,FSPI.SOP2.SSRC1,dtUInt32) then Assert(False);
emit_OpBitwiseOr(dst[0],src0[0],src1[0]);
emit_OpBitwiseOr(dst[1],src0[1],src1[1]);
src2[0]:=dst[0]^.current;
src2[1]:=dst[1]^.current;
src2[0]^.mark_read;
src2[1]^.mark_read;
emit_OpLogicalOr(@FRegsStory.SCC,src2[0],src2[1]); //implict cast (int != 0)
end;
procedure TEmit_SOP2._emit_S_NOR_B64; //SCC = (sdst[2] != 0)
Var
dst:array[0..1] of PsrRegSlot;
src0,src1,src2:array[0..1] of PsrRegNode;
begin
if not FRegsStory.get_sdst7_pair(FSPI.SOP2.SDST,@dst) then Assert(False);
if not fetch_ssrc9_pair(@src0,FSPI.SOP2.SSRC0,dtUInt32) then Assert(False);
if not fetch_ssrc9_pair(@src1,FSPI.SOP2.SSRC1,dtUInt32) then Assert(False);
emit_OpBitwiseOr(dst[0],src0[0],src1[0]);
emit_OpBitwiseOr(dst[1],src0[1],src1[1]);
src2[0]:=dst[0]^.current;
src2[1]:=dst[1]^.current;
src2[0]^.mark_read;
src2[1]^.mark_read;
emit_OpNot(dst[0],src2[0]);
emit_OpNot(dst[1],src2[1]);
src2[0]:=dst[0]^.current;
src2[1]:=dst[1]^.current;
src2[0]^.mark_read;
src2[1]^.mark_read;
emit_OpLogicalOr(@FRegsStory.SCC,src2[0],src2[1]); //implict cast (int != 0)
end;
procedure TEmit_SOP2._emit_S_CSELECT_B32; //sdst = SCC ? ssrc0 : ssrc1
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtUnknow);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtUnknow);
src[2]:=MakeRead(@FRegsStory.SCC,dtBool);
emit_OpSelect(dst,src[0],src[1],src[2]);
end;
//offset = ssrc1[4:0].u and 31
//width = ssrc1[22:16].u shr 16
procedure TEmit_SOP2._emit_S_BFE_U32; //sdst.u = bitFieldExtract(ssrc0); SCC = (sdst.u != 0)
Var
dst,tmp:PsrRegSlot;
src:array[0..1] of PsrRegNode;
num_31,num_16:PsrRegNode;
offset,count:PsrRegNode;
begin
dst:=FRegsStory.get_sdst7(FSPI.SOP2.SDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.SOP2.SSRC0,dtUint32);
src[1]:=fetch_ssrc9(FSPI.SOP2.SSRC1,dtUint32);
num_31:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[1],num_31);
offset:=MakeRead(tmp,dtUInt32);
num_16:=FetchReg(FConsts.Fetch(dtUInt32,16));
src[1]^.mark_read;
emit_OpShr(tmp,src[1],num_16);
count:=MakeRead(tmp,dtUInt32);
emit_OpBfeU(dst,src[0],offset,count);
tmp:=@FRegsStory.SCC;
MakeCopy(tmp,dst^.current);
tmp^.current^.dtype:=dtBool;
end;
procedure TEmit_SOP2._emit_SOP2;
begin
Case FSPI.SOP2.OP of
S_ADD_I32:
begin
_emit_S_ADD_I32;
end;
S_MUL_I32: //& 0xFFFFFFFF
begin
_emit_S_MUL_I32;
end;
S_LSHL_B32: //SCC = (sdst.u != 0)
begin
_emit_S_LSHL_B32;
end;
S_LSHR_B32:
begin
_emit_S_LSHR_B32;
end;
S_AND_B32:
begin
_emit_S_AND_B32;
end;
S_AND_B64:
begin
_emit_S_AND_B64;
end;
S_ANDN2_B64:
begin
_emit_S_ANDN2_B64;
end;
S_OR_B64:
begin
_emit_S_OR_B64;
end;
S_NOR_B64:
begin
_emit_S_NOR_B64;
end;
S_CSELECT_B32:
begin
_emit_S_CSELECT_B32;
end;
S_BFE_U32:
begin
_emit_S_BFE_U32;
end;
else
Assert(False,'SOP2?'+IntToStr(FSPI.SOP2.OP));
end;
end;
end.

66
spirv/emit_sopc.pas Normal file
View File

@ -0,0 +1,66 @@
unit emit_SOPC;
{$mode objfpc}{$H+}
interface
uses
sysutils,
spirv,
ps4_pssl,
srTypes,
srReg,
SprvEmit,
emit_op;
type
TEmit_SOPC=object(TEmitOp)
procedure _emit_SOPC;
procedure _emit_S_CMP_32(OpId:DWORD;rtype:TsrDataType);
end;
implementation
procedure TEmit_SOPC._emit_S_CMP_32(OpId:DWORD;rtype:TsrDataType);
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=@FRegsStory.SCC;
src[0]:=fetch_ssrc9(FSPI.SOPC.SSRC0,rtype);
src[1]:=fetch_ssrc9(FSPI.SOPC.SSRC1,rtype);
emit_OpCmpS(OpId,dst,src[0],src[1]);
end;
procedure TEmit_SOPC._emit_SOPC;
begin
Case FSPI.SOPC.OP of
S_CMP_EQ_I32 :_emit_S_CMP_32(Op.OpIEqual ,dtInt32);
S_CMP_LG_I32 :_emit_S_CMP_32(Op.OpINotEqual ,dtInt32);
S_CMP_GT_I32 :_emit_S_CMP_32(Op.OpSGreaterThan ,dtInt32);
S_CMP_GE_I32 :_emit_S_CMP_32(Op.OpSGreaterThanEqual,dtInt32);
S_CMP_LT_I32 :_emit_S_CMP_32(Op.OpSLessThan ,dtInt32);
S_CMP_LE_I32 :_emit_S_CMP_32(Op.OpSLessThanEqual ,dtInt32);
S_CMP_EQ_U32 :_emit_S_CMP_32(Op.OpIEqual ,dtUint32);
S_CMP_LG_U32 :_emit_S_CMP_32(Op.OpINotEqual ,dtUint32);
S_CMP_GT_U32 :_emit_S_CMP_32(Op.OpUGreaterThan ,dtUint32);
S_CMP_GE_U32 :_emit_S_CMP_32(Op.OpUGreaterThanEqual,dtUint32);
S_CMP_LT_U32 :_emit_S_CMP_32(Op.OpULessThan ,dtUint32);
S_CMP_LE_U32 :_emit_S_CMP_32(Op.OpULessThanEqual ,dtUint32);
//S_BITCMP0_B32:;
//S_BITCMP1_B32:;
//S_BITCMP0_B64:;
//S_BITCMP1_B64:;
//S_SETVSKIP :;
else
Assert(false,'SOPC?'+IntToStr(FSPI.SOPC.OP));
end;
end;
end.

300
spirv/emit_sopp.pas Normal file
View File

@ -0,0 +1,300 @@
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;
procedure emit_cond_block(pSlot:PsrRegSlot;n:Boolean;adr:TSrcAdr);
procedure UpBuildVol(last:PsrOpBlock);
procedure emit_loop(adr:TSrcAdr);
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;
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;
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');
Assert(false,'TODO');
end else
begin //down
if FCursor.pBlock^.IsBigOf(b_adr) then
begin //break?
if not IsEndLoop(b_adr) then Assert(false,'Unknow');
Assert(false,'TODO');
end else
begin //cond
emit_cond_block(pSlot,n,c_adr);
end;
end;
end;
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);
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.

417
spirv/emit_vbuf_chain.pas Normal file
View File

@ -0,0 +1,417 @@
unit emit_vbuf_chain;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
ps4_shader,
ps4_pssl,
srTypes,
srConst,
srReg,
srLayout,
SprvEmit,
emit_op,
srVBufInfo;
type
TBuf_adr=packed record
stride,align,fsize,csize:PtrInt;
soffset,ioffset,voffset:PtrInt;
sof,ofs,idx:PsrRegNode;
end;
TvcType=(vcInvalid,vcChainVector,vcChainElement,vcUniformVector,vcUniformElement);
TvarChain=record
vType:TvcType;
data:array[0..1] of Pointer;
end;
TEmit_vbuf_chain=object(TEmitOp)
function OpDivTo(pReg:PsrRegNode;i:QWORD):PsrRegNode;
function OpMulTo(pReg:PsrRegNode;i:QWORD):PsrRegNode;
function OpAddTo(pReg:PsrRegNode;i:QWORD):PsrRegNode;
function OpAddTo(pReg0,pReg1:PsrRegNode):PsrRegNode;
procedure get_reg_adr(var adr:TBuf_adr);
function get_sum_ofs(var adr:TBuf_adr):PsrRegNode;
function get_idx_elm(var adr:TBuf_adr):PsrRegNode;
function get_idx_fmt(var adr:TBuf_adr):PsrRegNode;
function get_chain(info:TBuf_info):TvarChain;
end;
implementation
function isPowerOfTwo(x:QWORD):Boolean; inline;
begin
Result:=((x-1) and x)=0;
end;
function fastIntLog2(i:QWORD):QWORD; inline;
begin
Result:=BsfQWORD(i);
end;
function TEmit_vbuf_chain.OpDivTo(pReg:PsrRegNode;i:QWORD):PsrRegNode;
begin
if (pReg=nil) or (i<=1) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
if isPowerOfTwo(i) then
begin
i:=fastIntLog2(i);
if (SignType(pReg^.dtype)<>0) then
begin
_emit_OpShrA(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end else
begin
_emit_OpShr(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end;
end else
begin
if (SignType(pReg^.dtype)<>0) then
begin
_emit_OpSDiv(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end else
begin
_emit_OpUDiv(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end;
end;
end;
function TEmit_vbuf_chain.OpMulTo(pReg:PsrRegNode;i:QWORD):PsrRegNode;
begin
if (pReg=nil) or (i<=1) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
if isPowerOfTwo(i) then
begin
i:=fastIntLog2(i);
_emit_OpShl(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end else
begin
_emit_OpIMul(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end;
end;
function TEmit_vbuf_chain.OpAddTo(pReg:PsrRegNode;i:QWORD):PsrRegNode;
begin
if (pReg=nil) or (i=0) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
_emit_OpIAdd(line,Result,pReg,FetchReg(FConsts.Fetchi(pReg^.dtype,i)));
end;
function TEmit_vbuf_chain.OpAddTo(pReg0,pReg1:PsrRegNode):PsrRegNode;
begin
if (pReg0=nil) then Exit(pReg1);
if (pReg1=nil) then Exit(pReg0);
Result:=NewReg(pReg0^.dtype);
pReg0^.mark_read;
pReg1^.mark_read;
_emit_OpIAdd(line,Result,pReg0,pReg1);
end;
procedure TEmit_vbuf_chain.get_reg_adr(var adr:TBuf_adr);
var
ofs:PsrRegSlot;
begin
if is_const_soffset(FSPI.MUBUF.SOFFSET) then
begin
adr.soffset:=get_soffset_const_int(FSPI.MUBUF.SOFFSET);
end else
begin
ofs:=FRegsStory.get_ssrc8(FSPI.MUBUF.SOFFSET);
if (ofs<>nil) then
begin
adr.sof:=ofs^.current;
if (adr.sof<>nil) then
begin
if (adr.sof^.is_const) then
begin
adr.soffset:=adr.sof^.AsConst^.AsInt;
adr.sof:=nil;
end else
begin
Assert(false,'FSPI.MUBUF.SOFFSET');
end;
end;
end;
end;
ofs:=nil;
if (FSPI.MUBUF.IDXEN=1) then
begin
adr.idx:=fetch_vsrc8(FSPI.MUBUF.VADDR+0,dtInt32);
if (FSPI.MUBUF.OFFEN=1) then
begin
ofs:=FRegsStory.get_vsrc8(FSPI.MUBUF.VADDR+1);
end;
end else
if (FSPI.MUBUF.OFFEN=1) then
begin
ofs:=FRegsStory.get_vsrc8(FSPI.MUBUF.VADDR+0);
end;
if (ofs<>nil) then
begin
adr.ofs:=ofs^.current;
if (adr.ofs<>nil) then
begin
if (adr.ofs^.is_const) then
begin
adr.voffset:=adr.ofs^.AsConst^.AsInt;
adr.ofs:=nil;
end else
begin
adr.ofs:=MakeRead(ofs,dtInt32);
end;
end;
end;
end;
function TEmit_vbuf_chain.get_sum_ofs(var adr:TBuf_adr):PsrRegNode;
var
foffset:PtrInt;
sum_d,ofs_d,idx_m:PsrRegNode;
begin
foffset:=adr.soffset+adr.ioffset+adr.voffset;
if (foffset mod adr.align=0) and //const offset is align
((adr.idx=nil) or //no index or
(adr.stride mod adr.align=0)) then //stride is align
begin
//(foffset is Align)
//(stride is Align)
//result=(foffset/Align+ofs/Align+idx*(stride/Align)) in elem
adr.ofs^.mark_unread;
ofs_d:=OpDivTo(adr.ofs,adr.align); //ofs/Align
sum_d:=OpAddTo(ofs_d,foffset div adr.align); //foffset/Align+ofs/Align
if (adr.idx<>nil) then
begin
adr.idx^.mark_unread;
idx_m:=OpMulTo(adr.idx,adr.stride div adr.align); //idx*(stride/Align)
sum_d:=OpAddTo(sum_d,idx_m);
end;
end else
begin
//result=(foffset+ofs+idx*stride)/Align in elem
adr.ofs^.mark_unread;
sum_d:=OpAddTo(adr.ofs,foffset); //foffset+ofs
if (adr.idx<>nil) then
begin
adr.idx^.mark_unread;
idx_m:=OpMulTo(adr.idx,adr.stride); //idx*stride
sum_d:=OpAddTo(sum_d,idx_m);
end;
sum_d:=OpDivTo(sum_d,adr.align); // sum/Align
end;
Result:=sum_d;
end;
function TEmit_vbuf_chain.get_idx_elm(var adr:TBuf_adr):PsrRegNode;
var
foffset:PtrInt;
sum_d,idx_m:PsrRegNode;
begin
//result=(foffset/Align+idx*(stride/Align)) in elem
foffset:=adr.soffset+adr.ioffset+adr.voffset;
foffset:=foffset div adr.align;
if (adr.idx=nil) then
begin
sum_d:=FetchReg(FConsts.Fetchi(dtUint32,foffset));
sum_d^.mark_unread;
end else
begin
adr.idx^.mark_unread;
idx_m:=OpMulTo(adr.idx,adr.stride div adr.align); //idx*(stride/Align)
sum_d:=OpAddTo(idx_m,foffset);
end;
Result:=sum_d;
end;
function TEmit_vbuf_chain.get_idx_fmt(var adr:TBuf_adr):PsrRegNode;
var
foffset:PtrInt;
sum_d,idx_m:PsrRegNode;
begin
//result=(foffset/size+idx*(stride/size)) in format
foffset:=adr.soffset+adr.ioffset+adr.voffset;
foffset:=foffset div adr.fsize;
if (adr.idx=nil) then
begin
sum_d:=FetchReg(FConsts.Fetchi(dtUint32,foffset));
sum_d^.mark_unread;
end else
begin
adr.idx^.mark_unread;
idx_m:=OpMulTo(adr.idx,adr.stride div adr.fsize); //idx*(stride/size)
sum_d:=OpAddTo(idx_m,foffset);
end;
Result:=sum_d;
end;
function Min(a,b:PtrInt):PtrInt; inline;
begin
if (a<b) then Result:=a else Result:=b;
end;
function TEmit_vbuf_chain.get_chain(info:TBuf_info):TvarChain;
var
PV:PVSharpResource4;
adr:TBuf_adr;
foffset:PtrInt;
sum_d:PsrRegNode;
ext:TsrChainExt;
img:TsrImageInfo;
begin
Result:=Default(TvarChain);
if (info.GetElemCount=0) then
begin
Result.vType:=vcInvalid;
Exit;
end;
PV:=info.grp^.pData;
Assert(PV^.swizzle_en=0,'swizzle_en');
Assert(PV^.addtid_en =0,'addtid_en');
adr:=Default(TBuf_adr);
adr.stride :=PV^.stride;
adr.align :=info.GetAlignSize;
adr.fsize :=info.GetSizeFormat;
adr.csize :=Min(info.GetElemSize*info.count,adr.fsize);
adr.ioffset:=FSPI.MUBUF.OFFSET;
if (adr.stride=0) then adr.stride:=1;
get_reg_adr(adr);
foffset:=adr.soffset+adr.ioffset+adr.voffset;
Assert(foffset>=0,'WTF');
if (adr.ofs=nil) and (adr.idx=nil) then //simple
begin
Result.vType :=vcChainVector;
Result.data[0]:=info.grp^.Fetch(foffset,adr.csize,nil);
Exit;
end;
//result=Align(foffset+ofs+idx*stride) in byte
if (adr.ofs<>nil) then
begin
sum_d:=get_sum_ofs(adr);
//minTexelBufferOffsetAlignment
if FUseTexelBuffer then
if (info.IsComp) and
(adr.stride div adr.align=0) then
begin
//is uniform buffer per element
img:=info.GetImageInfoElement;
Result.vType :=vcUniformElement;
Result.data[0]:=FetchImage(info.grp,img.dtype,img.tinfo);
Result.data[1]:=sum_d;
Exit;
end;
sum_d^.mark_read;
ext:=Default(TsrChainExt);
ext.pIndex:=sum_d;
ext.stride:=adr.align;
Result:=Default(TvarChain);
Result.vType :=vcChainElement;
Result.data[0]:=info.grp^.Fetch(0,adr.align,@ext);
Exit;
end else
begin //idx<>nil
//minTexelBufferOffsetAlignment
if FUseTexelBuffer then
if (info.IsComp) and
(adr.stride mod adr.fsize=0) and
(foffset mod adr.fsize=0) then
begin
//is uniform buffer per format
sum_d:=get_idx_fmt(adr);
img:=info.GetImageInfo;
Result.vType :=vcUniformVector;
Result.data[0]:=FetchImage(info.grp,img.dtype,img.tinfo);
Result.data[1]:=sum_d;
Exit;
end;
//minTexelBufferOffsetAlignment
if FUseTexelBuffer then
if (info.IsComp) and
(adr.stride div adr.align=0) then
begin
//is uniform buffer per element
sum_d:=get_idx_elm(adr);
img:=info.GetImageInfoElement;
Result.vType :=vcUniformElement;
Result.data[0]:=FetchImage(info.grp,img.dtype,img.tinfo);
Result.data[1]:=sum_d;
Exit;
end;
//adr.idx^.mark_read;
ext:=Default(TsrChainExt);
ext.pIndex:=adr.idx;
ext.stride:=adr.stride;
Result.vType :=vcChainVector;
Result.data[0]:=info.grp^.Fetch(foffset,adr.csize,@ext);
Exit;
end;
end;
end.

394
spirv/emit_vbuf_load.pas Normal file
View File

@ -0,0 +1,394 @@
unit emit_vbuf_load;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
spirv,
ps4_pssl,
srTypes,
srConst,
srReg,
srLayout,
SprvEmit,
emit_op,
srVBufInfo,
emit_vbuf_chain;
type
Tload_cache=record
info:TBuf_info;
v:TvarChain;
dst:PsrRegSlot;
elem_orig:TsrDataType;
elem_resl:TsrDataType;
elem_count:ptruint;
rsl:PsrRegNode;
elm:array[0..3] of PsrRegNode;
end;
TEmit_vbuf_load=object(TEmitOp)
procedure buf_load(info:TBuf_info);
function OpMulF(pReg:PsrRegNode;s:Single):PsrRegNode;
function OpAddF(pReg:PsrRegNode;s:Single):PsrRegNode;
function OpUToF(pReg:PsrRegNode):PsrRegNode;
function OpSToF(pReg:PsrRegNode):PsrRegNode;
function OpShlI(pReg:PsrRegNode;i:DWORD):PsrRegNode;
function OpAddI(pReg:PsrRegNode;i:DWORD):PsrRegNode;
function _convert_e(var lc:Tload_cache;src:PsrRegNode):PsrRegNode;
procedure _make_load_cv_id(var lc:Tload_cache;i:Byte);
procedure _make_load_ce_id(var lc:Tload_cache;i:Byte);
procedure _make_load_uv_id(var lc:Tload_cache;i:Byte);
procedure _make_load_ue_id(var lc:Tload_cache;i:Byte);
procedure _make_load_zero(var lc:Tload_cache);
procedure _make_load_one(var lc:Tload_cache);
procedure buf_load_cv(info:TBuf_info;v:TvarChain);
end;
implementation
procedure TEmit_vbuf_load.buf_load(info:TBuf_info);
var
v:TvarChain;
begin
v:=TEmit_vbuf_chain(Self).get_chain(info);
if (v.vType=vcUniformVector) then
begin
//reset dst sel
info.dsel:=dst_sel_identity;
end;
buf_load_cv(info,v);
end;
function TEmit_vbuf_load.OpMulF(pReg:PsrRegNode;s:Single):PsrRegNode;
begin
if (pReg=nil) or (s=1) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
_emit_Op2(line,Op.OpFMul,Result,pReg,FetchReg(FConsts.Fetchf(dtFloat32,s)));
end;
function TEmit_vbuf_load.OpAddF(pReg:PsrRegNode;s:Single):PsrRegNode;
begin
if (pReg=nil) or (s=0) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
_emit_Op2(line,Op.OpFAdd,Result,pReg,FetchReg(FConsts.Fetchf(dtFloat32,s)));
end;
function TEmit_vbuf_load.OpUToF(pReg:PsrRegNode):PsrRegNode;
begin
if (pReg=nil) then Exit(pReg);
Result:=NewReg(dtFloat32);
pReg^.mark_read;
_emit_Op1(line,Op.OpConvertUToF,Result,pReg);
end;
function TEmit_vbuf_load.OpSToF(pReg:PsrRegNode):PsrRegNode;
begin
if (pReg=nil) then Exit(pReg);
Result:=NewReg(dtFloat32);
pReg^.mark_read;
_emit_Op1(line,Op.OpConvertSToF,Result,pReg);
end;
function TEmit_vbuf_load.OpShlI(pReg:PsrRegNode;i:DWORD):PsrRegNode;
begin
if (pReg=nil) or (i=0) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
_emit_OpShl(line,Result,pReg,FetchReg(FConsts.Fetchi(dtUint32,i)));
end;
function TEmit_vbuf_load.OpAddI(pReg:PsrRegNode;i:DWORD):PsrRegNode;
begin
if (pReg=nil) or (i=0) then Exit(pReg);
Result:=NewReg(pReg^.dtype);
pReg^.mark_read;
_emit_OpIAdd(line,Result,pReg,FetchReg(FConsts.Fetchi(dtUint32,i)));
end;
function TEmit_vbuf_load._convert_e(var lc:Tload_cache;src:PsrRegNode):PsrRegNode;
begin
Result:=src;
if (lc.elem_resl<>lc.elem_orig) then
Case lc.info.NFMT of
BUF_NUM_FORMAT_UNORM : //Unsigned, normalized to range [0.0..1.0]; data/(1<<nbits-1)
begin
Result:=OpUToF(src);
Result:=OpMulF(Result,1/GetTypeHigh(lc.elem_orig));
end;
BUF_NUM_FORMAT_SNORM : //Signed, normalized to range [-1.0..1.0]; data/(1<<(nbits-1)-1) clamped
begin
Result:=OpSToF(src);
Result:=OpMulF(Result,1/(GetTypeHigh(lc.elem_orig) shr 1));
Result:=OpAddF(Result,-1);
end;
BUF_NUM_FORMAT_USCALED : //Unsigned integer to float [0.0 .. (1<<nbits)-1]
begin
Result:=OpUToF(src);
end;
BUF_NUM_FORMAT_SSCALED : //Signed integer to float [-(1<<(nbits-1)) ..(1<<(nbits-1))-1]
begin
Result:=OpSToF(src);
end;
BUF_NUM_FORMAT_SNORM_NZ: //Signed, normalized to range [-1.0..1.0]; (data*2+1)/(1<<nbits-1)
begin
if (lc.info.GetElemSize=4) then
begin
Result:=OpSToF(src);
Result:=OpMulF(Result,2);
Result:=OpAddF(Result,1);
Result:=OpMulF(Result,1/GetTypeHigh(lc.elem_orig));
end else
begin
Result:=OpShlI(src,1);
Result:=OpAddI(Result,1);
Result:=OpSToF(Result);
Result:=OpMulF(Result,1/GetTypeHigh(lc.elem_orig));
end;
end;
BUF_NUM_FORMAT_UINT :
begin
Result:=NewReg(lc.elem_resl);
src^.mark_read;
_emit_Op1(line,Op.OpUConvert,Result,src);
end;
BUF_NUM_FORMAT_SINT :
begin
Result:=NewReg(lc.elem_resl);
src^.mark_read;
_emit_Op1(line,Op.OpSConvert,Result,src);
end;
BUF_NUM_FORMAT_FLOAT :
begin
Result:=NewReg(lc.elem_resl);
src^.mark_read;
_emit_Op1(line,Op.OpFConvert,Result,src);
end;
end;
end;
procedure TEmit_vbuf_load._make_load_cv_id(var lc:Tload_cache;i:Byte);
var
rsl:PsrRegNode;
begin
rsl:=lc.rsl;
if (rsl=nil) then
begin
rsl:=FetchLoad(lc.v.data[0],GetVecType(lc.elem_orig,lc.elem_count));
lc.rsl:=rsl;
end;
if (lc.elm[i]=nil) then
begin
if (lc.elem_count=1) then
begin
rsl:=_convert_e(lc,rsl);
lc.elm[i]:=rsl;
end else
begin
lc.elm[i]:=NewReg(lc.elem_orig);
rsl^.mark_read;
emit_OpCompExtract(line,lc.elm[i],rsl,i);
lc.elm[i]:=_convert_e(lc,lc.elm[i]);
end;
end;
MakeCopy(lc.dst,lc.elm[i]);
end;
procedure TEmit_vbuf_load._make_load_ce_id(var lc:Tload_cache;i:Byte);
var
orig,elm:PsrChain;
sum_d:PsrRegNode;
ext:TsrChainExt;
rsl:PsrRegNode;
begin
if (lc.elm[i]=nil) then
begin
orig:=lc.v.data[0];
sum_d:=orig^.key.ext.pIndex;
if (i=0) then
begin
elm:=orig;
end else
begin
sum_d:=TEmit_vbuf_chain(Self).OpAddTo(sum_d,i);
sum_d^.mark_read;
ext:=Default(TsrChainExt);
ext.pIndex:=sum_d;
ext.stride:=orig^.key.ext.stride;
elm:=lc.info.grp^.Fetch(0,orig^.key.size,@ext);
end;
rsl:=FetchLoad(elm,lc.elem_orig);
rsl:=_convert_e(lc,rsl);
lc.elm[i]:=rsl;
end;
MakeCopy(lc.dst,lc.elm[i]);
end;
procedure TEmit_vbuf_load._make_load_uv_id(var lc:Tload_cache;i:Byte);
var
rsl,idx:PsrRegNode;
begin
rsl:=lc.rsl;
if (rsl=nil) then
begin
rsl:=NewReg(GetVecType(lc.elem_resl,4));
idx:=lc.v.data[1];
idx^.mark_read;
emit_OpImageRead(line,lc.v.data[0],rsl,idx);
lc.rsl:=rsl;
end;
if (lc.elm[i]=nil) then
begin
rsl^.mark_read;
lc.dst^.New(line,lc.elem_resl);
emit_OpCompExtract(line,lc.dst^.current,rsl,i);
lc.elm[i]:=lc.dst^.current;
end else
begin
MakeCopy(lc.dst,lc.elm[i]);
end;
end;
procedure TEmit_vbuf_load._make_load_ue_id(var lc:Tload_cache;i:Byte);
var
rsl,idx,sum_d:PsrRegNode;
begin
if (lc.elm[i]=nil) then
begin
idx:=lc.v.data[1];
if (i=0) then
begin
sum_d:=idx;
end else
begin
sum_d:=TEmit_vbuf_chain(Self).OpAddTo(idx,i);
end;
rsl:=lc.dst^.New(line,lc.elem_resl);
sum_d^.mark_read;
emit_OpImageRead(line,lc.v.data[0],rsl,sum_d);
lc.elm[i]:=rsl;
end else
begin
MakeCopy(lc.dst,lc.elm[i]);
end;
end;
procedure TEmit_vbuf_load._make_load_zero(var lc:Tload_cache);
begin
SetConst(lc.dst,FConsts.Fetchi(lc.elem_resl,0));
end;
procedure TEmit_vbuf_load._make_load_one(var lc:Tload_cache);
begin
if (lc.elem_resl=dtFloat32) then
begin
SetConst(lc.dst,FConsts.Fetchf(lc.elem_resl,1));
end else
begin
SetConst(lc.dst,FConsts.Fetchi(lc.elem_resl,1));
end;
end;
procedure TEmit_vbuf_load.buf_load_cv(info:TBuf_info;v:TvarChain);
var
lc:Tload_cache;
i,d,count:Byte;
begin
if info.IsExtFormat then Assert(false,'TODO');
lc:=Default(Tload_cache);
lc.info :=info;
lc.v :=v;
lc.elem_resl :=info.GetResultType;
lc.elem_orig :=info.GetElemType;
lc.elem_count:=info.GetElemCount;
count:=info.count;
For i:=0 to count-1 do
begin
lc.dst:=FRegsStory.get_vdst8(FSPI.MUBUF.VDATA+i);
if (lc.dst=nil) then Assert(false);
//0=0, 1=1, 4=R, 5=G, 6=B, 7=A
Case info.dsel[i] of
0:begin //0
_make_load_zero(lc);
end;
1:begin //1
_make_load_one(lc);
end;
4..7:
begin //RGBA
d:=info.dsel[i]-4;
if (d<lc.elem_count) then
begin
Case v.vType of
vcInvalid :_make_load_zero(lc);
vcChainVector :_make_load_cv_id(lc,d);
vcChainElement :_make_load_ce_id(lc,d);
vcUniformVector :_make_load_uv_id(lc,d);
vcUniformElement:_make_load_ue_id(lc,d);
end;
end else
begin //as zero
_make_load_zero(lc);
end;
end;
else
begin //as zero
_make_load_zero(lc);
end;
end;
end;
end;
end.

290
spirv/emit_vbuf_store.pas Normal file
View File

@ -0,0 +1,290 @@
unit emit_vbuf_store;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srConst,
srReg,
srLayout,
SprvEmit,
emit_op,
srVBufInfo,
emit_vbuf_chain;
type
Tstore_cache=record
info:TBuf_info;
v:TvarChain;
elem_orig:TsrDataType;
elem_resl:TsrDataType;
elem_count:ptruint;
elm:array[0..3] of PsrRegNode;
end;
TEmit_vbuf_store=object(TEmitOp)
procedure buf_store(info:TBuf_info);
function _fetch_id(var lc:Tstore_cache;i:Byte):PsrRegNode;
function _fetch_zero(var lc:Tstore_cache):PsrRegNode;
function _fetch_one(var lc:Tstore_cache):PsrRegNode;
procedure _make_store_cv(var lc:Tstore_cache);
procedure _make_store_ce(var lc:Tstore_cache);
procedure _make_store_uv(var lc:Tstore_cache);
procedure _make_store_ue(var lc:Tstore_cache);
procedure buf_store_cv(info:TBuf_info;v:TvarChain);
end;
implementation
procedure TEmit_vbuf_store.buf_store(info:TBuf_info);
var
v:TvarChain;
begin
v:=TEmit_vbuf_chain(Self).get_chain(info);
if (v.vType=vcUniformVector) then
begin
//reset dst sel
info.dsel:=dst_sel_identity;
end else
begin
info.dsel:=get_reverse_dst_sel(info.dsel);
end;
buf_store_cv(info,v);
end;
function TEmit_vbuf_store._fetch_id(var lc:Tstore_cache;i:Byte):PsrRegNode;
begin
Result:=fetch_vdst8(FSPI.MUBUF.VDATA+i,lc.elem_resl);
if (Result=nil) then Assert(false);
end;
function TEmit_vbuf_store._fetch_zero(var lc:Tstore_cache):PsrRegNode;
begin
Result:=FetchReg(FConsts.Fetchi(lc.elem_resl,0));
end;
function TEmit_vbuf_store._fetch_one(var lc:Tstore_cache):PsrRegNode;
begin
if (lc.elem_resl=dtFloat32) then
begin
Result:=FetchReg(FConsts.Fetchf(lc.elem_resl,1));
end else
begin
Result:=FetchReg(FConsts.Fetchi(lc.elem_resl,1));
end;
end;
function Min(a,b:PtrUInt):PtrUInt; inline;
begin
if (a<b) then Result:=a else Result:=b;
end;
procedure TEmit_vbuf_store._make_store_cv(var lc:Tstore_cache);
var
rsl:PsrRegNode;
i:Byte;
csize:PtrUInt;
orig,new:PsrChain;
idx:PsrRegNode;
ext:TsrChainExt;
begin
For i:=0 to lc.elem_count-1 do //fill
if (lc.elm[i]=nil) then
begin
Case lc.info.dsel[i] of
1:lc.elm[i]:=_fetch_one(lc);
else
lc.elm[i]:=_fetch_zero(lc);
end;
end;
Case lc.elem_count of
1:rsl:=lc.elm[0];
else
begin
rsl:=emit_OpMakeVec(line,GetVecType(lc.elem_resl,lc.elem_count),lc.elem_count,@lc.elm);
rsl^.mark_read;
end;
end;
Assert(lc.elem_resl=lc.elem_orig,'TODO CONVERT');
csize:=Min(lc.info.GetElemSize*lc.elem_count,lc.info.GetSizeFormat);
orig:=lc.v.data[0];
if (orig^.key.size<>csize) then //refetch
begin
idx:=orig^.key.ext.pIndex;
if (idx<>nil) then
begin
idx^.mark_read;
ext:=Default(TsrChainExt);
ext.pIndex:=idx;
ext.stride:=orig^.key.ext.stride;
new:=lc.info.grp^.Fetch(orig^.key.offset,csize,@ext);
end else
begin
new:=lc.info.grp^.Fetch(orig^.key.offset,csize,nil);
end;
orig:=new;
end;
FetchStore(orig,rsl);
end;
procedure TEmit_vbuf_store._make_store_ce(var lc:Tstore_cache);
var
orig,elm:PsrChain;
sum_d:PsrRegNode;
ext:TsrChainExt;
i:Byte;
begin
orig:=lc.v.data[0];
sum_d:=orig^.key.ext.pIndex;
For i:=0 to lc.elem_count-1 do
if (lc.elm[i]<>nil) then
begin
if (i=0) then
begin
elm:=orig;
end else
begin
sum_d:=TEmit_vbuf_chain(Self).OpAddTo(sum_d,i);
sum_d^.mark_read;
ext:=Default(TsrChainExt);
ext.pIndex:=sum_d;
ext.stride:=orig^.key.ext.stride;
elm:=lc.info.grp^.Fetch(0,orig^.key.size,@ext);
end;
Assert(lc.elem_resl=lc.elem_orig,'TODO CONVERT');
FetchStore(elm,lc.elm[i]);
end;
end;
procedure TEmit_vbuf_store._make_store_uv(var lc:Tstore_cache);
var
rsl,idx:PsrRegNode;
i:Byte;
begin
For i:=0 to lc.elem_count-1 do //fill
if (lc.elm[i]=nil) then
begin
Case lc.info.dsel[i] of
1:lc.elm[i]:=_fetch_one(lc);
else
lc.elm[i]:=_fetch_zero(lc);
end;
end;
Case lc.elem_count of
1:rsl:=lc.elm[0];
else
begin
rsl:=emit_OpMakeVec(line,GetVecType(lc.elem_resl,lc.elem_count),lc.elem_count,@lc.elm);
rsl^.mark_read;
end;
end;
idx:=lc.v.data[1];
idx^.mark_read;
rsl^.mark_read;
emit_OpImageWrite(line,lc.v.data[0],idx,rsl);
end;
procedure TEmit_vbuf_store._make_store_ue(var lc:Tstore_cache);
var
sum_d,idx,rsl:PsrRegNode;
i:Byte;
begin
idx:=lc.v.data[1];
For i:=0 to lc.elem_count-1 do
if (lc.elm[i]<>nil) then
begin
rsl:=lc.elm[i];
if (i=0) then
begin
sum_d:=idx;
end else
begin
sum_d:=TEmit_vbuf_chain(Self).OpAddTo(idx,i);
end;
sum_d^.mark_read;
rsl^.mark_read;
emit_OpImageWrite(line,lc.v.data[0],sum_d,rsl);
end;
end;
procedure TEmit_vbuf_store.buf_store_cv(info:TBuf_info;v:TvarChain);
var
lc:Tstore_cache;
i:Byte;
begin
Case v.vType of
vcInvalid:Exit;
else;
end;
if info.IsExtFormat then Assert(false,'TODO');
lc:=Default(Tstore_cache);
lc.info :=info;
lc.v :=v;
lc.elem_resl :=info.GetResultType;
lc.elem_orig :=info.GetElemType;
lc.elem_count:=info.GetElemCount;
For i:=0 to lc.elem_count-1 do
begin
lc.elm[i]:=nil;
Case lc.info.dsel[i] of
4..7:
begin //RGBA
lc.elm[i]:=_fetch_id(lc,lc.info.dsel[i]-4);
end;
else;
end;
end;
While (lc.elem_count<>0) do //trim count
begin
i:=lc.elem_count-1;
if (lc.elm[i]<>nil) then Break;
Dec(lc.elem_count);
end;
if (lc.elem_count=0) then Exit;
Case v.vType of
vcChainVector :_make_store_cv(lc);
vcChainElement :_make_store_ce(lc);
vcUniformVector :_make_store_uv(lc);
vcUniformElement:_make_store_ue(lc)
else;
end;
end;
end.

110
spirv/emit_vintrp.pas Normal file
View File

@ -0,0 +1,110 @@
unit emit_VINTRP;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srInput,
srReg,
spirv,
SprvEmit,
emit_op;
type
TEmit_VINTRP=object(TEmitOp)
procedure _emit_VINTRP;
end;
implementation
procedure TEmit_VINTRP._emit_VINTRP;
var
inp_M0:PsrInput;
src:PsrRegSlot;
dst:PsrRegSlot;
inp_SRC:PsrInput;
rsl:PsrRegNode;
begin
Assert(FExecutionModel=ExecutionModel.Fragment); //only pixel shader
dst:=FRegsStory.get_vdst8(FSPI.VINTRP.VDST);
inp_M0:=GetInputRegNode(FRegsStory.M0.current);
Assert(inp_M0<>nil);
Assert(inp_M0^.key.itype=itPsState);
Case FSPI.VINTRP.OP of
V_INTERP_P1_F32:
begin
src:=FRegsStory.get_vsrc8(FSPI.VINTRP.VSRC);
inp_SRC:=GetInputRegNode(src^.current);
Assert(inp_SRC<>nil);
Case inp_SRC^.key.itype of
itPerspSample,
itPerspCenter, //barycentrics with perspective interpolation
itPerspCentroid,
itLinearSample,
itLinearCenter,
itLinearCentroid:;
else
Assert(false);
end;
Assert(inp_SRC^.key.typeid=0); //I
rsl:=AddFragLayout(inp_SRC^.key.itype,dtVec4f,FSPI.VINTRP.ATTR);
rsl^.mark_read;
dst^.New(line,dtFloat32);
emit_OpCompExtract(line,dst^.current,rsl,FSPI.VINTRP.ATTRCHAN);
end;
V_INTERP_P2_F32:
begin
src:=FRegsStory.get_vsrc8(FSPI.VINTRP.VSRC);
inp_SRC:=GetInputRegNode(src^.current);
Assert(inp_SRC<>nil);
Case inp_SRC^.key.itype of
itPerspSample,
itPerspCenter, //barycentrics with perspective interpolation
itPerspCentroid,
itLinearSample,
itLinearCenter,
itLinearCentroid:;
else
Assert(false);
end;
Assert(inp_SRC^.key.typeid=1); //J
rsl:=AddFragLayout(inp_SRC^.key.itype,dtVec4f,FSPI.VINTRP.ATTR);
rsl^.mark_read;
dst^.New(line,dtFloat32);
emit_OpCompExtract(line,dst^.current,rsl,FSPI.VINTRP.ATTRCHAN);
end;
else
Assert(False,'VINTRP?'+IntToStr(FSPI.VINTRP.OP));
end;
end;
end.

273
spirv/emit_vop1.pas Normal file
View File

@ -0,0 +1,273 @@
unit emit_VOP1;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srReg,
spirv,
SprvEmit,
emit_op;
type
TEmit_VOP1=object(TEmitOp)
procedure _emit_VOP1;
procedure _emit_V_MOV_B32;
procedure _emit_V_CVT_F32_I32;
procedure _emit_V_CVT_U32_F32;
procedure _emit_V_CVT_I32_F32;
procedure _emit_V_CVT_F32_U32;
procedure _emit_V_CVT_OFF_F32_I4;
procedure _emit_V_SQRT_F32;
procedure _emit_V_RSQ_F32;
procedure _emit_V_FLOOR_F32;
procedure _emit_V_FRACT_F32;
procedure _emit_V_EXP_F32;
procedure _emit_V_RCP_F32;
procedure _emit_V_SIN_F32;
end;
implementation
procedure TEmit_VOP1._emit_V_MOV_B32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtUnknow);
_MakeCopy(dst,src);
end;
procedure TEmit_VOP1._emit_V_CVT_F32_I32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtInt32);
emit_Op1(Op.OpConvertSToF,dtFloat32,dst,src);
end;
procedure TEmit_VOP1._emit_V_CVT_I32_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_Op1(Op.OpConvertFToS,dtInt32,dst,src);
end;
procedure TEmit_VOP1._emit_V_CVT_U32_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_Op1(Op.OpConvertFToU,dtUInt32,dst,src);
end;
procedure TEmit_VOP1._emit_V_CVT_F32_U32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtUInt32);
emit_Op1(Op.OpConvertUToF,dtFloat32,dst,src);
end;
//V_CVT_OFF_F32_I4
//([0..3]-8)/16
procedure TEmit_VOP1._emit_V_CVT_OFF_F32_I4;
Var
dst,tmp:PsrRegSlot;
src:PsrRegNode;
num_8:PsrRegNode;
num_15:PsrRegNode;
num_16:PsrRegNode;
subi,subf:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtUInt32);
tmp:=@FRegsStory.FUnattach;
num_15:=FetchReg(FConsts.Fetch(dtUInt32,15));
emit_OpBitwiseAnd(tmp,src,num_15);
src:=MakeRead(tmp,dtUInt32);
num_8:=FetchReg(FConsts.Fetch(dtInt32,8));
subi:=dst^.New(line,dtInt32);
_emit_OpISub(line,subi,src,num_8);
subi^.mark_read;
subf:=dst^.New(line,dtFloat32);
_emit_Op1(line,Op.OpConvertSToF,subf,subi);
subf^.mark_read;
num_16:=FetchReg(FConsts.Fetchf(dtFloat32,16));
emit_OpFDiv(dst,subf,num_16);
end;
procedure TEmit_VOP1._emit_V_SQRT_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_OpSqrt(dst,src);
end;
procedure TEmit_VOP1._emit_V_RSQ_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_OpInverseSqrt(dst,src);
end;
procedure TEmit_VOP1._emit_V_FLOOR_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_OpFloor(dst,src);
end;
procedure TEmit_VOP1._emit_V_FRACT_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_OpFract(dst,src);
end;
procedure TEmit_VOP1._emit_V_EXP_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_OpExp2(dst,src);
end;
procedure TEmit_VOP1._emit_V_RCP_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
one:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
one:=FetchReg(FConsts.Fetchf(dtFloat32,1));
emit_OpFDiv(dst,one,src);
end;
procedure TEmit_VOP1._emit_V_SIN_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP1.VDST);
src:=fetch_ssrc9(FSPI.VOP1.SRC0,dtFloat32);
emit_OpSin(dst,src);
end;
procedure TEmit_VOP1._emit_VOP1;
begin
Case FSPI.VOP1.OP of
V_MOV_B32:
begin
_emit_V_MOV_B32;
end;
V_CVT_F32_I32:
begin
_emit_V_CVT_F32_I32;
end;
V_CVT_I32_F32:
begin
_emit_V_CVT_I32_F32;
end;
V_CVT_U32_F32:
begin
_emit_V_CVT_U32_F32;
end;
V_CVT_F32_U32:
begin
_emit_V_CVT_F32_U32;
end;
V_CVT_OFF_F32_I4:
begin
_emit_V_CVT_OFF_F32_I4;
end;
V_SQRT_F32:
begin
_emit_V_SQRT_F32;
end;
V_RSQ_F32:
begin
_emit_V_RSQ_F32;
end;
V_FLOOR_F32:
begin
_emit_V_FLOOR_F32;
end;
V_FRACT_F32:
begin
_emit_V_FRACT_F32;
end;
V_EXP_F32:
begin
_emit_V_EXP_F32;
end;
V_RCP_F32:
begin
_emit_V_RCP_F32;
end;
V_SIN_F32:
begin
_emit_V_SIN_F32;
end;
else
Assert(false,'VOP1?'+IntToStr(FSPI.VOP1.OP));
end;
end;
end.

511
spirv/emit_vop2.pas Normal file
View File

@ -0,0 +1,511 @@
unit emit_VOP2;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srConst,
srReg,
SprvEmit,
emit_op;
type
TEmit_VOP2=object(TEmitOp)
procedure _emit_VOP2;
procedure _emit_V_CNDMASK_B32;
procedure _emit_V_AND_B32;
procedure _emit_V_OR_B32;
procedure _emit_V_LSHL_B32;
procedure _emit_V_LSHLREV_B32;
procedure _emit_V_LSHR_B32;
procedure _emit_V_LSHRREV_B32;
procedure _emit_V_ASHR_I32;
procedure _emit_V_ASHRREV_I32;
procedure _emit_V_ADD_I32;
procedure _emit_V_SUB_I32;
procedure _emit_V_SUBREV_I32;
procedure _emit_V_ADD_F32;
procedure _emit_V_SUB_F32;
procedure _emit_V_SUBREV_F32;
procedure _emit_V_MUL_F32;
procedure _emit_V_CVT_PKRTZ_F16_F32;
procedure _emit_V_MAC_F32;
procedure _emit_V_MADAK_F32;
procedure _emit_V_MADMK_F32;
procedure _emit_V_MIN_F32;
procedure _emit_V_MAX_F32;
end;
implementation
procedure TEmit_VOP2._emit_V_CNDMASK_B32;
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUnknow);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUnknow);
src[2]:=MakeRead(@FRegsStory.VCC[0],dtBool);
emit_OpSelect(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP2._emit_V_AND_B32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUnknow);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUnknow);
emit_OpBitwiseAnd(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_OR_B32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUnknow);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUnknow);
emit_OpBitwiseOr(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_LSHL_B32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
src[2]:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[1],src[2]);
src[1]:=MakeRead(tmp,dtUInt32);
emit_OpShl(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_LSHLREV_B32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
src[2]:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[0],src[2]);
src[0]:=MakeRead(tmp,dtUInt32);
emit_OpShl(dst,src[1],src[0]);
end;
procedure TEmit_VOP2._emit_V_LSHR_B32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
src[2]:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[1],src[2]);
src[1]:=MakeRead(tmp,dtUInt32);
emit_OpShr(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_LSHRREV_B32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
src[2]:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[0],src[2]);
src[0]:=MakeRead(tmp,dtUInt32);
emit_OpShr(dst,src[1],src[0]);
end;
procedure TEmit_VOP2._emit_V_ASHR_I32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtInt32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
src[2]:=FetchReg(FConsts.Fetch(dtInt32,31));
emit_OpBitwiseAnd(tmp,src[1],src[2]);
src[1]:=MakeRead(tmp,dtInt32);
emit_OpShrA(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_ASHRREV_I32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtInt32);
src[2]:=FetchReg(FConsts.Fetch(dtInt32,31));
emit_OpBitwiseAnd(tmp,src[0],src[2]);
src[0]:=MakeRead(tmp,dtInt32);
emit_OpShrA(dst,src[1],src[0]);
end;
procedure TEmit_VOP2._emit_V_ADD_I32; //vdst = vsrc0.s + vsrc1.s; sdst[thread_id:] = carry_out & EXEC
Var
dst,car:PsrRegSlot;
src:array[0..1] of PsrRegNode;
exc,tmp:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
car:=@FRegsStory.VCC[0];
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
emit_OpIAddExt(dst,@FRegsStory.FUnattach,src[0],src[1]);
tmp:=FRegsStory.FUnattach.current;
tmp^.mark_read;
exc:=MakeRead(@FRegsStory.EXEC[0],dtUnknow);
emit_OpBitwiseAnd(car,tmp,exc);
end;
procedure TEmit_VOP2._emit_V_SUB_I32; //vdst = vsrc0.u - vsub.u; sdst[thread_id:] = borrow_out & EXEC
Var
dst,car:PsrRegSlot;
src:array[0..1] of PsrRegNode;
exc,tmp:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
car:=@FRegsStory.VCC[0];
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
emit_OpISubExt(dst,@FRegsStory.FUnattach,src[0],src[1]);
tmp:=FRegsStory.FUnattach.current;
tmp^.mark_read;
exc:=MakeRead(@FRegsStory.EXEC[0],dtUnknow);
emit_OpBitwiseAnd(car,tmp,exc);
end;
procedure TEmit_VOP2._emit_V_SUBREV_I32; //vdst = vsrc1.u - vsub.u; sdst[thread_id:] = borrow_out & EXEC
Var
dst,car:PsrRegSlot;
src:array[0..1] of PsrRegNode;
exc,tmp:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
car:=@FRegsStory.VCC[0];
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtUint32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtUint32);
emit_OpISubExt(dst,@FRegsStory.FUnattach,src[1],src[0]);
tmp:=FRegsStory.FUnattach.current;
tmp^.mark_read;
exc:=MakeRead(@FRegsStory.EXEC[0],dtUnknow);
emit_OpBitwiseAnd(car,tmp,exc);
end;
procedure TEmit_VOP2._emit_V_ADD_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFAdd(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_SUB_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFSub(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_SUBREV_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFSub(dst,src[1],src[0]);
end;
procedure TEmit_VOP2._emit_V_MUL_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFMul(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_CVT_PKRTZ_F16_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
_emit_ConvFloatToHalf(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_MAC_F32; //vdst = vsrc0.f * vsrc1.f + vdst.f -> fma
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
src[2]:=MakeRead(dst,dtFloat32);
emit_OpFmaF32(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP2._emit_V_MADAK_F32; //vdst = vsrc0.f * vsrc1.f + kadd.f
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
src[2]:=FetchReg(FConsts.Fetch(dtFloat32,FSPI.INLINE32));
emit_OpFmaF32(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP2._emit_V_MADMK_F32; //vdst = vsrc0.f * kmul.f + vadd.f
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=FetchReg(FConsts.Fetch(dtFloat32,FSPI.INLINE32));
src[2]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFmaF32(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP2._emit_V_MIN_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFMin(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_V_MAX_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP2.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP2.SRC0 ,dtFloat32);
src[1]:=fetch_vsrc8(FSPI.VOP2.VSRC1,dtFloat32);
emit_OpFMax(dst,src[0],src[1]);
end;
procedure TEmit_VOP2._emit_VOP2;
begin
Case FSPI.VOP2.OP of
V_CNDMASK_B32:
begin
_emit_V_CNDMASK_B32;
end;
V_AND_B32:
begin
_emit_V_AND_B32;
end;
V_OR_B32:
begin
_emit_V_OR_B32;
end;
V_LSHL_B32:
begin
_emit_V_LSHL_B32;
end;
V_LSHLREV_B32:
begin
_emit_V_LSHLREV_B32;
end;
V_LSHR_B32:
begin
_emit_V_LSHR_B32;
end;
V_LSHRREV_B32:
begin
_emit_V_LSHRREV_B32
end;
V_ASHR_I32:
begin
_emit_V_ASHR_I32;
end;
V_ASHRREV_I32:
begin
_emit_V_ASHRREV_I32
end;
V_ADD_I32: //vdst = vsrc0.s + vsrc1.s; sdst[thread_id:] = carry_out & EXEC
begin
// Vector ALU (except v_readlane, v_readfirstlane, v_writelane),
// Vector Memory,
// Local and Global Data Share
// and Export.
_emit_V_ADD_I32;
end;
V_SUB_I32:
begin
_emit_V_SUB_I32;
end;
V_SUBREV_I32:
begin
_emit_V_SUBREV_I32;
end;
V_ADD_F32:
begin
_emit_V_ADD_F32;
end;
V_SUB_F32:
begin
_emit_V_SUB_F32;
end;
V_SUBREV_F32:
begin
_emit_V_SUBREV_F32;
end;
V_MUL_F32:
begin
_emit_V_MUL_F32;
end;
V_CVT_PKRTZ_F16_F32:
begin
_emit_V_CVT_PKRTZ_F16_F32;
end;
V_MAC_F32: //vdst = vsrc0.f * vsrc1.f + vdst.f -> fma
begin
_emit_V_MAC_F32;
end;
V_MADAK_F32:
begin
_emit_V_MADAK_F32;
end;
V_MADMK_F32:
begin
_emit_V_MADMK_F32;
end;
V_MIN_F32:
begin
_emit_V_MIN_F32;
end;
V_MAX_F32:
begin
_emit_V_MAX_F32;
end;
else
Assert(false,'VOP2?'+IntToStr(FSPI.VOP2.OP));
end;
end;
end.

995
spirv/emit_vop3.pas Normal file
View File

@ -0,0 +1,995 @@
unit emit_VOP3;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
spirv,
srTypes,
srReg,
srOpUtils,
SprvEmit,
emit_op;
type
TEmit_VOP3=object(TEmitOp)
procedure _emit_VOP3c;
procedure _emit_VOP3b;
procedure _emit_VOP3a;
procedure _emit_V_CMP_32(OpId:DWORD;rtype:TsrDataType;x:Boolean);
procedure _emit_V_CMP_C(r,x:Boolean);
procedure _emit_src_neg_bit(src:PPsrRegNode;count:Byte);
procedure _emit_src_abs(src:PPsrRegNode);
procedure _emit_src_abs_bit(src:PPsrRegNode;count:Byte);
procedure _emit_dst_omod_f(dst:PsrRegSlot);
procedure _emit_dst_clamp_f(dst:PsrRegSlot);
procedure _emit_V_CNDMASK_B32;
procedure _emit_V_ADD_F32;
procedure _emit_V_SUB_F32;
procedure _emit_V_CVT_PKRTZ_F16_F32;
procedure _emit_V_MIN_F32;
procedure _emit_V_MAX_F32;
procedure _emit_V_MUL_LO_I32;
procedure _emit_V_MUL_F32;
procedure _emit_V_MUL_I32_I24;
procedure _emit_V_MAC_F32;
procedure _emit_V_BFE_U32;
procedure _emit_V_MAD_F32;
procedure _emit_V_MAD_I32_I24;
procedure _emit_V_MAD_U32_U24;
procedure _emit_V_SAD_U32;
procedure _emit_V_MAX3_F32;
procedure _emit_V_MIN3_F32;
procedure _emit_V_MED3_F32;
procedure _emit_V_FMA_F32;
procedure _emit_V_CUBE(OpId:DWORD);
procedure _emit_V_MOV_B32;
procedure _emit_V_SQRT_F32;
procedure _emit_V_RCP_F32;
end;
implementation
procedure TEmit_VOP3._emit_V_CMP_32(OpId:DWORD;rtype:TsrDataType;x:Boolean);
Var
dst:array[0..1] of PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst[0]:=FRegsStory.get_sdst7(FSPI.VOP3a.VDST+0);
dst[1]:=FRegsStory.get_sdst7(FSPI.VOP3a.VDST+1);
Assert(dst[0]<>nil);
Assert(dst[1]<>nil);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,rtype);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,rtype);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpCmpV(OpId,dst[0],src[0],src[1]);
SetConst(dst[1],dtUnknow,0); //set zero
if x then
begin
MakeCopy(@FRegsStory.EXEC[0],dst[0]^.current);
SetConst(@FRegsStory.EXEC[1],dtUnknow,0); //set zero
end;
end;
procedure TEmit_VOP3._emit_V_CMP_C(r,x:Boolean);
Var
dst:array[0..1] of PsrRegSlot;
begin
dst[0]:=FRegsStory.get_sdst7(FSPI.VOP3a.VDST+0);
dst[1]:=FRegsStory.get_sdst7(FSPI.VOP3a.VDST+1);
Assert(dst[0]<>nil);
Assert(dst[1]<>nil);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
SetConst(dst[0],dtBool,QWORD(r));
SetConst(dst[1],dtUnknow,0); //set zero
if x then
begin
MakeCopy(@FRegsStory.EXEC[0],dst[0]^.current);
SetConst(@FRegsStory.EXEC[1],dtUnknow,0); //set zero
end;
end;
procedure TEmit_VOP3._emit_src_neg_bit(src:PPsrRegNode;count:Byte);
var
i:Byte;
dst:PsrRegNode;
begin
if (FSPI.VOP3a.NEG=0) then Exit;
For i:=0 to count-1 do
if Byte(FSPI.VOP3a.NEG).TestBit(i) then
begin
dst:=NewReg(dtFloat32);
dst^.mark_read;
_emit_OpFNegate(line,dst,src[i]);
src[i]:=dst;
end;
end;
procedure TEmit_VOP3._emit_src_abs(src:PPsrRegNode);
var
dst:PsrRegNode;
begin
dst:=NewReg(dtFloat32);
dst^.mark_read;
_emit_OpFAbs(line,dst,src^);
src^:=dst;
end;
procedure TEmit_VOP3._emit_src_abs_bit(src:PPsrRegNode;count:Byte);
var
i:Byte;
begin
if (FSPI.VOP3a.ABS=0) then Exit;
For i:=0 to count-1 do
if Byte(FSPI.VOP3a.ABS).TestBit(i) then
begin
_emit_src_abs(@src[i]);
end;
end;
procedure TEmit_VOP3._emit_dst_omod_f(dst:PsrRegSlot);
var
src,tmp:PsrRegNode;
begin
Case FSPI.VOP3a.OMOD of
0:;
1: // *2
begin
src:=dst^.current;
src^.mark_read;
tmp:=FetchReg(FConsts.Fetchf(dtFloat32,2));
emit_OpFMul(dst,src,tmp);
end;
2: // *4
begin
src:=dst^.current;
src^.mark_read;
tmp:=FetchReg(FConsts.Fetchf(dtFloat32,4));
emit_OpFMul(dst,src,tmp);
end;
3: // /2
begin
src:=dst^.current;
src^.mark_read;
tmp:=FetchReg(FConsts.Fetchf(dtFloat32,2));
emit_OpFDiv(dst,src,tmp);
end;
end;
end;
procedure TEmit_VOP3._emit_dst_clamp_f(dst:PsrRegSlot);
var
src,min,max:PsrRegNode;
begin
if (FSPI.VOP3a.CLAMP=0) then Exit;
src:=dst^.current;
src^.mark_read;
min:=FetchReg(FConsts.Fetchf(dtFloat32,0));
max:=FetchReg(FConsts.Fetchf(dtFloat32,1));
emit_OpFClamp(dst,src,min,max);
end;
procedure TEmit_VOP3._emit_V_CNDMASK_B32;
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtUnknow);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtUnknow);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtBool);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpSelect(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP3._emit_V_ADD_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpFAdd(dst,src[0],src[1]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_SUB_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpFSub(dst,src[0],src[1]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_CVT_PKRTZ_F16_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
_emit_ConvFloatToHalf(dst,src[0],src[1]);
end;
procedure TEmit_VOP3._emit_V_MIN_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpFMin(dst,src[0],src[1]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_MAX_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpFMax(dst,src[0],src[1]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_MUL_LO_I32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtInt32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtInt32);
emit_OpIMul(dst,src[0],src[1]);
end;
procedure TEmit_VOP3._emit_V_MUL_F32;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
_emit_src_abs_bit(@src,2);
_emit_src_neg_bit(@src,2);
emit_OpFMul(dst,src[0],src[1]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_MUL_I32_I24;
Var
dst:PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtInt32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtInt32);
//24bit mask TODO
emit_OpIMul(dst,src[0],src[1]);
end;
procedure TEmit_VOP3._emit_V_MAC_F32; //vdst = vsrc0.f * vsrc1.f + vdst.f -> fma
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs_bit(@src,3);
_emit_src_neg_bit(@src,3);
emit_OpFmaF32(dst,src[0],src[1],src[2]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_BFE_U32;
Var
dst,tmp:PsrRegSlot;
src:array[0..2] of PsrRegNode;
num_31:PsrRegNode;
offset,count:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
tmp:=@FRegsStory.FUnattach;
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtUint32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtUint32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtUint32);
num_31:=FetchReg(FConsts.Fetch(dtUInt32,31));
emit_OpBitwiseAnd(tmp,src[1],num_31);
offset:=MakeRead(tmp,dtUInt32);
num_31^.mark_read;
emit_OpBitwiseAnd(tmp,src[2],num_31);
count:=MakeRead(tmp,dtUInt32);
emit_OpBfeU(dst,src[0],offset,count);
end;
procedure TEmit_VOP3._emit_V_MAD_F32; //vdst = vsrc0.f * vsrc1.f + vadd.f
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs_bit(@src,3);
_emit_src_neg_bit(@src,3);
emit_OpFmaF32(dst,src[0],src[1],src[2]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_MAD_I32_I24;
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtInt32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtInt32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtInt32);
emit_OpFmaI32(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP3._emit_V_MAD_U32_U24;
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtUInt32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtUInt32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtUInt32);
emit_OpFmaU32(dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP3._emit_V_SAD_U32; //dst.u = abs(vsrc0.u - vsrc1.u) + vaccum.u
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
rdif,rvac:PsrRegNode;
//msk:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtUInt32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtUInt32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtUInt32);
rdif:=NewReg(dtInt32);
_emit_OpAbsDiff(line,rdif,src[0],src[1]);
//msk:=FetchReg(FConsts.Fetch(dtUInt32,$FFFF)); mask need?
//emit_OpBitwiseAnd(tmp,src[2],msk);
//rvac:=tmp^.current;
rvac:=src[2];
rdif^.mark_read;
rvac^.mark_read;
emit_OpIAdd(dst,rdif,rvac);
end;
procedure TEmit_VOP3._emit_V_MAX3_F32;
Var
dst,tmp:PsrRegSlot;
src:array[0..3] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs_bit(@src,3);
_emit_src_neg_bit(@src,3);
emit_OpFMax(tmp,src[0],src[1]);
src[3]:=MakeRead(tmp,dtFloat32);
emit_OpFMax(dst,src[3],src[2]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_MIN3_F32;
Var
dst,tmp:PsrRegSlot;
src:array[0..3] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
tmp:=@FRegsStory.FUnattach;
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs_bit(@src,3);
_emit_src_neg_bit(@src,3);
emit_OpFMin(tmp,src[0],src[1]);
src[3]:=MakeRead(tmp,dtFloat32);
emit_OpFMin(dst,src[3],src[2]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_MED3_F32;
Var
dst:PsrRegSlot;
src:array[0..3] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs_bit(@src,3);
_emit_src_neg_bit(@src,3);
emit_MED3F(dst,src[0],src[1],src[2]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_FMA_F32;
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs_bit(@src,3);
_emit_src_neg_bit(@src,3);
emit_OpFmaF32(dst,src[0],src[1],src[2]);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
{
procedure TEmit_VOP3._emit_V_CUBEMA_F32;
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
max:array[0..1] of PsrRegNode;
num_2:PsrRegNode;
begin
//max(max(abs(x),abs(y)),abs(z))*2
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
_emit_src_abs(@src[0]);
_emit_src_abs(@src[1]);
_emit_src_abs(@src[2]);
max[0]:=NewReg(dtFloat32);
max[0]^.mark_read;
_emit_OpFMax(line,max[0],src[0],src[1]);
max[1]:=NewReg(dtFloat32);
max[1]^.mark_read;
_emit_OpFMax(line,max[1],max[0],src[2]);
num_2:=FetchReg(FConsts.Fetchf(dtFloat32,2));
emit_OpFMul(dst,max[1],num_2);
end;
}
procedure TEmit_VOP3._emit_V_CUBE(OpId:DWORD);
Var
dst:PsrRegSlot;
src:array[0..2] of PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.ABS =0,'FSPI.VOP3a.ABS');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
Assert(FSPI.VOP3a.NEG =0,'FSPI.VOP3a.NEG');
src[0]:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
src[1]:=fetch_ssrc9(FSPI.VOP3a.SRC1,dtFloat32);
src[2]:=fetch_ssrc9(FSPI.VOP3a.SRC2,dtFloat32);
emit_Op3(OpId,dtFloat32,dst,src[0],src[1],src[2]);
end;
procedure TEmit_VOP3._emit_V_MOV_B32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
Assert(FSPI.VOP3a.OMOD =0,'FSPI.VOP3a.OMOD');
Assert(FSPI.VOP3a.CLAMP=0,'FSPI.VOP3a.CLAMP');
if (Byte(FSPI.VOP3a.ABS).TestBit(0)) or
(Byte(FSPI.VOP3a.NEG).TestBit(0)) then
begin
src:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
_emit_src_abs_bit(@src,1);
_emit_src_neg_bit(@src,1);
_MakeCopy(dst,src);
end else
begin
src:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtUnknow);
_MakeCopy(dst,src);
end;
end;
procedure TEmit_VOP3._emit_V_SQRT_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
_emit_src_abs_bit(@src,1);
_emit_src_neg_bit(@src,1);
emit_OpSqrt(dst,src);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_V_RCP_F32;
Var
dst:PsrRegSlot;
src:PsrRegNode;
one:PsrRegNode;
begin
dst:=FRegsStory.get_vdst8(FSPI.VOP3a.VDST);
src:=fetch_ssrc9(FSPI.VOP3a.SRC0,dtFloat32);
_emit_src_abs_bit(@src,1);
_emit_src_neg_bit(@src,1);
one:=FetchReg(FConsts.Fetchf(dtFloat32,1));
emit_OpFDiv(dst,one,src);
_emit_dst_omod_f(dst);
_emit_dst_clamp_f(dst);
end;
procedure TEmit_VOP3._emit_VOP3c;
begin
Case FSPI.VOP3a.OP of
V_CMP_F_F32,
V_CMP_F_F64,
V_CMP_F_I32,
V_CMP_F_I64,
V_CMP_F_U32,
V_CMP_F_U64,
V_CMPS_F_F32,
V_CMPS_F_F64:_emit_V_CMP_C(false,false);
V_CMP_T_F32,
V_CMP_T_F64,
V_CMP_T_I32,
V_CMP_T_I64,
V_CMP_T_U32,
V_CMP_T_U64,
V_CMPS_T_F32,
V_CMPS_T_F64:_emit_V_CMP_C(true,false);
V_CMPX_F_F32,
V_CMPX_F_F64,
V_CMPX_F_I32,
V_CMPX_F_I64,
V_CMPX_F_U32,
V_CMPX_F_U64,
V_CMPSX_F_F32,
V_CMPSX_F_F64:_emit_V_CMP_C(false,true);
V_CMPX_T_F32,
V_CMPX_T_F64,
V_CMPX_T_I32,
V_CMPX_T_I64,
V_CMPX_T_U32,
V_CMPX_T_U64,
V_CMPSX_T_F32,
V_CMPSX_T_F64:_emit_V_CMP_C(true,true);
//
V_CMP_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,false);
V_CMP_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,false);
V_CMP_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,false);
V_CMP_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,false);
V_CMP_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,false);
V_CMP_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,false);
V_CMP_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,false);
V_CMP_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,false);
V_CMP_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,false);
V_CMP_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,false);
V_CMP_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,false);
V_CMP_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,false);
V_CMP_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,false);
V_CMP_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,false);
V_CMPX_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,true);
V_CMPX_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,true);
V_CMPX_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,true);
V_CMPX_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,true);
V_CMPX_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,true);
V_CMPX_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,true);
V_CMPX_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,true);
V_CMPX_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,true);
V_CMPX_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,true);
V_CMPX_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,true);
V_CMPX_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,true);
V_CMPX_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,true);
V_CMPX_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,true);
V_CMPX_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,true);
//
V_CMPS_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,false);
V_CMPS_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,false);
V_CMPS_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,false);
V_CMPS_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,false);
V_CMPS_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,false);
V_CMPS_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,false);
V_CMPS_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,false);
V_CMPS_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,false);
V_CMPS_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,false);
V_CMPS_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,false);
V_CMPS_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,false);
V_CMPS_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,false);
V_CMPS_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,false);
V_CMPS_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,false);
V_CMPSX_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,true);
V_CMPSX_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,true);
V_CMPSX_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,true);
V_CMPSX_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,true);
V_CMPSX_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,true);
V_CMPSX_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,true);
V_CMPSX_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,true);
V_CMPSX_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,true);
V_CMPSX_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,true);
V_CMPSX_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,true);
V_CMPSX_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,true);
V_CMPSX_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,true);
V_CMPSX_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,true);
V_CMPSX_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,true);
//
V_CMP_LT_I32 :_emit_V_CMP_32(Op.OpSLessThan ,dtInt32,false);
V_CMP_EQ_I32 :_emit_V_CMP_32(Op.OpIEqual ,dtInt32,false);
V_CMP_LE_I32 :_emit_V_CMP_32(Op.OpSLessThanEqual ,dtInt32,false);
V_CMP_GT_I32 :_emit_V_CMP_32(Op.OpSGreaterThan ,dtInt32,false);
V_CMP_LG_I32 :_emit_V_CMP_32(Op.OpINotEqual ,dtInt32,false);
V_CMP_GE_I32 :_emit_V_CMP_32(Op.OpSGreaterThanEqual ,dtInt32,false);
V_CMPX_LT_I32 :_emit_V_CMP_32(Op.OpSLessThan ,dtInt32,true);
V_CMPX_EQ_I32 :_emit_V_CMP_32(Op.OpIEqual ,dtInt32,true);
V_CMPX_LE_I32 :_emit_V_CMP_32(Op.OpSLessThanEqual ,dtInt32,true);
V_CMPX_GT_I32 :_emit_V_CMP_32(Op.OpSGreaterThan ,dtInt32,true);
V_CMPX_LG_I32 :_emit_V_CMP_32(Op.OpINotEqual ,dtInt32,true);
V_CMPX_GE_I32 :_emit_V_CMP_32(Op.OpSGreaterThanEqual ,dtInt32,true);
V_CMP_LT_U32 :_emit_V_CMP_32(Op.OpULessThan ,dtUint32,false);
V_CMP_EQ_U32 :_emit_V_CMP_32(Op.OpIEqual ,dtUint32,false);
V_CMP_LE_U32 :_emit_V_CMP_32(Op.OpULessThanEqual ,dtUint32,false);
V_CMP_GT_U32 :_emit_V_CMP_32(Op.OpUGreaterThan ,dtUint32,false);
V_CMP_LG_U32 :_emit_V_CMP_32(Op.OpINotEqual ,dtUint32,false);
V_CMP_GE_U32 :_emit_V_CMP_32(Op.OpUGreaterThanEqual ,dtUint32,false);
V_CMPX_LT_U32 :_emit_V_CMP_32(Op.OpULessThan ,dtUint32,true);
V_CMPX_EQ_U32 :_emit_V_CMP_32(Op.OpIEqual ,dtUint32,true);
V_CMPX_LE_U32 :_emit_V_CMP_32(Op.OpULessThanEqual ,dtUint32,true);
V_CMPX_GT_U32 :_emit_V_CMP_32(Op.OpUGreaterThan ,dtUint32,true);
V_CMPX_LG_U32 :_emit_V_CMP_32(Op.OpINotEqual ,dtUint32,true);
V_CMPX_GE_U32 :_emit_V_CMP_32(Op.OpUGreaterThanEqual ,dtUint32,true);
else
Assert(false,'VOP3c?'+IntToStr(FSPI.VOP3a.OP));
end;
end;
procedure TEmit_VOP3._emit_VOP3b;
begin
Assert(false,'VOP3b?'+IntToStr(FSPI.VOP3b.OP));
end;
procedure TEmit_VOP3._emit_VOP3a;
begin
Case FSPI.VOP3a.OP of
256+V_CNDMASK_B32:
begin
_emit_V_CNDMASK_B32;
end;
256+V_ADD_F32:
begin
_emit_V_ADD_F32;
end;
256+V_SUB_F32:
begin
_emit_V_SUB_F32;
end;
256+V_CVT_PKRTZ_F16_F32:
begin
_emit_V_CVT_PKRTZ_F16_F32;
end;
256+V_MIN_F32:
begin
_emit_V_MIN_F32;
end;
256+V_MAX_F32:
begin
_emit_V_MAX_F32;
end;
256+V_MUL_F32:
begin
_emit_V_MUL_F32;
end;
256+V_MUL_I32_I24:
begin
_emit_V_MUL_I32_I24;
end;
256+V_MAC_F32:
begin
_emit_V_MAC_F32;
end;
V_MUL_LO_I32:
begin
_emit_V_MUL_LO_I32;
end;
V_BFE_U32:
begin
_emit_V_BFE_U32;
end;
V_MAD_F32:
begin
_emit_V_MAD_F32;
end;
V_MAD_I32_I24:
begin
_emit_V_MAD_I32_I24;
end;
V_MAD_U32_U24:
begin
_emit_V_MAD_U32_U24;
end;
V_SAD_U32:
begin
_emit_V_SAD_U32;
end;
V_MAX3_F32:
begin
_emit_V_MAX3_F32;
end;
V_MIN3_F32:
begin
_emit_V_MIN3_F32;
end;
V_MED3_F32:
begin
_emit_V_MED3_F32;
end;
V_FMA_F32:
begin
_emit_V_FMA_F32;
end;
V_CUBEID_F32:_emit_V_CUBE(OpCUBEID);
V_CUBESC_F32:_emit_V_CUBE(OpCUBESC);
V_CUBETC_F32:_emit_V_CUBE(OpCUBETC);
V_CUBEMA_F32:_emit_V_CUBE(OpCUBEMA);
384+V_MOV_B32:
begin
_emit_V_MOV_B32;
end;
384+V_SQRT_F32:
begin
_emit_V_SQRT_F32;
end;
384+V_RCP_F32:
begin
_emit_V_RCP_F32;
end;
else
Assert(false,'VOP3a?'+IntToStr(FSPI.VOP3a.OP));
end;
end;
end.

205
spirv/emit_vopc.pas Normal file
View File

@ -0,0 +1,205 @@
unit emit_VOPC;
{$mode objfpc}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srReg,
spirv,
SprvEmit,
emit_op;
type
TEmit_VOPC=object(TEmitOp)
procedure _emit_VOPC;
procedure _emit_V_CMP_32(OpId:DWORD;rtype:TsrDataType;x:Boolean);
procedure _emit_V_CMP_C(r,x:Boolean);
end;
implementation
procedure TEmit_VOPC._emit_V_CMP_32(OpId:DWORD;rtype:TsrDataType;x:Boolean);
Var
dst:array[0..1] of PsrRegSlot;
src:array[0..1] of PsrRegNode;
begin
dst[0]:=@FRegsStory.VCC[0];
dst[1]:=@FRegsStory.VCC[1];
src[0]:=fetch_ssrc9(FSPI.VOPC.SRC0 ,rtype);
src[1]:=fetch_vsrc8(FSPI.VOPC.VSRC1,rtype);
emit_OpCmpV(OpId,dst[0],src[0],src[1]);
SetConst(dst[1],dtUnknow,0); //set zero
if x then
begin
MakeCopy(@FRegsStory.EXEC[0],dst[0]^.current);
SetConst(@FRegsStory.EXEC[1],dtUnknow,0); //set zero
end;
end;
procedure TEmit_VOPC._emit_V_CMP_C(r,x:Boolean);
Var
dst:array[0..1] of PsrRegSlot;
begin
dst[0]:=@FRegsStory.VCC[0];
dst[1]:=@FRegsStory.VCC[1];
SetConst(dst[0],dtBool,QWORD(r));
SetConst(dst[1],dtUnknow,0); //set zero
if x then
begin
MakeCopy(@FRegsStory.EXEC[0],dst[0]^.current);
SetConst(@FRegsStory.EXEC[1],dtUnknow,0); //set zero
end;
end;
procedure TEmit_VOPC._emit_VOPC;
begin
Case FSPI.VOPC.OP of
V_CMP_F_F32,
V_CMP_F_F64,
V_CMP_F_I32,
V_CMP_F_I64,
V_CMP_F_U32,
V_CMP_F_U64,
V_CMPS_F_F32,
V_CMPS_F_F64:_emit_V_CMP_C(false,false);
V_CMP_T_F32,
V_CMP_T_F64,
V_CMP_T_I32,
V_CMP_T_I64,
V_CMP_T_U32,
V_CMP_T_U64,
V_CMPS_T_F32,
V_CMPS_T_F64:_emit_V_CMP_C(true,false);
V_CMPX_F_F32,
V_CMPX_F_F64,
V_CMPX_F_I32,
V_CMPX_F_I64,
V_CMPX_F_U32,
V_CMPX_F_U64,
V_CMPSX_F_F32,
V_CMPSX_F_F64:_emit_V_CMP_C(false,true);
V_CMPX_T_F32,
V_CMPX_T_F64,
V_CMPX_T_I32,
V_CMPX_T_I64,
V_CMPX_T_U32,
V_CMPX_T_U64,
V_CMPSX_T_F32,
V_CMPSX_T_F64:_emit_V_CMP_C(true,true);
//
V_CMP_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,false);
V_CMP_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,false);
V_CMP_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,false);
V_CMP_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,false);
V_CMP_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,false);
V_CMP_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,false);
V_CMP_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,false);
V_CMP_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,false);
V_CMP_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,false);
V_CMP_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,false);
V_CMP_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,false);
V_CMP_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,false);
V_CMP_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,false);
V_CMP_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,false);
V_CMPX_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,true);
V_CMPX_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,true);
V_CMPX_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,true);
V_CMPX_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,true);
V_CMPX_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,true);
V_CMPX_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,true);
V_CMPX_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,true);
V_CMPX_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,true);
V_CMPX_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,true);
V_CMPX_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,true);
V_CMPX_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,true);
V_CMPX_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,true);
V_CMPX_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,true);
V_CMPX_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,true);
//
V_CMPS_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,false);
V_CMPS_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,false);
V_CMPS_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,false);
V_CMPS_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,false);
V_CMPS_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,false);
V_CMPS_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,false);
V_CMPS_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,false);
V_CMPS_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,false);
V_CMPS_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,false);
V_CMPS_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,false);
V_CMPS_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,false);
V_CMPS_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,false);
V_CMPS_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,false);
V_CMPS_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,false);
V_CMPSX_LT_F32 :_emit_V_CMP_32(Op.OpFOrdLessThan ,dtFloat32,true);
V_CMPSX_EQ_F32 :_emit_V_CMP_32(Op.OpFOrdEqual ,dtFloat32,true);
V_CMPSX_LE_F32 :_emit_V_CMP_32(Op.OpFOrdLessThanEqual ,dtFloat32,true);
V_CMPSX_GT_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThan ,dtFloat32,true);
V_CMPSX_LG_F32 :_emit_V_CMP_32(Op.OpFOrdNotEqual ,dtFloat32,true);
V_CMPSX_GE_F32 :_emit_V_CMP_32(Op.OpFOrdGreaterThanEqual ,dtFloat32,true);
V_CMPSX_O_F32 :_emit_V_CMP_32(Op.OpOrdered ,dtFloat32,true);
V_CMPSX_U_F32 :_emit_V_CMP_32(Op.OpUnordered ,dtFloat32,true);
V_CMPSX_NGE_F32 :_emit_V_CMP_32(Op.OpFUnordLessThan ,dtFloat32,true);
V_CMPSX_NLG_F32 :_emit_V_CMP_32(Op.OpFUnordEqual ,dtFloat32,true);
V_CMPSX_NGT_F32 :_emit_V_CMP_32(Op.OpFUnordLessThanEqual ,dtFloat32,true);
V_CMPSX_NLE_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThan ,dtFloat32,true);
V_CMPSX_NEQ_F32 :_emit_V_CMP_32(Op.OpFUnordNotEqual ,dtFloat32,true);
V_CMPSX_NLT_F32 :_emit_V_CMP_32(Op.OpFUnordGreaterThanEqual,dtFloat32,true);
//
V_CMP_LT_I32 :_emit_V_CMP_32(Op.OpSLessThan ,dtInt32,false);
V_CMP_EQ_I32 :_emit_V_CMP_32(Op.OpIEqual ,dtInt32,false);
V_CMP_LE_I32 :_emit_V_CMP_32(Op.OpSLessThanEqual ,dtInt32,false);
V_CMP_GT_I32 :_emit_V_CMP_32(Op.OpSGreaterThan ,dtInt32,false);
V_CMP_LG_I32 :_emit_V_CMP_32(Op.OpINotEqual ,dtInt32,false);
V_CMP_GE_I32 :_emit_V_CMP_32(Op.OpSGreaterThanEqual ,dtInt32,false);
V_CMPX_LT_I32 :_emit_V_CMP_32(Op.OpSLessThan ,dtInt32,true);
V_CMPX_EQ_I32 :_emit_V_CMP_32(Op.OpIEqual ,dtInt32,true);
V_CMPX_LE_I32 :_emit_V_CMP_32(Op.OpSLessThanEqual ,dtInt32,true);
V_CMPX_GT_I32 :_emit_V_CMP_32(Op.OpSGreaterThan ,dtInt32,true);
V_CMPX_LG_I32 :_emit_V_CMP_32(Op.OpINotEqual ,dtInt32,true);
V_CMPX_GE_I32 :_emit_V_CMP_32(Op.OpSGreaterThanEqual ,dtInt32,true);
V_CMP_LT_U32 :_emit_V_CMP_32(Op.OpULessThan ,dtUint32,false);
V_CMP_EQ_U32 :_emit_V_CMP_32(Op.OpIEqual ,dtUint32,false);
V_CMP_LE_U32 :_emit_V_CMP_32(Op.OpULessThanEqual ,dtUint32,false);
V_CMP_GT_U32 :_emit_V_CMP_32(Op.OpUGreaterThan ,dtUint32,false);
V_CMP_LG_U32 :_emit_V_CMP_32(Op.OpINotEqual ,dtUint32,false);
V_CMP_GE_U32 :_emit_V_CMP_32(Op.OpUGreaterThanEqual ,dtUint32,false);
V_CMPX_LT_U32 :_emit_V_CMP_32(Op.OpULessThan ,dtUint32,true);
V_CMPX_EQ_U32 :_emit_V_CMP_32(Op.OpIEqual ,dtUint32,true);
V_CMPX_LE_U32 :_emit_V_CMP_32(Op.OpULessThanEqual ,dtUint32,true);
V_CMPX_GT_U32 :_emit_V_CMP_32(Op.OpUGreaterThan ,dtUint32,true);
V_CMPX_LG_U32 :_emit_V_CMP_32(Op.OpINotEqual ,dtUint32,true);
V_CMPX_GE_U32 :_emit_V_CMP_32(Op.OpUGreaterThanEqual ,dtUint32,true);
else
Assert(false,'VOPC?');
end;
end;
end.

285
spirv/pssl-spirv.lpi Normal file
View File

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
<CompatibilityMode Value="True"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="pssl-spirv"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units Count="49">
<Unit0>
<Filename Value="pssl-spirv.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="Half16.pas"/>
<IsPartOfProject Value="True"/>
</Unit1>
<Unit2>
<Filename Value="srNodes.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
<Unit3>
<Filename Value="srTypes.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="srConst.pas"/>
<IsPartOfProject Value="True"/>
</Unit4>
<Unit5>
<Filename Value="srRefId.pas"/>
<IsPartOfProject Value="True"/>
</Unit5>
<Unit6>
<Filename Value="srIO.pas"/>
<IsPartOfProject Value="True"/>
</Unit6>
<Unit7>
<Filename Value="srOp.pas"/>
<IsPartOfProject Value="True"/>
</Unit7>
<Unit8>
<Filename Value="srReg.pas"/>
<IsPartOfProject Value="True"/>
</Unit8>
<Unit9>
<Filename Value="SprvEmit.pas"/>
<IsPartOfProject Value="True"/>
</Unit9>
<Unit10>
<Filename Value="srAllocator.pas"/>
<IsPartOfProject Value="True"/>
</Unit10>
<Unit11>
<Filename Value="srArray.pas"/>
<IsPartOfProject Value="True"/>
</Unit11>
<Unit12>
<Filename Value="emit_sop1.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_SOP1"/>
</Unit12>
<Unit13>
<Filename Value="emit_vop1.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_VOP1"/>
</Unit13>
<Unit14>
<Filename Value="emit_vopc.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_VOPC"/>
</Unit14>
<Unit15>
<Filename Value="emit_vop3b.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_VOP3b"/>
</Unit15>
<Unit16>
<Filename Value="emit_mubuf.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_MUBUF"/>
</Unit16>
<Unit17>
<Filename Value="emit_exp.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_EXP"/>
</Unit17>
<Unit18>
<Filename Value="emit_vintrp.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_VINTRP"/>
</Unit18>
<Unit19>
<Filename Value="emit_smrd.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_SMRD"/>
</Unit19>
<Unit20>
<Filename Value="emit_sop2.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_SOP2"/>
</Unit20>
<Unit21>
<Filename Value="emit_vop2.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_VOP2"/>
</Unit21>
<Unit22>
<Filename Value="emit_post_process.pas"/>
<IsPartOfProject Value="True"/>
</Unit22>
<Unit23>
<Filename Value="emit_print.pas"/>
<IsPartOfProject Value="True"/>
</Unit23>
<Unit24>
<Filename Value="emit_mimg.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_MIMG"/>
</Unit24>
<Unit25>
<Filename Value="emit_op.pas"/>
<IsPartOfProject Value="True"/>
</Unit25>
<Unit26>
<Filename Value="emit_sopp.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_SOPP"/>
</Unit26>
<Unit27>
<Filename Value="emit_sopc.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_SOPC"/>
</Unit27>
<Unit28>
<Filename Value="srparsernode.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="srParserNode"/>
</Unit28>
<Unit29>
<Filename Value="srLabel.pas"/>
<IsPartOfProject Value="True"/>
</Unit29>
<Unit30>
<Filename Value="emit_post_op.pas"/>
<IsPartOfProject Value="True"/>
</Unit30>
<Unit31>
<Filename Value="emit_bitcast.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="srBitcast"/>
</Unit31>
<Unit32>
<Filename Value="srVolatile.pas"/>
<IsPartOfProject Value="True"/>
</Unit32>
<Unit33>
<Filename Value="srLayout.pas"/>
<IsPartOfProject Value="True"/>
</Unit33>
<Unit34>
<Filename Value="srBuffer.pas"/>
<IsPartOfProject Value="True"/>
</Unit34>
<Unit35>
<Filename Value="gnSplayTree.pas"/>
<IsPartOfProject Value="True"/>
</Unit35>
<Unit36>
<Filename Value="srVariable.pas"/>
<IsPartOfProject Value="True"/>
</Unit36>
<Unit37>
<Filename Value="srInput.pas"/>
<IsPartOfProject Value="True"/>
</Unit37>
<Unit38>
<Filename Value="srOutput.pas"/>
<IsPartOfProject Value="True"/>
</Unit38>
<Unit39>
<Filename Value="srUniformConstant.pas"/>
<IsPartOfProject Value="True"/>
</Unit39>
<Unit40>
<Filename Value="srOpUtils.pas"/>
<IsPartOfProject Value="True"/>
</Unit40>
<Unit41>
<Filename Value="srCFG.pas"/>
<IsPartOfProject Value="True"/>
</Unit41>
<Unit42>
<Filename Value="srCap.pas"/>
<IsPartOfProject Value="True"/>
</Unit42>
<Unit43>
<Filename Value="srVertLayout.pas"/>
<IsPartOfProject Value="True"/>
</Unit43>
<Unit44>
<Filename Value="srFragLayout.pas"/>
<IsPartOfProject Value="True"/>
</Unit44>
<Unit45>
<Filename Value="srDecorate.pas"/>
<IsPartOfProject Value="True"/>
</Unit45>
<Unit46>
<Filename Value="emit_mbuf.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="emit_VBUF"/>
</Unit46>
<Unit47>
<Filename Value="srbufinfo.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="srBufInfo"/>
</Unit47>
<Unit48>
<Filename Value="emit_bin.pas"/>
<IsPartOfProject Value="True"/>
</Unit48>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="pssl-spirv"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..;..\rtl;..\chip;..\vulkan"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<RelocatableUnit Value="True"/>
</CodeGeneration>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf2Set"/>
<UseLineInfoUnit Value="False"/>
</Debugging>
<LinkSmart Value="True"/>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

784
spirv/pssl-spirv.lpr Normal file
View File

@ -0,0 +1,784 @@
{$mode objfpc}{$H+}
Uses
classes,
Sysutils,
si_ci_vi_merged_offset,
si_ci_vi_merged_registers,
ps4_pssl,
ps4_shader,
//spirv,
srBuffer,
SprvEmit,
emit_post,
emit_alloc,
emit_print,
emit_bin;
var
cfg:record
FName:RawByteString;
FSave:RawByteString;
FPrintInfo:Boolean;
FPrintAsm:Boolean;
FPrintSpv:Boolean;
FUseVertexInput:Boolean;
FUseTexelBuffer:Boolean;
BufferCfg:TsrBufferCfg;
end;
type
TDUMP_WORD=packed record
REG,COUNT:WORD;
end;
{
procedure load_spv(const fname:RawByteString);
var
M:TMemoryStream;
Header:TSPIRVHeader;
DW:TSPIRVInstruction;
label
_exit;
begin
M:=TMemoryStream.Create;
M.LoadFromFile(fname);
M.Position:=0;
Header:=Default(TSPIRVHeader);
M.Read(Header,SizeOf(TSPIRVHeader));
if (Header.MAGIC<>spirv.MagicNumber) then Goto _exit;
Writeln(HexStr(Header.TOOL_ID,8));
DW:=Default(TSPIRVInstruction);
repeat
if M.Read(DW,SizeOf(TSPIRVInstruction))<>SizeOf(TSPIRVInstruction) then Break;
Writeln(spirv.Op.GetStr(DW.OP));
if (DW.COUNT>1) then
begin
M.Seek(SizeOf(DWORD)*(DW.COUNT-1),soCurrent);
end;
until false;
_exit:
M.Free;
end;
}
procedure post_SprvEmit(var SprvEmit:TSprvEmit);
begin
TSprvEmit_post(SprvEmit).Post;
end;
procedure alloc_SprvEmit(var SprvEmit:TSprvEmit);
begin
TSprvEmit_alloc(SprvEmit).Alloc;
end;
procedure print_SprvEmit(var SprvEmit:TSprvEmit);
begin
TSprvEmit_print(SprvEmit).Print;
end;
procedure SaveToStream_SprvEmit(Stream:TStream;var SprvEmit:TSprvEmit);
begin
TSprvEmit_bin(SprvEmit).SaveToStream(Stream);
end;
procedure SaveToFile_SprvEmit(const FName:RawByteString;var SprvEmit:TSprvEmit);
var
F:TFileStream;
begin
F:=TFileStream.Create(FName,fmCreate);
SaveToStream_SprvEmit(F,SprvEmit);
F.Free;
end;
type
TSPI_USER_DATA=array[0..15] of DWORD;
var
GPU_REGS:packed record
PS:packed record
Addr:Pointer;
INPUT_CNTL:array[0..31] of TSPI_PS_INPUT_CNTL_0;
RSRC1:TSPI_SHADER_PGM_RSRC1_PS;
RSRC2:TSPI_SHADER_PGM_RSRC2_PS;
RSRC3:TSPI_SHADER_PGM_RSRC3_PS;
Z_FORMAT :TSPI_SHADER_Z_FORMAT;
COL_FORMAT:TSPI_SHADER_COL_FORMAT;
INPUT_ENA :TSPI_PS_INPUT_ENA;
INPUT_ADDR:TSPI_PS_INPUT_ADDR;
IN_CONTROL:TSPI_PS_IN_CONTROL;
BARYC_CNTL:TSPI_BARYC_CNTL;
SHADER_CONTROL:TDB_SHADER_CONTROL;
SHADER_MASK:TCB_SHADER_MASK;
USER_DATA:TSPI_USER_DATA;
end;
VS:packed record
Addr:Pointer;
RSRC1:TSPI_SHADER_PGM_RSRC1_VS;
RSRC2:TSPI_SHADER_PGM_RSRC2_VS;
RSRC3:TSPI_SHADER_PGM_RSRC3_VS;
OUT_CONFIG:TSPI_VS_OUT_CONFIG;
POS_FORMAT:TSPI_SHADER_POS_FORMAT;
OUT_CNTL :TPA_CL_VS_OUT_CNTL;
USER_DATA:TSPI_USER_DATA;
end;
CS:packed record
Addr:Pointer;
RSRC1:TCOMPUTE_PGM_RSRC1;
RSRC2:TCOMPUTE_PGM_RSRC2;
STATIC_THREAD_MGMT_SE0:TCOMPUTE_STATIC_THREAD_MGMT_SE0;
STATIC_THREAD_MGMT_SE1:TCOMPUTE_STATIC_THREAD_MGMT_SE1;
RESOURCE_LIMITS:TCOMPUTE_RESOURCE_LIMITS;
NUM_THREAD_X:TCOMPUTE_NUM_THREAD_X;
NUM_THREAD_Y:TCOMPUTE_NUM_THREAD_Y;
NUM_THREAD_Z:TCOMPUTE_NUM_THREAD_Z;
USER_DATA:TSPI_USER_DATA;
end;
VGT_NUM_INSTANCES:TVGT_NUM_INSTANCES;
end;
Blocks:TFPList;
procedure ClearBlocks;
var
i:Integer;
begin
if (Blocks=nil) then
begin
Blocks:=TFPList.Create;
Exit;
end;
if (Blocks.Count<>0) then
For i:=0 to Blocks.Count-1 do
begin
FreeMem(Blocks.Items[i]);
end;
Blocks.Clear;
end;
procedure load_dump(const fname:RawByteString);
var
M:TMemoryStream;
W:TDUMP_WORD;
V:DWORD;
addr:Pointer;
size,i:DWORD;
begin
ClearBlocks;
FillChar(GPU_REGS,SizeOf(GPU_REGS),0);
M:=TMemoryStream.Create;
M.LoadFromFile(fname);
M.Position:=0;
V:=0;
W:=Default(TDUMP_WORD);
repeat
if M.Read(W,SizeOf(W))<>SizeOf(W) then Break;
if (W.COUNT=0) then //simple
begin
if M.Read(V,SizeOf(V))<>SizeOf(V) then Break;
Case W.REG of
mmCOMPUTE_PGM_RSRC1 :DWORD(GPU_REGS.CS.RSRC1 ):=V;
mmCOMPUTE_PGM_RSRC2 :DWORD(GPU_REGS.CS.RSRC2 ):=V;
mmCOMPUTE_NUM_THREAD_X:DWORD(GPU_REGS.CS.NUM_THREAD_X):=V;
mmCOMPUTE_NUM_THREAD_Y:DWORD(GPU_REGS.CS.NUM_THREAD_Y):=V;
mmCOMPUTE_NUM_THREAD_Z:DWORD(GPU_REGS.CS.NUM_THREAD_Z):=V;
//
mmCOMPUTE_USER_DATA_0..mmCOMPUTE_USER_DATA_15:
begin
i:=W.REG-mmCOMPUTE_USER_DATA_0;
GPU_REGS.CS.USER_DATA[i]:=V;
end;
//
mmCOMPUTE_STATIC_THREAD_MGMT_SE0:DWORD(GPU_REGS.CS.STATIC_THREAD_MGMT_SE0):=V;
mmCOMPUTE_STATIC_THREAD_MGMT_SE1:DWORD(GPU_REGS.CS.STATIC_THREAD_MGMT_SE1):=V;
mmCOMPUTE_RESOURCE_LIMITS :DWORD(GPU_REGS.CS.RESOURCE_LIMITS ):=V;
//
mmSPI_SHADER_PGM_RSRC1_PS:DWORD(GPU_REGS.PS.RSRC1 ):=V;
mmSPI_SHADER_PGM_RSRC2_PS:DWORD(GPU_REGS.PS.RSRC2 ):=V;
mmSPI_SHADER_PGM_RSRC3_PS:DWORD(GPU_REGS.PS.RSRC3 ):=V;
mmSPI_SHADER_Z_FORMAT :DWORD(GPU_REGS.PS.Z_FORMAT ):=V;
mmSPI_SHADER_COL_FORMAT :DWORD(GPU_REGS.PS.COL_FORMAT ):=V;
mmSPI_PS_INPUT_ENA :DWORD(GPU_REGS.PS.INPUT_ENA ):=V;
mmSPI_PS_INPUT_ADDR :DWORD(GPU_REGS.PS.INPUT_ADDR ):=V;
mmSPI_PS_IN_CONTROL :DWORD(GPU_REGS.PS.IN_CONTROL ):=V;
mmSPI_BARYC_CNTL :DWORD(GPU_REGS.PS.BARYC_CNTL ):=V;
mmDB_SHADER_CONTROL :DWORD(GPU_REGS.PS.SHADER_CONTROL):=V;
mmCB_SHADER_MASK :DWORD(GPU_REGS.PS.SHADER_MASK ):=V;
//
mmSPI_SHADER_USER_DATA_PS_0..mmSPI_SHADER_USER_DATA_PS_15:
begin
i:=W.REG-mmSPI_SHADER_USER_DATA_PS_0;
GPU_REGS.PS.USER_DATA[i]:=V;
end;
//
mmSPI_PS_INPUT_CNTL_0..mmSPI_PS_INPUT_CNTL_31:
begin
i:=W.REG-mmSPI_PS_INPUT_CNTL_0;
DWORD(GPU_REGS.PS.INPUT_CNTL[i]):=V;
end;
//
mmSPI_SHADER_PGM_RSRC1_VS:DWORD(GPU_REGS.VS.RSRC1 ):=V;
mmSPI_SHADER_PGM_RSRC2_VS:DWORD(GPU_REGS.VS.RSRC2 ):=V;
mmSPI_SHADER_PGM_RSRC3_VS:DWORD(GPU_REGS.VS.RSRC3 ):=V;
mmSPI_VS_OUT_CONFIG :DWORD(GPU_REGS.VS.OUT_CONFIG):=V;
mmSPI_SHADER_POS_FORMAT :DWORD(GPU_REGS.VS.POS_FORMAT):=V;
mmPA_CL_VS_OUT_CNTL :DWORD(GPU_REGS.VS.OUT_CNTL ):=V;
//
mmSPI_SHADER_USER_DATA_VS_0..mmSPI_SHADER_USER_DATA_VS_15:
begin
i:=W.REG-mmSPI_SHADER_USER_DATA_VS_0;
GPU_REGS.VS.USER_DATA[i]:=V;
end;
//
mmVGT_NUM_INSTANCES :DWORD(GPU_REGS.VGT_NUM_INSTANCES):=V;
end;
end else
begin
size:=(W.COUNT+1)*4;
if cfg.FPrintInfo then
if (W.COUNT<>0) then Writeln('block:',getRegName(W.REG),' size:',size);
addr:=AllocMem(size+7);
if M.Read(Align(addr,8)^,size)<>size then
begin
FreeMem(addr);
Break;
end else
begin
Blocks.Add(addr);
addr:=Align(addr,8);
end;
Case W.REG of
mmCOMPUTE_PGM_LO:
begin
GPU_REGS.CS.Addr:=addr;
end;
mmSPI_SHADER_PGM_LO_PS:
begin
GPU_REGS.PS.Addr:=addr;
end;
mmSPI_SHADER_PGM_LO_VS:
begin
GPU_REGS.VS.Addr:=addr;
end;
mmCOMPUTE_USER_DATA_0..mmCOMPUTE_USER_DATA_14:
begin
i:=W.REG-mmCOMPUTE_USER_DATA_0;
GPU_REGS.CS.USER_DATA[i+0]:=DWORD({%H-}QWORD(addr));
GPU_REGS.CS.USER_DATA[i+1]:=DWORD({%H-}QWORD(addr) shr 32);
end;
mmSPI_SHADER_USER_DATA_PS_0..mmSPI_SHADER_USER_DATA_PS_14:
begin
i:=W.REG-mmSPI_SHADER_USER_DATA_PS_0;
GPU_REGS.PS.USER_DATA[i+0]:=DWORD({%H-}QWORD(addr));
GPU_REGS.PS.USER_DATA[i+1]:=DWORD({%H-}QWORD(addr) shr 32);
end;
mmSPI_SHADER_USER_DATA_VS_0..mmSPI_SHADER_USER_DATA_VS_14:
begin
i:=W.REG-mmSPI_SHADER_USER_DATA_VS_0;
GPU_REGS.VS.USER_DATA[i+0]:=DWORD({%H-}QWORD(addr));
GPU_REGS.VS.USER_DATA[i+1]:=DWORD({%H-}QWORD(addr) shr 32);
end;
end;
end;
until false;
end;
procedure load_pssl(base:Pointer);
var
info:PShaderBinaryInfo;
Slots:PInputUsageSlot;
SprvEmit:TSprvEmit;
//LParser:TsrLParser;
//FCode:TsrCodeBlock;
i:Byte;
begin
if (base=nil) then Exit;
info:=_calc_shader_info(base,MemSize(base) div 4);
if cfg.FPrintInfo then
if (info<>nil) then
begin
Writeln('signature =',info^.signature );
Writeln('version =',info^.version );
Writeln('pssl_or_cg =',info^.pssl_or_cg );
Writeln('cached =',info^.cached );
Writeln('m_type =',info^.m_type );
Writeln('source_type =',info^.source_type );
Writeln('length =',info^.length );
Writeln('chunkUsageBaseOffsetInDW=',info^.chunkUsageBaseOffsetInDW);
Writeln('numInputUsageSlots =',info^.numInputUsageSlots );
Writeln('isSrt =',info^.isSrt );
Writeln('isSrtUsedInfoValid =',info^.isSrtUsedInfoValid );
Writeln('isExtendedUsageInfo =',info^.isExtendedUsageInfo );
Writeln('reserved2 =',info^.reserved2 );
Writeln('reserved3 =',info^.reserved3 );
Writeln('shaderHash0 =','0x',HexStr(info^.shaderHash0,8));
Writeln('shaderHash1 =','0x',HexStr(info^.shaderHash1,8));
Writeln('crc32 =','0x',HexStr(info^.crc32,8) );
writeln;
if (info^.numInputUsageSlots<>0) then
begin
Slots:=_calc_shader_slot(info);
For i:=0 to info^.numInputUsageSlots-1 do
begin
Writeln('Slot[',i,']');
case Slots[i].m_usageType of
kShaderInputUsageImmResource :Writeln(' ','kShaderInputUsageImmResource ');
kShaderInputUsageImmSampler :Writeln(' ','kShaderInputUsageImmSampler ');
kShaderInputUsageImmConstBuffer :Writeln(' ','kShaderInputUsageImmConstBuffer ');
kShaderInputUsageImmVertexBuffer :Writeln(' ','kShaderInputUsageImmVertexBuffer ');
kShaderInputUsageImmRwResource :Writeln(' ','kShaderInputUsageImmRwResource ');
kShaderInputUsageImmAluFloatConst :Writeln(' ','kShaderInputUsageImmAluFloatConst ');
kShaderInputUsageImmAluBool32Const :Writeln(' ','kShaderInputUsageImmAluBool32Const ');
kShaderInputUsageImmGdsCounterRange :Writeln(' ','kShaderInputUsageImmGdsCounterRange ');
kShaderInputUsageImmGdsMemoryRange :Writeln(' ','kShaderInputUsageImmGdsMemoryRange ');
kShaderInputUsageImmGwsBase :Writeln(' ','kShaderInputUsageImmGwsBase ');
kShaderInputUsageImmShaderResourceTable :Writeln(' ','kShaderInputUsageImmShaderResourceTable ');
kShaderInputUsageImmLdsEsGsSize :Writeln(' ','kShaderInputUsageImmLdsEsGsSize ');
kShaderInputUsageSubPtrFetchShader :Writeln(' ','kShaderInputUsageSubPtrFetchShader ');
kShaderInputUsagePtrResourceTable :Writeln(' ','kShaderInputUsagePtrResourceTable ');
kShaderInputUsagePtrInternalResourceTable :Writeln(' ','kShaderInputUsagePtrInternalResourceTable ');
kShaderInputUsagePtrSamplerTable :Writeln(' ','kShaderInputUsagePtrSamplerTable ');
kShaderInputUsagePtrConstBufferTable :Writeln(' ','kShaderInputUsagePtrConstBufferTable ');
kShaderInputUsagePtrVertexBufferTable :Writeln(' ','kShaderInputUsagePtrVertexBufferTable ');
kShaderInputUsagePtrSoBufferTable :Writeln(' ','kShaderInputUsagePtrSoBufferTable ');
kShaderInputUsagePtrRwResourceTable :Writeln(' ','kShaderInputUsagePtrRwResourceTable ');
kShaderInputUsagePtrInternalGlobalTable :Writeln(' ','kShaderInputUsagePtrInternalGlobalTable ');
kShaderInputUsagePtrExtendedUserData :Writeln(' ','kShaderInputUsagePtrExtendedUserData ');
kShaderInputUsagePtrIndirectResourceTable :Writeln(' ','kShaderInputUsagePtrIndirectResourceTable ');
kShaderInputUsagePtrIndirectInternalResourceTable:Writeln(' ','kShaderInputUsagePtrIndirectInternalResourceTable');
kShaderInputUsagePtrIndirectRwResourceTable :Writeln(' ','kShaderInputUsagePtrIndirectRwResourceTable ');
kShaderInputUsageImmGdsKickRingBufferOffse :Writeln(' ','kShaderInputUsageImmGdsKickRingBufferOffse ');
kShaderInputUsageImmVertexRingBufferOffse :Writeln(' ','kShaderInputUsageImmVertexRingBufferOffse ');
kShaderInputUsagePtrDispatchDraw :Writeln(' ','kShaderInputUsagePtrDispatchDraw ');
kShaderInputUsageImmDispatchDrawInstances :Writeln(' ','kShaderInputUsageImmDispatchDrawInstances ');
else
Writeln(' m_usageType=',Slots[i].m_usageType);
end;
Writeln(' apiSlot=',Slots[i].m_apiSlot);
Writeln(' startRegister=',Slots[i].m_startRegister);
Writeln(' param=',HexStr(Slots[i].m_srtSizeInDWordMinusOne,2));
end;
Writeln;
end;
end;
Assert(info<>nil);
case info^.m_type of
kShaderTypePs :
begin
if cfg.FPrintInfo then
Writeln('USGPR:',GPU_REGS.PS.RSRC2.USER_SGPR,' VGPRS:',GPU_REGS.PS.RSRC1.VGPRS,' SGPRS:',GPU_REGS.PS.RSRC1.SGPRS);
SprvEmit.InitPs(GPU_REGS.PS.RSRC2,GPU_REGS.PS.INPUT_ENA);
SprvEmit.SetUserData(@GPU_REGS.PS.USER_DATA);
end;
kShaderTypeVsVs:
begin
if cfg.FPrintInfo then
Writeln('USGPR:',GPU_REGS.VS.RSRC2.USER_SGPR,' VGPRS:',GPU_REGS.VS.RSRC1.VGPRS,' SGPRS:',GPU_REGS.VS.RSRC1.SGPRS);
SprvEmit.InitVs(GPU_REGS.VS.RSRC2,GPU_REGS.VGT_NUM_INSTANCES);
SprvEmit.SetUserData(@GPU_REGS.VS.USER_DATA);
end;
kShaderTypeCs:
begin
if cfg.FPrintInfo then
Writeln('USGPR:',GPU_REGS.CS.RSRC2.USER_SGPR,' VGPRS:',GPU_REGS.CS.RSRC1.VGPRS,' SGPRS:',GPU_REGS.CS.RSRC1.SGPRS);
SprvEmit.InitCs(GPU_REGS.CS.RSRC2,GPU_REGS.CS.NUM_THREAD_X,GPU_REGS.CS.NUM_THREAD_Y,GPU_REGS.CS.NUM_THREAD_Z);
SprvEmit.SetUserData(@GPU_REGS.CS.USER_DATA);
end;
else
begin
_parse_print(base);
Exit;
end;
end;
SprvEmit.FPrintAsm :=cfg.FPrintAsm;
SprvEmit.FUseVertexInput:=cfg.FUseVertexInput;
SprvEmit.FUseTexelBuffer:=cfg.FUseTexelBuffer;
SprvEmit.FBuffers.cfg:=cfg.BufferCfg;
if (SprvEmit.Parse(base)>1) then
begin
Writeln(StdErr,'Shader Parse Err');
end;
if cfg.FPrintAsm or cfg.FPrintSpv or (cfg.FSave<>'') then
begin
post_SprvEmit(SprvEmit);
alloc_SprvEmit(SprvEmit);
end;
if cfg.FPrintSpv then
begin
print_SprvEmit(SprvEmit);
Writeln;
end;
if (cfg.FSave<>'') then
begin
SaveToFile_SprvEmit(cfg.FSave,SprvEmit);
end;
if cfg.FPrintInfo then
Writeln('used_size=',SprvEmit.FAllocator.used_size);
SprvEmit.FAllocator.Free;
end;
function ParseCmd:Boolean;
var
i,n:Integer;
label
promo;
begin
if (ParamCount=0) then
begin
promo:
Exit(False);
end;
cfg.FUseVertexInput:=True;
cfg.BufferCfg.Init;
n:=-1;
For i:=1 to ParamCount do
begin
case LowerCase(ParamStr(i)) of
'-i':cfg.FPrintInfo:=True;
'-a':cfg.FPrintAsm:=True;
'-p':cfg.FPrintSpv:=True;
'-eva':cfg.FUseVertexInput:=True;
'-dva':cfg.FUseVertexInput:=False;
'-etb':cfg.FUseTexelBuffer:=True;
'-dtb':cfg.FUseTexelBuffer:=False;
'-b':n:=0;
'-mubo':n:=1;//maxUniformBufferRange
'-pco':n:=2;//PushConstantsOffset
'-pcs':n:=3;//maxPushConstantsSize
'-sboa':n:=4;//minStorageBufferOffsetAlignment
'-uboa':n:=5;//minUniformBufferOffsetAlignment
else
begin
Case n of
-1:cfg.FName:=ParamStr(i);
0:cfg.FSave:=ParamStr(i);
1:cfg.BufferCfg.maxUniformBufferRange :=StrToInt64Def(ParamStr(i),0);
2:cfg.BufferCfg.PushConstantsOffset :=StrToInt64Def(ParamStr(i),0);
3:cfg.BufferCfg.maxPushConstantsSize :=StrToInt64Def(ParamStr(i),0);
4:cfg.BufferCfg.minStorageBufferOffsetAlignment:=StrToInt64Def(ParamStr(i),0);
5:cfg.BufferCfg.minUniformBufferOffsetAlignment:=StrToInt64Def(ParamStr(i),0);
end;
n:=-1;
end;
end;
end;
Result:=True;
end;
begin
DefaultSystemCodePage:=CP_UTF8;
DefaultUnicodeCodePage:=CP_UTF8;
DefaultFileSystemCodePage:=CP_UTF8;
DefaultRTLFileSystemCodePage:=CP_UTF8;
UTF8CompareLocale:=CP_UTF8;
FillChar(cfg,SizeOf(cfg),0);
ParseCmd;
if (cfg.FName='') then
begin
//loadspv('vert.spv');
//branch adr
//load_dump('shader_dump\MomodoraRUtM\MomodoraRUtM_ps_595F5E5D.dump');
//load_dump('shader_dump\MomodoraRUtM\MomodoraRUtM_vs_B9E80F51.dump');
//load_dump('shader_dump\MomodoraRUtM\MomodoraRUtM_vs_72685B15.dump');
//branch
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_cs_3685EFC7.dump');
//branch
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_8D309F69.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_30AC6582.dump');
//V_MED3_F32
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_46F7D0CB.dump');
//branch
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_897BFEFF.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_A9A43387.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_BD5B57D5.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_C342C7CD.dump');
//V_MED3_F32
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_E125C5F7.dump');
//branch cycle
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_ps_E820FFDE.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_vs_1CE5C47E.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_vs_22E9CA76.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_vs_48FA7A4C.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_vs_243D8C75.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_vs_B4E470AF.dump');
//load_dump('shader_dump\tutorial_anti-aliasing_debug\tutorial_anti-aliasing_debug_vs_E1C90BE3.dump');
//branch
////load_dump('shader_dump\WeAreDoomed\WeAreDoomed_ps4_cs_FEA061C5.dump');
//load_dump('shader_dump\simplet-simple-fs_debug\simplet-simple-fs_debug_vs_398C5BF6.dump');
//load_dump('shader_dump\simplet-simple-fs_debug\simplet-simple-fs_debug_ps_F327ABD1.dump');
//load_dump('shader_dump\simplet-single-triangle_debug\simplet-single-triangle_debug_vs_78EF9008.dump');
//load_dump('shader_dump\simplet-single-triangle_debug\simplet-single-triangle_debug_ps_FBCA196D.dump');
//load_dump('shader_dump\basic_quad_debug\basic_quad_debug_ps_C342C7CD.dump');
//load_dump('shader_dump\basic_quad_debug\basic_quad_debug_vs_D216FEB8.dump');
//load_dump('shader_dump\basic_quad_debug\basic_quad_debug_cs_3685EFC7.dump');
//load_dump('shader_dump\basic_quad_debug\basic_quad_debug_ps_A9F64695.dump');
//load_dump('shader_dump\basic_quad_debug\basic_quad_debug_vs_B4E470AF.dump');
//load_dump('shader_dump\basic_quad_debug\basic_quad_debug_vs_1CE5C47E.dump');
//load_dump('shader_dump\basic-compute_debug\basic-compute_debug_ps_4BD7E17E.dump');
//load_dump('shader_dump\basic-compute_debug\basic-compute_debug_vs_0C30DA0F.dump');
//load_dump('shader_dump\SonicMania\SonicMania_ps_0C48E8B2.dump');
//load_dump('shader_dump\SonicMania\SonicMania_ps_B4281DBF.dump');
load_dump('shader_dump\SonicMania\SonicMania_ps_11DF2A32.dump');
//load_dump('shader_dump\SonicMania\SonicMania_ps_3CC22A00.dump'); //cfg
end;
if (cfg.FName<>'') then
load_dump(cfg.FName);
load_pssl(GPU_REGS.CS.Addr);
load_pssl(GPU_REGS.VS.Addr);
load_pssl(GPU_REGS.PS.Addr);
if cfg.FPrintInfo then
readln;
end.
{
///////////////////source ext
[USER_DATA]
|
v
//DATA LAYOUT
[PARENT_LAYOUT|DATA_TYPE|OFFSET|INDEX]
^ ^ ^
| | | //CHILD LAYOUT //UNIFORM
| |[PARENT_LAYOUT|DATA_TYPE|OFFSET] <- [SOURCE_LAYOUT|HANDLE_TYPE|PVAR|PREG]
| | ^ ^
| | | |
| | /-------------------------/ |
| | | |
| | v |
| | [PVAR] <- [opLoad]<--------------/
| |
| | //CHILD LAYOUT //BUFFER
| [PARENT_LAYOUT|DATA_TYPE|OFFSET] <- [SOURCE_LAYOUT|CAST_NUM|PVAR] <-> [PVAR]<----------\
| ^ |
| | //BUFFER FIELD |
| [SOURCE_BUFFER|SOURCE_FIELD|ID|OFFSET|SIZE|PREG] |
| ^ | |
| /------------/ | |
| | | |
| [OpAccessChain|ID|ID...]<-------------------------/
| ^ |
| | |
| [opLoad]<-----------------------------------/
|
|[SET]
|
| //CHAIN LAYOUT
[SOURCE_LAYOUT|OFFSET|PREG] <-> [opLoad]
///////////////////
[FUserDataVar]
^
| /----------------------------------------v---------------------------\
[pArray|Source] <- [OpAccessChain|[Index]] <- [PChain|pWriter|ID] <- [opLoad] <- [pReg|ID]
[PChain]*x
^ ^
| |
[pGroup|chains]
//////////////////
[pUniform]
| ^
v /-----------------------\
[Forked_Var] <- [opLoad] <- [pReg|ID] <- [OpImageRead1D]
//////////////////
[OpVariable] [pointer struct] PushConstant
^ ^
| |
| [OpTypePointer] PushConstant [struct]
| ^
| |
| [OpTypeStruct] [item1:type] <- aType
| ^ ^ ^
| | | |
| | [OpMemberDecorate] [struct] [item1:index] Offset 0
| |
| [OpDecorate] [struct] Block
|
| [OpTypePointer] PushConstant [item1:type]
| |
| v
[OpAccessChain] [pointer type] [pVar] [item1:index]
}
{
x:=1 //write
[opLabel]->
y:=x+1 //read ^make var
[opLabel]<-
//////////////////////////////
y:=0 //write
[opLabel]->
y:=1 //write
y:=y+y //write <-
[opLabel]<-
x:=y+1; //read ^make var
y:=1 //write <- reset var
//////////////////////////////
y:=0 //write
[opLabel]->
x:=1 //write
[opLabel]<-
x:=y+1; //read ^nop
//////////////////////////////
[OpCond]
IF[ [OpSelectionMerge] [OpBranchConditional] [OpLabel]
//body
[OpLabel] ]ENDIF
//////////////////////////////
IF[ [OpBranch] [OpLabel]
WHILE[ [OpLoopMerge] [OpBranch] [OpLabel]
//body
[OpBranch] [OpLabel] ]WHILE(1)
[OpCond]
[OpBranchConditional] [OpLabel] ]WHILE(2) ]ENDIF
//////////////////////////////
}

4120
spirv/spirv.pas Normal file

File diff suppressed because it is too large Load Diff

81
spirv/srAllocator.pas Normal file
View File

@ -0,0 +1,81 @@
unit srAllocator;
{$mode objfpc}{$H+}
interface
uses
srNodes;
type
PsrAllocNode=^TsrAllocNode;
TsrAllocNode=packed record
pNext:PsrAllocNode;
data:record end;
end;
_TsrAllocator=specialize TNodeStack<PsrAllocNode>;
TsrAllocator=object(_TsrAllocator)
curr_apos:ptruint; //alloc pos in current node
curr_size:ptruint; //useable size of current node
used_size:ptruint; //full usable size
full_size:ptruint; //full alloc size
Function Alloc(Size:ptruint):Pointer;
Procedure Free;
end;
implementation
Function TsrAllocator.Alloc(Size:ptruint):Pointer;
const
asize=$FFFF-SizeOf(ptruint)*3;
var
mem_size:ptruint;
function _alloc:Pointer;
begin
if (Size>asize-SizeOf(Pointer)) then
begin
Result:=AllocMem(Size+SizeOf(Pointer));
end else
begin
Result:=AllocMem(asize);
end;
end;
begin
if (pHead=nil) or (Size>curr_size) then
begin
Push_head(_alloc);
mem_size:=MemSize(pHead);
curr_apos:=0;
curr_size:=mem_size-SizeOf(Pointer);
Inc(full_size,mem_size);
end;
Result:=@PByte(@pHead^.data)[curr_apos];
Inc(used_size,Size);
Size:=Align(Size,SizeOf(ptruint));
Inc(curr_apos,Size);
Dec(curr_size,Size);
end;
Procedure TsrAllocator.Free;
var
node:PsrAllocNode;
begin
node:=Pop_head;
While (node<>nil) do
begin
FreeMem(node);
node:=Pop_head;
end;
curr_apos:=0;
curr_size:=0;
used_size:=0;
full_size:=0;
end;
end.

152
spirv/srBitcast.pas Normal file
View File

@ -0,0 +1,152 @@
unit srBitcast;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
srNodes,
srTypes,
srConst,
srReg;
type
PsrBitcast=^TsrBitcast;
TsrBitcast=object
pLeft,pRight:PsrBitcast;
//----
key:packed record
dtype:TsrDataType;
src:PsrRegNode;
end;
dst:PsrRegNode;
function c(n1,n2:PsrBitcast):Integer; static;
end;
TsrBitcastList=object
type
TNodeFetch=specialize TNodeFetch<PsrBitcast,TsrBitcast>;
var
pRoot:Pointer;
FNTree:TNodeFetch;
function Find(dtype:TsrDataType;src:PsrRegNode):PsrBitcast;
function FetchRead(dtype:TsrDataType;src:PsrRegNode):PsrRegNode;
function FetchDst(dtype:TsrDataType;src:PsrRegNode):PsrRegNode;
function FetchCast(dtype:TsrDataType;src:PsrRegNode):PsrRegNode;
end;
implementation
uses
SprvEmit,
emit_op;
function TsrBitcast.c(n1,n2:PsrBitcast):Integer;
begin
Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrBitcast.key));
end;
function TsrBitcastList.Find(dtype:TsrDataType;src:PsrRegNode):PsrBitcast;
var
node:TsrBitcast;
begin
node:=Default(TsrBitcast);
node.key.dtype:=dtype;
node.key.src:=src;
Result:=FNTree.Find(@node);
end;
function TsrBitcastList.FetchRead(dtype:TsrDataType;src:PsrRegNode):PsrRegNode;
var
dst:PsrRegNode;
begin
Result:=src;
if (src=nil) then Exit;
if (dtype=dtUnknow) or (dtype=src^.dtype) then
begin
src^.mark_read;
Exit;
end;
src^.mark_read;
dst:=PSprvEmit(pRoot)^.NewReg(dtype);
dst^.pLine:=src^.pLine;
dst^.pWriter.SetParam(ntReg,src);
dst^.mark_read;
Result:=dst;
end;
function TsrBitcastList.FetchDst(dtype:TsrDataType;src:PsrRegNode):PsrRegNode;
begin
Result:=src;
if (src=nil) then Exit;
if (dtype=dtUnknow) or (dtype=src^.dtype) then Exit;
Result:=PSprvEmit(pRoot)^.NewReg(dtype);
Result^.pLine:=src^.pLine;
Result^.mark_read;
Result^.pWriter:=src^.pWriter;
src^.pWriter.SetParam(ntReg,Result);
end;
function TsrBitcastList.FetchCast(dtype:TsrDataType;src:PsrRegNode):PsrRegNode;
var
node:PsrBitcast;
dst:PsrRegNode;
begin
Result:=src;
if (src=nil) then Exit;
if (dtype=dtUnknow) or (dtype=src^.dtype) then
begin
src^.mark_read;
Exit;
end;
dst:=nil;
node:=Find(dtype,src);
if (node<>nil) then
begin
dst:=node^.dst;
dst^.mark_read;
Result:=dst;
Exit;
end;
if src^.is_const then
begin
src^.AsConst^.mark_unread;
dst:=PSprvEmit(pRoot)^.NewReg(dtype);
dst^.pLine:=src^.pLine;
dst^.pWriter.SetParam(ntConst,PSprvEmit(pRoot)^.FConsts.Bitcast(dtype,src^.AsConst));
end else
begin
if TryBitcastType(src^.dtype,dtype) then
begin
src^.mark_read;
dst:=PSprvEmit(pRoot)^.NewReg(dtype);
dst^.pLine:=src^.pLine;
PEmitOp(pRoot)^.emit_OpCastExt(src^.pLine,dst,src);
end else
begin
Assert(false,'bitcast');
end;
end;
node:=PSprvEmit(pRoot)^.Alloc(SizeOf(TsrBitcast));
node^:=Default(TsrBitcast);
node^.key.dtype:=dtype;
node^.key.src:=src;
node^.dst:=dst;
FNTree.Insert(node);
dst^.mark_read;
Result:=dst;
end;
end.

837
spirv/srBuffer.pas Normal file
View File

@ -0,0 +1,837 @@
unit srBuffer;
{$mode ObjFPC}{$H+}
interface
uses
spirv,
srNodes,
srTypes,
srVariable,
srLayout,
srDecorate;
type
PsrBuffer=^TsrBuffer;
PsrField=^TsrField;
TsrFieldValue=(frNotFit,frIdent,frVectorAsValue,frValueInVector,frValueInArray);
TFieldFetchValue=record
fValue:TsrFieldValue;
pField:PsrField;
end;
TFieldEnumCb=procedure(pField:PsrField) of object;
TsrField=object
type
TFieldFetch=specialize TNodeFetch<PsrField,TsrField>;
var
pLeft,pRight:PsrField;
//----
pBuffer:PsrBuffer;
parent:PsrField;
offset:PtrUint;
size:PtrUint;
stride:PtrUint;
FCount:PtrUint;
dtype:TsrDataType;
pType:PsrType;
FID:Integer; //alloc late
//
Alloc:TfnAlloc;
FList:TFieldFetch;
function c(n1,n2:PsrField):Integer; static;
function Cross(o,s:PtrUint):Boolean;
function Find_be(o:PtrUint):PsrField;
function Find_le(o:PtrUint):PsrField;
function First:PsrField;
function Last:PsrField;
function Next(p:PsrField):PsrField;
function Prev(p:PsrField):PsrField;
function Fetch(o:PtrUint):PsrField;
function FetchValue(_offset,_size:PtrUint;_dtype:TsrDataType):TFieldFetchValue;
function FetchRuntimeArray(_offset,_stride:PtrUint):TFieldFetchValue;
function IsStructUsedRuntimeArray:Boolean;
function IsStructNotUsed:Boolean;
function GetStructDecorate:DWORD;
procedure FillNode(o,s:PtrUint);
function FillSpace:Integer;
procedure AllocID;
procedure AllocBinding(aType:PsrType;Decorates:PsrDecorateList);
end;
TsrBufferType=(btStorageBuffer,btUniformBuffer,btPushConstant);
TsrBuffer=object(TsrDescriptor)
pLeft,pRight:PsrBuffer;
//----
key:packed record
pLayout:PsrDataLayout;
CastNum:PtrInt;
end;
bType:TsrBufferType;
write_count:DWORD;
align_offset:DWORD;
FTop:TsrField;
function c(n1,n2:PsrBuffer):Integer; static;
function GetTypeChar:Char;
function GetString:RawByteString;
function GetStructName:RawByteString;
procedure UpdateSize;
function GetSize:PtrUint;
procedure EnumAllField(cb:TFieldEnumCb);
procedure ShiftOffset(Offset:PtrUint);
end;
TsrBufferCfg=object
SpvVersion:PtrUint;
maxUniformBufferRange:PtrUint; // $FFFF
PushConstantsOffset:PtrUint; // 0
maxPushConstantsSize:PtrUint; // 128
minStorageBufferOffsetAlignment:PtrUint; // $10
minUniformBufferOffsetAlignment:PtrUint; // $100
Procedure Init;
Function CanUseStorageBufferClass:Boolean;
end;
TsrBufferList=object
type
TNodeFetch=specialize TNodeFetch<PsrBuffer,TsrBuffer>;
var
Alloc:TfnAlloc;
cfg:TsrBufferCfg;
FNTree:TNodeFetch;
FPushConstant:PsrBuffer;
procedure Init(cb:TfnAlloc);
function Fetch(s:PsrDataLayout;n:PtrInt):PsrBuffer;
function NextCast(buf:PsrBuffer):PsrBuffer;
Function First:PsrBuffer;
Function Next(node:PsrBuffer):PsrBuffer;
procedure EnumAllField(cb:TFieldEnumCb);
procedure OnFillSpace(node:PsrField);
procedure FillSpace;
procedure OnAllocID(node:PsrField);
procedure AllocID;
procedure AllocBinding(Var FBinding:Integer;Decorates:PsrDecorateList);
procedure AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
procedure UpdateStorage(node:PsrChain;pBuffer:PsrBuffer);
procedure ApplyBufferType;
procedure AlignOffset(node:PsrBuffer;offset:PtrUint);
procedure AlignOffset;
end;
implementation
//---
function TsrField.c(n1,n2:PsrField):Integer;
begin
Result:=Integer(n1^.offset>n2^.offset)-Integer(n1^.offset<n2^.offset);
end;
function TsrField.Cross(o,s:PtrUint):Boolean;
begin
Result:=((o>=offset) and (o<offset+size)) or
((offset>=o) and (offset<o+s));
end;
function TsrField.Find_be(o:PtrUint):PsrField;
var
node:TsrField;
begin
node:=Default(TsrField);
node.offset:=o;
Result:=FList.Find_be(@node);
end;
function TsrField.Find_le(o:PtrUint):PsrField;
var
node:TsrField;
begin
node:=Default(TsrField);
node.offset:=o;
Result:=FList.Find_le(@node);
end;
function TsrField.First:PsrField;
begin
Result:=FList.Min;
end;
function TsrField.Last:PsrField;
begin
Result:=FList.Max;
end;
function TsrField.Next(p:PsrField):PsrField;
begin
Result:=FList.Next(p);
end;
function TsrField.Prev(p:PsrField):PsrField;
begin
Result:=FList.Prev(p);
end;
function TsrField.Fetch(o:PtrUint):PsrField;
var
node:TsrField;
begin
node:=Default(TsrField);
node.offset:=o;
Result:=FList.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrField));
Result^.Alloc:=Alloc;
Result^.pBuffer:=pBuffer;
Result^.parent:=@Self;
Result^.offset:=o;
Result^.FID:=-1;
FList.Insert(Result);
Inc(FCount);
end;
end;
function TsrField.FetchValue(_offset,_size:PtrUint;_dtype:TsrDataType):TFieldFetchValue;
var
node:PsrField;
_stride:PtrUint;
begin
Result:=Default(TFieldFetchValue);
_stride:=0;
if isVector(_dtype) then
begin
_stride:=BitSizeType(GetVecChild(_dtype)) div 8;
end;
node:=Find_le(_offset);
if (node<>nil) then
begin
if not node^.Cross(_offset,_size) then
begin
node:=Next(node);
if (node<>nil) then
begin
if not node^.Cross(_offset,_size) then
begin
node:=nil;
end;
end;
end;
end;
if (node=nil) then
begin
//new
node:=Fetch(_offset);
node^.size :=_size;
node^.stride:=_stride;
node^.dtype :=_dtype;
Result.fValue:=frIdent;
Result.pField:=node;
end else
Case node^.dtype of
dtTypeArray:
begin
if (node^.offset>_offset) then Exit; //ident or big than
if (node^.offset+node^.size<_offset+_size) then Exit;
if (node^.stride<_size) then Exit; //ident or min stride
Result.fValue:=frValueInArray;
Result.pField:=node;
end;
dtTypeRuntimeArray:
begin
if (node^.offset>_offset) then Exit; //ident or big than
if (node^.stride<_size) then Exit; //ident or min stride
Result.fValue:=frValueInArray;
Result.pField:=node;
end;
else
begin
if isVector(node^.dtype) then
begin //ftVector
if isVector(_dtype) then
begin
if (node^.offset=_offset) and
(node^.size =_size) and
(node^.stride=_stride) then
begin
Result.fValue:=frIdent; //ident
Result.pField:=node;
end;
end else
begin
if (node^.offset>_offset) then Exit; //ident or big than
_offset:=_offset-node^.offset;
if (node^.stride=_size) and
(_offset mod node^.stride=0) then
begin
Result.fValue:=frValueInVector; //down to vector
Result.pField:=node;
end;
end;
end else
begin //ftValue
if isVector(_dtype) then
begin
if (node^.offset=_offset) and
(node^.size =_size) then
begin
Result.fValue:=frVectorAsValue; //vector as value?
Result.pField:=node;
end;
end else
begin
if (node^.offset=_offset) and
(node^.size =_size) then
begin
Result.fValue:=frIdent; //ident
Result.pField:=node;
end;
end;
end;
end;
end;
end;
function TsrField.FetchRuntimeArray(_offset,_stride:PtrUint):TFieldFetchValue;
var
node:PsrField;
begin
Result:=Default(TFieldFetchValue);
node:=Find_le(_offset);
if (node=nil) then
begin
//new
node:=Fetch(_offset);
node^.size :=High(PtrUint)-_offset;
node^.stride :=_stride;
node^.dtype :=dtTypeRuntimeArray;
Result.fValue:=frValueInArray;
Result.pField:=node;
end else
if (node^.stride=_stride) and
(node^.dtype =dtTypeRuntimeArray) and
(node^.offset<=_offset) then //ident or big than
begin
Result.fValue:=frValueInArray;
Result.pField:=node;
end;
end;
function TsrField.IsStructUsedRuntimeArray:Boolean;
var
node:PsrField;
begin
Result:=False;
if (dtype=dtTypeStruct) then
begin
node:=FList.Max;
if (node<>nil) then
begin
size:=node^.offset+node^.size;
end;
Result:=(size=High(PtrUint));
end;
end;
function TsrField.IsStructNotUsed:Boolean;
begin
Result:=(FCount<=1) and (parent<>nil);
end;
function TsrField.GetStructDecorate:DWORD;
begin
Result:=DWORD(-1); //dont use
if (parent=nil) then //is top
if (dtype=dtTypeStruct) then //is struct
begin
if (pBuffer^.FStorage<>StorageClass.StorageBuffer) and
(pBuffer^.bType=btStorageBuffer) then
begin
Result:=Decoration.BufferBlock;
end else
begin
Result:=Decoration.Block;
end;
end;
end;
procedure TsrField.FillNode(o,s:PtrUint);
procedure _Pad(p,v:PtrUint;_dtype:TsrDataType); //inline;
var
node:PsrField;
begin
if (o mod p<>0) and (s>=v) then
begin
node:=Fetch(o);
Assert(node^.dtype=dtUnknow,'WTF');
node^.size:=v;
node^.dtype:=_dtype;
o:=o+v;
s:=s-v;
end;
end;
procedure _Fill(v:PtrUint;_dtype:TsrDataType); //inline;
var
count:PtrUint;
node:PsrField;
begin
count:=s div v;
While (count<>0) do
begin
node:=Fetch(o);
Assert(node^.dtype=dtUnknow,'WTF');
node^.size:=v;
node^.dtype:=_dtype;
o:=o+v;
s:=s-v;
Dec(count);
end;
end;
begin
if (s=0) then Exit;
_Pad ( 2,1,dtUint8);
_Pad ( 4,2,dtHalf16);
_Pad ( 8,4,dtFloat32);
_Pad (16,8,dtVec2f);
_Fill(16,dtVec4f);
_Fill(8 ,dtVec2f);
_Fill(4 ,dtFloat32);
_Fill(2 ,dtHalf16);
_Fill(1 ,dtUint8);
end;
function TsrField.FillSpace:Integer;
var
pNode:PsrField;
Foffset,Fsize:PtrUint;
begin
Result:=0;
pNode:=First;
if (pNode=nil) then Exit;
Foffset:=0;
While (pNode<>nil) do
begin
Assert(pNode^.dtype<>dtUnknow,'WTF');
if (Foffset<pNode^.offset) then
begin
Fsize:=pNode^.offset-Foffset;
FillNode(Foffset,Fsize);
Inc(Result);
end;
Foffset:=pNode^.offset+pNode^.size;
pNode:=Next(pNode);
end;
if (stride<>0) and (dtype in [dtTypeArray,dtTypeRuntimeArray]) then
begin
pNode:=FList.Max;
if (pNode<>nil) then
begin
Foffset:=pNode^.offset+pNode^.size;
Assert(Foffset<=stride);
if (Foffset<stride) then
begin
Fsize:=stride-Foffset;
FillNode(Foffset,Fsize);
Inc(Result);
end;
end;
end;
end;
procedure TsrField.AllocID;
var
node:PsrField;
ID:Integer;
begin
ID:=0;
node:=First;
While (node<>nil) do
begin
if IsVector(dtype) then
begin
ID:=node^.offset div stride;
node^.FID:=ID;
end else
begin
node^.FID:=ID;
Inc(ID);
end;
node:=Next(node);
end;
end;
procedure TsrField.AllocBinding(aType:PsrType;Decorates:PsrDecorateList);
var
node:PsrField;
begin
if (aType=nil) then Exit;
if (Decorates=nil) then Exit;
if isVector(dtype) then Exit;
node:=First;
While (node<>nil) do
begin
Decorates^.emit_member_decorate(ntType,aType,node^.FID,node^.offset);
node:=Next(node);
end;
end;
//--
function TsrBuffer.c(n1,n2:PsrBuffer):Integer;
begin
//first pLayout
Result:=Integer(n1^.key.pLayout>n2^.key.pLayout)-Integer(n1^.key.pLayout<n2^.key.pLayout);
if (Result<>0) then Exit;
//second CastNum
Result:=Integer(n1^.key.CastNum>n2^.key.CastNum)-Integer(n1^.key.CastNum<n2^.key.CastNum);
end;
function TsrBuffer.GetTypeChar:Char;
begin
Result:=#0;
Case bType of
btStorageBuffer:Result:='S';
btUniformBuffer:Result:='U';
btPushConstant :Result:='P';
end;
end;
function TsrBuffer.GetString:RawByteString;
var
PID:DWORD;
begin
PID:=0;
if (key.pLayout<>nil) then
begin
PID:=key.pLayout^.FID;
end;
Result:='B'+GetTypeChar+
';PID='+HexStr(PID,8)+
';BND='+HexStr(FBinding,8)+
';LEN='+HexStr(GetSize,8)+
';OFS='+HexStr(align_offset,8);
end;
function TsrBuffer.GetStructName:RawByteString;
begin
Result:='TD'+HexStr(FBinding,8);
end;
procedure TsrBuffer.UpdateSize;
var
node:PsrField;
begin
node:=FTop.FList.Max;
if (node<>nil) then
begin
FTop.size:=node^.offset+node^.size;
end;
end;
function TsrBuffer.GetSize:PtrUint;
begin
UpdateSize;
Result:=FTop.size;
end;
procedure TsrBuffer.EnumAllField(cb:TFieldEnumCb);
var
curr,node:PsrField;
begin
if (cb=nil) then Exit;
curr:=@FTop;
node:=curr^.First;
repeat
While (node<>nil) do
begin
if (node^.FList.pRoot<>nil) then //child exist
begin
curr^.FList._Splay(node); //Move to root
curr:=node;
node:=curr^.First; //down
end else
begin
cb(node);
node:=curr^.Next(node);
end;
end;
cb(curr);
curr:=curr^.parent; //up
if (curr=nil) then Break;
node:=curr^.FList.pRoot; //last find
node:=curr^.Next(node);
until false;
end;
procedure TsrBuffer.ShiftOffset(Offset:PtrUint);
var
node:PsrField;
begin
if (Offset=0) then Exit;
node:=FTop.Last;
While (node<>nil) do
begin
if (node^.offset+node^.size=High(PtrUint)) then
begin
node^.size:=node^.size-Offset;
end;
node^.offset:=node^.offset+Offset;
node:=FTop.Prev(node);
end;
end;
Procedure TsrBufferCfg.Init;
begin
SpvVersion:=$10100;
maxUniformBufferRange:=$FFFF;
maxPushConstantsSize:=128;
minStorageBufferOffsetAlignment:=$10;
minUniformBufferOffsetAlignment:=$100;
end;
Function TsrBufferCfg.CanUseStorageBufferClass:Boolean;
begin
Result:=(SpvVersion>=$10300);
end;
procedure TsrBufferList.Init(cb:TfnAlloc);
begin
Alloc:=cb;
cfg.Init;
end;
function TsrBufferList.Fetch(s:PsrDataLayout;n:PtrInt):PsrBuffer;
var
node:TsrBuffer;
begin
node:=Default(TsrBuffer);
node.key.pLayout:=s;
node.key.CastNum:=n;
Result:=FNTree.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrBuffer));
Result^.key.pLayout:=s;
Result^.key.CastNum:=n;
Result^.bType :=btStorageBuffer;
Result^.FStorage:=StorageClass.Uniform;
Result^.FBinding:=-1;
Result^.FTop.Alloc:=Alloc;
Result^.FTop.pBuffer:=Result;
Result^.FTop.FID:=-1;
Result^.FTop.dtype:=dtTypeStruct;
FNTree.Insert(Result);
end;
end;
function TsrBufferList.NextCast(buf:PsrBuffer):PsrBuffer;
begin
Result:=nil;
if (buf=nil) then Exit;
Result:=Fetch(buf^.key.pLayout,buf^.key.CastNum+1);
end;
Function TsrBufferList.First:PsrBuffer;
begin
Result:=FNTree.Min;
end;
Function TsrBufferList.Next(node:PsrBuffer):PsrBuffer;
begin
Result:=FNTree.Next(node);
end;
procedure TsrBufferList.EnumAllField(cb:TFieldEnumCb);
var
node:PsrBuffer;
begin
if (cb=nil) then Exit;
node:=First;
While (node<>nil) do
begin
node^.EnumAllField(cb);
node:=Next(node);
end;
end;
procedure TsrBufferList.OnFillSpace(node:PsrField);
begin
node^.FillSpace;
end;
procedure TsrBufferList.FillSpace;
begin
EnumAllField(@OnFillSpace);
end;
procedure TsrBufferList.OnAllocID(node:PsrField);
begin
node^.AllocID;
end;
procedure TsrBufferList.AllocID;
begin
EnumAllField(@OnAllocID);
end;
procedure TsrBufferList.AllocBinding(Var FBinding:Integer;Decorates:PsrDecorateList);
var
node:PsrBuffer;
pVar:PsrVariable;
begin
if (Decorates=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
if (node^.bType<>btPushConstant) then
if (node^.FBinding=-1) then //alloc
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.Binding,FBinding);
Decorates^.emit_decorate(ntVar,pVar,Decoration.DescriptorSet,Decorates^.FDescriptorSet);
node^.FBinding:=FBinding;
Inc(FBinding);
end;
end;
node:=Next(node);
end;
end;
procedure TsrBufferList.AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
var
node:PsrBuffer;
pVar:PsrVariable;
begin
if (FDebugInfo=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
FDebugInfo^.emit_source_extension(node^.GetString);
end;
node:=Next(node);
end;
end;
procedure TsrBufferList.UpdateStorage(node:PsrChain;pBuffer:PsrBuffer);
begin
if (node=nil) or (pBuffer=nil) then Exit;
pBuffer^.write_count:=pBuffer^.write_count+node^.write_count;
end;
procedure TsrBufferList.ApplyBufferType;
var
node:PsrBuffer;
begin
node:=First;
While (node<>nil) do
begin
if (node^.bType=btStorageBuffer) then
begin
if (FPushConstant=nil) and
(node^.write_count=0) and
(node^.GetSize<=cfg.maxPushConstantsSize) then
begin
node^.bType :=btPushConstant;
node^.FStorage:=StorageClass.PushConstant;
FPushConstant:=node;
end else
if (node^.write_count=0) and
(node^.GetSize<=cfg.maxUniformBufferRange) then
begin
node^.bType :=btUniformBuffer;
node^.FStorage:=StorageClass.Uniform;
end else
if cfg.CanUseStorageBufferClass then
begin
node^.FStorage:=StorageClass.StorageBuffer;
end else
begin
node^.FStorage:=StorageClass.Uniform;
end;
end;
node:=Next(node);
end;
end;
function AlignShift(addr:Pointer;alignment:PtrUInt):PtrUInt; inline;
begin
if (alignment>1) then
begin
Result:=(PtrUInt(addr) mod alignment);
end else
begin
Result:=0;
end;
end;
procedure TsrBufferList.AlignOffset(node:PsrBuffer;offset:PtrUint);
var
P:Pointer;
begin
P:=node^.key.pLayout^.GetData;
offset:=AlignShift(P,offset);
node^.align_offset:=offset;
node^.ShiftOffset(offset);
end;
procedure TsrBufferList.AlignOffset;
var
node:PsrBuffer;
begin
node:=First;
While (node<>nil) do
begin
Case node^.bType of
btStorageBuffer:
begin
AlignOffset(node,cfg.minStorageBufferOffsetAlignment);
end;
btUniformBuffer:
begin
AlignOffset(node,cfg.minUniformBufferOffsetAlignment);
end;
btPushConstant:
begin
node^.align_offset:=cfg.PushConstantsOffset;
node^.ShiftOffset(cfg.PushConstantsOffset);
end;
end;
node:=Next(node);
end;
end;
end.

626
spirv/srCFG.pas Normal file
View File

@ -0,0 +1,626 @@
unit srCFG;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
ps4_pssl,
srNodes,
srLabel;
type
PsrCFGBlock=^TsrCFGBlock;
TsrCFGBlockList=specialize TNodeList<PsrCFGBlock>;
TsrCFGBlock=object
pParent,pPrev,pNext:PsrCFGBlock;
FList:TsrCFGBlockList;
pBLabel:PsrLabel;
pELabel:PsrLabel;
bType:TsrBlockType;
term_id:Integer;
function IsEndOf(Adr:TSrcAdr):Boolean;
function IsBigOf(Adr:TSrcAdr):Boolean;
function IsContain(Adr:TSrcAdr):Boolean;
function FindBlock(Adr:TSrcAdr):PsrCFGBlock;
function DownBlock(Adr:TSrcAdr):PsrCFGBlock;
function UpBlock(Adr:TSrcAdr):PsrCFGBlock;
function FindUpLoop:PsrCFGBlock;
Procedure InsertBlockList(New,child:PsrCFGBlock);
function get_level:DWORD;
end;
PsrCodeBlock=^TsrCodeBlock;
TsrCodeBlock=object
pNext:PsrCodeBlock;
//----
Alloc:TfnAlloc;
Body:Pointer;
Size:ptruint;
FLabels:TsrLabels;
FTop:TsrCFGBlock;
Function FindLabel(Adr:TSrcAdr):PsrLabel;
Function FetchLabel(Adr:TSrcAdr):PsrLabel;
Function IsContain(P:Pointer):Boolean;
end;
TsrCFGParser=object
FCursor:TsrLCursor;
pCode:PsrCodeBlock;
pBlock:PsrCFGBlock;
FSPI:TSPI;
procedure _print_label(Adr:TSrcAdr);
procedure Print(base:Pointer);
function Parse(base:Pointer):Byte;
function NextParse:Byte;
Procedure Finalize;
function CheckBlock:Boolean;
Procedure CheckLabel;
Procedure CheckTerm;
function emit_SOP1:Boolean;
function emit_SOPP:Boolean;
Function NewBlock:PsrCFGBlock;
Procedure PushBlock(New:PsrCFGBlock);
function PopBlock:Boolean;
procedure emit_S_BRANCH;
end;
function parse_code_cfg(bType:TsrBlockType;base:Pointer;pCode:PsrCodeBlock):Byte;
implementation
function parse_code_cfg(bType:TsrBlockType;base:Pointer;pCode:PsrCodeBlock):Byte;
var
LParser:TsrCFGParser;
begin
pCode^.FTop.bType:=bType;
LParser:=Default(TsrCFGParser);
LParser.pCode:=pCode;
Result:=LParser.Parse(base);
//LParser.Print(base);
end;
function TsrCFGBlock.IsEndOf(Adr:TSrcAdr):Boolean;
begin
Result:=False;
if (pELabel<>nil) then
begin
Result:=(pELabel^.Adr.get_pc<=Adr.get_pc);
end;
end;
function TsrCFGBlock.IsBigOf(Adr:TSrcAdr):Boolean;
begin
Result:=False;
if (pELabel<>nil) then
begin
Result:=(pELabel^.Adr.get_pc<Adr.get_pc);
end;
end;
function TsrCFGBlock.IsContain(Adr:TSrcAdr):Boolean;
var
b,e:Boolean;
begin
b:=true;
if (pBLabel<>nil) then
begin
b:=(pBLabel^.Adr.get_pc<=Adr.get_pc);
end;
e:=true;
if (pELabel<>nil) then
begin
e:=(pELabel^.Adr.get_pc>Adr.get_pc);
end;
Result:=b and e;
end;
function TsrCFGBlock.FindBlock(Adr:TSrcAdr):PsrCFGBlock;
var
node:PsrCFGBlock;
begin
Result:=nil;
node:=FList.pHead;
While (node<>nil) do
begin
if node^.IsContain(Adr) then Exit(node);
node:=node^.pNext;
end;
end;
function TsrCFGBlock.DownBlock(Adr:TSrcAdr):PsrCFGBlock;
var
next:PsrCFGBlock;
begin
Result:=@Self;
repeat
next:=Result^.FindBlock(Adr);
if (next=nil) then Exit;
Result:=next;
until false;
end;
function TsrCFGBlock.UpBlock(Adr:TSrcAdr):PsrCFGBlock;
var
next:PsrCFGBlock;
begin
Result:=@Self;
While (Result^.IsEndOf(Adr)) do
begin
next:=Result^.pParent;
if (next=nil) then Exit;
Result:=next;
end;
end;
function TsrCFGBlock.FindUpLoop:PsrCFGBlock;
var
node:PsrCFGBlock;
begin
Result:=nil;
node:=@Self;
While (node<>nil) do
begin
if (node^.bType=btLoop) then Exit(node);
node:=node^.pParent;
end;
end;
Procedure TsrCFGBlock.InsertBlockList(New,child:PsrCFGBlock);
var
next:PsrCFGBlock;
begin
if (New=nil) then Exit;
New^.pParent:=@Self;
While (child<>nil) do
begin
Assert(child^.pParent=@Self);
next:=child^.pNext;
FList.Remove(child);
New^.FList.Push_tail(child);
child^.pParent:=New;
child:=next;
end;
FList.Push_tail(New);
end;
function TsrCFGBlock.get_level:DWORD;
var
node:PsrCFGBlock;
begin
node:=@Self;
Result:=0;
While (node<>nil) do
begin
Inc(Result);
node:=node^.pParent;
end;
end;
procedure TsrCFGParser._print_label(Adr:TSrcAdr);
var
pLabel:PsrLabel;
begin
pLabel:=pCode^.FindLabel(Adr);
if (pLabel<>nil) then
begin
Write('label_',HexStr(Adr.Offdw*4,4),': ;');
if (ltBranch in pLabel^.lType) then Write('ltBranch ');
if (ltUnknow in pLabel^.lType) then Write('ltUnknow ');
if (ltBegAdr in pLabel^.lType) then Write('ltBegAdr ');
if (ltEndAdr in pLabel^.lType) then Write('ltEndAdr ');
if (ltBegCond in pLabel^.lType) then Write('ltBegCond ');
if (ltEndCond in pLabel^.lType) then Write('ltEndCond ');
if (ltBegLoop in pLabel^.lType) then Write('ltBegLoop ');
if (ltEndLoop in pLabel^.lType) then Write('ltEndLoop ');
writeln;
end;
end;
procedure TsrCFGParser.Print(base:Pointer);
var
Adr:TSrcAdr;
level:DWORD;
i:Byte;
begin
FCursor.Init(base);
pBlock:=@pCode^.FTop;
repeat
Adr:=FCursor.Adr;
pBlock:=pBlock^.DownBlock(Adr);
level:=pBlock^.get_level;
_print_label(Adr);
Write(' ',HexStr(FCursor.OFFSET_DW*4,4));
Write(Space(level));
FSPI:=Default(TSPI);
i:=FCursor.Next(FSPI);
Case i of
0,1:begin
print_spi(FSPI);
Adr:=FCursor.Adr;
pBlock:=pBlock^.UpBlock(Adr);
end;
end;
until (i<>0);
_print_label(Adr);
end;
function TsrCFGParser.Parse(base:Pointer):Byte;
begin
if (pCode=nil) then Exit(4);
pCode^.Body:=base;
FCursor.Init(base);
pBlock:=@pCode^.FTop;
pCode^.FTop.pBLabel:=pCode^.FetchLabel(FCursor.Adr);
repeat
Result:=NextParse;
Case Result of
0:;
1:Break;
else
Break;
end;
until false;
end;
function TsrCFGParser.NextParse:Byte;
begin
FSPI:=Default(TSPI);
Result:=FCursor.Next(FSPI);
Case Result of
0,1:begin
Case FSPI.CMD.EN of
W_SOP1:if emit_SOP1 then Result:=1;
W_SOPP:if emit_SOPP then Result:=1;
end;
While (CheckBlock) do;
if (Result=0) then
begin
CheckTerm;
end;
CheckLabel;
if (Result=1) then
begin
Finalize;
end;
end;
end;
end;
Procedure TsrCFGParser.Finalize;
begin
pCode^.FTop.pELabel:=pCode^.FetchLabel(FCursor.Adr);
pCode^.Size:=FCursor.OFFSET_DW*4;
end;
function TsrCFGParser.CheckBlock:Boolean;
var
pLabel:PsrLabel;
begin
Result:=False;
if (pBlock=nil) then Exit;
Result:=pBlock^.IsEndOf(FCursor.Adr);
if Result then
begin
Case pBlock^.bType of
btAdr:
begin
pLabel:=pBlock^.pELabel;
pLabel^.AddType(ltEndAdr);
end;
btLoop:
begin
pLabel:=pBlock^.pELabel;
pLabel^.AddType(ltEndLoop);
end;
else;
end;
PopBlock;
end;
end;
Procedure TsrCFGParser.CheckLabel;
var
c_adr:TSrcAdr;
pLabel:array[0..1] of PsrLabel;
node,prev:PsrCFGBlock;
begin
c_adr:=FCursor.Adr;
pLabel[0]:=pCode^.FindLabel(c_adr);
if (pLabel[0]=nil) then Exit;
if not (pLabel[0]^.IsType(ltUnknow)) then Exit;
prev:=pBlock^.FList.pTail;
While (prev<>nil) do
begin
if prev^.IsContain(c_adr) then Break;
prev:=prev^.pPrev;
end;
if (prev=nil) then Exit;
if not (prev^.IsContain(c_adr)) then Exit;
pLabel[1]:=prev^.pBLabel;
pLabel[0]^.RemType(ltUnknow); //ltEndLoop later
pLabel[1]^.AddType(ltBegLoop);
node:=NewBlock;
node^.pBLabel:=pLabel[1];
node^.pELabel:=pLabel[0];
node^.bType:=btLoop;
pBlock^.InsertBlockList(node,prev);
end;
Procedure TsrCFGParser.CheckTerm;
var
c_adr:TSrcAdr;
pLabel:array[0..1] of PsrLabel;
node,prev:PsrCFGBlock;
begin
With pBlock^ do
begin
if (term_id>=0) then Exit;
term_id:=Abs(term_id);
end;
c_adr:=FCursor.Adr;
pLabel[0]:=pCode^.FetchLabel(c_adr);
pLabel[1]:=nil;
pLabel[0]^.RemType(ltUnknow);
pLabel[0]^.AddType(ltBegAdr);
prev:=pBlock^.pParent;
if (prev<>nil) then
begin
pLabel[1]:=prev^.pELabel;
end;
node:=NewBlock;
node^.pBLabel:=pLabel[0];
node^.pELabel:=pLabel[1];
node^.bType:=btAdr;
PushBlock(node);
end;
function TsrCFGParser.emit_SOP1:Boolean;
begin
Result:=False;
Case FSPI.SOP1.OP of
S_SETPC_B64:if (pBlock^.bType=btSetpc) then Result:=True;
end;
end;
function TsrCFGParser.emit_SOPP:Boolean;
var
c_adr:TSrcAdr;
pLabel:PsrLabel;
begin
Result:=False;
Case FSPI.SOPP.OP of
S_ENDPGM:
begin
if (pBlock^.bType=btAdr) then
begin
c_adr:=FCursor.Adr;
pLabel:=pCode^.FetchLabel(c_adr);
pLabel^.AddType(ltEndAdr);
pBlock^.pELabel:=pLabel;
PopBlock;
end;
With pBlock^ do
begin
term_id:=-(Abs(term_id)+1);
end;
end;
S_CBRANCH_SCC0 ,
S_CBRANCH_SCC1 ,
S_CBRANCH_VCCZ ,
S_CBRANCH_VCCNZ ,
S_CBRANCH_EXECZ ,
S_CBRANCH_EXECNZ,
S_BRANCH :emit_S_BRANCH;
else;
end;
end;
Function TsrCodeBlock.FindLabel(Adr:TSrcAdr):PsrLabel;
var
node:TsrLabel;
begin
Result:=nil;
node:=Default(TsrLabel);
node.Adr:=Adr;
Result:=FLabels.FNTree.Find(@node);
end;
Function TsrCodeBlock.FetchLabel(Adr:TSrcAdr):PsrLabel;
var
node:TsrLabel;
begin
Result:=nil;
node:=Default(TsrLabel);
node.Adr:=Adr;
Result:=FLabels.FNTree.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrLabel));
Result^.Adr:=Adr;
FLabels.FNTree.Insert(Result);
//FLabels.FList.Push_tail(Result);
end;
end;
Function TsrCodeBlock.IsContain(P:Pointer):Boolean;
begin
Result:=(Body<=P) and ((Body+Size)>P);
end;
Function TsrCFGParser.NewBlock:PsrCFGBlock;
begin
Result:=pCode^.Alloc(SizeOf(TsrCFGBlock));
end;
Procedure TsrCFGParser.PushBlock(New:PsrCFGBlock);
begin
if (New=nil) then Exit;
pBlock^.FList.Push_tail(New);
New^.pParent:=pBlock;
pBlock:=New;
end;
function TsrCFGParser.PopBlock:Boolean;
begin
Result:=False;
if (pBlock=nil) then Exit;
if (pBlock^.pParent=nil) then Exit;
pBlock:=pBlock^.pParent;
Result:=True;
end;
procedure TsrCFGParser.emit_S_BRANCH;
var
pLabel:array[0..1] of PsrLabel;
c_adr,b_adr,t_adr:TSrcAdr;
node,child,prev,parent:PsrCFGBlock;
begin
c_adr:=FCursor.Adr;
b_adr:=c_adr;
b_adr.Offdw:=get_branch_offset(FSPI);
pLabel[0]:=pCode^.FetchLabel(c_adr);
pLabel[1]:=pCode^.FetchLabel(b_adr);
pLabel[0]^.AddType(ltBranch);
if (SmallInt(FSPI.SOPP.SIMM)<0) then //up
begin
child:=nil;
parent:=pBlock;
repeat
if (parent^.pBLabel=nil) then
begin
t_adr:=c_adr;
t_adr.Offdw:=0;
end else
begin
t_adr:=parent^.pBLabel^.Adr;
end;
if (parent^.bType=btLoop) and (t_adr.get_pc=b_adr.get_pc) then //is exist loop
begin
pLabel[0]^.RemType(ltUnknow); //ltEndLoop later
if (parent^.pELabel=nil) then
begin
parent^.pELabel:=pLabel[0]; //set end
end else
begin
t_adr:=parent^.pELabel^.Adr;
if (t_adr.get_pc<c_adr.get_pc) then
begin
parent^.pELabel:=pLabel[0]; //update end of loop
end;
end;
Exit;
end;
if (t_adr.get_pc<=b_adr.get_pc) then Break;
child:=parent;
parent:=parent^.pParent;
until false;
if (child<>nil) then
repeat //up list
if child^.IsContain(t_adr) then Assert(false);
prev:=child^.pPrev;
if (prev=nil) then Break;
if (prev^.pELabel=nil) then
begin
t_adr:=c_adr;
end else
begin
t_adr:=prev^.pELabel^.Adr;
end;
if (t_adr.get_pc<=b_adr.get_pc) then Break;
child:=prev;
until false;
//new loop block
pLabel[0]^.RemType(ltUnknow); //ltEndLoop later
pLabel[1]^.AddType(ltBegLoop);
node:=NewBlock;
node^.pBLabel:=pLabel[1];
node^.pELabel:=pLabel[0];
node^.bType:=btLoop;
parent^.InsertBlockList(node,child);
end else //down
begin
if (pBlock^.pELabel<>nil) then
if (pBlock^.pELabel^.Adr.get_pc<b_adr.get_pc) then
begin
//push adr or loop end
if not pLabel[1]^.IsType(ltBegAdr) then
begin
pLabel[1]^.AddType(ltUnknow);
end;
Exit;
end;
pLabel[0]^.AddType(ltBegCond);
pLabel[1]^.AddType(ltEndCond);
node:=NewBlock;
node^.pBLabel:=pLabel[0];
node^.pELabel:=pLabel[1];
node^.bType:=btCond;
PushBlock(node);
end;
end;
end.

61
spirv/srCap.pas Normal file
View File

@ -0,0 +1,61 @@
unit srCap;
{$mode ObjFPC}{$H+}
interface
uses
srNodes;
type
PSpirvCap=^TSpirvCap;
TSpirvCap=object
pLeft,pRight:PSpirvCap;
//----
ID:DWORD;
function c(n1,n2:PSpirvCap):Integer; static;
end;
TsrCapList=object
type
TNodeFetch=specialize TNodeFetch<PSpirvCap,TSpirvCap>;
var
Alloc:TfnAlloc;
FNTree:TNodeFetch;
procedure Add(ID:DWORD);
Function First:PSpirvCap;
Function Next(node:PSpirvCap):PSpirvCap;
end;
implementation
function TSpirvCap.c(n1,n2:PSpirvCap):Integer;
begin
Result:=Integer(n1^.ID>n2^.ID)-Integer(n1^.ID<n2^.ID);
end;
procedure TsrCapList.Add(ID:DWORD);
var
fnode:TSpirvCap;
pnode:PSpirvCap;
begin
fnode:=Default(TSpirvCap);
fnode.ID:=ID;
if (FNTree.Find(@fnode)<>nil) then Exit;
pnode:=Alloc(SizeOf(TSpirvCap));
Move(fnode,pnode^,SizeOf(TSpirvCap));
FNTree.Insert(pnode);
end;
Function TsrCapList.First:PSpirvCap;
begin
Result:=FNTree.Min;
end;
Function TsrCapList.Next(node:PSpirvCap):PSpirvCap;
begin
Result:=FNTree.Next(node);
end;
end.

601
spirv/srConst.pas Normal file
View File

@ -0,0 +1,601 @@
unit srConst;
{$mode objfpc}{$H+}
interface
uses
srNodes,
srRefId,
srTypes,
half16;
type
PPsrConst=^PsrConst;
PsrConst=^TsrConst;
TsrConst=object
pPrev,pNext,pLeft,pRight:PsrConst;
//----
read_count:DWORD;
ID:TsrRefId; //post id
pType:PsrType;
key:packed record
dtype:TsrDataType;
count:DWORD;
end;
Data:QWORD;
function c(n1,n2:PsrConst):Integer; static;
Procedure mark_read;
Procedure mark_unread;
function GetCompItem(i:Byte):PsrConst; inline;
Procedure SetCompItem(i:Byte;p:PsrConst); inline;
function GetData:QWORD;
Function isZeroVal:Boolean; inline;
Function isBoolVal:Boolean;
Function AsBool:Boolean; inline;
Function AsUint:DWORD;
function AsInt:Integer; inline;
Function AsUint64:QWORD; inline;
Function AsInt64:Int64; inline;
function AsFloat32:Single;
function AsHalf16:THalf16;
function AsWord:Word;
function AsByte:Byte;
Procedure _mark_read_child;
Procedure _mark_unread_child;
Procedure Clear;
end;
TsrConstList=object
type
TNodeList=specialize TNodeList<PsrConst>;
TNodeFetch=specialize TNodeFetch<PsrConst,TsrConst>;
var
Alloc:TfnAlloc;
FList:TNodeList;
FNTree:TNodeFetch;
function _Fetch(node:PsrConst):PsrConst;
function Fetch(dtype:TsrDataType;value:QWORD):PsrConst;
function Fetchb(value:Boolean):PsrConst; inline;
function Fetchi(dtype:TsrDataType;value:Integer):PsrConst; inline;
Function Fetchf(dtype:TsrDataType;value:Single):PsrConst; inline;
function Fetch_ssrc9_const(SSRC:Word;d2:DWORD):PsrConst;
function Fetch_ssrc9_const(SSRC:Word;d2:DWORD;rtype:TsrDataType):PsrConst;
function Fetch_ssrc8_const(SSRC:Byte;d2:DWORD):PsrConst; inline;
function Fetch_ssrc8_const(SSRC:Byte;d2:DWORD;rtype:TsrDataType):PsrConst; inline;
function Fetch_vec(rtype:TsrDataType;count:Byte;nodes:PPsrConst):PsrConst;
function Bitcast(rtype:TsrDataType;old:PsrConst):PsrConst;
end;
function get_soffset_const_int(SSRC:Word):Integer;
function is_const_soffset(SSRC:Byte):Boolean; inline;
function is_const_ssrc8(SSRC:Byte):Boolean; inline;
function is_const_ssrc9(SSRC:Word):Boolean; inline;
function CompareConst(r1,r2:PsrConst):Boolean;
implementation
function TsrConst.c(n1,n2:PsrConst):Integer;
var
count:DWORD;
begin
Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrConst.key));
if (Result<>0) then Exit;
count:=n1^.key.count;
if (count=0) then
begin
Result:=Integer(n1^.Data>n2^.Data)-Integer(n1^.Data<n2^.Data);
end else
begin
Result:=ComparePtruint(@n1^.Data,@n2^.Data,count);
end;
end;
Procedure TsrConst.mark_read;
begin
Inc(read_count);
end;
Procedure TsrConst.mark_unread;
begin
Assert(read_count<>0);
if (read_count<>0) then Dec(read_count);
end;
function TsrConst.GetCompItem(i:Byte):PsrConst; inline;
begin
Result:=PPsrConst(@Data)[i];
end;
Procedure TsrConst.SetCompItem(i:Byte;p:PsrConst); inline;
begin
PPsrConst(@Data)[i]:=p;
end;
function TsrConst.GetData:QWORD;
begin
Result:=0;
case key.dtype of
dtVec2f:
begin
PSingle(@Result)[0]:=GetCompItem(0)^.AsFloat32;
PSingle(@Result)[1]:=GetCompItem(1)^.AsFloat32;
end;
dtVec2h:
begin
PHalf16(@Result)[0]:=GetCompItem(0)^.AsHalf16;
PHalf16(@Result)[1]:=GetCompItem(1)^.AsHalf16;
end;
dtVec4h:
begin
PHalf16(@Result)[0]:=GetCompItem(0)^.AsHalf16;
PHalf16(@Result)[1]:=GetCompItem(1)^.AsHalf16;
PHalf16(@Result)[2]:=GetCompItem(2)^.AsHalf16;
PHalf16(@Result)[3]:=GetCompItem(3)^.AsHalf16;
end;
dtStruct2u:
begin
PDWord(@Result)[0]:=GetCompItem(0)^.AsUint;
PDWord(@Result)[1]:=GetCompItem(1)^.AsUint;
end;
else
begin
Assert(key.count=0,'count<>0');
Result:=data;
end;
end;
end;
Function TsrConst.isZeroVal:Boolean;
begin
case key.dtype of
dtInt32 ,
dtUint32 ,
dtFloat32:Result:=(AsUint=0);
else
Result:=False;
end;
end;
Function TsrConst.isBoolVal:Boolean;
begin
if (key.count<>0) then Exit(False);
Case Data of
0,1:Result:=True;
else
Result:=False;
end;
end;
Function TsrConst.AsBool:Boolean; inline;
begin
Result:=PBoolean(@Data)^;
end;
Function TsrConst.AsUint:DWORD;
begin
Result:=PDWORD(@Data)^;
end;
function TsrConst.AsInt:Integer; inline;
begin
Result:=PInteger(@Data)^;
end;
Function TsrConst.AsUint64:QWORD; inline;
begin
Result:=Data;
end;
Function TsrConst.AsInt64:Int64; inline;
begin
Result:=Int64(Data);
end;
function TsrConst.AsFloat32:Single;
begin
Result:=PSingle(@Data)^;
end;
function TsrConst.AsHalf16:THalf16;
begin
Result:=PHalf16(@Data)^
end;
function TsrConst.AsWord:Word;
begin
Result:=PWord(@Data)^;
end;
function TsrConst.AsByte:Byte;
begin
Result:=PByte(@Data)^;
end;
Procedure TsrConst._mark_read_child;
var
i:DWORD;
begin
if (key.count<>0) then
For i:=0 to key.count-1 do
begin
GetCompItem(i)^.mark_read;
end;
end;
Procedure TsrConst._mark_unread_child;
var
i:DWORD;
begin
if (key.count<>0) then
For i:=0 to key.count-1 do
begin
GetCompItem(i)^.mark_unread;
end;
end;
Procedure TsrConst.Clear;
var
i:DWORD;
begin
if (key.count<>0) then
begin
For i:=0 to key.count-1 do
begin
GetCompItem(i)^.mark_unread;
end;
key.count:=0;
end;
end;
function TsrConstList._Fetch(node:PsrConst):PsrConst;
var
size:DWORD;
begin
Result:=FNTree.Find(node);
if (Result=nil) then
begin
size:=node^.key.count;
if (size=0) then
size:=SizeOf(TsrConst)
else
size:=SizeOf(TsrConst)-SizeOf(TsrConst.Data)+SizeOf(Pointer)*size;
Result:=Alloc(size);
Move(node^,Result^,size);
FNTree.Insert(Result);
FList.Push_tail(Result);
end else
begin
node^._mark_unread_child;
end;
end;
function TsrConstList.Fetch(dtype:TsrDataType;value:QWORD):PsrConst;
var
rec:record
node:TsrConst;
align:array[0..3] of Pointer;
end;
h:array[0..3] of PsrConst;
begin
Result:=nil;
rec.node:=Default(TsrConst);
value:=value and GetTypeHigh(dtype);
Case dtype of
dtUnknow,
dtBool,
dtFloat32,
dtHalf16,
dtInt32,
dtUint32,
dtInt64,
dtUint64:
begin
rec.node.key.dtype:=dtype;
rec.node.Data:=value;
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtStruct2u,
dtVec2u,
dtVec2i,
dtVec2f:
begin
rec.node.key.dtype:=GetVecChild(dtype);
rec.node.Data:=PDWORD(@value)[0];
h[0]:=_Fetch(@rec.node);
h[0]^.mark_read;
rec.node.Data:=PDWORD(@value)[1];
h[1]:=_Fetch(@rec.node);
h[1]^.mark_read;
rec.node.key.dtype:=dtype;
rec.node.key.count:=2;
rec.node.SetCompItem(0,h[0]);
rec.node.SetCompItem(1,h[1]);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtVec2h:
begin
rec.node.key.dtype:=dtHalf16;
rec.node.Data:=PWORD(@value)[0];
h[0]:=_Fetch(@rec.node);
h[0]^.mark_read;
rec.node.Data:=PWORD(@value)[1];
h[1]:=_Fetch(@rec.node);
h[1]^.mark_read;
rec.node.key.dtype:=dtVec2h;
rec.node.key.count:=2;
rec.node.SetCompItem(0,h[0]);
rec.node.SetCompItem(1,h[1]);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtVec4h:
begin
rec.node.key.dtype:=dtHalf16;
rec.node.Data:=PWORD(@value)[0];
h[0]:=_Fetch(@rec.node);
h[0]^.mark_read;
rec.node.Data:=PWORD(@value)[1];
h[1]:=_Fetch(@rec.node);
h[1]^.mark_read;
rec.node.Data:=PWORD(@value)[2];
h[2]:=_Fetch(@rec.node);
h[2]^.mark_read;
rec.node.Data:=PWORD(@value)[3];
h[3]:=_Fetch(@rec.node);
h[3]^.mark_read;
rec.node.key.dtype:=dtVec4h;
rec.node.key.count:=4;
rec.node.SetCompItem(0,h[0]);
rec.node.SetCompItem(1,h[1]);
rec.node.SetCompItem(2,h[2]);
rec.node.SetCompItem(3,h[3]);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
else
Assert(false);
end;
end;
function TsrConstList.Fetchb(value:Boolean):PsrConst; inline;
begin
Result:=Fetch(dtBool,QWORD(value));
end;
function TsrConstList.Fetchi(dtype:TsrDataType;value:Integer):PsrConst; inline;
begin
Result:=Fetch(dtype,PDWORD(@value)^);
end;
Function TsrConstList.Fetchf(dtype:TsrDataType;value:Single):PsrConst; inline;
begin
Result:=Fetch(dtype,PDWORD(@value)^);
end;
function TsrConstList.Fetch_ssrc9_const(SSRC:Word;d2:DWORD):PsrConst;
begin
Case SSRC of
128:Result:=Fetch(dtUnknow,0);
129..192:Result:=Fetch(dtUint32,SSRC-128);
193..208:Result:=Fetchi(dtInt32,-(SSRC-192));
240:Result:=Fetchf(dtFloat32, 0.5);
241:Result:=Fetchf(dtFloat32,-0.5);
242:Result:=Fetchf(dtFloat32, 1.0);
243:Result:=Fetchf(dtFloat32,-1.0);
244:Result:=Fetchf(dtFloat32, 2.0);
245:Result:=Fetchf(dtFloat32,-2.0);
246:Result:=Fetchf(dtFloat32, 4.0);
247:Result:=Fetchf(dtFloat32,-4.0);
255:Result:=Fetch(dtUnknow,d2);
else
Result:=nil;
end;
end;
function TsrConstList.Fetch_ssrc9_const(SSRC:Word;d2:DWORD;rtype:TsrDataType):PsrConst;
begin
Case SSRC of
128:Result:=Fetch(rtype,0);
129..192:
begin
if CompareType(dtUint32,rtype) then
begin
Result:=Fetch(dtUint32,SSRC-128);
end else
begin
Result:=Fetch(rtype,SSRC-128);
end;
end;
193..208:
begin
if CompareType(dtInt32,rtype) then
begin
Result:=Fetchi(dtInt32,-(SSRC-192));
end else
begin
Result:=Fetchi(rtype,-(SSRC-192));
end;
end;
240:Result:=Fetchf(rtype, 0.5);
241:Result:=Fetchf(rtype,-0.5);
242:Result:=Fetchf(rtype, 1.0);
243:Result:=Fetchf(rtype,-1.0);
244:Result:=Fetchf(rtype, 2.0);
245:Result:=Fetchf(rtype,-2.0);
246:Result:=Fetchf(rtype, 4.0);
247:Result:=Fetchf(rtype,-4.0);
255:Result:=Fetch(rtype,d2);
else
Result:=nil;
end;
end;
function TsrConstList.Fetch_ssrc8_const(SSRC:Byte;d2:DWORD):PsrConst; inline;
begin
Result:=Fetch_ssrc9_const(SSRC,d2);
end;
function TsrConstList.Fetch_ssrc8_const(SSRC:Byte;d2:DWORD;rtype:TsrDataType):PsrConst; inline;
begin
Result:=Fetch_ssrc9_const(SSRC,d2,rtype);
end;
function TsrConstList.Fetch_vec(rtype:TsrDataType;count:Byte;nodes:PPsrConst):PsrConst;
var
rec:record
node:TsrConst;
align:array[0..3] of Pointer;
end;
h:PsrConst;
i:Byte;
begin
Assert(count<>0);
Assert(count<=4);
rec.node:=Default(TsrConst);
rec.node.key.dtype:=rtype;
rec.node.key.count:=count;
For i:=0 to count-1 do
begin
h:=nodes[i];
h^.mark_read;
rec.node.SetCompItem(i,h);
end;
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrConstList.Bitcast(rtype:TsrDataType;old:PsrConst):PsrConst;
var
data:qword;
begin
Result:=nil;
if (old=nil) then Exit;
if (rtype=dtUnknow) or (rtype=old^.key.dtype) then
begin
old^.mark_read;
Exit(old);
end;
if (old^.key.dtype=dtUnknow) then
begin
data:=old^.Data;
Result:=Fetch(rtype,data);
Exit;
end;
if TryBitcastType(rtype,old^.key.dtype) then
begin
data:=old^.GetData;
Result:=Fetch(rtype,data);
end else
begin
Assert(false,'const bitcast');
end;
end;
function get_soffset_const_int(SSRC:Word):Integer;
type
TRec=packed record
Case byte of
0:(i:Integer);
1:(s:Single);
end;
begin
Case SSRC of
128:Result:=0;
129..192:Result:=SSRC-128;
193..208:Result:=-(SSRC-192);
240:TRec(Result).s:= 0.5;
241:TRec(Result).s:=-0.5;
242:TRec(Result).s:= 1.0;
243:TRec(Result).s:=-1.0;
244:TRec(Result).s:= 2.0;
245:TRec(Result).s:=-2.0;
246:TRec(Result).s:= 4.0;
247:TRec(Result).s:=-4.0;
else
Result:=0;
end;
end;
function is_const_soffset(SSRC:Byte):Boolean; inline;
begin
Case SSRC of
128..192,
193..208,
240..247:Result:=True;
else
Result:=False;
end;
end;
function is_const_ssrc8(SSRC:Byte):Boolean; inline;
begin
Case SSRC of
128..192,
193..208,
240..247,
255:Result:=True;
else
Result:=False;
end;
end;
function is_const_ssrc9(SSRC:Word):Boolean; inline;
begin
Case SSRC of
128..192,
193..208,
240..247,
255:Result:=True;
else
Result:=False;
end;
end;
function CompareConstCount(buf1,buf2:PPsrConst;count:PtrUint):Boolean;
begin
Result:=true;
While (count<>0) do
begin
Result:=CompareConst(buf1^,buf2^);
if not Result then Exit;
Inc(buf1);
Inc(buf2);
Dec(count);
end;
end;
function CompareConst(r1,r2:PsrConst):Boolean;
begin
Result:=false;
if (r1<>nil) and (r2<>nil) then
begin
Result:=(r1=r2);
if Result then Exit;
if CompareType(r1^.key.dtype,r2^.key.dtype) and (r1^.key.count=r2^.key.count) then
begin
if (r1^.key.count=0) then
begin
Result:=(r1^.Data=r2^.Data);
end else
begin
Result:=CompareConstCount(@r1^.Data,@r2^.Data,r1^.key.count);
end;
end;
end;
end;
end.

80
spirv/srDecorate.pas Normal file
View File

@ -0,0 +1,80 @@
unit srDecorate;
{$mode ObjFPC}{$H+}
interface
uses
spirv,
srNodes,
srOp;
type
PsrDecorateList=^TsrDecorateList;
TsrDecorateList=object(TsrOpBlockSimple)
FDescriptorSet:DWORD;
procedure emit_decorate(ntype:TsrNodeType;Data:Pointer;dec_id,param:DWORD);
procedure emit_member_decorate(ntype:TsrNodeType;Data:Pointer;index,offset:DWORD);
end;
PsrDebugInfoList=^TsrDebugInfoList;
TsrDebugInfoList=object(TsrOpBlockSimple)
procedure emit_source_extension(const n:RawByteString);
procedure emit_name(ntype:TsrNodeType;Data:Pointer;const n:RawByteString);
end;
implementation
procedure TsrDecorateList.emit_decorate(ntype:TsrNodeType;Data:Pointer;dec_id,param:DWORD);
var
node:PSpirvOp;
begin
node:=AddSpirvOp(Op.OpDecorate);
node^.AddParam(ntype,Data);
node^.AddLiteral(dec_id,Decoration.GetStr(dec_id));
Case dec_id of
Decoration.BuiltIn:
node^.AddLiteral(param,BuiltIn.GetStr(param));
Decoration.ArrayStride,
Decoration.MatrixStride,
Decoration.Location,
Decoration.Index,
Decoration.Binding,
Decoration.DescriptorSet:
node^.AddLiteral(param);
else;
end;
end;
procedure TsrDecorateList.emit_member_decorate(ntype:TsrNodeType;Data:Pointer;index,offset:DWORD);
var
node:PSpirvOp;
begin
node:=AddSpirvOp(Op.OpMemberDecorate);
node^.AddParam(ntype,Data);
node^.AddLiteral(index);
node^.AddLiteral(Decoration.Offset,Decoration.GetStr(Decoration.Offset));
node^.AddLiteral(offset);
end;
procedure TsrDebugInfoList.emit_source_extension(const n:RawByteString);
var
node:PSpirvOp;
begin
node:=AddSpirvOp(Op.OpSourceExtension);
node^.AddString(n);
end;
procedure TsrDebugInfoList.emit_name(ntype:TsrNodeType;Data:Pointer;const n:RawByteString);
var
node:PSpirvOp;
begin
node:=AddSpirvOp(Op.OpName);
node^.AddParam(ntype,Data);
node^.AddString(n);
end;
end.

182
spirv/srFragLayout.pas Normal file
View File

@ -0,0 +1,182 @@
unit srFragLayout;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
spirv,
srNodes,
srReg,
srOp,
srLayout,
srVariable,
srInput,
srDecorate;
type
//itPerspSample, //Sample
//itPerspCenter,
//itPerspCentroid, //Centroid
//itLinearSample, //NoPerspective Sample
//itLinearCenter, //NoPerspective
//itLinearCentroid, //NoPerspective Centroid
PsrFragLayout=^TsrFragLayout;
TsrFragLayout=object(TsrDescriptor)
pLeft,pRight:PsrFragLayout;
//----
itype:TpsslInputType;
pReg:PsrRegNode;
function c(n1,n2:PsrFragLayout):Integer; static;
function GetName:RawByteString;
end;
TsrFragLayoutList=object
type
TNodeFetch=specialize TNodeFetch<PsrFragLayout,TsrFragLayout>;
var
Alloc:TfnAlloc;
FNTree:TNodeFetch;
procedure Init(cb:TfnAlloc);
function Fetch(itype:TpsslInputType;location:DWORD):PsrFragLayout;
Function First:PsrFragLayout;
Function Next(node:PsrFragLayout):PsrFragLayout;
procedure AllocBinding(Decorates:PsrDecorateList);
procedure AllocEntryPoint(EntryPoint:PSpirvOp);
end;
implementation
function TsrFragLayout.c(n1,n2:PsrFragLayout):Integer;
begin
//first itype
Result:=Integer(n1^.itype>n2^.itype)-Integer(n1^.itype<n2^.itype);
//second location
Result:=Integer(n1^.FBinding>n2^.FBinding)-Integer(n1^.FBinding<n2^.FBinding);
//Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrFragLayout.key));
end;
function TsrFragLayout.GetName:RawByteString;
begin
Case itype of
itPerspSample:
Result:='itPSample'+IntToStr(FBinding);
itPerspCenter:
Result:='itParam'+IntToStr(FBinding);
itPerspCentroid:
Result:='itPCentroid'+IntToStr(FBinding);
itLinearSample:
Result:='itLSample'+IntToStr(FBinding);
itLinearCenter:
Result:='itLCenter'+IntToStr(FBinding);
itLinearCentroid:
Result:='itLCentroid'+IntToStr(FBinding);
else
Result:='';
end;
end;
procedure TsrFragLayoutList.Init(cb:TfnAlloc);
begin
Alloc:=cb;
end;
function TsrFragLayoutList.Fetch(itype:TpsslInputType;location:DWORD):PsrFragLayout;
var
node:TsrFragLayout;
begin
node:=Default(TsrFragLayout);
node.itype:=itype;
node.FStorage:=StorageClass.Input;
node.FBinding:=location;
Result:=FNTree.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrFragLayout));
Move(node,Result^,SizeOf(TsrFragLayout));
FNTree.Insert(Result);
end;
end;
Function TsrFragLayoutList.First:PsrFragLayout;
begin
Result:=FNTree.Min;
end;
Function TsrFragLayoutList.Next(node:PsrFragLayout):PsrFragLayout;
begin
Result:=FNTree.Next(node);
end;
procedure TsrFragLayoutList.AllocBinding(Decorates:PsrDecorateList);
var
node:PsrFragLayout;
pVar:PsrVariable;
begin
if (Decorates=nil) then Exit;
//interpolate param
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.Location,node^.FBinding);
case node^.itype of
itPerspSample: //Sample
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.Sample,0);
end;
itPerspCenter:; //default
itPerspCentroid: //Centroid
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.Centroid,0);
end;
itLinearSample: //NoPerspective Sample
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.NoPerspective,0);
Decorates^.emit_decorate(ntVar,pVar,Decoration.Sample,0);
end;
itLinearCenter: //NoPerspective
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.NoPerspective,0);
end;
itLinearCentroid: //NoPerspective Centroid
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.NoPerspective,0);
Decorates^.emit_decorate(ntVar,pVar,Decoration.Centroid,0);
end;
else
Assert(false,'AllocBinding');
end;
end;
node:=Next(node);
end;
end;
procedure TsrFragLayoutList.AllocEntryPoint(EntryPoint:PSpirvOp);
var
node:PsrFragLayout;
pVar:PsrVariable;
begin
if (EntryPoint=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
EntryPoint^.AddParam(ntVar,pVar);
end;
node:=Next(node);
end;
end;
end.

200
spirv/srInput.pas Normal file
View File

@ -0,0 +1,200 @@
unit srInput;
{$mode ObjFPC}{$H+}
interface
uses
typinfo,
sysutils,
spirv,
srNodes,
srReg,
srOp,
srLayout,
srVariable,
srDecorate;
type
TpsslInputType=(
itUnknow,
itVsState,
itWriteIndex,
itOffset,
itWaveId,
itScratch,
itVIndex,
itVInstance,
itPsState,
itWaveCnt,
itPerspSample,
itPerspCenter,
itPerspCentroid,
itPerspW,
itLinearSample,
itLinearCenter,
itLinearCentroid,
itFloatPos,
itFrontFace,
itAncillary,
itSampleCoverage,
itPosFixed,
itTgid,
itTgSize,
itThreadId
);
PsrInput=^TsrInput;
TsrInput=object(TsrDescriptor)
pLeft,pRight:PsrInput;
//----
key:packed record
itype:TpsslInputType;
typeid:Byte;
end;
pReg:PsrRegNode;
function c(n1,n2:PsrInput):Integer; static;
function GetName:RawByteString;
end;
TsrInputList=object
type
TNodeFetch=specialize TNodeFetch<PsrInput,TsrInput>;
var
Alloc:TfnAlloc;
FNTree:TNodeFetch;
procedure Init(cb:TfnAlloc);
function Search(itype:TpsslInputType;id:Byte=0):PsrInput;
function Fetch(itype:TpsslInputType;id:Byte=0):PsrInput;
Function First:PsrInput;
Function Next(node:PsrInput):PsrInput;
procedure AllocBinding(Decorates:PsrDecorateList);
procedure AllocEntryPoint(EntryPoint:PSpirvOp);
end;
implementation
function TsrInput.c(n1,n2:PsrInput):Integer;
begin
Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrInput.key));
end;
function TsrInput.GetName:RawByteString;
begin
Result:=GetEnumName(TypeInfo(TpsslInputType),ord(key.itype))+IntToStr(key.typeid);
end;
procedure TsrInputList.Init(cb:TfnAlloc);
begin
Alloc:=cb;
end;
function TsrInputList.Search(itype:TpsslInputType;id:Byte=0):PsrInput;
var
node:TsrInput;
begin
node:=Default(TsrInput);
node.key.itype:=itype;
node.key.typeid:=id;
Result:=FNTree.Find(@node);
end;
function TsrInputList.Fetch(itype:TpsslInputType;id:Byte=0):PsrInput;
var
node:TsrInput;
begin
node:=Default(TsrInput);
node.key.itype:=itype;
node.key.typeid:=id;
node.FStorage:=StorageClass.Input;
node.FBinding:=-1;
Result:=FNTree.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrInput));
Move(node,Result^,SizeOf(TsrInput));
FNTree.Insert(Result);
end;
end;
Function TsrInputList.First:PsrInput;
begin
Result:=FNTree.Min;
end;
Function TsrInputList.Next(node:PsrInput):PsrInput;
begin
Result:=FNTree.Next(node);
end;
procedure TsrInputList.AllocBinding(Decorates:PsrDecorateList);
var
node:PsrInput;
pVar:PsrVariable;
begin
if (Decorates=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
Case node^.key.itype of
itFloatPos:
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.BuiltIn,BuiltIn.FragCoord);
end;
itTgid:
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.BuiltIn,BuiltIn.WorkgroupId);
end;
itThreadId:
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.BuiltIn,BuiltIn.LocalInvocationID);
end;
itVIndex:
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.BuiltIn,BuiltIn.VertexIndex);
end;
else
Assert(false,'AllocBinding');
end;
end;
node:=Next(node);
end;
end;
procedure TsrInputList.AllocEntryPoint(EntryPoint:PSpirvOp);
var
node:PsrInput;
pVar:PsrVariable;
begin
if (EntryPoint=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
EntryPoint^.AddParam(ntVar,pVar);
end;
node:=Next(node);
end;
end;
end.

111
spirv/srLabel.pas Normal file
View File

@ -0,0 +1,111 @@
unit srLabel;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
ps4_pssl,
srNodes;
type
TSrcAdr=object
pBody:PDWORD;
Offdw:ptrint;
function get_pc:PDWORD;
end;
TsrLCursor=object(TShaderParser)
private
function get_src_adr:TSrcAdr;
Procedure set_src_adr(src:TSrcAdr);
public
procedure Init(base:Pointer);
property Adr:TSrcAdr read get_src_adr write set_src_adr;
end;
TsrLabelType=(ltBranch,ltUnknow,ltBegAdr,ltEndAdr,ltBegCond,ltEndCond,ltBegLoop,ltEndLoop);
TsrSetLabelType=Set of TsrLabelType;
TsrBlockType=(btMain,btAdr,btSetpc,btCond,btLoop,btOther);
PsrLabel=^TsrLabel;
TsrLabel=object
pLeft,pRight:PsrLabel;
//----
Adr:TSrcAdr;
lType:TsrSetLabelType;
function c(n1,n2:PsrLabel):Integer; static;
Procedure AddType(t:TsrLabelType);
Procedure RemType(t:TsrLabelType);
function IsType(t:TsrLabelType):Boolean;
end;
TsrLabels=object
type
TNodeFetch=specialize TNodeFetch<PsrLabel,TsrLabel>;
var
FNTree:TNodeFetch;
end;
function get_branch_offset(var FSPI:TSPI):ptrint;
implementation
function TSrcAdr.get_pc:PDWORD;
begin
Result:=pBody+Offdw;
end;
procedure TsrLCursor.Init(base:Pointer);
begin
Body :=base;
OFFSET_DW:=0;
end;
function TsrLCursor.get_src_adr:TSrcAdr;
begin
Result:=Default(TSrcAdr);
Result.pBody:=Body;
Result.Offdw:=OFFSET_DW;
end;
Procedure TsrLCursor.set_src_adr(src:TSrcAdr);
begin
Body :=src.pBody;
OFFSET_DW:=src.Offdw;
end;
function TsrLabel.c(n1,n2:PsrLabel):Integer;
var
p1,p2:Pointer;
begin
p1:=n1^.Adr.get_pc;
p2:=n2^.Adr.get_pc;
Result:=Integer(p1>p2)-Integer(p1<p2);
end;
Procedure TsrLabel.AddType(t:TsrLabelType);
begin
lType:=lType+[t];
end;
Procedure TsrLabel.RemType(t:TsrLabelType);
begin
lType:=lType-[t];
end;
function TsrLabel.IsType(t:TsrLabelType):Boolean;
begin
Result:=t in lType;
end;
function get_branch_offset(var FSPI:TSPI):ptrint;
begin
Result:=FSPI.OFFSET_DW+Smallint(FSPI.SOPP.SIMM)+1;
end;
end.

515
spirv/srLayout.pas Normal file
View File

@ -0,0 +1,515 @@
unit srLayout;
{$mode ObjFPC}{$H+}
interface
uses
ps4_shader,
srNodes,
srParser,
srCFG,
srTypes,
srReg,
srVariable,
srRefId,
srDecorate;
type
TsrResourceType=(
rtBufPtr2,
rtFunPtr2,
rtVSharp4,
rtSSharp4,
rtTSharp4,
rtTSharp8
);
type
PsrDataLayout=^TsrDataLayout;
PsrChainExt=^TsrChainExt;
TsrChainExt=object
pIndex:PsrRegNode;
stride:PtrUint;
function c(n1,n2:PsrChainExt):Integer; static;
end;
PsrChain=^TsrChain;
TsrChain=object
pLeft,pRight:PsrChain;
//----
read_count:DWORD;
write_count:DWORD;
parent:PsrDataLayout;
key:packed record
ext:TsrChainExt;
size,offset:PtrUint;
end;
rSlot:TsrRegSlot;
pField:Pointer;
pLine:Pointer;
ID:TsrRefId; //post id
function c(n1,n2:PsrChain):Integer; static;
Procedure mark_read;
Procedure mark_unread;
Procedure mark_write;
Procedure SetRegType(rtype:TsrDataType);
function GetRegType:TsrDataType;
function IsUsed:Boolean;
end;
TsrChains=array[0..7] of PsrChain;
//----
TsrDataLayout=object
type
TChainFetch=specialize TNodeFetch<PsrChain,TsrChain>;
var
pLeft,pRight:PsrDataLayout;
//----
key:packed record
parent:PsrDataLayout;
offset:PtrUint;
rtype:TsrResourceType;
end;
pData:Pointer;
FID:Integer;
Alloc:TfnAlloc;
FList:TChainFetch;
function c(n1,n2:PsrDataLayout):Integer; static;
function Fetch(o,s:PtrUint;ext:PsrChainExt):PsrChain;
Function First:PsrChain;
Function Last:PsrChain;
Function Next(node:PsrChain):PsrChain;
Function Prev(node:PsrChain):PsrChain;
function GetData:Pointer;
function GetStride:PtrUint;
function GetTypeChar:Char;
function GetString:RawByteString;
function GetFuncString(LEN:DWORD):RawByteString;
end;
TsrDataLayoutList=object
type
TNodeFetch=specialize TNodeFetch<PsrDataLayout,TsrDataLayout>;
var
FTop:TsrDataLayout;
FNTree:TNodeFetch;
procedure Init(cb:TfnAlloc);
procedure SetUserData(pData:Pointer);
function Fetch(p:PsrDataLayout;o:PtrUint;t:TsrResourceType):PsrDataLayout;
Function First:PsrDataLayout;
Function Next(node:PsrDataLayout):PsrDataLayout;
function Grouping(const chain:TsrChains;rtype:TsrResourceType):PsrDataLayout;
Procedure AllocID;
procedure AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
procedure AllocFuncExt(FDebugInfo:PsrDebugInfoList;var Heap:TsrCodeHeap);
end;
//----
PsrDescriptor=^TsrDescriptor;
TsrDescriptor=object
pVar:PsrVariable;
FStorage:DWORD;
FBinding:Integer;
end;
function is_consistents(const chains:TsrChains;count:Byte):Boolean;
function is_no_index_chains(const chains:TsrChains;count:Byte):Boolean;
function is_userdata_chains(const chains:TsrChains;count:Byte):Boolean;
function GetResourceSizeDw(r:TsrResourceType):Byte;
implementation
function TsrDataLayout.c(n1,n2:PsrDataLayout):Integer;
begin
//first parent
Result:=Integer(n1^.key.parent>n2^.key.parent)-Integer(n1^.key.parent<n2^.key.parent);
if (Result<>0) then Exit;
//second offset
Result:=Integer(n1^.key.offset>n2^.key.offset)-Integer(n1^.key.offset<n2^.key.offset);
if (Result<>0) then Exit;
//third rtype
Result:=Integer(n1^.key.rtype>n2^.key.rtype)-Integer(n1^.key.rtype<n2^.key.rtype);
end;
function TsrDataLayout.Fetch(o,s:PtrUint;ext:PsrChainExt):PsrChain;
var
node:TsrChain;
begin
node:=Default(TsrChain);
node.key.offset:=o;
node.key.size :=s;
if (ext<>nil) then
begin
node.key.ext:=ext^;
end;
Result:=FList.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrChain));
Result^.parent:=@Self;
Result^.key.offset:=o;
Result^.key.size :=s;
if (ext<>nil) then
begin
Result^.key.ext:=ext^;
end;
Result^.rSlot.Init(Alloc,'CHAIN');
FList.Insert(Result);
end else
begin
if (ext<>nil) then
if (ext^.pIndex<>nil) then
begin
ext^.pIndex^.mark_unread;
end;
end;
end;
Function TsrDataLayout.First:PsrChain;
begin
Result:=FList.Min;
end;
Function TsrDataLayout.Last:PsrChain;
begin
Result:=FList.Max;
end;
Function TsrDataLayout.Next(node:PsrChain):PsrChain;
begin
Result:=FList.Next(node);
end;
Function TsrDataLayout.Prev(node:PsrChain):PsrChain;
begin
Result:=FList.Prev(node);
end;
function TsrDataLayout.GetData:Pointer;
begin
Result:=nil;
if (pData<>nil) then
Case key.rtype of
rtBufPtr2,
rtFunPtr2:Result:=pData;
rtVSharp4:Result:={%H-}Pointer(PVSharpResource4(pData)^.base);
rtTSharp4,
rtTSharp8:Result:={%H-}Pointer(PTSharpResource4(pData)^.base shl 8);
else;
end;
end;
function TsrDataLayout.GetStride:PtrUint;
begin
Result:=0;
if (pData<>nil) then
Case key.rtype of
rtBufPtr2:Result:=4;
rtVSharp4:Result:=PVSharpResource4(pData)^.stride;
else;
end;
end;
function TsrDataLayout.GetTypeChar:Char;
begin
Result:=#0;
case key.rtype of
rtBufPtr2:Result:='B';
rtFunPtr2:Result:='F';
rtVSharp4:Result:='V';
rtSSharp4:Result:='S';
rtTSharp4:Result:='t';
rtTSharp8:Result:='T';
end;
end;
function TsrDataLayout.GetString:RawByteString;
var
PID:DWORD;
begin
PID:=0;
if (key.parent<>nil) then
begin
PID:=key.parent^.FID;
end;
Result:='#'+GetTypeChar+
';PID='+HexStr(PID,8)+
';OFS='+HexStr(key.offset,8);
end;
function TsrDataLayout.GetFuncString(LEN:DWORD):RawByteString;
begin
Result:='FF'+
';PID='+HexStr(FID,8)+
';LEN='+HexStr(LEN,8);
end;
procedure TsrDataLayoutList.Init(cb:TfnAlloc);
begin
FTop.Alloc:=cb;
FNTree.Insert(@FTop);
end;
procedure TsrDataLayoutList.SetUserData(pData:Pointer);
begin
FTop.pData:=pData;
end;
function TsrDataLayoutList.Fetch(p:PsrDataLayout;o:PtrUint;t:TsrResourceType):PsrDataLayout;
var
node:TsrDataLayout;
pData:Pointer;
begin
node:=Default(TsrDataLayout);
node.Alloc:=FTop.Alloc;
node.key.parent:=p;
node.key.offset:=o;
node.key.rtype :=t;
Result:=FNTree.Find(@node);
if (Result=nil) then
begin
Result:=FTop.Alloc(SizeOf(TsrDataLayout));
Move(node,Result^,SizeOf(TsrDataLayout));
FNTree.Insert(Result);
Result^.FID:=-1;
if (p<>nil) then
begin
pData:=p^.GetData;
if (pData<>nil) then
case t of
rtBufPtr2,
rtFunPtr2:Result^.pData:={%H-}Pointer(PPtrUint(pData+o)^ and (not 3));
rtVSharp4,
rtSSharp4,
rtTSharp4,
rtTSharp8:Result^.pData:=pData+o;
end;
end;
end;
end;
Function TsrDataLayoutList.First:PsrDataLayout;
begin
Result:=FNTree.Min;
end;
Function TsrDataLayoutList.Next(node:PsrDataLayout):PsrDataLayout;
begin
Result:=FNTree.Next(node);
end;
function GetResourceSizeDw(r:TsrResourceType):Byte;
begin
Result:=0;
Case r of
rtBufPtr2:Result:=2;
rtFunPtr2:Result:=2;
rtVSharp4:Result:=4;
rtSSharp4:Result:=4;
rtTSharp4:Result:=4;
rtTSharp8:Result:=8;
end;
end;
function TsrDataLayoutList.Grouping(const chain:TsrChains;rtype:TsrResourceType):PsrDataLayout;
begin
Result:=nil;
if not is_consistents(chain,GetResourceSizeDw(rtype)) then
begin
Assert(False,'inconsistent resources not supported');
end;
if not is_no_index_chains(chain,GetResourceSizeDw(rtype)) then
begin
Assert(False,'indexed chain not support');
end;
Result:=Fetch(chain[0]^.parent,chain[0]^.key.offset,rtype);
end;
Procedure TsrDataLayoutList.AllocID;
var
node:PsrDataLayout;
FID:Integer;
begin
FID:=1;
node:=First;
While (node<>nil) do
begin
if (node^.FID=-1) then
begin
node^.FID:=FID;
Inc(FID);
end;
node:=Next(node);
end;
end;
procedure TsrDataLayoutList.AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
var
node:PsrDataLayout;
begin
if (FDebugInfo=nil) then Exit;
node:=First;
While (node<>nil) do
begin
FDebugInfo^.emit_source_extension(node^.GetString);
node:=Next(node);
end;
end;
procedure TsrDataLayoutList.AllocFuncExt(FDebugInfo:PsrDebugInfoList;var Heap:TsrCodeHeap);
var
node:PsrDataLayout;
block:PsrCodeBlock;
begin
node:=First;
While (node<>nil) do
begin
if (node^.key.rtype=rtFunPtr2) then
begin
block:=Heap.FindByPtr(node^.pData);
if (block<>nil) then
begin
FDebugInfo^.emit_source_extension(node^.GetFuncString(block^.Size));
end;
end;
node:=Next(node);
end;
end;
function TsrChainExt.c(n1,n2:PsrChainExt):Integer;
begin
//first pIndex forward
Result:=Integer(n1^.pIndex>n2^.pIndex)-Integer(n1^.pIndex<n2^.pIndex);
if (Result<>0) then Exit;
//second stride forward
Result:=Integer(n1^.stride>n2^.stride)-Integer(n1^.stride<n2^.stride);
end;
function TsrChain.c(n1,n2:PsrChain):Integer;
begin
//first ext
Result:=TsrChainExt.c(@n1^.key.ext,@n2^.key.ext);
if (Result<>0) then Exit;
//second size backward
Result:=Integer(n1^.key.size<n2^.key.size)-Integer(n1^.key.size>n2^.key.size);
if (Result<>0) then Exit;
//third offset forward
Result:=Integer(n1^.key.offset>n2^.key.offset)-Integer(n1^.key.offset<n2^.key.offset);
end;
Procedure TsrChain.mark_read;
begin
Inc(read_count);
end;
Procedure TsrChain.mark_unread;
begin
if (read_count<>0) then Dec(read_count);
end;
Procedure TsrChain.mark_write;
begin
Inc(write_count);
end;
Procedure TsrChain.SetRegType(rtype:TsrDataType);
var
node:PsrRegNode;
begin
node:=rSlot.pStory.pHead;
While (node<>nil) do
begin
node^.dtype:=rtype;
node:=node^.pNext;
end;
end;
function TsrChain.GetRegType:TsrDataType;
var
pReg:PsrRegNode;
begin
Result:=dtUnknow;
pReg:=rSlot.current;
if (pReg=nil) then Exit;
Result:=pReg^.dtype;
end;
function TsrChain.IsUsed:Boolean;
begin
Result:=((read_count<>0) or
(write_count<>0)) and
(rSlot.current<>nil);
end;
function is_consistents(const chains:TsrChains;count:Byte):Boolean;
var
parent:PsrDataLayout;
offset,t:PtrUint;
i:Byte;
begin
offset:=0;
t:=0;
if (count<2) then Exit(True);
Result:=False;
if (chains[0]=nil) then Exit;
parent:=chains[0]^.parent;
offset:=chains[0]^.key.offset;
For i:=1 to count-1 do
begin
t:=chains[i-1]^.key.size;
offset:=offset+t;
if (chains[i]=nil) then Exit;
if (chains[i]^.parent<>parent) then Exit;
t:=chains[i]^.key.offset;
if (offset<>t) then Exit;
end;
Result:=True;
end;
function is_no_index_chains(const chains:TsrChains;count:Byte):Boolean;
var
i:Byte;
begin
Result:=False;
if (count=0) then Exit;
For i:=0 to count-1 do
begin
if (chains[i]=nil) then Exit;
if (chains[i]^.key.ext.pIndex<>nil) then Exit;
end;
Result:=True;
end;
function is_userdata_chains(const chains:TsrChains;count:Byte):Boolean;
var
parent:PsrDataLayout;
i:Byte;
begin
Result:=False;
if (count=0) then Exit;
For i:=0 to count-1 do
begin
if (chains[i]=nil) then Exit;
parent:=chains[i]^.parent;
if (parent=nil) then Exit;
if (parent^.key.parent<>nil) then Exit;
end;
Result:=True;
end;
end.

570
spirv/srNodes.pas Normal file
View File

@ -0,0 +1,570 @@
unit srNodes;
{$mode objfpc}{$H+}
interface
type
generic TNodeStack<PNode>=object
pHead:PNode;
procedure Push_head(Node:PNode);
function Pop_head:PNode;
procedure Move_from(var s:TNodeStack);
end;
generic TNodeQueue<PNode>=object
pHead,pTail:PNode;
procedure Push_head(Node:PNode);
procedure Push_tail(Node:PNode);
function Pop_head:PNode;
procedure InsertAfter(node,new:PNode);
end;
generic TNodeList<PNode>=object
pHead,pTail:PNode;
procedure Push_head(Node:PNode);
procedure Push_tail(Node:PNode);
function Pop_head:PNode;
function Pop_tail:PNode;
procedure InsertAfter(node,new:PNode);
procedure InsertBefore(node,new:PNode);
procedure Remove(node:PNode);
end;
generic TNodeFetch<PNode,TNode>=object
var
pRoot:PNode;
function _Splay(node:PNode):Integer;
function Min:PNode;
function Max:PNode;
function Next(node:PNode):PNode;
function Prev(node:PNode):PNode;
function Find(node:PNode):PNode;
function Find_be(node:PNode):PNode;
function Find_le(node:PNode):PNode;
procedure Insert(new:PNode);
end;
TsrNodeType=(
ntUnknow,
ntLiteral,
ntString,
ntConst,
ntType,
ntLabel,
ntBlock,
ntFunc,
ntVar,
ntRefId,
ntOp,
ntReg,
ntVolatile,
ntInput,
ntVertLayout,
ntFragLayout,
ntOutput,
ntChain,
ntUniform,
ntBuffer
);
TOpParamSingle=packed object
ntype:TsrNodeType;
pData:Pointer;
procedure SetParam(_ntype:TsrNodeType;_Data:Pointer);
function AsConst:Pointer;
function AsOp:Pointer;
function AsReg:Pointer;
function AsVar:Pointer;
function AsBlock:Pointer;
function AsInput:Pointer;
function AsRefId:Pointer;
function AsUniform:Pointer;
end;
TfnAlloc=Function(Size:ptruint):Pointer of object;
function ComparePtruint(buf1,buf2:PPtruint;count:PtrUint):Integer;
implementation
function TNodeFetch._Splay(node:PNode):Integer;
var
aux:TNode;
t,l,r,y:PNode;
begin
t:=pRoot;
l:=@aux;
r:=@aux;
aux.pLeft:=nil;
aux.pRight:=nil;
while (true) do
begin
Result:=TNode.c(t,node);
if (Result=0) then Break;
if (Result>0) then
begin
if (t^.pLeft=nil) then break;
if (TNode.c(node,t^.pLeft)<0) then
begin
y:=t^.pLeft; // rotate pRight
t^.pLeft:=y^.pRight;
y^.pRight:=t;
t:=y;
if (t^.pLeft=nil) then break;
end;
r^.pLeft:=t; // link pRight
r:=t;
t:=t^.pLeft;
end else
begin
if (t^.pRight=nil) then break;
if (TNode.c(node,t^.pRight)>0) then
begin
y:=t^.pRight; // rotate pLeft
t^.pRight:=y^.pLeft;
y^.pLeft:=t;
t:=y;
if (t^.pRight=nil) then break;
end;
l^.pRight:=t; // link pLeft
l:=t;
t:=t^.pRight;
end;
end;
l^.pRight:=t^.pLeft; // assemble
r^.pLeft :=t^.pRight;
t^.pLeft :=aux.pRight;
t^.pRight:=aux.pLeft;
pRoot:=t;
end;
function TNodeFetch.Min:PNode;
var
node:PNode;
begin
Result:=nil;
node:=pRoot;
While (node<>nil) do
begin
Result:=node;
node:=node^.pLeft;
end;
end;
function TNodeFetch.Max:PNode;
var
node:PNode;
begin
Result:=nil;
node:=pRoot;
While (node<>nil) do
begin
Result:=node;
node:=node^.pRight;
end;
end;
function TNodeFetch.Next(node:PNode):PNode;
begin
Result:=nil;
if (pRoot=nil) or (node=nil) then Exit;
if (node^.pRight=nil) then
begin
_Splay(node);
end;
node:=node^.pRight;
While (node<>nil) do
begin
Result:=node;
node:=node^.pLeft;
end;
end;
function TNodeFetch.Prev(node:PNode):PNode;
begin
Result:=nil;
if (pRoot=nil) or (node=nil) then Exit;
if (node^.pLeft=nil) then
begin
_Splay(node);
end;
node:=node^.pLeft;
While (node<>nil) do
begin
Result:=node;
node:=node^.pRight;
end;
end;
function TNodeFetch.Find(node:PNode):PNode;
begin
Result:=nil;
if (pRoot=nil) or (node=nil) then Exit;
if (_Splay(node)=0) then Result:=pRoot;
end;
function TNodeFetch.Find_be(node:PNode):PNode;
begin
Result:=nil;
if (pRoot=nil) or (node=nil) then Exit;
if (_Splay(node)<0) then
begin
Result:=Next(pRoot);
end else
begin
Result:=pRoot;
end;
end;
function TNodeFetch.Find_le(node:PNode):PNode;
begin
Result:=nil;
if (pRoot=nil) or (node=nil) then Exit;
if (_Splay(node)>0) then
begin
Result:=Prev(pRoot);
end else
begin
Result:=pRoot;
end;
end;
procedure TNodeFetch.Insert(new:PNode);
var
c:Integer;
begin
if (new=nil) then Exit;
if (pRoot=nil) then
begin
pRoot:=new;
end else
begin
c:=TNode.c(pRoot,new);
if (c<>0) then
begin
if (c<0) then
begin
new^.pRight:=pRoot^.pRight;
new^.pLeft :=pRoot;
pRoot^.pRight:=nil;
end else
begin
new^.pLeft :=pRoot^.pLeft;
new^.pRight:=pRoot;
pRoot^.pLeft:=nil;
end;
pRoot:=new;
end;
end;
end;
//--
procedure TNodeStack.Push_head(Node:PNode);
begin
if (pHead=nil) then
begin
node^.pNext:=nil;
end else
begin
node^.pNext:=pHead;
end;
pHead:=node;
end;
function TNodeStack.Pop_head:PNode;
begin
Result:=pHead;
if (pHead<>nil) then
begin
pHead:=pHead^.pNext;
end;
if (Result<>nil) then
begin
Result^.pNext:=nil;
end;
end;
procedure TNodeStack.Move_from(var s:TNodeStack);
var
node:PNode;
begin
repeat
node:=s.Pop_head;
if (node=nil) then Break;
Push_head(node);
until false;
end;
//--
procedure TNodeQueue.Push_head(Node:PNode);
begin
if (pHead=nil) then
begin
pTail:=node;
node^.pNext:=nil;
end else
begin
node^.pNext:=pHead;
end;
pHead:=node;
end;
procedure TNodeQueue.Push_tail(Node:PNode);
begin
if (pTail=nil) then
begin
pHead:=node;
node^.pNext:=nil;
end else
begin
pTail^.pNext:=node;
end;
pTail:=node;
end;
function TNodeQueue.Pop_head:PNode;
begin
if (pHead=nil) then
begin
Result:=nil;
end else
begin
Result:=pHead;
pHead:=pHead^.pNext;
if (pHead=nil) then
begin
pTail:=nil;
end;
Result^.pNext:=nil;
end;
end;
procedure TNodeQueue.InsertAfter(node,new:PNode);
begin
if (node^.pNext=nil) then
begin
new^.pNext:=nil;
pTail:=new;
end else
begin
new^.pNext:=node^.pNext;
end;
node^.pNext:=new;
end;
//--
procedure TNodeList.Push_head(Node:PNode);
begin
if (pHead=nil) then
begin
pTail:=node;
node^.pNext:=nil;
end else
begin
pHead^.pPrev:=node;
node^.pNext:=pHead;
end;
node^.pPrev:=nil;
pHead:=node;
end;
procedure TNodeList.Push_tail(Node:PNode);
begin
if (pTail=nil) then
begin
pHead:=node;
node^.pPrev:=nil;
end else
begin
pTail^.pNext:=node;
node^.pPrev:=pTail;
end;
node^.pNext:=nil;
pTail:=node;
end;
function TNodeList.Pop_head:PNode;
begin
if (pHead=nil) then
begin
Result:=nil;
end else
begin
Result:=pHead;
pHead:=pHead^.pNext;
if (pHead=nil) then
begin
pTail:=nil;
end else
begin
pHead^.pPrev:=nil;
end;
Result^.pPrev:=nil;
Result^.pNext:=nil;
end;
end;
function TNodeList.Pop_tail:PNode;
begin
if (pTail=nil) then
begin
Result:=nil;
end else
begin
Result:=pTail;
pTail:=pTail^.pPrev;
if (pTail=nil) then
begin
pHead:=nil;
end else
begin
pTail^.pNext:=nil;
end;
Result^.pPrev:=nil;
Result^.pNext:=nil;
end;
end;
procedure TNodeList.InsertAfter(node,new:PNode);
begin
new^.pPrev:=node;
if (node^.pNext=nil) then
begin
new^.pNext:=nil;
pTail:=new;
end else
begin
new^.pNext:=node^.pNext;
node^.pNext^.pPrev:=new;
end;
node^.pNext:=new;
end;
procedure TNodeList.InsertBefore(node,new:PNode);
begin
new^.pNext:=node;
if (node^.pPrev=nil) then
begin
new^.pPrev:=nil;
pHead:=new;
end else
begin
new^.pPrev:=node^.pPrev;
node^.pPrev^.pNext:=new;
end;
node^.pPrev:=new;
end;
procedure TNodeList.Remove(node:PNode);
begin
if (node^.pPrev=nil) then
begin
if (pHead=node) then
begin
pHead:=node^.pNext;
end;
end else
begin
node^.pPrev^.pNext:=node^.pNext;
end;
if (node^.pNext=nil) then
begin
if (pTail=node) then
begin
pTail:=node^.pPrev;
end;
end else
begin
node^.pNext^.pPrev:=node^.pPrev;
end;
end;
procedure TOpParamSingle.SetParam(_ntype:TsrNodeType;_Data:Pointer);
begin
ntype:=_ntype;
pData:=_Data;
end;
function TOpParamSingle.AsConst:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntConst) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsOp:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntOp) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsReg:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntReg) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsVar:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntVar) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsBlock:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntBlock) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsInput:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntInput) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsRefId:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntRefId) then Exit;
Result:=pData;
end;
function TOpParamSingle.AsUniform:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntUniform) then Exit;
Result:=pData;
end;
function ComparePtruint(buf1,buf2:PPtruint;count:PtrUint):Integer;
begin
Result:=0;
While (count<>0) do
begin
Result:=Integer(buf1^>buf2^)-Integer(buf1^<buf2^);
if (Result<>0) then Exit;
Inc(buf1);
Inc(buf2);
Dec(count);
end;
end;
end.

534
spirv/srOp.pas Normal file
View File

@ -0,0 +1,534 @@
unit srOp;
{$mode objfpc}{$H+}
interface
uses
srNodes,
srLabel,
srCFG,
srParser,
srTypes,
srRefId,
srReg;
type
POpParamNode=^TOpParamNode;
TOpParamNode=packed record
pNext:POpParamNode;
//----
ntype:TsrNodeType;
Case Byte of
0:(pData:Pointer);
1:(Value:DWORD;name:record end);
end;
TOpParamQueue=specialize TNodeQueue<POpParamNode>;
PsrOpBlock=^TsrOpBlock;
PspirvOp=^TspirvOp;
TspirvOp=object
pPrev,pNext:PspirvOp;
//----
pParent:PsrOpBlock;
pParam:TOpParamQueue;
Adr:TSrcAdr;
dst_type:PsrType;
dst:TOpParamSingle;
OpId:DWORD;
procedure InsertAfter(new:PspirvOp);
procedure InsertBefore(new:PspirvOp);
procedure Remove;
function ParamNode(i:Byte):POpParamNode;
procedure AddParam(const s:TOpParamSingle);
procedure AddParam(ntype:TsrNodeType;Data:Pointer);
procedure AddParamAfter(prev:POpParamNode;ntype:TsrNodeType;Data:Pointer);
procedure AddLiteral(Value:PtrUint;const name:RawByteString='');
procedure AddString(const name:RawByteString);
Procedure SetDstReg(r:Pointer);
end;
TsrVolMark=(vmNone,vmEnd,vmBreak,vmCont);
TsrBlockInfo=packed record
b_adr,e_adr:TSrcAdr;
bType:TsrBlockType;
end;
TsrOpList=specialize TNodeList<PspirvOp>;
TsrOpBlockSimple=object(TsrOpList)
Alloc:TfnAlloc;
procedure Init(cb:TfnAlloc);
function NewSpirvOp(OpId:DWORD):PSpirvOp;
function AddSpirvOp(node:PSpirvOp):PSpirvOp;
function AddSpirvOp(OpId:DWORD):PSpirvOp;
end;
TsrOpBlock=object(TsrOpBlockSimple)
pParent:PsrOpBlock;
pUpLine:PSpirvOp; //from post
Block:TsrBlockInfo;
Labels:record
pBegOp:PspirvOp;
pEndOp:PspirvOp;
pMrgOp:PspirvOp;
end;
FCursor:TsrCursor;
Regs:record
pSnap:PsrRegsSnapshot;
FVolMark:TsrVolMark;
end;
Cond:record
pReg:PsrRegNode;
FVal:Boolean;
FUseCont:Boolean;
end;
FLevel:DWORD;
dummy:TspirvOp;
function line:PSpirvOp;
procedure SetCFGBlock(pLBlock:PsrCFGBlock);
procedure SetInfo(const b:TsrBlockInfo);
procedure SetInfo(bType:TsrBlockType;b_adr,e_adr:TSrcAdr);
procedure SetLabels(pBegOp,pEndOp,pMrgOp:PspirvOp);
procedure SetCond(pReg:PsrRegNode;FVal:Boolean);
function IsEndOf(Adr:TSrcAdr):Boolean;
function FindUpLoop:PsrOpBlock;
function FindUpCond(pReg:PsrRegNode):PsrOpBlock;
end;
PSpirvFunc=^TSpirvFunc;
TSpirvFunc=object
pPrev,pNext,pLeft,pRight:PSpirvFunc;
//----
read_count:DWORD;
FTop:TsrOpBlock;
pBlock:PsrOpBlock;
ID:TsrRefId; //post id
name:RawByteString;
function c(n1,n2:PSpirvFunc):Integer; static;
Procedure PushBlock(New:PsrOpBlock);
function PopBlock:Boolean;
function line:PSpirvOp;
Procedure Init(const fname:RawByteString;Alloc:TfnAlloc);
Procedure mark_read;
Procedure mark_unread;
function NewSpirvOp(OpId:DWORD):PSpirvOp;
function AddSpirvOp(node:PSpirvOp):PSpirvOp;
function AddSpirvOp(OpId:DWORD):PSpirvOp;
end;
TsrFuncList=object
type
TNodeList=specialize TNodeList<PSpirvFunc>;
TNodeFetch=specialize TNodeFetch<PSpirvFunc,TSpirvFunc>;
var
FList:TNodeList;
FNTree:TNodeFetch;
function Search(const name:RawByteString):PSpirvFunc;
procedure Insert(new:PSpirvFunc);
end;
PsrCacheOp=^TsrCacheOp;
TsrCacheOp=object
pLeft,pRight:PsrCacheOp;
//----
pReg:PsrRegNode;
key:packed record
place:PsrOpBlock;
OpId:DWORD;
dtype:TsrDataType;
count:DWORD;
end;
Data:record end;
function c(n1,n2:PsrCacheOp):Integer; static;
function GetCompItem(i:Byte):PsrRegNode; inline;
Procedure SetCompItem(i:Byte;p:PsrRegNode); inline;
end;
TsrCacheOpList=object
type
TNodeFetch=specialize TNodeFetch<PsrCacheOp,TsrCacheOp>;
var
Alloc:TfnAlloc;
FNTree:TNodeFetch;
function Fetch(place:PsrOpBlock;OpId:DWORD;rtype:TsrDataType;count:Byte;src:PPsrRegNode):PsrCacheOp;
end;
implementation
uses
SprvEmit;
procedure TspirvOp.InsertAfter(new:PspirvOp);
begin
Assert(new<>nil);
Assert(pParent<>nil);
pParent^.InsertAfter(@Self,new);
new^.pParent:=pParent;
end;
procedure TspirvOp.InsertBefore(new:PspirvOp);
begin
Assert(new<>nil);
Assert(pParent<>nil);
pParent^.InsertAfter(@Self,new);
new^.pParent:=pParent;
end;
procedure TspirvOp.Remove;
begin
Assert(pParent<>nil);
pParent^.Remove(@Self);
pParent:=nil;
end;
function TspirvOp.ParamNode(i:Byte):POpParamNode;
var
node:POpParamNode;
begin
Result:=nil;
node:=pParam.pHead;
While (node<>nil) do
begin
if (i=0) then Exit(node);
Dec(i);
node:=node^.pNext;
end;
end;
procedure TspirvOp.AddParam(const s:TOpParamSingle);
var
node:POpParamNode;
begin
node:=pParent^.Alloc(SizeOf(TOpParamNode));
node^.ntype:=s.ntype;
node^.pData:=s.pData;
pParam.Push_tail(node);
end;
procedure TspirvOp.AddParam(ntype:TsrNodeType;Data:Pointer);
var
node:POpParamNode;
begin
node:=pParent^.Alloc(SizeOf(TOpParamNode));
node^.ntype:=ntype;
node^.pData:=Data;
pParam.Push_tail(node);
end;
procedure TspirvOp.AddParamAfter(prev:POpParamNode;ntype:TsrNodeType;Data:Pointer);
var
node:POpParamNode;
begin
node:=pParent^.Alloc(SizeOf(TOpParamNode));
node^.ntype:=ntype;
node^.pData:=Data;
pParam.InsertAfter(prev,node);
end;
procedure TspirvOp.AddLiteral(Value:PtrUint;const name:RawByteString='');
var
node:POpParamNode;
l:ptruint;
begin
l:={%H-}ptruint(@TOpParamNode(nil^).name)+Length(name)+1;
node:=pParent^.Alloc(l);
node^.ntype:=ntLiteral;
node^.Value:=Value;
Move(PChar(name)^,node^.name,Length(name)+1);
pParam.Push_tail(node);
end;
procedure TspirvOp.AddString(const name:RawByteString);
var
node:POpParamNode;
l:ptruint;
begin
l:={%H-}ptruint(@TOpParamNode(nil^).name)+Length(name)+1;
l:=Align(l,SizeOf(DWORD));
node:=pParent^.Alloc(l);
node^.ntype:=ntString;
node^.Value:=0;
Move(PChar(name)^,node^.name,Length(name)+1);
pParam.Push_tail(node);
end;
Procedure TspirvOp.SetDstReg(r:Pointer);
begin
Assert(r<>nil);
dst.SetParam(ntReg,r);
PsrRegNode(r)^.pWriter.SetParam(ntOp,@Self);
PsrRegNode(r)^.pLine:=@Self; //update line [bitcast order]
end;
function TsrOpBlock.line:PSpirvOp;
begin
Result:=nil;
if (@Self<>nil) then
begin
Result:=pTail;
end;
end;
procedure TsrOpBlock.SetCFGBlock(pLBlock:PsrCFGBlock);
begin
dummy.Adr :=pLBlock^.pBLabel^.Adr;
Block.b_adr:=pLBlock^.pBLabel^.Adr;
Block.e_adr:=pLBlock^.pELabel^.Adr;
Block.bType:=pLBlock^.bType;
end;
procedure TsrOpBlock.SetInfo(const b:TsrBlockInfo);
begin
dummy.Adr :=b.b_adr;
Block.b_adr:=b.b_adr;
Block.e_adr:=b.e_adr;
Block.bType:=b.bType;
end;
procedure TsrOpBlock.SetInfo(bType:TsrBlockType;b_adr,e_adr:TSrcAdr);
begin
dummy.Adr :=b_adr;
Block.b_adr:=b_adr;
Block.e_adr:=e_adr;
Block.bType:=bType;
end;
procedure TsrOpBlock.SetLabels(pBegOp,pEndOp,pMrgOp:PspirvOp);
begin
Labels.pBegOp:=pBegOp;
Labels.pEndOp:=pEndOp;
Labels.pMrgOp:=pMrgOp;
end;
procedure TsrOpBlock.SetCond(pReg:PsrRegNode;FVal:Boolean);
begin
Cond.pReg:=pReg;
Cond.FVal:=FVal;
end;
function TsrOpBlock.IsEndOf(Adr:TSrcAdr):Boolean;
begin
Result:=(Block.e_adr.get_pc<=Adr.get_pc);
end;
function TsrOpBlock.FindUpLoop:PsrOpBlock;
var
node:PsrOpBlock;
begin
Result:=nil;
node:=@Self;
While (node<>nil) do
begin
if (node^.Block.bType=btLoop) then Exit(node);
node:=node^.pParent;
end;
end;
function TsrOpBlock.FindUpCond(pReg:PsrRegNode):PsrOpBlock;
var
node:PsrOpBlock;
begin
Result:=nil;
if (pReg=nil) then Exit;
pReg:=RegDown(pReg);
if pReg^.is_const then Exit;
node:=@Self;
While (node<>nil) do
begin
if (node^.Block.bType=btCond) and (pReg=RegDown(node^.Cond.pReg)) then Exit(node);
node:=node^.pParent;
end;
end;
function TSpirvFunc.c(n1,n2:PSpirvFunc):Integer;
var
count1,count2:sizeint;
begin
Count1:=Length(n1^.name);
Count2:=Length(n2^.name);
Result:=Integer(Count1>Count2)-Integer(Count1<Count2);
if (Result=0) then
begin
Result:=CompareByte(PChar(n1^.name)^,PChar(n2^.name)^,Count1);
end;
end;
Procedure TSpirvFunc.PushBlock(New:PsrOpBlock);
begin
if (New=nil) then Exit;
New^.pParent:=pBlock;
New^.FLevel :=pBlock^.FLevel+1;
pBlock:=New;
end;
function TSpirvFunc.PopBlock:Boolean;
begin
Result:=False;
if (pBlock=nil) then Exit;
if (pBlock^.pParent=nil) then Exit;
pBlock:=pBlock^.pParent;
Result:=True;
end;
function TSpirvFunc.line:PSpirvOp;
begin
Result:=nil;
if (pBlock<>nil) then
begin
Result:=pBlock^.pTail;
end;
end;
Procedure TSpirvFunc.Init(const fname:RawByteString;Alloc:TfnAlloc);
begin
name:=fname;
pBlock:=@FTop;
pBlock^.Alloc:=Alloc;
pBlock^.dummy.pParent:=pBlock;
pBlock^.Push_head(@pBlock^.dummy);
end;
Procedure TSpirvFunc.mark_read;
begin
Inc(read_count);
end;
Procedure TSpirvFunc.mark_unread;
begin
if (read_count<>0) then Dec(read_count);
end;
function TSpirvFunc.NewSpirvOp(OpId:DWORD):PSpirvOp;
begin
Result:=FTop.Alloc(SizeOf(TSpirvOp));
Result^.OpId:=OpId;
end;
function TSpirvFunc.AddSpirvOp(node:PSpirvOp):PSpirvOp;
begin
Result:=node;
if (node=nil) then Exit;
pBlock^.Push_tail(node);
node^.pParent:=pBlock;
end;
function TSpirvFunc.AddSpirvOp(OpId:DWORD):PSpirvOp;
begin
Result:=AddSpirvOp(NewSpirvOp(OpId));
end;
//
procedure TsrOpBlockSimple.Init(cb:TfnAlloc);
begin
Alloc:=cb;
end;
function TsrOpBlockSimple.NewSpirvOp(OpId:DWORD):PSpirvOp;
begin
Result:=Alloc(SizeOf(TSpirvOp));
Result^.OpId:=OpId;
end;
function TsrOpBlockSimple.AddSpirvOp(node:PSpirvOp):PSpirvOp;
begin
Result:=node;
if (node=nil) then Exit;
Push_tail(node);
node^.pParent:=@Self;
end;
function TsrOpBlockSimple.AddSpirvOp(OpId:DWORD):PSpirvOp;
begin
Result:=AddSpirvOp(NewSpirvOp(OpId));
end;
//
function TsrFuncList.Search(const name:RawByteString):PSpirvFunc;
var
node:TSpirvFunc;
begin
node:=Default(TSpirvFunc);
node.name:=name;
Result:=FNTree.Find(@node);
end;
procedure TsrFuncList.Insert(new:PSpirvFunc);
begin
FNTree.Insert(new);
FList.Push_head(new);
end;
//--
function TsrCacheOp.c(n1,n2:PsrCacheOp):Integer;
var
count:DWORD;
begin
Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrCacheOp.key));
if (Result=0) then
begin
count:=n1^.key.count;
if (count<>0) then
begin
Result:=CompareByte(n1^.Data,n2^.Data,count*SizeOf(Pointer));
end;
end;
end;
function TsrCacheOp.GetCompItem(i:Byte):PsrRegNode; inline;
begin
Result:=PPsrRegNode(@Data)[i];
end;
Procedure TsrCacheOp.SetCompItem(i:Byte;p:PsrRegNode); inline;
begin
PPsrRegNode(@Data)[i]:=p;
end;
function TsrCacheOpList.Fetch(place:PsrOpBlock;OpId:DWORD;rtype:TsrDataType;count:Byte;src:PPsrRegNode):PsrCacheOp;
var
i:Byte;
size:ptruint;
rec:record
node:TsrCacheOp;
align:array[0..3] of Pointer;
end;
begin
Assert(place<>nil);
Assert((count>0) and (count<=4));
Result:=nil;
rec.node:=Default(TsrCacheOp);
rec.node.key.place:=place;
rec.node.key.OpId :=OpId;
rec.node.key.dtype:=rtype;
rec.node.key.count:=count;
For i:=0 to count-1 do
begin
rec.node.SetCompItem(i,src[i]);
end;
Result:=FNTree.Find(@rec.node);
if (Result=nil) then
begin
size:=SizeOf(TsrCacheOp)+SizeOf(Pointer)*count;
Result:=Alloc(size);
Move(rec.node,Result^,Size);
FNTree.Insert(Result);
end;
end;
end.

357
spirv/srOpUtils.pas Normal file
View File

@ -0,0 +1,357 @@
unit srOpUtils;
{$mode objfpc}{$H+}
{$MODESWITCH ADVANCEDRECORDS}
interface
uses
spirv,
srNodes,
srTypes,
srReg,
srConst,
srLayout,
srVariable,
srOp;
const
OpLinks =DWORD(-1);
OpBlock =DWORD(-2);
OpMakeExp=DWORD(-3);
OpMakeVec=DWORD(-4);
OpIAddExt=DWORD(-5);
OpISubExt=DWORD(-6);
OpAbsDiff=DWORD(-7);
OpWQM32 =DWORD(-8);
OpPackOfs=DWORD(-9);
//OpMED3F
OpCUBEID =DWORD(-10);
OpCUBESC =DWORD(-11);
OpCUBETC =DWORD(-12);
OpCUBEMA =DWORD(-13);
OpMakeCM =DWORD(-14);
type
TOpParamNodeHelper = record helper for TOpParamNode
function AsParam:TOpParamSingle;
function AsReg:Pointer;
function AsVar:Pointer;
function AsChain:Pointer;
function TryGetValue(var V:DWORD):Boolean;
end;
function InsSpirvOp(pLine,pNew:PspirvOp):PSpirvOp;
Procedure MarkUnreadParamSingle(const node:TOpParamSingle);
Function get_inverse_cmp_op(OpId:DWORD):DWORD;
Function is_term_op(OpId:DWORD):Boolean;
Function is_merge_op(OpId:DWORD):Boolean;
Function is_term_op(pLine:PspirvOp):Boolean;
procedure _up_merge_line(var pLine:PspirvOp);
function FindUpSameOp(pLine,node:PspirvOp):PspirvOp;
function GreaterThanLine(p1,p2:PspirvOp):Boolean; //(p1>p2)
function GetMaxPlace(pLine:PSpirvOp;count:Byte;src:PPsrRegNode):PSpirvOp;
implementation
function TOpParamNodeHelper.AsParam:TOpParamSingle;
begin
Result:=Default(TOpParamSingle);
if (@Self=nil) then Exit;
Result.ntype:=ntype;
Result.pData:=pData;
end;
function TOpParamNodeHelper.AsReg:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntReg) then Exit;
Result:=pData;
end;
function TOpParamNodeHelper.AsVar:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntVar) then Exit;
Result:=pData;
end;
function TOpParamNodeHelper.AsChain:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (ntype<>ntChain) then Exit;
Result:=pData;
end;
function TOpParamNodeHelper.TryGetValue(var V:DWORD):Boolean;
begin
Result:=False;
if (@Self=nil) then Exit;
if (ntype<>ntLiteral) then Exit;
V:=Value;
Result:=True;
end;
//--
function InsSpirvOp(pLine,pNew:PspirvOp):PSpirvOp;
begin
Result:=nil;
Assert(pLine<>nil);
if (pLine=nil) or (pNew=nil) then Exit;
if (pLine^.pNext<>nil) then
begin
pNew^.adr:=pLine^.adr;
end;
pLine^.InsertAfter(pNew);
Result:=pNew;
end;
Procedure MarkUnreadParamSingle(const node:TOpParamSingle);
begin
Case node.ntype of
ntLiteral:;
ntConst:PsrConst (node.pData)^.mark_unread;
ntType :PsrType (node.pData)^.mark_unread;
ntFunc :PSpirvFunc (node.pData)^.mark_unread;
ntVar :PsrVariable(node.pData)^.mark_unread;
ntRefId:;
ntReg :PsrRegNode (node.pData)^.mark_unread;
//ntReg :RegUnmark(node.pData);
ntChain:PsrChain (node.pData)^.mark_unread;
else
Assert(false);
end;
end;
function GreaterThanLine(p1,p2:PspirvOp):Boolean; //(p1>p2)
begin
Result:=False;
p2:=p2^.pNext;
While (p2<>nil) do
begin
if (p1=p2) then Exit(True);
p2:=p2^.pNext;
end;
end;
Function ParentOf(pLine,pCurr:PsrOpBlock):Boolean;
begin
Result:=False;
While (pLine<>nil) do
begin
if (pLine=pCurr) then Exit(True);
pLine:=pLine^.pParent;
end;
end;
function GetMaxPlace(pLine:PSpirvOp;count:Byte;src:PPsrRegNode):PSpirvOp;
var
m,t:PSpirvOp;
i:Byte;
begin
Result:=pLine;
if (count=0) or (src=nil) then Exit;
m:=nil;
For i:=0 to count-1 do
begin
t:=src[i]^.pLine;
if not src[i]^.is_const then
if ParentOf(pLine^.pParent,t^.pParent) then
begin
if (m=nil) then
begin
m:=t;
end else
if (m^.pParent=t^.pParent) then
begin
if GreaterThanLine(t,m) then
begin
m:=t;
end;
end else
if (t^.pParent^.FLevel>m^.pParent^.FLevel) then
begin
m:=t;
end;
end;
end;
if (m<>nil) then
begin
Result:=m;
end;
end;
Function get_inverse_cmp_op(OpId:DWORD):DWORD;
begin
Result:=0;
Case OpId of
Op.OpFOrdLessThan :Result:=Op.OpFOrdGreaterThan ;
Op.OpFOrdEqual :Result:=Op.OpFOrdEqual ;
Op.OpFOrdLessThanEqual :Result:=Op.OpFOrdGreaterThanEqual ;
Op.OpFOrdGreaterThan :Result:=Op.OpFOrdLessThan ;
Op.OpFOrdNotEqual :Result:=Op.OpFOrdNotEqual ;
Op.OpFOrdGreaterThanEqual :Result:=Op.OpFOrdLessThanEqual ;
Op.OpOrdered :Result:=Op.OpOrdered ;
Op.OpUnordered :Result:=Op.OpUnordered ;
Op.OpFUnordLessThan :Result:=Op.OpFUnordGreaterThan ;
Op.OpFUnordEqual :Result:=Op.OpFUnordEqual ;
Op.OpFUnordLessThanEqual :Result:=Op.OpFUnordGreaterThanEqual;
Op.OpFUnordGreaterThan :Result:=Op.OpFUnordLessThan ;
Op.OpFUnordNotEqual :Result:=Op.OpFUnordNotEqual ;
Op.OpFUnordGreaterThanEqual:Result:=Op.OpFUnordLessThanEqual ;
Op.OpSLessThan :Result:=Op.OpSGreaterThan ;
Op.OpIEqual :Result:=Op.OpIEqual ;
Op.OpSLessThanEqual :Result:=Op.OpSGreaterThanEqual ;
Op.OpSGreaterThan :Result:=Op.OpSLessThan ;
Op.OpINotEqual :Result:=Op.OpINotEqual ;
Op.OpSGreaterThanEqual :Result:=Op.OpSLessThanEqual ;
Op.OpULessThan :Result:=Op.OpUGreaterThan ;
Op.OpULessThanEqual :Result:=Op.OpUGreaterThanEqual ;
Op.OpUGreaterThan :Result:=Op.OpULessThan ;
Op.OpUGreaterThanEqual :Result:=Op.OpULessThanEqual ;
else
Assert(false);
end;
end;
Function is_term_op(OpId:DWORD):Boolean;
begin
Case OpId of
Op.OpBranch,
Op.OpBranchConditional,
Op.OpSwitch,
Op.OpReturn,
Op.OpReturnValue,
Op.OpKill,
Op.OpTerminateInvocation,
Op.OpDemoteToHelperInvocation,
Op.OpUnreachable:Result:=True;
else
Result:=False;
end;
end;
Function is_merge_op(OpId:DWORD):Boolean;
begin
Case OpId of
Op.OpSelectionMerge,
Op.OpLoopMerge:Result:=True;
else
Result:=False;
end;
end;
Function is_term_op(pLine:PspirvOp):Boolean;
begin
Result:=False;
if (pLine=nil) then Exit;
repeat //up
Case pLine^.OpId of
Op.OpNop,
OpLinks:pLine:=pLine^.pPrev;
OpBlock:pLine:=PsrOpBlock(pLine^.dst.pData)^.pTail;
else
Break;
end;
if (pLine=nil) then Exit;
until false;
Result:=is_term_op(pLine^.OpId);
end;
procedure _up_merge_line(var pLine:PspirvOp);
begin
repeat
if is_merge_op(pLine^.OpId) then
begin
pLine:=pLine^.pPrev;
Assert(pLine<>nil);
end else
begin
Break;
end;
until false;
end;
function CompareParam(p1,p2:POpParamNode):Boolean;
begin
Result:=(p1^.ntype=p2^.ntype) and (p1^.pData=p2^.pData);
end;
function CompareOp(p1,p2:PspirvOp):Boolean;
var
n1,n2:POpParamNode;
begin
Result:=False;
if (p1^.OpId<>p2^.OpId) then Exit;
if (p1^.dst_type<>p2^.dst_type) then Exit;
n1:=p1^.pParam.pHead;
n2:=p2^.pParam.pHead;
While (n1<>nil) do
begin
if (n2=nil) then Exit;
if not CompareParam(n1,n2) then Exit;
n1:=n1^.pNext;
n2:=n2^.pNext;
end;
Result:=(n2=nil);
end;
function FindUpSameOp(pLine,node:PspirvOp):PspirvOp;
var
tmp:PspirvOp;
pBlock:PsrOpBlock;
begin
Result:=nil;
if (pLine=nil) or (node=nil) then Exit;
While (pLine<>nil) do
begin
if CompareOp(pLine,node) then Exit(pLine);
tmp:=pLine^.pPrev;
if (tmp=nil) then
begin
pBlock:=pLine^.pParent;
if (pBlock=nil) then Exit;
tmp:=pBlock^.pUpLine;
if (tmp=nil) then
begin
pBlock:=pBlock^.pParent;
if (pBlock=nil) then Exit;
tmp:=pBlock^.pHead;
While (tmp<>nil) do
begin
if (tmp^.OpId=OpBlock) and (tmp^.dst.pData=pBlock) then
begin
tmp:=tmp^.pPrev;
Break;
end;
tmp:=tmp^.pNext;
end;
end else
begin
tmp:=tmp^.pPrev;
end;
end;
pLine:=tmp;
end;
end;
end.

140
spirv/srOutput.pas Normal file
View File

@ -0,0 +1,140 @@
unit srOutput;
{$mode ObjFPC}{$H+}
interface
uses
typinfo,
spirv,
srNodes,
srOp,
srLayout,
srVariable,
srDecorate;
type
TpsslExportType=(
etMrt0,etMrt1,etMrt2,etMrt3,
etMrt4,etMrt5,etMrt6,etMrt7,
etMrtz,
etNull,
etUnknow0,etUnknow1,
etPos0,etPos1,etPos2,etPos3,
etUnknow2,etUnknow3,
etUnknow4,etUnknow5,
etUnknow6,etUnknow7,
etUnknow8,etUnknow9,
etUnknow10,etUnknow11,
etUnknow12,etUnknow13,
etUnknow14,etUnknow15,
etUnknow16,etUnknow17,
etParam0 ,etParam1 ,etParam2 ,etParam3,
etParam4 ,etParam5 ,etParam6 ,etParam7,
etParam8 ,etParam9 ,etParam10,etParam11,
etParam12,etParam13,etParam14,etParam15,
etParam16,etParam17,etParam18,etParam19,
etParam20,etParam21,etParam22,etParam23,
etParam24,etParam25,etParam26,etParam27,
etParam28,etParam29,etParam30,etParam31
);
PsrOutput=^TsrOutput;
TsrOutput=object(TsrDescriptor)
etype:TpsslExportType;
function GetName:RawByteString;
end;
TsrOutputList=object
data:array[TpsslExportType] of TsrOutput;
Procedure Init;
function Fetch(etype:TpsslExportType):PsrOutput;
procedure AllocBinding(Decorates:PsrDecorateList);
procedure AllocEntryPoint(EntryPoint:PSpirvOp);
end;
implementation
function TsrOutput.GetName:RawByteString;
begin
Result:=GetEnumName(TypeInfo(TpsslExportType),ord(etype));
end;
Procedure TsrOutputList.Init;
var
i:TpsslExportType;
begin
For i:=Low(TpsslExportType) to High(TpsslExportType) do
begin
data[i].etype:=i;
data[i].FStorage:=StorageClass.Output;
data[i].FBinding:=-1;
end;
end;
function TsrOutputList.Fetch(etype:TpsslExportType):PsrOutput;
begin
Result:=@data[etype];
end;
procedure TsrOutputList.AllocBinding(Decorates:PsrDecorateList);
var
i:TpsslExportType;
pVar:PsrVariable;
FLocation:Integer;
begin
if (Decorates=nil) then Exit;
For i:=Low(TpsslExportType) to High(TpsslExportType) do
begin
pVar:=data[i].pVar;
if (pVar<>nil) then
begin
Case i of
etMrt0..etMrt7:
begin
if (data[i].FBinding=-1) then //alloc
begin
FLocation:=ord(i)-ord(etMrt0);
Decorates^.emit_decorate(ntVar,pVar,Decoration.Location,FLocation);
data[i].FBinding:=FLocation;
end;
//Decoration.Index; ???
end;
//etMrtz,
etPos0:
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.BuiltIn,BuiltIn.Position);
end;
//etPos1..etPos3,
etParam0..etParam31: //interpolate param
begin
FLocation:=ord(i)-ord(etParam0);
Decorates^.emit_decorate(ntVar,pVar,Decoration.Location,FLocation);
data[i].FBinding:=FLocation;
end;
else
Assert(False,'AllocBinding');
end;
end;
end;
end;
procedure TsrOutputList.AllocEntryPoint(EntryPoint:PSpirvOp);
var
i:TpsslExportType;
pVar:PsrVariable;
begin
if (EntryPoint=nil) then Exit;
For i:=Low(TpsslExportType) to High(TpsslExportType) do
begin
pVar:=data[i].pVar;
if (pVar<>nil) then
begin
EntryPoint^.AddParam(ntVar,pVar);
end;
end;
end;
end.

84
spirv/srParser.pas Normal file
View File

@ -0,0 +1,84 @@
unit srParser;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
srLabel,
srCFG,
srNodes;
type
TsrCursor=object(TsrLCursor)
pCode:PsrCodeBlock;
pBlock:PsrCFGBlock;
function PopBlock:Boolean;
end;
TsrCodeList=specialize TNodeQueue<PsrCodeBlock>;
TsrCodeHeap=object(TsrCodeList)
Alloc:TfnAlloc;
function FindByPtr(base:Pointer):PsrCodeBlock;
function FetchByPtr(base:Pointer;bType:TsrBlockType):TsrCursor;
end;
implementation
//
function TsrCodeHeap.FindByPtr(base:Pointer):PsrCodeBlock;
var
node:PsrCodeBlock;
begin
Result:=nil;
node:=pHead;
While (node<>nil) do
begin
if node^.IsContain(base) then
begin
Exit(node);
end;
node:=node^.pNext;
end;
end;
function TsrCodeHeap.FetchByPtr(base:Pointer;bType:TsrBlockType):TsrCursor;
var
node:PsrCodeBlock;
adr:TSrcAdr;
begin
node:=FindByPtr(base);
if (node=nil) then
begin
node:=Alloc(SizeOf(TsrCodeBlock));
node^.Alloc:=Alloc;
if parse_code_cfg(bType,base,node)>1 then Assert(False);
Push_tail(node);
end;
Result:=Default(TsrCursor);
Result.Init(node^.Body);
Result.pCode :=node;
Result.pBlock:=@node^.FTop;
adr:=Default(TSrcAdr);
adr.pBody:=node^.Body;
adr.Offdw:=(Pointer(base)-Pointer(adr.pBody)) div 4;
Result.Adr:=adr;
Result.pBlock:=Result.pBlock^.DownBlock(adr);
end;
function TsrCursor.PopBlock:Boolean;
begin
Result:=False;
if (pBlock=nil) then Exit;
if (pBlock^.pParent=nil) then Exit;
pBlock:=pBlock^.pParent;
Result:=True;
end;
end.

49
spirv/srRefId.pas Normal file
View File

@ -0,0 +1,49 @@
unit srRefId;
{$mode objfpc}{$H+}
interface
type
PsrRefId=^TsrRefId;
TsrRefId=packed object
ID:DWORD;
function Alloc:Boolean; inline;
end;
PsrRefIdAlloc=^TsrRefIdAlloc;
TsrRefIdAlloc=object
FSpirvID:DWORD;
function FetchSpirvID:DWORD; inline;
procedure FetchSpirvID(P:PsrRefId);
function GetSpirvIDBound:DWORD; inline;
end;
implementation
function TsrRefId.Alloc:Boolean; inline;
begin
Result:=(ID<>0);
end;
function TsrRefIdAlloc.FetchSpirvID:DWORD; inline;
begin
Inc(FSpirvID);
Result:=FSpirvID;
end;
procedure TsrRefIdAlloc.FetchSpirvID(P:PsrRefId);
begin
if (P<>nil) and (not P^.Alloc) then
begin
P^.ID:=FetchSpirvID;
end;
end;
function TsrRefIdAlloc.GetSpirvIDBound:DWORD; inline;
begin
Result:=FSpirvID+1;
end;
end.

469
spirv/srReg.pas Normal file
View File

@ -0,0 +1,469 @@
unit srReg;
{$mode objfpc}{$H+}
interface
uses
srNodes,
srRefId,
srTypes,
srConst;
type
PPsrRegSlot=^PsrRegSlot;
PsrRegSlot=^TsrRegSlot;
PPsrRegNode=^PsrRegNode;
PsrRegNode=^TsrRegNode;
TsrRegNode=packed object
pPrev,pNext:PsrRegNode;
//----
read_count:DWORD;
ID:TsrRefId; //post id
pSlot:PsrRegSlot;
pWriter:TOpParamSingle; //ntReg,ntConst,ntOp,ntVolatile
pLine:Pointer; //PspirvOp;
dtype:TsrDataType;
function GetName:RawByteString;
Procedure mark_read;
Procedure mark_unread;
procedure SetConst(pConst:PsrConst);
function AsConst:PsrConst;
function AsOp:Pointer;
function AsReg:Pointer;
function is_const:Boolean;
function is_bool:Boolean;
function is_bool_or_const_bool:Boolean;
function is_unknow:Boolean;
end;
TRegStory=specialize TNodeList<PsrRegNode>;
TString5=string[5];
TsrRegSlot=object
Alloc:TfnAlloc;
pVar:Pointer;
pStory:TRegStory;
rid:TString5;
Procedure Init(a:TfnAlloc;const n:TString5);
function first:PsrRegNode;
function current:PsrRegNode;
function New(pLine:Pointer;rtype:TsrDataType):PsrRegNode;
function NewAfter(rtype:TsrDataType;r:PsrRegNode):PsrRegNode;
procedure Remove(r:PsrRegNode);
end;
PsrRegsSnapshot=^TsrRegsSnapshot;
TsrRegsSnapshot=object
SGRP:array[0..103] of PsrRegNode;
VCC:array[0..1] of PsrRegNode;
M0:PsrRegNode;
EXEC:array[0..1] of PsrRegNode;
SCC:PsrRegNode;
VGRP:array[0..255] of PsrRegNode;
end;
TForEachSlot=procedure(pSlot:PsrRegSlot) of object;
TForEachSnap=procedure(pSlot:PsrRegSlot;var old:PsrRegNode) of object;
TsrRegsStory=object
SGRP:array[0..103] of TsrRegSlot;
VCC:array[0..1] of TsrRegSlot;
M0:TsrRegSlot;
EXEC:array[0..1] of TsrRegSlot;
SCC:TsrRegSlot;
VGRP:array[0..255] of TsrRegSlot;
FUnattach:TsrRegSlot;
Procedure Init(Alloc:TfnAlloc);
function get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
function get_sdst7(SDST:Byte):PsrRegSlot;
function get_ssrc8(SSRC:Byte):PsrRegSlot;
function get_ssrc9_pair(SSRC:Word;src:PPsrRegSlot):Boolean;
function get_ssrc9(SSRC:Word):PsrRegSlot;
function get_vsrc8(VSRC:Byte):PsrRegSlot;
function get_vdst8(VDST:Byte):PsrRegSlot;
function get_sbase(SBASE,count:Byte;src:PPsrRegSlot):Boolean;
function get_srsrc(SRSRC,count:Byte;src:PPsrRegSlot):Boolean;
function get_snapshot:TsrRegsSnapshot;
procedure ForEachSlot(cb:TForEachSlot);
procedure ForEachSnap(cb:TForEachSnap;old:PsrRegsSnapshot);
end;
implementation
Procedure TsrRegsStory.Init(Alloc:TfnAlloc);
var
i:Word;
n:TString5;
begin
FillChar(Self,SizeOf(TsrRegsStory),0);
For i:=0 to 103 do
begin
Str(i,n);
SGRP[i].Init(Alloc,'S'+n);
end;
VCC[0].Init(Alloc,'VCCL');
VCC[1].Init(Alloc,'VCCH');
M0.Init(Alloc,'M0');
EXEC[0].Init(Alloc,'EXECL');
EXEC[1].Init(Alloc,'EXECH');
SCC.Init(Alloc,'SCC');
For i:=0 to 255 do
begin
Str(i,n);
VGRP[i].Init(Alloc,'V'+n);
end;
FUnattach.Init(Alloc,'UNATT');
end;
function TsrRegsStory.get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
begin
Result:=True;
if (dst=nil) then Exit(false);
Case SDST of
0..102:
begin
dst[0]:=@SGRP[SDST];
dst[1]:=@SGRP[SDST+1];
end;
106:
begin
dst[0]:=@VCC[0];
dst[1]:=@VCC[1];
end;
126:
begin
dst[0]:=@EXEC[0];
dst[1]:=@EXEC[1];
end;
else
Result:=False;
end;
end;
function TsrRegsStory.get_sdst7(SDST:Byte):PsrRegSlot;
begin
Case SDST of
0..103:Result:=@SGRP[SDST];
106:Result:=@VCC[0];
107:Result:=@VCC[1];
124:Result:=@M0;
126:Result:=@EXEC[0];
127:Result:=@EXEC[1];
else
Result:=nil;
end;
end;
function TsrRegsStory.get_ssrc8(SSRC:Byte):PsrRegSlot;
begin
Case SSRC of
0..103:Result:=@SGRP[SSRC];
106:Result:=@VCC[0];
107:Result:=@VCC[1];
124:Result:=@M0;
126:Result:=@EXEC[0];
127:Result:=@EXEC[1];
//251:Result:=@VCC[0]; //VCCZ
//252:Result:=@EXEC[0]; //EXECZ
253:Result:=@SCC;
//254:Write('LDS_DIRECT');
else
Result:=nil;
end;
end;
function TsrRegsStory.get_ssrc9_pair(SSRC:Word;src:PPsrRegSlot):Boolean;
begin
Result:=True;
if (src=nil) then Exit(False);
Case SSRC of
0..102:
begin
src[0]:=@SGRP[SSRC];
src[1]:=@SGRP[SSRC+1];
end;
106:
begin
src[0]:=@VCC[0];
src[1]:=@VCC[1];
end;
126:
begin
src[0]:=@EXEC[0];
src[1]:=@EXEC[1];
end;
256..510:
begin
src[0]:=@VGRP[SSRC-256];
src[1]:=@VGRP[SSRC-255];
end;
else
Result:=False;
end;
end;
function TsrRegsStory.get_ssrc9(SSRC:Word):PsrRegSlot;
begin
Case SSRC of
0..103:Result:=@SGRP[SSRC];
106:Result:=@VCC[0];
107:Result:=@VCC[1];
124:Result:=@M0;
126:Result:=@EXEC[0];
127:Result:=@EXEC[1];
//251:Result:=@VCC[0]; //VCCZ
//252:Result:=@EXEC[0]; //EXECZ
253:Result:=@SCC;
//254:Write('LDS_DIRECT');
256..511:Result:=@VGRP[SSRC-256];
else
Result:=nil;
end;
end;
function TsrRegsStory.get_vsrc8(VSRC:Byte):PsrRegSlot;
begin
Result:=@VGRP[VSRC];
end;
function TsrRegsStory.get_vdst8(VDST:Byte):PsrRegSlot;
begin
Result:=@VGRP[VDST];
end;
//SBASE 0..63
//SGRP:array[0..103] of TpsslRegSlot;
function TsrRegsStory.get_sbase(SBASE,count:Byte;src:PPsrRegSlot):Boolean;
var
i,p:Byte;
begin
Result:=True;
if (SBASE>63) or (count=0) or (src=nil) then Exit(False);
p:=SBASE*2;
if ((p+count)>104) then Exit(False);
For i:=0 to count-1 do
begin
src[i]:=@SGRP[p+i];
end;
end;
//SRSRC 0..31
function TsrRegsStory.get_srsrc(SRSRC,count:Byte;src:PPsrRegSlot):Boolean;
var
i,p:Byte;
begin
Result:=True;
if (SRSRC>31) or (count=0) or (src=nil) then Exit(False);
p:=SRSRC*4;
if ((p+count)>104) then Exit(False);
For i:=0 to count-1 do
begin
src[i]:=@SGRP[p+i];
end;
end;
//
function TsrRegsStory.get_snapshot:TsrRegsSnapshot;
var
i:Word;
begin
Result:=Default(TsrRegsSnapshot);
For i:=0 to 103 do
begin
Result.SGRP[i]:=SGRP[i].current;
end;
For i:=0 to 1 do
begin
Result.VCC[i] :=VCC[i].current;
end;
Result.M0 :=M0.current;
For i:=0 to 1 do
begin
Result.EXEC[i]:=EXEC[i].current;
end;
Result.SCC :=SCC.current;
For i:=0 to 255 do
begin
Result.VGRP[i]:=VGRP[i].current;
end;
end;
procedure TsrRegsStory.ForEachSlot(cb:TForEachSlot);
var
i:Word;
begin
if (cb=nil) then Exit;
For i:=0 to 103 do
begin
cb(@SGRP[i]);
end;
For i:=0 to 1 do
begin
cb(@VCC[i]);
end;
cb(@M0);
For i:=0 to 1 do
begin
cb(@EXEC[i]);
end;
cb(@SCC);
For i:=0 to 255 do
begin
cb(@VGRP[i]);
end;
end;
procedure TsrRegsStory.ForEachSnap(cb:TForEachSnap;old:PsrRegsSnapshot);
var
i:Word;
begin
if (cb=nil) or (old=nil) then Exit;
For i:=0 to 103 do
begin
cb(@SGRP[i],Old^.SGRP[i]);
end;
For i:=0 to 1 do
begin
cb(@VCC[i],Old^.VCC[i]);
end;
cb(@M0,Old^.M0);
For i:=0 to 1 do
begin
cb(@EXEC[i],Old^.EXEC[i]);
end;
cb(@SCC,Old^.SCC);
For i:=0 to 255 do
begin
cb(@VGRP[i],Old^.VGRP[i]);
end;
end;
//--
function TsrRegNode.GetName:RawByteString;
begin
Result:='';
if (pSlot<>nil) then Result:=pSlot^.rid;
end;
Procedure TsrRegNode.mark_read;
begin
Inc(read_count);
end;
Procedure TsrRegNode.mark_unread;
begin
Assert(read_count<>0);
if (read_count<>0) then Dec(read_count);
end;
procedure TsrRegNode.SetConst(pConst:PsrConst);
begin
pWriter.SetParam(ntConst,pConst);
dtype:=pConst^.key.dtype;
end;
function TsrRegNode.AsConst:PsrConst;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (pWriter.ntype<>ntConst) then Exit;
Result:=pWriter.pData;
end;
function TsrRegNode.AsOp:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (pWriter.ntype<>ntOp) then Exit;
Result:=pWriter.pData;
end;
function TsrRegNode.AsReg:Pointer;
begin
Result:=nil;
if (@Self=nil) then Exit;
if (pWriter.ntype<>ntReg) then Exit;
Result:=pWriter.pData;
end;
function TsrRegNode.is_const:Boolean;
begin
Result:=(pWriter.ntype=ntConst);
end;
function TsrRegNode.is_bool:Boolean;
begin
Result:=(dtype=dtBool);
end;
function TsrRegNode.is_bool_or_const_bool:Boolean;
begin
Result:=is_bool or
(is_const and (AsConst<>nil) and AsConst^.isBoolVal);
end;
function TsrRegNode.is_unknow:Boolean;
begin
Result:=(dtype=dtUnknow);
end;
//--
Procedure TsrRegSlot.Init(a:TfnAlloc;const n:TString5);
begin
Alloc:=a;
rid :=n;
end;
function TsrRegSlot.first:PsrRegNode;
begin
Result:=pStory.pHead;
end;
function TsrRegSlot.current:PsrRegNode;
begin
Result:=pStory.pTail;
end;
function TsrRegSlot.New(pLine:Pointer;rtype:TsrDataType):PsrRegNode;
var
node:PsrRegNode;
begin
node:=Alloc(SizeOf(TsrRegNode));
node^.pSlot:=@Self;
node^.dtype:=rtype;
node^.pLine:=pLine;
pStory.Push_tail(node);
Result:=node;
end;
function TsrRegSlot.NewAfter(rtype:TsrDataType;r:PsrRegNode):PsrRegNode;
var
node:PsrRegNode;
begin
node:=Alloc(SizeOf(TsrRegNode));
node^.pSlot:=@Self;
node^.dtype:=rtype;
node^.pLine:=r^.pLine;
pStory.InsertAfter(r,node);
Result:=node;
end;
procedure TsrRegSlot.Remove(r:PsrRegNode);
begin
if (r=nil) then Exit;
pStory.Remove(r);
end;
end.

952
spirv/srTypes.pas Normal file
View File

@ -0,0 +1,952 @@
unit srTypes;
{$mode objfpc}{$H+}
interface
uses
bittype,
Half16,
spirv,
srNodes,
srRefId;
type
TsrDataType=(
//Real types
dtUnknow,
dtBool,
dtFloat32,
dtHalf16,
dtInt8,
dtUint8,
dtInt16,
dtUint16,
dtInt32,
dtUint32,
dtInt64,
dtUint64,
//Composite types
dtVec2b,
dtVec3b,
dtVec4b,
dtStruct2u,
dtVec2u8,
dtVec4u8,
dtVec2i8,
dtVec4i8,
dtVec2u16,
dtVec4u16,
dtVec2i16,
dtVec4i16,
dtVec2u,
dtVec3u,
dtVec4u,
dtVec2i,
dtVec3i,
dtVec4i,
dtVec2f,
dtVec3f,
dtVec4f,
dtVec2h,
dtVec4h,
//Spirv types
dtTypeVoid,
dtTypeFunction,
dtTypePointer,
dtTypeStruct,
dtTypeArray,
dtTypeRuntimeArray,
dtTypeImage,
dtTypeSampler,
dtTypeSampledImage
);
Pvec2f=^Tvec2f;
Tvec2f=array[0..1] of Single;
Pvec3f=^Tvec3f;
Tvec3f=array[0..2] of Single;
Pvec4f=^Tvec4f;
Tvec4f=array[0..3] of Single;
Pvec2h=^Tvec2h;
Tvec2h=array[0..1] of THalf16;
Pvec4h=^Tvec4h;
Tvec4h=array[0..3] of THalf16;
PPsrType=^PsrType;
PsrType=^TsrType;
//child - result type
TsrTypeImageInfo=bitpacked record
Dim :bit3; //Dim.*
Depth :bit2; //0:no,1:yes,2:any
Arrayed:bit1; //0:no,1:yes
MS :bit1; //0:no,1:yes
Sampled:bit2; //0:runtime,1:sampling,2:read/write
Format :bit23; //ImageFormat.*
end;
PsrImageInfo=^TsrImageInfo;
TsrImageInfo=packed record
dtype:TsrDataType;
tinfo:TsrTypeImageInfo;
end;
TsrType=object
pPrev,pNext,pLeft,pRight:PsrType;
//----
ID:TsrRefId; //post id
read_count:DWORD;
dtype:TsrDataType;
key:packed record
OpId:DWORD;
count:DWORD;
ext:packed record
case byte of
0:(int_size,int_sign:DWORD);
1:(float_size:DWORD);
2:(storage_class:DWORD);
3:(pField:Pointer);
4:(array_count,array_stride:DWORD);
5:(vector_count:DWORD);
6:(image:TsrTypeImageInfo);
end;
end;
Data:record end;
function c(n1,n2:PsrType):Integer; static;
Procedure mark_read;
Procedure mark_unread;
function GetCompItem(i:DWORD):PsrType; inline;
Procedure SetCompItem(i:DWORD;p:PsrType); inline;
Procedure _mark_read_child;
Procedure _mark_unread_child;
Procedure Clear;
end;
TsrTypeList=object
type
TNodeList=specialize TNodeList<PsrType>;
TNodeFetch=specialize TNodeFetch<PsrType,TsrType>;
var
Alloc:TfnAlloc;
FList:TNodeList;
FNTree:TNodeFetch;
function _New(count:DWORD):PsrType;
function _Insert(node:PsrType):PsrType;
function _Fetch(node:PsrType):PsrType;
function _FetchVector(dtype,ctype:TsrDataType;vector_count:DWORD):PsrType;
function Fetch(dtype:TsrDataType):PsrType;
function FetchPointer(child:PsrType;storage_class:DWORD):PsrType;
function FetchFunction(ret:PsrType):PsrType;
function FetchFunction1(ret,param:PsrType):PsrType;
function FetchStruct(child:PsrType;pField:Pointer):PsrType;
function FetchStructNode(node:PsrType;count:DWORD;pField:Pointer):PsrType;
function FetchArrayNode(node,child:PsrType;array_count,array_stride:DWORD):PsrType;
function FetchArray(child:PsrType;array_count,array_stride:DWORD):PsrType;
function FetchRuntimeArray(child:PsrType;array_stride:DWORD):PsrType;
function FetchImage(child:PsrType;image_info:TsrTypeImageInfo):PsrType;
function FetchSampledImage(child:PsrType):PsrType;
end;
const
ExtImgBuf:TsrTypeImageInfo=(
Dim :0; //Dim1D
Depth :0;
Arrayed:0;
MS :0;
Sampled:2;
Format :0; //Unknown
);
ExtImage2D:TsrTypeImageInfo=(
Dim :1; //Dim2D
Depth :0;
Arrayed:0;
MS :0;
Sampled:1;
Format :0; //Unknown
);
function _GetNodeSize(count:DWORD):ptruint; inline;
function LazyType2(t1,t2:TsrDataType):TsrDataType;
function LazyType3(t1,t2,t3:TsrDataType):TsrDataType;
function isIntVector(rtype:TsrDataType):Boolean; inline;
function isIntScalar(rtype:TsrDataType):Boolean; inline;
function GetVecChild(rtype:TsrDataType):TsrDataType;
function GetVecCount(rtype:TsrDataType):Byte;
Function GetVecType(elem:TsrDataType;count:Byte):TsrDataType;
function isVector(rtype:TsrDataType):Boolean; inline;
function GetTypeHigh(rtype:TsrDataType):QWORD;
function CompareType(rtype1,rtype2:TsrDataType):Boolean;
function SignType(rtype:TsrDataType):Byte;
function BitSizeType(rtype:TsrDataType):Byte;
function TryBitcastType(rtype1,rtype2:TsrDataType):Boolean;
implementation
function TsrType.c(n1,n2:PsrType):Integer;
begin
Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrType.key));
if (Result<>0) then Exit;
Result:=ComparePtruint(@n1^.Data,@n2^.Data,n1^.key.count);
end;
Procedure TsrType.mark_read;
begin
Inc(read_count);
end;
Procedure TsrType.mark_unread;
begin
if (read_count<>0) then Dec(read_count);
end;
function TsrType.GetCompItem(i:DWORD):PsrType; inline;
begin
Result:=PPsrType(@Data)[i];
end;
Procedure TsrType.SetCompItem(i:DWORD;p:PsrType); inline;
begin
PPsrType(@Data)[i]:=p;
end;
Procedure TsrType._mark_read_child;
var
i:DWORD;
begin
if (key.count<>0) then
For i:=0 to key.count-1 do
begin
GetCompItem(i)^.mark_read;
end;
end;
Procedure TsrType._mark_unread_child;
var
i:DWORD;
begin
if (key.count<>0) then
For i:=0 to key.count-1 do
begin
GetCompItem(i)^.mark_unread;
end;
end;
Procedure TsrType.Clear;
var
i:DWORD;
begin
if (key.count<>0) then
begin
For i:=0 to key.count-1 do
begin
GetCompItem(i)^.mark_unread;
SetCompItem(i,nil);
end;
key.count:=0;
end;
end;
function _GetNodeSize(count:DWORD):ptruint; inline;
begin
Result:=SizeOf(TsrType)+SizeOf(Pointer)*count;
end;
function TsrTypeList._New(count:DWORD):PsrType;
begin
Result:=Alloc(_GetNodeSize(count));
end;
function TsrTypeList._Insert(node:PsrType):PsrType;
begin
Result:=FNTree.Find(node);
if (Result=nil) then
begin
FNTree.Insert(node);
FList.Push_tail(node);
Result:=node;
end else
begin
node^._mark_unread_child;
end;
end;
function TsrTypeList._Fetch(node:PsrType):PsrType;
var
size:ptruint;
begin
Result:=FNTree.Find(node);
if (Result=nil) then
begin
size:=_GetNodeSize(node^.key.count);
Result:=Alloc(size);
Move(node^,Result^,Size);
FNTree.Insert(Result);
FList.Push_tail(Result);
end else
begin
node^._mark_unread_child;
end;
end;
function TsrTypeList._FetchVector(dtype,ctype:TsrDataType;vector_count:DWORD):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
child:PsrType;
begin
Result:=nil;
child:=Fetch(ctype);
rec.node:=Default(TsrType);
rec.node.dtype:=dtype;
rec.node.key.OpId:=Op.OpTypeVector;
rec.node.key.ext.vector_count:=vector_count;
rec.node.key.count:=1;
rec.node.SetCompItem(0,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.Fetch(dtype:TsrDataType):PsrType;
var
rec:record
node:TsrType;
align:array[0..1] of Pointer;
end;
child:PsrType;
begin
Result:=nil;
rec.node:=Default(TsrType);
Case dtype of
dtUnknow:;
dtBool:
begin
rec.node.dtype:=dtype;
rec.node.key.OpId:=Op.OpTypeBool;
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtInt8,
dtUint8,
dtInt16,
dtUint16,
dtInt32,
dtUint32,
dtInt64,
dtUint64:
begin
rec.node.dtype:=dtype;
rec.node.key.OpId:=Op.OpTypeInt;
rec.node.key.ext.int_sign:=SignType(dtype);
rec.node.key.ext.int_size:=BitSizeType(dtype);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtFloat32,
dtHalf16:
begin
rec.node.dtype:=dtype;
rec.node.key.OpId:=Op.OpTypeFloat;
rec.node.key.ext.float_size:=BitSizeType(dtype);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtTypeVoid:
begin
rec.node.dtype:=dtype;
rec.node.key.OpId:=Op.OpTypeVoid;
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
dtTypeSampler:
begin
rec.node.dtype:=dtype;
rec.node.key.OpId:=Op.OpTypeSampler;
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
//
dtVec2b,
dtVec3b,
dtVec4b,
dtVec2u8,
dtVec4u8,
dtVec2i8,
dtVec4i8,
dtVec2u16,
dtVec4u16,
dtVec2i16,
dtVec4i16,
dtVec2u,
dtVec3u,
dtVec4u,
dtVec2i,
dtVec3i,
dtVec4i,
dtVec2f,
dtVec3f,
dtVec4f,
dtVec2h,
dtVec4h:Result:=_FetchVector(dtype,GetVecChild(dtype),GetVecCount(dtype));
//
dtStruct2u:
begin
child:=Fetch(dtUint32);
child^.mark_read;
rec.node.dtype:=dtStruct2u;
rec.node.key.OpId:=Op.OpTypeStruct;
rec.node.key.count:=2;
rec.node.SetCompItem(0,child);
rec.node.SetCompItem(1,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
//
else
Assert(false);
end;
end;
function TsrTypeList.FetchPointer(child:PsrType;storage_class:DWORD):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
begin
Assert(child<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypePointer;
rec.node.key.OpId:=Op.OpTypePointer;
rec.node.key.ext.storage_class:=storage_class;
rec.node.key.count:=1;
rec.node.SetCompItem(0,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchFunction(ret:PsrType):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
begin
Assert(ret<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeFunction;
rec.node.key.OpId:=Op.OpTypeFunction;
rec.node.key.count:=1;
rec.node.SetCompItem(0,ret);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchFunction1(ret,param:PsrType):PsrType;
var
rec:record
node:TsrType;
align:array[0..1] of Pointer;
end;
begin
Assert(ret<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeFunction;
rec.node.key.OpId:=Op.OpTypeFunction;
rec.node.key.count:=2;
rec.node.SetCompItem(0,ret);
rec.node.SetCompItem(1,param);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchStruct(child:PsrType;pField:Pointer):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
begin
Assert(child<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeStruct;
rec.node.key.OpId:=Op.OpTypeStruct;
rec.node.key.ext.pField:=pField;
rec.node.key.count:=1;
rec.node.SetCompItem(0,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchStructNode(node:PsrType;count:DWORD;pField:Pointer):PsrType;
begin
Assert(node<>nil);
node^.dtype:=dtTypeStruct;
node^.key.OpId:=Op.OpTypeStruct;
node^.key.ext.pField:=pField;
node^.key.count:=count;
Result:=_Insert(node);
Result^.mark_read;
end;
function TsrTypeList.FetchArrayNode(node,child:PsrType;array_count,array_stride:DWORD):PsrType;
var
aUint:PsrType;
begin
Assert(node<>nil);
Assert(child<>nil);
node^:=Default(TsrType);
node^.dtype:=dtTypeArray;
node^.key.OpId:=Op.OpTypeArray;
node^.key.ext.array_count:=array_count;
node^.key.ext.array_stride:=array_stride;
node^.key.count:=2;
node^.SetCompItem(0,child);
aUint:=Fetch(dtUInt32);
node^.SetCompItem(1,aUint);
FList.Push_tail(node);
Result:=node;
Result^.mark_read;
end;
function TsrTypeList.FetchArray(child:PsrType;array_count,array_stride:DWORD):PsrType;
var
rec:record
node:TsrType;
align:array[0..1] of Pointer;
end;
aUint:PsrType;
begin
Assert(child<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeArray;
rec.node.key.OpId:=Op.OpTypeArray;
rec.node.key.ext.array_count:=array_count;
rec.node.key.ext.array_stride:=array_stride;
rec.node.key.count:=2;
rec.node.SetCompItem(0,child);
aUint:=Fetch(dtUInt32);
rec.node.SetCompItem(1,aUint);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchRuntimeArray(child:PsrType;array_stride:DWORD):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
begin
Assert(child<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeRuntimeArray;
rec.node.key.OpId:=Op.OpTypeRuntimeArray;
rec.node.key.ext.array_stride:=array_stride;
rec.node.key.count:=1;
rec.node.SetCompItem(0,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchImage(child:PsrType;image_info:TsrTypeImageInfo):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
begin
Assert(child<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeImage;
rec.node.key.OpId:=Op.OpTypeImage;
rec.node.key.ext.image:=image_info;
rec.node.key.count:=1;
rec.node.SetCompItem(0,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function TsrTypeList.FetchSampledImage(child:PsrType):PsrType;
var
rec:record
node:TsrType;
align:Pointer;
end;
begin
Assert(child<>nil);
rec.node:=Default(TsrType);
rec.node.dtype:=dtTypeSampledImage;
rec.node.key.OpId:=Op.OpTypeSampledImage;
rec.node.key.count:=1;
rec.node.SetCompItem(0,child);
Result:=_Fetch(@rec.node);
Result^.mark_read;
end;
function LazyType2(t1,t2:TsrDataType):TsrDataType;
begin
if (t1<>dtUnknow) then Result:=t1 else Result:=t2;
end;
function LazyType3(t1,t2,t3:TsrDataType):TsrDataType;
begin
if (t1<>dtUnknow) then Result:=t1 else Result:=t2;
if (Result=dtUnknow) then Result:=t3;
end;
function isIntVector(rtype:TsrDataType):Boolean; inline;
begin
Case rtype of
dtVec2u8,
dtVec4u8,
dtVec2i8,
dtVec4i8,
dtVec2u16,
dtVec4u16,
dtVec2i16,
dtVec4i16,
dtVec2u,
dtVec3u,
dtVec4u,
dtVec2i,
dtVec3i,
dtVec4i:Result:=True;
else
Result:=False;
end;
end;
function isIntScalar(rtype:TsrDataType):Boolean; inline;
begin
Case rtype of
dtInt8,
dtUint8,
dtInt16,
dtUint16,
dtInt32 ,
dtUint32,
dtInt64 ,
dtUint64:Result:=True;
else
Result:=False;
end;
end;
function GetVecChild(rtype:TsrDataType):TsrDataType;
begin
Case rtype of
dtVec2b,
dtVec3b,
dtVec4b:Result:=dtBool;
dtVec2u8,
dtVec4u8:Result:=dtUint8;
dtVec2i8,
dtVec4i8:Result:=dtInt8;
dtVec2u16,
dtVec4u16:Result:=dtUint16;
dtVec2i16,
dtVec4i16:Result:=dtInt16;
dtStruct2u,
dtVec2u,
dtVec3u,
dtVec4u:Result:=dtUint32;
dtVec2i,
dtVec3i,
dtVec4i:Result:=dtInt32;
dtVec2f,
dtVec3f,
dtVec4f:Result:=dtFloat32;
dtVec2h,
dtVec4h:Result:=dtHalf16;
else
Result:=dtUnknow;
end;
end;
function GetVecCount(rtype:TsrDataType):Byte;
begin
Case rtype of
dtVec2b,
dtVec2u8,
dtVec2i8,
dtVec2u16,
dtVec2i16,
dtVec2u,
dtVec2i,
dtVec2f,
dtVec2h,
dtStruct2u:Result:=2;
dtVec3b,
dtVec3u,
dtVec3i,
dtVec3f:Result:=3;
dtVec4b,
dtVec4u8,
dtVec4i8,
dtVec4u16,
dtVec4i16,
dtVec4u,
dtVec4i,
dtVec4f,
dtVec4h:Result:=4;
else
Result:=0;
end;
end;
Function GetVecType(elem:TsrDataType;count:Byte):TsrDataType;
begin
Result:=dtUnknow;
if (count<=1) then Exit(elem);
Case elem of
dtBool:
Case count of
2:Result:=dtVec2b;
3:Result:=dtVec3b;
4:Result:=dtVec4b;
end;
dtUint8:
Case count of
2:Result:=dtVec2u8;
4:Result:=dtVec4u8;
end;
dtInt8:
Case count of
2:Result:=dtVec2i8;
4:Result:=dtVec4i8;
end;
dtUint16:
Case count of
2:Result:=dtVec2u16;
4:Result:=dtVec4u16;
end;
dtInt16:
Case count of
2:Result:=dtVec2i16;
4:Result:=dtVec4i16;
end;
dtHalf16:
Case count of
2:Result:=dtVec2h;
4:Result:=dtVec4h;
end;
dtFloat32:
Case count of
2:Result:=dtVec2f;
3:Result:=dtVec3f;
4:Result:=dtVec4f;
end;
dtInt32:
Case count of
2:Result:=dtVec2i;
3:Result:=dtVec3i;
4:Result:=dtVec4i;
end;
dtUint32:
Case count of
2:Result:=dtVec2u;
3:Result:=dtVec3u;
4:Result:=dtVec4u;
end;
else;
end;
end;
function isVector(rtype:TsrDataType):Boolean; inline;
begin
Result:=GetVecChild(rtype)<>dtUnknow;
end;
function GetTypeHigh(rtype:TsrDataType):QWORD;
var
s:Byte;
begin
Result:=0;
if (rtype=dtBool) then Exit(1);
s:=BitSizeType(rtype);
Case s of
8:Result:=High(Byte);
16:Result:=High(Word);
32:Result:=High(DWord);
64:Result:=High(QWord);
else
Assert(false);
end;
end;
function CompareType(rtype1,rtype2:TsrDataType):Boolean;
begin
Case rtype1 of
dtInt8,
dtUint8:Result:=(rtype2=dtInt8) or (rtype2=dtUint8);
dtInt16,
dtUint16:Result:=(rtype2=dtInt16) or (rtype2=dtUint16);
dtInt32,
dtUint32:Result:=(rtype2=dtInt32) or (rtype2=dtUint32);
dtVec2u8,
dtVec2i8:Result:=(rtype2=dtVec2u8) or (rtype2=dtVec2i8);
dtVec4u8,
dtVec4i8:Result:=(rtype2=dtVec4u8) or (rtype2=dtVec4i8);
dtVec2u16,
dtVec2i16:Result:=(rtype2=dtVec2u16) or (rtype2=dtVec2i16);
dtVec4u16,
dtVec4i16:Result:=(rtype2=dtVec4u16) or (rtype2=dtVec4i16);
dtVec2u,
dtVec2i:Result:=(rtype2=dtVec2u) or (rtype2=dtVec2i);
dtVec3u,
dtVec3i:Result:=(rtype2=dtVec3u) or (rtype2=dtVec3i);
dtVec4u,
dtVec4i:Result:=(rtype2=dtVec4u) or (rtype2=dtVec4i);
else
Result:=(rtype1=rtype2);
end;
end;
function SignType(rtype:TsrDataType):Byte;
begin
Result:=0;
Case rtype of
dtInt8,
dtInt16,
dtInt32,
dtInt64:Result:=1;
dtHalf16,
dtFloat32,
dtVec2h,
dtVec4h,
dtVec2f,
dtVec3f,
dtVec4f:Result:=1;
else;
end;
end;
function BitSizeType(rtype:TsrDataType):Byte;
begin
Result:=0;
Case rtype of
dtInt8,
dtUint8:Result:=8;
dtInt16,
dtUint16,
dtVec2u8,
dtVec2i8,
dtHalf16:Result:=16;
dtUnknow,
dtBool, //for typecast
dtFloat32,
dtInt32,
dtUint32,
dtVec4u8,
dtVec4i8,
dtVec2u16,
dtVec2i16,
dtVec2h:Result:=32;
dtInt64,
dtUint64,
dtVec4u16,
dtVec4i16,
dtVec2f,
dtVec4h,
dtStruct2u:Result:=64;
dtVec3u,
dtVec3f:Result:=96;
dtVec4f:Result:=128;
else;
end;
end;
function TryBitcastType(rtype1,rtype2:TsrDataType):Boolean;
var
s,d:Byte;
begin
s:=BitSizeType(rtype1);
d:=BitSizeType(rtype2);
Result:=(s<>0) and (d<>0) and (s=d);
end;
end.

183
spirv/srUniform.pas Normal file
View File

@ -0,0 +1,183 @@
unit srUniform;
{$mode ObjFPC}{$H+}
interface
uses
spirv,
srNodes,
srTypes,
srLayout,
srReg,
srVariable,
srDecorate;
type
String2=String[2];
PsrUniform=^TsrUniform;
TsrUniform=object(TsrDescriptor)
pLeft,pRight:PsrUniform;
//----
key:packed record
pLayout:PsrDataLayout;
pType:PsrType;
end;
pReg:PsrRegNode;
function c(n1,n2:PsrUniform):Integer; static;
function GetTypeChar:String2;
function GetString:RawByteString;
end;
TsrUniformList=object
type
TNodeFetch=specialize TNodeFetch<PsrUniform,TsrUniform>;
var
Alloc:TfnAlloc;
FNTree:TNodeFetch;
procedure Init(cb:TfnAlloc);
function Fetch(s:PsrDataLayout;t:PsrType):PsrUniform;
Function First:PsrUniform;
Function Next(node:PsrUniform):PsrUniform;
procedure AllocBinding(Var FBinding:Integer;Decorates:PsrDecorateList);
procedure AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
end;
implementation
function TsrUniform.c(n1,n2:PsrUniform):Integer;
begin
//first pLayout
Result:=Integer(n1^.key.pLayout>n2^.key.pLayout)-Integer(n1^.key.pLayout<n2^.key.pLayout);
if (Result<>0) then Exit;
//second pType
Result:=Integer(n1^.key.pType>n2^.key.pType)-Integer(n1^.key.pType<n2^.key.pType);
end;
function TsrUniform.GetTypeChar:String2;
begin
Result:='';
if (key.pType<>nil) then
With key.pType^.key do
Case key.pType^.dtype of
dtTypeImage:
begin
if (ext.image.Dim=Dim.Buffer) then
begin
Case ext.image.Sampled of
1:Result:='UB'; //VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
2:Result:='SB'; //VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
else Result:='RB'; //runtime texel buffer
end;
end else
begin
Case ext.image.Sampled of
1:Result:='UI'; //VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
2:Result:='SI'; //VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
else Result:='RI'; //runtime image
end;
end;
end;
dtTypeSampler:Result:='US'; //VK_DESCRIPTOR_TYPE_SAMPLER
else;
end;
end;
function TsrUniform.GetString:RawByteString;
var
PID:DWORD;
begin
PID:=0;
if (key.pLayout<>nil) then
begin
PID:=key.pLayout^.FID;
end;
Result:=GetTypeChar+
';PID='+HexStr(PID,8)+
';BND='+HexStr(FBinding,8);
end;
procedure TsrUniformList.Init(cb:TfnAlloc);
begin
Alloc:=cb;
end;
function TsrUniformList.Fetch(s:PsrDataLayout;t:PsrType):PsrUniform;
var
node:TsrUniform;
begin
node:=Default(TsrUniform);
node.key.pLayout:=s;
node.key.pType:=t;
node.FStorage:=StorageClass.UniformConstant;
node.FBinding:=-1;
Result:=FNTree.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrUniform));
Move(node,Result^,SizeOf(TsrUniform));
FNTree.Insert(Result);
end else
begin
t^.mark_unread;
end;
end;
Function TsrUniformList.First:PsrUniform;
begin
Result:=FNTree.Min;
end;
Function TsrUniformList.Next(node:PsrUniform):PsrUniform;
begin
Result:=FNTree.Next(node);
end;
procedure TsrUniformList.AllocBinding(Var FBinding:Integer;Decorates:PsrDecorateList);
var
node:PsrUniform;
pVar:PsrVariable;
begin
if (Decorates=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
if (node^.FBinding=-1) then //alloc
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.Binding,FBinding);
Decorates^.emit_decorate(ntVar,pVar,Decoration.DescriptorSet,Decorates^.FDescriptorSet);
node^.FBinding:=FBinding;
Inc(FBinding);
end;
end;
node:=Next(node);
end;
end;
procedure TsrUniformList.AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
var
node:PsrUniform;
pVar:PsrVariable;
begin
if (FDebugInfo=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
FDebugInfo^.emit_source_extension(node^.GetString);
end;
node:=Next(node);
end;
end;
end.

447
spirv/srVBufInfo.pas Normal file
View File

@ -0,0 +1,447 @@
unit srVBufInfo;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
ps4_pssl,
srTypes,
srLayout,
spirv;
type
//Destination channel select:
//0=0, 1=1, 4=R, 5=G, 6=B, 7=A
Tdst_sel=array[0..3] of Byte;
TBuf_info=packed object
grp:PsrDataLayout;
dsel:Tdst_sel;
DFMT:Byte; //BUF_DATA_FORMAT_*
NFMT:Byte; //BUF_NUM_FORMAT_*
count:Byte; //count reg dst
function GetResultType:TsrDataType;
function GetElemType:TsrDataType;
function GetElemCount:Byte; inline;
function GetElemSize:Byte; inline;
function GetSizeFormat:Byte; inline;
function GetAlignSize:Byte; inline;
function IsComp:Boolean;
function IsExtFormat:Boolean;
function GetImageFormat:Byte;
function GetImageFormatElement:Byte;
function GetImageInfo:TsrImageInfo;
function GetImageInfoElement:TsrImageInfo;
end;
const
dst_sel_identity:Tdst_sel=(4,5,6,7);
function Buf_info(grp:PsrDataLayout;dsel:Tdst_sel;DFMT,NFMT,count:Byte):TBuf_info; inline;
function dst_sel(r,g,b,a:Byte):Tdst_sel; inline;
function get_reverse_dst_sel(dst:Tdst_sel):Tdst_sel;
function GetElemCount(DFMT:Byte):Byte; inline;
implementation
const
DFMT_ELEM_COUNT:array[0..15] of Byte=(
0, //BUF_DATA_FORMAT_INVALID
1, //BUF_DATA_FORMAT_8
1, //BUF_DATA_FORMAT_16
2, //BUF_DATA_FORMAT_8_8
1, //BUF_DATA_FORMAT_32
2, //BUF_DATA_FORMAT_16_16
3, //BUF_DATA_FORMAT_10_11_11
3, //BUF_DATA_FORMAT_11_11_10
4, //BUF_DATA_FORMAT_10_10_10_2
4, //BUF_DATA_FORMAT_2_10_10_10
4, //BUF_DATA_FORMAT_8_8_8_8
2, //BUF_DATA_FORMAT_32_32
4, //BUF_DATA_FORMAT_16_16_16_16
3, //BUF_DATA_FORMAT_32_32_32
4, //BUF_DATA_FORMAT_32_32_32_32
0); //BUF_DATA_FORMAT_RESERVED
DFMT_ELEM_SIZE:array[0..15] of Byte=(
0, //BUF_DATA_FORMAT_INVALID
1, //BUF_DATA_FORMAT_8
2, //BUF_DATA_FORMAT_16
1, //BUF_DATA_FORMAT_8_8
4, //BUF_DATA_FORMAT_32
2, //BUF_DATA_FORMAT_16_16
4, //BUF_DATA_FORMAT_10_11_11
4, //BUF_DATA_FORMAT_11_11_10
4, //BUF_DATA_FORMAT_10_10_10_2
4, //BUF_DATA_FORMAT_2_10_10_10
1, //BUF_DATA_FORMAT_8_8_8_8
4, //BUF_DATA_FORMAT_32_32
2, //BUF_DATA_FORMAT_16_16_16_16
4, //BUF_DATA_FORMAT_32_32_32
4, //BUF_DATA_FORMAT_32_32_32_32
0); //BUF_DATA_FORMAT_RESERVED
DFMT_SIZE:array[0..15] of Byte=(
0, //BUF_DATA_FORMAT_INVALID
1, //BUF_DATA_FORMAT_8 //shr 2
2, //BUF_DATA_FORMAT_16 //shr 2
2, //BUF_DATA_FORMAT_8_8 //shr 2
4, //BUF_DATA_FORMAT_32 //shr 2
4, //BUF_DATA_FORMAT_16_16 //shr 2
4, //BUF_DATA_FORMAT_10_11_11 //shr 2
4, //BUF_DATA_FORMAT_11_11_10 //shr 2
4, //BUF_DATA_FORMAT_10_10_10_2 //shr 2
4, //BUF_DATA_FORMAT_2_10_10_10 //shr 2
4, //BUF_DATA_FORMAT_8_8_8_8 //shr 2
8, //BUF_DATA_FORMAT_32_32 //shr 3
8, //BUF_DATA_FORMAT_16_16_16_16 //shr 3
12, //BUF_DATA_FORMAT_32_32_32 //div 12
16, //BUF_DATA_FORMAT_32_32_32_32 //shr 4
0); //BUF_DATA_FORMAT_RESERVED
function Buf_info(grp:PsrDataLayout;dsel:Tdst_sel;DFMT,NFMT,count:Byte):TBuf_info; inline;
begin
Result.grp :=grp;
Result.dsel :=dsel;
Result.DFMT :=DFMT;
Result.NFMT :=NFMT;
Result.count:=count;
end;
function dst_sel(r,g,b,a:Byte):Tdst_sel; inline;
begin
Result[0]:=r;
Result[1]:=g;
Result[2]:=b;
Result[3]:=a;
end;
function get_reverse_dst_sel(dst:Tdst_sel):Tdst_sel;
var
i,f,d:Byte;
begin
Result:=Default(Tdst_sel);
For i:=0 to 3 do
For f:=0 to 3 do
begin
d:=dst[f];
Case d of
4..7:
begin
d:=d-4;
if (i=d) then
begin
Result[i]:=f+4;
Break;
end;
end;
else;
end;
end;
end;
function TBuf_info.GetResultType:TsrDataType;
begin
Result:=dtFloat32;
Case NFMT of
BUF_NUM_FORMAT_UINT:Result:=dtUint32;
BUF_NUM_FORMAT_SINT:Result:=dtInt32;
else;
end;
end;
function TBuf_info.GetElemType:TsrDataType;
begin
Result:=dtUnknow;
Case DFMT_ELEM_SIZE[DFMT] of
1:Case NFMT of
BUF_NUM_FORMAT_SNORM ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_SINT ,
BUF_NUM_FORMAT_SNORM_NZ:Result:=dtInt8;
else Result:=dtUint8;
end;
2:Case NFMT of
BUF_NUM_FORMAT_SNORM ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_SINT ,
BUF_NUM_FORMAT_SNORM_NZ:Result:=dtInt16;
BUF_NUM_FORMAT_FLOAT :Result:=dtHalf16;
else Result:=dtUint16;
end;
4:Case NFMT of
BUF_NUM_FORMAT_SNORM ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_SINT ,
BUF_NUM_FORMAT_SNORM_NZ:Result:=dtInt32;
BUF_NUM_FORMAT_FLOAT :Result:=dtFloat32;
else Result:=dtUint32;
end;
else;
end;
end;
function GetElemCount(DFMT:Byte):Byte; inline;
begin
Result:=DFMT_ELEM_COUNT[DFMT];
end;
function TBuf_info.GetElemCount:Byte; inline;
begin
Result:=DFMT_ELEM_COUNT[DFMT];
end;
function TBuf_info.GetElemSize:Byte; inline;
begin
Result:=DFMT_ELEM_SIZE[DFMT];
end;
function TBuf_info.GetSizeFormat:Byte; inline;
begin
Result:=DFMT_SIZE[DFMT];
end;
function Min(a,b:PtrInt):PtrInt; inline;
begin
if (a<b) then Result:=a else Result:=b;
end;
function TBuf_info.GetAlignSize:Byte; inline;
begin
Result:=Min(4,GetSizeFormat);
end;
function TBuf_info.IsComp:Boolean;
begin
Case DFMT of
BUF_DATA_FORMAT_8 ,
BUF_DATA_FORMAT_16 ,
BUF_DATA_FORMAT_8_8 ,
BUF_DATA_FORMAT_16_16 ,
BUF_DATA_FORMAT_10_11_11 ,
BUF_DATA_FORMAT_11_11_10 ,
BUF_DATA_FORMAT_10_10_10_2 ,
BUF_DATA_FORMAT_2_10_10_10 ,
BUF_DATA_FORMAT_8_8_8_8 ,
BUF_DATA_FORMAT_16_16_16_16:Result:=True;
else
Result:=False;
end;
end;
function TBuf_info.IsExtFormat:Boolean;
begin
Case DFMT of
BUF_DATA_FORMAT_10_11_11 ,
BUF_DATA_FORMAT_11_11_10 ,
BUF_DATA_FORMAT_10_10_10_2 ,
BUF_DATA_FORMAT_2_10_10_10 :Result:=True;
else
Result:=False;
end;
end;
function TBuf_info.GetImageFormat:Byte;
begin
Result:=ImageFormat.Unknown;
Case DFMT of
BUF_DATA_FORMAT_8 : //R8 R8Snorm R8ui R8i
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.R8;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.R8Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.R8ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.R8i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.R8i;
else;
end;
BUF_DATA_FORMAT_16 : //R16 R16Snorm R16ui R16i R16f
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.R16;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.R16Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.R16ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.R16i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.R16i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.R16f;
end;
BUF_DATA_FORMAT_8_8 : //Rg8 Rg8Snorm Rg8ui Rg8i
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.Rg8;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.Rg8Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rg8ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.Rg8i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.Rg8i;
else;
end;
BUF_DATA_FORMAT_32 : //R32ui R32i R32f
Case NFMT of
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.R32ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.R32i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.R32i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.R32f;
else;
end;
BUF_DATA_FORMAT_16_16 : //Rg16 Rg16Snorm Rg16ui Rg16i Rg16f
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.Rg16;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.Rg16Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rg16ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.Rg16i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.Rg16i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.Rg16f;
end;
BUF_DATA_FORMAT_10_11_11 ,
BUF_DATA_FORMAT_11_11_10 : //R11fG11fB10f
Case NFMT of
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.R11fG11fB10f;
else;
end;
BUF_DATA_FORMAT_10_10_10_2 ,
BUF_DATA_FORMAT_2_10_10_10 : //Rgb10A2 Rgb10a2ui
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.Rgb10A2;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rgb10a2ui;
else;
end;
BUF_DATA_FORMAT_8_8_8_8 : //Rgba8 Rgba8Snorm Rgba8ui Rgba8i
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.Rgba8;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.Rgba8Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rgba8ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.Rgba8i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.Rgba8i;
else;
end;
BUF_DATA_FORMAT_32_32 : //Rg32ui Rg32i Rg32f
Case NFMT of
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rg32ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.Rg32i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.Rg32i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.Rg32f;
else;
end;
BUF_DATA_FORMAT_16_16_16_16: //Rgba16 Rgba16Snorm Rgba16ui Rgba16i Rgba16f
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.Rgba16;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.Rgba16Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rgba16ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.Rgba16i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.Rgba16i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.Rgba16f;
end;
BUF_DATA_FORMAT_32_32_32 ,
BUF_DATA_FORMAT_32_32_32_32: //Rgba32ui Rgba32i Rgba32f
Case NFMT of
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rgba32ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.Rgba32i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.Rgba32i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.Rgba32f;
else;
end;
else;
end;
end;
//
function TBuf_info.GetImageFormatElement:Byte;
begin
Result:=ImageFormat.Unknown;
Case DFMT of
BUF_DATA_FORMAT_8 ,
BUF_DATA_FORMAT_8_8 ,
BUF_DATA_FORMAT_8_8_8_8 : //R8 R8Snorm R8ui R8i
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.R8;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.R8Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.R8ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.R8i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.R8i;
else;
end;
BUF_DATA_FORMAT_16 ,
BUF_DATA_FORMAT_16_16 ,
BUF_DATA_FORMAT_16_16_16_16: //R16 R16Snorm R16ui R16i R16f
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.R16;
BUF_NUM_FORMAT_SNORM :Result:=ImageFormat.R16Snorm;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.R16ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.R16i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.R16i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.R16f;
end;
BUF_DATA_FORMAT_32 , //R32ui R32i R32f
BUF_DATA_FORMAT_32_32 ,
BUF_DATA_FORMAT_32_32_32 ,
BUF_DATA_FORMAT_32_32_32_32:
Case NFMT of
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.R32ui;
BUF_NUM_FORMAT_SINT :Result:=ImageFormat.R32i;
BUF_NUM_FORMAT_SNORM_NZ:Result:=ImageFormat.R32i;
BUF_NUM_FORMAT_USCALED ,
BUF_NUM_FORMAT_SSCALED ,
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.R32f;
else;
end;
BUF_DATA_FORMAT_10_11_11 ,
BUF_DATA_FORMAT_11_11_10 : //R11fG11fB10f
Case NFMT of
BUF_NUM_FORMAT_FLOAT :Result:=ImageFormat.R11fG11fB10f;
else;
end;
BUF_DATA_FORMAT_10_10_10_2 ,
BUF_DATA_FORMAT_2_10_10_10 : //Rgb10A2 Rgb10a2ui
Case NFMT of
BUF_NUM_FORMAT_UNORM :Result:=ImageFormat.Rgb10A2;
BUF_NUM_FORMAT_UINT :Result:=ImageFormat.Rgb10a2ui;
else;
end;
else;
end;
end;
//
function TBuf_info.GetImageInfo:TsrImageInfo;
begin
Result:=Default(TsrImageInfo);
Result.dtype:=GetResultType;
Result.tinfo.Dim :=Dim.Buffer;
Result.tinfo.Depth :=2;
Result.tinfo.Arrayed:=0;
Result.tinfo.MS :=0;
Result.tinfo.Sampled:=2;
Result.tinfo.Format :=GetImageFormat;
end;
function TBuf_info.GetImageInfoElement:TsrImageInfo;
begin
Result:=Default(TsrImageInfo);
Result.dtype:=GetResultType;
Result.tinfo.Dim :=Dim.Buffer;
Result.tinfo.Depth :=2;
Result.tinfo.Arrayed:=0;
Result.tinfo.MS :=0;
Result.tinfo.Sampled:=2;
Result.tinfo.Format :=GetImageFormatElement;
end;
end.

118
spirv/srVariable.pas Normal file
View File

@ -0,0 +1,118 @@
unit srVariable;
{$mode ObjFPC}{$H+}
interface
uses
spirv,
srNodes,
srTypes,
srRefId;
type
PsrVariable=^TsrVariable;
TsrVariable=object
pPrev,pNext:PsrVariable;
//----
read_count:DWORD;
write_count:DWORD;
ID:TsrRefId; //post id
pType:PsrType;
dtype:TsrDataType;
pSource:TOpParamSingle; //ntInput,ntVertLayout,ntFragLayout,ntOutput,ntUniform,ntBuffer
Procedure mark_read;
Procedure mark_unread;
Procedure mark_write;
Function GetStorageClass:DWORD;
Procedure Clear;
function GetName:RawByteString;
end;
TsrVariableList=specialize TNodeList<PsrVariable>;
implementation
uses
srLayout,
srVertLayout,
srFragLayout,
srInput,
srOutput;
Procedure TsrVariable.mark_read;
begin
Inc(read_count);
end;
Procedure TsrVariable.mark_unread;
begin
if (read_count<>0) then Dec(read_count);
end;
Procedure TsrVariable.mark_write;
begin
Inc(write_count);
end;
Function TsrVariable.GetStorageClass:DWORD;
begin
Result:=StorageClass.Private_;
if (pSource.pData<>nil) then
Case pSource.ntype of
ntInput,
ntVertLayout,
ntFragLayout,
ntOutput ,
ntUniform ,
ntBuffer :Result:=PsrDescriptor(pSource.pData)^.FStorage;
else
Assert(false,'GetStorageClass');
end;
end;
Procedure TsrVariable.Clear;
begin
if (pType<>nil) then
begin
pType^.mark_unread;
pType:=nil;
end;
if (pSource.pData<>nil) then
begin
Case pSource.ntype of
ntInput ,
ntVertLayout,
ntFragLayout,
ntOutput ,
ntUniform ,
ntBuffer :PsrDescriptor(pSource.pData)^.pVar:=nil;
else
Assert(false,'Clear');
end;
pSource.pData:=nil;
end;
end;
function TsrVariable.GetName:RawByteString;
begin
Result:='';
if (pSource.pData<>nil) then
begin
Case pSource.ntype of
ntInput :
Result:=PsrInput(pSource.pData)^.GetName;
ntVertLayout:
Result:=PsrVertLayout(pSource.pData)^.GetName;
ntFragLayout:
Result:=PsrFragLayout(pSource.pData)^.GetName;
ntOutput:
Result:=PsrOutput(pSource.pData)^.GetName;
else;
end;
end;
end;
end.

164
spirv/srVertLayout.pas Normal file
View File

@ -0,0 +1,164 @@
unit srVertLayout;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
spirv,
srNodes,
srReg,
srOp,
srVariable,
srLayout,
srDecorate;
type
PsrVertLayout=^TsrVertLayout;
TsrVertLayout=object(TsrDescriptor)
pLeft,pRight:PsrVertLayout;
//----
pLayout:PsrDataLayout;
pReg:PsrRegNode;
function c(n1,n2:PsrVertLayout):Integer; static;
function GetString:RawByteString;
function GetName:RawByteString;
end;
TsrVertLayoutList=object
type
TNodeFetch=specialize TNodeFetch<PsrVertLayout,TsrVertLayout>;
var
Alloc:TfnAlloc;
FNTree:TNodeFetch;
procedure Init(cb:TfnAlloc);
function Fetch(p:PsrDataLayout):PsrVertLayout;
Function First:PsrVertLayout;
Function Next(node:PsrVertLayout):PsrVertLayout;
procedure AllocBinding(Decorates:PsrDecorateList);
procedure AllocEntryPoint(EntryPoint:PSpirvOp);
procedure AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
end;
implementation
function TsrVertLayout.c(n1,n2:PsrVertLayout):Integer;
begin
Result:=Integer(n1^.pLayout>n2^.pLayout)-Integer(n1^.pLayout<n2^.pLayout);
//Result:=CompareByte(n1^.key,n2^.key,SizeOf(TsrVertLayout.key));
end;
function TsrVertLayout.GetString:RawByteString;
var
PID:DWORD;
begin
PID:=0;
if (pLayout<>nil) then
begin
PID:=pLayout^.FID;
end;
Result:='VA;PID='+HexStr(PID,8)+
';BND='+HexStr(FBinding,8);
end;
function TsrVertLayout.GetName:RawByteString;
begin
Result:='atParam'+IntToStr(FBinding);
end;
procedure TsrVertLayoutList.Init(cb:TfnAlloc);
begin
Alloc:=cb;
end;
function TsrVertLayoutList.Fetch(p:PsrDataLayout):PsrVertLayout;
var
node:TsrVertLayout;
begin
node:=Default(TsrVertLayout);
node.pLayout:=p;
Result:=FNTree.Find(@node);
if (Result=nil) then
begin
Result:=Alloc(SizeOf(TsrVertLayout));
Result^.pLayout:=p;
Result^.FStorage:=StorageClass.Input;
Result^.FBinding:=-1;
FNTree.Insert(Result);
end;
end;
Function TsrVertLayoutList.First:PsrVertLayout;
begin
Result:=FNTree.Min;
end;
Function TsrVertLayoutList.Next(node:PsrVertLayout):PsrVertLayout;
begin
Result:=FNTree.Next(node);
end;
procedure TsrVertLayoutList.AllocBinding(Decorates:PsrDecorateList);
var
node:PsrVertLayout;
pVar:PsrVariable;
FBinding:Integer;
begin
if (Decorates=nil) then Exit;
FBinding:=0;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
if (node^.FBinding=-1) then //alloc
begin
Decorates^.emit_decorate(ntVar,pVar,Decoration.Location,FBinding);
node^.FBinding:=FBinding;
Inc(FBinding);
end;
end;
node:=Next(node);
end;
end;
procedure TsrVertLayoutList.AllocEntryPoint(EntryPoint:PSpirvOp);
var
node:PsrVertLayout;
pVar:PsrVariable;
begin
if (EntryPoint=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
EntryPoint^.AddParam(ntVar,pVar);
end;
node:=Next(node);
end;
end;
procedure TsrVertLayoutList.AllocSourceExtension(FDebugInfo:PsrDebugInfoList);
var
node:PsrVertLayout;
pVar:PsrVariable;
begin
if (FDebugInfo=nil) then Exit;
node:=First;
While (node<>nil) do
begin
pVar:=node^.pVar;
if (pVar<>nil) then
begin
FDebugInfo^.emit_source_extension(node^.GetString);
end;
node:=Next(node);
end;
end;
end.

468
spirv/srVolatile.pas Normal file
View File

@ -0,0 +1,468 @@
unit srVolatile;
{$mode ObjFPC}{$H+}
interface
uses
spirv,
srNodes,
srTypes,
srConst,
srReg,
srVariable,
srOp,
srOpUtils,
SprvEmit;
type
PsrVolatile=^TsrVolatile;
TsrVolatile=object
pNext:PsrVolatile;
pReg:PsrRegNode;
pPar:PsrOpBlock;
FID:SizeUint;
end;
PsrVolatiles=^TsrVolatiles;
_TsrVolatiles=specialize TNodeStack<PsrVolatile>;
TsrVolatiles=object(_TsrVolatiles)
function pop_reg:PsrRegNode;
function find_reg(pReg:PsrRegNode):PsrVolatile;
end;
TEmitVolatile=object(TSprvEmit)
procedure NextVolatileID;
function AllocVolatile:PsrVolatile;
function NewVolatile(pReg:PsrRegNode):PsrVolatile;
procedure build_slot_dis(pSlot:PsrRegSlot;var old:PsrRegNode);
procedure build_slot_cur(pSlot:PsrRegSlot;var old:PsrRegNode);
procedure build_slot_old(pSlot:PsrRegSlot;var old:PsrRegNode);
procedure build_volatile_dis(old:PsrRegsSnapshot);
procedure build_volatile_cur(old:PsrRegsSnapshot);
procedure build_volatile_old(old:PsrRegsSnapshot);
procedure make_copy_slot(pSlot:PsrRegSlot);
procedure make_copy_all;
procedure PrepVolatile(dst:PspirvOp;src:PsrRegNode);
end;
implementation
uses
emit_post;
function CompareReg(r1,r2:PsrRegNode):Boolean;
begin
r1:=RegDown(r1);
r2:=RegDown(r2);
Result:=(r1=r2);
if not Result then
begin
Result:=CompareConst(r1^.AsConst,r2^.AsConst);
end;
end;
function TsrVolatiles.pop_reg:PsrRegNode;
var
node:PsrVolatile;
begin
Result:=nil;
node:=Pop_head;
if (node=nil) then Exit;
Result:=node^.pReg;
end;
function TsrVolatiles.find_reg(pReg:PsrRegNode):PsrVolatile;
var
node:PsrVolatile;
begin
Result:=nil;
//pReg:=RegDownSlot(pReg);
node:=pHead;
While (node<>nil) do
begin
if (pReg={RegDownSlot}(node^.pReg)) then Exit(node);
node:=node^.pNext;
end;
end;
procedure TEmitVolatile.NextVolatileID;
begin
Inc(FVolatileID);
end;
function TEmitVolatile.AllocVolatile:PsrVolatile;
begin
Result:=Alloc(SizeOf(TsrVolatile));
end;
function TEmitVolatile.NewVolatile(pReg:PsrRegNode):PsrVolatile;
begin
Result:=AllocVolatile;
Result^.pReg:=pReg;
Result^.pPar:=FMain^.pBlock;
Result^.FID :=FVolatileID;
pReg^.mark_read;
end;
procedure TEmitVolatile.build_slot_dis(pSlot:PsrRegSlot;var old:PsrRegNode);
var
cur:PsrRegNode;
begin
cur:=pSlot^.current;
While (cur<>old) do
begin
pSlot^.Remove(cur);
cur:=pSlot^.current;
end;
end;
procedure TEmitVolatile.build_slot_cur(pSlot:PsrRegSlot;var old:PsrRegNode);
var
cur,prv,new:PsrRegNode;
st_cur:TsrVolatiles;
rtype:TsrDataType;
begin
cur:=RegDownSlot(pSlot^.current);
prv:=RegDownSlot(old);
if CompareReg(cur,prv) then Exit;
cur:=pSlot^.current;
if (cur<>nil) then
begin
rtype:=cur^.dtype;
end else
begin
rtype:=old^.dtype;
end;
if (cur=nil) then
begin
Assert(false,'WTF');
//cur:=pSlot^.New(rtype); //Unresolve
end;
if (old=nil) then
begin
//old:=pSlot^.New(rtype); //Unresolve
end;
st_cur:=Default(TsrVolatiles);
if (old<>nil) then
begin
st_cur.Push_head(NewVolatile(old));
end;
st_cur.Push_head(NewVolatile(cur));
new:=pSlot^.New(cur^.pLine,rtype);
new^.pWriter.SetParam(ntVolatile,st_cur.pHead);
new^.mark_read;
PostReg(new);
old:=new; //update snap
end;
procedure TEmitVolatile.build_slot_old(pSlot:PsrRegSlot;var old:PsrRegNode);
var
cur,prv:PsrRegNode;
st_old:TsrVolatiles;
begin
cur:=RegDownSlot(pSlot^.current);
prv:=RegDownSlot(old);
if (prv=nil) or CompareReg(cur,prv) then Exit;
cur:=pSlot^.current;
if (old^.pWriter.ntype=ntVolatile) then
begin
st_old.pHead:=old^.pWriter.pData;
st_old.Push_head(NewVolatile(cur));
Exit;
end;
Assert(old^.pWriter.ntype=ntReg);
Assert(old^.pWriter.pData<>nil);
prv:=old^.pWriter.pData;
st_old:=Default(TsrVolatiles);
st_old.Push_head(NewVolatile(prv));
st_old.Push_head(NewVolatile(cur));
prv^.mark_unread;
old^.pWriter.SetParam(ntVolatile,st_old.pHead);
end;
procedure TEmitVolatile.build_volatile_dis(old:PsrRegsSnapshot);
begin
FRegsStory.ForEachSnap(@build_slot_dis,old);
end;
procedure TEmitVolatile.build_volatile_cur(old:PsrRegsSnapshot);
begin
NextVolatileID;
FRegsStory.ForEachSnap(@build_slot_cur,old);
end;
procedure TEmitVolatile.build_volatile_old(old:PsrRegsSnapshot);
begin
NextVolatileID;
FRegsStory.ForEachSnap(@build_slot_old,old);
end;
procedure TEmitVolatile.make_copy_slot(pSlot:PsrRegSlot);
var
cur:PsrRegNode;
begin
if (pSlot^.current<>nil) then
begin
cur:=pSlot^.current;
MakeCopy(pSlot,cur);
pSlot^.current^.pLine:=cur^.pLine;
end;
end;
procedure TEmitVolatile.make_copy_all;
begin
FRegsStory.ForEachSlot(@make_copy_slot);
end;
function get_load_from(r:PsrRegNode):PsrVariable;
var
pOp:PspirvOp;
begin
Result:=nil;
pOp:=r^.AsOp;
if (pOp=nil) then Exit;
if (pOp^.OpId<>Op.OpLoad) then Exit;
Result:=pOp^.pParam.pHead^.AsVar;
end;
type
TsrTypesA=array[Low(TsrDataType)..High(TsrDataType)] of DWORD;
function calc_best_type(pSlot:PsrRegSlot;st:TsrVolatiles):TsrDataType;
var
node:PsrVolatile;
pReg:PsrRegNode;
types:TsrTypesA;
i,max_id:TsrDataType;
bonly:Boolean;
begin
Result:=dtUnknow;
case pSlot^.rid of
'SCC':Exit(dtBool); //only bool
end;
types:=Default(TsrTypesA);
bonly:=true;
node:=st.pHead;
While (node<>nil) do
begin
if (node^.pReg<>nil) then
begin
pReg:=RegDown(node^.pReg);
if (pReg^.dtype<>dtBool) then bonly:=false;
Inc(types[pReg^.dtype]);
end;
node:=node^.pNext;
end;
case pSlot^.rid of
'VCCL',
'VCCH',
'EXECL',
'EXECH':if (types[dtBool]<>0) then Exit(dtBool); //prior bool
end;
if bonly and (types[dtBool]<>0) then
begin
Exit(dtBool);
end else
begin
//types[dtBool]:=0;
end;
max_id:=dtUnknow;
For i:=Low(TsrDataType) to High(TsrDataType) do
begin
if (max_id=dtUnknow) and (types[i]<>0) then
begin
max_id:=i;
end else
begin
if (types[i]>types[max_id]) then max_id:=i
end;
end;
Result:=max_id;
end;
{
procedure MoveVolatiles(dst,src:PsrVolatiles);
var
node:PsrVolatile;
begin
repeat
node:=src^.Pop_head;
if (node=nil) then Break;
if (dst^.find_reg(node^.pReg)=nil) then
begin
//Writeln(node^.pReg^.GetName);
dst^.Push_head(node);
end else
begin
RegUnmark(node^.pReg);
end;
until false;
end;
function TEmitVolatile._PrepVolatile(src:PsrRegNode):Integer;
var
st_tmp:TsrVolatiles;
node:PsrVolatile;
pReg:PsrRegNode;
begin
Result:=0;
if (src=nil) then Exit;
if (src^.pWriter.ntype<>ntVolatile) then Exit;
node:=src^.pWriter.pData;
While (node<>nil) do
begin
pReg:=RegDownSlot(node^.pReg);
if (pReg<>nil) then
begin
if (pReg^.pWriter.ntype=ntVolatile) then
begin
st_tmp.pHead:=pReg^.pWriter.pData;
Assert(st_tmp.pHead<>nil);
MoveVolatiles(@src^.pWriter.pData,@st_tmp);
pReg^.pWriter.SetParam(ntReg,src);
node^.pReg:=nil;
Inc(Result);
end;
end;
node:=node^.pNext;
end;
end;
}
procedure TEmitVolatile.PrepVolatile(dst:PspirvOp;src:PsrRegNode);
var
rtype:TsrDataType;
pSlot:PsrRegSlot;
pReg,tmp:PsrRegNode;
v:PsrVariable;
node:PsrVolatile;
st,st_tmp:TsrVolatiles;
pLine:PspirvOp;
begin
if (src=nil) then Exit;
if (src^.pWriter.ntype<>ntVolatile) then Exit;
pSlot:=src^.pSlot;
st.pHead:=src^.pWriter.pData;
Assert(st.pHead<>nil);
//While _PrepVolatile(src)<>0 do;
v:=pSlot^.pVar;
if (v=nil) then
begin
rtype:=calc_best_type(pSlot,st);
v:=NewVariable;
v^.dtype:=rtype;
pSlot^.pVar:=v;
end else
begin
rtype:=v^.dtype;
end;
repeat
node:=st.Pop_head;
if (node=nil) then Break;
pReg:=node^.pReg;
if (pReg=nil) then Continue;
//Assert(pReg<>nil);
//Assert(pReg^.pWriter.ntype<>ntVolatile);
tmp:=RegDownSlot(pReg);
if (v<>get_load_from(tmp)) then
begin
//mark_read volatile->emit_OpStore
pLine:=tmp^.pLine;
Assert(pLine<>nil);
if (tmp^.pWriter.ntype=ntVolatile) then
begin
st_tmp.pHead:=tmp^.pWriter.pData;
Assert(st_tmp.pHead<>nil);
st.Move_from(st_tmp);
src^.mark_read;
tmp^.pWriter.SetParam(ntReg,src);
//tmp^.pLine:=dst;
//writeln;
//PrepVolatile(pReg^.pLine,pReg);
node^.pReg:=nil;
Continue;
end;
{Case pLine^.OpId of
OpLinks:Writeln('OpLinks');
OpBlock:Writeln('OpBlock');
else
Writeln(Op.GetStr(pLine^.OpId));
end;
Writeln(HexStr(pLine^.Adr.Offdw*4,4));
Assert(pReg^.pWriter.ntype<>ntVolatile);}
TSprvEmit_post(Self).PrepTypeNode(pReg,rtype);
{if pLine^.Adr.Offdw*4=$AC then
begin
writeln('dst:',Op.GetStr(dst^.OpId),' ',HexStr(dst^.Adr.Offdw*4,4));
writeln;
end;}
_up_merge_line(pLine);
TSprvEmit_post(Self).emit_OpStore(pLine,v,pReg); //after reg
end else
begin
RegUnmark(pReg);
//pReg^.mark_unread;
end;
until false;
v^.mark_read;
//src^.dtype:=rtype; //reuse
pLine:=dst;
Assert(pLine<>nil);
pLine:=pLine^.pPrev;
Assert(pLine<>nil);
_up_merge_line(pLine);
Assert(pLine<>nil);
TSprvEmit_post(Self).PrepTypeDst(src,rtype); //reuse
TSprvEmit_post(Self).emit_OpLoad(pLine,src,v); //before reg
end;
end.