示例#1
0
        private AssignmentStatement <TInstruction> CreateAssignment(
            Expression <TInstruction> expression,
            TInstruction instruction,
            IVariable[] writtenVariables)
        {
            // We will create stack slots for every push and "simulate" an assignment
            // to them. This way the resulting AST won't have the "concept" of a stack.
            int pushes = _context.Architecture.GetStackPushCount(instruction);
            var slots  = GetStackSlots(pushes);
            var buffer = new AstVariable[slots.Length + writtenVariables.Length];

            slots.CopyTo(buffer.AsSpan());

            // Also assign to written variables.
            for (int i = 0; i < writtenVariables.Length; i++)
            {
                // Get the correct version of the variable to assign to.
                var variable          = writtenVariables[i];
                int version           = _context.GetVariableVersion(variable);
                var snapshot          = new VariableSnapshot(variable, version);
                var versionedVariable = _context.GetVersionedVariable(snapshot);

                buffer[slots.Length + i] = versionedVariable;
            }

            // Assign stack slots.
            _context.StackSlots[instruction] = slots;
            return(new AssignmentStatement <TInstruction>(buffer, expression));
        }
示例#2
0
        internal AstVariable GetVersionedVariable(VariableSnapshot snapshot)
        {
            if (VersionedVariables.TryGetValue(snapshot, out var variable))
            {
                return(variable);
            }

            variable = new AstVariable(snapshot.ToString());
            VersionedVariables.Add(snapshot, variable);

            return(variable);
        }
示例#3
0
        private IVariable[] VersionWrittenVariables(TInstruction instruction)
        {
            var buffer = GetWrittenVariables(instruction);

            foreach (var variable in buffer)
            {
                if (_context.VariableStates.TryGetValue(instruction, out var states))
                {
                    // If we already have a dictionary that contains versions for this instruction,
                    // we can reuse the same instance.

                    // If the instruction hasn't "seen" the variable before, we add a new entry.
                    if (!states.ContainsKey(variable))
                    {
                        states.Add(variable, _context.VariableVersions[variable]++);
                    }

                    // Create a new snapshot of the variable and store the versioned variable
                    // created from the snapshot.
                    var snapshot          = new VariableSnapshot(variable, _context.VariableVersions[variable]);
                    var versionedVariable = _context.GetVersionedVariable(snapshot);
                    _context.VersionedVariables[snapshot] = versionedVariable;
                }
                else
                {
                    // Otherwise we will create a new dictionary and store it so it can be
                    // reused later.

                    // Increment the version of the variable, create a snapshot and
                    // add it to the newly created dictionary.
                    int version  = _context.IncrementVariableVersion(variable);
                    var snapshot = new VariableSnapshot(variable, version);
                    states = new Dictionary <IVariable, int>
                    {
                        [variable] = version
                    };

                    // Save the dictionary for later reuse and get a variable for the snapshot.
                    _context.VariableStates[instruction]  = states;
                    _context.VersionedVariables[snapshot] = _context.GetVersionedVariable(snapshot);
                }
            }

            return(buffer);
        }
示例#4
0
        private void CollectVariableDependencies(
            BasicBlock <Statement <TInstruction> > block,
            DataFlowNode <TInstruction> dataFlowNode,
            Span <IVariable> buffer,
            ref int phiStatementCount)
        {
            int index = 0;
            var variableDependencies = dataFlowNode.VariableDependencies;

            foreach (var pair in variableDependencies)
            {
                var variable   = pair.Key;
                var dependency = pair.Value;

                if (dependency.Count <= 1)
                {
                    // If the dependency has only 1 possible source we just simply
                    // get the variable. But since the AST utilizes SSA, all of the
                    // variables are versioned. This is good because everything is
                    // "immutable". One "real" variable will have a new versioned
                    // variable created every time it is assigned to.
                    int version  = _context.GetVariableVersion(variable);
                    var snapshot = new VariableSnapshot(variable, version);

                    buffer[index++] = _context.GetVersionedVariable(snapshot);
                    continue;
                }

                // Otherwise (>0), we will get the list of versioned(!) variables
                // that could reach the instruction and create a "phi" statement
                // like in the stack dependencies.
                var sources = CollectVariables();

                if (_context.VariableSourcesToPhiVariable.TryGetValue(sources, out var phi))
                {
                    // If a phi slot already exists for the list of variables,
                    // reuse the same phi slot.
                    buffer[index++] = phi;
                }
                else
                {
                    // Otherwise, create a new phi slot for the list of variables
                    // and save it if we encounter the same variables again.
                    phi = CreatePhiSlot();
                    var slots = sources
                                .Select(source => new VariableExpression <TInstruction>(source))
                                .ToArray();

                    _context.VariableSourcesToPhiVariable.Add(sources, phi);
                    block.Instructions.Insert(phiStatementCount++, new PhiStatement <TInstruction>(phi, slots));
                    buffer[index++] = phi;
                }

                List <AstVariable> CollectVariables()
                {
                    var result = new List <AstVariable>();

                    foreach (var instruction in dependency.Select(dep => dep.Node.Contents))
                    {
                        if (_context.VariableStates.TryGetValue(instruction, out var versions))
                        {
                            // If we already have a dictionary for the instruction, we will
                            // just get the versioned variable from the existing dictionary.
                            var snapshot = new VariableSnapshot(variable, versions[variable]);
                            result.Add(_context.VersionedVariables[snapshot]);
                        }
                        else
                        {
                            // Otherwise, we will create a new dictionary for the instruction.
                            var snapshot = new VariableSnapshot(variable, 0);
                            var slot     = _context.GetVersionedVariable(snapshot);

                            _context.VariableStates.Add(instruction, new Dictionary <IVariable, int>
                            {
                                [variable] = 0
                            });

                            result.Add(slot);
                        }
                    }

                    return(result);
                }
            }
        }