Beispiel #1
0
        internal static bool TryGetFusibleTail(
            BasicBlockTag head,
            FlowGraph graph,
            BasicBlockPredecessors predecessors,
            out BasicBlockTag tail)
        {
            var block    = graph.GetBasicBlock(head);
            var jumpFlow = block.Flow as JumpFlow;

            if (jumpFlow != null && graph.EntryPointTag != jumpFlow.Branch.Target)
            {
                var preds = predecessors.GetPredecessorsOf(jumpFlow.Branch.Target).ToArray();
                if (preds.Length == 1 && preds[0] == block.Tag)
                {
                    tail = jumpFlow.Branch.Target;
                    return(true);
                }
            }
            tail = null;
            return(false);
        }
            /// <summary>
            /// Runs the SSA construction algorithm.
            /// </summary>
            public void Run()
            {
                var entryPoint = graphBuilder.GetBasicBlock(graphBuilder.EntryPointTag);

                // Create a set of all entry point parameters.
                // Here's why: entry point parameters have a
                // very specific meaning in Flame IR. Each parameter
                // corresponds to a method body parameter.
                // The SSA construction algorithm will sometimes
                // append block parameters to the entry point block,
                // which is not something we want.
                //
                // By keeping track of the original entry point
                // parameters, we can tell parameters inserted
                // by the algorithm from preexisting parameters.
                var oldEntryPointParams = entryPoint.Parameters;

                // Fill the entry point first. This will also
                // fill all blocks reachable from the entry
                // point.
                FillBlock(entryPoint);

                // Fill all the garbage blocks.
                foreach (var block in graphBuilder.BasicBlocks)
                {
                    FillBlock(block);
                }

                // Delete the allocas we replaced with copies.
                foreach (var tag in eligibleAllocas)
                {
                    graphBuilder.RemoveInstruction(tag);
                }

                // Somehow eliminate additional entry point parameters.
                // We will use one of two techniques, depending on the
                // situation:
                //
                //   1. If the entry point does not have any predecessors,
                //      then we will simply replace all newly created
                //      entry point parameters with `default` instructions.
                //
                //   2. If the entry point has one or more predecessors,
                //      then we'll create a new entry point block with
                //      a parameter list equivalent to the original entry
                //      point parameters and have that block jump to the
                //      original entry point.
                //
                var epPreds = predecessors.GetPredecessorsOf(entryPoint.Tag).ToArray();

                if (epPreds.Length == 0)
                {
                    var oldParamSet = new HashSet <ValueTag>(oldEntryPointParams.Select(p => p.Tag));
                    var newParams   = entryPoint.Parameters;

                    // Restore entry point parameters.
                    entryPoint.Parameters = oldEntryPointParams;

                    // Define extra parameters as `default` constant instructions.
                    foreach (var parameter in newParams.Reverse())
                    {
                        if (!oldParamSet.Contains(parameter.Tag))
                        {
                            entryPoint.InsertInstruction(
                                0,
                                Instruction.CreateDefaultConstant(parameter.Type),
                                parameter.Tag);
                        }
                    }
                }
                else
                {
                    // Create a new entry point.
                    var newEntryPoint = graphBuilder.AddBasicBlock(
                        entryPoint.Tag.Name + ".thunk");

                    graphBuilder.EntryPointTag = newEntryPoint.Tag;

                    var oldToNew = new Dictionary <ValueTag, ValueTag>();
                    foreach (var oldParam in oldEntryPointParams)
                    {
                        var oldTag = oldParam.Tag;
                        var newTag = new ValueTag(oldTag.Name);
                        newEntryPoint.AppendParameter(
                            new BlockParameter(oldParam.Type, newTag));
                        oldToNew[oldTag] = newTag;
                    }

                    var branchArgs = new List <ValueTag>();
                    foreach (var parameter in entryPoint.Parameters)
                    {
                        ValueTag newTag;
                        if (oldToNew.TryGetValue(parameter.Tag, out newTag))
                        {
                            branchArgs.Add(newTag);
                        }
                        else
                        {
                            branchArgs.Add(
                                newEntryPoint.AppendInstruction(
                                    Instruction.CreateDefaultConstant(parameter.Type)));
                        }
                    }

                    newEntryPoint.Flow = new JumpFlow(entryPoint.Tag, branchArgs);
                }
            }