From 4f290ee246457aec1d7f6d0246fcf8895d23b9ff Mon Sep 17 00:00:00 2001 From: Torsten Date: Wed, 18 Mar 2020 17:50:22 +0200 Subject: [PATCH] basic liveliness for allocator --- lib/risc/standard_allocator.rb | 23 +++++++++++++++++++++++ test/risc/test_standard_allocator.rb | 7 +++++++ test/risc/test_standard_allocator1.rb | 22 ++++++++++++++++++++++ test/support/compiling.rb | 2 +- 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 test/risc/test_standard_allocator1.rb diff --git a/lib/risc/standard_allocator.rb b/lib/risc/standard_allocator.rb index 01f4f218..ff38a331 100644 --- a/lib/risc/standard_allocator.rb +++ b/lib/risc/standard_allocator.rb @@ -13,6 +13,7 @@ module Risc @compiler = compiler @platform = platform @used_regs = {} + @release_points = Hash.new( [] ) @reg_names = (0 ... platform.num_registers).collect{|i| "r#{i-1}".to_sym } end attr_reader :used_regs , :compiler , :platform , :reg_names @@ -23,7 +24,29 @@ module Risc # Ie on arm register names are r0 .. . r15 , so it keeps a list of unused # regs and frees regs according to live ranges def allocate_regs + determine_liveness + end + # determines when registers can be freed + # + # this is done by walking the instructions backwards and saving the first + # occurence of a register name. (The last, as we walk backwards) + def determine_liveness + walk_and_mark(@compiler.risc_instructions) + end + + # First walk down, and on the way up mark register occurences, unless they + # have been marked already + def walk_and_mark(instruction) + released = [] + released = walk_and_mark(instruction.next) if instruction.next + #puts instruction.class.name + instruction.register_names.each do |name| + next if released.include?(name) + @release_points[instruction] << name + released << name + end + released end def used_regs_empty? diff --git a/test/risc/test_standard_allocator.rb b/test/risc/test_standard_allocator.rb index 76dd5906..16fbb5af 100644 --- a/test/risc/test_standard_allocator.rb +++ b/test/risc/test_standard_allocator.rb @@ -26,6 +26,13 @@ module Risc def test_platform assert_equal Arm::ArmPlatform , @allocator.platform.class end + def test_allocate_runs + assert @allocator.allocate_regs + end + def test_live + live = @allocator.determine_liveness + assert_equal 0 , live.length + end def test_add_ok assert_equal RegisterValue, @allocator.use_reg(tmp_reg).class end diff --git a/test/risc/test_standard_allocator1.rb b/test/risc/test_standard_allocator1.rb new file mode 100644 index 00000000..c34d8293 --- /dev/null +++ b/test/risc/test_standard_allocator1.rb @@ -0,0 +1,22 @@ +require_relative "../helper" + +module Risc + class TestStandardAllocator1 < MiniTest::Test + include SlotMachineCompile + def setup + coll = compile_slot( "class Space ; def main(); main{return 'Ho'};return 'Hi'; end; end;") + @compiler = coll.to_risc.method_compilers + @allocator = Platform.for(:arm).allocator(@compiler) + end + def test_main + assert_equal :main , @compiler.callable.name + end + def test_allocate_runs + assert @allocator.allocate_regs + end + def test_live_length + live = @allocator.determine_liveness + assert_equal 10 , live.length + end + end +end diff --git a/test/support/compiling.rb b/test/support/compiling.rb index a4c8ba9f..483de819 100644 --- a/test/support/compiling.rb +++ b/test/support/compiling.rb @@ -4,7 +4,7 @@ module ScopeHelper def compiler_with_main(options = {}) compiler = RubyX::RubyXCompiler.new(RubyX.default_test_options.merge(options)) - compiler.ruby_to_sol( in_Space( as_main("return")) ) + compiler.ruby_to_sol( as_main("return 5") ) compiler end def in_Test(statements)