diff --git a/src/chalk/codegen.cr b/src/chalk/codegen.cr index f63328f..183f592 100644 --- a/src/chalk/codegen.cr +++ b/src/chalk/codegen.cr @@ -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 diff --git a/src/chalk/ir.cr b/src/chalk/ir.cr index 50938d5..ded53bf 100644 --- a/src/chalk/ir.cr +++ b/src/chalk/ir.cr @@ -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