Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Various formatting for CFG and DFG
  • Loading branch information
kddnewton committed Feb 3, 2023
commit 28c5a4ac92745c26590794366f014742bc02eebd
30 changes: 18 additions & 12 deletions lib/syntax_tree/yarv/control_flow_graph.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ def disasm

blocks.each do |block|
fmt.output.puts(block.id)
fmt.with_prefix(" ") do
fmt.with_prefix(" ") do |prefix|
unless block.incoming_blocks.empty?
from = block.incoming_blocks.map(&:id).join(", ")
fmt.output.puts("#{fmt.current_prefix}== from: #{from}")
from = block.incoming_blocks.map(&:id)
fmt.output.puts("#{prefix}== from: #{from.join(", ")}")
end

fmt.format_insns!(block.insns, block.block_start)

to = block.outgoing_blocks.map(&:id)
to << "leaves" if block.insns.last.leaves?
fmt.output.puts("#{fmt.current_prefix}== to: #{to.join(", ")}")
fmt.output.puts("#{prefix}== to: #{to.join(", ")}")
end
end

Expand Down Expand Up @@ -142,14 +142,19 @@ def build_basic_blocks

length = 0
blocks =
iseq.insns.grep(Instruction).slice_after do |insn|
length += insn.length
block_starts.include?(length)
end
iseq
.insns
.grep(Instruction)
.slice_after do |insn|
length += insn.length
block_starts.include?(length)
end

block_starts.zip(blocks).to_h do |block_start, block_insns|
[block_start, BasicBlock.new(block_start, block_insns)]
end
block_starts
.zip(blocks)
.to_h do |block_start, block_insns|
[block_start, BasicBlock.new(block_start, block_insns)]
end
end

# Connect the blocks by letting them know which blocks are incoming and
Expand All @@ -162,7 +167,8 @@ def connect_basic_blocks(blocks)
block.outgoing_blocks << blocks.fetch(labels[branch_target])
end

if (insn.branch_targets.empty? && !insn.leaves?) || insn.falls_through?
if (insn.branch_targets.empty? && !insn.leaves?) ||
insn.falls_through?
fall_through_start = block_start + block.insns.sum(&:length)
block.outgoing_blocks << blocks.fetch(fall_through_start)
end
Expand Down
45 changes: 21 additions & 24 deletions lib/syntax_tree/yarv/data_flow_graph.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,39 +32,39 @@ def disasm

cfg.blocks.each do |block|
fmt.output.puts(block.id)
fmt.with_prefix(" ") do
fmt.with_prefix(" ") do |prefix|
unless block.incoming_blocks.empty?
from = block.incoming_blocks.map(&:id).join(", ")
fmt.output.puts("#{fmt.current_prefix}== from: #{from}")
from = block.incoming_blocks.map(&:id)
fmt.output.puts("#{prefix}== from: #{from.join(", ")}")
end

block_flow = block_flows.fetch(block.id)
unless block_flow.in.empty?
fmt.output.puts("#{fmt.current_prefix}== in: #{block_flow.in.join(", ")}")
fmt.output.puts("#{prefix}== in: #{block_flow.in.join(", ")}")
end

fmt.format_insns!(block.insns, block.block_start) do |insn, length|
fmt.format_insns!(block.insns, block.block_start) do |_, length|
insn_flow = insn_flows[length]
next if insn_flow.in.empty? && insn_flow.out.empty?

fmt.output.print(" # ")
unless insn_flow.in.empty?
fmt.output.print("in: #{insn_flow.in.join(", ")}")
fmt.output.print("; ") unless insn_flow.out.empty?
end

unless insn_flow.out.empty?
fmt.output.print("out: #{insn_flow.out.join(", ")}")
end
end

to = block.outgoing_blocks.map(&:id)
to << "leaves" if block.insns.last.leaves?
fmt.output.puts("#{fmt.current_prefix}== to: #{to.join(", ")}")
fmt.output.puts("#{prefix}== to: #{to.join(", ")}")

unless block_flow.out.empty?
fmt.output.puts("#{fmt.current_prefix}== out: #{block_flow.out.join(", ")}")
end
fmt.output.puts("#{prefix}== out: #{block_flow.out.join(", ")}")
end
end
end

Expand Down Expand Up @@ -104,23 +104,20 @@ def self.compile(cfg)
# This class is responsible for creating a data flow graph from the given
# control flow graph.
class Compiler
attr_reader :cfg, :insn_flows, :block_flows
# This is the control flow graph that is being compiled.
attr_reader :cfg

def initialize(cfg)
@cfg = cfg
# This data structure will hold the data flow between instructions
# within individual basic blocks.
attr_reader :insn_flows

# This data structure will hold the data flow between instructions
# within individual basic blocks.
@insn_flows = {}
cfg.insns.each_key do |length|
@insn_flows[length] = DataFlow.new
end
# This data structure will hold the data flow between basic blocks.
attr_reader :block_flows

# This data structure will hold the data flow between basic blocks.
@block_flows = {}
cfg.blocks.each do |block|
@block_flows[block.id] = DataFlow.new
end
def initialize(cfg)
@cfg = cfg
@insn_flows = cfg.insns.to_h { |length, _| [length, DataFlow.new] }
@block_flows = cfg.blocks.to_h { |block| [block.id, DataFlow.new] }
end

def compile
Expand Down
2 changes: 1 addition & 1 deletion lib/syntax_tree/yarv/disassembler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def with_prefix(value)

begin
@current_prefix = value
yield
yield value
ensure
@current_prefix = previous
end
Expand Down
2 changes: 1 addition & 1 deletion lib/syntax_tree/yarv/instruction_sequence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def disasm
end

def inspect
"#<ISeq:#{name}@<compiled>:1 (#{line},#{0})-(#{line},#{0})>"
"#<ISeq:#{name}@<compiled>:1 (#{line},0)-(#{line},0)>"
end

# This method converts our linked list of instructions into a final array
Expand Down