Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Preliminary.

  • Loading branch information...
commit 09e4c6384bbdd1498c86c2b2a33172b1cc97461b 1 parent f0eedce
@whitequark authored
View
13 lib/furnace-avm2/abc/metadata/method_body_info.rb
@@ -40,15 +40,20 @@ def code_to_cfg(options={})
]),
Furnace::AVM2::Transform::FoldPassthroughAssignments.new,
-=begin
- Furnace::AVM2::Transform::ConvertLocalsToSSA.new,
+
+ Furnace::AVM2::Transform::ConvertLocalsToSSA.new(method: method),
+ Furnace::AVM2::Transform::PropagateConstants.new,
+
Furnace::Transform::IterativeProcess.new([
Furnace::AVM2::Transform::DataflowInvariantCodeMotion.new,
+ Furnace::AVM2::Transform::MetadataCheck.new(after: 'dicm'),
Furnace::AVM2::Transform::PartialEvaluation.new,
+ Furnace::AVM2::Transform::MetadataCheck.new(after: 'pe'),
Furnace::AVM2::Transform::SSAOptimize.new,
+ Furnace::AVM2::Transform::MetadataCheck.new(after: 'ssao'),
+ Furnace::AVM2::Transform::FoldInvariantPhiNodes.new,
+ Furnace::AVM2::Transform::MetadataCheck.new(after: 'fipn'),
]),
-=end
- Furnace::AVM2::Transform::PropagateConstants.new,
Furnace::AVM2::Transform::ExpandUnreferencedSets.new,
Furnace::AVM2::Transform::UpdateExceptionVariables.new,
View
3  lib/furnace-avm2/transform.rb
@@ -13,6 +13,7 @@ module Furnace::AVM2::Transform
require_relative "transform/dataflow_invariant_code_motion"
require_relative "transform/partial_evaluation"
require_relative "transform/propagate_constants"
+require_relative "transform/fold_invariant_phi_nodes"
require_relative "transform/fold_ternary_operators"
require_relative "transform/fold_boolean_shortcuts"
require_relative "transform/convert_locals_to_ssa"
@@ -22,3 +23,5 @@ module Furnace::AVM2::Transform
require_relative "transform/update_exception_variables"
require_relative "transform/cfg_reduce"
require_relative "transform/nf_normalize"
+
+require_relative "transform/metadata_check"
View
6 lib/furnace-avm2/transform/convert_locals_to_ssa.rb
@@ -74,6 +74,12 @@ def transform(cfg)
node.metadata)
block.metadata.add_set s_index, s_node
+ block.metadata.gets_upper.each do |get, upper|
+ if upper == node
+ block.metadata.gets_upper[get] = s_node
+ end
+ end
+
set_locals << s_index
variable_map[index].add s_index
View
6 lib/furnace-avm2/transform/dataflow_invariant_code_motion.rb
@@ -11,7 +11,7 @@ def update(ast, meta, new_upper)
end
def on_r(node)
- @meta.gets_upper[node] = @new_upper
+ @meta.add_get node.children, @new_upper, node
end
end
@@ -64,8 +64,9 @@ def transform(cfg)
end
if do_move
- block.insns.delete src_node
block_meta.remove_set id
+ block_meta.unregister_upper src_node
+ block.insns.delete src_node
value = src_node.children.last
dst_node.update(value.type, value.children, value.metadata)
@@ -88,6 +89,7 @@ def transform(cfg)
if src_node.nil? || src_node.metadata[:write_barrier].empty?
block.insns.delete src_node
block_meta.remove_set id
+ block_meta.unregister_upper src_node
block_changed = true
end
View
1  lib/furnace-avm2/transform/expand_unreferenced_sets.rb
@@ -12,6 +12,7 @@ def transform(cfg)
if set.metadata[:write_barrier].empty?
block.insns.delete set
+ block.metadata.unregister_upper set
else
_, set_value = set.children
set.update(set_value.type,
View
68 lib/furnace-avm2/transform/fold_invariant_phi_nodes.rb
@@ -0,0 +1,68 @@
+module Furnace::AVM2
+ module Transform
+ class FoldInvariantPhiNodes
+ def transform(cfg)
+ set_aliases = Hash.new { Set[] }
+ set_origins = {}
+
+ cfg.nodes.each do |block|
+ block_aliases = Set[]
+
+ block.metadata.sets.each do |set|
+ set_origins[set] = block
+ set_aliases[set] = block_aliases
+ block_aliases.add set
+ end
+ end
+
+ updated = false
+
+ cfg.nodes.each do |block|
+ p "========== BLOCK #{block.label}"
+ block.metadata.gets_map.each do |get, nodes|
+ nodes.each do |node|
+ p "GET #{get} #{node}"
+
+ redundant = set_aliases[get] & node.children
+ origin = set_origins[get]
+
+ if origin == block
+ preceding_sets = redundant.select { |id|
+ origin.insns.index(origin.metadata.set_map[id]) <
+ origin.insns.index(origin.metadata.gets_upper[node])
+ }
+ p "SAME ORIGIN", preceding_sets
+ else
+ preceding_sets = redundant
+ p "OTHER ORIGIN", preceding_sets
+ end
+
+ next unless preceding_sets.count > 1
+
+ keep = preceding_sets.max_by { |id|
+ origin.insns.index(origin.metadata.set_map[id])
+ }
+
+ preceding_sets.delete keep
+ p "KEEP #{keep} REMOVE #{preceding_sets.to_a}"
+
+ node.children -= preceding_sets.to_a
+
+ preceding_sets.each do |id|
+ block.metadata.gets_map[id].delete node
+ if block.metadata.gets_map[id].empty?
+ block.metadata.gets.delete id
+ block.metadata.gets_map.delete id
+ end
+ end
+
+ updated = true
+ end
+ end
+ end
+
+ cfg if updated
+ end
+ end
+ end
+end
View
78 lib/furnace-avm2/transform/metadata_check.rb
@@ -0,0 +1,78 @@
+module Furnace::AVM2
+ module Transform
+ class MetadataCheck
+ include AST::Visitor
+
+ def on_s(node)
+ id, value = node.children
+ @set_map[id] = node
+ @sets.add id
+ end
+
+ def on_r(node)
+ ids = node.children
+ ids.each do |id|
+ @gets.add id
+ @gets_map[id] << node
+ @gets_upper[node] = @upper
+ end
+ end
+
+ def initialize(options={})
+ @idempotent = options[:idempotent] || false
+ @after = options[:after]
+ end
+
+ def transform(cfg)
+ cfg.nodes.each do |block|
+ @sets = Set[]
+ @gets = Set[]
+ @set_map = {}
+ @gets_map = Hash.new { |h, k| h[k] = Set[] }
+ @gets_upper = {}
+
+ block.insns.each do |node|
+ @upper = node
+ visit node
+ end
+
+ metadata = block.metadata
+
+ metadata.gets_map.each do |id,|
+ # make automatically created sets to be the same in both hashes
+ @gets_map[id]
+ end
+
+ block = "block #{block.label}"
+ block << " after #{@after}" if @after
+
+ if @gets != metadata.gets
+ raise "#{block}: gets mismatch: diff: actual #{(@gets - metadata.gets).inspect}, stored #{(metadata.gets - @gets).inspect}"
+ end
+
+ if @sets != metadata.sets
+ raise "#{block}: sets mismatch: diff: actual #{(@sets - metadata.sets).inspect}, stored #{(metadata.sets - @sets).inspect}"
+ end
+
+ if @set_map != metadata.set_map
+ raise "#{block}: set map mismatch: actual #{@set_map.pretty_inspect}, stored #{metadata.set_map.pretty_inspect}"
+ end
+
+ if @gets_map != metadata.gets_map
+ raise "#{block}: gets map mismatch: actual #{@gets_map.pretty_inspect}, stored #{metadata.gets_map.pretty_inspect}"
+ end
+
+ if @gets_upper != metadata.gets_upper
+ raise "#{block}: gets upper mismatch: actual #{@gets_upper.pretty_inspect}, stored #{metadata.gets_upper.pretty_inspect}"
+ end
+ end
+
+ if @idempotent
+ cfg
+ else
+ nil
+ end
+ end
+ end
+ end
+end
View
1  lib/furnace-avm2/transform/partial_evaluation.rb
@@ -20,6 +20,7 @@ def transform(cfg)
end
block.insns.delete block.cti
+ block.metadata.unregister_upper block.cti
block.cti = nil
changed = true
View
1  lib/furnace-avm2/transform/propagate_constants.rb
@@ -23,6 +23,7 @@ def transform(cfg)
if replaced_all
block.metadata.remove_set id
+ block.metadata.unregister_upper set
block.insns.delete set
end
View
21 lib/furnace-avm2/transform/ssa_transform.rb
@@ -75,6 +75,27 @@ def unregister_get(id)
@gets_map.delete id
end
+ def unregister_get_node(node)
+ node.children.each do |id|
+ @gets_map[id].delete node
+
+ if @gets_map[id].empty?
+ @gets_map.delete id
+ @gets.delete id
+ end
+ end
+
+ @gets_upper.delete node
+ end
+
+ def unregister_upper(target_upper)
+ @gets_upper.each do |node, upper|
+ if upper == target_upper
+ unregister_get_node(node)
+ end
+ end
+ end
+
def remove_set(id)
@sets.delete id
@set_map.delete id
View
18 lib/furnace-avm2/transform/subgraph_operations.rb
@@ -88,18 +88,24 @@ def replace_r_nodes(cfg, root, target_id, replacement)
replaced_all = true
walk_live_nodes(cfg, root, target_id) do |block|
- gets = block.metadata.gets_map[target_id]
- gets.each do |get|
- if get.children.one?
- get.update(replacement.type,
+ replaced_all_in_block = true
+
+ gets_map = block.metadata.gets_map[target_id]
+ gets_map.each do |node|
+ if node.children.one?
+ node.update(replacement.type,
replacement.children,
replacement.metadata)
else
- replaced_all = false
+ replaced_all_in_block = false
end
end
- block.metadata.unregister_get target_id
+ if replaced_all_in_block
+ block.metadata.unregister_get target_id
+ else
+ replaced_all = false
+ end
end
if replaced_all
Please sign in to comment.
Something went wrong with that request. Please try again.