Compare commits
6 Commits
23f95fe68c
...
5e93fa1963
Author | SHA1 | Date |
---|---|---|
Danila Fedorin | 5e93fa1963 | |
Danila Fedorin | c04997ad17 | |
Danila Fedorin | 774ab2f92e | |
Danila Fedorin | cc82894454 | |
Danila Fedorin | 99a47be826 | |
Danila Fedorin | 8c63cbfb7b |
|
@ -1,117 +1,113 @@
|
||||||
require "./ir.cr"
|
require "./ir.cr"
|
||||||
|
require "./emitter.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
class CodeGenerator
|
class CodeGenerator
|
||||||
|
include Emitter
|
||||||
|
RETURN_REG = 14
|
||||||
|
STACK_REG = 13
|
||||||
|
|
||||||
def initialize(table, @function : TreeFunction)
|
def initialize(table, @function : TreeFunction)
|
||||||
@register = 0
|
@registers = 0
|
||||||
@instructions = [] of Instruction
|
@instructions = [] of Instruction
|
||||||
@table = Table.new table
|
@table = Table.new table
|
||||||
|
|
||||||
@function.params.each do |param|
|
@function.params.each do |param|
|
||||||
@table[param] = VarEntry.new @register
|
@table[param] = VarEntry.new @registers
|
||||||
@register += 1
|
@registers += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def load(into, value)
|
def generate!(tree, table, target, free)
|
||||||
inst = LoadInstruction.new into, value.to_i32
|
|
||||||
@instructions << inst
|
|
||||||
return inst
|
|
||||||
end
|
|
||||||
|
|
||||||
private def loadr(into, from)
|
|
||||||
inst = LoadRegInstruction.new into, from
|
|
||||||
@instructions << inst
|
|
||||||
return inst
|
|
||||||
end
|
|
||||||
|
|
||||||
private def op(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)
|
|
||||||
inst = StoreInstruction.new up_to
|
|
||||||
@instructions << inst
|
|
||||||
return inst
|
|
||||||
end
|
|
||||||
|
|
||||||
private def restore(up_to)
|
|
||||||
inst = RestoreInstruction.new up_to
|
|
||||||
@instructions << inst
|
|
||||||
return inst
|
|
||||||
end
|
|
||||||
|
|
||||||
private def ret(reg)
|
|
||||||
inst = ReturnInstruction.new reg
|
|
||||||
@instructions << inst
|
|
||||||
return inst
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate!(tree, target)
|
|
||||||
case tree
|
case tree
|
||||||
when TreeId
|
when TreeId
|
||||||
entry = @table[tree.id]?
|
entry = table[tree.id]?
|
||||||
raise "Unknown variable" unless entry &&
|
raise "Unknown variable" unless entry &&
|
||||||
entry.is_a?(VarEntry)
|
entry.is_a?(VarEntry)
|
||||||
loadr target, entry.register
|
loadr target, entry.register
|
||||||
when TreeLit
|
when TreeLit
|
||||||
load target, tree.lit
|
load target, tree.lit
|
||||||
when TreeOp
|
when TreeOp
|
||||||
into = @register
|
generate! tree.left, table, target, free
|
||||||
@register += 1
|
generate! tree.right, table, free, free + 1
|
||||||
generate! tree.left, target
|
opr tree.op, target, free
|
||||||
generate! tree.right, into
|
when TreeCall
|
||||||
@register -= 1
|
entry = table[tree.name]?
|
||||||
op tree.op, target, into
|
raise "Unknown function" unless entry &&
|
||||||
when TreeBlock
|
entry.is_a?(FunctionEntry)
|
||||||
register = @register
|
raise "Invalid call" if tree.params.size != entry.function.params.size
|
||||||
tree.children.each do |child|
|
|
||||||
generate! child, @register
|
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
|
||||||
|
load free, start_at
|
||||||
|
opr TokenType::OpSub, STACK_REG, free
|
||||||
|
# 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|
|
||||||
|
free += generate! child, table, free, free
|
||||||
end
|
end
|
||||||
@register = register
|
|
||||||
when TreeVar
|
when TreeVar
|
||||||
entry = @table[tree.name]?
|
entry = table[tree.name]?
|
||||||
if entry == nil
|
if entry == nil
|
||||||
entry = VarEntry.new @register
|
entry = VarEntry.new free
|
||||||
@register += 1
|
table[tree.name] = entry
|
||||||
@table[tree.name] = entry
|
|
||||||
end
|
end
|
||||||
raise "Unknown variable" unless entry.is_a?(VarEntry)
|
raise "Unknown variable" unless entry.is_a?(VarEntry)
|
||||||
generate! tree.expr, entry.register
|
generate! tree.expr, table, entry.register, free + 1
|
||||||
|
return 1
|
||||||
when TreeAssign
|
when TreeAssign
|
||||||
entry = @table[tree.name]?
|
entry = table[tree.name]?
|
||||||
raise "Unknown variable" unless entry &&
|
raise "Unknown variable" unless entry &&
|
||||||
entry.is_a?(VarEntry)
|
entry.is_a?(VarEntry)
|
||||||
generate! tree.expr, entry.register
|
generate! tree.expr, table, entry.register, free
|
||||||
when TreeIf
|
when TreeIf
|
||||||
cond_target = @register
|
generate! tree.condition, table, target, free
|
||||||
@register += 1
|
sne target, 0
|
||||||
|
jump_inst = jr 0
|
||||||
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
|
old_size = @instructions.size
|
||||||
generate! tree.block, @register
|
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
|
||||||
|
|
||||||
generate! tree.otherwise, @register if tree.otherwise
|
old_size = @instructions.size
|
||||||
|
generate! tree.otherwise, table, free, free + 1 if tree.otherwise
|
||||||
|
jump_after.offset = @instructions.size - old_size + 1
|
||||||
when TreeReturn
|
when TreeReturn
|
||||||
into = @register
|
generate! tree.rvalue, table, RETURN_REG, free
|
||||||
@register += 1
|
ret
|
||||||
generate! tree.rvalue, into
|
|
||||||
@register -= 1
|
|
||||||
ret into
|
|
||||||
end
|
end
|
||||||
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
private def check_dead(inst)
|
private def check_dead(inst)
|
||||||
|
@ -121,39 +117,8 @@ module Chalk
|
||||||
return false
|
return false
|
||||||
end
|
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!
|
def generate!
|
||||||
generate!(@function.block, @register)
|
generate!(@function.block, @table, -1, @registers)
|
||||||
optimize!
|
|
||||||
return @instructions
|
return @instructions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,47 +6,56 @@ module Chalk
|
||||||
class Compiler
|
class Compiler
|
||||||
def initialize(@config : Config)
|
def initialize(@config : Config)
|
||||||
@logger = Logger.new STDOUT
|
@logger = Logger.new STDOUT
|
||||||
@lexer = Lexer.new
|
|
||||||
@parser = Parser.new
|
|
||||||
@logger.debug("Initialized compiler")
|
@logger.debug("Initialized compiler")
|
||||||
@logger.level = Logger::DEBUG
|
@logger.level = Logger::DEBUG
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_trees(file)
|
private def create_trees(file)
|
||||||
string = File.read(file)
|
string = File.read(file)
|
||||||
tokens = @lexer.lex string
|
@logger.debug("Tokenizing")
|
||||||
|
lexer = Lexer.new
|
||||||
|
tokens = lexer.lex string
|
||||||
if tokens.size == 0 && string != ""
|
if tokens.size == 0 && string != ""
|
||||||
raise "Unable to tokenize file."
|
raise "Unable to tokenize file."
|
||||||
end
|
end
|
||||||
@logger.debug("Finished tokenizing")
|
@logger.debug("Finished tokenizing")
|
||||||
if trees = @parser.parse?(tokens)
|
@logger.debug("Beginning parsing")
|
||||||
|
parser = Parser.new
|
||||||
|
if trees = parser.parse?(tokens)
|
||||||
@logger.debug("Finished parsing")
|
@logger.debug("Finished parsing")
|
||||||
|
@logger.debug("Beginning constant folding")
|
||||||
|
folder = ConstantFolder.new
|
||||||
|
trees.map! do |tree|
|
||||||
|
@logger.debug("Constant folding #{tree.name}")
|
||||||
|
tree.apply(folder).as(TreeFunction)
|
||||||
|
end
|
||||||
|
@logger.debug("Done constant folding")
|
||||||
return trees
|
return trees
|
||||||
end
|
end
|
||||||
raise "Unable to parse file."
|
raise "Unable to parse file."
|
||||||
end
|
end
|
||||||
|
|
||||||
private def process_initial(trees)
|
private def create_table(trees)
|
||||||
table = Table.new
|
table = Table.new
|
||||||
folder = ConstantFolder.new
|
@logger.debug("Creating symbol table")
|
||||||
trees.each do |tree|
|
trees.each do |tree|
|
||||||
tree = tree.as(TreeFunction)
|
|
||||||
@logger.debug("Constant folding #{tree.name}")
|
|
||||||
tree = tree.apply(folder).as(TreeFunction)
|
|
||||||
@logger.debug("Storing #{tree.name} in symbol table")
|
@logger.debug("Storing #{tree.name} in symbol table")
|
||||||
table[tree.name] = FunctionEntry.new tree
|
table[tree.name] = FunctionEntry.new tree
|
||||||
end
|
end
|
||||||
|
@logger.debug("Done creating symbol table")
|
||||||
return table
|
return table
|
||||||
end
|
end
|
||||||
|
|
||||||
private def generate_code(trees, table)
|
private def create_code(tree : TreeFunction, table)
|
||||||
|
generator = CodeGenerator.new table, tree
|
||||||
|
@logger.debug("Generating code for #{tree.name}")
|
||||||
|
return generator.generate!
|
||||||
|
end
|
||||||
|
|
||||||
|
private def create_code(trees : Array(TreeFunction), table)
|
||||||
code = {} of String => Array(Instruction)
|
code = {} of String => Array(Instruction)
|
||||||
trees.each do |tree|
|
trees.each do |tree|
|
||||||
tree = tree.as(TreeFunction)
|
code[tree.name] = create_code(tree, table)
|
||||||
generator = CodeGenerator.new table, tree
|
|
||||||
@logger.debug("Generating code for #{tree.name}")
|
|
||||||
instructions = generator.generate!
|
|
||||||
code[tree.name] = instructions
|
|
||||||
end
|
end
|
||||||
return code
|
return code
|
||||||
end
|
end
|
||||||
|
@ -60,9 +69,8 @@ module Chalk
|
||||||
|
|
||||||
private def run_intermediate
|
private def run_intermediate
|
||||||
trees = create_trees(@config.file)
|
trees = create_trees(@config.file)
|
||||||
table = process_initial(trees)
|
table = create_table(trees)
|
||||||
raise "No main function!" unless table["main"]?
|
code = create_code(trees, table)
|
||||||
code = generate_code(trees, table)
|
|
||||||
code.each do |name, insts|
|
code.each do |name, insts|
|
||||||
puts "Code for #{name}:"
|
puts "Code for #{name}:"
|
||||||
insts.each { |it| puts it }
|
insts.each { |it| puts it }
|
||||||
|
@ -70,7 +78,60 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def generate_binary(table, instructions, dest)
|
||||||
|
context = InstructionContext.new table, instructions.size
|
||||||
|
binary = instructions.map_with_index { |it, i| it.to_bin(context, i).to_u16 }
|
||||||
|
binary.each do |inst|
|
||||||
|
first = (inst >> 8).to_u8
|
||||||
|
dest.write_byte(first)
|
||||||
|
second = (inst & 0xff).to_u8
|
||||||
|
dest.write_byte(second)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def collect_calls(table)
|
||||||
|
open = Set(String).new
|
||||||
|
done = Set(String).new
|
||||||
|
|
||||||
|
open << "main"
|
||||||
|
while !open.empty?
|
||||||
|
first = open.first
|
||||||
|
open.delete first
|
||||||
|
done << first
|
||||||
|
|
||||||
|
entry = table[first]?
|
||||||
|
raise "Unknown function" unless entry && entry.is_a?(FunctionEntry)
|
||||||
|
next unless entry.function.is_a?(TreeFunction)
|
||||||
|
|
||||||
|
visitor = CallVisitor.new
|
||||||
|
entry.function.accept(visitor)
|
||||||
|
open.concat(visitor.calls - done)
|
||||||
|
end
|
||||||
|
return done
|
||||||
|
end
|
||||||
|
|
||||||
private def run_binary
|
private def run_binary
|
||||||
|
all_instructions = [] of Instruction
|
||||||
|
trees = create_trees(@config.file)
|
||||||
|
table = create_table(trees)
|
||||||
|
names = collect_calls(table)
|
||||||
|
names.delete "main"
|
||||||
|
|
||||||
|
main_entry = table["main"]?.as(FunctionEntry)
|
||||||
|
all_instructions.concat create_code(main_entry.function, table)
|
||||||
|
main_entry.addr = 0
|
||||||
|
all_instructions << JumpRelativeInstruction.new 0
|
||||||
|
|
||||||
|
names.each do |name|
|
||||||
|
entry = table[name]?.as(FunctionEntry)
|
||||||
|
entry.addr = all_instructions.size
|
||||||
|
all_instructions.concat create_code(entry.function, table)
|
||||||
|
all_instructions << ReturnInstruction.new
|
||||||
|
end
|
||||||
|
|
||||||
|
file = File.open("out.ch8", "w")
|
||||||
|
generate_binary(table, all_instructions, file)
|
||||||
|
file.close
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
module Chalk
|
||||||
|
module Emitter
|
||||||
|
private def load(into, value)
|
||||||
|
inst = LoadInstruction.new into, value.to_i32
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
|
||||||
|
private def loadr(into, from)
|
||||||
|
inst = LoadRegInstruction.new into, from
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
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 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
|
||||||
|
|
||||||
|
private def store(up_to)
|
||||||
|
inst = StoreInstruction.new up_to
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
|
||||||
|
private def restore(up_to)
|
||||||
|
inst = RestoreInstruction.new up_to
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
|
||||||
|
private def ret
|
||||||
|
inst = ReturnInstruction.new
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
|
||||||
|
private def call(func)
|
||||||
|
inst = CallInstruction.new func
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setis
|
||||||
|
inst = SetIStackInstruction.new
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
|
||||||
|
private def addi(reg)
|
||||||
|
inst = AddIRegInstruction.new reg
|
||||||
|
@instructions << inst
|
||||||
|
return inst
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
module Chalk
|
||||||
|
class CallVisitor < Visitor
|
||||||
|
property calls : Set(String)
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@calls = Set(String).new
|
||||||
|
end
|
||||||
|
|
||||||
|
def visit(t : TreeCall)
|
||||||
|
@calls << t.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
184
src/chalk/ir.cr
184
src/chalk/ir.cr
|
@ -2,6 +2,17 @@ require "./lexer.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
class Instruction
|
class Instruction
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class InstructionContext
|
||||||
|
property table : Table
|
||||||
|
property stack : Int32
|
||||||
|
|
||||||
|
def initialize(@table, @stack)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class LoadInstruction < Instruction
|
class LoadInstruction < Instruction
|
||||||
|
@ -16,6 +27,10 @@ module Chalk
|
||||||
@register.to_s(16, io)
|
@register.to_s(16, io)
|
||||||
io << " " << @value
|
io << " " << @value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
0x6000 | (register << 8) | value
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class LoadRegInstruction < Instruction
|
class LoadRegInstruction < Instruction
|
||||||
|
@ -31,6 +46,10 @@ module Chalk
|
||||||
io << " R"
|
io << " R"
|
||||||
@from.to_s(16, io)
|
@from.to_s(16, io)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
0x8000 | (into << 8) | (from << 4)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class OpInstruction < Instruction
|
class OpInstruction < Instruction
|
||||||
|
@ -46,6 +65,15 @@ module Chalk
|
||||||
@into.to_s(16, io)
|
@into.to_s(16, io)
|
||||||
io << " " << @value
|
io << " " << @value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
case op
|
||||||
|
when TokenType::OpAdd
|
||||||
|
return 0x7000 | (into << 8) | value
|
||||||
|
else
|
||||||
|
raise "Invalid instruction"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class OpRegInstruction < Instruction
|
class OpRegInstruction < Instruction
|
||||||
|
@ -62,6 +90,25 @@ module Chalk
|
||||||
io << " R"
|
io << " R"
|
||||||
@from.to_s(16, io)
|
@from.to_s(16, io)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
code = 0
|
||||||
|
case op
|
||||||
|
when TokenType::OpAdd
|
||||||
|
code = 4
|
||||||
|
when TokenType::OpSub
|
||||||
|
code = 5
|
||||||
|
when TokenType::OpOr
|
||||||
|
code = 1
|
||||||
|
when TokenType::OpAnd
|
||||||
|
code = 2
|
||||||
|
when TokenType::OpXor
|
||||||
|
code = 3
|
||||||
|
else
|
||||||
|
raise "Invalid instruction"
|
||||||
|
end
|
||||||
|
return 0x8000 | (into << 8) | (from << 4) | code
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class StoreInstruction < Instruction
|
class StoreInstruction < Instruction
|
||||||
|
@ -74,6 +121,10 @@ module Chalk
|
||||||
io << "store R"
|
io << "store R"
|
||||||
@up_to.to_s(16, io)
|
@up_to.to_s(16, io)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0xf055 | (up_to << 8)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class RestoreInstruction < Instruction
|
class RestoreInstruction < Instruction
|
||||||
|
@ -86,49 +137,152 @@ module Chalk
|
||||||
io << "restore R"
|
io << "restore R"
|
||||||
@up_to.to_s(16, io)
|
@up_to.to_s(16, io)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0xf065 | (up_to << 8)
|
||||||
|
end
|
||||||
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
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x00ee
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class JumpEqInstruction < 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
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x1000 | ((offset + index) * 2 + 0x200)
|
||||||
|
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)
|
@left.to_s(16, io)
|
||||||
io << " " << right
|
io << " " << right
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x3000 | (left << 8) | right
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class JumpEqRegInstruction < Instruction
|
class SkipNeInstruction < Instruction
|
||||||
property offset : Int32
|
|
||||||
property left : Int32
|
property left : Int32
|
||||||
property right : Int32
|
property right : Int32
|
||||||
|
|
||||||
def initialize(@offset, @left, @right)
|
def initialize(@left, @right)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s(io)
|
def to_s(io)
|
||||||
io << "jeq " << offset << " R"
|
io << "sne R"
|
||||||
|
@left.to_s(16, io)
|
||||||
|
io << " " << right
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x4000 | (left << 8) | 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)
|
@left.to_s(16, io)
|
||||||
io << " R"
|
io << " R"
|
||||||
@right.to_s(16, io)
|
@right.to_s(16, io)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x5000 | (left << 8) | (right << 4)
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x9000 | (left << 8) | (right << 4)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CallInstruction < Instruction
|
||||||
|
property name : String
|
||||||
|
|
||||||
|
def initialize(@name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(io)
|
||||||
|
io << "call " << @name
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0x2000 | (i.table[name]?.as(FunctionEntry).addr * 2 + 0x200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SetIStackInstruction < Instruction
|
||||||
|
def to_s(io)
|
||||||
|
io << "setis"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0xa000 | (i.stack * 2 + 0x200)
|
||||||
|
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
|
||||||
|
|
||||||
|
def to_bin(i, index)
|
||||||
|
return 0xf000 | (reg << 8) | 0x1e
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
module Chalk
|
||||||
|
class Optimizer
|
||||||
|
def initialize(instructions : Array(Instruction))
|
||||||
|
@instructions = instructions.dup
|
||||||
|
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?(JumpRelativeInstruction)
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
|
@ -156,14 +156,14 @@ module Chalk
|
||||||
params = arr[3..arr.size - 5].map &.as(Token).string
|
params = arr[3..arr.size - 5].map &.as(Token).string
|
||||||
code = arr[arr.size - 1].as(Tree)
|
code = arr[arr.size - 1].as(Tree)
|
||||||
type = arr[arr.size - 2].as(Token).type
|
type = arr[arr.size - 2].as(Token).type
|
||||||
TreeFunction.new(name, params, code).as(Tree)
|
TreeFunction.new(name, params, code)
|
||||||
end
|
end
|
||||||
return func
|
return func
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
_, block = create_statement_block
|
_, block = create_statement_block
|
||||||
@parser = many(create_func(block, create_type)).as(BasicParser(Array(Tree)))
|
@parser = many(create_func(block, create_type)).as(BasicParser(Array(TreeFunction)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse?(tokens)
|
def parse?(tokens)
|
||||||
|
|
Loading…
Reference in New Issue