private static void PropagateExpression(AstOperand propVar, IAstNode source) { IAstNode[] uses = propVar.Uses.ToArray(); foreach (IAstNode useNode in uses) { if (useNode is AstBlock useBlock) { useBlock.Condition = source; } else if (useNode is AstOperation useOperation) { for (int srcIndex = 0; srcIndex < useOperation.SourcesCount; srcIndex++) { if (useOperation.GetSource(srcIndex) == propVar) { useOperation.SetSource(srcIndex, source); } } } else if (useNode is AstAssignment useAssignment) { useAssignment.Source = source; } } }
public static AstOperand Local(VariableType type) { AstOperand local = new AstOperand(OperandType.LocalVariable); local.VarType = type; return(local); }
public static VariableType GetVarType(AstOperand operand) { if (operand.Type == OperandType.LocalVariable) { return(operand.VarType); } else { return(GetVarType(operand.Type)); } }
private static void AddOperation(StructuredProgramContext context, Operation operation) { Instruction inst = operation.Inst; IAstNode[] sources = new IAstNode[operation.SourcesCount]; for (int index = 0; index < sources.Length; index++) { sources[index] = context.GetOperandUse(operation.GetSource(index)); } if (operation.Dest != null) { AstOperand dest = context.GetOperandDef(operation.Dest); if (inst == Instruction.LoadConstant) { Operand ldcSource = operation.GetSource(0); if (ldcSource.Type != OperandType.Constant) { throw new InvalidOperationException("Found LDC with non-constant constant buffer slot."); } context.Info.CBuffers.Add(ldcSource.Value); } AstAssignment assignment; //If all the sources are bool, it's better to use short-circuiting //logical operations, rather than forcing a cast to int and doing //a bitwise operation with the value, as it is likely to be used as //a bool in the end. if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, VariableType.Bool)) { inst = GetLogicalFromBitwiseInst(inst); } bool isCondSel = inst == Instruction.ConditionalSelect; bool isCopy = inst == Instruction.Copy; if (isCondSel || isCopy) { VariableType type = GetVarTypeFromUses(operation.Dest); if (isCondSel && type == VariableType.F32) { inst |= Instruction.FP; } dest.VarType = type; } else { dest.VarType = InstructionInfo.GetDestVarType(inst); } int componentMask = 1 << operation.ComponentIndex; IAstNode source; if (operation is TextureOperation texOp) { AstTextureOperation astTexOp = new AstTextureOperation( inst, texOp.Type, texOp.Flags, texOp.Handle, componentMask, sources); context.Info.Samplers.Add(astTexOp); source = astTexOp; } else if (!isCopy) { source = new AstOperation(inst, componentMask, sources); } else { source = sources[0]; } assignment = new AstAssignment(dest, source); context.AddNode(assignment); } else { context.AddNode(new AstOperation(inst, sources)); } }
private static void AddOperation(StructuredProgramContext context, Operation operation) { Instruction inst = operation.Inst; if (inst == Instruction.LoadAttribute) { Operand src1 = operation.GetSource(0); Operand src2 = operation.GetSource(1); if (src1.Type == OperandType.Constant && src2.Type == OperandType.Constant) { int attrOffset = (src1.Value & AttributeConsts.Mask) + (src2.Value << 2); context.Info.Inputs.Add(attrOffset); } } int sourcesCount = operation.SourcesCount; int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0; IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount]; for (int index = 0; index < operation.SourcesCount; index++) { sources[index] = context.GetOperandUse(operation.GetSource(index)); } for (int index = 0; index < outDestsCount; index++) { AstOperand oper = context.GetOperandDef(operation.GetDest(1 + index)); oper.VarType = InstructionInfo.GetSrcVarType(inst, sourcesCount + index); sources[sourcesCount + index] = oper; } AstTextureOperation GetAstTextureOperation(TextureOperation texOp) { return(new AstTextureOperation( inst, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle, texOp.Index, sources)); } if (operation.Dest != null) { AstOperand dest = context.GetOperandDef(operation.Dest); // If all the sources are bool, it's better to use short-circuiting // logical operations, rather than forcing a cast to int and doing // a bitwise operation with the value, as it is likely to be used as // a bool in the end. if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, VariableType.Bool)) { inst = GetLogicalFromBitwiseInst(inst); } bool isCondSel = inst == Instruction.ConditionalSelect; bool isCopy = inst == Instruction.Copy; if (isCondSel || isCopy) { VariableType type = GetVarTypeFromUses(operation.Dest); if (isCondSel && type == VariableType.F32) { inst |= Instruction.FP32; } dest.VarType = type; } else { dest.VarType = InstructionInfo.GetDestVarType(inst); } IAstNode source; if (operation is TextureOperation texOp) { if (texOp.Inst == Instruction.ImageLoad) { dest.VarType = texOp.Format.GetComponentType(); } source = GetAstTextureOperation(texOp); } else if (!isCopy) { source = new AstOperation(inst, operation.Index, sources, operation.SourcesCount); } else { source = sources[0]; } context.AddNode(new AstAssignment(dest, source)); } else if (operation.Inst == Instruction.Comment) { context.AddNode(new AstComment(((CommentNode)operation).Comment)); } else if (operation is TextureOperation texOp) { AstTextureOperation astTexOp = GetAstTextureOperation(texOp); context.AddNode(astTexOp); } else { context.AddNode(new AstOperation(inst, operation.Index, sources, operation.SourcesCount)); } // Those instructions needs to be emulated by using helper functions, // because they are NVIDIA specific. Those flags helps the backend to // decide which helper functions are needed on the final generated code. switch (operation.Inst) { case Instruction.AtomicMaxS32 | Instruction.MrShared: case Instruction.AtomicMinS32 | Instruction.MrShared: context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Shared; break; case Instruction.AtomicMaxS32 | Instruction.MrStorage: case Instruction.AtomicMinS32 | Instruction.MrStorage: context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Storage; break; case Instruction.MultiplyHighS32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32; break; case Instruction.MultiplyHighU32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighU32; break; case Instruction.Shuffle: context.Info.HelperFunctionsMask |= HelperFunctionsMask.Shuffle; break; case Instruction.ShuffleDown: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleDown; break; case Instruction.ShuffleUp: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleUp; break; case Instruction.ShuffleXor: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleXor; break; case Instruction.StoreShared16: case Instruction.StoreShared8: context.Info.HelperFunctionsMask |= HelperFunctionsMask.StoreSharedSmallInt; break; case Instruction.StoreStorage16: case Instruction.StoreStorage8: context.Info.HelperFunctionsMask |= HelperFunctionsMask.StoreStorageSmallInt; break; case Instruction.SwizzleAdd: context.Info.HelperFunctionsMask |= HelperFunctionsMask.SwizzleAdd; break; case Instruction.FSIBegin: case Instruction.FSIEnd: context.Info.HelperFunctionsMask |= HelperFunctionsMask.FSI; break; } }
private static void AddOperation(StructuredProgramContext context, Operation operation) { Instruction inst = operation.Inst; int sourcesCount = operation.SourcesCount; int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0; IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount]; for (int index = 0; index < operation.SourcesCount; index++) { sources[index] = context.GetOperandUse(operation.GetSource(index)); } for (int index = 0; index < outDestsCount; index++) { AstOperand oper = context.GetOperandDef(operation.GetDest(1 + index)); oper.VarType = InstructionInfo.GetSrcVarType(inst, sourcesCount + index); sources[sourcesCount + index] = oper; } AstTextureOperation GetAstTextureOperation(TextureOperation texOp) { return(new AstTextureOperation( inst, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle, 4, // TODO: Non-hardcoded array size. texOp.Index, sources)); } if (operation.Dest != null) { AstOperand dest = context.GetOperandDef(operation.Dest); if (inst == Instruction.LoadConstant) { Operand slot = operation.GetSource(0); if (slot.Type == OperandType.Constant) { context.Info.CBuffers.Add(slot.Value); } else { // If the value is not constant, then we don't know // how many constant buffers are used, so we assume // all of them are used. int cbCount = 32 - BitOperations.LeadingZeroCount(context.Config.GpuAccessor.QueryConstantBufferUse()); for (int index = 0; index < cbCount; index++) { context.Info.CBuffers.Add(index); } context.Info.UsesCbIndexing = true; } } else if (UsesStorage(inst)) { AddSBufferUse(context.Info.SBuffers, operation); } // If all the sources are bool, it's better to use short-circuiting // logical operations, rather than forcing a cast to int and doing // a bitwise operation with the value, as it is likely to be used as // a bool in the end. if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, VariableType.Bool)) { inst = GetLogicalFromBitwiseInst(inst); } bool isCondSel = inst == Instruction.ConditionalSelect; bool isCopy = inst == Instruction.Copy; if (isCondSel || isCopy) { VariableType type = GetVarTypeFromUses(operation.Dest); if (isCondSel && type == VariableType.F32) { inst |= Instruction.FP32; } dest.VarType = type; } else { dest.VarType = InstructionInfo.GetDestVarType(inst); } IAstNode source; if (operation is TextureOperation texOp) { if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore) { dest.VarType = texOp.Format.GetComponentType(); } AstTextureOperation astTexOp = GetAstTextureOperation(texOp); if (texOp.Inst == Instruction.ImageLoad) { context.Info.Images.Add(astTexOp); } else { context.Info.Samplers.Add(astTexOp); } source = astTexOp; } else if (!isCopy) { source = new AstOperation(inst, operation.Index, sources, operation.SourcesCount); } else { source = sources[0]; } context.AddNode(new AstAssignment(dest, source)); } else if (operation.Inst == Instruction.Comment) { context.AddNode(new AstComment(((CommentNode)operation).Comment)); } else if (operation is TextureOperation texOp) { AstTextureOperation astTexOp = GetAstTextureOperation(texOp); context.Info.Images.Add(astTexOp); context.AddNode(astTexOp); } else { if (UsesStorage(inst)) { AddSBufferUse(context.Info.SBuffers, operation); } context.AddNode(new AstOperation(inst, operation.Index, sources, operation.SourcesCount)); } // Those instructions needs to be emulated by using helper functions, // because they are NVIDIA specific. Those flags helps the backend to // decide which helper functions are needed on the final generated code. switch (operation.Inst) { case Instruction.AtomicMaxS32 | Instruction.MrShared: case Instruction.AtomicMinS32 | Instruction.MrShared: context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Shared; break; case Instruction.AtomicMaxS32 | Instruction.MrStorage: case Instruction.AtomicMinS32 | Instruction.MrStorage: context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Storage; break; case Instruction.MultiplyHighS32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32; break; case Instruction.MultiplyHighU32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighU32; break; case Instruction.Shuffle: context.Info.HelperFunctionsMask |= HelperFunctionsMask.Shuffle; break; case Instruction.ShuffleDown: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleDown; break; case Instruction.ShuffleUp: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleUp; break; case Instruction.ShuffleXor: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleXor; break; case Instruction.SwizzleAdd: context.Info.HelperFunctionsMask |= HelperFunctionsMask.SwizzleAdd; break; } }
private static void AddOperation(StructuredProgramContext context, Operation operation) { Instruction inst = operation.Inst; IAstNode[] sources = new IAstNode[operation.SourcesCount]; for (int index = 0; index < sources.Length; index++) { sources[index] = context.GetOperandUse(operation.GetSource(index)); } AstTextureOperation GetAstTextureOperation(TextureOperation texOp) { return(new AstTextureOperation( inst, texOp.Type, texOp.Flags, texOp.Handle, 4, // TODO: Non-hardcoded array size. texOp.Index, sources)); } if (operation.Dest != null) { AstOperand dest = context.GetOperandDef(operation.Dest); if (inst == Instruction.LoadConstant) { Operand slot = operation.GetSource(0); if (slot.Type != OperandType.Constant) { throw new InvalidOperationException("Found load with non-constant constant buffer slot."); } context.Info.CBuffers.Add(slot.Value); } else if (UsesStorage(inst)) { AddSBufferUse(context.Info.SBuffers, operation); } AstAssignment assignment; // If all the sources are bool, it's better to use short-circuiting // logical operations, rather than forcing a cast to int and doing // a bitwise operation with the value, as it is likely to be used as // a bool in the end. if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, VariableType.Bool)) { inst = GetLogicalFromBitwiseInst(inst); } bool isCondSel = inst == Instruction.ConditionalSelect; bool isCopy = inst == Instruction.Copy; if (isCondSel || isCopy) { VariableType type = GetVarTypeFromUses(operation.Dest); if (isCondSel && type == VariableType.F32) { inst |= Instruction.FP32; } dest.VarType = type; } else { dest.VarType = InstructionInfo.GetDestVarType(inst); } IAstNode source; if (operation is TextureOperation texOp) { AstTextureOperation astTexOp = GetAstTextureOperation(texOp); if (texOp.Inst == Instruction.ImageLoad) { context.Info.Images.Add(astTexOp); } else { context.Info.Samplers.Add(astTexOp); } source = astTexOp; } else if (!isCopy) { source = new AstOperation(inst, operation.Index, sources); } else { source = sources[0]; } assignment = new AstAssignment(dest, source); context.AddNode(assignment); } else if (operation.Inst == Instruction.Comment) { context.AddNode(new AstComment(((CommentNode)operation).Comment)); } else if (operation is TextureOperation texOp) { AstTextureOperation astTexOp = GetAstTextureOperation(texOp); context.Info.Images.Add(astTexOp); context.AddNode(astTexOp); } else { if (UsesStorage(inst)) { AddSBufferUse(context.Info.SBuffers, operation); } context.AddNode(new AstOperation(inst, operation.Index, sources)); } // Those instructions needs to be emulated by using helper functions, // because they are NVIDIA specific. Those flags helps the backend to // decide which helper functions are needed on the final generated code. switch (operation.Inst) { case Instruction.MultiplyHighS32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32; break; case Instruction.MultiplyHighU32: context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighU32; break; case Instruction.Shuffle: context.Info.HelperFunctionsMask |= HelperFunctionsMask.Shuffle; break; case Instruction.ShuffleDown: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleDown; break; case Instruction.ShuffleUp: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleUp; break; case Instruction.ShuffleXor: context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleXor; break; case Instruction.SwizzleAdd: context.Info.HelperFunctionsMask |= HelperFunctionsMask.SwizzleAdd; break; } }