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

View File

@ -89,14 +89,11 @@ module Chalk
end
class ReturnInstruction < Instruction
property to_return : Int32
def initialize(@to_return)
def initialize()
end
def to_s(io)
io << "return R"
@to_return.to_s(16, io)
io << "return"
end
end
@ -115,16 +112,69 @@ module Chalk
end
end
class JumpEqRegInstruction < Instruction
class JumpRelativeInstruction < Instruction
property offset : Int32
property left : Int32
property right : Int32
def initialize(@offset, @left, @right)
def initialize(@offset)
end
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)
io << " R"
@right.to_s(16, io)
@ -138,8 +188,36 @@ module Chalk
end
def to_s(io)
io << "call " << name
io << "call " << @name
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