예제 #1
0
 private void ClearGraph()
 {
     m_CurSelectAsset = null;
     m_CurFlowGraph   = null;
     m_CurAssetPath   = "";
 }
예제 #2
0
        public void MinCostFlowStressTest()
        {
            for (var ph = 0; ph < 1000; ph++)
            {
                var n = Utilities.RandomInteger(2, 20);
                var m = Utilities.RandomInteger(1, 100);
                var(s, t) = Utilities.RandomPair(0, n - 1);
                if (Utilities.RandomBool())
                {
                    (s, t) = (t, s);
                }

                var mfg  = new FlowGraph(n);
                var mcfg = new FlowGraph(n);
                for (var i = 0; i < m; i++)
                {
                    var u    = Utilities.RandomInteger(0, n - 1);
                    var v    = Utilities.RandomInteger(0, n - 1);
                    var cap  = Utilities.RandomInteger(0, 10);
                    var cost = Utilities.RandomInteger(0, 10000);
                    mcfg.AddEdge(u, v, cap, cost);
                    mfg.AddEdge(u, v, cap);
                }

                var(flow, cost1) = mcfg.MinCostFlow(s, t);
                Assert.That(flow, Is.EqualTo(mfg.MaxFlow(s, t)));

                var cost2      = 0L;
                var capacities = new long[n];
                foreach (var edge in mcfg.GetEdges())
                {
                    capacities[edge.From] -= edge.Flow;
                    capacities[edge.To]   += edge.Flow;
                    cost2 += edge.Flow * edge.Cost;
                }

                Assert.That(cost1, Is.EqualTo(cost2));

                for (var i = 0; i < n; i++)
                {
                    if (i == s)
                    {
                        Assert.That(capacities[i], Is.EqualTo(-flow));
                    }
                    else if (i == t)
                    {
                        Assert.That(capacities[i], Is.EqualTo(flow));
                    }
                    else
                    {
                        Assert.That(capacities[i], Is.EqualTo(0));
                    }
                }

                Assert.DoesNotThrow(() =>
                {
                    var dist = new long[n];
                    while (true)
                    {
                        var update = false;
                        foreach (var edge in mcfg.GetEdges())
                        {
                            if (edge.Flow < edge.Capacity)
                            {
                                var ndist = dist[edge.From] + edge.Cost;
                                if (ndist < dist[edge.To])
                                {
                                    update        = true;
                                    dist[edge.To] = ndist;
                                }
                            }

                            if (edge.Flow == 0)
                            {
                                continue;
                            }
                            {
                                var ndist = dist[edge.To] - edge.Cost;
                                if (ndist < dist[edge.From])
                                {
                                    update          = true;
                                    dist[edge.From] = ndist;
                                }
                            }
                        }

                        if (!update)
                        {
                            break;
                        }
                    }
                });
            }
        }
예제 #3
0
        private void DrawMain()
        {
            if (m_CurFlowGraph == null)
            {
                if (GUI.Button(new Rect(m_SplitterX / 2f - 50f, position.height / 2f - 15f, 100f, 30f), "Create"))
                {
                    m_CurFlowGraph = CreateInstance <FlowGraph>();
                }
            }
            else
            {
                DrawMiniMap();

                if (m_CurFlowGraph.nodeCount > 0)
                {
                    Handles.BeginGUI();

                    foreach (var node in m_CurFlowGraph.nodeList)
                    {
                        if (node == null)
                        {
                            Debug.Log("[FlowEditorWindow] node is null");

                            continue;
                        }

                        if (node.linkList == null)
                        {
                            continue;
                        }

                        FlowNode deleteNode = null;

                        foreach (int linkId in node.linkList)
                        {
                            var linkNode = m_CurFlowGraph.GetNode(linkId);
                            var nodeRect = node.GetRectInGraph(m_CurFlowGraph);
                            var linkRect = linkNode.GetRectInGraph(m_CurFlowGraph);

                            if (DrawBezier(new Vector2(nodeRect.x + nodeRect.width, nodeRect.y + LINK_ICON_WIDTH / 2f), new Vector2(linkRect.x, linkRect.y + LINK_ICON_WIDTH / 2f), Color.yellow))
                            {
                                deleteNode = linkNode;
                            }
                        }

                        if (deleteNode != null)
                        {
                            node.RemoveLinkNode(deleteNode);
                            deleteNode.RemovePreNode(node);
                        }
                    }

                    Handles.EndGUI();
                }

                BeginWindows();

                var nodeList  = m_CurFlowGraph.nodeList;
                int nodeCount = m_CurFlowGraph.nodeCount;

                for (int i = 0; i < nodeCount; i++)
                {
                    var node = nodeList[i];

                    var rect        = node.GetRectInGraph(m_CurFlowGraph);
                    var topLeft     = new Vector2(rect.x, rect.y);
                    var topRight    = new Vector2(rect.x + node.NodeWidth, rect.y);
                    var bottomLeft  = new Vector2(rect.x, rect.y + node.NodeHeight);
                    var bottomRight = new Vector2(rect.x + node.NodeWidth, rect.y + node.NodeHeight);

                    if (m_RectMain.Contains(topLeft) ||
                        m_RectMain.Contains(topRight) ||
                        m_RectMain.Contains(bottomLeft) ||
                        m_RectMain.Contains(bottomRight))
                    {
                        if (node == m_CurSelectFlowNode)
                        {
                            GUI.color = nodeSelectedColor;
                        }
                        else
                        {
                            GUI.color = node.GetColor();
                        }

                        rect = GUI.Window(node.id, rect, DrawNode, node.NodeName);

                        GUI.color = Color.white;
                    }

                    node.SetRectInGraph(m_CurFlowGraph, rect.position);
                }

                DrawLinking();

                EndWindows();
            }
        }
예제 #4
0
            public LatticeCell Evaluate(
                Instruction instruction,
                IReadOnlyDictionary <ValueTag, LatticeCell> cells,
                FlowGraph graph)
            {
                if (instruction.Prototype is CopyPrototype)
                {
                    // Special case on copy instructions because they're
                    // easy to deal with: just return the lattice cell for
                    // the argument.
                    return(cells[instruction.Arguments[0]]);
                }

                var foundTop = false;
                var args     = new Constant[instruction.Arguments.Count];

                for (int i = 0; i < args.Length; i++)
                {
                    var argCell = cells[instruction.Arguments[i]];

                    if (argCell.Kind == LatticeCellKind.Top)
                    {
                        // We can't evaluate this value *yet*. Keep looking
                        // for bottom argument cells and set a flag to record
                        // that this value cannot be evaluated yet.
                        foundTop = true;
                    }
                    else if (argCell.Kind == LatticeCellKind.Constant)
                    {
                        // Yay. We found a compile-time constant.
                        args[i] = argCell.Value;
                    }
                    else
                    {
                        // We can't evaluate this value at compile-time
                        // because one if its arguments is unknown.
                        // Time to early-out.
                        return(EvaluateNonConstantInstruction(instruction, graph));
                    }
                }

                if (foundTop)
                {
                    // We can't evaluate this value yet.
                    return(LatticeCell.Top);
                }
                else
                {
                    // Evaluate the instruction.
                    var constant = EvaluateAsConstant(instruction.Prototype, args);
                    if (constant == null)
                    {
                        // Turns out we can't evaluate the instruction. But maybe
                        // we can say something sensible about its nullability?
                        return(EvaluateNonConstantInstruction(instruction, graph));
                    }
                    else
                    {
                        return(LatticeCell.Constant(constant));
                    }
                }
            }
예제 #5
0
        /// <summary>
        /// Computes the set of all live values in the graph.
        /// </summary>
        /// <param name="graph">The graph to inspect.</param>
        /// <returns>A set of live values.</returns>
        private static HashSet <ValueTag> ComputeLiveValues(FlowGraph graph)
        {
            var liveValues = new HashSet <ValueTag>();

            // Effectful instructions are always live.
            liveValues.UnionWith(graph.GetAnalysisResult <EffectfulInstructions>().Instructions);

            // Remove stores to local variables from the set of
            // effectful instructions. Our reason for doing this is
            // that stores to dead local variables are effectively
            // dead themselves. However, if we assert a priori that all
            // stores are live, then we will end up keeping both the
            // stores and the local variables, as the former take the
            // latter as arguments.
            //
            // When local variables become live, we will mark stores to
            // those variables as live as well. We will not do so before then.
            var localStores = GetLocalStores(graph);

            foreach (var set in localStores.Values)
            {
                liveValues.ExceptWith(set);
            }

            // Entry point parameters are always live too.
            liveValues.UnionWith(graph.GetBasicBlock(graph.EntryPointTag).ParameterTags);

            // Also construct a mapping of basic block parameters to the
            // arguments they take.
            var phiArgs = new Dictionary <ValueTag, HashSet <ValueTag> >();

            foreach (var param in graph.ParameterTags)
            {
                phiArgs[param] = new HashSet <ValueTag>();
            }

            // Instructions that are part of block flows are live.
            foreach (var block in graph.BasicBlocks)
            {
                var flow = block.Flow;
                foreach (var instruction in flow.Instructions)
                {
                    liveValues.UnionWith(instruction.Arguments);
                }

                // While we're at it, we might as well populate `phiArgs`.
                foreach (var branch in flow.Branches)
                {
                    foreach (var pair in branch.ZipArgumentsWithParameters(graph))
                    {
                        if (pair.Value.IsValue)
                        {
                            phiArgs[pair.Key].Add(pair.Value.ValueOrNull);
                        }
                    }
                }
            }

            // Now we simply compute the transitive closure of
            // the set of live values.
            var worklist = new Queue <ValueTag>(liveValues);

            liveValues.Clear();
            while (worklist.Count > 0)
            {
                var value = worklist.Dequeue();
                if (liveValues.Add(value))
                {
                    HashSet <ValueTag> args;
                    if (phiArgs.TryGetValue(value, out args))
                    {
                        foreach (var arg in args)
                        {
                            worklist.Enqueue(arg);
                        }
                    }
                    else
                    {
                        foreach (var arg in graph.GetInstruction(value).Instruction.Arguments)
                        {
                            worklist.Enqueue(arg);
                        }
                        HashSet <ValueTag> storeDependencies;
                        if (localStores.TryGetValue(value, out storeDependencies))
                        {
                            // A local variable has become live. We must mark any store instructions
                            // that depend on said local as live as well.
                            foreach (var dep in storeDependencies)
                            {
                                worklist.Enqueue(dep);
                            }
                        }
                    }
                }
            }

            return(liveValues);
        }
예제 #6
0
 public LabelArgs(string label, FlowGraph graph)
 {
     this.label = label;
     this.graph = graph;
 }
예제 #7
0
        /// <inheritdoc/>
        public RegisterAllocation <TRegister> Analyze(
            FlowGraph graph)
        {
            // Run the related values and interference graph analyses.
            var related      = graph.GetAnalysisResult <RelatedValues>();
            var interference = graph.GetAnalysisResult <InterferenceGraph>();

            // Create a mapping of values to registers. This will become our
            // return value.
            var allocation = new Dictionary <ValueTag, TRegister>();

            // Create a mapping of registers to the set of all values they
            // interfere with due to the registers getting allocated to values.
            var registerInterference = new Dictionary <TRegister, HashSet <ValueTag> >();

            // Before we do any real register allocation, we should set up
            // preallocated registers. The reason for doing this now instead
            // of later on in the allocation loop is that preallocated registers
            // are "free:" they don't incur register allocations. At the same time,
            // preallocated registers can be recycled, so we'll have more
            // registers to recycle (and hopefully create fewer new ones) if we
            // handle preallocated registers first.
            foreach (var value in graph.ValueTags)
            {
                TRegister assignedRegister;
                if (TryGetPreallocatedRegister(value, graph, out assignedRegister))
                {
                    // If we have a preallocated register, then we should just accept it.
                    allocation[value] = assignedRegister;
                    registerInterference[assignedRegister] = new HashSet <ValueTag>(
                        interference.GetInterferingValues(value));
                }
            }

            // Iterate over all values in the graph.
            foreach (var value in graph.ValueTags)
            {
                if (!RequiresRegister(value, graph) || allocation.ContainsKey(value))
                {
                    // The value may not need a register or may already have one.
                    // If so, then we shouldn't allocate one.
                    continue;
                }

                // Compose a set of registers we might be able to recycle.
                // Specifically, we'll look for all registers that are not
                // allocated to values that interfere with the current value.
                var recyclable = new HashSet <TRegister>();
                foreach (var pair in registerInterference)
                {
                    if (!pair.Value.Contains(value))
                    {
                        // If the value is not in the interference set of
                        // the register, then we're good to go.
                        recyclable.Add(pair.Key);
                    }
                }

                // We would like to recycle a register that has been
                // allocated to a related but non-interfering value.
                // To do so, we'll build a set of candidate registers.
                var relatedRegisters = new HashSet <TRegister>();
                foreach (var relatedValue in related.GetRelatedValues(value))
                {
                    TRegister reg;
                    if (allocation.TryGetValue(relatedValue, out reg) &&
                        recyclable.Contains(reg))
                    {
                        relatedRegisters.Add(reg);
                    }
                }

                // If at all possible, try to recycle a related register. If that
                // doesn't work out, try to recycle a non-related register. If
                // that fails as well, then we'll create a new register.
                var       valueType = graph.GetValueType(value);
                TRegister assignedRegister;
                if (!TryRecycleRegister(valueType, relatedRegisters, out assignedRegister) &&
                    !TryRecycleRegister(valueType, recyclable, out assignedRegister))
                {
                    assignedRegister = CreateRegister(valueType);
                    registerInterference[assignedRegister] = new HashSet <ValueTag>();
                }

                // Allocate the register we recycled or created to the value.
                allocation[value] = assignedRegister;
                registerInterference[assignedRegister].UnionWith(
                    interference.GetInterferingValues(value));
            }

            return(new RegisterAllocation <TRegister>(allocation));
        }
 public T Analyze(FlowGraph graph)
 {
     return(Result);
 }
 public T AnalyzeWithUpdates(FlowGraph graph, T previousResult, IReadOnlyList <FlowGraphUpdate> updates)
 {
     return(previousResult);
 }
예제 #10
0
        public void AddTag(string tag, FlowGraph graph)
        {
            VariableDeclarations variableDeclarations = Variables.Graph(graph);

            tags.Add(tag, variableDeclarations);
        }
예제 #11
0
 public FlowGraphView(EditorWindow host, FlowGraph graph, UnityEngine.Object target) : base(host)
 {
     this.m_Graph  = graph;
     this.m_Target = target;
 }
예제 #12
0
        static void Main(string[] args)
        {
            //var input = "{ int x; x := 3; }";
            var input = @"
{
    int x;
    int [10] a;
    int y;
    
    x := 0 + 1 + 2;
    y := x;
    if (not true & false) {
        x := 3;
    } else {
        y := 3;
    }
    a[1+1] := (1+1)*2;
}
";

            var aeinput = @"
{
    int x;
    int [10] a;
    int y;
    
    x := 0 + 1 + 2;
    y := x;
    if (not true & false) {
        x := 3;
    } else {
        y := 3;
    }
    a[1+1] := (1+1)*2;
}";

            var rdinput = @"
{
int x;
int y;
int q;
int r;
if (x >= 0 & y >0) {
q := 0;
r := x;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
}
}
}
} else {
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
    r := r - y;
    q := q + 1;
    while ( r >= y) {
        r := r - y;
        q := q + 1;
    }
}
}
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
    r := r - y;
    q := q + 1;
}           
}

}
write r;
}
";

            var lvinput = @"
{
int x;
int y;
int q;
int r;
if (x >= 0 & y >0) {
q := 0;
r := x;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
}
}
}
} else {
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
    r := r - y;
    q := q + 1;
    while ( r >= y) {
        r := r - y;
        q := q + 1;
    }
}
}
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
    r := r - y;
    q := q + 1;
}           
}

}
write r;
}

";

            var input1 = @"
{
{ int fst; int snd } r;
int x;

r := (0,1);


while (x > 0) {
r.fst := r.fst + x;
r.snd := r.snd * x;
x := x - 1;
}

r := (0, 0);
}
";

            var input2 = @"
{
int x;
int y;
int q;
int r;
if (x >= 0 & y >0) {
q := 0;
r := x;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
}
}
}
} 
write r;
}
";
            var input3 = @"
{
int x;
int y;
int q;
int r;
if (x >= 0 & y >0) {
q := 0;
r := x;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
r := r - y;
q := q + 1;
}
}
}
} else {
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
    r := r - y;
    q := q + 1;
    while ( r >= y) {
        r := r - y;
        q := q + 1;
    }
}
}
while ( r >= y) {
r := r - y;
q := q + 1;
while ( r >= y) {
    r := r - y;
    q := q + 1;
}           
}

}
write r;
}
";


            var result1 = Parser.Util.StringToAst(input1);
            var result2 = Parser.Util.StringToAst(input2);
            var result3 = Parser.Util.StringToAst(input3);

            var result   = Parser.Util.StringToAst(input);
            var aeresult = Parser.Util.StringToAst(aeinput);
            var rdresult = Parser.Util.StringToAst(rdinput);
            var lvresult = Parser.Util.StringToAst(lvinput);

            Console.WriteLine(result);
            var fg = new FlowGraph(result);

            Console.WriteLine(fg.Inital);
            Console.WriteLine(string.Join(" ", fg.Final));
            Console.WriteLine(string.Join("\n", fg.Blocks.Select(s => s.PrintBlock())));
            Console.WriteLine(fg.Edges.Count());
            Console.WriteLine(string.Join("\r\n", fg.Edges));
            var fv = Analysis.Analysis.AnalysisUtil.FreeVariables(result);

            Console.WriteLine(fv.Count);

            var exp1 = new ABinOp(new IntLit(3), new IntLit(4), ABinOperator.Plus);
            var exp2 = new ABinOp(new IntLit(3), new IntLit(4), ABinOperator.Plus);
            var exp3 = new ABinOp(new IntLit(4), new IntLit(4), ABinOperator.Plus);

            var exp4 = new ABinOp(exp1, exp2, ABinOperator.Mult);
            var exp5 = new ABinOp(exp4, exp3, ABinOperator.Div);


            Console.WriteLine(exp1 == exp2);      // Should be false as we are not overloading the operator
            Console.WriteLine(exp1.Equals(exp2)); // Should be true as we have implemented the IEquatable interface
            Console.WriteLine(exp1.Equals(exp3)); // Should be false, different expressions

            var ae  = Analysis.Analysis.AnalysisUtil.AvailableExpressions(exp5);
            var ae2 = Analysis.Analysis.AnalysisUtil.AvailableExpressions(result);

            Console.WriteLine("=========");
            Console.WriteLine(ae);
            Console.WriteLine(ae2);

            //// Overflowing program debug
            //var overflow = "{int x; x:=0; Point.x := 0;}";
            //var overflowParse = Parser.Util.StringToAst(overflow);
            //
            //Console.WriteLine(overflowParse);

            //var x = new Identifier("x", "int", 0);
            //var y = new Identifier("y", "int", 2);
            //var A = new Identifier("A", "array", 1);
            //var d1 = new Dictionary<Identifier, HashSet<int>>();
            //d1[x] = new HashSet<int> {1,2};
            //d1[A] = new HashSet<int> {1};
            //d1[y] = new HashSet<int>() {3};
            //var d2 = new Dictionary<Identifier, HashSet<int>>();
            //d2[x] = new HashSet<int> {1,2,3};
            //d2[A] = new HashSet<int> {2};
            //var l1 = new RDLattice(d1);
            //var l2 = new RDLattice(d2);
            //Console.WriteLine(l1.PartialOrder(l2));
            //var joined = l1.Join(l2);
            //Console.WriteLine(joined);

            // var n = d2.Except(d1);
            // var s = string.Join("\n", n.Select(x => $"{x.Key}: {string.Join(",", x.Value)}"));
            // Console.WriteLine(s);

            //var hs = new HashSet<int?>();
            //hs.Add(1);
            //hs.Add(null);
            //hs.Add(null);
            //hs.Add(2);
            //Console.WriteLine(hs.Count);


            //var t = new AELattice(ae2);
            //var t2 = new AELattice(ae);
            //Console.WriteLine(t);
            //Console.WriteLine(t2);
            //Console.WriteLine(t <= t);
            //Console.WriteLine(t2 <= (t & t2));
            //
            //var analysis = new AEAnalysis(aeresult);
            //Console.WriteLine(analysis);
            //var analysis = new RDAnalysis(rdresult);
            //Console.WriteLine(analysis);


            Console.WriteLine("------- Analysis 1 --------");
            var analysis1 = new FVAnalysis(result1);

            Console.WriteLine("--------- Analysis 2 --------");
            var analysis2 = new FVAnalysis(result2);

            Console.WriteLine("------- Analysis 3 -------");
            var analysis3 = new FVAnalysis(result3);

            Console.WriteLine(string.Join(" ", AnalysisUtil.InterestingValues(result1).Select(x => x.ToString())));

            var analysis4 = new IAAnalysis(result1);

            Console.WriteLine(analysis4);
            //Console.WriteLine(analysis1);
            //Console.WriteLine(analysis2);
            //Console.WriteLine(analysis3);
            //var analysis2 = new LVAnalysis(lvresult);
            //var analysis3 = new FVAnalysis(lvresult);
            //var analysis4 = new DSAnalysis(lvresult);
            //Console.WriteLine(analysis2);
            //Console.WriteLine(analysis3);
            //Console.WriteLine(analysis4);
        }
예제 #13
0
        public void ArgumentExceptionInMinCostSlope()
        {
            var fg = new FlowGraph(2);

            Assert.Throws <ArgumentException>(() => fg.MinCostSlope(1, 1));
        }
예제 #14
0
        public void ArgumentOutOfRangeExceptionInMinCostSlope(int u, int v)
        {
            var fg = new FlowGraph(2);

            Assert.Throws <ArgumentOutOfRangeException>(() => fg.MinCostSlope(u, v));
        }
예제 #15
0
 public void CreateGraph(Object asset)
 {
     m_CurSelectAsset = asset;
     m_CurAssetPath   = AssetDatabase.GetAssetPath(m_CurSelectAsset);
     m_CurFlowGraph   = FlowGraph.LoadFromAsset(m_CurSelectAsset);
 }
예제 #16
0
 /// <inheritdoc/>
 public LatticeAnalysisResult <TCell> Analyze(FlowGraph graph)
 {
     return(FillCells(graph));
 }
예제 #17
0
 public static void GotoLabel(GraphReference reference, string label, FlowGraph graph)
 {
     reference.TriggerEventHandler <LabelArgs>(hook => hook.name == "Label", new LabelArgs(label, graph), parent => true, true);
 }
예제 #18
0
        private LatticeAnalysisResult <TCell> FillCells(FlowGraph graph)
        {
            var uses = graph.GetAnalysisResult <ValueUses>();

            // Create a mapping of values to their corresponding lattice cells.
            var valueCells      = new Dictionary <ValueTag, TCell>();
            var parameterArgs   = new Dictionary <ValueTag, HashSet <ValueTag> >();
            var entryPointBlock = graph.GetBasicBlock(graph.EntryPointTag);

            // Assign 'top' to all values in the graph.
            foreach (var tag in graph.ValueTags)
            {
                valueCells[tag] = Top;
            }

            foreach (var methodParameter in entryPointBlock.ParameterTags)
            {
                // The values of method parameters cannot be inferred by
                // just looking at a method's body. Mark them as bottom cells
                // so we don't fool ourselves into thinking they are constants.
                valueCells[methodParameter] = Bottom;
            }

            var visitedBlocks = new HashSet <BasicBlockTag>();
            var liveBlockSet  = new HashSet <BasicBlockTag>();
            var valueWorklist = new Queue <ValueTag>(entryPointBlock.InstructionTags);
            var flowWorklist  = new Queue <BasicBlockTag>();

            flowWorklist.Enqueue(entryPointBlock);
            visitedBlocks.Add(entryPointBlock);
            liveBlockSet.Add(entryPointBlock);

            while (valueWorklist.Count > 0 || flowWorklist.Count > 0)
            {
                // Process all values in the worklist.
                while (valueWorklist.Count > 0)
                {
                    var value = valueWorklist.Dequeue();
                    var cell  = valueCells[value];

                    var newCell = graph.ContainsInstruction(value)
                        ? UpdateInstructionCell(value, valueCells, graph)
                        : UpdateBlockParameterCell(value, valueCells, parameterArgs);

                    valueCells[value] = newCell;
                    if (!Equals(cell, newCell))
                    {
                        // Visit all instructions and flows that depend on
                        // this instruction.
                        foreach (var item in uses.GetInstructionUses(value))
                        {
                            valueWorklist.Enqueue(item);
                        }
                        foreach (var item in uses.GetFlowUses(value))
                        {
                            flowWorklist.Enqueue(item);
                        }
                    }
                }

                if (flowWorklist.Count > 0)
                {
                    var block = graph.GetBasicBlock(flowWorklist.Dequeue());
                    if (visitedBlocks.Add(block))
                    {
                        // When a block is visited for the first time, add
                        // all of its instructions to the value worklist.
                        foreach (var item in block.InstructionTags)
                        {
                            valueWorklist.Enqueue(item);
                        }
                    }

                    // Process the live branches.
                    foreach (var branch in GetLiveBranches(block.Flow, valueCells, graph))
                    {
                        // The target of every branch we visit is live.
                        liveBlockSet.Add(branch.Target);

                        // Add the branch target to the worklist of blocks
                        // to process if we haven't processed it already.
                        if (!visitedBlocks.Contains(branch.Target))
                        {
                            flowWorklist.Enqueue(branch.Target);
                        }

                        foreach (var pair in branch.ZipArgumentsWithParameters(graph))
                        {
                            if (pair.Value.IsValue)
                            {
                                HashSet <ValueTag> args;
                                if (!parameterArgs.TryGetValue(pair.Key, out args))
                                {
                                    args = new HashSet <ValueTag>();
                                    parameterArgs[pair.Key] = args;
                                }

                                args.Add(pair.Value.ValueOrNull);
                                valueWorklist.Enqueue(pair.Key);
                            }
                            else
                            {
                                valueCells[pair.Key] = Bottom;
                            }
                            valueWorklist.Enqueue(pair.Key);
                        }
                    }
                }
            }

            return(new LatticeAnalysisResult <TCell>(valueCells, liveBlockSet));
        }
예제 #19
0
 /// <summary>
 /// Tells if a register should be allocated for a
 /// particular value.
 /// </summary>
 /// <param name="value">
 /// The value for which register allocation may or may
 /// not be necessary.
 /// </param>
 /// <param name="graph">
 /// The control flow graph that defines <paramref name="value"/>.
 /// </param>
 /// <returns>
 /// <c>true</c> if a register must be allocated to
 /// <paramref name="value"/>; otherwise, <c>false</c>.
 /// </returns>
 /// <remarks>
 /// Implementations may override this method to suppress
 /// register allocation for values that are, e.g., stored
 /// on an evaluation stack.
 /// </remarks>
 protected virtual bool RequiresRegister(
     ValueTag value,
     FlowGraph graph)
 {
     return(true);
 }
예제 #20
0
 /// <inheritdoc/>
 public LazyBlockReachability Analyze(FlowGraph graph)
 {
     return(new LazyBlockReachability(graph));
 }
예제 #21
0
        /// <inheritdoc/>
        public override FlowGraph Apply(FlowGraph graph)
        {
            // Do the fancy analysis.
            var analysis   = Analyzer.Analyze(graph);
            var cells      = analysis.ValueCells;
            var liveBlocks = analysis.LiveBlocks;

            // Get ready to rewrite the flow graph.
            var graphBuilder = graph.ToBuilder();

            // Eliminate switch cases whenever possible.
            SimplifySwitches(graphBuilder, cells);

            // Replace instructions with constants.
            foreach (var selection in graphBuilder.NamedInstructions)
            {
                LatticeCell cell;
                if (cells.TryGetValue(selection, out cell) &&
                    cell.IsConstant)
                {
                    selection.Instruction = Instruction.CreateConstant(
                        cell.Value,
                        selection.Instruction.ResultType);
                }
            }

            // Replace block parameters with constants if possible.
            var phiReplacements = new Dictionary <ValueTag, ValueTag>();
            var entryPoint      = graphBuilder.GetBasicBlock(graphBuilder.EntryPointTag);

            foreach (var block in graphBuilder.BasicBlocks)
            {
                foreach (var param in block.Parameters)
                {
                    LatticeCell cell;
                    if (cells.TryGetValue(param.Tag, out cell) &&
                        cell.IsConstant)
                    {
                        phiReplacements[param.Tag] = entryPoint.InsertInstruction(
                            0,
                            Instruction.CreateConstant(cell.Value, param.Type));
                    }
                }

                var  flowInstructions    = block.Flow.Instructions;
                var  newFlowInstructions = new Instruction[flowInstructions.Count];
                bool anyChanged          = false;
                for (int i = 0; i < newFlowInstructions.Length; i++)
                {
                    var cell = Analyzer.Evaluate(flowInstructions[i], cells, graph);
                    if (cell.IsConstant)
                    {
                        anyChanged             = true;
                        newFlowInstructions[i] = Instruction.CreateConstant(
                            cell.Value,
                            flowInstructions[i].ResultType);
                    }
                    else
                    {
                        newFlowInstructions[i] = flowInstructions[i];
                    }
                }

                if (anyChanged)
                {
                    block.Flow = block.Flow.WithInstructions(newFlowInstructions);
                }
            }

            graphBuilder.ReplaceUses(phiReplacements);
            graphBuilder.RemoveDefinitions(phiReplacements.Keys);

            // Remove all instructions from dead blocks and mark the blocks
            // themselves as unreachable.
            foreach (var tag in graphBuilder.BasicBlockTags.Except(liveBlocks).ToArray())
            {
                var block = graphBuilder.GetBasicBlock(tag);

                // Turn the block's flow into unreachable flow.
                block.Flow = UnreachableFlow.Instance;

                // Delete the block's instructions.
                graphBuilder.RemoveInstructionDefinitions(block.InstructionTags);
            }

            return(graphBuilder.ToImmutable());
        }
예제 #22
0
 /// <summary>
 /// Creates a lazy block reachability analysis for a particular graph.
 /// </summary>
 /// <param name="graph">The graph to create a reachability analysis for.</param>
 public LazyBlockReachability(FlowGraph graph)
 {
     this.Graph   = graph;
     this.results = new Dictionary <BasicBlockTag, HashSet <BasicBlockTag> >();
 }
예제 #23
0
        /// <inheritdoc/>
        public override FlowGraph Apply(FlowGraph graph)
        {
            var memSSA        = graph.GetAnalysisResult <MemorySSA>();
            var aliasing      = graph.GetAnalysisResult <AliasAnalysisResult>();
            var effectfulness = graph.GetAnalysisResult <EffectfulInstructions>();

            var builder = graph.ToBuilder();

            // First try and eliminate loads and stores based on their memory SSA
            // states.
            foreach (var instruction in builder.NamedInstructions)
            {
                var proto = instruction.Prototype;
                if (proto is LoadPrototype)
                {
                    // Loads can be eliminated if we know the memory contents.
                    var      loadProto = (LoadPrototype)proto;
                    var      state     = memSSA.GetMemoryAfter(instruction);
                    ValueTag value;
                    if (state.TryGetValueAt(
                            loadProto.GetPointer(instruction.Instruction),
                            graph,
                            out value))
                    {
                        instruction.Instruction = Instruction.CreateCopy(
                            instruction.ResultType,
                            value);
                    }
                }
                else if (proto is StorePrototype)
                {
                    // Stores can be eliminated if they don't affect the memory state.
                    var storeProto  = (StorePrototype)proto;
                    var stateBefore = memSSA.GetMemoryBefore(instruction);
                    var stateAfter  = memSSA.GetMemoryAfter(instruction);
                    if (stateBefore == stateAfter)
                    {
                        EliminateStore(instruction);
                    }
                }
            }

            // Then try to coalesce stores by iterating through basic blocks.
            foreach (var block in builder.BasicBlocks)
            {
                var pendingStores = new List <NamedInstructionBuilder>();
                foreach (var instruction in block.NamedInstructions)
                {
                    var proto = instruction.Prototype;
                    if (proto is StorePrototype)
                    {
                        var storeProto = (StorePrototype)proto;
                        var pointer    = storeProto.GetPointer(instruction.Instruction);

                        var newPending = new List <NamedInstructionBuilder>();
                        foreach (var pending in pendingStores)
                        {
                            var pendingProto   = (StorePrototype)pending.Prototype;
                            var pendingPointer = pendingProto.GetPointer(pending.Instruction);
                            var aliasState     = aliasing.GetAliasing(pointer, pendingPointer);
                            if (aliasState == Aliasing.MustAlias)
                            {
                                // Yes, do it. Delete the pending store.
                                EliminateStore(pending);
                            }
                            else if (aliasState == Aliasing.NoAlias)
                            {
                                // We can't eliminate the pending store, but we can keep it
                                // in the pending list.
                                newPending.Add(pending);
                            }
                        }
                        pendingStores = newPending;

                        // Add this store to the list of pending stores as well.
                        pendingStores.Add(instruction);
                    }
                    else if (proto is LoadPrototype || proto is CopyPrototype)
                    {
                        // Loads are perfectly benign. They *may* be effectful in the sense
                        // that they can trigger a segfault and make the program blow up, but
                        // there's no way we can catch that anyway. We'll just allow store
                        // coalescing across load boundaries.
                        //
                        // We also want to test for copy instructions here because our effectfulness
                        // analysis is slightly outdated and we may have turned loads/stores into copies.
                    }
                    else if (effectfulness.Instructions.Contains(instruction))
                    {
                        // Effectful instructions are a barrier for store coalescing.
                        pendingStores.Clear();
                    }
                }
            }

            return(builder.ToImmutable());
        }
        /// <summary>
        /// Takes a flow graph and translates it to an instruction stream.
        /// </summary>
        /// <param name="graph">
        /// The flow graph to translate.
        /// </param>
        /// <returns>
        /// A linear sequence of target-specific instructions.
        /// </returns>
        public IReadOnlyList <TInstruction> ToInstructionStream(FlowGraph graph)
        {
            // One thing to keep in mind when selecting instructions is that
            // not all IR instructions must be translated to target-specific instructions.
            //
            // For example, suppose that the target has a specialized add-constant-integer
            // instruction---let's call it `addi`. Then the following sequence of instructions
            //
            //     one = const(1, System::Int32)();
            //     addition = intrinsic(@arith.add, System::Int32, #(System::Int32, System::Int32))(arg, one);
            //
            // should get translated to
            //
            //     <addition> = addi <arg>, 1
            //
            // Note how the `one` instruction doesn't get emitted despite the fact that
            // is it *not* dead from an IR point of view. That's definitely a good thing
            // and it's not something we'll get if we naively create a linear stream of
            // instructions by simply selecting instructions for each IR instruction.
            //
            // To ensure that we select only the instructions we actually need, we will
            // start at
            //
            //   1. "root" instructions: reachable instructions that may have side-effects
            //       and hence *must* be selected, and
            //
            //   2. block flows.
            //
            // Furthermore, we also want to make sure that we emit only reachable basic blocks.
            // All other basic blocks are dead code and we shouldn't bother selecting instructions
            // for them.
            //
            // To figure out which instructions are effectful instructions and which blocks are
            // reachable, we will rely on a couple of analyses.

            var reachability = graph.GetAnalysisResult <BlockReachability>();
            var effectful    = graph.GetAnalysisResult <EffectfulInstructions>();

            // Find the exact set of root instructions. Add them all
            // to a queue of instructions to select.
            var selectionWorklist = new Queue <ValueTag>();

            foreach (var block in graph.BasicBlocks)
            {
                if (!reachability.IsReachableFrom(graph.EntryPointTag, block))
                {
                    continue;
                }

                foreach (var tag in block.InstructionTags.Reverse())
                {
                    if (effectful.Instructions.Contains(tag))
                    {
                        selectionWorklist.Enqueue(tag);
                    }
                }
            }

            // Select target-specific instructions for reachable block flows.
            // Also order the basic blocks.
            var flowLayout    = new List <BasicBlockTag>();
            var flowSelection = new Dictionary <BasicBlockTag, IReadOnlyList <TInstruction> >();
            var flowWorklist  = new Stack <BasicBlockTag>();

            flowWorklist.Push(graph.EntryPointTag);
            while (flowWorklist.Count > 0)
            {
                var tag = flowWorklist.Pop();
                if (flowSelection.ContainsKey(tag))
                {
                    // Never select blocks twice.
                    continue;
                }

                // Assign a dummy value (null) to the block tag so we don't fool
                // ourselves into thinking that the block isn't being processed
                // yet.
                flowSelection[tag] = null;

                // Add the block to the flow layout.
                flowLayout.Add(tag);

                // Fetch the block's flow from the graph.
                var block = graph.GetBasicBlock(tag);
                var flow  = block.Flow;

                // Select instructions for the flow.
                BasicBlockTag fallthrough;
                var           selection = InstructionSelector.SelectInstructions(
                    flow,
                    block.Tag,
                    graph,
                    flow.BranchTargets.FirstOrDefault(target => !flowSelection.ContainsKey(target)),
                    out fallthrough);

                // Emit all branch targets.
                foreach (var target in flow.BranchTargets)
                {
                    flowWorklist.Push(target);
                }

                var selInstructions = selection.Instructions;
                if (fallthrough != null)
                {
                    if (flowSelection.ContainsKey(fallthrough))
                    {
                        // We found a fallthrough block that has already been selected.
                        // This is quite unfortunate; we'll have to introduce a branch.
                        var insns = new List <TInstruction>(selInstructions);
                        insns.AddRange(InstructionSelector.CreateJumpTo(fallthrough));
                        selInstructions = insns;
                    }
                    else
                    {
                        // We found a fallthrough block that has not been selected yet.
                        // Add it to the flow worklist last (because the "worklist" is
                        // actually a stack) to see it get emitted right after this block.
                        flowWorklist.Push(fallthrough);
                    }
                }

                flowSelection[tag] = selInstructions;
                foreach (var item in selection.Dependencies)
                {
                    selectionWorklist.Enqueue(item);
                }
            }

            // Select target-specific instructions.
            var instructionSelection = new Dictionary <ValueTag, IReadOnlyList <TInstruction> >();

            while (selectionWorklist.Count > 0)
            {
                var tag = selectionWorklist.Dequeue();
                if (instructionSelection.ContainsKey(tag) ||
                    graph.ContainsBlockParameter(tag))
                {
                    // Never select instructions twice. Also, don't try
                    // to "select" block parameters.
                    continue;
                }

                var instruction = graph.GetInstruction(tag);
                var selection   = InstructionSelector.SelectInstructions(instruction);

                instructionSelection[tag] = selection.Instructions;
                foreach (var item in selection.Dependencies)
                {
                    selectionWorklist.Enqueue(item);
                }
            }

            // We have selected target-specific instructions for reachable IR block
            // flows and required IR instructions. All we need to do now is patch them
            // together into a linear sequence of target-specific instructions.
            var instructionStream = new List <TInstruction>();

            foreach (var blockTag in flowLayout)
            {
                instructionStream.AddRange(InstructionSelector.CreateBlockMarker(graph.GetBasicBlock(blockTag)));
                foreach (var insnTag in graph.GetBasicBlock(blockTag).InstructionTags)
                {
                    IReadOnlyList <TInstruction> selection;
                    if (instructionSelection.TryGetValue(insnTag, out selection))
                    {
                        instructionStream.AddRange(selection);
                    }
                }
                instructionStream.AddRange(flowSelection[blockTag]);
            }
            return(instructionStream);
        }
예제 #25
0
        /// <inheritdoc/>
        public override FlowGraph Apply(FlowGraph graph)
        {
            // Figure out which aggregates can be replaced by scalars.
            var eligible = FindEligibleAllocas(graph);

            var builder = graph.ToBuilder();

            // Create allocas for fields.
            var replacements = new Dictionary <ValueTag, Dictionary <IField, ValueTag> >();

            foreach (var allocaTag in eligible)
            {
                var allocaInstruction = builder.GetInstruction(allocaTag);
                var allocaProto       = (AllocaPrototype)allocaInstruction.Prototype;
                var fieldSlots        = new Dictionary <IField, ValueTag>();
                foreach (var field in allocaProto.ElementType.Fields)
                {
                    fieldSlots[field] = allocaInstruction.InsertAfter(
                        Instruction.CreateAlloca(field.FieldType),
                        allocaTag.Name + "_field_" + field.Name);
                }
                replacements[allocaTag] = fieldSlots;
            }

            // Rewrite instructions.
            foreach (var instruction in builder.NamedInstructions)
            {
                var proto = instruction.Prototype;
                if (proto is GetFieldPointerPrototype)
                {
                    var gfpProto    = (GetFieldPointerPrototype)proto;
                    var basePointer = gfpProto.GetBasePointer(instruction.Instruction);
                    if (eligible.Contains(basePointer))
                    {
                        instruction.Instruction = Instruction.CreateCopy(
                            instruction.Instruction.ResultType,
                            replacements[basePointer][gfpProto.Field]);
                    }
                }
                else if (IsDefaultInitialization(instruction.ToImmutable()))
                {
                    var storeProto = (StorePrototype)proto;
                    var pointer    = storeProto.GetPointer(instruction.Instruction);
                    if (eligible.Contains(pointer))
                    {
                        foreach (var pair in replacements[pointer])
                        {
                            // Initialize each field with
                            //
                            //     c = const(#default, field_type)();
                            //     _ = store(field_pointer, c);
                            //
                            var constant = instruction.InsertAfter(
                                Instruction.CreateDefaultConstant(pair.Key.FieldType));

                            constant.InsertAfter(
                                Instruction.CreateStore(
                                    pair.Key.FieldType,
                                    pair.Value,
                                    constant));
                        }
                        // Replace the store with a copy, in case someone is
                        // using the value it returns.
                        instruction.Instruction = Instruction.CreateCopy(
                            instruction.Instruction.ResultType,
                            storeProto.GetValue(instruction.Instruction));
                    }
                }
            }

            // Delete the replaced allocas.
            builder.RemoveInstructionDefinitions(eligible);

            return(builder.ToImmutable());
        }
예제 #26
0
 public LocalFlowVariableOverlay <T> this[FlowGraph graph]
 {
     get { return(this.localVariableOverlay[graph]); }
     set { this.localVariableOverlay[graph] = value; }
 }