public static void Mov_C(ShaderIrBlock Block, long OpCode) { ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Cbuf), OpCode)); }
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position) { EmitFsetp(Block, OpCode, ShaderOper.RR); }
public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position) { EmitBfe(Block, OpCode, ShaderOper.CR); }
private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) { bool AbsA = OpCode.Read(7); bool NegP = OpCode.Read(42); bool NegA = OpCode.Read(43); bool AbsB = OpCode.Read(44); ShaderIrNode OperA = OpCode.Gpr8(), OperB; switch (Oper) { case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; case ShaderOper.RR: OperB = OpCode.Gpr20(); break; default: throw new ArgumentException(nameof(Oper)); } ShaderIrInst CmpInst; if (IsFloat) { OperA = GetAluFabsFneg(OperA, AbsA, NegA); OperB = GetAluFabs(OperB, AbsB); CmpInst = OpCode.CmpF(); } else { CmpInst = OpCode.Cmp(); } ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB); ShaderIrOperPred P0Node = OpCode.Pred3(); ShaderIrOperPred P1Node = OpCode.Pred0(); ShaderIrOperPred P2Node = OpCode.Pred39(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); ShaderIrInst LopInst = OpCode.BLop45(); if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst) { return; } ShaderIrNode P2NNode = P2Node; if (NegP) { P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode); } Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node); Op = new ShaderIrOp(LopInst, Op, P2NNode); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op))); Op = new ShaderIrOp(LopInst, P0Node, P2NNode); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); }
private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { //TODO: Confirm SignAB/C, it is just a guess. //TODO: Implement Mode 3 (CSFU), what it does? bool SignAB = OpCode.Read(48); bool SignC = OpCode.Read(49); bool HighB = OpCode.Read(52); bool HighA = OpCode.Read(53); int Mode = OpCode.Read(50, 7); ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC; ShaderIrOperImm Imm16 = new ShaderIrOperImm(16); ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff); ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr; ShaderIrInst ShiftC = SignC ? ShaderIrInst.Asr : ShaderIrInst.Lsr; if (HighA) { OperA = new ShaderIrOp(ShiftAB, OperA, Imm16); } switch (Oper) { case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; case ShaderOper.RC: OperB = OpCode.Gpr39(); break; case ShaderOper.RR: OperB = OpCode.Gpr20(); break; default: throw new ArgumentException(nameof(Oper)); } bool ProductShiftLeft = false, Merge = false; if (Oper == ShaderOper.RC) { OperC = OpCode.Cbuf34(); } else { OperC = OpCode.Gpr39(); ProductShiftLeft = OpCode.Read(36); Merge = OpCode.Read(37); } switch (Mode) { //CLO. case 1: OperC = ExtendTo32(OperC, SignC, 16); break; //CHI. case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break; } ShaderIrNode OperBH = OperB; if (HighB) { OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16); } ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH); if (ProductShiftLeft) { MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16); } ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC); if (Merge) { AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk); OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16); AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB); } if (Mode == 4) { OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16); AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB); } Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp))); }
private static void EmitTexs(ShaderIrBlock block, long opCode, ShaderIrInst inst, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix) { if (inst == ShaderIrInst.Txlf && textureTarget == GalTextureTarget.CubeArray) { throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); } bool isArray = ImageUtils.IsArray(textureTarget); ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; ShaderIrOperGpr operA = opCode.Gpr8(); ShaderIrOperGpr operB = opCode.Gpr20(); ShaderIrOperGpr suffixExtra = opCode.Gpr20(); suffixExtra.Index += 1; int coordStartIndex = 0; if (isArray) { coordStartIndex++; coords[coords.Length - 1] = opCode.Gpr8(); } switch (coords.Length - coordStartIndex) { case 1: coords[0] = opCode.Gpr8(); break; case 2: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; break; case 3: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; coords[1] = opCode.Gpr8(); coords[1].Index += 1 + coordStartIndex; break; default: throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TEXS"); } int operBIndex = 0; ShaderIrOperGpr levelOfDetail = null; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; // OperB is always the last value // Not applicable to 1d textures if (coords.Length - coordStartIndex != 1) { coords[coords.Length - coordStartIndex - 1] = operB; operBIndex++; } // Encoding of TEXS/TLDS is a bit special and change for 2d textures // NOTE: OperA seems to hold at best two args. // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. if (textureInstructionSuffix != TextureInstructionSuffix.None && textureInstructionSuffix != TextureInstructionSuffix.Lz && textureTarget == GalTextureTarget.TwoD) { coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; operBIndex--; } // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?) if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0) { levelOfDetail = opCode.Gpr20(); levelOfDetail.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } int lutIndex; lutIndex = !opCode.Gpr0().IsConst ? 1 : 0; lutIndex |= !opCode.Gpr28().IsConst ? 2 : 0; if (lutIndex == 0) { //Both destination registers are RZ, do nothing. return; } bool fp16 = !opCode.Read(59); int dstIncrement = 0; ShaderIrOperGpr GetDst() { ShaderIrOperGpr dst; if (fp16) { //FP16 mode, two components are packed on the two //halfs of a 32-bits register, as two half-float values. int halfPart = dstIncrement & 1; switch (lutIndex) { case 1: dst = opCode.GprHalf0(halfPart); break; case 2: dst = opCode.GprHalf28(halfPart); break; case 3: dst = (dstIncrement >> 1) != 0 ? opCode.GprHalf28(halfPart) : opCode.GprHalf0(halfPart); break; default: throw new InvalidOperationException(); } } else { //32-bits mode, each component uses one register. //Two components uses two consecutive registers. switch (lutIndex) { case 1: dst = opCode.Gpr0(); break; case 2: dst = opCode.Gpr28(); break; case 3: dst = (dstIncrement >> 1) != 0 ? opCode.Gpr28() : opCode.Gpr0(); break; default: throw new InvalidOperationException(); } dst.Index += dstIncrement & 1; } dstIncrement++; return(dst); } int chMask = _maskLut[lutIndex, opCode.Read(50, 7)]; if (chMask == 0) { //All channels are disabled, do nothing. return; } ShaderIrNode operC = opCode.Imm13_36(); coords = CoordsRegistersToTempRegisters(block, coords); for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { LevelOfDetail = levelOfDetail, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(inst, operA, operB, operC, meta); ShaderIrOperGpr dst = GetDst(); if (dst.IsValidRegister && !dst.IsConst) { block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } } }
private ShaderIrBlock PrintNodes( ShaderIrBlock Block, ShaderIrBlock EndBlock, ShaderIrBlock LoopBlock, string Identation, params ShaderIrNode[] Nodes) { /* * Notes about control flow and if-else/loop generation: * The code assumes that the program has sane control flow, * that is, there's no jumps to a location after another jump or * jump target (except for the end of an if-else block), and backwards * jumps to a location before the last loop dominator. * Such cases needs to be transformed on a step before the GLSL code * generation to ensure that we have sane graphs to work with. * TODO: Such transformation is not yet implemented. */ string NewIdent = Identation + IdentationStr; ShaderIrBlock LoopTail = GetLoopTailBlock(Block); if (LoopTail != null && LoopBlock != Block) { //Shoock! kuma shock! We have a loop here! //The entire sequence needs to be inside a do-while block. ShaderIrBlock LoopEnd = GetDownBlock(LoopTail); PrintBlockScope(Block, LoopEnd, Block, "while (false)", NewIdent, IsDoWhile: true); return(LoopEnd); } foreach (ShaderIrNode Node in Nodes) { if (Node is ShaderIrCond Cond) { string IfExpr = GetSrcExpr(Cond.Pred, true); if (Cond.Not) { IfExpr = "!(" + IfExpr + ")"; } if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra) { //Branch is a loop branch and would result in infinite recursion. if (Block.Branch.Position <= Block.Position) { SB.AppendLine(Identation + "if (" + IfExpr + ") {"); SB.AppendLine(Identation + IdentationStr + "continue;"); SB.AppendLine(Identation + "}"); continue; } string SubScopeName = "if (!" + IfExpr + ")"; PrintBlockScope(Block.Next, Block.Branch, LoopBlock, SubScopeName, NewIdent); ShaderIrBlock IfElseEnd = GetUpBlock(Block.Branch).Branch; if (IfElseEnd?.Position > Block.Branch.Position) { PrintBlockScope(Block.Branch, IfElseEnd, LoopBlock, "else", NewIdent); return(IfElseEnd); } return(Block.Branch); } else { SB.AppendLine(Identation + "if (" + IfExpr + ") {"); PrintNodes(Block, EndBlock, LoopBlock, NewIdent, Cond.Child); SB.AppendLine(Identation + "}"); } }
public static void Ffma_RR(ShaderIrBlock Block, long OpCode) { EmitAluFfma(Block, OpCode, ShaderOper.RR); }
public static void Fmul_R(ShaderIrBlock Block, long OpCode) { EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul); }
public static void Shr_R(ShaderIrBlock Block, long OpCode) { EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode)); }
private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) { bool Aa = ((OpCode >> 7) & 1) != 0; bool Np = ((OpCode >> 42) & 1) != 0; bool Na = ((OpCode >> 43) & 1) != 0; bool Ab = ((OpCode >> 44) & 1) != 0; ShaderIrNode OperA = GetOperGpr8(OpCode), OperB; switch (Oper) { case ShaderOper.CR: OperB = GetOperCbuf34(OpCode); break; case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break; case ShaderOper.RR: OperB = GetOperGpr20(OpCode); break; default: throw new ArgumentException(nameof(Oper)); } ShaderIrInst CmpInst; if (IsFloat) { OperA = GetAluAbsNeg(OperA, Aa, Na); OperB = GetAluAbs(OperB, Ab); CmpInst = GetCmpF(OpCode); } else { CmpInst = GetCmp(OpCode); } ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB); ShaderIrOperPred P0Node = GetOperPred3(OpCode); ShaderIrOperPred P1Node = GetOperPred0(OpCode); ShaderIrOperPred P2Node = GetOperPred39(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); ShaderIrInst LopInst = GetBLop(OpCode); if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst) { return; } ShaderIrNode P2NNode = P2Node; if (Np) { P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode); } Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node); Op = new ShaderIrOp(LopInst, Op, P2NNode); Block.AddNode(GetPredNode(new ShaderIrAsg(P1Node, Op), OpCode)); Op = new ShaderIrOp(LopInst, P0Node, P2NNode); Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); }
public static void Texs(ShaderIrBlock Block, long OpCode) { EmitTexs(Block, OpCode, ShaderIrInst.Texs); }
public static void Tex(ShaderIrBlock Block, long OpCode) { EmitTex(Block, OpCode, GprHandle: false); }
public static void Mov_I(ShaderIrBlock Block, long OpCode) { ShaderIrOperImm Imm = GetOperImm19_20(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode)); }
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) { //TODO: Support other formats. ShaderIrNode OperA = OpCode.Gpr8(); ShaderIrNode OperB = OpCode.Gpr20(); ShaderIrNode OperC = OpCode.Imm13_36(); int LutIndex; LutIndex = OpCode.Gpr0().Index != ShaderIrOperGpr.ZRIndex ? 1 : 0; LutIndex |= OpCode.Gpr28().Index != ShaderIrOperGpr.ZRIndex ? 2 : 0; if (LutIndex == 0) { //Both registers are RZ, color is not written anywhere. //So, the intruction is basically a no-op. return; } int ChMask = MaskLut[LutIndex, OpCode.Read(50, 7)]; for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); } int RegInc = 0; ShaderIrOperGpr GetDst() { ShaderIrOperGpr Dst; switch (LutIndex) { case 1: Dst = OpCode.Gpr0(); break; case 2: Dst = OpCode.Gpr28(); break; case 3: Dst = (RegInc >> 1) != 0 ? OpCode.Gpr28() : OpCode.Gpr0(); break; default: throw new InvalidOperationException(); } Dst.Index += RegInc++ & 1; return(Dst); } for (int Ch = 0; Ch < 4; Ch++) { if (!IsChannelUsed(ChMask, Ch)) { continue; } ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrOperGpr Dst = GetDst(); if (Dst.Index != ShaderIrOperGpr.ZRIndex) { Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Src))); } } }
public static void Fsetp_C(ShaderIrBlock Block, long OpCode) { EmitFsetp(Block, OpCode, ShaderOper.CR); }
private static void EmitTex(ShaderIrBlock block, long opCode, TextureInstructionSuffix textureInstructionSuffix, bool gprHandle) { bool isArray = opCode.HasArray(); GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); bool hasDepthCompare = opCode.Read(0x32); if (hasDepthCompare) { textureInstructionSuffix |= TextureInstructionSuffix.Dc; } ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; int indexExtraCoord = 0; if (isArray) { indexExtraCoord++; coords[coords.Length - 1] = opCode.Gpr8(); } for (int index = 0; index < coords.Length - indexExtraCoord; index++) { ShaderIrOperGpr coordReg = opCode.Gpr8(); coordReg.Index += index; coordReg.Index += indexExtraCoord; if (!coordReg.IsValidRegister) { coordReg.Index = ShaderIrOperGpr.ZrIndex; } coords[index] = coordReg; } int chMask = opCode.Read(31, 0xf); ShaderIrOperGpr levelOfDetail = null; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; // TODO: determine first argument when TEX.B is used int operBIndex = gprHandle ? 1 : 0; if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0 || (textureInstructionSuffix & TextureInstructionSuffix.Lb) != 0 || (textureInstructionSuffix & TextureInstructionSuffix.Lba) != 0 || (textureInstructionSuffix & TextureInstructionSuffix.Lla) != 0) { levelOfDetail = opCode.Gpr20(); levelOfDetail.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } // ??? ShaderIrNode operC = gprHandle ? (ShaderIrNode)opCode.Gpr20() : (ShaderIrNode)opCode.Imm13_36(); ShaderIrInst inst = gprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; coords = CoordsRegistersToTempRegisters(block, coords); int regInc = 0; for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrOperGpr dst = opCode.Gpr0(); dst.Index += regInc++; if (!dst.IsValidRegister || dst.IsConst) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { LevelOfDetail = levelOfDetail, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(inst, coords[0], coords.Length > 1 ? coords[1] : null, operC, meta); block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } }
public static void Fadd_C(ShaderIrBlock Block, long OpCode) { EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd); }
private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar) { ShaderIrOperGpr operA = opCode.Gpr8(); ShaderIrOperGpr operB = opCode.Gpr20(); ShaderIrOperImm operC = opCode.Imm13_36(); ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)]; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; bool isArray = ImageUtils.IsArray(textureType); int operBIndex = 0; if (scalar) { int coordStartIndex = 0; if (isArray) { coordStartIndex++; coords[coords.Length - 1] = operB; } switch (coords.Length - coordStartIndex) { case 1: coords[0] = opCode.Gpr8(); break; case 2: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; break; case 3: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; coords[1] = opCode.Gpr8(); coords[1].Index += 1 + coordStartIndex; break; default: throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S"); } if (coords.Length - coordStartIndex != 1) { coords[coords.Length - coordStartIndex - 1] = operB; operBIndex++; } if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD) { coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; operBIndex--; } } else { int indexExtraCoord = 0; if (isArray) { indexExtraCoord++; coords[coords.Length - 1] = opCode.Gpr8(); } for (int index = 0; index < coords.Length - indexExtraCoord; index++) { coords[index] = opCode.Gpr8(); coords[index].Index += index; coords[index].Index += indexExtraCoord; if (coords[index].Index > ShaderIrOperGpr.ZrIndex) { coords[index].Index = ShaderIrOperGpr.ZrIndex; } } } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } coords = CoordsRegistersToTempRegisters(block, coords); int regInc = 0; for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrOperGpr dst = opCode.Gpr0(); dst.Index += regInc++; if (!dst.IsValidRegister || dst.IsConst) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords) { Component = component, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Tld4, operA, operB, operC, meta); block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } }
public static void Isetp_I(ShaderIrBlock Block, long OpCode) { EmitIsetp(Block, OpCode, ShaderOper.Imm); }
private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { EmitSetp(Block, OpCode, false, Oper); }
private void PrintNode(ShaderIrBlock Block, ShaderIrNode Node, string Identation) { if (Node is ShaderIrCond Cond) { string IfExpr = GetSrcExpr(Cond.Pred, true); if (Cond.Not) { IfExpr = "!(" + IfExpr + ")"; } SB.AppendLine(Identation + "if (" + IfExpr + ") {"); PrintNode(Block, Cond.Child, Identation + IdentationStr); SB.AppendLine(Identation + "}"); } else if (Node is ShaderIrAsg Asg) { if (IsValidOutOper(Asg.Dst)) { string Expr = GetSrcExpr(Asg.Src, true); Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";"); } } else if (Node is ShaderIrOp Op) { switch (Op.Inst) { case ShaderIrInst.Bra: { SB.AppendLine(Identation + "return " + GetBlockPosition(Block.Branch) + ";"); break; } case ShaderIrInst.Emit: { PrintAttrToOutput(Identation); SB.AppendLine(Identation + "EmitVertex();"); break; } case ShaderIrInst.Ssy: { string StackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; int TargetPosition = (Op.OperandA as ShaderIrOperImm).Value; string Target = "0x" + TargetPosition.ToString("x8") + "u"; SB.AppendLine(Identation + StackIndex + " = " + Target + ";"); SB.AppendLine(Identation + GlslDecl.SsyCursorName + "++;"); break; } case ShaderIrInst.Sync: { SB.AppendLine(Identation + GlslDecl.SsyCursorName + "--;"); string Target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; SB.AppendLine(Identation + "return " + Target + ";"); break; } default: SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";"); break; } } else if (Node is ShaderIrCmnt Cmnt) { SB.AppendLine(Identation + "// " + Cmnt.Comment); } else { throw new InvalidOperationException(); } }
public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position) { EmitFmul(Block, OpCode, ShaderOper.CR); }
public static void Exit(ShaderIrBlock Block, long OpCode) { Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode)); }
public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFset(Block, OpCode, ShaderOper.Immf); }
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position) { EmitTex(Block, OpCode, GprHandle: true); }
public static void Hmul2_R(ShaderIrBlock Block, long OpCode, int Position) { EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fmul); }
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position) { EmitTexs(Block, OpCode, ShaderIrInst.Txlf); }
public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd(Block, OpCode, ShaderOper.CR); }
public static void I2i_R(ShaderIrBlock Block, long OpCode) { EmitI2i(Block, OpCode, ShaderOper.RR); }