checkpointing on the mad road to register allocation

This commit is contained in:
Torsten Ruger 2014-05-13 18:21:24 +03:00
parent b0302948dd
commit f6711ea49c
12 changed files with 86 additions and 76 deletions

View File

@ -31,45 +31,45 @@ module Arm
end end
end end
def integer_less_or_equal left , right def integer_less_or_equal block , left , right
cmp(:left => left , :right => right ) block.add_code cmp(:left => left , :right => right )
Vm::Bool.new
end end
def integer_plus left , right def integer_plus block , left , right
add(:left => left , :right => right ) block.add_code add(:left => left , :right => right )
left
end end
def word_load value , reg def integer_load block , left , right
raise "not a register :#{reg}:" unless reg.class == Symbol reg = "r#{left.register}".to_sym
mov( :left => reg , :right => value ) block.add_code mov( :left => reg , :right => right )
left
end end
def string_load str_lit , reg def string_load block , str_lit , reg
[ add( :left => "r#{reg}".to_sym , :extra => str_lit ) , #right is pc, implicit block.add_code add( :left => "r#{reg}".to_sym , :extra => str_lit ) #right is pc, implicit
#second arg is a hack to get the stringlength without coding #second arg is a hack to get the stringlength without coding
mov( :left => "r#{reg+1}".to_sym , :right => str_lit.length ) ] block.add_code mov( :left => "r#{reg+1}".to_sym , :right => str_lit.length )
str_lit
end end
def function_call call def function_call call
raise "Not FunctionCall #{call.inspect}" unless call.is_a? Vm::FunctionCall raise "Not FunctionCall #{call.inspect}" unless call.is_a? Vm::FunctionCall
call.args.each do | arg | block.add_code bl( :left => call.function )
end call.function.return_value
bl( :left => call.function )
end end
def main_start def main_start entry
entry = Vm::Block.new("main_entry")
entry.add_code mov( :left => :fp , :right => 0 ) entry.add_code mov( :left => :fp , :right => 0 )
end end
def main_exit def main_exit exit
entry = Vm::Block.new("main_exit") exit.add_code syscall(1)
entry.add_code syscall(1)
end end
def function_entry f_name def function_entry block, f_name
entry = Vm::Block.new("#{f_name}_entry") # entry.add_code push( :regs => [:lr] )
# entry.add_code push( :regs => [:lr] ) block
end end
def function_exit f_name def function_exit entry , f_name
entry = Vm::Block.new("#{f_name}_exit")
entry.add_code mov( :left => :pc , :right => :lr ) entry.add_code mov( :left => :pc , :right => :lr )
end end
def putstring def putstring

View File

@ -14,7 +14,7 @@ module Ast
value.to_s value.to_s
end end
def compile context , into def compile context , into
Vm::Integer.new value Vm::IntegerConstant.new value
end end
def attributes def attributes
[:value] [:value]

View File

@ -18,16 +18,20 @@ module Ast
end end
def compile context , into def compile context , into
raise "function does not compile into anything #{self}" if into raise "function does not compile into anything #{self}" if into
parent_locals = context.locals
context.locals = {}
args = [] args = []
locals = {}
params.each_with_index do |param , index| params.each_with_index do |param , index|
arg = param.name arg = param.name
arg_value = Vm::Integer.new(index) arg_value = Vm::Integer.new(index)
context.locals[arg] = arg_value locals[arg] = arg_value
args << arg_value args << arg_value
end end
function = Vm::Function.new(name , args ) function = Vm::Function.new(name , args )
parent_locals = context.locals
parent_function = context.function
context.locals = locals
context.function = function
context.program.add_function function context.program.add_function function
into = function.entry into = function.entry
block.each do |b| block.each do |b|
@ -41,6 +45,7 @@ module Ast
puts compiled.inspect puts compiled.inspect
end end
context.locals = parent_locals context.locals = parent_locals
context.function = parent_function
function function
end end

View File

@ -43,10 +43,15 @@ module Ast
"#{left} #{operator} #{right}" "#{left} #{operator} #{right}"
end end
def compile context , into def compile context , into
puts "compile #{to_s}"
r_val = right.compile(context , into) r_val = right.compile(context , into)
if operator == "=" # assignemnt if operator == "=" # assignemnt
raise "Can only assign variables, not #{left}" unless left.is_a?(NameExpression) raise "Can only assign variables, not #{left}" unless left.is_a?(NameExpression)
if r_val.is_a? Vm::IntegerConstant
puts context.attributes.keys.join(" ")
next_register = context.function.next_register
r_val = Vm::Integer.new(next_register).load( into , r_val )
end
context.locals[left.name] = r_val context.locals[left.name] = r_val
return r_val return r_val
end end
@ -54,9 +59,9 @@ module Ast
case operator case operator
when ">" when ">"
code = l_val.less_or_equal r_val code = l_val.less_or_equal into , r_val
when "+" when "+"
code = l_val.plus r_val code = l_val.plus into , r_val
else else
raise "unimplemented operator #{operator} #{self}" raise "unimplemented operator #{operator} #{self}"
end end

View File

@ -4,19 +4,19 @@ module Core
#there are no Kernel instances, only class methods. #there are no Kernel instances, only class methods.
# We use this module syntax to avoid the (ugly) self (also eases searching). # We use this module syntax to avoid the (ugly) self (also eases searching).
module ClassMethods module ClassMethods
def main_start def main_start block
#TODO extract args into array of strings #TODO extract args into array of strings
Vm::CMachine.instance.main_start Vm::CMachine.instance.main_start block
end end
def main_exit def main_exit block
# Machine.exit mov r7 , 0 + swi 0 # Machine.exit mov r7 , 0 + swi 0
Vm::CMachine.instance.main_exit Vm::CMachine.instance.main_exit block
end end
def function_entry f_name def function_entry block , f_name
Vm::CMachine.instance.function_entry f_name Vm::CMachine.instance.function_entry block , f_name
end end
def function_exit f_name def function_exit block , f_name
Vm::CMachine.instance.function_exit f_name Vm::CMachine.instance.function_exit block , f_name
end end
def putstring def putstring
# should unwrap from string to char* # should unwrap from string to char*

View File

@ -34,11 +34,7 @@ module Vm
end end
def add_code(kode) def add_code(kode)
if( kode.is_a? Array ) @codes << kode
kode.each { |code| @codes << code }
else
@codes << kode
end
self self
end end

View File

@ -11,7 +11,7 @@ module Vm
class IntegerConstant < Constant class IntegerConstant < Constant
def init int def initialize int
@integer = int @integer = int
end end
attr_reader :integer attr_reader :integer

View File

@ -12,6 +12,6 @@ module Vm
@attributes = {} @attributes = {}
@attributes[:program] = program @attributes[:program] = program
end end
attr_reader :attributes
end end
end end

View File

@ -22,24 +22,24 @@ module Vm
super() super()
@name = name @name = name
@args = args @args = args
@entry = Core::Kernel::function_entry( name ) @entry = Core::Kernel::function_entry( Vm::Block.new("#{name}_exit") ,name )
@exit = Core::Kernel::function_exit( name ) @exit = Core::Kernel::function_exit( Vm::Block.new("#{name}_entry") , name )
@body = Block.new("#{name}_body") @body = Block.new("#{name}_body")
@reg_count = 0
branch_body branch_body
end end
attr_reader :args , :entry , :exit , :body , :name attr_reader :args , :entry , :exit , :body , :name
# this creates a branch from entry here and from here to exit
# unless there is a link existing, in which you are resposible
def set_body body
@body = body
branch_body
end
def arity def arity
@args.length @args.length
end end
def next_register
next_free = @reg_count
@reg_count += 1
next_free + args.length
end
def link_at address , context def link_at address , context
raise "undefined code #{inspect}" if @body.nil? raise "undefined code #{inspect}" if @body.nil?
super #just sets the position super #just sets the position
@ -66,10 +66,5 @@ module Vm
@entry.set_next(@body) @entry.set_next(@body)
@body.set_next(@exit) if @body and !@body.next @body.set_next(@exit) if @body and !@body.next
end end
def add_arg value
# TODO check
@args << value
end
end end
end end

View File

@ -12,9 +12,9 @@ module Vm
attr_reader :function , :args , :name attr_reader :function , :args , :name
def load_args into def load_args into
raise args.inspect
args.each_with_index do |arg , index| args.each_with_index do |arg , index|
into.add_code arg.load("r#{index}".to_sym) puts "load " + arg.inspect
into.add_code arg.move("r#{index}".to_sym)
end end
end end

View File

@ -31,10 +31,10 @@ module Vm
@objects = [] @objects = []
# global functions # global functions
@functions = [] @functions = []
@entry = Core::Kernel::main_start @entry = Core::Kernel::main_start Vm::Block.new("main_entry")
#main gets executed between entry and exit #main gets executed between entry and exit
@main = Block.new("main") @main = Block.new("main")
@exit = Core::Kernel::main_exit @exit = Core::Kernel::main_exit Vm::Block.new("main_exit")
end end
attr_reader :context , :main , :functions attr_reader :context , :main , :functions
@ -58,9 +58,7 @@ module Vm
fun = get_function name fun = get_function name
unless fun unless fun
puts @functions.inspect puts @functions.inspect
fun = Function.new(name) fun = Core::Kernel.send(name)
block = Core::Kernel.send(name)
fun.set_body block
@functions << fun @functions << fun
end end
fun fun

View File

@ -27,6 +27,11 @@ module Vm
end end
end end
# Just a nice way to write branches
class Bool < Value
end
# This is what it is when we don't know what it is. # This is what it is when we don't know what it is.
# Must be promoted to A Word-Value to to anything # Must be promoted to A Word-Value to to anything
# remembering that our oo machine is typed, no overloading or stuff # remembering that our oo machine is typed, no overloading or stuff
@ -34,10 +39,12 @@ module Vm
attr_accessor :register attr_accessor :register
def initialize reg def inspect
register = reg self.class.name + ":reg:#{register}:"
end
def initialize reg
@register = reg
end end
def length def length
4 4
end end
@ -45,19 +52,23 @@ module Vm
class Unsigned < Word class Unsigned < Word
def plus unsigned def plus block , unsigned
Machine.instance.unsigned_plus self , unsigned CMachine.instance.unsigned_plus self , unsigned
end end
end end
class Integer < Word class Integer < Word
def less_or_equal right def less_or_equal block , right
Machine.instance.integer_less_or_equal self , right CMachine.instance.integer_less_or_equal block , self , right
end end
def plus right def plus block , right
Machine.instance.integer_plus self , right CMachine.instance.integer_plus block , self , right
end
def load block , right
CMachine.instance.integer_load block , self , right
end end
end end
end end