Exemple #1
0
        public static StructuredProgramInfo MakeStructuredProgram(BasicBlock[] blocks)
        {
            PhiFunctions.Remove(blocks);

            StructuredProgramContext context = new StructuredProgramContext(blocks.Length);

            for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
            {
                BasicBlock block = blocks[blkIndex];

                context.EnterBlock(block);

                foreach (INode node in block.Operations)
                {
                    Operation operation = (Operation)node;

                    if (IsBranchInst(operation.Inst))
                    {
                        context.LeaveBlock(block, operation);
                    }
                    else
                    {
                        AddOperation(context, operation);
                    }
                }
            }

            GotoElimination.Eliminate(context.GetGotos());

            AstOptimizer.Optimize(context.Info);

            return(context.Info);
        }
Exemple #2
0
        public static void Optimize(StructuredProgramContext context)
        {
            AstBlock mainBlock = context.CurrentFunction.MainBlock;

            // When debug mode is enabled, we disable expression propagation
            // (this makes comparison with the disassembly easier).
            if ((context.Config.Options.Flags & TranslationFlags.DebugMode) == 0)
            {
                AstBlockVisitor visitor = new AstBlockVisitor(mainBlock);

                foreach (IAstNode node in visitor.Visit())
                {
                    if (node is AstAssignment assignment && assignment.Destination is AstOperand propVar)
                    {
                        bool isWorthPropagating = propVar.Uses.Count == 1 || IsWorthPropagating(assignment.Source);

                        if (propVar.Defs.Count == 1 && isWorthPropagating)
                        {
                            PropagateExpression(propVar, assignment.Source);
                        }

                        if (propVar.Type == OperandType.LocalVariable && propVar.Uses.Count == 0)
                        {
                            visitor.Block.Remove(assignment);

                            context.CurrentFunction.Locals.Remove(propVar);
                        }
                    }
                }
            }

            RemoveEmptyBlocks(mainBlock);
        }
Exemple #3
0
        public static StructuredProgramInfo MakeStructuredProgram(Function[] functions, ShaderConfig config)
        {
            StructuredProgramContext context = new StructuredProgramContext(config);

            for (int funcIndex = 0; funcIndex < functions.Length; funcIndex++)
            {
                Function function = functions[funcIndex];

                BasicBlock[] blocks = function.Blocks;

                VariableType returnType = function.ReturnsValue ? VariableType.S32 : VariableType.None;

                VariableType[] inArguments  = new VariableType[function.InArgumentsCount];
                VariableType[] outArguments = new VariableType[function.OutArgumentsCount];

                for (int i = 0; i < inArguments.Length; i++)
                {
                    inArguments[i] = VariableType.S32;
                }

                for (int i = 0; i < outArguments.Length; i++)
                {
                    outArguments[i] = VariableType.S32;
                }

                context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);

                PhiFunctions.Remove(blocks);

                for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
                {
                    BasicBlock block = blocks[blkIndex];

                    context.EnterBlock(block);

                    for (LinkedListNode <INode> opNode = block.Operations.First; opNode != null; opNode = opNode.Next)
                    {
                        Operation operation = (Operation)opNode.Value;

                        if (IsBranchInst(operation.Inst))
                        {
                            context.LeaveBlock(block, operation);
                        }
                        else
                        {
                            AddOperation(context, operation);
                        }
                    }
                }

                GotoElimination.Eliminate(context.GetGotos());

                AstOptimizer.Optimize(context);

                context.LeaveFunction();
            }

            return(context.Info);
        }
Exemple #4
0
        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));
            }
        }
Exemple #5
0
        public static StructuredProgramInfo MakeStructuredProgram(Function[] functions, ShaderConfig config)
        {
            StructuredProgramContext context = new StructuredProgramContext(config);

            for (int funcIndex = 0; funcIndex < functions.Length; funcIndex++)
            {
                Function function = functions[funcIndex];

                BasicBlock[] blocks = function.Blocks;

                VariableType returnType = function.ReturnsValue ? VariableType.S32 : VariableType.None;

                VariableType[] inArguments  = new VariableType[function.InArgumentsCount];
                VariableType[] outArguments = new VariableType[function.OutArgumentsCount];

                for (int i = 0; i < inArguments.Length; i++)
                {
                    inArguments[i] = VariableType.S32;
                }

                for (int i = 0; i < outArguments.Length; i++)
                {
                    outArguments[i] = VariableType.S32;
                }

                context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);

                PhiFunctions.Remove(blocks);

                for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
                {
                    BasicBlock block = blocks[blkIndex];

                    context.EnterBlock(block);

                    for (LinkedListNode <INode> opNode = block.Operations.First; opNode != null; opNode = opNode.Next)
                    {
                        Operation operation = (Operation)opNode.Value;

                        if (IsBranchInst(operation.Inst))
                        {
                            context.LeaveBlock(block, operation);
                        }
                        else
                        {
                            AddOperation(context, operation);
                        }
                    }
                }

                GotoElimination.Eliminate(context.GetGotos());

                AstOptimizer.Optimize(context);

                context.LeaveFunction();
            }

            if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
            {
                for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++)
                {
                    var locations = config.GpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex);
                    var stride    = config.GpuAccessor.QueryTransformFeedbackStride(tfbIndex);

                    for (int j = 0; j < locations.Length; j++)
                    {
                        byte location = locations[j];
                        if (location < 0xc0)
                        {
                            context.Info.TransformFeedbackOutputs[location] = new TransformFeedbackOutput(tfbIndex, j * 4, stride);
                        }
                    }
                }
            }

            return(context.Info);
        }
Exemple #6
0
        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;
            }
        }
Exemple #8
0
        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;
            }
        }