class SyntaxTree::YARV::SeaOfNodes::Compiler

def create_local_graph(block)

inputs and outputs will be left dangling, to be connected later.
Create a sub-graph for a single basic block - block block argument
def create_local_graph(block)
  block_flow = dfg.block_flows.fetch(block.id)
  # A map of instructions to nodes.
  insn_nodes = {}
  # Create a node for each instruction in the block.
  block.each_with_length do |insn, offset|
    node = InsnNode.new(insn, offset)
    insn_nodes[offset] = node
    nodes << node
  end
  # The first and last node in the sub-graph, and the last fixed node.
  previous_fixed = nil
  first_fixed = nil
  last_fixed = nil
  # The merge node for the phi nodes to attach to.
  merge_node = nil
  # If there is more than one predecessor and we have basic block
  # arguments coming in, then we need a merge node for the phi nodes to
  # attach to.
  if block.incoming_blocks.size > 1 && !block_flow.in.empty?
    merge_node = MergeNode.new(id_counter)
    nodes << merge_node
    previous_fixed = merge_node
    first_fixed = merge_node
    last_fixed = merge_node
  end
  # Connect local control flow (only nodes with side effects.)
  block.each_with_length do |insn, length|
    if insn.side_effects?
      insn_node = insn_nodes[length]
      connect previous_fixed, insn_node, :control if previous_fixed
      previous_fixed = insn_node
      first_fixed ||= insn_node
      last_fixed = insn_node
    end
  end
  # Connect basic block arguments.
  inputs = {}
  outputs = {}
  block_flow.in.each do |arg|
    # Each basic block argument gets a phi node. Even if there's only
    # one predecessor! We'll tidy this up later.
    phi = PhiNode.new(id_counter)
    connect(phi, merge_node, :info) if merge_node
    nodes << phi
    inputs[arg] = phi
    block.each_with_length do |_, consumer_offset|
      consumer_flow = dfg.insn_flows[consumer_offset]
      consumer_flow.in.each_with_index do |producer, input_index|
        if producer == arg
          connect(phi, insn_nodes[consumer_offset], :data, input_index)
        end
      end
    end
    block_flow.out.each { |out| outputs[out] = phi if out == arg }
  end
  # Connect local dataflow from consumers back to producers.
  block.each_with_length do |_, consumer_offset|
    consumer_flow = dfg.insn_flows.fetch(consumer_offset)
    consumer_flow.in.each_with_index do |producer, input_index|
      if producer.local?
        connect(
          insn_nodes[producer.length],
          insn_nodes[consumer_offset],
          :data,
          input_index
        )
      end
    end
  end
  # Connect dataflow from producers that leaves the block.
  block.each_with_length do |_, producer_pc|
    dfg
      .insn_flows
      .fetch(producer_pc)
      .out
      .each do |consumer|
        unless consumer.local?
          # This is an argument to the successor block - not to an
          # instruction here.
          outputs[consumer.name] = insn_nodes[producer_pc]
        end
      end
  end
  # A graph with only side-effect free instructions will currently have
  # no fixed nodes! In that case just use the first instruction's node
  # for both first and last. But it's a bug that it'll appear in the
  # control flow path!
  SubGraph.new(
    first_fixed || insn_nodes[block.block_start],
    last_fixed || insn_nodes[block.block_start],
    inputs,
    outputs
  )
end