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); } }