Fix register allocation and calling (somewhat)

This commit is contained in:
Danila Fedorin 2018-07-27 18:01:00 -07:00
parent 23f95fe68c
commit 8c63cbfb7b
2 changed files with 63 additions and 39 deletions

View File

@ -3,13 +3,13 @@ require "./ir.cr"
module Chalk module Chalk
class CodeGenerator class CodeGenerator
def initialize(table, @function : TreeFunction) def initialize(table, @function : TreeFunction)
@register = 0 @registers = 0
@instructions = [] of Instruction @instructions = [] of Instruction
@table = Table.new table @table = Table.new table
@function.params.each do |param| @function.params.each do |param|
@table[param] = VarEntry.new @register @table[param] = VarEntry.new @registers
@register += 1 @registers += 1
end end
end end
@ -50,68 +50,81 @@ module Chalk
end end
private def ret(reg) private def ret(reg)
inst = ReturnInstruction.new reg inst = ReturnInstruction.new reg
@instructions << inst @instructions << inst
return inst return inst
end end
def generate!(tree, target) private def call(func)
inst = CallInstruction.new func
@instructions << inst
return inst
end
def generate!(tree, table, target, free)
case tree case tree
when TreeId when TreeId
entry = @table[tree.id]? entry = table[tree.id]?
raise "Unknown variable" unless entry && raise "Unknown variable" unless entry &&
entry.is_a?(VarEntry) entry.is_a?(VarEntry)
loadr target, entry.register loadr target, entry.register
when TreeLit when TreeLit
load target, tree.lit load target, tree.lit
when TreeOp when TreeOp
into = @register generate! tree.left, table, target, free
@register += 1 generate! tree.right, table, free, free + 1
generate! tree.left, target op tree.op, target, free
generate! tree.right, into when TreeCall
@register -= 1 entry = table[tree.name]?
op tree.op, target, into raise "Unknown function" unless entry &&
when TreeBlock entry.is_a?(FunctionEntry)
register = @register raise "Invalid call" if tree.params.size != entry.function.params.size
tree.children.each do |child|
generate! child, @register start_at = free
store (start_at - 1) unless start_at == 0
tree.params.each do |param|
generate! param, table, free, free + 1
free += 1
end
tree.params.size.times do |time|
loadr time, time + start_at
end
call tree.name
restore (start_at - 1) unless start_at == 0
when TreeBlock
table = Table.new(table)
tree.children.each do |child|
free += generate! child, table, free, free
end end
@register = register
when TreeVar when TreeVar
entry = @table[tree.name]? entry = table[tree.name]?
if entry == nil if entry == nil
entry = VarEntry.new @register entry = VarEntry.new free
@register += 1 table[tree.name] = entry
@table[tree.name] = entry
end end
raise "Unknown variable" unless entry.is_a?(VarEntry) raise "Unknown variable" unless entry.is_a?(VarEntry)
generate! tree.expr, entry.register generate! tree.expr, table, entry.register, free + 1
return 1
when TreeAssign when TreeAssign
entry = @table[tree.name]? entry = table[tree.name]?
raise "Unknown variable" unless entry && raise "Unknown variable" unless entry &&
entry.is_a?(VarEntry) entry.is_a?(VarEntry)
generate! tree.expr, entry.register generate! tree.expr, table, entry.register, free
when TreeIf when TreeIf
cond_target = @register generate! tree.condition, table, target, free
@register += 1 load free, 0
jump_inst = jeq 0, target, free
generate! tree.condition, cond_target
load cond_target + 1, 0
jump_inst = jeq 0, cond_target, cond_target + 1
@register -= 1
old_size = @instructions.size old_size = @instructions.size
generate! tree.block, @register generate! tree.block, table, free, free + 1
jump_inst.offset = @instructions.size - old_size + 1 jump_inst.offset = @instructions.size - old_size + 1
generate! tree.otherwise, @register if tree.otherwise generate! tree.otherwise, table, free, free + 1 if tree.otherwise
when TreeReturn when TreeReturn
into = @register generate! tree.rvalue, table, free, free + 1
@register += 1 ret free
generate! tree.rvalue, into
@register -= 1
ret into
end end
return 0
end end
private def check_dead(inst) private def check_dead(inst)
@ -152,7 +165,7 @@ module Chalk
end end
def generate! def generate!
generate!(@function.block, @register) generate!(@function.block, @table, -1, @registers)
optimize! optimize!
return @instructions return @instructions
end end

View File

@ -130,5 +130,16 @@ module Chalk
@right.to_s(16, io) @right.to_s(16, io)
end end
end end
class CallInstruction < Instruction
property name : String
def initialize(@name)
end
def to_s(io)
io << "call " << name
end
end
end end