create a load on the compiler

thus removing the need for << with objects on RegisterValue
This commit is contained in:
Torsten 2020-03-01 10:52:21 +02:00
parent 95f3eec043
commit 64d860b2bf
7 changed files with 48 additions and 92 deletions

View File

@ -90,18 +90,16 @@ module Risc
copied copied
end end
# releasing a register (accuired by use_reg) makes it available for use again # Load a constant, meaning create a LoadConstant instruction for the constant
# thus avoiding possibly using too many registers # add the instruction to the code and return the register_value that was created
def release_reg( reg ) # for further use
last = @allocator.pop def load_object( object )
raise "released register in wrong order, expect #{last} but was #{reg}" if reg != last raise "must be Parfait, not #{object.class}" unless object.is_a?(Parfait::Object)
end ins = Risc.load_constant("load to #{object.type}" , object)
add_code ins
# reset the registers to be used. Start at r4 for next usage. # todo for constants (not objects)
# Every statement starts with this, meaning each statement may use all registers, but none # add_constant(right) if compiler
# get saved. Statements have affect on objects. ins.register
def reset_regs
@allocator.clear_regs
end end
# Build with builder (see there), adding the created instructions # Build with builder (see there), adding the created instructions

View File

@ -14,10 +14,10 @@ module Risc
# or r-vlalue respectively. # or r-vlalue respectively.
class RegisterSlot class RegisterSlot
attr_reader :register , :index , :builder attr_reader :register , :index , :compiler
def initialize(register, index , builder) def initialize(register, index , compiler)
@register , @index , @builder = register , index , builder @register , @index , @compiler = register , index , compiler
end end
# fullfil the objects purpose by creating a RegToSlot instruction from # fullfil the objects purpose by creating a RegToSlot instruction from
@ -25,7 +25,7 @@ module Risc
def <<( reg ) def <<( reg )
raise "not reg #{reg}" unless reg.is_a?(RegisterValue) raise "not reg #{reg}" unless reg.is_a?(RegisterValue)
reg_to_slot = Risc.reg_to_slot("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index) reg_to_slot = Risc.reg_to_slot("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index)
builder.add_code(reg_to_slot) if builder compiler.add_code(reg_to_slot) if compiler
reg_to_slot reg_to_slot
end end
@ -34,7 +34,7 @@ module Risc
def <=( reg ) def <=( reg )
raise "not reg #{reg}" unless reg.is_a?(RegisterValue) raise "not reg #{reg}" unless reg.is_a?(RegisterValue)
reg_to_byte = Risc.reg_to_byte("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index) reg_to_byte = Risc.reg_to_byte("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index)
builder.add_code(reg_to_byte) if builder compiler.add_code(reg_to_byte) if compiler
reg_to_byte reg_to_byte
end end

View File

@ -5,13 +5,13 @@ module Risc
# The type is always known, and sometimes the value too # The type is always known, and sometimes the value too
# Or something about the value, like some instances types # Or something about the value, like some instances types
# #
# When participating in the builder dsl, a builder may be set to get the # When participating in the compiler dsl, a compiler may be set to get the
# results of dsl operations (like <<) back to the builder # results of dsl operations (like <<) back to the compiler
class RegisterValue class RegisterValue
attr_reader :symbol , :type , :extra attr_reader :symbol , :type , :extra
attr_reader :builder attr_reader :compiler
# The first arg is a symbol :r0 - :r12 # The first arg is a symbol :r0 - :r12
# Second arg is the type, which may be given as the symbol of the class name # Second arg is the type, which may be given as the symbol of the class name
@ -34,11 +34,11 @@ module Risc
@type.class_name @type.class_name
end end
# allows to set the builder, which is mainly done by the builder # allows to set the compiler, which is mainly done by the compiler
# but sometimes, eg in exit, one nneds to create the reg by hand and set # but sometimes, eg in exit, one nneds to create the reg by hand and set
# return the RegisterValue for chaining in assignment # return the RegisterValue for chaining in assignment
def set_builder( builder ) def set_compiler( compiler )
@builder = builder @compiler = compiler
self self
end end
@ -64,10 +64,10 @@ module Risc
type.type_at(index) type.type_at(index)
end end
# reduce integer to fixnum and add instruction if builder is used # reduce integer to fixnum and add instruction if compiler is used
def reduce_int def reduce_int
reduce = Risc::SlotToReg.new( "int -> fix" , self , Parfait::Integer.integer_index , self) reduce = Risc::SlotToReg.new( "int -> fix" , self , Parfait::Integer.integer_index , self)
builder.add_code(reduce) if builder compiler.add_code(reduce) if compiler
reduce reduce
end end
@ -136,25 +136,19 @@ module Risc
# - an RegisterSlot, resulting in an SlotToReg # - an RegisterSlot, resulting in an SlotToReg
def <<( right ) def <<( right )
case right case right
when Symbol
ins = Risc::LoadConstant.new("#{right.class} to #{self.type}" , right , self)
when Parfait::Object
ins = Risc::LoadConstant.new("#{right.class} to #{self.type}" , right , self)
builder.compiler.add_constant(right) if builder
when Label when Label
ins = Risc::LoadConstant.new("#{right.class} to #{self.type}" , right , self) ins = Risc::LoadConstant.new("#{right.class} to #{self.type}" , right , self)
builder.compiler.add_constant(right.address) if builder compiler.compiler.add_constant(right.address) if compiler
when ::Integer when ::Integer
ins = Risc.load_data("#{right.class} to #{self.type}" , right , self) ins = Risc.load_data("#{right.class} to #{self.type}" , right , self)
when RegisterValue when RegisterValue
ins = Risc.transfer("#{right.type} to #{self.type}" , right , self) ins = Risc.transfer("#{right.type} to #{self.type}" , right , self)
when RegisterSlot when RegisterSlot
puts right.to_s
ins = Risc::SlotToReg.new("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self) ins = Risc::SlotToReg.new("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self)
else else
raise "not implemented for #{right.class}:#{right}" raise "not implemented for #{right.class}:#{right}"
end end
builder.add_code(ins) if builder compiler.add_code(ins) if compiler
return ins return ins
end end
@ -163,14 +157,14 @@ module Risc
def <=( right ) def <=( right )
raise "not implemented for #{right.class}:#{right}" unless right.is_a?( RegisterSlot ) raise "not implemented for #{right.class}:#{right}" unless right.is_a?( RegisterSlot )
ins = Risc.byte_to_reg("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self) ins = Risc.byte_to_reg("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self)
builder.add_code(ins) if builder compiler.add_code(ins) if compiler
return ins return ins
end end
def -( right ) def -( right )
raise "operators only on registers, not #{right.class}" unless right.is_a? RegisterValue raise "operators only on registers, not #{right.class}" unless right.is_a? RegisterValue
op = Risc.op("#{self.type} - #{right.type}", :- , self , right ) op = Risc.op("#{self.type} - #{right.type}", :- , self , right )
builder.add_code(op) if builder compiler.add_code(op) if compiler
op op
end end
@ -178,7 +172,7 @@ module Risc
# doesn't read quite as smoothly as one would like, but better than the compiler version # doesn't read quite as smoothly as one would like, but better than the compiler version
def op( operator , right) def op( operator , right)
ret = Risc.op( "operator #{operator}" , operator , self , right) ret = Risc.op( "operator #{operator}" , operator , self , right)
builder.add_code(ret) if builder compiler.add_code(ret) if compiler
ret ret
end end
@ -186,7 +180,7 @@ module Risc
# The RegisterSlot then gets used in a RegToSlot or SlotToReg, where # The RegisterSlot then gets used in a RegToSlot or SlotToReg, where
# the values are unpacked to call Risc.reg_to_slot or Risc.slot_to_reg # the values are unpacked to call Risc.reg_to_slot or Risc.slot_to_reg
def []( index ) def []( index )
RegisterSlot.new( self , index , builder) RegisterSlot.new( self , index , compiler)
end end
end end

View File

@ -1,13 +1,5 @@
require_relative "helper" require_relative "helper"
module Risc module Risc
class FakeCallableCompiler < CallableCompiler
def initialize(a,c)
super(a,c)
end
def source_name
"luke"
end
end
class TestCallableCompiler < MiniTest::Test class TestCallableCompiler < MiniTest::Test
def setup def setup
Parfait.boot!({}) Parfait.boot!({})
@ -29,28 +21,15 @@ module Risc
def test_const def test_const
assert_equal Array , @compiler.constants.class assert_equal Array , @compiler.constants.class
end end
def test_load_class
object = @compiler.load_object(Parfait.object_space)
assert_equal RegisterValue , object.class
assert object.is_object?
end end
class TestFakeCallableCompiler < MiniTest::Test def test_load_code
def setup object = @compiler.load_object(Parfait.object_space)
Parfait.boot!({}) assert_equal LoadConstant , @compiler.current.class
label = SlotMachine::Label.new("hi","ho") assert_equal Parfait::Space , @compiler.current.constant.class
@compiler = FakeCallableCompiler.new(FakeCallable.new , label)
end
def test_ok
assert @compiler
end
def test_current
assert @compiler.current
end
def test_current_label
assert_equal Label , @compiler.current.class
assert_equal "ho" , @compiler.current.name
end
def test_slot
assert @compiler.risc_instructions
end
def test_const
assert_equal Array , @compiler.constants.class
end end
end end
end end

View File

@ -17,14 +17,6 @@ module Risc
def test_r0 def test_r0
assert_equal :message , @r0.symbol assert_equal :message , @r0.symbol
end end
def test_load_space
move = @r0 << Parfait.object_space
assert_equal LoadConstant , move.class
end
def test_load_symbol
move = @r1 << :puts
assert_equal LoadConstant , move.class
end
def test_load_label def test_load_label
label = Risc::Label.new("HI","ho" , FakeAddress.new(0)) label = Risc::Label.new("HI","ho" , FakeAddress.new(0))
move = @r1 << label move = @r1 << label

View File

@ -1,9 +1,9 @@
require_relative "../helper" require_relative "../helper"
class FakeBuilder class SuperFakeCompiler
attr_reader :built attr_reader :code
def add_code(ins) def add_code(ins)
@built = ins @code = ins
end end
end end
module Risc module Risc
@ -24,14 +24,6 @@ module Risc
def test_r0 def test_r0
assert_equal :message , @r0.symbol assert_equal :message , @r0.symbol
end end
def test_load_space
move = @r0 << Parfait.object_space
assert_equal LoadConstant , move.class
end
def test_load_symbol
move = @r1 << :puts
assert_equal LoadConstant , move.class
end
def test_load_label def test_load_label
label = Risc::Label.new("HI","ho" , FakeAddress.new(0)) label = Risc::Label.new("HI","ho" , FakeAddress.new(0))
move = @r1 << label move = @r1 << label
@ -41,16 +33,16 @@ module Risc
transfer = @r0 << @r1 transfer = @r0 << @r1
assert_equal Transfer , transfer.class assert_equal Transfer , transfer.class
end end
def test_set_builder def test_set_compiler
reg = @r0.set_builder(FakeBuilder.new) reg = @r0.set_compiler(SuperFakeCompiler.new)
assert_equal RegisterValue , reg.class assert_equal RegisterValue , reg.class
assert reg.builder assert reg.compiler
end end
def test_calls_builder def test_calls_compiler
builder = FakeBuilder.new compiler = SuperFakeCompiler.new
@r0.set_builder( builder ) @r0.set_compiler( compiler )
@r0 << @r1 @r0 << @r1
assert_equal Transfer , builder.built.class assert_equal Transfer , compiler.code.class
end end
def test_index_op def test_index_op
message = @r0[:next_message] message = @r0[:next_message]

View File

@ -1,5 +1,6 @@
require_relative "helper" require_relative "helper"
module SlotMachine module SlotMachine
# need to derive, to overwrite source_name
class FakeCallableCompiler < CallableCompiler class FakeCallableCompiler < CallableCompiler
def source_name def source_name
"luke" "luke"