public BuildBlocks(List<TExp> instList) { Dictionary<Temp.Label, BasicBlock> LabelToBlock = new Dictionary<Temp.Label, BasicBlock>(); foreach (TExp e in instList) { if (e is Label) { BasicBlock b = new BasicBlock(); Blocks.Add(b); LabelToBlock[(e as Label).Lab] = b; } Blocks[Blocks.Count - 1].List.Add(e); } for (int i = 0; i < Blocks.Count; ++i) { BasicBlock b = Blocks[i]; if (b.List[b.List.Count - 1] is Jump) { b.AddEdge(LabelToBlock[(b.List[b.List.Count - 1] as Jump).Label.Lab]); } else { if (i + 1 < Blocks.Count) b.AddEdge(Blocks[i + 1]); if (b.List[b.List.Count - 1] is CJump) b.AddEdge(LabelToBlock[(b.List[b.List.Count - 1] as CJump).Label.Lab]); else if (b.List[b.List.Count - 1] is CJumpInt) b.AddEdge(LabelToBlock[(b.List[b.List.Count - 1] as CJumpInt).Label.Lab]); } } }
public override BasicBlock<MilocInstruction> Load(int target) { var b = new BasicBlock<MilocInstruction>(); b.Add(new LoadaiFieldInstruction(addressReg, name, target) { ContainingType = containingType, FieldIndex = fieldIndex, FieldType = this.Type }); b.Reg = target; return b; }
public void AddEdge(BasicBlock target) { if (target == null) return; Next.Add(target); target.Prev.Add(this); }
public override BasicBlock<MilocInstruction> Load(int target) { var b = new BasicBlock<MilocInstruction>(); b.Add(new LoadglobalInstruction(name, target) { Type = this.Type }); b.Reg = target; return b; }
public override BasicBlock<MilocInstruction> Load(int target) { var b = new BasicBlock<MilocInstruction>(); b.Add(new LoadaiVarInstruction(name, target) { ArgIndex = ArgIndex }); b.Reg = target; return b; }
public override BasicBlock<MilocInstruction> Load(int target) { var b = new BasicBlock<MilocInstruction>(); b.Add(new MovInstruction(this.reg, target) { ArgIndex = ArgIndex, ArgReg = reg }); b.Reg = target; return b; }
/// <summary> /// replaces comparisons where one operand has just been set to a const zero. /// asumes that instruction is a comparison instruction with two registers. /// </summary> private bool OptimizeComparisonToConstZero(Instruction ins, BasicBlock bb) { var r1 = ins.Registers[0]; var r2 = ins.Registers[1]; bool? r1IsZero = null, r2IsZero = null; if (r1.Category == RCategory.Argument || r1.PreventOptimization) r1IsZero = false; if (r2.Category == RCategory.Argument || r2.PreventOptimization) r2IsZero = false; for (var prev = ins.PreviousOrDefault; prev != null && prev.Index >= bb.Entry.Index; prev=prev.PreviousOrDefault) { if(r1IsZero.HasValue && r2IsZero.HasValue) break; if ((r1IsZero.HasValue && r1IsZero.Value) || (r2IsZero.HasValue && r2IsZero.Value)) break; if (r1IsZero == null) { if (r1.IsDestinationIn(prev)) { r1IsZero = prev.Code == RCode.Const && Convert.ToInt32(prev.Operand) == 0; continue; } } if (r2IsZero == null) { if (r2.IsDestinationIn(prev)) { r2IsZero = prev.Code == RCode.Const && Convert.ToInt32(prev.Operand) == 0; continue; } } } if (r2IsZero.HasValue && r2IsZero.Value) { ins.Code = ToComparisonWithZero(ins.Code); ins.Registers.Clear(); ins.Registers.Add(r1); return true; } if (r1IsZero.HasValue && r1IsZero.Value) { // swap the registers before converting to zero-comparison. ins.Code = ToComparisonWithZero(SwapComparisonRegisters(ins.Code)); ins.Registers.Clear(); ins.Registers.Add(r2); return true; } return false; }
/// <summary> /// Links the blocks. /// </summary> /// <param name="source">The source.</param> /// <param name="destination">The destination.</param> protected void LinkBlocks(BasicBlock source, BasicBlock destination) { if (!source.NextBlocks.Contains(destination)) source.NextBlocks.Add(destination); if (!destination.PreviousBlocks.Contains(source)) destination.PreviousBlocks.Add(source); }
public IEnumerable<BasicBlock> GetSuccessors(BasicBlock source) { foreach (XRef xref in graph.GetReferencesFrom(source.Location)) { // TODO: change Find to ExactMatch. yield return blocks.Find(xref.Target); } }
/// <summary> /// /// </summary> /// <param name="context"></param> public void LinkBlockToClause(Context context, BasicBlock block) { foreach (EhClause clause in this.Clauses) { if (clause.LinkBlockToClause(context, block)) return; } }
public BasicBlockEdge(CFG cfg, int fromName, int toName) { From = cfg.CreateNode(fromName); To = cfg.CreateNode(toName); From.OutEdges.Add(To); To.InEdges.Add(From); cfg.AddEdge(this); }
List<BasicBlock> IDominanceAnalysis.GetChildren(BasicBlock block) { List<BasicBlock> child; if (children.TryGetValue(block, out child)) return child; else return new List<BasicBlock>(); // Empty List }
public BBLoop(BasicBlock head, BasicBlock tail, IMSet<BasicBlock> body, JST.Identifier label) { Head = head; Tail = tail; Body = body; Label = label; var headEscapes = false; var headbranchbb = head as BranchBasicBlock; foreach (var t in head.Targets) { if (!body.Contains(t)) headEscapes = true; } var tailEscapes = false; var tailbranchbb = tail as BranchBasicBlock; foreach (var t in tail.Targets) { if (!body.Contains(t)) tailEscapes = true; } if (!headEscapes && tailEscapes && tailbranchbb != null) { if (tailbranchbb.Target.Equals(head)) Flavor = LoopFlavor.DoWhile; else if (tailbranchbb.Fallthrough.Equals(head)) Flavor = LoopFlavor.FlippedDoWhile; else throw new InvalidOperationException("invalid loop"); } else if (headEscapes && !tailEscapes && headbranchbb != null) { if (body.Contains(headbranchbb.Target)) Flavor = LoopFlavor.WhileDo; else if (body.Contains(headbranchbb.Fallthrough)) Flavor = LoopFlavor.FlippedWhileDo; else throw new InvalidOperationException("invalid loop"); } else if (!headEscapes && !tailEscapes) Flavor = LoopFlavor.Loop; else if (headEscapes && tailEscapes && headbranchbb != null && tailbranchbb != null) { // Could encode as do-while with a break at start, or while-do with a break at end. if (body.Contains(headbranchbb.Target)) Flavor = LoopFlavor.WhileDo; else if (body.Contains(headbranchbb.Fallthrough)) Flavor = LoopFlavor.FlippedWhileDo; else throw new InvalidOperationException("invalid loop"); } else Flavor = LoopFlavor.Unknown; }
private static void Redirect(List<BasicBlock> blocks, BasicBlock oldBlock, BasicBlock newBlock) { foreach (BasicBlock b in blocks) { if (b.UnconditionalTarget == oldBlock) b.UnconditionalTarget = newBlock; if (b.ConditionalTarget == oldBlock) b.ConditionalTarget = newBlock; } }
private Context GetFirstContext(BasicBlock block) { for (Context context = new Context(InstructionSet, block); !context.IsBlockEndInstruction; context.GotoNext()) { if (context.IsBlockStartInstruction) continue; return context; } return null; }
public BasicBlockEdge(CFG cfg, int fromName, int toName) { from = cfg.createNode(fromName); to = cfg.createNode(toName); from.addOutEdge(to); to.addInEdge(from); cfg.addEdge(this); }
public ExtendedBlock(BasicBlock basicBlock, int registerCount, int loopDepth) { this.BasicBlock = basicBlock; this.LiveGen = new BitArray(registerCount); this.LiveKill = new BitArray(registerCount); this.LiveOut = new BitArray(registerCount); this.LiveIn = new BitArray(registerCount); this.LiveKillNot = new BitArray(registerCount); this.LoopDepth = loopDepth; }
private void doInvoke(string id, BasicBlock<MilocInstruction> b, List<int> regLocs) { var fun = CSC431.Program.Stable.Value.getType(id); for (int i = 0; i < regLocs.Count; i++) { var t = fun.getArgs()[i]; b.Add(new StoreoutargumentInstruction(regLocs[i], i) { Type = t }); } b.Add(new CallInstruction(id)); }
protected void RemoveDeadBlock(BasicBlock block) { if (trace.Active) trace.Log("*** RemoveBlock: " + block.ToString()); var nextBlocks = block.NextBlocks.ToArray(); EmptyBlockOfAllInstructions(block); UpdatePhiList(block, nextBlocks); }
public MoveResolver(BasicBlock anchor, BasicBlock source, BasicBlock destination) { Debug.Assert(source != null); Debug.Assert(destination != null); Debug.Assert(anchor != null); this.Anchor = anchor; this.Source = source; this.Destination = destination; this.moves = new List<Move>(); }
private void SplitEdge(BasicBlock from, BasicBlock to) { // Create new block z var ctx = CreateNewBlockContext(); InsertJumpInstruction(ctx, to); ctx.Label = -1; ReplaceBranchTargets(from, to, ctx.Block); }
public BasicBlock CreateNode(int name) { var node = BasicBlockMap.ContainsKey(name) ? BasicBlockMap[name] : null; if (node == null) { node = new BasicBlock(name); BasicBlockMap[name] = node; } if (StartNode == null) StartNode = node; return node; }
public IDominanceAnalysis GetDominanceAnalysis(BasicBlock headBlock) { IDominanceAnalysis analysis; if (!blockAnalysis.TryGetValue(headBlock, out analysis)) { analysis = dominanceAnalysisFactory(); analysis.PerformAnalysis(basicBlocks, headBlock); blockAnalysis.Add(headBlock, analysis); } return analysis; }
internal ILBuilder(ITokenDeferral module, LocalSlotManager localSlotManager, OptimizationLevel optimizations) { Debug.Assert(BitConverter.IsLittleEndian); this.module = module; this.LocalSlotManager = localSlotManager; _emitState = default(EmitState); _scopeManager = new LocalScopeManager(); leaderBlock = _currentBlock = _scopeManager.CreateBlock(this); _labelInfos = new SmallDictionary<object, LabelInfo>(ReferenceEqualityComparer.Instance); _optimizations = optimizations; }
internal ILBuilder(ITokenDeferral module, LocalSlotManager localSlotManager, bool isOptimizing) { Debug.Assert(BitConverter.IsLittleEndian); this.module = module; this.LocalSlotManager = localSlotManager; this.emitState = default(EmitState); this.scopeManager = new LocalScopeManager(); leaderBlock = currentBlock = this.scopeManager.CreateBlock(this); labelInfos = new SmallDictionary<object, LabelInfo>(ReferenceEqualityComparer.Instance); this.isOptimizing = isOptimizing; }
/// <summary> /// Default ctor. /// </summary> internal BlockSpillCodeGenerator(BasicBlock block, RegisterMapper mapper, List<Register> lowRegisters, List<Register> invokeFrame, List<Register> allRegisters) { this.block = block; this.mapper = mapper; this.lowRegisters = new LowRegisterState[lowRegisters.Count]; LowRegisterState next = null; for (var i = lowRegisters.Count - 1; i >= 0; i--) { this.lowRegisters[i] = new LowRegisterState(lowRegisters[i], next); next = this.lowRegisters[i]; } this.invokeFrame = invokeFrame; this.allRegisters = allRegisters; }
/// <summary> /// Adds the value. /// </summary> /// <param name="ctx">The context.</param> /// <param name="edge">The edge.</param> /// <param name="op">The op.</param> public static void AddValue(Context ctx, BasicBlock edge, StackOperand op) { PhiData phiData = ctx.Other as PhiData; if (phiData == null) { phiData = new PhiData(); ctx.Other = phiData; } List<BasicBlock> blocks = phiData.Blocks as List<BasicBlock>; Debug.Assert(blocks.Count < 255, @"Maximum number of operands in PHI exceeded."); blocks.Add(edge); phiData.Operands.Add(op); }
private static int RefCount(List<BasicBlock> blocks, BasicBlock block) { int refcnt = 0; foreach (BasicBlock b in blocks) { if (b.UnconditionalTarget == block) refcnt++; if (b.ConditionalTarget == block) refcnt++; if (b.handlerTarget == block) refcnt++; } return refcnt; }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> void IMethodCompilerStage.Run() { if (methodCompiler.Compiler.PlugSystem.GetPlugMethod(methodCompiler.Method) != null) return; if (!methodCompiler.Method.HasCode) return; // Create the prologue block Context context = new Context(instructionSet); // Add a jump instruction to the first block from the prologue context.AppendInstruction(IRInstruction.Jmp); context.SetBranch(0); context.Label = BasicBlock.PrologueLabel; prologue = basicBlocks.CreateBlock(BasicBlock.PrologueLabel, context.Index); basicBlocks.AddHeaderBlock(prologue); SplitIntoBlocks(0); // Create the epilogue block context = new Context(instructionSet); // Add null instruction, necessary to generate a block index context.AppendInstruction(null); context.Label = BasicBlock.EpilogueLabel; epilogue = basicBlocks.CreateBlock(BasicBlock.EpilogueLabel, context.Index); // Link all the blocks together BuildBlockLinks(prologue); foreach (ExceptionHandlingClause exceptionClause in methodCompiler.ExceptionClauseHeader.Clauses) { if (exceptionClause.HandlerOffset != 0) { BasicBlock basicBlock = basicBlocks.GetByLabel(exceptionClause.HandlerOffset); BuildBlockLinks(basicBlock); basicBlocks.AddHeaderBlock(basicBlock); } if (exceptionClause.FilterOffset != 0) { BasicBlock basicBlock = basicBlocks.GetByLabel(exceptionClause.FilterOffset); BuildBlockLinks(basicBlock); basicBlocks.AddHeaderBlock(basicBlock); } } }
/// <summary> /// Enters the SSA. /// </summary> /// <param name="headBlock">The head block.</param> private void EnterSSA(BasicBlock headBlock) { var analysis = MethodCompiler.DominanceAnalysis.GetDominanceAnalysis(headBlock); variables = new Dictionary<Operand, Stack<int>>(); counts = new Dictionary<Operand, int>(); foreach (var op in phiPlacementStage.Assignments.Keys) { AddToAssignments(op); } if (headBlock.NextBlocks.Count > 0) { RenameVariables(headBlock.NextBlocks[0], analysis); } }
protected virtual void UpdateOutput(DataFlowAnalysisResultBuilder <TAnalysisData> builder, BasicBlock block, TAnalysisData newOutput) { var currentData = builder[block]; var newData = currentData.WithOutput(newOutput); builder.Update(block, newData); }
public Edge(BasicBlock fromNode, BasicBlock toNode) { From = fromNode; To = toNode; }
/// <summary> /// Function to find out whether a basic block is in a loop body, or not. /// </summary> /// <param name="actual">The questioned basic block.</param> /// <returns>True if the basic block is in a loop, False if not.</returns> private static bool _isLoopBody(BasicBlock bb) { return(StartFromBB(bb, true)); }
internal static ThrownExceptionInfo CreateDefaultInfoForExceptionsPathAnalysis(BasicBlock block, WellKnownTypeProvider wellKnownTypeProvider, ImmutableStack <IOperation> interproceduralCallStackOpt) { Debug.Assert(wellKnownTypeProvider.Exception != null); return(new ThrownExceptionInfo(block, wellKnownTypeProvider.Exception, interproceduralCallStackOpt, isDefaultExceptionForExceptionsPathAnalysis: true)); }
public TAnalysisResult this[BasicBlock block] => _basicBlockStateMap[block];
internal void Update(BasicBlock block, TAnalysisData newData) { _info[block] = newData; }
public TAnalysisData this[BasicBlock block] => _info[block];
private TAnalysisData Flow(BasicBlock block, TAnalysisData data) { return(Flow(OperationVisitor, block, data)); }
public LoopRegion(BasicBlock header, List <int> outputBlocks, BodyRegion body) : base(header, outputBlocks) { Body = body; }
internal abstract TAnalysisResult ToResult(BasicBlock basicBlock, DataFlowAnalysisInfo <TAnalysisData> blockAnalysisData);
public static TAnalysisData Flow(DataFlowOperationVisitor <TAnalysisData, TAbstractAnalysisValue> operationVisitor, BasicBlock block, TAnalysisData data) { if (block.Kind == BasicBlockKind.Entry) { operationVisitor.OnEntry(block, data); } else if (block.Kind == BasicBlockKind.Exit) { operationVisitor.OnExit(block, data); } foreach (var statement in block.Statements) { data = operationVisitor.Flow(statement, block, data); } return(data); }
public override void SetCurrentAnalysisData(BasicBlock basicBlock, BasicBlockAnalysisData data) => _analysisData.SetBlockAnalysisDataFrom(basicBlock, data);
public override BasicBlockAnalysisData GetCurrentAnalysisData(BasicBlock basicBlock) => _analysisData.GetBlockAnalysisData(basicBlock);
public override BasicBlockAnalysisData AnalyzeNonConditionalBranch( BasicBlock basicBlock, BasicBlockAnalysisData currentBlockAnalysisData, CancellationToken cancellationToken) => AnalyzeBranch(basicBlock, currentBlockAnalysisData, cancellationToken);
void SetProgramLocation(BasicBlock block) { _nextNodes = new Queue <CSharpSyntaxNode>(block.Nodes); _nextTerminator = block.Terminator; }
public static string GetDump(ControlFlowGraph cfg) { StringBuilder sb = new StringBuilder(); Dictionary <Operand, string> localNames = new Dictionary <Operand, string>(); string indentation = string.Empty; void IncreaseIndentation() { indentation += Indentation; } void DecreaseIndentation() { indentation = indentation.Substring(0, indentation.Length - Indentation.Length); } void AppendLine(string text) { sb.AppendLine(indentation + text); } IncreaseIndentation(); for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { string blockName = GetBlockName(block); if (block.Next != null) { blockName += $" (next {GetBlockName(block.Next)})"; } if (block.Branch != null) { blockName += $" (branch {GetBlockName(block.Branch)})"; } blockName += ":"; AppendLine(blockName); IncreaseIndentation(); for (Node node = block.Operations.First; node != null; node = node.ListNext) { string[] sources = new string[node.SourcesCount]; string instName = string.Empty; if (node is PhiNode phi) { for (int index = 0; index < sources.Length; index++) { string phiBlockName = GetBlockName(phi.GetBlock(index)); string operName = GetOperandName(phi.GetSource(index), localNames); sources[index] = $"({phiBlockName}: {operName})"; } instName = "Phi"; } else if (node is Operation operation) { for (int index = 0; index < sources.Length; index++) { sources[index] = GetOperandName(operation.GetSource(index), localNames); } instName = operation.Instruction.ToString(); } string allSources = string.Join(", ", sources); string line = instName + " " + allSources; if (node.Destination != null) { line = GetOperandName(node.Destination, localNames) + " = " + line; } AppendLine(line); } DecreaseIndentation(); } return(sb.ToString()); }
protected override ValueContentBlockAnalysisResult ToBlockResult(BasicBlock basicBlock, ValueContentAnalysisData blockAnalysisData) => new ValueContentBlockAnalysisResult(basicBlock, blockAnalysisData);
private static string GetBlockName(BasicBlock block) { return($"block{block.Index}"); }
internal void Add(BasicBlock block) { _info.Add(block, null); }
private static void MarkReachableFromSwitch(ArrayBuilder <BasicBlock> reachableBlocks, BasicBlock block) { var switchBlock = (SwitchBlock)block; var blockBuilder = ArrayBuilder <BasicBlock> .GetInstance(); switchBlock.GetBranchBlocks(blockBuilder); foreach (var targetBlock in blockBuilder) { PushReachableBlockToProcess(reachableBlocks, targetBlock); } blockBuilder.Free(); }
internal ThrownExceptionInfo With(BasicBlock block, ImmutableStack <IOperation> interproceduralCallStackOpt) { Debug.Assert(interproceduralCallStackOpt != InterproceduralCallStack); return(new ThrownExceptionInfo(block, ExceptionType, interproceduralCallStackOpt, IsDefaultExceptionForExceptionsPathAnalysis)); }
private static void MarkReachableFromTry(ArrayBuilder <BasicBlock> reachableBlocks, BasicBlock block) { // Since the try block is reachable, associated // catch and finally blocks are also reachable. var handlerBlock = ((ExceptionHandlerLeaderBlock)block).NextExceptionHandler; Debug.Assert(handlerBlock != null); // Subsequent handlers are either one or more catch // blocks or a single finally block, but not both. if (handlerBlock.Type == BlockType.Finally) { Debug.Assert(handlerBlock.NextExceptionHandler == null); // Walk the finally block before walking the try block since we // need to determine whether the finally makes any code after // the try/finally unreachable (if the finally throws an exception). // (Note, the try block is walked in the outer loop.) if (handlerBlock.Reachability != Reachability.Reachable) { // we have not processed Finally yet, reschedule block for processing // but process the handler first. block.Reachability = Reachability.NotReachable; PushReachableBlockToProcess(reachableBlocks, block); PushReachableBlockToProcess(reachableBlocks, handlerBlock); return; } } else { // The order the try and handler blocks are walked is not important. // Here, we push the handler blocks, then the try block. while (handlerBlock != null) { Debug.Assert(handlerBlock.Type == BlockType.Catch || handlerBlock.Type == BlockType.Fault || handlerBlock.Type == BlockType.Filter); PushReachableBlockToProcess(reachableBlocks, handlerBlock); handlerBlock = handlerBlock.NextExceptionHandler; } } MarkReachableFromBranch(reachableBlocks, block); }
internal static ThrownExceptionInfo Create(BasicBlock block, INamedTypeSymbol exceptionType, ImmutableStack <IOperation> interproceduralCallStackOpt) { return(new ThrownExceptionInfo(block, exceptionType, interproceduralCallStackOpt, isDefaultExceptionForExceptionsPathAnalysis: false)); }
private static void MarkReachableFromBranch(ArrayBuilder <BasicBlock> reachableBlocks, BasicBlock block) { var branchBlock = block.BranchBlock; if (branchBlock != null) { // if branch is blocked by a finally, then should branch to corresponding // BlockedBranchDestination instead. Original label may not be reachable. // if there are no blocking finallys, then BlockedBranchDestination returns null // and we just visit the target. var blockedDest = BlockedBranchDestination(block, branchBlock); if (blockedDest == null) { PushReachableBlockToProcess(reachableBlocks, branchBlock); } else { // just redirect. No need to visit blocking destination // it is a single block infinite loop. RedirectBranchToBlockedDestination(block, blockedDest); } } }
protected override GlobalFlowStateBlockAnalysisResult ToBlockResult(BasicBlock basicBlock, GlobalFlowStateAnalysisData data) => new GlobalFlowStateBlockAnalysisResult(basicBlock, data);
/// <summary> /// Marks blocks that are recursively reachable from the given block. /// </summary> private static void MarkReachableFrom(ArrayBuilder <BasicBlock> reachableBlocks, BasicBlock block) { tryAgain: if (block != null && block.Reachability == Reachability.NotReachable) { block.Reachability = Reachability.Reachable; var branchCode = block.BranchCode; if (branchCode == ILOpCode.Nop && block.Type == BlockType.Normal) { block = block.NextBlock; goto tryAgain; } if (branchCode.CanFallThrough()) { PushReachableBlockToProcess(reachableBlocks, block.NextBlock); } else { // If this block is an "endfinally" block, then clear // the reachability of the following special block. if (branchCode == ILOpCode.Endfinally) { var enclosingFinally = block.EnclosingHandler; if (enclosingFinally != null) { enclosingFinally.UnblockFinally(); } } } switch (block.Type) { case BlockType.Switch: MarkReachableFromSwitch(reachableBlocks, block); break; case BlockType.Try: MarkReachableFromTry(reachableBlocks, block); break; default: MarkReachableFromBranch(reachableBlocks, block); break; } } }
/// <summary> /// Function to find out whether a basic block is in the main Control Flow, or not. /// </summary> /// <param name="bb">The questioned basic block.</param> /// <returns>True if the basic block is in the main Control Flow, False if not.</returns> private static bool _isMainRoute(BasicBlock bb) { return(!StartFromBB(bb, false)); }
private static void PushReachableBlockToProcess(ArrayBuilder <BasicBlock> reachableBlocks, BasicBlock block) { if (block.Reachability == Reachability.NotReachable) { reachableBlocks.Push(block); } }
protected virtual IEnumerable <BasicBlock> GetSuccessors(BasicBlock block) => block.Successors;
protected virtual IEnumerable <BasicBlock> GetPredecessors(BasicBlock block) => block.Predecessors;