Example #1
0
        public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
        {
            // Compute local register inputs and outputs used inside blocks.
            RegisterMask[] localInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];

            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                for (Operation node = block.Operations.First; node != default; node = node.ListNext)
                {
                    for (int index = 0; index < node.SourcesCount; index++)
                    {
                        Operand source = node.GetSource(index);

                        if (source.Kind == OperandKind.Register)
                        {
                            Register register = source.GetRegister();

                            localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
                        }
                    }

                    if (node.Destination != default && node.Destination.Kind == OperandKind.Register)
                    {
                        localOutputs[block.Index] |= GetMask(node.Destination.GetRegister());
                    }
                }
            }

            // Compute global register inputs and outputs used across blocks.
            RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count];

            RegisterMask[] globalInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count];

            bool modified;
            bool firstPass = true;

            do
            {
                modified = false;

                // Compute register outputs.
                for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    if (block.Predecessors.Count != 0 && !HasContextLoad(block))
                    {
                        BasicBlock predecessor = block.Predecessors[0];

                        RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
                        RegisterMask outputs    = globalOutputs[predecessor.Index];

                        for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
                        {
                            predecessor = block.Predecessors[pIndex];

                            cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
                            outputs    |= globalOutputs[predecessor.Index];
                        }

                        globalInputs[block.Index] |= outputs & ~cmnOutputs;

                        if (!firstPass)
                        {
                            cmnOutputs &= globalCmnOutputs[block.Index];
                        }

                        modified |= Exchange(globalCmnOutputs, block.Index, cmnOutputs);
                        outputs  |= localOutputs[block.Index];
                        modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs);
                    }
                    else
                    {
                        modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]);
                    }
                }

                // Compute register inputs.
                for (int index = 0; index < cfg.PostOrderBlocks.Length; index++)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    RegisterMask inputs = localInputs[block.Index];

                    for (int i = 0; i < block.SuccessorsCount; i++)
                    {
                        inputs |= globalInputs[block.GetSuccessor(i).Index];
                    }

                    inputs &= ~globalCmnOutputs[block.Index];

                    modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs);
                }

                firstPass = false;
            }while (modified);

            // Insert load and store context instructions where needed.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                bool hasContextLoad = HasContextLoad(block);

                if (hasContextLoad)
                {
                    block.Operations.Remove(block.Operations.First);
                }

                Operand arg = default;

                // The only block without any predecessor should be the entry block.
                // It always needs a context load as it is the first block to run.
                if (block.Predecessors.Count == 0 || hasContextLoad)
                {
                    long vecMask = globalInputs[block.Index].VecMask;
                    long intMask = globalInputs[block.Index].IntMask;

                    if (vecMask != 0 || intMask != 0)
                    {
                        arg = Local(OperandType.I64);

                        Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0)));

                        LoadLocals(block, vecMask, RegisterType.Vector, mode, loadArg, arg);
                        LoadLocals(block, intMask, RegisterType.Integer, mode, loadArg, arg);
                    }
                }

                bool hasContextStore = HasContextStore(block);

                if (hasContextStore)
                {
                    block.Operations.Remove(block.Operations.Last);
                }

                if (EndsWithReturn(block) || hasContextStore)
                {
                    long vecMask = globalOutputs[block.Index].VecMask;
                    long intMask = globalOutputs[block.Index].IntMask;

                    if (vecMask != 0 || intMask != 0)
                    {
                        if (arg == default)
                        {
                            arg = Local(OperandType.I64);

                            block.Append(Operation(Instruction.LoadArgument, arg, Const(0)));
                        }

                        StoreLocals(block, intMask, RegisterType.Integer, mode, arg);
                        StoreLocals(block, vecMask, RegisterType.Vector, mode, arg);
                    }
                }
            }
        }
Example #2
0
        public static void Construct(ControlFlowGraph cfg)
        {
            var globalDefs = new DefMap[cfg.Blocks.Count];
            var localDefs  = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];

            var dfPhiBlocks = new Queue <BasicBlock>();

            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                globalDefs[block.Index] = new DefMap();
            }

            // First pass, get all defs and locals uses.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                for (Operation node = block.Operations.First; node != default; node = node.ListNext)
                {
                    for (int index = 0; index < node.SourcesCount; index++)
                    {
                        Operand src = node.GetSource(index);

                        if (TryGetId(src, out int srcKey))
                        {
                            Operand local = localDefs[srcKey];

                            if (local == default)
                            {
                                local = src;
                            }

                            node.SetSource(index, local);
                        }
                    }

                    Operand dest = node.Destination;

                    if (TryGetId(dest, out int destKey))
                    {
                        Operand local = Local(dest.Type);

                        localDefs[destKey] = local;

                        node.Destination = local;
                    }
                }

                for (int key = 0; key < localDefs.Length; key++)
                {
                    Operand local = localDefs[key];

                    if (local == default)
                    {
                        continue;
                    }

                    globalDefs[block.Index].TryAddOperand(key, local);

                    dfPhiBlocks.Enqueue(block);

                    while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock))
                    {
                        foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers)
                        {
                            if (globalDefs[domFrontier.Index].AddPhi(key))
                            {
                                dfPhiBlocks.Enqueue(domFrontier);
                            }
                        }
                    }
                }

                Array.Clear(localDefs, 0, localDefs.Length);
            }

            // Second pass, rename variables with definitions on different blocks.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                for (Operation node = block.Operations.First; node != default; node = node.ListNext)
                {
                    for (int index = 0; index < node.SourcesCount; index++)
                    {
                        Operand src = node.GetSource(index);

                        if (TryGetId(src, out int key))
                        {
                            Operand local = localDefs[key];

                            if (local == default)
                            {
                                local          = FindDef(globalDefs, block, src);
                                localDefs[key] = local;
                            }

                            node.SetSource(index, local);
                        }
                    }
                }

                Array.Clear(localDefs, 0, localDefs.Length);
            }
        }
Example #3
0
        public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
        {
            // Compute local register inputs and outputs used inside blocks.
            RegisterMask[] localInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];

            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                for (Node node = block.Operations.First; node != null; node = node.ListNext)
                {
                    Operation operation = node as Operation;

                    for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
                    {
                        Operand source = operation.GetSource(srcIndex);

                        if (source.Kind != OperandKind.Register)
                        {
                            continue;
                        }

                        Register register = source.GetRegister();

                        localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
                    }

                    if (operation.Destination != null && operation.Destination.Kind == OperandKind.Register)
                    {
                        localOutputs[block.Index] |= GetMask(operation.Destination.GetRegister());
                    }
                }
            }

            // Compute global register inputs and outputs used across blocks.
            RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count];

            RegisterMask[] globalInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count];

            bool modified;

            bool firstPass = true;

            do
            {
                modified = false;

                // Compute register outputs.
                for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    if (block.Predecessors.Count != 0 && !HasContextLoad(block))
                    {
                        BasicBlock predecessor = block.Predecessors[0];

                        RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];

                        RegisterMask outputs = globalOutputs[predecessor.Index];

                        for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
                        {
                            predecessor = block.Predecessors[pIndex];

                            cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];

                            outputs |= globalOutputs[predecessor.Index];
                        }

                        globalInputs[block.Index] |= outputs & ~cmnOutputs;

                        if (!firstPass)
                        {
                            cmnOutputs &= globalCmnOutputs[block.Index];
                        }

                        if (Exchange(globalCmnOutputs, block.Index, cmnOutputs))
                        {
                            modified = true;
                        }

                        outputs |= localOutputs[block.Index];

                        if (Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs))
                        {
                            modified = true;
                        }
                    }
                    else if (Exchange(globalOutputs, block.Index, localOutputs[block.Index]))
                    {
                        modified = true;
                    }
                }

                // Compute register inputs.
                for (int index = 0; index < cfg.PostOrderBlocks.Length; index++)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    RegisterMask inputs = localInputs[block.Index];

                    for (int i = 0; i < block.SuccessorCount; i++)
                    {
                        inputs |= globalInputs[block.GetSuccessor(i).Index];
                    }

                    inputs &= ~globalCmnOutputs[block.Index];

                    if (Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs))
                    {
                        modified = true;
                    }
                }

                firstPass = false;
            }while (modified);

            // Insert load and store context instructions where needed.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                bool hasContextLoad = HasContextLoad(block);

                if (hasContextLoad)
                {
                    block.Operations.Remove(block.Operations.First);
                }

                // The only block without any predecessor should be the entry block.
                // It always needs a context load as it is the first block to run.
                if (block.Predecessors.Count == 0 || hasContextLoad)
                {
                    LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector, mode);
                    LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer, mode);
                }

                bool hasContextStore = HasContextStore(block);

                if (hasContextStore)
                {
                    block.Operations.Remove(block.Operations.Last);
                }

                if (EndsWithReturn(block) || hasContextStore)
                {
                    StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, mode);
                    StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, mode);
                }
            }
        }
Example #4
0
        public static void Construct(ControlFlowGraph cfg)
        {
            DefMap[] globalDefs = new DefMap[cfg.Blocks.Count];

            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                globalDefs[block.Index] = new DefMap();
            }

            Queue <BasicBlock> dfPhiBlocks = new Queue <BasicBlock>();

            // First pass, get all defs and locals uses.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                Operand[] localDefs = new Operand[RegisterConsts.TotalCount];

                Node node = block.Operations.First;

                Operand RenameLocal(Operand operand)
                {
                    if (operand != null && operand.Kind == OperandKind.Register)
                    {
                        Operand local = localDefs[GetIdFromRegister(operand.GetRegister())];

                        operand = local ?? operand;
                    }

                    return(operand);
                }

                while (node != null)
                {
                    if (node is Operation operation)
                    {
                        for (int index = 0; index < operation.SourcesCount; index++)
                        {
                            operation.SetSource(index, RenameLocal(operation.GetSource(index)));
                        }

                        Operand dest = operation.Destination;

                        if (dest != null && dest.Kind == OperandKind.Register)
                        {
                            Operand local = Local(dest.Type);

                            localDefs[GetIdFromRegister(dest.GetRegister())] = local;

                            operation.Destination = local;
                        }
                    }

                    node = node.ListNext;
                }

                for (int index = 0; index < RegisterConsts.TotalCount; index++)
                {
                    Operand local = localDefs[index];

                    if (local == null)
                    {
                        continue;
                    }

                    Register reg = GetRegisterFromId(index);

                    globalDefs[block.Index].TryAddOperand(reg, local);

                    dfPhiBlocks.Enqueue(block);

                    while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock))
                    {
                        foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers)
                        {
                            if (globalDefs[domFrontier.Index].AddPhi(reg))
                            {
                                dfPhiBlocks.Enqueue(domFrontier);
                            }
                        }
                    }
                }
            }

            // Second pass, rename variables with definitions on different blocks.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                Operand[] localDefs = new Operand[RegisterConsts.TotalCount];

                Node node = block.Operations.First;

                Operand RenameGlobal(Operand operand)
                {
                    if (operand != null && operand.Kind == OperandKind.Register)
                    {
                        int key = GetIdFromRegister(operand.GetRegister());

                        Operand local = localDefs[key];

                        if (local == null)
                        {
                            local = FindDef(globalDefs, block, operand);

                            localDefs[key] = local;
                        }

                        operand = local;
                    }

                    return(operand);
                }

                while (node != null)
                {
                    if (node is Operation operation)
                    {
                        for (int index = 0; index < operation.SourcesCount; index++)
                        {
                            operation.SetSource(index, RenameGlobal(operation.GetSource(index)));
                        }
                    }

                    node = node.ListNext;
                }
            }
        }