private static void EmitIscadd(ShaderIrBlock block, long opCode, ShaderOper oper) { bool negB = opCode.Read(48); bool negA = opCode.Read(49); ShaderIrNode operA = opCode.Gpr8(), operB; ShaderIrOperImm scale = opCode.Imm5_39(); switch (oper) { case ShaderOper.Cr: operB = opCode.Cbuf34(); break; case ShaderOper.Imm: operB = opCode.Imm19_20(); break; case ShaderOper.Rr: operB = opCode.Gpr20(); break; default: throw new ArgumentException(nameof(oper)); } operA = GetAluIneg(operA, negA); operB = GetAluIneg(operB, negB); ShaderIrOp scaleOp = new ShaderIrOp(ShaderIrInst.Lsl, operA, scale); ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, operB, scaleOp); block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp))); }
private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { bool NegB = OpCode.Read(48); bool NegA = OpCode.Read(49); ShaderIrNode OperA = OpCode.Gpr8(), OperB; ShaderIrOperImm Scale = OpCode.Imm5_39(); switch (Oper) { case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; case ShaderOper.RR: OperB = OpCode.Gpr20(); break; default: throw new ArgumentException(nameof(Oper)); } OperA = GetAluIneg(OperA, NegA); OperB = GetAluIneg(OperB, NegB); ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale); ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp))); }
public static void Mov_S(ShaderIrBlock block, long opCode, int position) { block.AddNode(new ShaderIrCmnt("Stubbed.")); //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS ShaderIrNode source = new ShaderIrOperImm(0); block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), source))); }
public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position) { Block.AddNode(new ShaderIrCmnt("Stubbed.")); //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS ShaderIrNode Source = new ShaderIrOperImm(0); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Source), OpCode)); }
private static void EmitBfe(ShaderIrBlock block, long opCode, ShaderOper oper) { //TODO: Handle the case where position + length //is greater than the word size, in this case the sign bit //needs to be replicated to fill the remaining space. bool negB = opCode.Read(48); bool negA = opCode.Read(49); ShaderIrNode operA = opCode.Gpr8(), operB; switch (oper) { case ShaderOper.Cr: operB = opCode.Cbuf34(); break; case ShaderOper.Imm: operB = opCode.Imm19_20(); break; case ShaderOper.Rr: operB = opCode.Gpr20(); break; default: throw new ArgumentException(nameof(oper)); } ShaderIrNode op; bool signed = opCode.Read(48); //? if (operB is ShaderIrOperImm posLen) { int position = (posLen.Value >> 0) & 0xff; int length = (posLen.Value >> 8) & 0xff; int lSh = 32 - (position + length); ShaderIrInst rightShift = signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; op = new ShaderIrOp(ShaderIrInst.Lsl, operA, new ShaderIrOperImm(lSh)); op = new ShaderIrOp(rightShift, op, new ShaderIrOperImm(lSh + position)); } else { ShaderIrOperImm shift = new ShaderIrOperImm(8); ShaderIrOperImm mask = new ShaderIrOperImm(0xff); ShaderIrNode opPos, opLen; opPos = new ShaderIrOp(ShaderIrInst.And, operB, mask); opLen = new ShaderIrOp(ShaderIrInst.Lsr, operB, shift); opLen = new ShaderIrOp(ShaderIrInst.And, opLen, mask); op = new ShaderIrOp(ShaderIrInst.Lsr, operA, opPos); op = ExtendTo32(op, signed, opLen); } block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); }
private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { //TODO: Handle the case where position + length //is greater than the word size, in this case the sign bit //needs to be replicated to fill the remaining space. bool NegB = OpCode.Read(48); bool NegA = OpCode.Read(49); ShaderIrNode OperA = OpCode.Gpr8(), OperB; switch (Oper) { case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; case ShaderOper.RR: OperB = OpCode.Gpr20(); break; default: throw new ArgumentException(nameof(Oper)); } ShaderIrNode Op; bool Signed = OpCode.Read(48); //? if (OperB is ShaderIrOperImm PosLen) { int Position = (PosLen.Value >> 0) & 0xff; int Length = (PosLen.Value >> 8) & 0xff; int LSh = 32 - (Position + Length); ShaderIrInst RightShift = Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; Op = new ShaderIrOp(ShaderIrInst.Lsl, OperA, new ShaderIrOperImm(LSh)); Op = new ShaderIrOp(RightShift, Op, new ShaderIrOperImm(LSh + Position)); } else { ShaderIrOperImm Shift = new ShaderIrOperImm(8); ShaderIrOperImm Mask = new ShaderIrOperImm(0xff); ShaderIrNode OpPos, OpLen; OpPos = new ShaderIrOp(ShaderIrInst.And, OperB, Mask); OpLen = new ShaderIrOp(ShaderIrInst.Lsr, OperB, Shift); OpLen = new ShaderIrOp(ShaderIrInst.And, OpLen, Mask); Op = new ShaderIrOp(ShaderIrInst.Lsr, OperA, OpPos); Op = ExtendTo32(Op, Signed, OpLen); } Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); }
public static void Ssy(ShaderIrBlock block, long opCode, int position) { if ((opCode & 0x20) != 0) { //This reads the target offset from the constant buffer. //Almost impossible to support with GLSL. throw new NotImplementedException(); } ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch()); block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, imm)); }
public static void Bra(ShaderIrBlock Block, long OpCode, int Position) { if ((OpCode & 0x20) != 0) { //This reads the target offset from the constant buffer. //Almost impossible to support with GLSL. throw new NotImplementedException(); } ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch()); Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm))); }
public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, ShaderIrNode Size) { ShaderIrOperImm WordSize = new ShaderIrOperImm(32); ShaderIrOp Shift = new ShaderIrOp(ShaderIrInst.Sub, WordSize, Size); ShaderIrInst RightShift = Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, Shift); Node = new ShaderIrOp(RightShift, Node, Shift); return(Node); }
public static void Bra(ShaderIrBlock Block, long OpCode, long Position) { if ((OpCode & 0x20) != 0) { //This reads the target offset from the constant buffer. //Almost impossible to support with GLSL. throw new NotImplementedException(); } int Target = ((int)(OpCode >> 20) << 8) >> 8; ShaderIrOperImm Imm = new ShaderIrOperImm(Target); Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm), OpCode)); }
public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrOperImm Imm = OpCode.Imm32_20(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm))); }
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 EmitI2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { IntType Type = GetIntType(OpCode); if (Type == IntType.U64 || Type == IntType.S64) { //TODO: 64-bits support. //Note: GLSL doesn't support 64-bits integers. throw new NotImplementedException(); } int Sel = (int)(OpCode >> 41) & 3; bool NegA = ((OpCode >> 45) & 1) != 0; bool AbsA = ((OpCode >> 49) & 1) != 0; bool SatA = ((OpCode >> 50) & 1) != 0; ShaderIrNode OperA; switch (Oper) { case ShaderOper.CR: OperA = GetOperCbuf34(OpCode); break; case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break; case ShaderOper.RR: OperA = GetOperGpr20(OpCode); break; default: throw new ArgumentException(nameof(Oper)); } OperA = GetAluIabsIneg(OperA, AbsA, NegA); bool Signed = Type >= IntType.S8; int Shift = Sel * 8; int Size = 8 << ((int)Type & 3); if (Shift != 0) { OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift)); } if (Size < 32) { uint Mask = uint.MaxValue >> (32 - Size); if (SatA) { uint CMin = 0; uint CMax = Mask; if (Signed) { uint HalfMask = Mask >> 1; CMin -= HalfMask + 1; CMax = HalfMask; } ShaderIrOperImm IMin = new ShaderIrOperImm((int)CMin); ShaderIrOperImm IMax = new ShaderIrOperImm((int)CMax); OperA = new ShaderIrOp(Signed ? ShaderIrInst.Clamps : ShaderIrInst.Clampu, OperA, IMin, IMax); } else { OperA = ExtendTo32(OperA, Signed, Size); } } Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); }
private static void EmitSet(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) { bool negA = opCode.Read(43); bool absB = opCode.Read(44); bool negB = opCode.Read(53); bool absA = opCode.Read(54); bool boolFloat = opCode.Read(isFloat ? 52 : 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 = GetAluFabsFneg(operB, absB, negB); cmpInst = opCode.CmpF(); } else { cmpInst = opCode.Cmp(); } ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB); ShaderIrInst lopInst = opCode.BLop45(); ShaderIrOperPred pNode = opCode.Pred39(); ShaderIrNode imm0, imm1; if (boolFloat) { imm0 = new ShaderIrOperImmf(0); imm1 = new ShaderIrOperImmf(1); } else { imm0 = new ShaderIrOperImm(0); imm1 = new ShaderIrOperImm(-1); } ShaderIrNode asg0 = new ShaderIrAsg(opCode.Gpr0(), imm0); ShaderIrNode asg1 = new ShaderIrAsg(opCode.Gpr0(), imm1); if (lopInst != ShaderIrInst.Band || !pNode.IsConst) { ShaderIrOp op2 = new ShaderIrOp(lopInst, op, pNode); asg0 = new ShaderIrCond(op2, asg0, not: true); asg1 = new ShaderIrCond(op2, asg1, not: false); } else { asg0 = new ShaderIrCond(op, asg0, not: true); asg1 = new ShaderIrCond(op, asg1, not: false); } block.AddNode(opCode.PredNode(asg0)); block.AddNode(opCode.PredNode(asg1)); }
public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrOperImm Imm = GetOperImm32_20(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode)); }
private static void EmitI2I(ShaderIrBlock block, long opCode, ShaderOper oper) { IntType type = GetIntType(opCode); if (type == IntType.U64 || type == IntType.S64) { //TODO: 64-bits support. //Note: GLSL doesn't support 64-bits integers. throw new NotImplementedException(); } int sel = opCode.Read(41, 3); bool negA = opCode.Read(45); bool absA = opCode.Read(49); bool satA = opCode.Read(50); ShaderIrNode operA; switch (oper) { case ShaderOper.Cr: operA = opCode.Cbuf34(); break; case ShaderOper.Immf: operA = opCode.Immf19_20(); break; case ShaderOper.Rr: operA = opCode.Gpr20(); break; default: throw new ArgumentException(nameof(oper)); } operA = GetAluIabsIneg(operA, absA, negA); bool signed = type >= IntType.S8; int shift = sel * 8; int size = 8 << ((int)type & 3); if (shift != 0) { operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift)); } if (size < 32) { uint mask = uint.MaxValue >> (32 - size); if (satA) { uint cMin = 0; uint cMax = mask; if (signed) { uint halfMask = mask >> 1; cMin -= halfMask + 1; cMax = halfMask; } ShaderIrOperImm min = new ShaderIrOperImm((int)cMin); ShaderIrOperImm max = new ShaderIrOperImm((int)cMax); operA = new ShaderIrOp(signed ? ShaderIrInst.Clamps : ShaderIrInst.Clampu, operA, min, max); } else { operA = ExtendTo32(operA, signed, size); } } block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); }
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 Mov_I32(ShaderIrBlock block, long opCode, int position) { ShaderIrOperImm imm = opCode.Imm32_20(); block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm))); }
private static void EmitXmad(ShaderIrBlock block, long opCode, ShaderOper oper) { bool signedA = opCode.Read(48); bool signedB = 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; switch (oper) { case ShaderOper.Cr: operB = opCode.Cbuf34(); break; case ShaderOper.Imm: operB = opCode.ImmU16_20(); break; case ShaderOper.Rc: operB = opCode.Gpr39(); break; case ShaderOper.Rr: operB = opCode.Gpr20(); break; default: throw new ArgumentException(nameof(oper)); } ShaderIrNode operB2 = operB; if (oper == ShaderOper.Imm) { int imm = ((ShaderIrOperImm)operB2).Value; if (!highB) { imm <<= 16; } if (signedB) { imm >>= 16; } else { imm = (int)((uint)imm >> 16); } operB2 = new ShaderIrOperImm(imm); } ShaderIrOperImm imm16 = new ShaderIrOperImm(16); //If we are working with the lower 16-bits of the A/B operands, //we need to shift the lower 16-bits to the top 16-bits. Later, //they will be right shifted. For U16 types, this will be a logical //right shift, and for S16 types, a arithmetic right shift. if (!highA) { operA = new ShaderIrOp(ShaderIrInst.Lsl, operA, imm16); } if (!highB && oper != ShaderOper.Imm) { operB2 = new ShaderIrOp(ShaderIrInst.Lsl, operB2, imm16); } ShaderIrInst shiftA = signedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr; ShaderIrInst shiftB = signedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr; operA = new ShaderIrOp(shiftA, operA, imm16); if (oper != ShaderOper.Imm) { operB2 = new ShaderIrOp(shiftB, operB2, imm16); } bool productShiftLeft = false; bool merge = false; if (oper == ShaderOper.Rc) { operC = opCode.Cbuf34(); } else { operC = opCode.Gpr39(); productShiftLeft = opCode.Read(36); merge = opCode.Read(37); } ShaderIrOp mulOp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB2); if (productShiftLeft) { mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16); } switch ((XmadMode)mode) { case XmadMode.Clo: operC = ExtendTo32(operC, signed: false, size: 16); break; case XmadMode.Chi: operC = new ShaderIrOp(ShaderIrInst.Lsr, operC, imm16); break; case XmadMode.Cbcc: { ShaderIrOp operBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16); operC = new ShaderIrOp(ShaderIrInst.Add, operC, operBLsh16); break; } case XmadMode.Csfu: { ShaderIrOperImm imm31 = new ShaderIrOperImm(31); ShaderIrOp signAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, operA, imm31); ShaderIrOp signAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, operB2, imm31); signAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustA, imm16); signAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustB, imm16); ShaderIrOp signAdjust = new ShaderIrOp(ShaderIrInst.Add, signAdjustA, signAdjustB); operC = new ShaderIrOp(ShaderIrInst.Sub, operC, signAdjust); break; } } ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, mulOp, operC); if (merge) { ShaderIrOperImm imm16Mask = new ShaderIrOperImm(0xffff); addOp = new ShaderIrOp(ShaderIrInst.And, addOp, imm16Mask); 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 EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) { bool NegA = OpCode.Read(43); bool AbsB = OpCode.Read(44); bool NegB = OpCode.Read(53); bool AbsA = OpCode.Read(54); bool BoolFloat = OpCode.Read(IsFloat ? 52 : 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 = GetAluFabsFneg(OperB, AbsB, NegB); CmpInst = OpCode.CmpF(); } else { CmpInst = OpCode.Cmp(); } ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB); ShaderIrInst LopInst = OpCode.BLop45(); ShaderIrOperPred PNode = OpCode.Pred39(); ShaderIrNode Imm0, Imm1; if (BoolFloat) { Imm0 = new ShaderIrOperImmf(0); Imm1 = new ShaderIrOperImmf(1); } else { Imm0 = new ShaderIrOperImm(0); Imm1 = new ShaderIrOperImm(-1); } ShaderIrNode Asg0 = new ShaderIrAsg(OpCode.Gpr0(), Imm0); ShaderIrNode Asg1 = new ShaderIrAsg(OpCode.Gpr0(), Imm1); if (LopInst != ShaderIrInst.Band || !PNode.IsConst) { ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode); Asg0 = new ShaderIrCond(Op2, Asg0, Not: true); Asg1 = new ShaderIrCond(Op2, Asg1, Not: false); } else { Asg0 = new ShaderIrCond(Op, Asg0, Not: true); Asg1 = new ShaderIrCond(Op, Asg1, Not: false); } Block.AddNode(OpCode.PredNode(Asg0)); Block.AddNode(OpCode.PredNode(Asg1)); }
private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { bool SignedA = OpCode.Read(48); bool SignedB = 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; switch (Oper) { case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; case ShaderOper.Imm: OperB = OpCode.ImmU16_20(); break; case ShaderOper.RC: OperB = OpCode.Gpr39(); break; case ShaderOper.RR: OperB = OpCode.Gpr20(); break; default: throw new ArgumentException(nameof(Oper)); } ShaderIrNode OperB2 = OperB; if (Oper == ShaderOper.Imm) { int Imm = ((ShaderIrOperImm)OperB2).Value; if (!HighB) { Imm <<= 16; } if (SignedB) { Imm >>= 16; } else { Imm = (int)((uint)Imm >> 16); } OperB2 = new ShaderIrOperImm(Imm); } ShaderIrOperImm Imm16 = new ShaderIrOperImm(16); //If we are working with the lower 16-bits of the A/B operands, //we need to shift the lower 16-bits to the top 16-bits. Later, //they will be right shifted. For U16 types, this will be a logical //right shift, and for S16 types, a arithmetic right shift. if (!HighA) { OperA = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Imm16); } if (!HighB && Oper != ShaderOper.Imm) { OperB2 = new ShaderIrOp(ShaderIrInst.Lsl, OperB2, Imm16); } ShaderIrInst ShiftA = SignedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr; ShaderIrInst ShiftB = SignedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr; OperA = new ShaderIrOp(ShiftA, OperA, Imm16); if (Oper != ShaderOper.Imm) { OperB2 = new ShaderIrOp(ShiftB, OperB2, Imm16); } bool ProductShiftLeft = false; bool Merge = false; if (Oper == ShaderOper.RC) { OperC = OpCode.Cbuf34(); } else { OperC = OpCode.Gpr39(); ProductShiftLeft = OpCode.Read(36); Merge = OpCode.Read(37); } ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB2); if (ProductShiftLeft) { MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16); } switch ((XmadMode)Mode) { case XmadMode.Clo: OperC = ExtendTo32(OperC, Signed: false, Size: 16); break; case XmadMode.Chi: OperC = new ShaderIrOp(ShaderIrInst.Lsr, OperC, Imm16); break; case XmadMode.Cbcc: { ShaderIrOp OperBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16); OperC = new ShaderIrOp(ShaderIrInst.Add, OperC, OperBLsh16); break; } case XmadMode.Csfu: { ShaderIrOperImm Imm31 = new ShaderIrOperImm(31); ShaderIrOp SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, OperA, Imm31); ShaderIrOp SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, OperB2, Imm31); SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustA, Imm16); SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustB, Imm16); ShaderIrOp SignAdjust = new ShaderIrOp(ShaderIrInst.Add, SignAdjustA, SignAdjustB); OperC = new ShaderIrOp(ShaderIrInst.Sub, OperC, SignAdjust); break; } } ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC); if (Merge) { ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff); AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask); OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16); AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB); } Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp))); }