unit emit_post; {$mode objfpc}{$H+} interface uses sysutils, spirv, srNode, srType, srTypes, srConst, srReg, srVariable, srLayout, srBuffer, srBitcast, srPrivate, srOutput, srOp, srOpUtils, srDecorate, emit_fetch; type TPostCb=function(node:TSpirvOp):Integer of object; TRegsCb=function(pLine:TspirvOp;var node:TsrRegNode):Integer of object; TSprvEmit_post=class(TEmitFetch) function PostStage:Integer; function RegFindCond(pLine:TspirvOp;var node:TsrRegNode):Integer; function RegCollapse(pLine:TspirvOp;var node:TsrRegNode):Integer; function RegVResolve(pLine:TspirvOp;var node:TsrRegNode):Integer; function RegWResolve(pLine:TspirvOp;var node:TsrRegNode):Integer; function RegTypecast(pLine:TspirvOp;var node:TsrRegNode):Integer; function RegSTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer; function RegVTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer; //function NodeOpSameOp(node:TspirvOp):Integer; function NodeOpStrict(node:TspirvOp):Integer; function OnOpStep1(node:TspirvOp):Integer; //backward function OnOpStep2(node:TspirvOp):Integer; //forward function OnOpStep3(node:TspirvOp):Integer; //forward function OnOpStep4(node:TspirvOp):Integer; //forward function OnOpStep5(node:TspirvOp):Integer; //backward function OnOpStep6(node:TspirvOp):Integer; //backward function OnOpStep7(node:TspirvOp):Integer; //backward function OnDecorate(node:TspirvOp):Integer; function PostFuncAnalize:Integer; function OnChainUpdate(node:TsrChain):Integer; function PostAllocField:Integer; function PostAllocBuffer:Integer; procedure ShiftIndex(pChain:TsrChain;const F:TFieldFetchValue;var _offset:PtrUint); function FetchField(pChain:TsrChain):TsrField; function OnChainField(node:TsrChain):Integer; procedure AdjustMaxSize(tbuf:TsrBuffer); function LinkBitcast(pBuffer:TsrBuffer):TsrNode; function OnChainAlloc(node:TsrChain):Integer; procedure OnFieldType(node:TsrField); function PostConstAnalize:Integer; function PostVariableAnalize:Integer; function PostTypeAnalize:Integer; end; function EnumLineRegs(cb:TRegsCb;pLine:TspirvOp):Integer; function EnumFirstReg(cb:TRegsCb;pLine:TspirvOp):Integer; function EnumBlockOpForward(cb:TPostCb;pBlock:TsrOpBlock):Integer; function EnumBlockOpBackward(cb:TPostCb;pBlock:TsrOpBlock):Integer; implementation uses emit_post_op; function TSprvEmit_post.PostStage:Integer; begin Result:=0; InputList.Test; Result:=Result+PostFuncAnalize; Result:=Result+PostVariableAnalize; Result:=Result+PostConstAnalize; Result:=Result+PostTypeAnalize; end; function EnumLineRegs(cb:TRegsCb;pLine:TspirvOp):Integer; var node:POpParamNode; pReg:TsrRegNode; begin Result:=0; if (cb=nil) or (pLine=nil) then Exit; node:=pLine.ParamFirst; While (node<>nil) do begin if node.Value.IsType(ntReg) then begin pReg:=node.AsReg; Result:=Result+cb(pLine,pReg); node.Value:=pReg; end; node:=node.Next; end; end; function EnumFirstReg(cb:TRegsCb;pLine:TspirvOp):Integer; var node:POpParamNode; pReg:TsrRegNode; begin Result:=0; if (cb=nil) or (pLine=nil) then Exit; node:=pLine.ParamFirst; if (node<>nil) then begin if node.Value.IsType(ntReg) then begin pReg:=node.AsReg; Result:=Result+cb(pLine,pReg); node.Value:=pReg; end; end; end; function EnumBlockOpForward(cb:TPostCb;pBlock:TsrOpBlock):Integer; var node,prev:TspirvOp; begin Result:=0; if (pBlock=nil) or (cb=nil) then Exit; node:=pBlock.First; While (node<>nil) do begin prev:=node; node:=flow_down_next_up(node); if prev.IsType(ntOp) then begin Result:=Result+cb(prev); end; end; end; function EnumBlockOpBackward(cb:TPostCb;pBlock:TsrOpBlock):Integer; var node,prev:TspirvOp; begin Result:=0; if (pBlock=nil) or (cb=nil) then Exit; node:=pBlock.Last; While (node<>nil) do begin prev:=node; node:=flow_down_prev_up(node); if prev.IsType(ntOp) then begin Result:=Result+cb(prev); end; end; end; function TSprvEmit_post.RegFindCond(pLine:TspirvOp;var node:TsrRegNode):Integer; var old:TsrRegNode; pBlock:TsrOpBlock; pCond :TsrOpBlock; pIf :TsrOpBlock; src:TsrRegNode; pOpNot:TspirvOp; Invert:Boolean; begin Result:=0; if (node=nil) then Exit; old:=node; src:=RegDown(node); Invert:=false; pBlock:=pLine.Parent; if (pLine.OpId=Op.OpBranchConditional) then begin //move to parent of current "If" block pIf :=pBlock.FindUpCond; pBlock:=pBlock.Parent; // if (pIf<>nil) then if (RegDown(pIf.Cond.pReg)<>src) then begin //non cond pIf:=nil; end; end else begin pIf:=nil; end; repeat if src.is_const then Exit; pCond:=pBlock.FindUpCondByReg(src,True,Invert); if (pCond<>nil) then begin //Exit(0); //Writeln(OpGetStr(pLine)); //FNormalOrder=true Invert=false : result=true //FNormalOrder=true Invert=true : result=false //FNormalOrder=false Invert=false : result=false //FNormalOrder=false Invert=true : result=true Invert:=Invert xor pCond.Cond.FNormalOrder; node:=NewImm_q(old.dtype,ord(Invert),pLine); if (pIf<>nil) then begin //replace cond pIf.Cond.pReg:=node; end; Exit(1); end; pOpNot:=src.pWriter.specialize AsType; if (pOpNot=nil) then Exit; Case pOpNot.OpId of Op.OpLogicalNot:; Op.OpNot:; else Exit; end; src:=pOpNot.ParamFirst.AsReg; if (src=nil) then Exit; src:=RegDown(src); Invert:=not Invert; until false; end; function CompareTypeOp(OpId:DWORD;rtype1,rtype2:TsrDataType):Boolean; var relax:Boolean; begin Case OpId of Op.OpLoad , Op.OpImageRead , Op.OpImageWrite , Op.OpBitFieldSExtract , Op.OpBitFieldUExtract , Op.OpSelect , Op.OpIAddCarry , Op.OpISubBorrow , Op.OpUMulExtended , Op.OpSMulExtended , Op.OpCompositeConstruct:relax:=False; else relax:=True; end; Case relax of True :Result:=CompareType(rtype1,rtype2); False:Result:=(rtype1=rtype2); end; end; function TSprvEmit_post.RegCollapse(pLine:TspirvOp;var node:TsrRegNode):Integer; var rold,rnew:TsrRegNode; begin Result:=0; if (node=nil) then Exit; if (node.dtype=dtUnknow) then Exit; rold:=node; rnew:=RegDown(rold); if (rold<>rnew) then //is change? begin if (rnew.dtype=dtUnknow) or CompareTypeOp(pLine.OpId,rnew.dtype,rold.dtype) then begin rnew.PrepType(ord(rold.dtype)); if (rnew.dtype<>dtUnknow) then begin node:=rnew; Inc(Result); end; end else begin //save to another step rold.pWriter:=rnew; node:=rold; end; end; { if (rold.dtype<>dtUnknow) and (node.dtype=dtUnknow) then begin writeln; assert(false); end; } end; function TSprvEmit_post.RegVResolve(pLine:TspirvOp;var node:TsrRegNode):Integer; var old:TsrRegNode; begin Result:=0; if (node=nil) then Exit; //if not (node.IsUsed) then Exit; old:=node; node:=RegDown(old); if node.pWriter.IsType(ntVolatile) then begin //create load/store //use forward only node:=PrivateList.PrepVolatile(pLine,node); Inc(Result); end; if (old<>node) then //is change? begin if (node.dtype=dtUnknow) or (node.dtype=old.dtype) then begin Inc(Result); end else begin //save to another step old.pWriter:=node; node:=old; end; end; { if (old.dtype<>dtUnknow) and (node.dtype=dtUnknow) then begin writeln; assert(false); end; } end; function GetDepType(src:TsrRegNode):TsrDataType; var node:TDependenceNode; pReg:TsrRegNode; pLine:TspirvOp; Function CmpType(var ret:TsrDataType;dtype:TsrDataType):Boolean; begin Result:=False; if (dtype=dtUnknow) then Exit; if (ret=dtUnknow) then begin ret:=dtype; end else begin if (ret<>dtype) then begin ret:=dtUnknow; Result:=True; //Exit end; end; end; begin Result:=dtUnknow; node:=src.FirstDependence; // While (node<>nil) do begin if node.pNode.IsType(ntReg) then begin pReg:=node.pNode.specialize AsType; if (pReg<>nil) then begin if CmpType(Result,pReg.dtype) then Exit; end; end else if node.pNode.IsType(ntOp) then begin pLine:=node.pNode.specialize AsType; if (classif_rw_op(pLine.OpId) and 2)<>0 then begin //ignore? end else begin if CmpType(Result,src.dtype) then Exit; end; end; // node:=src.NextDependence(node); end; end; function ResolveWeak(new:TsrRegNode):Integer; var dtype:TsrDataType; begin Result:=0; While (new<>nil) do begin if new.dweak then begin dtype:=GetDepType(new); if (dtype<>dtUnknow) then begin if (new.dtype<>dtype) then begin new.dtype:=dtype; new.dweak:=False; Inc(Result); end else begin new.dweak:=False; end; end; end; new:=new.AsReg; //next end; end; function TSprvEmit_post.RegWResolve(pLine:TspirvOp;var node:TsrRegNode):Integer; begin Result:=0; if (node=nil) then Exit; Result:=Result+ResolveWeak(node); end; function TSprvEmit_post.RegTypecast(pLine:TspirvOp;var node:TsrRegNode):Integer; var old:TsrRegNode; cst:TsrConst; dtype:TsrDataType; begin Result:=0; if (node=nil) then Exit; old:=node; node:=RegDown(old); if (old<>node) then //is change? begin if (node.dtype=dtUnknow) or (node.dtype=old.dtype) then begin Inc(Result); end else begin //bitcast node:=BitcastList.FetchCast(old.dtype,node); Inc(Result); end; end else if node.pWriter.IsType(ntConst) then begin cst:=node.pWriter.specialize AsType; // dtype:=LazyType3(old.dtype,node.dtype,cst.dtype); // if (dtype<>dtUnknow) then if not CompareType(cst.dtype,dtype) then begin cst:=ConstList.Bitcast(dtype,cst); old.pWriter:=cst; Inc(Result); end; end; { if (old.dtype<>dtUnknow) and (node.dtype=dtUnknow) then begin writeln; assert(false); end; } end; function TSprvEmit_post.RegSTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer; var dtype:TsrDataType; dst:TsrRegNode; begin Result:=0; if (node.dtype=dtBool) then Exit; dst:=pLine.pDst.specialize AsType; if (dst=nil) then Exit; dtype:=dst.dtype; if (dtype<>dtUnknow) and (node.dtype<>dtUnknow) and (dtype<>node.dtype) then begin node:=BitcastList.FetchCast(dtype,node); //strict type Inc(Result); end; end; function TSprvEmit_post.RegVTStrict(pLine:TspirvOp;var node:TsrRegNode):Integer; var dtype:TsrDataType; dst:TsrRegNode; begin Result:=0; dst:=pLine.pDst.specialize AsType; if (dst=nil) then Exit; dtype:=dst.dtype.Child; if (dtype<>dtUnknow) and (node.dtype<>dtUnknow) and (dtype<>node.dtype) then begin node:=BitcastList.FetchCast(dtype,node); //strict type Inc(Result); end; end; { function TSprvEmit_post.NodeOpSameOp(node:TspirvOp):Integer; var tmp:TspirvOp; dst,src:TsrRegNode; begin Result:=0; if (node^.dst.ntype<>ntReg) then Exit; //is reg Case node^.OpId of Op.OpLoad:; Op.OpCompositeConstruct:; OpMakeExp:; OpMakeVec:; OpPackOfs:; else Exit; end; tmp:=FindUpSameOp(node^.pPrev,node); if (tmp=nil) then Exit; src:=tmp^.dst.AsReg; dst:=node^.dst.AsReg; if (src=nil) or (dst=nil) then Exit; dst^.SetReg(src); node^.OpId:=OpLinks; //mark remove node^.dst:=Default(TOpParamSingle); Result:=1; end; } function TSprvEmit_post.NodeOpStrict(node:TspirvOp):Integer; begin Result:=0; if not node.pDst.IsType(ntReg) then Exit; //is reg Case node.OpId of Op.OpBitFieldSExtract , Op.OpBitFieldUExtract :Result:=EnumFirstReg(@RegSTStrict,node); Op.OpSelect :Result:=EnumLineRegs(@RegSTStrict,node); Op.OpIAddCarry , Op.OpISubBorrow , Op.OpUMulExtended , Op.OpSMulExtended , Op.OpCompositeConstruct:Result:=EnumLineRegs(@RegVTStrict,node); else; end; end; // function TSprvEmit_post.OnOpStep1(node:TspirvOp):Integer; //backward begin Result:=0; if node.is_cleared then Exit; if node.can_clear then begin if node.Clear then Inc(Result); end else begin //Result:=Result+NodeOpSameOp(node); Result:=Result+EnumLineRegs(@RegCollapse,node); Result:=Result+EnumLineRegs(@RegFindCond,node); end; end; function TSprvEmit_post.OnOpStep2(node:TspirvOp):Integer; //forward begin Result:=0; if node.is_cleared then Exit; if node.can_clear then begin if node.Clear then Inc(Result); end else begin Result:=Result+TEmitPostOp(TObject(Self)).PostForward1(node); end; end; function TSprvEmit_post.OnOpStep3(node:TspirvOp):Integer; //forward begin Result:=0; if node.is_cleared then Exit; if node.can_clear then begin if node.Clear then Inc(Result); end else begin Result:=Result+TEmitPostOp(TObject(Self)).PostForward2(node); end; end; function TSprvEmit_post.OnOpStep4(node:TspirvOp):Integer; //forward begin Result:=0; { //prior if node.is_post then begin Result:=Result+EnumLineRegs(@RegVResolve,node); Exit; end; } if node.is_cleared then Exit; if node.can_clear then begin if node.Clear then Inc(Result); end else begin Result:=Result+EnumLineRegs(@RegVResolve,node); end; end; function TSprvEmit_post.OnOpStep5(node:TspirvOp):Integer; //backward begin Result:=0; if node.is_cleared then Exit; if node.can_clear then begin if node.Clear then Inc(Result); end else begin Result:=Result+EnumLineRegs(@RegWResolve,node); end; end; function TSprvEmit_post.OnOpStep6(node:TspirvOp):Integer; //backward begin Result:=0; if node.is_cleared then Exit; if node.can_clear then begin if node.Clear then Inc(Result); end else begin Result:=Result+EnumLineRegs(@RegTypecast,node); Result:=Result+NodeOpStrict(node); Result:=Result+EnumLineRegs(@RegFindCond,node); end; end; function TSprvEmit_post.OnOpStep7(node:TspirvOp):Integer; //backward begin Result:=0; if node.is_cleared then begin // if (node.read_count<>0) then if not node.is_force then begin Assert(false,'Wrong read_count on:'+OpGetStrDebug(node)); end; // node.Remove; Inc(Result); end else if node.can_clear then begin node.Clear; node.Remove; Inc(Result); end; end; function TSprvEmit_post.OnDecorate(node:TspirvOp):Integer; var r:TsrRegNode; begin Result:=0; case node.OpId of Op.OpFAdd, Op.OpFSub, Op.OpFMul, Op.OpFDiv, Op.OpFRem, Op.OpFMod: if (node.pDst<>nil) then begin DecorateList.OpDecorate(node.pDst,Decoration.NoContraction,0); end; Op.OpImageQuerySizeLod, Op.OpImageQueryLod: begin AddCapability(Capability.ImageQuery); end; Op.OpGroupNonUniformShuffle: begin //upgrade version to 1.3 Config.UpgradeVersion($10300); AddCapability(Capability.GroupNonUniformShuffle); end; Op.OpGroupNonUniformQuadBroadcast: begin r:=node.ParamNode(2).Value; r:=RegDown(r); // if r.is_const then begin //upgrade version to 1.3 Config.UpgradeVersion($10300); end else begin //upgrade version to 1.5 Config.UpgradeVersion($10500); end; // AddCapability(Capability.GroupNonUniformQuad); end; else; end; end; function TSprvEmit_post.PostFuncAnalize:Integer; label _pass; var pFunc:TSpirvFunc; data_layout:Boolean; i,r4:Integer; begin Result:=0; data_layout:=false; //backward analize pFunc:=FuncList.FList.pTail; While (pFunc<>nil) do begin data_layout:=(Main=pFunc); _pass: repeat //OnOpStep5 repeat //OnOpStep3 repeat //OnOpStep2 repeat //OnOpStep1 i:=EnumBlockOpBackward(@OnOpStep1,pFunc.pTop); //OnOpStep1 Reg Collapse if (i=0) then Break; Result:=Result+i; until false; i:=EnumBlockOpForward(@OnOpStep2,pFunc.pTop); //OnOpStep2 PostForward1 if (i=0) then Break; Result:=Result+i; until false; i:=EnumBlockOpForward(@OnOpStep3,pFunc.pTop); //OnOpStep3 PostForward2 if (i=0) then Break; Result:=Result+i; until false; if data_layout then begin Result:=Result+PostAllocField; end; repeat //OnOpStep4 Volatile Reslove i:=EnumBlockOpForward(@OnOpStep4,pFunc.pTop); if (i=0) then Break; Result:=Result+i; until false; r4:=0; repeat //OnOpStep5 Weak Reslove i:=EnumBlockOpBackward(@OnOpStep5,pFunc.pTop); if (i=0) then Break; r4:=r4+i; until false; if (r4=0) then Break; Result:=Result+r4; until false; if data_layout then begin Result:=Result+PostAllocBuffer; end; //UpdateRegType OpLoad/OpStore DataLayoutList.EnumChain(@OnChainUpdate); PrivateList.Post; if data_layout then begin OutputList.Post; end; { //pass agian if data_layout then begin data_layout:=false; goto _pass; end; } repeat //OnOpStep6 Typecast i:=EnumBlockOpBackward(@OnOpStep6,pFunc.pTop); if (i=0) then Break; Result:=Result+i; until false; //pass agian if data_layout or (i<>0) then begin data_layout:=false; goto _pass; end; PrivateList.RemoveAllStore; Result:=Result+EnumBlockOpBackward(@OnOpStep7,pFunc.pTop); //OnOpStep7 Remove Lines EnumBlockOpForward(@OnDecorate,pFunc.pTop); //NoContraction pFunc:=pFunc.Prev; end; end; function TSprvEmit_post.OnChainUpdate(node:TsrChain):Integer; var pField:TsrField; begin Result:=0; // pField:=node.pField; if (pField<>nil) then if (pField.Fdtype<>dtUnknow) then if (node.dtype=dtUnknow) then begin node.dtype:=pField.Fdtype; //update type end; // node.UpdateRegType; end; function TSprvEmit_post.PostAllocField:Integer; begin Result:=0; DataLayoutList.AllocID; Result:=Result+DataLayoutList.EnumChain(@OnChainField); end; function TSprvEmit_post.PostAllocBuffer:Integer; begin Result:=0; BufferList.ApplyBufferType; BufferList.AlignOffset; BufferList.FillSpace; BufferList.AllocID; BufferList.EnumAllField(@OnFieldType); Result:=Result+DataLayoutList.EnumChain(@OnChainAlloc); end; procedure TSprvEmit_post.ShiftIndex(pChain:TsrChain;const F:TFieldFetchValue;var _offset:PtrUint); var _stride,_count:PtrUint; pIndex:TsrRegNode; pLine:TsrNode; begin _offset:=_offset-F.pField.offset; //stride relative _stride:=F.pField.stride; _count :=_offset div _stride; _offset:=_offset mod _stride; // if (_count<>0) or (pChain.pIndex=nil) then begin //save pChain.FUndoIndex :=pChain.pIndex; pChain.FUndoOffset:=pChain.offset; //shift pIndex:=pChain.pIndex; if (pIndex<>nil) then begin pLine :=pIndex.pLine; pIndex:=OpIAddTo(pIndex,_count,@pLine); end else begin pLine :=init_line; pIndex:=NewImm_q(dtUint32,_count,pLine); end; pChain.pIndex:=pIndex; pChain.stride:=_stride; pChain.offset:=pChain.offset-(_count*_stride); end; end; procedure UndoIndex(pChain:TsrChain); begin if (pChain.FUndoIndex<>nil) then begin //undo pChain.pIndex:=pChain.FUndoIndex; pChain.offset:=pChain.FUndoOffset; //clear pChain.FUndoIndex :=nil; pChain.FUndoOffset:=0; end; end; function TSprvEmit_post.FetchField(pChain:TsrChain):TsrField; label _start, _resolve, _exit; var buf:TsrBuffer; F:TFieldFetchValue; _offset:PtrUint; dtype:TsrDataType; max:DWORD; begin buf:=nil; _start: dtype:=pChain.dtype; if (buf=nil) then begin buf:=BufferList.Fetch(pChain.parent,0,pChain.Flags.GLC,pChain.Flags.SLC); end else begin buf:=BufferList.NextAlias(buf,pChain.Flags.GLC,pChain.Flags.SLC); end; UndoIndex(pChain); _offset:=pChain.offset; if (pChain.pIndex<>nil) then begin //TODO: interval analize if pChain.Parent.IsLocalDataShare or pChain.Parent.IsGlobalDataShare then begin //fixed to 64KB //FLDS_SIZE max:=0; case pChain.Parent.key.rtype of rtLDS: begin max:=32*1024; if (max>FLDS_SIZE) then max:=FLDS_SIZE; end; rtGDS:max:=64*1024; end; if (max=0) then begin Assert(false,'Access to LDS/GDS and the maximum is 0?'); end; if (Align(_offset,pChain.stride)>max) then begin Assert(false,'LDS/GDS big addresing?'); end; Assert(pChain.stride<>0); F:=buf.FTop.FetchArray(_offset,(max-_offset),pChain.stride); end else begin Assert(pChain.stride<>0); F:=buf.FTop.FetchRuntimeArray(_offset,pChain.stride); end; goto _resolve; end else begin F.pField:=buf.FTop; end; repeat F:=F.pField.FetchValue(_offset,pChain.size,dtype,pChain.dweak); _resolve: Case F.fValue of frNotFit :goto _start; //next alias frIdent :goto _exit; frVectorAsValue:goto _exit; frValueInVector: begin _offset:=_offset-F.pField.offset; //patch dtype dtype:=F.pField.Fdtype.Child; end; frValueInArray : begin ShiftIndex(pChain,F,_offset); end; end; until false; _exit: Result:=F.pField; end; function TSprvEmit_post.OnChainField(node:TsrChain):Integer; var pField:TsrField; begin Result:=1; //Writeln('OnChainsField:',dtype,':',node^.key.offset); pField:=FetchField(node); Assert(pField<>nil); node.pField :=pField; //save link node.dtype :=pField.Fdtype; //update type node.pBuffer:=pField.pBuffer; //save buffer end; procedure TSprvEmit_post.OnFieldType(node:TsrField); var count:PtrUint; items:PPsrType; sType,vType:TsrType; child:TsrField; begin if (node.vType<>nil) then Exit; if (node.Fdtype in [dtTypeStruct,dtTypeArray,dtTypeRuntimeArray]) then begin if node.IsStructNotUsed then begin child:=node.First; Assert(child<>nil); Assert(child.vType<>nil); sType:=child.vType; end else begin count:=node.FCount; Assert(count<>0); items:=Alloc(SizeOf(Pointer)*count); count:=0; child:=node.First; While (child<>nil) do begin Assert(child.vType<>nil); items[count]:=child.vType; Inc(count); child:=node.Next(child); end; if node.IsTop then begin //on top level stride is unknow sType:=TypeList.InsertStruct(count,items,False,node.Size); //unique end else begin sType:=TypeList.FetchStruct (count,items,False,node.stride); end; end; Case node.Fdtype of dtTypeArray: begin count:=node.count; vType:=TypeList.FetchArray(sType,count); end; dtTypeRuntimeArray: begin vType:=TypeList.FetchRuntimeArray(sType); end; else begin vType:=sType; end; end; node.sType:=sType; node.vType:=vType; if node.IsTop then begin //Alloc Type Var node.pBuffer.pType:=vType; end; end else begin node.sType:=nil; node.vType:=TypeList.Fetch(node.Fdtype); end; end; procedure TSprvEmit_post.AdjustMaxSize(tbuf:TsrBuffer); var node:TsrBuffer; max,size:Ptruint; begin node:=tbuf; max:=0; while (node<>nil) do begin size:=node.GetSize; if (size>max) then begin max:=size; end; // node:=node.pNextAlias; end; // size:=tbuf.GetSize; if (max>size) then begin if (max>=High(WORD)) then begin //runtime array fill tbuf.FTop.FetchRuntimeArray(size,4); end else begin //fixed fill tbuf.FTop.FillNode(size,max-size); end; // tbuf.EnumAllField(@OnFieldType); end; end; function TSprvEmit_post.LinkBitcast(pBuffer:TsrBuffer):TsrNode; var pLine:TspirvOp; tbuf:TsrBuffer; tref:TsrNode; pType:TsrType; begin Result:=pBuffer.pVar; //direct if pBuffer.pLayout.UseBitcast then if pBuffer.Flags.Aliased then if (pBuffer.AliasId<>0) then begin pLine:=init_line; //zero alias tbuf:=BufferList.Fetch(pBuffer.pLayout,0,False,False); tref:=tbuf.tRef; if (tref=nil) then begin //calc max size AdjustMaxSize(tbuf); Assert(tbuf.FTop.vType<>nil); Assert(tbuf.pVar<>nil); //OpAccessChain storage class link tref:=specialize New; TsrChain(tref).pBuffer:=tbuf; //self ref pLine:=OpAccessChain(pLine,tbuf.FTop.vType,tref,tbuf.pVar); //cache tbuf.tRef:=tref; tbuf.Flags.Bitcast:=True; end; Result:=pBuffer.tRef; if (Result=nil) then begin Assert(pBuffer.FTop.vType<>nil); Assert(pBuffer.pVar<>nil); //OpAccessChain storage class link Result:=specialize New; TsrChain(Result).pBuffer:=pBuffer; //bitcast pointer to this alias pType:=TypeList.FetchPointer(pBuffer.FTop.vType,pBuffer.pVar.GetStorageClass); pLine:=OpBitcast(pLine,pType,Result,tref); //cache pBuffer.tRef:=Result; pBuffer.Flags.Bitcast:=True; end; end; end; function TSprvEmit_post.OnChainAlloc(node:TsrChain):Integer; var pLine:TspirvOp; pIndex:TsrRegNode; pReg:TsrRegNode; pField:TsrField; Parent:TsrField; src:TsrNode; pParam:POpParamNode; begin Result:=1; pField:=node.pField; Assert(pField<>nil); //Make Bitcast type or directly src:=LinkBitcast(pField.pBuffer); Assert(src<>nil); // //get line after LinkBitcast pIndex:=RegDown(node.pIndex); if (pIndex=nil) or (pIndex.is_const) then begin pLine:=init_line; end else begin pLine:=node.FirstLine; Assert(pLine<>nil); pLine:=pLine.Prev; Assert(pLine<>nil); end; //restore pIndex:=node.pIndex; pLine:=OpAccessChain(pLine,pField.vType,node,src); pParam:=pLine.ParamLast; repeat Parent:=pField.pParent; if (Parent<>nil) then Case Parent.Fdtype of dtTypeStruct: begin pReg:=NewImm_i(dtUint32,pField.FID,pLine); pLine.AddParamAfter(pParam,pReg); end; dtTypeArray, dtTypeRuntimeArray: begin if not Parent.IsStructNotUsed then begin pReg:=NewImm_i(dtUint32,pField.FID,pLine); pLine.AddParamAfter(pParam,pReg); end; Assert(pIndex<>nil); pLine.AddParamAfter(pParam,pIndex); end; else if Parent.Fdtype.isVector then begin pReg:=NewImm_i(dtUint32,pField.FID,pLine); pLine.AddParamAfter(pParam,pReg); end; end; pField:=Parent; until (pField=nil); end; function TSprvEmit_post.PostConstAnalize:Integer; var node:TsrConst; begin Result:=0; node:=ConstList.FList.pTail; While (node<>nil) do begin if (not node.IsUsed) then begin ConstList.FList.Remove(node); //remove? Inc(Result); end; node:=node.Prev; end; end; function TSprvEmit_post.PostVariableAnalize:Integer; var node:TsrVariable; begin Result:=0; node:=VariableList.FList.pTail; While (node<>nil) do begin if (not node.IsUsed) then begin VariableList.FList.Remove(node); //remove? Inc(Result); end else begin node.UpdateType(); end; node:=node.Prev; end; end; function TSprvEmit_post.PostTypeAnalize:Integer; var node:TsrType; begin Result:=0; node:=TypeList.FList.pTail; While (node<>nil) do begin if (not node.IsUsed) then begin TypeList.FList.Remove(node); //remove? Inc(Result); end; node:=node.Prev; end; end; end.