/// <summary> /// Determines if a method body can be inlined, that is, if invalid /// code will be generated by inlining it. /// </summary> /// <param name="calleeBody"> /// A method body that is an inlining candidate. /// </param> /// <param name="caller"> /// The caller that wants to inline <paramref name="calleeBody"/>. /// </param> /// <param name="callerBody"> /// The method body for <paramref name="caller"/>. /// </param> /// <returns> /// <c>true</c> if inlining <paramref name="calleeBody"/> into <paramref name="caller"/> is /// safe; otherwise, <c>false</c>. /// </returns> protected virtual bool CanInline(MethodBody calleeBody, IMethod caller, FlowGraph callerBody) { // To determine if we can inline a method, we essentially just need to // consider all members that show up in the method body and see if the // caller is allowed to access them. var rules = callerBody.GetAnalysisResult <AccessRules>(); var members = calleeBody.Implementation .NamedInstructions.Select(insn => insn.Instruction) .Concat(calleeBody.Implementation.BasicBlocks.SelectMany(block => block.Flow.Instructions)) .SelectMany(insn => insn.Prototype.Members); foreach (var item in members) { if (item is IType && !rules.CanAccess(caller, (IType)item)) { return(false); } else if (item is ITypeMember && !rules.CanAccess(caller, (ITypeMember)item)) { return(false); } } return(true); }
/// <inheritdoc/> public override FlowGraph Apply(FlowGraph graph) { // Compute the value numbering for the graph. var numbering = graph.GetAnalysisResult <ValueNumbering>(); // Partition the set of all instructions into equivalence classes. var equivValues = new Dictionary <Instruction, HashSet <ValueTag> >( new ValueNumberingInstructionComparer(numbering)); foreach (var insn in graph.NamedInstructions) { HashSet <ValueTag> valueSet; if (!equivValues.TryGetValue(insn.Instruction, out valueSet)) { equivValues[insn.Instruction] = valueSet = new HashSet <ValueTag>(); } valueSet.Add(insn); } // Compute the dominator tree for the graph. var domTree = graph.GetAnalysisResult <DominatorTree>(); // Replace instructions with copies to your heart's content. var builder = graph.ToBuilder(); foreach (var insn in builder.Instructions) { // An instruction can be replaced with another instruction // if it is equivalent to that instruction and it is strictly // dominated by the other instruction. HashSet <ValueTag> valueSet; if (!equivValues.TryGetValue(insn.Instruction, out valueSet)) { continue; } foreach (var equivValue in valueSet) { if (domTree.IsStrictlyDominatedBy(insn, equivValue)) { insn.Instruction = Instruction.CreateCopy(insn.Instruction.ResultType, equivValue); break; } } } return(builder.ToImmutable()); }
/// <summary> /// Computes a mapping from basic block tags to their immediate /// dominators. The entry point block is mapped to <c>null</c>. /// </summary> private static IReadOnlyDictionary <BasicBlockTag, BasicBlockTag> GetImmediateDominators( FlowGraph graph) { var preds = graph.GetAnalysisResult <BasicBlockPredecessors>(); return(GetImmediateDominators( graph.BasicBlockTags, graph.EntryPointTag, tag => graph.GetBasicBlock(tag).Flow.BranchTargets, preds.GetPredecessorsOf)); }
/// <inheritdoc/> public ValueLiveness Analyze(FlowGraph graph) { var liveness = new Dictionary <BasicBlockTag, BlockLiveness>(); // First create liveness data for blocks in isolation. foreach (var block in graph.BasicBlocks) { liveness[block.Tag] = BlockLiveness.Create(block); } var preds = graph.GetAnalysisResult <BasicBlockPredecessors>(); // Then propagate imports until a fixpoint is reached. // The idea is to create a worklist of basic blocks that // still need to be processed. var worklist = new Queue <BasicBlockTag>(graph.BasicBlockTags); var workset = new HashSet <BasicBlockTag>(graph.BasicBlockTags); while (worklist.Count > 0) { // Dequeue a block from the worklist. var blockTag = worklist.Dequeue(); workset.Remove(blockTag); var blockData = liveness[blockTag]; // Propagate imports to predecessors. foreach (var predTag in preds.GetPredecessorsOf(blockTag)) { // Every predecessor must export each and every one of the // block's imports. var predData = liveness[predTag]; foreach (var import in blockData.Imports) { // Have the predecessor export the imported value. if (predData.Export(import)) { // The predecessor block doesn't define the imported value // and hence also had to import the imported value. Add the // predecessor block to the worklist. if (workset.Add(predTag)) { worklist.Enqueue(predTag); } } } } } return(new ValueLiveness(liveness)); }