From 9687d6611f2d03612774bb4539a430ad898161d2 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sun, 19 Aug 2018 17:29:04 +0300 Subject: [PATCH] avoid adding risc instructions twice that causes loops in the chain infinite loops in the code that are hard to debug closes #11 --- lib/mom/instruction/jump.rb | 3 +- lib/mom/instruction/label.rb | 39 ++++++++++++------- lib/mom/instruction/not_same_check.rb | 2 +- lib/mom/instruction/truth_check.rb | 2 +- lib/risc/callable_compiler.rb | 3 +- test/mom/send/test_setup_simple.rb | 5 +++ .../{instruction => }/test_return_sequence.rb | 2 +- 7 files changed, 37 insertions(+), 19 deletions(-) rename test/mom/{instruction => }/test_return_sequence.rb (98%) diff --git a/lib/mom/instruction/jump.rb b/lib/mom/instruction/jump.rb index 470aac2d..8f51de64 100644 --- a/lib/mom/instruction/jump.rb +++ b/lib/mom/instruction/jump.rb @@ -12,8 +12,7 @@ module Mom @label = label end def to_risc(compiler) - label = @label.to_risc(compiler) - compiler.add_code Risc::Branch.new(self , label) + compiler.add_code Risc::Branch.new(self , @label.risc_label) end end diff --git a/lib/mom/instruction/label.rb b/lib/mom/instruction/label.rb index 3770f29d..5a5cc2ec 100644 --- a/lib/mom/instruction/label.rb +++ b/lib/mom/instruction/label.rb @@ -8,6 +8,19 @@ module Mom # # A Label has a name which is mainly used for debugging. # + # A Mom::Label converts one2one to a Risc::Label. So in a way it could not be more + # simple. + # Alas, since almost by definition several roads lead to this label, all those + # several converted instructions must also point to the identical label on the + # risc level. + # + # This is achieved by caching the created Risc::Label in an instance variable. + # All branches that lead to this label can thus safely call the to_risc and + # whoever calls first triggers the labels creation, but all get the same label. + # + # Off course some specific place still has to be responsible for actually + # adding the label to the instruction list (usually an if/while) + class Label < Instruction attr_reader :name def initialize(name) @@ -18,20 +31,20 @@ module Mom "Label: #{name}" end - # A Mom::Label converts one2one to a Risc::Label. So in a way it could not be more - # simple. - # Alas, since almost by definition several roads lead to this label, all those - # several converted instructions must also point to the identical label on the - # risc level. - # - # This is achieved by caching the created Risc::Label in an instance variable. - # All branches that lead to this label can thus safely call the to_risc and - # whoever calls first triggers the labels creation, but all get the same label. - # - # Off course some specific place still has to be responsible for actually - # adding the label to the instruction list (usually an if/while) - def to_risc(compiler) + # generate the risc label lazily + def risc_label @risc_label ||= Risc.label(self,name) end + + # add the risc_label to the compiler (instruction flow) + # should only be called once + def to_risc(compiler) + if( @added ) + raise "added already #{@added}" + else + @added = true + compiler.add_code( risc_label ) + end + end end end diff --git a/lib/mom/instruction/not_same_check.rb b/lib/mom/instruction/not_same_check.rb index 67034c4a..fa00eacd 100644 --- a/lib/mom/instruction/not_same_check.rb +++ b/lib/mom/instruction/not_same_check.rb @@ -26,7 +26,7 @@ module Mom l_reg = left.to_register(compiler, self) r_reg = right.to_register(compiler, self) compiler.add_code Risc.op( self , :- , l_reg , r_reg) - compiler.add_code Risc::IsZero.new( self, false_jump.to_risc(compiler)) + compiler.add_code Risc::IsZero.new( self, false_jump.risc_label) end end end diff --git a/lib/mom/instruction/truth_check.rb b/lib/mom/instruction/truth_check.rb index 94fb37fd..0a5214ef 100644 --- a/lib/mom/instruction/truth_check.rb +++ b/lib/mom/instruction/truth_check.rb @@ -19,7 +19,7 @@ module Mom end def to_risc(compiler) - false_label = @false_jump.to_risc(compiler) + false_label = @false_jump.risc_label builder = compiler.builder("TruthCheck") condition_reg = @condition.to_register(compiler,self) builder.build do diff --git a/lib/risc/callable_compiler.rb b/lib/risc/callable_compiler.rb index 438f4e44..f79d37f3 100644 --- a/lib/risc/callable_compiler.rb +++ b/lib/risc/callable_compiler.rb @@ -16,10 +16,11 @@ module Risc @constants = [] @block_compilers = [] @risc_instructions = Risc.label(source_name, source_name) - @current = @risc_instructions + @current = start = @risc_instructions add_code Risc.label( source_name, "return_label") Mom::ReturnSequence.new.to_risc(self) add_code Risc.label( source_name, "unreachable") + @current = start reset_regs end attr_reader :risc_instructions , :constants , :block_compilers , :callable , :current diff --git a/test/mom/send/test_setup_simple.rb b/test/mom/send/test_setup_simple.rb index 45d91175..d44dcda1 100644 --- a/test/mom/send/test_setup_simple.rb +++ b/test/mom/send/test_setup_simple.rb @@ -50,5 +50,10 @@ module Risc sl = @produced.next( 7 ) assert_reg_to_slot( sl , :r1 , :r3 , 7 ) end + def test_label + sl = @produced.next( 17 ) + assert_equal Risc::Label , sl.class + assert_equal "return_label" , sl.name + end end end diff --git a/test/mom/instruction/test_return_sequence.rb b/test/mom/test_return_sequence.rb similarity index 98% rename from test/mom/instruction/test_return_sequence.rb rename to test/mom/test_return_sequence.rb index 432d9c72..3387d5f3 100644 --- a/test/mom/instruction/test_return_sequence.rb +++ b/test/mom/test_return_sequence.rb @@ -1,4 +1,4 @@ -require_relative "../helper" +require_relative "helper" module Risc class TestReturnSequence < MiniTest::Test