Fix register allocation and calling (somewhat)
This commit is contained in:
parent
23f95fe68c
commit
8c63cbfb7b
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user