Intermediate commit. Remove type restrictions.

Code gen is very broken
This commit is contained in:
Danila Fedorin 2018-07-27 00:06:33 -07:00
parent 3853d212b9
commit 23f95fe68c
8 changed files with 196 additions and 76 deletions

View File

@ -5,7 +5,6 @@ module Chalk
config = Config.parse!
exit unless config.validate!
generator = CodeGenerator.new (Table.new)
compiler = Compiler.new config
compiler.run
end

View File

@ -2,53 +2,81 @@ require "./ir.cr"
module Chalk
class CodeGenerator
def initialize(@table : Table)
def initialize(table, @function : TreeFunction)
@register = 0
@instructions = [] of Instruction
@block_edges = [] of Int32
@table = Table.new table
@function.params.each do |param|
@table[param] = VarEntry.new @register
@register += 1
end
end
private def load(into, value)
@instructions << LoadInstruction.new into, value.to_i32
inst = LoadInstruction.new into, value.to_i32
@instructions << inst
return inst
end
private def loadr(into, from)
@instructions << LoadRegInstruction.new into, from
inst = LoadRegInstruction.new into, from
@instructions << inst
return inst
end
private def op(op, into, from)
@instructions << OpRegInstruction.new 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
@instructions << inst
return inst
end
private def store(up_to)
@instructions << StoreInstruction.new up_to
inst = StoreInstruction.new up_to
@instructions << inst
return inst
end
private def restore(up_to)
@instructions << RestoreInstruction.new up_to
inst = RestoreInstruction.new up_to
@instructions << inst
return inst
end
private def ret(reg)
@instructions << ReturnInstruction.new reg
inst = ReturnInstruction.new reg
@instructions << inst
return inst
end
def generate(tree : Tree, target : Int32)
def generate!(tree, target)
case tree
when TreeId
entry = @table[tree.id]?
raise "Unknown variable" unless entry &&
entry.is_a?(VarEntry)
loadr target, entry.as(VarEntry).register
loadr target, entry.register
when TreeLit
load target, tree.lit
when TreeOp
generate tree.left, target
generate tree.right, @register
op tree.op, target, @register
into = @register
@register += 1
generate! tree.left, target
generate! tree.right, into
@register -= 1
op tree.op, target, into
when TreeBlock
register = @register
tree.children.each do |child|
generate child, @register
generate! child, @register
end
@register = register
when TreeVar
entry = @table[tree.name]?
if entry == nil
@ -57,22 +85,75 @@ module Chalk
@table[tree.name] = entry
end
raise "Unknown variable" unless entry.is_a?(VarEntry)
generate tree.expr, entry.register
generate! tree.expr, entry.register
when TreeAssign
entry = @table[tree.name]?
raise "Unknown variable" unless entry &&
entry.is_a?(VarEntry)
generate tree.expr, entry.as(VarEntry).register
generate! tree.expr, entry.register
when TreeIf
cond_target = @register
@register += 1
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
generate! tree.block, @register
jump_inst.offset = @instructions.size - old_size + 1
generate! tree.otherwise, @register if tree.otherwise
when TreeReturn
generate tree.rvalue, target
ret target
into = @register
@register += 1
generate! tree.rvalue, into
@register -= 1
ret into
end
end
def generate(tree : Tree)
generate(tree, 0)
@block_edges << @instructions.size
@block_edges.sort!
private def check_dead(inst)
if inst.is_a?(LoadRegInstruction)
return inst.from == inst.into
end
return false
end
private def optimize!(range)
offset = 0
range.each do |index|
if check_dead(@instructions[index + offset])
@instructions.delete_at(index + offset)
offset -= 1
end
end
return offset
end
private def optimize!
block_boundaries = [ @instructions.size ]
@instructions.each_with_index do |inst, i|
if inst.is_a?(JumpEqRegInstruction) ||
inst.is_a?(JumpEqInstruction)
block_boundaries << (inst.offset + i)
end
end
block_boundaries.sort!
previous = 0
offset = 0
block_boundaries.each do |boundary|
range = (previous + offset)...(boundary + offset)
offset += optimize!(range)
previous = boundary
end
end
def generate!
generate!(@function.block, @register)
optimize!
return @instructions
end
end

View File

@ -40,11 +40,15 @@ module Chalk
end
private def generate_code(trees, table)
code = {} of String => Array(Instruction)
trees.each do |tree|
generator = CodeGenerator.new table
instructions = generator.generate tree.as(TreeFunction).block
instructions.each { |it| puts it }
tree = tree.as(TreeFunction)
generator = CodeGenerator.new table, tree
@logger.debug("Generating code for #{tree.name}")
instructions = generator.generate!
code[tree.name] = instructions
end
return code
end
private def run_tree
@ -57,7 +61,13 @@ module Chalk
private def run_intermediate
trees = create_trees(@config.file)
table = process_initial(trees)
generate_code(trees, table)
raise "No main function!" unless table["main"]?
code = generate_code(trees, table)
code.each do |name, insts|
puts "Code for #{name}:"
insts.each { |it| puts it }
puts "-----"
end
end
private def run_binary

View File

@ -8,7 +8,7 @@ module Chalk
property register : Int32
property value : Int32
def initialize(@register : Int32, @value : Int32)
def initialize(@register, @value)
end
def to_s(io)
@ -22,7 +22,7 @@ module Chalk
property into : Int32
property from : Int32
def initialize(@into : Int32, @from : Int32)
def initialize(@into, @from)
end
def to_s(io)
@ -38,8 +38,7 @@ module Chalk
property into : Int32
property value : Int32
def initialize(@op : TokenType, @into : Int32,
@value : Int32)
def initialize(@op, @into, @value)
end
def to_s(io)
@ -54,7 +53,7 @@ module Chalk
property into : Int32
property from : Int32
def initialize(@op : TokenType, @into : Int32, @from : Int32)
def initialize(@op, @into, @from)
end
def to_s(io)
@ -68,7 +67,7 @@ module Chalk
class StoreInstruction < Instruction
property up_to : Int32
def initialize(@up_to : Int32)
def initialize(@up_to)
end
def to_s(io)
@ -80,7 +79,7 @@ module Chalk
class RestoreInstruction < Instruction
property up_to : Int32
def initialize(@up_to : Int32)
def initialize(@up_to)
end
def to_s(io)
@ -92,7 +91,7 @@ module Chalk
class ReturnInstruction < Instruction
property to_return : Int32
def initialize(@to_return : Int32)
def initialize(@to_return)
end
def to_s(io)
@ -100,4 +99,36 @@ module Chalk
@to_return.to_s(16, io)
end
end
class JumpEqInstruction < Instruction
property offset : Int32
property left : Int32
property right : Int32
def initialize(@offset, @left, @right)
end
def to_s(io)
io << "jeq " << offset << " R"
@left.to_s(16, io)
io << " " << right
end
end
class JumpEqRegInstruction < Instruction
property offset : Int32
property left : Int32
property right : Int32
def initialize(@offset, @left, @right)
end
def to_s(io)
io << "jeq " << offset << " R"
@left.to_s(16, io)
io << " R"
@right.to_s(16, io)
end
end
end

View File

@ -5,8 +5,7 @@ module Chalk
abstract def parse?(tokens : Array(Token),
index : Int64) : Tuple(T, Int64)?
def parse(tokens : Array(Token),
index : Int64) : Tuple(T, Int64)
def parse(tokens, index)
return parse?(tokens, index).not_nil!
end

View File

@ -6,7 +6,7 @@ module Chalk
property function : TreeFunction
property addr : Int32
def initialize(@function : TreeFunction, @addr : Int32 = -1)
def initialize(@function, @addr = -1)
end
def to_s(io)
@ -17,7 +17,7 @@ module Chalk
class VarEntry < Entry
property register : Int32
def initialize(@register : Int32)
def initialize(@register)
end
def to_s(io)
@ -28,11 +28,11 @@ module Chalk
class Table
property parent : Table?
def initialize(@parent : Table? = nil)
def initialize(@parent = nil)
@data = {} of String => Entry
end
def []?(key) : Entry?
def []?(key)
if entry = @data[key]?
return entry
end

View File

@ -1,25 +1,25 @@
module Chalk
class Visitor
def visit(tree : Tree)
def visit(tree)
end
def finish(tree : Tree)
def finish(tree)
end
end
class Transformer
def transform(tree : Tree) : Tree
def transform(tree)
return tree
end
end
class Tree
def accept(v : Visitor)
def accept(v)
v.visit(self)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
return t.transform(self)
end
end
@ -27,14 +27,14 @@ module Chalk
class TreeId < Tree
property id : String
def initialize(@id : String)
def initialize(@id)
end
end
class TreeLit < Tree
property lit : Int64
def initialize(@lit : Int64)
def initialize(@lit)
end
end
@ -42,16 +42,16 @@ module Chalk
property name : String
property params : Array(Tree)
def initialize(@name : String, @params : Array(Tree))
def initialize(@name, @params)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@params.each &.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@params.map! do |param|
param.apply(t)
end
@ -64,17 +64,17 @@ module Chalk
property left : Tree
property right : Tree
def initialize(@op : TokenType, @left : Tree, @right : Tree)
def initialize(@op, @left, @right)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@left.accept(v)
@right.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@left = @left.apply(t)
@right = @right.apply(t)
return t.transform(self)
@ -84,16 +84,16 @@ module Chalk
class TreeBlock < Tree
property children : Array(Tree)
def initialize(@children : Array(Tree))
def initialize(@children)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@children.each &.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@children.map! do |child|
child.apply(t)
end
@ -106,16 +106,16 @@ module Chalk
property params : Array(String)
property block : Tree
def initialize(@name : String, @params : Array(String), @block : Tree)
def initialize(@name, @params, @block)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@block.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@block = @block.apply(t)
return t.transform(self)
end
@ -125,16 +125,16 @@ module Chalk
property name : String
property expr : Tree
def initialize(@name : String, @expr : Tree)
def initialize(@name, @expr)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@expr.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@expr = @expr.apply(t)
return t.transform(self)
end
@ -144,16 +144,16 @@ module Chalk
property name : String
property expr : Tree
def initialize(@name : String, @expr : Tree)
def initialize(@name, @expr)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@expr.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@expr = @expr.apply(t)
return t.transform(self)
end
@ -164,10 +164,10 @@ module Chalk
property block : Tree
property otherwise : Tree?
def initialize(@condition : Tree, @block : Tree, @otherwise : Tree? = nil)
def initialize(@condition, @block, @otherwise = nil)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@condition.accept(v)
@block.accept(v)
@ -175,7 +175,7 @@ module Chalk
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@condition = @condition.apply(t)
@block = @block.apply(t)
@otherwise = @otherwise.try &.apply(t)
@ -187,17 +187,17 @@ module Chalk
property condition : Tree
property block : Tree
def initialize(@condition : Tree, @block : Tree)
def initialize(@condition, @block)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@condition.accept(v)
@block.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@condition = @condition.apply(t)
@block = @block.apply(t)
return t.transform(self)
@ -207,16 +207,16 @@ module Chalk
class TreeReturn < Tree
property rvalue : Tree
def initialize(@rvalue : Tree)
def initialize(@rvalue)
end
def accept(v : Visitor)
def accept(v)
v.visit(self)
@rvalue.accept(v)
v.finish(self)
end
def apply(t : Transformer)
def apply(t)
@rvalue = @rvalue.apply(t)
return t.transform(self)
end

View File

@ -9,7 +9,7 @@ module Chalk
property file : String
property mode : OutputMode
def initialize(@file : String = "",
def initialize(@file = "",
@mode = OutputMode::Tree)
end