Make IR closer to actual CHIP-8

This commit is contained in:
Danila Fedorin 2018-07-27 18:57:08 -07:00
parent 8c63cbfb7b
commit 99a47be826
2 changed files with 151 additions and 22 deletions

View File

@ -2,6 +2,9 @@ require "./ir.cr"
module Chalk module Chalk
class CodeGenerator class CodeGenerator
RETURN_REG = 14
STACK_REG = 13
def initialize(table, @function : TreeFunction) def initialize(table, @function : TreeFunction)
@registers = 0 @registers = 0
@instructions = [] of Instruction @instructions = [] of Instruction
@ -26,13 +29,25 @@ module Chalk
end end
private def op(op, into, from) private def op(op, into, from)
inst = OpInstruction.new op, into, from
@instructions << inst
return inst
end
private def opr(op, into, from)
inst = OpRegInstruction.new op, into, from inst = OpRegInstruction.new op, into, from
@instructions << inst @instructions << inst
return inst return inst
end end
private def jeq(rel, l, r) private def sne(l, r)
inst = JumpEqRegInstruction.new rel, l, r inst = SkipNeInstruction.new l, r
@instructions << inst
return inst
end
private def jr(o)
inst = JumpRelativeInstruction.new o
@instructions << inst @instructions << inst
return inst return inst
end end
@ -49,8 +64,8 @@ module Chalk
return inst return inst
end end
private def ret(reg) private def ret
inst = ReturnInstruction.new reg inst = ReturnInstruction.new
@instructions << inst @instructions << inst
return inst return inst
end end
@ -61,6 +76,18 @@ module Chalk
return inst return inst
end end
def setis
inst = SetIStackInstruction.new
@instructions << inst
return inst
end
def addi(reg)
inst = AddIRegInstruction.new reg
@instructions << inst
return inst
end
def generate!(tree, table, target, free) def generate!(tree, table, target, free)
case tree case tree
when TreeId when TreeId
@ -73,7 +100,7 @@ module Chalk
when TreeOp when TreeOp
generate! tree.left, table, target, free generate! tree.left, table, target, free
generate! tree.right, table, free, free + 1 generate! tree.right, table, free, free + 1
op tree.op, target, free opr tree.op, target, free
when TreeCall when TreeCall
entry = table[tree.name]? entry = table[tree.name]?
raise "Unknown function" unless entry && raise "Unknown function" unless entry &&
@ -81,16 +108,38 @@ module Chalk
raise "Invalid call" if tree.params.size != entry.function.params.size raise "Invalid call" if tree.params.size != entry.function.params.size
start_at = free start_at = free
# Move I to stack
setis
# Get to correct stack position
addi STACK_REG
# Store variables
store (start_at - 1) unless start_at == 0 store (start_at - 1) unless start_at == 0
# Increment I and stack position
load free, start_at
opr TokenType::OpAdd, STACK_REG, free
addi free
# Calculate the parameters
tree.params.each do |param| tree.params.each do |param|
generate! param, table, free, free + 1 generate! param, table, free, free + 1
free += 1 free += 1
end end
# Call the function
tree.params.size.times do |time| tree.params.size.times do |time|
loadr time, time + start_at loadr time, time + start_at
end end
call tree.name call tree.name
# Reduce stack pointer
op TokenType::OpSub, STACK_REG, start_at
# Move I to stack
setis
# Get to correct stack position
addi STACK_REG
# Restore
restore (start_at - 1) unless start_at == 0 restore (start_at - 1) unless start_at == 0
# Get call value into target
loadr target, RETURN_REG
when TreeBlock when TreeBlock
table = Table.new(table) table = Table.new(table)
tree.children.each do |child| tree.children.each do |child|
@ -112,17 +161,20 @@ module Chalk
generate! tree.expr, table, entry.register, free generate! tree.expr, table, entry.register, free
when TreeIf when TreeIf
generate! tree.condition, table, target, free generate! tree.condition, table, target, free
load free, 0 sne target, 0
jump_inst = jeq 0, target, free jump_inst = jr 0
old_size = @instructions.size old_size = @instructions.size
generate! tree.block, table, free, free + 1 generate! tree.block, table, free, free + 1
jump_after = jr 0
jump_inst.offset = @instructions.size - old_size + 1 jump_inst.offset = @instructions.size - old_size + 1
old_size = @instructions.size
generate! tree.otherwise, table, free, free + 1 if tree.otherwise generate! tree.otherwise, table, free, free + 1 if tree.otherwise
jump_after.offset = @instructions.size - old_size + 1
when TreeReturn when TreeReturn
generate! tree.rvalue, table, free, free + 1 generate! tree.rvalue, table, RETURN_REG, free
ret free ret
end end
return 0 return 0
end end
@ -148,8 +200,7 @@ module Chalk
private def optimize! private def optimize!
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?(JumpEqRegInstruction) || if inst.is_a?(JumpRelativeInstruction)
inst.is_a?(JumpEqInstruction)
block_boundaries << (inst.offset + i) block_boundaries << (inst.offset + i)
end end
end end

View File

@ -89,14 +89,11 @@ module Chalk
end end
class ReturnInstruction < Instruction class ReturnInstruction < Instruction
property to_return : Int32 def initialize()
def initialize(@to_return)
end end
def to_s(io) def to_s(io)
io << "return R" io << "return"
@to_return.to_s(16, io)
end end
end end
@ -115,16 +112,69 @@ module Chalk
end end
end end
class JumpEqRegInstruction < Instruction class JumpRelativeInstruction < Instruction
property offset : Int32 property offset : Int32
property left : Int32
property right : Int32
def initialize(@offset, @left, @right) def initialize(@offset)
end end
def to_s(io) def to_s(io)
io << "jeq " << offset << " R" io << "jr " << @offset
end
end
class SkipEqInstruction < Instruction
property left : Int32
property right : Int32
def initialize(@left, @right)
end
def to_s(io)
io << "seq R"
@left.to_s(16, io)
io << " " << right
end
end
class SkipNeInstruction < Instruction
property left : Int32
property right : Int32
def initialize(@left, @right)
end
def to_s(io)
io << "sne R"
@left.to_s(16, io)
io << " " << right
end
end
class SkipRegEqInstruction < Instruction
property left : Int32
property right : Int32
def initialize(@left, @right)
end
def to_s(io)
io << "seqr R"
@left.to_s(16, io)
io << " R"
@right.to_s(16, io)
end
end
class SkipRegNeInstruction < Instruction
property left : Int32
property right : Int32
def initialize(@left, @right)
end
def to_s(io)
io << "sner R"
@left.to_s(16, io) @left.to_s(16, io)
io << " R" io << " R"
@right.to_s(16, io) @right.to_s(16, io)
@ -138,8 +188,36 @@ module Chalk
end end
def to_s(io) def to_s(io)
io << "call " << name io << "call " << @name
end end
end end
class SetIInstruction < Instruction
property value : Int32
def initialize(@value)
end
def to_s(io)
io << "seti " << @value
end
end
class SetIStackInstruction < Instruction
def to_s(io)
io << "setis"
end
end
class AddIRegInstruction < Instruction
property reg : Int32
def initialize(@reg)
end
def to_s(io)
io << "addi R"
reg.to_s(16, io)
end
end
end end