chalk/src/chalk/optimizer.cr

71 lines
2.3 KiB
Crystal
Raw Normal View History

module Chalk
2018-08-01 22:40:41 -07:00
module Compiler
2018-08-02 01:09:48 -07:00
# Class to optimize instructions.
2018-08-01 22:40:41 -07:00
class Optimizer
2018-08-02 01:09:48 -07:00
# Checks if *inst* is "dead code",
# an instruction that is completely useless.
2018-08-01 22:40:41 -07:00
private def check_dead(inst)
if inst.is_a?(Ir::LoadRegInstruction)
return inst.from == inst.into
end
return false
end
2018-08-02 01:09:48 -07:00
# Optimizes *instructions* in the basic block given by the *range*,
# storing addresses of instructions to be deleted into *deletions*,
# and the number of deleted instructions so far into *deletions_at*
2018-08-01 22:40:41 -07:00
private def optimize!(instructions, range, deletions, deletions_at)
range.each do |index|
if check_dead(instructions[index])
deletions << index
end
deletions_at[index] = deletions.size
end
2018-07-27 23:27:13 -07:00
end
2018-08-02 01:09:48 -07:00
# Optimizes the given list of instructions.
# The basic blocks are inferred from the various
# jumps and skips.
2018-08-01 22:40:41 -07:00
def optimize(instructions)
instructions = instructions.dup
block_boundaries = [instructions.size]
instructions.each_with_index do |inst, i|
if inst.is_a?(Ir::JumpRelativeInstruction)
2018-08-02 01:09:48 -07:00
block_boundaries << (i + 1)
2018-08-01 22:40:41 -07:00
block_boundaries << (inst.offset + i)
end
2018-08-02 01:09:48 -07:00
if inst.is_a?(Ir::SkipNeInstruction | Ir::SkipEqInstruction |
Ir::SkipRegEqInstruction | Ir::SkipRegNeInstruction)
block_boundaries << (i + 1)
end
end
2018-08-01 22:40:41 -07:00
block_boundaries.uniq!.sort!
2018-07-27 23:27:13 -07:00
2018-08-01 22:40:41 -07:00
previous = 0
deletions = [] of Int32
deletions_at = {} of Int32 => Int32
block_boundaries.each do |boundary|
range = previous...boundary
optimize!(instructions, range, deletions, deletions_at)
previous = boundary
end
2018-08-01 22:40:41 -07:00
instructions.each_with_index do |inst, i|
next if !inst.is_a?(Ir::JumpRelativeInstruction)
jump_to = inst.offset + i
next unless deletions_at[jump_to]?
deletions_offset = deletions_at[i] - deletions_at[jump_to]
inst.offset += deletions_offset
end
2018-08-01 22:40:41 -07:00
deletions.reverse!
deletions.each do |i|
instructions.delete_at i
end
2018-08-01 22:40:41 -07:00
return instructions
end
end
2018-07-27 23:27:13 -07:00
end
end