public static void Mov(EmitterContext context) { OpCodeAlu op = (OpCodeAlu)context.CurrOp; context.Copy(GetDest(context), GetSrcB(context)); }
public static void F2I(EmitterContext context) { OpCodeFArith op = (OpCodeFArith)context.CurrOp; IntegerType intType = (IntegerType)op.RawOpCode.Extract(8, 2); if (intType == IntegerType.U64) { context.Config.PrintLog("Unimplemented 64-bits F2I."); return; } bool isSmallInt = intType <= IntegerType.U16; FPType floatType = (FPType)op.RawOpCode.Extract(10, 2); bool isSignedInt = op.RawOpCode.Extract(12); bool negateB = op.RawOpCode.Extract(45); bool absoluteB = op.RawOpCode.Extract(49); if (isSignedInt) { intType |= IntegerType.S8; } Operand srcB = context.FPAbsNeg(GetSrcB(context, floatType), absoluteB, negateB); switch (op.RoundingMode) { case RoundingMode.ToNearest: srcB = context.FPRound(srcB); break; case RoundingMode.TowardsNegativeInfinity: srcB = context.FPFloor(srcB); break; case RoundingMode.TowardsPositiveInfinity: srcB = context.FPCeiling(srcB); break; case RoundingMode.TowardsZero: srcB = context.FPTruncate(srcB); break; } if (!isSignedInt) { // Negative float to uint cast is undefined, so we clamp // the value before conversion. srcB = context.FPMaximum(srcB, ConstF(0)); } srcB = isSignedInt ? context.FPConvertToS32(srcB) : context.FPConvertToU32(srcB); if (isSmallInt) { int min = (int)GetIntMin(intType); int max = (int)GetIntMax(intType); srcB = isSignedInt ? context.IClampS32(srcB, Const(min), Const(max)) : context.IClampU32(srcB, Const(min), Const(max)); } Operand dest = GetDest(context); context.Copy(dest, srcB); // TODO: CC. }
public static Operand GetDest(EmitterContext context) { return(Register(((IOpCodeRd)context.CurrOp).Rd)); }
public static Operand GetDest2(EmitterContext context) { Register rd = ((IOpCodeRd)context.CurrOp).Rd; return(Register(rd.Index | 1, rd.Type)); }
public static void Sts(EmitterContext context) { EmitStore(context, MemoryRegion.Shared); }
public static Operand GetFromTruthTable(EmitterContext context, Operand srcA, Operand srcB, Operand srcC, int imm) { Operand expr = null; // Handle some simple cases, or cases where // the KMap would yield poor results (like XORs). if (imm == 0x96 || imm == 0x69) { // XOR (0x96) and XNOR (0x69). if (imm == 0x69) { srcA = context.BitwiseNot(srcA); } expr = context.BitwiseExclusiveOr(srcA, srcB); expr = context.BitwiseExclusiveOr(expr, srcC); return(expr); } else if (imm == 0) { // Always false. return(Const(IrConsts.False)); } else if (imm == 0xff) { // Always true. return(Const(IrConsts.True)); } int map; // Encode into gray code. map = ((imm >> 0) & 1) << 0; map |= ((imm >> 1) & 1) << 4; map |= ((imm >> 2) & 1) << 1; map |= ((imm >> 3) & 1) << 5; map |= ((imm >> 4) & 1) << 3; map |= ((imm >> 5) & 1) << 7; map |= ((imm >> 6) & 1) << 2; map |= ((imm >> 7) & 1) << 6; // Solve KMap, get sum of products. int visited = 0; for (int index = 0; index < 8 && visited != 0xff; index++) { if ((map & (1 << index)) == 0) { continue; } int mask = 0; for (int mSize = 4; mSize != 0; mSize >>= 1) { mask = RotateLeft4((1 << mSize) - 1, index & 3) << (index & 4); if ((map & mask) == mask) { break; } } // The mask should wrap, if we are on the high row, shift to low etc. int mask2 = (index & 4) != 0 ? mask >> 4 : mask << 4; if ((map & mask2) == mask2) { mask |= mask2; } if ((mask & visited) == mask) { continue; } bool notA = (mask & 0x33) != 0; bool notB = (mask & 0x99) != 0; bool notC = (mask & 0x0f) != 0; bool aChanges = (mask & 0xcc) != 0 && notA; bool bChanges = (mask & 0x66) != 0 && notB; bool cChanges = (mask & 0xf0) != 0 && notC; Operand localExpr = null; void And(Operand source) { if (localExpr != null) { localExpr = context.BitwiseAnd(localExpr, source); } else { localExpr = source; } } if (!aChanges) { And(context.BitwiseNot(srcA, notA)); } if (!bChanges) { And(context.BitwiseNot(srcB, notB)); } if (!cChanges) { And(context.BitwiseNot(srcC, notC)); } if (expr != null) { expr = context.BitwiseOr(expr, localExpr); } else { expr = localExpr; } visited |= mask; } return(expr); }
public static void Depbar(EmitterContext context) { }
public static void St(EmitterContext context) { EmitStore(context, MemoryRegion.Local); }
public static Operand GetSrcA(EmitterContext context) { return(Register(((IOpCodeRa)context.CurrOp).Ra)); }
public static void Bra(EmitterContext context) { EmitBranch(context, context.CurrBlock.Branch.Address); }
private static void Tex(EmitterContext context, TextureFlags flags) { OpCodeTexture op = (OpCodeTexture)context.CurrOp; bool isBindless = (flags & TextureFlags.Bindless) != 0; bool intCoords = (flags & TextureFlags.IntCoords) != 0; if (op.Rd.IsRZ) { return; } int raIndex = op.Ra.Index; int rbIndex = op.Rb.Index; Operand Ra() { if (raIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(context.Copy(Register(raIndex++, RegisterType.Gpr))); } Operand Rb() { if (rbIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(context.Copy(Register(rbIndex++, RegisterType.Gpr))); } Operand arrayIndex = op.IsArray ? Ra() : null; List <Operand> sourcesList = new List <Operand>(); if (isBindless) { sourcesList.Add(Rb()); } TextureType type = GetTextureType(op.Dimensions); int coordsCount = type.GetCoordsCount(); for (int index = 0; index < coordsCount; index++) { sourcesList.Add(Ra()); } if (op.IsArray) { sourcesList.Add(arrayIndex); type |= TextureType.Array; } bool hasLod = op.LodMode > TextureLodMode.LodZero; Operand lodValue = hasLod ? Rb() : ConstF(0); Operand packedOffs = op.HasOffset ? Rb() : null; if (op.HasDepthCompare) { sourcesList.Add(Rb()); type |= TextureType.Shadow; } if ((op.LodMode == TextureLodMode.LodZero || op.LodMode == TextureLodMode.LodLevel || op.LodMode == TextureLodMode.LodLevelA) && !op.IsMultisample) { sourcesList.Add(lodValue); flags |= TextureFlags.LodLevel; } if (op.HasOffset) { for (int index = 0; index < coordsCount; index++) { sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4))); } flags |= TextureFlags.Offset; } if (op.LodMode == TextureLodMode.LodBias || op.LodMode == TextureLodMode.LodBiasA) { sourcesList.Add(lodValue); flags |= TextureFlags.LodBias; } if (op.IsMultisample) { sourcesList.Add(Rb()); type |= TextureType.Multisample; } Operand[] sources = sourcesList.ToArray(); int rdIndex = op.Rd.Index; Operand GetDest() { if (rdIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(Register(rdIndex++, RegisterType.Gpr)); } int handle = !isBindless ? op.Immediate : 0; for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) { if ((compMask & 1) != 0) { Operand dest = GetDest(); TextureOperation operation = new TextureOperation( Instruction.TextureSample, type, flags, handle, compIndex, dest, sources); context.Add(operation); } } }
private static void Txq(EmitterContext context, bool bindless) { OpCodeTex op = (OpCodeTex)context.CurrOp; if (op.Rd.IsRZ) { return; } TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6); // TODO: Validate and use property. Instruction inst = Instruction.TextureSize; TextureType type = TextureType.Texture2D; TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None; int raIndex = op.Ra.Index; Operand Ra() { if (raIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(context.Copy(Register(raIndex++, RegisterType.Gpr))); } List <Operand> sourcesList = new List <Operand>(); if (bindless) { sourcesList.Add(Ra()); } sourcesList.Add(Ra()); Operand[] sources = sourcesList.ToArray(); int rdIndex = op.Rd.Index; Operand GetDest() { if (rdIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(Register(rdIndex++, RegisterType.Gpr)); } int handle = !bindless ? op.Immediate : 0; for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) { if ((compMask & 1) != 0) { Operand dest = GetDest(); TextureOperation operation = new TextureOperation( inst, type, flags, handle, compIndex, dest, sources); context.Add(operation); } } }
public static void Txq_B(EmitterContext context) { Txq(context, bindless: true); }
public static void Txq(EmitterContext context) { Txq(context, bindless: false); }
public static void Kil(EmitterContext context) { context.Discard(); }
public static void Lds(EmitterContext context) { EmitLoad(context, MemoryRegion.Shared); }
public static void Nop(EmitterContext context) { }
public static void Stg(EmitterContext context) { EmitStoreGlobal(context); }
public static void Ssy(EmitterContext context) { EmitPbkOrSsy(context); }
private static Operand EmitAtomicOp( EmitterContext context, Instruction mr, AtomicOp op, ReductionType type, Operand addrLow, Operand addrHigh, Operand value) { Operand res = Const(0); switch (op) { case AtomicOp.Add: if (type == ReductionType.S32 || type == ReductionType.U32) { res = context.AtomicAdd(mr, addrLow, addrHigh, value); } else { context.Config.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; case AtomicOp.BitwiseAnd: if (type == ReductionType.S32 || type == ReductionType.U32) { res = context.AtomicAnd(mr, addrLow, addrHigh, value); } else { context.Config.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; case AtomicOp.BitwiseExclusiveOr: if (type == ReductionType.S32 || type == ReductionType.U32) { res = context.AtomicXor(mr, addrLow, addrHigh, value); } else { context.Config.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; case AtomicOp.BitwiseOr: if (type == ReductionType.S32 || type == ReductionType.U32) { res = context.AtomicOr(mr, addrLow, addrHigh, value); } else { context.Config.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; case AtomicOp.Maximum: if (type == ReductionType.S32) { res = context.AtomicMaxS32(mr, addrLow, addrHigh, value); } else if (type == ReductionType.U32) { res = context.AtomicMaxU32(mr, addrLow, addrHigh, value); } else { context.Config.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; case AtomicOp.Minimum: if (type == ReductionType.S32) { res = context.AtomicMinS32(mr, addrLow, addrHigh, value); } else if (type == ReductionType.U32) { res = context.AtomicMinU32(mr, addrLow, addrHigh, value); } else { context.Config.GpuAccessor.Log($"Invalid reduction type: {type}."); } break; } return(res); }
public static void Sync(EmitterContext context) { EmitBrkOrSync(context); }
public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits) { return(context.BitfieldExtractS32(src, Const(0), Const(srcBits))); }
public static void Al2p(EmitterContext context) { InstAl2p op = context.GetOp <InstAl2p>(); context.Copy(GetDest(op.Dest), context.IAdd(GetSrcReg(context, op.SrcA), Const(op.Imm11))); }
public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits) { int mask = (int)(0xffffffffu >> (32 - srcBits)); return(context.BitwiseAnd(src, Const(mask))); }
public static void OutC(EmitterContext context) { InstOutC op = context.GetOp <InstOutC>(); EmitOut(context, op.OutType.HasFlag(OutType.Emit), op.OutType.HasFlag(OutType.Cut)); }
public static void Mov(EmitterContext context) { context.Copy(GetDest(context), GetSrcB(context)); }
public static void Ld(EmitterContext context) { EmitLoad(context, MemoryRegion.Local); }
private static void EmitF2I( EmitterContext context, DstFmt srcType, IDstFmt dstType, RoundMode2 roundingMode, Operand src, int rd, bool absolute, bool negate) { if (dstType == IDstFmt.U64) { context.Config.GpuAccessor.Log("Unimplemented 64-bits F2I."); } Instruction fpType = srcType.ToInstFPType(); bool isSignedInt = dstType == IDstFmt.S16 || dstType == IDstFmt.S32 || dstType == IDstFmt.S64; bool isSmallInt = dstType == IDstFmt.U16 || dstType == IDstFmt.S16; Operand srcB = context.FPAbsNeg(src, absolute, negate, fpType); srcB = roundingMode switch { RoundMode2.Round => context.FPRound(srcB, fpType), RoundMode2.Floor => context.FPFloor(srcB, fpType), RoundMode2.Ceil => context.FPCeiling(srcB, fpType), RoundMode2.Trunc => context.FPTruncate(srcB, fpType), _ => srcB }; if (!isSignedInt) { // Negative float to uint cast is undefined, so we clamp the value before conversion. Operand c0 = srcType == DstFmt.F64 ? context.PackDouble2x32(0.0) : ConstF(0); srcB = context.FPMaximum(srcB, c0, fpType); } if (srcType == DstFmt.F64) { srcB = isSignedInt ? context.FP64ConvertToS32(srcB) : context.FP64ConvertToU32(srcB); } else { srcB = isSignedInt ? context.FP32ConvertToS32(srcB) : context.FP32ConvertToU32(srcB); } if (isSmallInt) { int min = (int)GetIntMin(dstType); int max = (int)GetIntMax(dstType); srcB = isSignedInt ? context.IClampS32(srcB, Const(min), Const(max)) : context.IClampU32(srcB, Const(min), Const(max)); } Operand dest = GetDest(rd); context.Copy(dest, srcB); // TODO: CC. }
public static void Ldg(EmitterContext context) { EmitLoadGlobal(context); }
public abstract void EmitObject(LogicalObject obj, EmitterContext context);
public static void Texs(EmitterContext context) { OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp; if (op.Rd0.IsRZ && op.Rd1.IsRZ) { return; } List <Operand> sourcesList = new List <Operand>(); int raIndex = op.Ra.Index; int rbIndex = op.Rb.Index; Operand Ra() { if (raIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(context.Copy(Register(raIndex++, RegisterType.Gpr))); } Operand Rb() { if (rbIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(context.Copy(Register(rbIndex++, RegisterType.Gpr))); } void AddTextureOffset(int coordsCount, int stride, int size) { Operand packedOffs = Rb(); for (int index = 0; index < coordsCount; index++) { sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * stride), Const(size))); } } TextureType type; TextureFlags flags; if (op is OpCodeTexs texsOp) { type = GetTextureType(texsOp.Type); flags = GetTextureFlags(texsOp.Type); if ((type & TextureType.Array) != 0) { Operand arrayIndex = Ra(); sourcesList.Add(Ra()); sourcesList.Add(Rb()); sourcesList.Add(arrayIndex); if ((type & TextureType.Shadow) != 0) { sourcesList.Add(Rb()); } if ((flags & TextureFlags.LodLevel) != 0) { sourcesList.Add(ConstF(0)); } } else { switch (texsOp.Type) { case TextureScalarType.Texture1DLodZero: sourcesList.Add(Ra()); break; case TextureScalarType.Texture2D: sourcesList.Add(Ra()); sourcesList.Add(Rb()); break; case TextureScalarType.Texture2DLodZero: sourcesList.Add(Ra()); sourcesList.Add(Rb()); sourcesList.Add(ConstF(0)); break; case TextureScalarType.Texture2DLodLevel: case TextureScalarType.Texture2DDepthCompare: case TextureScalarType.Texture3D: case TextureScalarType.TextureCube: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Rb()); break; case TextureScalarType.Texture2DLodZeroDepthCompare: case TextureScalarType.Texture3DLodZero: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Rb()); sourcesList.Add(ConstF(0)); break; case TextureScalarType.Texture2DLodLevelDepthCompare: case TextureScalarType.TextureCubeLodLevel: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Rb()); sourcesList.Add(Rb()); break; } } } else if (op is OpCodeTlds tldsOp) { type = GetTextureType(tldsOp.Type); flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords; switch (tldsOp.Type) { case TexelLoadScalarType.Texture1DLodZero: sourcesList.Add(Ra()); sourcesList.Add(Const(0)); break; case TexelLoadScalarType.Texture1DLodLevel: sourcesList.Add(Ra()); sourcesList.Add(Rb()); break; case TexelLoadScalarType.Texture2DLodZero: sourcesList.Add(Ra()); sourcesList.Add(Rb()); sourcesList.Add(Const(0)); break; case TexelLoadScalarType.Texture2DLodZeroOffset: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Const(0)); break; case TexelLoadScalarType.Texture2DLodZeroMultisample: case TexelLoadScalarType.Texture2DLodLevel: case TexelLoadScalarType.Texture2DLodLevelOffset: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Rb()); break; case TexelLoadScalarType.Texture3DLodZero: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Rb()); sourcesList.Add(Const(0)); break; case TexelLoadScalarType.Texture2DArrayLodZero: sourcesList.Add(Rb()); sourcesList.Add(Rb()); sourcesList.Add(Ra()); sourcesList.Add(Const(0)); break; } if ((flags & TextureFlags.Offset) != 0) { AddTextureOffset(type.GetCoordsCount(), 4, 4); } } else if (op is OpCodeTld4s tld4sOp) { if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset)) { sourcesList.Add(Ra()); sourcesList.Add(Rb()); } else { sourcesList.Add(Ra()); sourcesList.Add(Ra()); } type = TextureType.Texture2D; flags = TextureFlags.Gather; if (tld4sOp.HasDepthCompare) { sourcesList.Add(Rb()); type |= TextureType.Shadow; } if (tld4sOp.HasOffset) { AddTextureOffset(type.GetCoordsCount(), 8, 6); flags |= TextureFlags.Offset; } sourcesList.Add(Const(tld4sOp.GatherCompIndex)); } else { throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\"."); } Operand[] sources = sourcesList.ToArray(); Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) }; Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) }; int destIncrement = 0; Operand GetDest() { int high = destIncrement >> 1; int low = destIncrement & 1; destIncrement++; if (op.IsFp16) { return(high != 0 ? (rd1[low] = Local()) : (rd0[low] = Local())); } else { int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index; if (rdIndex < RegisterConsts.RegisterZeroIndex) { rdIndex += low; } return(Register(rdIndex, RegisterType.Gpr)); } } int handle = op.Immediate; for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) { if ((compMask & 1) != 0) { Operand dest = GetDest(); TextureOperation operation = new TextureOperation( Instruction.TextureSample, type, flags, handle, compIndex, dest, sources); context.Add(operation); } } if (op.IsFp16) { context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1])); context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1])); } }