fix releasing in allocator
fell into hash new trap, which reuses the object you give it. not good for mutable objects like the array. also previous logic was broken in terms of machine vs ssa names
This commit is contained in:
parent
3f131a4018
commit
f13e6dcf57
@ -13,7 +13,7 @@ module Risc
|
||||
@compiler = compiler
|
||||
@platform = platform
|
||||
@used_regs = {}
|
||||
@release_points = Hash.new( [] )
|
||||
@release_points = Hash.new {|hash , key | hash[key] = [] }
|
||||
@reg_names = (0 ... platform.num_registers).collect{|i| "r#{i}".to_sym }
|
||||
end
|
||||
attr_reader :used_regs , :compiler , :platform , :reg_names
|
||||
@ -28,11 +28,25 @@ module Risc
|
||||
pointer = @compiler.risc_instructions
|
||||
while(pointer)
|
||||
names = assign(pointer)
|
||||
names.each {|name| release_reg(name)}
|
||||
names.each {|name| release_after(pointer, name)}
|
||||
pointer = pointer.next
|
||||
end
|
||||
end
|
||||
|
||||
# if the instruction has a release point with the given name, release it
|
||||
# Release points store the last use of a register (in ssa)
|
||||
# This method is called after machine registers have been assigned,
|
||||
# and give us the chance to reclaim any unsued machine regs
|
||||
# (via the precalculated release_points)
|
||||
def release_after(instruction , ssa_name)
|
||||
release = @release_points[instruction]
|
||||
return unless release
|
||||
return unless release.include?(ssa_name)
|
||||
#puts "ReleasePoint #{ssa_name} for #{instruction} #{release}"
|
||||
pois = reverse_used(ssa_name)
|
||||
release_reg( pois ) if pois
|
||||
end
|
||||
|
||||
def assign(instruction)
|
||||
names = instruction.register_names
|
||||
names.each do |for_name|
|
||||
@ -52,10 +66,11 @@ module Risc
|
||||
def walk_and_mark(instruction)
|
||||
released = []
|
||||
released = walk_and_mark(instruction.next) if instruction.next
|
||||
#puts instruction.class.name
|
||||
#puts "Walking #{instruction}"
|
||||
instruction.register_names.each do |name|
|
||||
next if released.include?(name)
|
||||
@release_points[instruction] << name
|
||||
#puts "ADDING #{name}"
|
||||
released << name
|
||||
end
|
||||
released
|
||||
@ -65,21 +80,32 @@ module Risc
|
||||
@used_regs.empty?
|
||||
end
|
||||
|
||||
def use_reg(reg , for_name)
|
||||
# use the given reg (first) parameter and mark it as assigned to
|
||||
# it's ssa form, the second parameter.
|
||||
# forward check is trivial, and reverse_used provides reverse check
|
||||
def use_reg(reg , ssa_name)
|
||||
reg = reg.symbol if reg.is_a?(RegisterValue)
|
||||
raise "Stupid error #{reg}" unless reg.is_a?(Symbol)
|
||||
puts "Using #{reg} for #{for_name}"
|
||||
@used_regs[reg] = for_name
|
||||
#puts "Using #{reg} for #{ssa_name}"
|
||||
@used_regs[reg] = ssa_name
|
||||
end
|
||||
|
||||
# if a register has been assigned to the given name, return that
|
||||
# Check whether a register has been assigned to the given ssa form given.
|
||||
# Ie a reverse check on the used_regs hash
|
||||
def reverse_used( ssa_name )
|
||||
@used_regs.each {|reg,name| return reg if ssa_name == name }
|
||||
return nil
|
||||
end
|
||||
|
||||
# if a register has been assigned to the given ssa name, return that
|
||||
#
|
||||
# otherwise find the first free register by going through the available names
|
||||
# and checking if it is used
|
||||
def get_reg(for_name)
|
||||
@used_regs.each {|reg,name| return reg if for_name == name }
|
||||
def get_reg(ssa_name)
|
||||
name = reverse_used( ssa_name )
|
||||
return name if name
|
||||
@reg_names.each do |name|
|
||||
return use_reg(name , for_name) unless @used_regs.has_key?(name)
|
||||
return use_reg(name , ssa_name) unless @used_regs.has_key?(name)
|
||||
end
|
||||
raise "No more registers #{self}"
|
||||
end
|
||||
@ -89,6 +115,7 @@ module Risc
|
||||
def release_reg( reg )
|
||||
reg = reg.symbol if reg.is_a?(RegisterValue)
|
||||
raise "not symbol #{reg}:#{reg.class}" unless reg.is_a?(Symbol)
|
||||
#puts "Releasing #{reg} "
|
||||
@used_regs.delete(reg)
|
||||
end
|
||||
|
||||
|
@ -37,6 +37,10 @@ module Risc
|
||||
assert_equal Symbol, @allocator.use_reg(:r1, :some).class
|
||||
assert @allocator.used_regs.include?(:r1)
|
||||
end
|
||||
def test_reverse_check
|
||||
assert_equal Symbol, @allocator.use_reg(:r1, :some).class
|
||||
assert_equal :r1 , @allocator.reverse_used(:some)
|
||||
end
|
||||
def test_add_fail
|
||||
assert_raises{ @allocator.use_reg(1)}
|
||||
end
|
||||
|
@ -13,7 +13,7 @@ module Risc
|
||||
end
|
||||
def test_allocate_runs
|
||||
assert_nil @allocator.allocate_regs
|
||||
assert_equal 10 , @allocator.used_regs.length
|
||||
assert_equal 0 , @allocator.used_regs.length
|
||||
end
|
||||
def test_live_length
|
||||
live = @allocator.walk_and_mark(@compiler.risc_instructions)
|
||||
|
Loading…
x
Reference in New Issue
Block a user