~tim/scheme-vm

scheme-vm/compiler/optimizer.rb -rw-r--r-- 1.3 KiB
00cdee12Tim Morgan Remove old code 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
require_relative '../vm'

class Compiler
  class Optimizer
    def initialize(instructions)
      @instructions = instructions.dup
    end

    def optimize
      jump_to_return
      @instructions
    end

    private

    # changes JUMP -> RETURN if the JUMP would land on a RETURN,
    # or if JUMP would land on a JUMP that would land on a RETURN, and so on,
    # allowing tail-call elimination to work with if expressions
    def jump_to_return
      jumps.reverse.each do |ip|
        hops = @instructions[ip + 1]
        if @instructions[ip + hops + 1] == VM::RETURN
          # add a NOOP so other JUMPs don't break
          @instructions[ip, 2] = [VM::RETURN, VM::NOOP]
        end
      end
    end

    def jumps
      ip = 0
      jumps = []
      while ip < @instructions.size
        instruction = @instructions[ip]
        raise_invalid_instruction_error(ip) unless instruction.is_a?(Integer)
        (_name, arity) = VM::INSTRUCTIONS.fetch(instruction)
        jumps << ip if instruction == VM::JUMP
        ip += arity + 1
      end
      jumps
    end

    def raise_invalid_instruction_error(ip)
      puts 'Full compiled code:'
      p @instructions
      puts "Something is wrong starting at index #{ip}: #{@instructions[ip..(ip + 2)].inspect}"
      raise 'Invalid compiled code.'
    end
  end
end