bit of cleaning, updated readme

This commit is contained in:
Torsten Ruger
2015-10-22 17:38:49 +03:00
parent c68577c3f4
commit f658ecf425
5 changed files with 33 additions and 89 deletions

82
stash/optimisations.rb Normal file
View File

@ -0,0 +1,82 @@
module Register
# Passes, or BlockPasses, could have been procs that just get each block passed.
# Instead they are proper objects in case they want to save state.
# The idea is
# - reduce noise in the main code by having this code seperately (aspect/concern style)
# - abstract the iteration
# - allow not yet written code to hook in
class RemoveStubs
def run block
block.codes.dup.each_with_index do |kode , index|
next unless kode.is_a? StackInstruction
if kode.registers.empty?
block.codes.delete(kode)
puts "deleted stack instruction in #{b.name}"
end
end
end
end
# Operators eg a + b , must assign their result somewhere and as such create temporary variables.
# but if code is c = a + b , the generated instructions would be more like tmp = a + b ; c = tmp
# SO if there is an move instruction just after a logic instruction where the result of the logic
# instruction is moved straight away, we can undo that mess and remove one instruction.
class LogicMoveReduction
def run block
org = block.codes.dup
org.each_with_index do |kode , index|
n = org[index+1]
next if n.nil?
next unless kode.is_a? LogicInstruction
next unless n.is_a? MoveInstruction
# specific arm instructions, don't optimize as don't know what the extra mean
# small todo. This does not catch condition_code that are not :al
next if (n.attributes.length > 3) or (kode.attributes.length > 3)
if kode.result == n.from
puts "Logic reduction #{kode} removes #{n}"
kode.result = n.to
block.codes.delete(n)
end
end
end
end
# Sometimes there are double moves ie mov a, b and mov b , c . We reduce that to move a , c
# (but don't check if that improves register allocation. Yet ?)
class MoveMoveReduction
def run block
org = block.codes.dup
org.each_with_index do |kode , index|
n = org[index+1]
next if n.nil?
next unless kode.is_a? MoveInstruction
next unless n.is_a? MoveInstruction
# specific arm instructions, don't optimize as don't know what the extra mean
# small todo. This does not catch condition_code that are not :al
next if (n.attributes.length > 3) or (kode.attributes.length > 3)
if kode.to == n.from
puts "Move reduction #{kode}: removes #{n} "
kode.to = n.to
block.codes.delete(n)
end
end
end
end
#As the name says, remove no-ops. Currently mov x , x supported
class NoopReduction
def run block
block.codes.dup.each_with_index do |kode , index|
next unless kode.is_a? MoveInstruction
# specific arm instructions, don't optimize as don't know what the extra mean
# small todo. This does not catch condition_code that are not :al
next if (kode.attributes.length > 3)
if kode.to == kode.from
block.codes.delete(kode)
puts "deleted noop move in #{block.name} #{kode}"
end
end
end
end
end

68
stash/plock.rb Normal file
View File

@ -0,0 +1,68 @@
module Virtual
# Plock (Proc-Block) is mostly a Block but also somewhat Proc-ish: A Block that carries data.
#
# Data in a Block is usefull in the same way data in objects is. Plocks being otherwise just code.
#
# But the concept is not quite straigtforwrd: If one thinks of a Plock embedded in a normal method,
# the a data in the Plock would be static data. In OO terms this comes quite close to a Proc,
# if the data is the local variables.
# Quite possibly they shall be used to implement procs, but that is not the direction now.
#
# For now we use Plocks behaind the scenes as it were. In the code that you never see,
# method invocation mainly.
#
# In terms of implementation the Plock is a Block with data
# (Not too much data, mainly a couple of references).
# The block writes it's instructions as normal, but a jump is inserted as the last instruction.
# The jump is to the next block, over the data that is inserted after the block code
# (and so before the next)
#
# It follows that Plocks should be linear blocks.
class Plock < Block
def initialize(name , method , next_block )
super
@data = []
@branch_code = RegisterMachine.instance.b next_block
end
def set_next next_b
super
@branch_code = RegisterMachine.instance.b next_block
end
# Data gets assembled after methods
def add_data o
return if @objects.include? o
raise "must be derived from Code #{o.inspect}" unless o.is_a? Register::Code
@data << o # TODO check type , no basic values allowed (must be wrapped)
end
# Code interface follows. Note position is inheitted as is from Code
# length of the Plock is the length of the block, plus the branch, plus data.
def byte_length
len = @data.inject(super) {| sum , item | sum + item.word_length}
len + @branch_code.word_length
end
# again, super + branch plus data
def link_at pos , context
super(pos , context)
@branch_code.link_at pos , context
@data.each do |code|
code.link_at(pos , context)
pos += code.word_length
end
end
# again, super + branch plus data
def assemble(io)
super
@branch_code.assemble(io)
@data.each do |obj|
obj.assemble io
end
end
end
end