Fix optimizer to adjust jumps after instruction deletion.

This commit is contained in:
Danila Fedorin 2018-08-01 21:46:16 -07:00
parent 147837c011
commit cd0e5c2919
2 changed files with 33 additions and 16 deletions

View File

@ -52,13 +52,16 @@ module Chalk
return table return table
end end
private def create_code(tree : TreeFunction, table) private def create_code(tree : TreeFunction, table, instruction = ReturnInstruction.new)
optimizer = Optimizer.new
generator = CodeGenerator.new table, tree generator = CodeGenerator.new table, tree
@logger.debug("Generating code for #{tree.name}") @logger.debug("Generating code for #{tree.name}")
return generator.generate! code = generator.generate!
code << instruction
return optimizer.optimize(code)
end end
private def create_code(tree : BuiltinFunction, table) private def create_code(tree : BuiltinFunction, table, instruction = nil)
instructions = [] of Instruction instructions = [] of Instruction
tree.generate!(instructions) tree.generate!(instructions)
return instructions return instructions
@ -132,9 +135,9 @@ module Chalk
names.delete "main" names.delete "main"
main_entry = table["main"]?.as(FunctionEntry) main_entry = table["main"]?.as(FunctionEntry)
all_instructions.concat create_code(main_entry.function.as(TreeFunction), table) all_instructions.concat create_code(main_entry.function.as(TreeFunction),
table, JumpRelativeInstruction.new 0)
main_entry.addr = 0 main_entry.addr = 0
all_instructions << JumpRelativeInstruction.new 0
names.each do |name| names.each do |name|
entry = table[name]?.as(FunctionEntry) entry = table[name]?.as(FunctionEntry)

View File

@ -1,21 +1,19 @@
module Chalk module Chalk
class Optimizer class Optimizer
private def check_dead(inst) private def check_dead(inst)
if inst.is_a?(LoadRegInstruction) if inst.is_a?(LoadRegInstruction)
return inst.from == inst.into return inst.from == inst.into
end end
return false return false
end end
private def optimize!(instructions, range) private def optimize!(instructions, range, deletions, deletions_at)
offset = 0
range.each do |index| range.each do |index|
if check_dead(instructions[index + offset]) if check_dead(instructions[index])
instructions.delete_at(index + offset) deletions << index
offset -= 1
end end
deletions_at[index] = deletions.size
end end
return offset
end end
def optimize(instructions) def optimize(instructions)
@ -23,18 +21,34 @@ module Chalk
block_boundaries = [instructions.size] block_boundaries = [instructions.size]
instructions.each_with_index do |inst, i| instructions.each_with_index do |inst, i|
if inst.is_a?(JumpRelativeInstruction) if inst.is_a?(JumpRelativeInstruction)
block_boundaries << i
block_boundaries << (inst.offset + i) block_boundaries << (inst.offset + i)
end end
end end
block_boundaries.sort! block_boundaries.uniq!.sort!
previous = 0 previous = 0
offset = 0 deletions = [] of Int32
deletions_at = {} of Int32 => Int32
block_boundaries.each do |boundary| block_boundaries.each do |boundary|
range = (previous + offset)...(boundary + offset) range = previous...boundary
offset += optimize!(instructions, range) optimize!(instructions, range, deletions, deletions_at)
previous = boundary previous = boundary
end end
instructions.each_with_index do |inst, i|
next if !inst.is_a?(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
deletions.reverse!
deletions.each do |i|
instructions.delete_at i
end
return instructions return instructions
end end
end end