Make IR closer to actual CHIP-8
This commit is contained in:
parent
8c63cbfb7b
commit
99a47be826
|
@ -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
|
||||||
|
|
100
src/chalk/ir.cr
100
src/chalk/ir.cr
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user