Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 439ffb6

Browse files
committed
Refactor various graphs
1 parent 92cbfca commit 439ffb6

File tree

4 files changed

+218
-191
lines changed

4 files changed

+218
-191
lines changed

lib/syntax_tree.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
require_relative "syntax_tree/index"
3030

3131
require_relative "syntax_tree/yarv"
32+
require_relative "syntax_tree/yarv/basic_block"
3233
require_relative "syntax_tree/yarv/bf"
3334
require_relative "syntax_tree/yarv/compiler"
3435
require_relative "syntax_tree/yarv/control_flow_graph"

lib/syntax_tree/yarv/basic_block.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
module SyntaxTree
4+
module YARV
5+
# This object represents a single basic block, wherein all contained
6+
# instructions do not branch except for the last one.
7+
class BasicBlock
8+
# This is the unique identifier for this basic block.
9+
attr_reader :id
10+
11+
# This is the index into the list of instructions where this block starts.
12+
attr_reader :block_start
13+
14+
# This is the set of instructions that this block contains.
15+
attr_reader :insns
16+
17+
# This is an array of basic blocks that lead into this block.
18+
attr_reader :incoming_blocks
19+
20+
# This is an array of basic blocks that this block leads into.
21+
attr_reader :outgoing_blocks
22+
23+
def initialize(block_start, insns)
24+
@id = "block_#{block_start}"
25+
26+
@block_start = block_start
27+
@insns = insns
28+
29+
@incoming_blocks = []
30+
@outgoing_blocks = []
31+
end
32+
33+
# Yield each instruction in this basic block along with its index from the
34+
# original instruction sequence.
35+
def each_with_index(&block)
36+
insns.each.with_index(block_start, &block)
37+
end
38+
39+
# This method is used to verify that the basic block is well formed. It
40+
# checks that the only instruction in this basic block that branches is
41+
# the last instruction.
42+
def verify
43+
insns[0...-1].each { |insn| raise unless insn.branch_targets.empty? }
44+
end
45+
end
46+
end
47+
end

lib/syntax_tree/yarv/control_flow_graph.rb

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ def disasm
4040
blocks.each do |block|
4141
output.print(block.id)
4242

43-
unless block.predecessors.empty?
44-
output.print(" # from: #{block.predecessors.map(&:id).join(", ")}")
43+
unless block.incoming_blocks.empty?
44+
output.print(" # from: #{block.incoming_blocks.map(&:id).join(", ")}")
4545
end
4646

4747
output.puts
@@ -51,9 +51,9 @@ def disasm
5151
output.puts(insn.disasm(fmt))
5252
end
5353

54-
successors = block.successors.map(&:id)
55-
successors << "leaves" if block.insns.last.leaves?
56-
output.print(" # to: #{successors.join(", ")}") unless successors.empty?
54+
dests = block.outgoing_blocks.map(&:id)
55+
dests << "leaves" if block.insns.last.leaves?
56+
output.print(" # to: #{dests.join(", ")}") unless dests.empty?
5757

5858
output.puts
5959
end
@@ -72,49 +72,6 @@ def self.compile(iseq)
7272
Compiler.new(iseq).compile
7373
end
7474

75-
# This object represents a single basic block, wherein all contained
76-
# instructions do not branch except for the last one.
77-
class BasicBlock
78-
# This is the unique identifier for this basic block.
79-
attr_reader :id
80-
81-
# This is the index into the list of instructions where this block
82-
# starts.
83-
attr_reader :block_start
84-
85-
# This is the set of instructions that this block contains.
86-
attr_reader :insns
87-
88-
# This is an array of basic blocks that are predecessors to this block.
89-
attr_reader :predecessors
90-
91-
# This is an array of basic blocks that are successors to this block.
92-
attr_reader :successors
93-
94-
def initialize(block_start, insns)
95-
@id = "block_#{block_start}"
96-
97-
@block_start = block_start
98-
@insns = insns
99-
100-
@predecessors = []
101-
@successors = []
102-
end
103-
104-
# Yield each instruction in this basic block along with its index from
105-
# the original instruction sequence.
106-
def each_with_index(&block)
107-
insns.each.with_index(block_start, &block)
108-
end
109-
110-
# This method is used to verify that the basic block is well formed. It
111-
# checks that the only instruction in this basic block that branches is
112-
# the last instruction.
113-
def verify
114-
insns[0...-1].each { |insn| raise unless insn.branch_targets.empty? }
115-
end
116-
end
117-
11875
# This class is responsible for creating a control flow graph from the
11976
# given instruction sequence.
12077
class Compiler
@@ -186,22 +143,22 @@ def build_basic_blocks
186143
end
187144
end
188145

189-
# Connect the blocks by letting them know which blocks precede them and
190-
# which blocks succeed them.
146+
# Connect the blocks by letting them know which blocks are incoming and
147+
# outgoing from each block.
191148
def connect_basic_blocks(blocks)
192149
blocks.each do |block_start, block|
193150
insn = block.insns.last
194151

195152
insn.branch_targets.each do |branch_target|
196-
block.successors << blocks.fetch(labels[branch_target])
153+
block.outgoing_blocks << blocks.fetch(labels[branch_target])
197154
end
198155

199156
if (insn.branch_targets.empty? && !insn.leaves?) || insn.falls_through?
200-
block.successors << blocks.fetch(block_start + block.insns.length)
157+
block.outgoing_blocks << blocks.fetch(block_start + block.insns.length)
201158
end
202159

203-
block.successors.each do |successor|
204-
successor.predecessors << block
160+
block.outgoing_blocks.each do |outgoing_block|
161+
outgoing_block.incoming_blocks << block
205162
end
206163
end
207164
end

0 commit comments

Comments
 (0)