rucc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +55 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +46 -0
- data/LICENCE +21 -0
- data/README.md +82 -0
- data/Rakefile +2 -0
- data/Vagrantfile +10 -0
- data/bin/console +10 -0
- data/bin/rspec +2 -0
- data/bin/setup +8 -0
- data/exe/rucc +7 -0
- data/include/8cc.h +48 -0
- data/include/float.h +44 -0
- data/include/iso646.h +20 -0
- data/include/rucc.h +2 -0
- data/include/stdalign.h +11 -0
- data/include/stdarg.h +52 -0
- data/include/stdbool.h +11 -0
- data/include/stddef.h +15 -0
- data/include/stdnoreturn.h +8 -0
- data/lib/rucc.rb +8 -0
- data/lib/rucc/case.rb +22 -0
- data/lib/rucc/decl.rb +9 -0
- data/lib/rucc/enc.rb +9 -0
- data/lib/rucc/engine.rb +138 -0
- data/lib/rucc/file_io.rb +108 -0
- data/lib/rucc/file_io_list.rb +56 -0
- data/lib/rucc/gen.rb +1602 -0
- data/lib/rucc/int_evaluator.rb +114 -0
- data/lib/rucc/k.rb +73 -0
- data/lib/rucc/keyword.rb +17 -0
- data/lib/rucc/kind.rb +43 -0
- data/lib/rucc/label_gen.rb +13 -0
- data/lib/rucc/lexer.rb +40 -0
- data/lib/rucc/lexer/impl.rb +683 -0
- data/lib/rucc/lexer/preprocessor.rb +888 -0
- data/lib/rucc/lexer/preprocessor/cond_incl.rb +27 -0
- data/lib/rucc/lexer/preprocessor/constructor.rb +54 -0
- data/lib/rucc/lexer/preprocessor/pragma.rb +31 -0
- data/lib/rucc/lexer/preprocessor/special_macro.rb +110 -0
- data/lib/rucc/libc.rb +47 -0
- data/lib/rucc/m.rb +7 -0
- data/lib/rucc/macro.rb +24 -0
- data/lib/rucc/node.rb +530 -0
- data/lib/rucc/node/conv.rb +33 -0
- data/lib/rucc/op.rb +61 -0
- data/lib/rucc/operator.rb +13 -0
- data/lib/rucc/option.rb +30 -0
- data/lib/rucc/parser.rb +961 -0
- data/lib/rucc/parser/break.rb +18 -0
- data/lib/rucc/parser/builtin.rb +25 -0
- data/lib/rucc/parser/continue.rb +18 -0
- data/lib/rucc/parser/do.rb +33 -0
- data/lib/rucc/parser/ensure.rb +39 -0
- data/lib/rucc/parser/enum.rb +64 -0
- data/lib/rucc/parser/expr.rb +493 -0
- data/lib/rucc/parser/for.rb +71 -0
- data/lib/rucc/parser/func.rb +274 -0
- data/lib/rucc/parser/func_call.rb +54 -0
- data/lib/rucc/parser/goto.rb +29 -0
- data/lib/rucc/parser/if.rb +23 -0
- data/lib/rucc/parser/initializer.rb +237 -0
- data/lib/rucc/parser/label.rb +31 -0
- data/lib/rucc/parser/return.rb +16 -0
- data/lib/rucc/parser/struct_and_union.rb +280 -0
- data/lib/rucc/parser/switch.rb +117 -0
- data/lib/rucc/parser/while.rb +29 -0
- data/lib/rucc/pos.rb +11 -0
- data/lib/rucc/rmap.rb +22 -0
- data/lib/rucc/s.rb +9 -0
- data/lib/rucc/static_label_gen.rb +15 -0
- data/lib/rucc/t.rb +18 -0
- data/lib/rucc/tempname_gen.rb +14 -0
- data/lib/rucc/token.rb +114 -0
- data/lib/rucc/token_gen.rb +68 -0
- data/lib/rucc/type.rb +304 -0
- data/lib/rucc/type/check.rb +39 -0
- data/lib/rucc/type/conv.rb +29 -0
- data/lib/rucc/type_info.rb +21 -0
- data/lib/rucc/utf.rb +126 -0
- data/lib/rucc/util.rb +111 -0
- data/lib/rucc/version.rb +3 -0
- data/rucc.gemspec +38 -0
- metadata +201 -0
    
        data/include/stdbool.h
    ADDED
    
    
    
        data/include/stddef.h
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            // Copyright 2012 Rui Ueyama. Released under the MIT license.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #ifndef __STDDEF_H
         | 
| 4 | 
            +
            #define __STDDEF_H
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #define NULL ((void *)0)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            typedef unsigned long size_t;
         | 
| 9 | 
            +
            typedef long ptrdiff_t;
         | 
| 10 | 
            +
            typedef unsigned int wchar_t;
         | 
| 11 | 
            +
            typedef long double max_align_t;
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            #define offsetof(type, member) ((size_t)&(((type *)0)->member))
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            #endif
         | 
    
        data/lib/rucc.rb
    ADDED
    
    
    
        data/lib/rucc/case.rb
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class Case
         | 
| 3 | 
            +
                # @param [Integer] b
         | 
| 4 | 
            +
                # @param [Integer] e
         | 
| 5 | 
            +
                # @param [String] label
         | 
| 6 | 
            +
                def initialize(b:, e:, label:)
         | 
| 7 | 
            +
                  @b = b
         | 
| 8 | 
            +
                  @e = e
         | 
| 9 | 
            +
                  @label = label
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                attr_reader :b, :e, :label
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                class << self
         | 
| 14 | 
            +
                  # @param [Integer] b
         | 
| 15 | 
            +
                  # @param [Integer] e
         | 
| 16 | 
            +
                  # @param [String] label
         | 
| 17 | 
            +
                  def make_case(b, e, label)
         | 
| 18 | 
            +
                    Case.new(b: b, e: e, label: label)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
    
        data/lib/rucc/decl.rb
    ADDED
    
    
    
        data/lib/rucc/enc.rb
    ADDED
    
    
    
        data/lib/rucc/engine.rb
    ADDED
    
    | @@ -0,0 +1,138 @@ | |
| 1 | 
            +
            require 'fileutils'
         | 
| 2 | 
            +
            require "rucc/option"
         | 
| 3 | 
            +
            require "rucc/parser"
         | 
| 4 | 
            +
            require "rucc/gen"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Rucc
         | 
| 7 | 
            +
              class Engine
         | 
| 8 | 
            +
                # When io is specified, io is used as input source. When io is not specified,
         | 
| 9 | 
            +
                # ARGV[0] is considered as sourcde file.
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                # @param [<String>] argv
         | 
| 12 | 
            +
                # @param [IO, NilClass] input
         | 
| 13 | 
            +
                def initialize(argv, input = nil)
         | 
| 14 | 
            +
                  @option = Option.new
         | 
| 15 | 
            +
                  @option.parse!(argv)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  if input
         | 
| 18 | 
            +
                    @filename = "-"
         | 
| 19 | 
            +
                  else
         | 
| 20 | 
            +
                    @filename = argv.first
         | 
| 21 | 
            +
                    input = File.open(@filename)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # Setup lexer
         | 
| 25 | 
            +
                  @lexer = Lexer.new(input, @filename)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  # Setup parser
         | 
| 28 | 
            +
                  label_gen = LabelGen.new
         | 
| 29 | 
            +
                  @parser = Parser.new(@lexer, label_gen)
         | 
| 30 | 
            +
                  @lexer.expr_reader = -> { @parser.read_expr }
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  # Setup gen
         | 
| 33 | 
            +
                  @out = StringIO.new
         | 
| 34 | 
            +
                  @gen = Gen.new(@out, label_gen)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  init_environment!
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # NOTE: Used only for debug
         | 
| 40 | 
            +
                def lex
         | 
| 41 | 
            +
                  r = []
         | 
| 42 | 
            +
                  while (tok = @lexer.lex).kind != T::EOF
         | 
| 43 | 
            +
                    r.push(tok)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  r
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def parse
         | 
| 49 | 
            +
                  @parser.read_toplevels
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def gen
         | 
| 53 | 
            +
                  parse.each do |toplevel_ast|
         | 
| 54 | 
            +
                    @gen.emit_toplevel(toplevel_ast)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                  @out.rewind
         | 
| 57 | 
            +
                  @out.read
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def run!
         | 
| 61 | 
            +
                  asm = gen
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  if @option.dumpasm
         | 
| 64 | 
            +
                    File.write(outfile('s'), asm)
         | 
| 65 | 
            +
                    return
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  File.write(tmpfile('s'), asm)
         | 
| 69 | 
            +
                  assemble!(src: tmpfile('s'), dst: tmpfile('o'))
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  if @option.dontlink
         | 
| 72 | 
            +
                    FileUtils.copy(tmpfile('o'), outfile('o'))
         | 
| 73 | 
            +
                    return
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  link!(src: tmpfile('o'), dst: (@option.outfile || "a.out"))
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              private
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def tmpfile(ext)
         | 
| 82 | 
            +
                  "/tmp/ruccXXXXXX.#{ext}"
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def outfile(ext)
         | 
| 86 | 
            +
                  if @option.outfile
         | 
| 87 | 
            +
                    @option.outfile
         | 
| 88 | 
            +
                  else
         | 
| 89 | 
            +
                    @filename.gsub(/\.c$/, ".#{ext}")
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                def assemble!(src:, dst:)
         | 
| 94 | 
            +
                  # TODO(south37) Check status code
         | 
| 95 | 
            +
                  `as -o #{dst} -c #{src}`
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def link!(src:, dst:)
         | 
| 99 | 
            +
                  # TODO(south37) Check status code
         | 
| 100 | 
            +
                  `/usr/lib/gcc/x86_64-linux-gnu/6/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/6/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper -plugin-opt=-fresolution=/tmp/ccGgKweC.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/6/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/6 -L/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/6/../../.. #{src} -o #{dst} -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/6/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crtn.o`
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def init_environment!
         | 
| 104 | 
            +
                  pre_difined_include_path.each do |path|
         | 
| 105 | 
            +
                    @lexer.append_include_path(path)
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  @option.include_path.each do |path|
         | 
| 109 | 
            +
                    @lexer.append_include_path(path)
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  read_from_string("#include <#{::Rucc.root}/include/rucc.h>")
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                def pre_difined_include_path
         | 
| 116 | 
            +
                  [
         | 
| 117 | 
            +
                    "#{::Rucc.root}/include",
         | 
| 118 | 
            +
                    "/usr/local/lib/rucc/include",
         | 
| 119 | 
            +
                    "/usr/local/include",
         | 
| 120 | 
            +
                    "/usr/include",
         | 
| 121 | 
            +
                    "/usr/include/linux",
         | 
| 122 | 
            +
                    "/usr/include/x86_64-linux-gnu",
         | 
| 123 | 
            +
                  ]
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                # Reads from a string as if the string is a content of input file.
         | 
| 127 | 
            +
                # Convenient for evaluating small string snippet contaiing preprocessor macros.
         | 
| 128 | 
            +
                #
         | 
| 129 | 
            +
                # @param [String] buf
         | 
| 130 | 
            +
                def read_from_string(buf)
         | 
| 131 | 
            +
                  @lexer.stream_stash([FileIO.new(StringIO.new(buf), "-")])
         | 
| 132 | 
            +
                  parse.each do |toplevel_ast|
         | 
| 133 | 
            +
                    @gen.emit_toplevel(toplevel_ast)
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
                  @lexer.stream_unstash
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
            end
         | 
    
        data/lib/rucc/file_io.rb
    ADDED
    
    | @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            module Rucc
         | 
| 2 | 
            +
              class FileIO
         | 
| 3 | 
            +
                EOF = nil
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # @param [IO] io
         | 
| 6 | 
            +
                # @param [String] name
         | 
| 7 | 
            +
                def initialize(io, name)
         | 
| 8 | 
            +
                  @io = io
         | 
| 9 | 
            +
                  @name = name
         | 
| 10 | 
            +
                  @line = 1
         | 
| 11 | 
            +
                  @column = 1
         | 
| 12 | 
            +
                  @ntok = 0  # Token counter
         | 
| 13 | 
            +
                  @buflen = 0
         | 
| 14 | 
            +
                  @buf = Array.new(3)
         | 
| 15 | 
            +
                  @last = Object.new  # NOTE: Not use nil because nil means EOF. Set dummy data at first.
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # TODO(south37) Set @mtime
         | 
| 18 | 
            +
                  # struct stat st;
         | 
| 19 | 
            +
                  # if (fstat(fileno(file), &st) == -1)
         | 
| 20 | 
            +
                  #     error("fstat failed: %s", strerror(errno));
         | 
| 21 | 
            +
                  # r->mtime = st.st_mtime;
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                attr_reader :name, :line, :column, :ntok
         | 
| 24 | 
            +
                attr_writer :name, :line
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # @return [Char, NilClass] nil at EOF
         | 
| 27 | 
            +
                def readc
         | 
| 28 | 
            +
                  while true do
         | 
| 29 | 
            +
                    c = get
         | 
| 30 | 
            +
                    if c == EOF
         | 
| 31 | 
            +
                      return c
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                    if (c != "\\")
         | 
| 34 | 
            +
                      return c
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                    c2 = get
         | 
| 37 | 
            +
                    if c2 == "\n"
         | 
| 38 | 
            +
                      next
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                    unreadc(c2)
         | 
| 41 | 
            +
                    return c
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                # @param [Char] c
         | 
| 46 | 
            +
                def unreadc(c)
         | 
| 47 | 
            +
                  return if c == EOF
         | 
| 48 | 
            +
                  Util.assert!{ @buflen < @buf.size }
         | 
| 49 | 
            +
                  @buf[@buflen] = c
         | 
| 50 | 
            +
                  @buflen += 1
         | 
| 51 | 
            +
                  if c == "\n"
         | 
| 52 | 
            +
                    @column = 1
         | 
| 53 | 
            +
                    @line -= 1
         | 
| 54 | 
            +
                  else
         | 
| 55 | 
            +
                    @column -= 1
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def incr_ntok!
         | 
| 60 | 
            +
                  @ntok += 1
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def close
         | 
| 64 | 
            +
                  @io.close
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def mtime
         | 
| 68 | 
            +
                  Util.assert!{ @io.is_a?(File) }
         | 
| 69 | 
            +
                  File.mtime(@io)
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              private
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                # @return [Char, NilClass] nil at EOF
         | 
| 75 | 
            +
                def get
         | 
| 76 | 
            +
                  if @buflen > 0
         | 
| 77 | 
            +
                    @buflen -= 1
         | 
| 78 | 
            +
                    c = @buf[@buflen]
         | 
| 79 | 
            +
                  else
         | 
| 80 | 
            +
                    c = readc_file
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  if c == "\n"
         | 
| 84 | 
            +
                    @line += 1
         | 
| 85 | 
            +
                    @column = 1
         | 
| 86 | 
            +
                  elsif c != EOF
         | 
| 87 | 
            +
                    @column += 1
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                  c
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                # @return [Char, NilClass] nil at EOF
         | 
| 93 | 
            +
                def readc_file
         | 
| 94 | 
            +
                  c = @io.getc
         | 
| 95 | 
            +
                  if c == EOF
         | 
| 96 | 
            +
                    c = (@last == "\n" || @last == EOF) ? nil : "\n"
         | 
| 97 | 
            +
                  elsif c == "\r"
         | 
| 98 | 
            +
                    c2 = @io.getc
         | 
| 99 | 
            +
                    if c2 != "\n"
         | 
| 100 | 
            +
                      @io.ungetc(c2)
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
                    c = "\n"
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
                  @last = c
         | 
| 105 | 
            +
                  c
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            require "forwardable"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rucc
         | 
| 4 | 
            +
              class FileIOList
         | 
| 5 | 
            +
                extend Forwardable
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # @param [FileIO] file
         | 
| 8 | 
            +
                def initialize(file)
         | 
| 9 | 
            +
                  @files = [file]
         | 
| 10 | 
            +
                  @stashed = []  # buffer for stashed files
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                delegate [:push, :first, :last] => :@files
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # @return [FileIO]
         | 
| 15 | 
            +
                def current
         | 
| 16 | 
            +
                  @files.last
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # @return [Char, NilClass]
         | 
| 20 | 
            +
                def readc
         | 
| 21 | 
            +
                  while true
         | 
| 22 | 
            +
                    c = current.readc
         | 
| 23 | 
            +
                    if !c.nil?  # not EOF
         | 
| 24 | 
            +
                      return c
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    if @files.size == 1
         | 
| 28 | 
            +
                      return c
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                    f = @files.pop
         | 
| 31 | 
            +
                    f.close
         | 
| 32 | 
            +
                    next
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                  raise "Must not reach here!"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # @param [Char, NilClass]
         | 
| 38 | 
            +
                def unreadc(c)
         | 
| 39 | 
            +
                  current.unreadc(c)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # @param [<FileIO>] files
         | 
| 43 | 
            +
                def stream_stash(files)
         | 
| 44 | 
            +
                  @stashed.push(@files)
         | 
| 45 | 
            +
                  @files = files
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def stream_unstash
         | 
| 49 | 
            +
                  @files = @stashed.pop
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def stream_depth
         | 
| 53 | 
            +
                  @files.size
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
    
        data/lib/rucc/gen.rb
    ADDED
    
    | @@ -0,0 +1,1602 @@ | |
| 1 | 
            +
            require "rucc/int_evaluator"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rucc
         | 
| 4 | 
            +
              class Gen
         | 
| 5 | 
            +
                REGS  = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"].freeze
         | 
| 6 | 
            +
                SREGS = ["dil", "sil", "dl", "cl", "r8b", "r9b"].freeze
         | 
| 7 | 
            +
                MREGS = ["edi", "esi", "edx", "ecx", "r8d", "r9d"].freeze
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                # @param [IO] output
         | 
| 10 | 
            +
                # @param [LabelGen] label_gen
         | 
| 11 | 
            +
                def initialize(output, label_gen)
         | 
| 12 | 
            +
                  @output    = output
         | 
| 13 | 
            +
                  @label_gen = label_gen
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  @stackpos = nil
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # number of float and int
         | 
| 18 | 
            +
                  @numgp = nil
         | 
| 19 | 
            +
                  @numfp = nil
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # @param [Node] v
         | 
| 23 | 
            +
                def emit_toplevel(v)
         | 
| 24 | 
            +
                  @stackpos = 8
         | 
| 25 | 
            +
                  if v.kind == AST::FUNC
         | 
| 26 | 
            +
                    emit_func_prologue(v)
         | 
| 27 | 
            +
                    emit_expr(v.body)
         | 
| 28 | 
            +
                    emit_ret
         | 
| 29 | 
            +
                  elsif v.kind == AST::DECL
         | 
| 30 | 
            +
                    emit_global_var(v)
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    raise "internal error"
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              private
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # @param [String] fmt
         | 
| 39 | 
            +
                def emit(fmt, *args)
         | 
| 40 | 
            +
                  emit_noindent("\t#{fmt}", *args)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                # @param [String] fmt
         | 
| 44 | 
            +
                def emit_noindent(fmt, *args)
         | 
| 45 | 
            +
                  # Replace "#" with "%%" so that vfprintf prints out "#" as "%".
         | 
| 46 | 
            +
                  @output.printf(fmt.gsub('#', '%%'), *args)
         | 
| 47 | 
            +
                  # TODO(south37) Impl dumpstack when necessary
         | 
| 48 | 
            +
                  # if (dumpstack) {
         | 
| 49 | 
            +
                  #     for (char *p = fmt; *p; p++)
         | 
| 50 | 
            +
                  #         if (*p == '\t')
         | 
| 51 | 
            +
                  #             col += TAB - 1;
         | 
| 52 | 
            +
                  #     int space = (28 - col) > 0 ? (30 - col) : 2;
         | 
| 53 | 
            +
                  #     fprintf(outputfp, "%*c %s:%d", space, '#', get_caller_list(), line);
         | 
| 54 | 
            +
                  # }
         | 
| 55 | 
            +
                  @output.print("\n")
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                # @param [String] label
         | 
| 59 | 
            +
                def emit_label(label)
         | 
| 60 | 
            +
                  emit("#{label}:")
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                # @param [Integer] n
         | 
| 64 | 
            +
                # @param [Integer] m
         | 
| 65 | 
            +
                # @return [Integer]
         | 
| 66 | 
            +
                def align(n, m)
         | 
| 67 | 
            +
                  rem = n % m
         | 
| 68 | 
            +
                  return (rem == 0) ? n : (n - rem + m)
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                # @param [Integer] reg
         | 
| 72 | 
            +
                def push_xmm(reg)
         | 
| 73 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 74 | 
            +
                  # SAVE
         | 
| 75 | 
            +
                  emit("sub $8, #rsp")
         | 
| 76 | 
            +
                  emit("movsd #xmm#{reg}, (#rsp)")
         | 
| 77 | 
            +
                  @stackpos += 8
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                # @param [Integer] reg
         | 
| 81 | 
            +
                def pop_xmm(reg)
         | 
| 82 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 83 | 
            +
                  # SAVE
         | 
| 84 | 
            +
                  emit("movsd (#rsp), #xmm#{reg}")
         | 
| 85 | 
            +
                  emit("add $8, #rsp");
         | 
| 86 | 
            +
                  @stackpos -= 8;
         | 
| 87 | 
            +
                  Util.assert!{ @stackpos >= 0 }
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                # @param [String] reg
         | 
| 91 | 
            +
                def push(reg)
         | 
| 92 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 93 | 
            +
                  # SAVE
         | 
| 94 | 
            +
                  emit("push ##{reg}")
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  @stackpos += 8
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                # @param [String] reg
         | 
| 100 | 
            +
                def pop(reg)
         | 
| 101 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 102 | 
            +
                  # SAVE
         | 
| 103 | 
            +
                  emit("pop ##{reg}")
         | 
| 104 | 
            +
                  @stackpos -= 8
         | 
| 105 | 
            +
                  Util.assert!{ @stackpos >= 0 }
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                # @param [Node] func
         | 
| 109 | 
            +
                def emit_func_prologue(func)
         | 
| 110 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 111 | 
            +
                  # SAVE
         | 
| 112 | 
            +
                  emit(".text");
         | 
| 113 | 
            +
                  if !func.ty.isstatic
         | 
| 114 | 
            +
                    emit_noindent(".global #{func.fname}")
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                  emit_noindent("#{func.fname}:")
         | 
| 117 | 
            +
                  emit("nop")
         | 
| 118 | 
            +
                  push("rbp")
         | 
| 119 | 
            +
                  emit("mov #rsp, #rbp")
         | 
| 120 | 
            +
                  off = 0
         | 
| 121 | 
            +
                  if func.ty.hasva
         | 
| 122 | 
            +
                    set_reg_nums(func.params)
         | 
| 123 | 
            +
                    off -= emit_regsave_area
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                  push_func_params(func.params, off)
         | 
| 126 | 
            +
                  off -= func.params.size * 8
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  localarea = 0
         | 
| 129 | 
            +
                  func.localvars.each do |v|
         | 
| 130 | 
            +
                    size = align(v.ty.size, 8)
         | 
| 131 | 
            +
                    Util.assert!{ size % 8 == 0 }
         | 
| 132 | 
            +
                    off -= size
         | 
| 133 | 
            +
                    v.loff = off
         | 
| 134 | 
            +
                    localarea += size
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                  if localarea > 0
         | 
| 137 | 
            +
                    emit("sub $#{localarea}, #rsp")
         | 
| 138 | 
            +
                    @stackpos += localarea
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                # @param [<Node>] args
         | 
| 143 | 
            +
                def set_reg_nums(args)
         | 
| 144 | 
            +
                  @numgp = @numfp = 0
         | 
| 145 | 
            +
                  args.each do |arg|
         | 
| 146 | 
            +
                    if Type.is_flotype(arg.ty)
         | 
| 147 | 
            +
                      @numfp += 1
         | 
| 148 | 
            +
                    else
         | 
| 149 | 
            +
                      @numgp += 1
         | 
| 150 | 
            +
                    end
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                REGAREA_SIZE = 176
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                # @return [Integer]
         | 
| 157 | 
            +
                def emit_regsave_area
         | 
| 158 | 
            +
                  emit("sub $#{REGAREA_SIZE}, #rsp")
         | 
| 159 | 
            +
                  emit("mov #rdi, (#rsp)")
         | 
| 160 | 
            +
                  emit("mov #rsi, 8(#rsp)")
         | 
| 161 | 
            +
                  emit("mov #rdx, 16(#rsp)")
         | 
| 162 | 
            +
                  emit("mov #rcx, 24(#rsp)")
         | 
| 163 | 
            +
                  emit("mov #r8, 32(#rsp)")
         | 
| 164 | 
            +
                  emit("mov #r9, 40(#rsp)")
         | 
| 165 | 
            +
                  emit("movaps #xmm0, 48(#rsp)")
         | 
| 166 | 
            +
                  emit("movaps #xmm1, 64(#rsp)")
         | 
| 167 | 
            +
                  emit("movaps #xmm2, 80(#rsp)")
         | 
| 168 | 
            +
                  emit("movaps #xmm3, 96(#rsp)")
         | 
| 169 | 
            +
                  emit("movaps #xmm4, 112(#rsp)")
         | 
| 170 | 
            +
                  emit("movaps #xmm5, 128(#rsp)")
         | 
| 171 | 
            +
                  emit("movaps #xmm6, 144(#rsp)")
         | 
| 172 | 
            +
                  emit("movaps #xmm7, 160(#rsp)")
         | 
| 173 | 
            +
                  REGAREA_SIZE
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                # @param [Array] params
         | 
| 177 | 
            +
                # @param [Integer] off
         | 
| 178 | 
            +
                def push_func_params(params, off)
         | 
| 179 | 
            +
                  ireg = 0
         | 
| 180 | 
            +
                  xreg = 0
         | 
| 181 | 
            +
                  arg = 2
         | 
| 182 | 
            +
                  params.each do |v|
         | 
| 183 | 
            +
                    if v.ty.kind == Kind::STRUCT
         | 
| 184 | 
            +
                      emit("lea #{arg * 8}(#rbp), #rax")
         | 
| 185 | 
            +
                      size = push_struct(v.ty.size)
         | 
| 186 | 
            +
                      off -= size
         | 
| 187 | 
            +
                      arg += (size / 8)
         | 
| 188 | 
            +
                    elsif Type.is_flotype(v.ty)
         | 
| 189 | 
            +
                      if xreg >= 8
         | 
| 190 | 
            +
                        emit("mov %d(#rbp), #rax", arg * 8)
         | 
| 191 | 
            +
                        arg += 1
         | 
| 192 | 
            +
                        push("rax")
         | 
| 193 | 
            +
                      else
         | 
| 194 | 
            +
                        push_xmm(xreg)
         | 
| 195 | 
            +
                        xreg += 1
         | 
| 196 | 
            +
                      end
         | 
| 197 | 
            +
                      off -= 8
         | 
| 198 | 
            +
                    else
         | 
| 199 | 
            +
                      if ireg >= 6
         | 
| 200 | 
            +
                        if v.ty.kind == Kind::BOOL
         | 
| 201 | 
            +
                          emit("mov #{arg * 8}(#rbp), #al")
         | 
| 202 | 
            +
                          arg += 1
         | 
| 203 | 
            +
                          emit("movzb #al, #eax")
         | 
| 204 | 
            +
                        else
         | 
| 205 | 
            +
                          emit("mov #{arg * 8}(#rbp), #rax")
         | 
| 206 | 
            +
                          arg += 1
         | 
| 207 | 
            +
                        end
         | 
| 208 | 
            +
                        push("rax")
         | 
| 209 | 
            +
                      else
         | 
| 210 | 
            +
                        if v.ty.kind == Kind::BOOL
         | 
| 211 | 
            +
                          emit("movzb ##{SREGS[ireg]}, ##{MREGS[ireg]}")
         | 
| 212 | 
            +
                        end
         | 
| 213 | 
            +
                        push(REGS[ireg])
         | 
| 214 | 
            +
                        ireg += 1
         | 
| 215 | 
            +
                      end
         | 
| 216 | 
            +
                      off -= 8
         | 
| 217 | 
            +
                    end
         | 
| 218 | 
            +
                    v.loff = off
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
                end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                # @param [Integer] size
         | 
| 223 | 
            +
                # @return [Integer]
         | 
| 224 | 
            +
                def push_struct(size)
         | 
| 225 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 226 | 
            +
                  # SAVE;
         | 
| 227 | 
            +
                  aligned = align(size, 8)
         | 
| 228 | 
            +
                  emit("sub $#{aligned}, #rsp")
         | 
| 229 | 
            +
                  emit("mov #rcx, -8(#rsp)")
         | 
| 230 | 
            +
                  emit("mov #r11, -16(#rsp)")
         | 
| 231 | 
            +
                  emit("mov #rax, #rcx")
         | 
| 232 | 
            +
                  i = 0
         | 
| 233 | 
            +
                  while i < size
         | 
| 234 | 
            +
                    emit("movq #{i}(#rcx), #r11")
         | 
| 235 | 
            +
                    emit("mov #r11, #{i}(#rsp)")
         | 
| 236 | 
            +
                    i += 8
         | 
| 237 | 
            +
                  end
         | 
| 238 | 
            +
                  while i < size
         | 
| 239 | 
            +
                    emit("movl #{i}(#rcx), #r11")
         | 
| 240 | 
            +
                    emit("movl #r11d, #{i}(#rsp)")
         | 
| 241 | 
            +
                    i += 4
         | 
| 242 | 
            +
                  end
         | 
| 243 | 
            +
                  while i < size
         | 
| 244 | 
            +
                    emit("movb %d(#rcx), #r11", i)
         | 
| 245 | 
            +
                    emit("movb #r11b, %d(#rsp)", i)
         | 
| 246 | 
            +
                    i += 1
         | 
| 247 | 
            +
                  end
         | 
| 248 | 
            +
                  emit("mov -8(#rsp), #rcx")
         | 
| 249 | 
            +
                  emit("mov -16(#rsp), #r11")
         | 
| 250 | 
            +
                  @stackpos += aligned
         | 
| 251 | 
            +
                  aligned
         | 
| 252 | 
            +
                end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                # @param [Node] node
         | 
| 255 | 
            +
                def emit_expr(node)
         | 
| 256 | 
            +
                  # TODO(south37) Impl SAVE when necessary
         | 
| 257 | 
            +
                  # SAVE
         | 
| 258 | 
            +
                  # maybe_print_source_loc(node)
         | 
| 259 | 
            +
                  case node.kind
         | 
| 260 | 
            +
                  when AST::LITERAL          then emit_literal(node)
         | 
| 261 | 
            +
                  when AST::LVAR             then emit_lvar(node)
         | 
| 262 | 
            +
                  when AST::GVAR             then emit_gvar(node)
         | 
| 263 | 
            +
                  when AST::FUNCDESG         then emit_addr(node)
         | 
| 264 | 
            +
                  when AST::FUNCALL
         | 
| 265 | 
            +
                    return if maybe_emit_builtin(node)
         | 
| 266 | 
            +
                    emit_func_call(node)
         | 
| 267 | 
            +
                  when AST::FUNCPTR_CALL     then emit_func_call(node)
         | 
| 268 | 
            +
                  when AST::DECL             then emit_decl(node)
         | 
| 269 | 
            +
                  when AST::CONV             then emit_conv(node)
         | 
| 270 | 
            +
                  when AST::ADDR             then emit_addr(node.operand)
         | 
| 271 | 
            +
                  when AST::DEREF            then emit_deref(node)
         | 
| 272 | 
            +
                  when AST::IF, AST::TERNARY then emit_ternary(node)
         | 
| 273 | 
            +
                  when AST::GOTO             then emit_goto(node)
         | 
| 274 | 
            +
                  when AST::LABEL            then (emit_label(node.newlabel) if node.newlabel)
         | 
| 275 | 
            +
                  when AST::RETURN           then emit_return(node)
         | 
| 276 | 
            +
                  when AST::COMPOUND_STMT    then emit_compound_stmt(node)
         | 
| 277 | 
            +
                  when AST::STRUCT_REF       then emit_load_struct_ref(node.struct, node.ty, 0)
         | 
| 278 | 
            +
                  when OP::PRE_INC           then emit_pre_inc_dec(node, "add")
         | 
| 279 | 
            +
                  when OP::PRE_DEC           then emit_pre_inc_dec(node, "sub")
         | 
| 280 | 
            +
                  when OP::POST_INC          then emit_post_inc_dec(node, "add")
         | 
| 281 | 
            +
                  when OP::POST_DEC          then emit_post_inc_dec(node, "sub")
         | 
| 282 | 
            +
                  when '!'                   then emit_lognot(node)
         | 
| 283 | 
            +
                  when '&'                   then emit_bitand(node)
         | 
| 284 | 
            +
                  when '|'                   then emit_bitor(node)
         | 
| 285 | 
            +
                  when '~'                   then emit_bitnot(node)
         | 
| 286 | 
            +
                  when OP::LOGAND            then emit_logand(node)
         | 
| 287 | 
            +
                  when OP::LOGOR             then emit_logor(node)
         | 
| 288 | 
            +
                  when OP::CAST              then emit_cast(node)
         | 
| 289 | 
            +
                  when ','                   then emit_comma(node)
         | 
| 290 | 
            +
                  when '='                   then emit_assign(node)
         | 
| 291 | 
            +
                  when OP::LABEL_ADDR        then emit_label_addr(node)
         | 
| 292 | 
            +
                  when AST::COMPUTED_GOTO    then emit_computed_goto(node)
         | 
| 293 | 
            +
                  else                            emit_binop(node)
         | 
| 294 | 
            +
                  end
         | 
| 295 | 
            +
                end
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                # @param [Node] node
         | 
| 298 | 
            +
                def emit_literal(node)
         | 
| 299 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 300 | 
            +
                  # SAVE
         | 
| 301 | 
            +
                  case node.ty.kind
         | 
| 302 | 
            +
                  when Kind::BOOL, Kind::CHAR, Kind::SHORT
         | 
| 303 | 
            +
                    emit("mov $%u, #rax" % node.ival)
         | 
| 304 | 
            +
                  when Kind::INT
         | 
| 305 | 
            +
                    emit("mov $%u, #rax" % node.ival)
         | 
| 306 | 
            +
                  when Kind::LONG, Kind::LLONG
         | 
| 307 | 
            +
                    emit("mov $%u, #rax" % node.ival)
         | 
| 308 | 
            +
                  when Kind::FLOAT
         | 
| 309 | 
            +
                    if !node.flabel
         | 
| 310 | 
            +
                      node.flabel = @label_gen.next
         | 
| 311 | 
            +
                      emit_noindent(".data")
         | 
| 312 | 
            +
                      emit_label(node.flabel)
         | 
| 313 | 
            +
                      emit(".long #{[node.fval].pack('f').unpack('I')[0]}")
         | 
| 314 | 
            +
                      emit_noindent(".text")
         | 
| 315 | 
            +
                    end
         | 
| 316 | 
            +
                    emit("movss #{node.flabel}(#rip), #xmm0")
         | 
| 317 | 
            +
                  when Kind::DOUBLE, Kind::LDOUBLE
         | 
| 318 | 
            +
                    if !node.flabel
         | 
| 319 | 
            +
                      node.flabel = @label_gen.next
         | 
| 320 | 
            +
                      emit_noindent(".data")
         | 
| 321 | 
            +
                      emit_label(node.flabel)
         | 
| 322 | 
            +
                      emit(".quad #{[node.fval].pack('d').unpack('Q')[0]}")
         | 
| 323 | 
            +
                      emit_noindent(".text")
         | 
| 324 | 
            +
                    end
         | 
| 325 | 
            +
                    emit("movsd #{node.flabel}(#rip), #xmm0")
         | 
| 326 | 
            +
                  when Kind::ARRAY
         | 
| 327 | 
            +
                    if !node.slabel
         | 
| 328 | 
            +
                      node.slabel = @label_gen.next
         | 
| 329 | 
            +
                      emit_noindent(".data")
         | 
| 330 | 
            +
                      emit_label(node.slabel)
         | 
| 331 | 
            +
                      emit(".string \"%s\"", Util.quote_cstring(node.sval))
         | 
| 332 | 
            +
                      emit_noindent(".text")
         | 
| 333 | 
            +
                    end
         | 
| 334 | 
            +
                    emit("lea #{node.slabel}(#rip), #rax")
         | 
| 335 | 
            +
                  else
         | 
| 336 | 
            +
                    raise "internal error"
         | 
| 337 | 
            +
                  end
         | 
| 338 | 
            +
                end
         | 
| 339 | 
            +
             | 
| 340 | 
            +
                # @param [Node] node
         | 
| 341 | 
            +
                def emit_lvar(node)
         | 
| 342 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 343 | 
            +
                  # SAVE;
         | 
| 344 | 
            +
                  ensure_lvar_init(node)
         | 
| 345 | 
            +
                  emit_lload(node.ty, "rbp", node.loff)
         | 
| 346 | 
            +
                end
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                # @param [Node] node
         | 
| 349 | 
            +
                def emit_gvar(node)
         | 
| 350 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 351 | 
            +
                  # SAVE;
         | 
| 352 | 
            +
                  emit_gload(node.ty, node.glabel, 0)
         | 
| 353 | 
            +
                end
         | 
| 354 | 
            +
             | 
| 355 | 
            +
                # @param [Type] ty
         | 
| 356 | 
            +
                # @param [String] label
         | 
| 357 | 
            +
                # @param [Integer] off
         | 
| 358 | 
            +
                def emit_gload(ty, label, off)
         | 
| 359 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 360 | 
            +
                  # SAVE;
         | 
| 361 | 
            +
                  if ty.kind == Kind::ARRAY
         | 
| 362 | 
            +
                    if off > 0
         | 
| 363 | 
            +
                      emit("lea %s+#{off}(#rip), #rax", label)
         | 
| 364 | 
            +
                    else
         | 
| 365 | 
            +
                      emit("lea %s(#rip), #rax", label)
         | 
| 366 | 
            +
                    end
         | 
| 367 | 
            +
                    return
         | 
| 368 | 
            +
                  end
         | 
| 369 | 
            +
                  inst = get_load_inst(ty)
         | 
| 370 | 
            +
                  emit("#{inst} %s+#{off}(#rip), #rax", label)
         | 
| 371 | 
            +
                  maybe_emit_bitshift_load(ty)
         | 
| 372 | 
            +
                end
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                # @param [Node] v
         | 
| 375 | 
            +
                def emit_global_var(v)
         | 
| 376 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 377 | 
            +
                  # SAVE;
         | 
| 378 | 
            +
                  if v.declinit
         | 
| 379 | 
            +
                    emit_data(v, 0, 0)
         | 
| 380 | 
            +
                  else
         | 
| 381 | 
            +
                    emit_bss(v)
         | 
| 382 | 
            +
                  end
         | 
| 383 | 
            +
                end
         | 
| 384 | 
            +
             | 
| 385 | 
            +
                # @param [Node] v
         | 
| 386 | 
            +
                # @param [Integer] off
         | 
| 387 | 
            +
                # @param [Integer] depth
         | 
| 388 | 
            +
                def emit_data(v, off, depth)
         | 
| 389 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 390 | 
            +
                  # SAVE;
         | 
| 391 | 
            +
                  emit(".data #{depth}")
         | 
| 392 | 
            +
                  if !v.declvar.ty.isstatic
         | 
| 393 | 
            +
                    emit_noindent(".global #{v.declvar.glabel}")
         | 
| 394 | 
            +
                  end
         | 
| 395 | 
            +
                  emit_noindent("#{v.declvar.glabel}:")
         | 
| 396 | 
            +
                  do_emit_data(v.declinit, v.declvar.ty.size, off, depth)
         | 
| 397 | 
            +
                end
         | 
| 398 | 
            +
             | 
| 399 | 
            +
                # @param [Array] inits
         | 
| 400 | 
            +
                # @param [Integer] size
         | 
| 401 | 
            +
                # @param [Integer] off
         | 
| 402 | 
            +
                # @param [Integer] depth
         | 
| 403 | 
            +
                def do_emit_data(inits, size, off, depth)
         | 
| 404 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 405 | 
            +
                  # SAVE;
         | 
| 406 | 
            +
                  i = 0
         | 
| 407 | 
            +
                  while (i < inits.size && 0 < size)
         | 
| 408 | 
            +
                    node = inits[i]
         | 
| 409 | 
            +
                    v = node.initval
         | 
| 410 | 
            +
                    emit_padding(node, off)
         | 
| 411 | 
            +
                    if node.totype.bitsize && (node.totype.bitsize > 0)
         | 
| 412 | 
            +
                      Util.assert!{ node.totype.bitoff == 0 }
         | 
| 413 | 
            +
                      data = IntEvaluator.eval(v).first
         | 
| 414 | 
            +
                      totype = node.totype
         | 
| 415 | 
            +
                      while (i < inits.size)
         | 
| 416 | 
            +
                        node = inits[i]
         | 
| 417 | 
            +
                        if node.totype.bitsize.nil? || (node.totype.bitsize <= 0)
         | 
| 418 | 
            +
                          break
         | 
| 419 | 
            +
                        end
         | 
| 420 | 
            +
                        v = node.initval
         | 
| 421 | 
            +
                        totype = node.totype
         | 
| 422 | 
            +
                        data |= (((1 << totype.bitsize) - 1) & IntEvaluator.eval(v).first) << totype.bitoff
         | 
| 423 | 
            +
                        i += 1
         | 
| 424 | 
            +
                      end
         | 
| 425 | 
            +
                      emit_data_primtype(totype, Node.new(AST::LITERAL, ty: totype, ival: data), depth)
         | 
| 426 | 
            +
                      off += totype.size
         | 
| 427 | 
            +
                      size -= totype.size
         | 
| 428 | 
            +
                      break if i == inits.size
         | 
| 429 | 
            +
                    else
         | 
| 430 | 
            +
                      off += node.totype.size
         | 
| 431 | 
            +
                      size -= node.totype.size
         | 
| 432 | 
            +
                    end
         | 
| 433 | 
            +
                    if v.kind == AST::ADDR
         | 
| 434 | 
            +
                      emit_data_addr(v.operand, depth)
         | 
| 435 | 
            +
                      i += 1
         | 
| 436 | 
            +
                      next
         | 
| 437 | 
            +
                    end
         | 
| 438 | 
            +
                    if (v.kind == AST::LVAR) && v.lvarinit
         | 
| 439 | 
            +
                      do_emit_data(v.lvarinit, v.ty.size, 0, depth)
         | 
| 440 | 
            +
                      i += 1
         | 
| 441 | 
            +
                      next
         | 
| 442 | 
            +
                    end
         | 
| 443 | 
            +
                    emit_data_primtype(node.totype, node.initval, depth)
         | 
| 444 | 
            +
                    i += 1
         | 
| 445 | 
            +
                  end
         | 
| 446 | 
            +
                  emit_zero(size)
         | 
| 447 | 
            +
                end
         | 
| 448 | 
            +
             | 
| 449 | 
            +
                # @param [Node] node
         | 
| 450 | 
            +
                # @param [Intyeger] off
         | 
| 451 | 
            +
                def emit_padding(node, off)
         | 
| 452 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 453 | 
            +
                  # SAVE;
         | 
| 454 | 
            +
                  diff = node.initoff - off
         | 
| 455 | 
            +
                  Util.assert!{ diff >= 0 }
         | 
| 456 | 
            +
                  emit_zero(diff)
         | 
| 457 | 
            +
                end
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                # @param [Integer] size
         | 
| 460 | 
            +
                def emit_zero(size)
         | 
| 461 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 462 | 
            +
                  # SAVE;
         | 
| 463 | 
            +
                  while (size >= 8) do
         | 
| 464 | 
            +
                    emit(".quad 0")
         | 
| 465 | 
            +
                    size -= 8
         | 
| 466 | 
            +
                  end
         | 
| 467 | 
            +
                  while (size >= 4) do
         | 
| 468 | 
            +
                    emit(".long 0")
         | 
| 469 | 
            +
                    size -= 4
         | 
| 470 | 
            +
                  end
         | 
| 471 | 
            +
                  while (size > 0) do
         | 
| 472 | 
            +
                    emit(".byte 0")
         | 
| 473 | 
            +
                    size -= 1
         | 
| 474 | 
            +
                  end
         | 
| 475 | 
            +
                end
         | 
| 476 | 
            +
             | 
| 477 | 
            +
                # @param [Type] ty
         | 
| 478 | 
            +
                # @param [Node] val
         | 
| 479 | 
            +
                # @param [Integer] depth
         | 
| 480 | 
            +
                def emit_data_primtype(ty, val, depth)
         | 
| 481 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 482 | 
            +
                  # SAVE;
         | 
| 483 | 
            +
                  case ty.kind
         | 
| 484 | 
            +
                  when Kind::FLOAT
         | 
| 485 | 
            +
                    emit(".long #{[val.fval].pack('f').unpack('I')[0]}")
         | 
| 486 | 
            +
                  when Kind::DOUBLE
         | 
| 487 | 
            +
                    emit(".quad #{[node.fval].pack('d').unpack('Q')[0]}")
         | 
| 488 | 
            +
                  when Kind::BOOL
         | 
| 489 | 
            +
                    emit(".byte #{IntEvaluator.eval(val).first > 0 ? 1 : 0}")
         | 
| 490 | 
            +
                  when Kind::CHAR
         | 
| 491 | 
            +
                    emit(".byte #{IntEvaluator.eval(val).first}")
         | 
| 492 | 
            +
                  when Kind::SHORT
         | 
| 493 | 
            +
                    emit(".short #{IntEvaluator.eval(val).first}")
         | 
| 494 | 
            +
                  when Kind::INT
         | 
| 495 | 
            +
                    emit(".long #{IntEvaluator.eval(val).first}")
         | 
| 496 | 
            +
                  when Kind::LONG, Kind::LLONG, Kind::PTR
         | 
| 497 | 
            +
                    if val.kind == OP::LABEL_ADDR
         | 
| 498 | 
            +
                      emit(".quad #{val.newlabel}")
         | 
| 499 | 
            +
                      return
         | 
| 500 | 
            +
                    end
         | 
| 501 | 
            +
             | 
| 502 | 
            +
                    is_char_ptr = val.operand && (val.operand.ty.kind == Kind::ARRAY && val.operand.ty.ptr.kind == Kind::CHAR)
         | 
| 503 | 
            +
                    if is_char_ptr
         | 
| 504 | 
            +
                      emit_data_charptr(val.operand.sval, depth)
         | 
| 505 | 
            +
                    elsif val.kind == AST::GVAR
         | 
| 506 | 
            +
                      emit(".quad #{val.glabel}")
         | 
| 507 | 
            +
                    else
         | 
| 508 | 
            +
                      v, base = IntEvaluator.eval(val)
         | 
| 509 | 
            +
                      if !base
         | 
| 510 | 
            +
                        emit(".quad %u", v)
         | 
| 511 | 
            +
                        return
         | 
| 512 | 
            +
                      end
         | 
| 513 | 
            +
                      ty = base.ty
         | 
| 514 | 
            +
                      if (base.kind == AST::CONV) || (base.kind == AST::ADDR)
         | 
| 515 | 
            +
                        base = base.operand
         | 
| 516 | 
            +
                      end
         | 
| 517 | 
            +
                      if base.kind != AST::GVAR
         | 
| 518 | 
            +
                        raise "global variable expected, but got #{base}"
         | 
| 519 | 
            +
                      end
         | 
| 520 | 
            +
                      Util.assert!{ !ty.ptr.nil? }
         | 
| 521 | 
            +
                      emit(".quad #{base.glabel}+#{v * ty.ptr.size}")
         | 
| 522 | 
            +
                    end
         | 
| 523 | 
            +
                  else
         | 
| 524 | 
            +
                    raise "don't know how to handle\n  <#{ty}>\n  <#{val}>"
         | 
| 525 | 
            +
                  end
         | 
| 526 | 
            +
                end
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                # @param [Node] operand
         | 
| 529 | 
            +
                # @param [Integer] depth
         | 
| 530 | 
            +
                def emit_data_addr(operand, depth)
         | 
| 531 | 
            +
                  case operand.kind
         | 
| 532 | 
            +
                  when AST::LVAR
         | 
| 533 | 
            +
                    label = @label_gen.next
         | 
| 534 | 
            +
                    emit(".data %d", depth + 1)
         | 
| 535 | 
            +
                    emit_label(label)
         | 
| 536 | 
            +
                    do_emit_data(operand.lvarinit, operand.ty.size, 0, depth + 1)
         | 
| 537 | 
            +
                    emit(".data #{depth}")
         | 
| 538 | 
            +
                    emit(".quad #{label}")
         | 
| 539 | 
            +
                    return
         | 
| 540 | 
            +
                  when AST::GVAR
         | 
| 541 | 
            +
                    emit(".quad #{operand.glabel}")
         | 
| 542 | 
            +
                    return
         | 
| 543 | 
            +
                  else
         | 
| 544 | 
            +
                    raise "internal error"
         | 
| 545 | 
            +
                    # error("internal error");
         | 
| 546 | 
            +
                  end
         | 
| 547 | 
            +
                end
         | 
| 548 | 
            +
             | 
| 549 | 
            +
                # @param [String] s
         | 
| 550 | 
            +
                # @param [Integer] depth
         | 
| 551 | 
            +
                def emit_data_charptr(s, depth)
         | 
| 552 | 
            +
                  label = @label_gen.next
         | 
| 553 | 
            +
                  emit(".data #{depth + 1}")
         | 
| 554 | 
            +
                  emit_label(label)
         | 
| 555 | 
            +
                  emit(".string \"#{Util.quote_cstring(s)}\"")
         | 
| 556 | 
            +
                  emit(".data #{depth}")
         | 
| 557 | 
            +
                  emit(".quad #{label}")
         | 
| 558 | 
            +
                end
         | 
| 559 | 
            +
             | 
| 560 | 
            +
                # @param [Node] v
         | 
| 561 | 
            +
                def emit_bss(v)
         | 
| 562 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 563 | 
            +
                  # SAVE
         | 
| 564 | 
            +
                  emit(".data")
         | 
| 565 | 
            +
                  if !v.declvar.ty.isstatic
         | 
| 566 | 
            +
                    emit(".global #{v.declvar.glabel}")
         | 
| 567 | 
            +
                  end
         | 
| 568 | 
            +
                  emit(".lcomm #{v.declvar.glabel}, #{v.declvar.ty.size}")
         | 
| 569 | 
            +
                end
         | 
| 570 | 
            +
             | 
| 571 | 
            +
                # @param [Node] node
         | 
| 572 | 
            +
                def emit_conv(node)
         | 
| 573 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 574 | 
            +
                  # SAVE
         | 
| 575 | 
            +
                  emit_expr(node.operand)
         | 
| 576 | 
            +
                  emit_load_convert(node.ty, node.operand.ty)
         | 
| 577 | 
            +
                end
         | 
| 578 | 
            +
             | 
| 579 | 
            +
                # @param [Type] to
         | 
| 580 | 
            +
                # @param [Type] from
         | 
| 581 | 
            +
                def emit_load_convert(to, from)
         | 
| 582 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 583 | 
            +
                  # SAVE
         | 
| 584 | 
            +
                  if Type.is_inttype(from) && to.kind == Kind::FLOAT
         | 
| 585 | 
            +
                    emit("cvtsi2ss #eax, #xmm0")
         | 
| 586 | 
            +
                  elsif Type.is_inttype(from) && to.kind == Kind::DOUBLE
         | 
| 587 | 
            +
                    emit("cvtsi2sd #eax, #xmm0")
         | 
| 588 | 
            +
                  elsif from.kind == Kind::FLOAT && to.kind == Kind::DOUBLE
         | 
| 589 | 
            +
                    emit("cvtps2pd #xmm0, #xmm0")
         | 
| 590 | 
            +
                  elsif (from.kind == Kind::DOUBLE || from.kind == Kind::LDOUBLE) && (to.kind == Kind::FLOAT)
         | 
| 591 | 
            +
                    emit("cvtpd2ps #xmm0, #xmm0")
         | 
| 592 | 
            +
                  elsif to.kind == Kind::BOOL
         | 
| 593 | 
            +
                    emit_to_bool(from)
         | 
| 594 | 
            +
                  elsif Type.is_inttype(from) && Type.is_inttype(to)
         | 
| 595 | 
            +
                    emit_intcast(from)
         | 
| 596 | 
            +
                  elsif Type.is_inttype(to)
         | 
| 597 | 
            +
                    emit_toint(from)
         | 
| 598 | 
            +
                  end
         | 
| 599 | 
            +
                end
         | 
| 600 | 
            +
             | 
| 601 | 
            +
                # @param [Type] ty
         | 
| 602 | 
            +
                def emit_intcast(ty)
         | 
| 603 | 
            +
                  case ty.kind
         | 
| 604 | 
            +
                  when Kind::BOOL, Kind::CHAR
         | 
| 605 | 
            +
                    ty.usig ? emit("movzbq #al, #rax") : emit("movsbq #al, #rax")
         | 
| 606 | 
            +
                  when Kind::SHORT
         | 
| 607 | 
            +
                    ty.usig ? emit("movzwq #ax, #rax") : emit("movswq #ax, #rax")
         | 
| 608 | 
            +
                  when Kind::INT
         | 
| 609 | 
            +
                    # cf. https://web.stanford.edu/class/cs107/guide/x86-64.html
         | 
| 610 | 
            +
                    ty.usig ? emit("mov #eax, #eax") : emit("cltq");
         | 
| 611 | 
            +
                  when Kind::LONG, Kind::LLONG
         | 
| 612 | 
            +
                    # Do nothing
         | 
| 613 | 
            +
                  end
         | 
| 614 | 
            +
                end
         | 
| 615 | 
            +
             | 
| 616 | 
            +
                # @param [Type] ty
         | 
| 617 | 
            +
                def emit_to_bool(ty)
         | 
| 618 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 619 | 
            +
                  # SAVE;
         | 
| 620 | 
            +
                  if Type.is_flotype(ty)
         | 
| 621 | 
            +
                    push_xmm(1)
         | 
| 622 | 
            +
                    emit("xorpd #xmm1, #xmm1")
         | 
| 623 | 
            +
                    emit("%s #xmm1, #xmm0", (ty.kind == Kind::FLOAT) ? "ucomiss" : "ucomisd")
         | 
| 624 | 
            +
                    emit("setne #al")
         | 
| 625 | 
            +
                    pop_xmm(1)
         | 
| 626 | 
            +
                  else
         | 
| 627 | 
            +
                    emit("cmp $0, #rax")
         | 
| 628 | 
            +
                    emit("setne #al")
         | 
| 629 | 
            +
                  end
         | 
| 630 | 
            +
                  emit("movzb #al, #eax")
         | 
| 631 | 
            +
                end
         | 
| 632 | 
            +
             | 
| 633 | 
            +
                # @param [Type] ty
         | 
| 634 | 
            +
                def emit_toint(ty)
         | 
| 635 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 636 | 
            +
                  # SAVE
         | 
| 637 | 
            +
                  if ty.kind == Kind::FLOAT
         | 
| 638 | 
            +
                    emit("cvttss2si #xmm0, #eax")
         | 
| 639 | 
            +
                  elsif ty.kind == Kind::DOUBLE
         | 
| 640 | 
            +
                    emit("cvttsd2si #xmm0, #eax")
         | 
| 641 | 
            +
                  end
         | 
| 642 | 
            +
                end
         | 
| 643 | 
            +
             | 
| 644 | 
            +
                # @param [Node] node
         | 
| 645 | 
            +
                def emit_return(node)
         | 
| 646 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 647 | 
            +
                  # SAVE
         | 
| 648 | 
            +
                  if node.retval
         | 
| 649 | 
            +
                    emit_expr(node.retval)
         | 
| 650 | 
            +
                    maybe_booleanize_retval(node.retval.ty)
         | 
| 651 | 
            +
                  end
         | 
| 652 | 
            +
                  emit_ret
         | 
| 653 | 
            +
                end
         | 
| 654 | 
            +
             | 
| 655 | 
            +
                # @param [Type] ty
         | 
| 656 | 
            +
                def maybe_booleanize_retval(ty)
         | 
| 657 | 
            +
                  if ty.kind == Kind::BOOL
         | 
| 658 | 
            +
                    emit("movzx #al, #rax")
         | 
| 659 | 
            +
                  end
         | 
| 660 | 
            +
                end
         | 
| 661 | 
            +
             | 
| 662 | 
            +
                def emit_ret
         | 
| 663 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 664 | 
            +
                  # SAVE
         | 
| 665 | 
            +
                  emit("leave")
         | 
| 666 | 
            +
                  emit("ret")
         | 
| 667 | 
            +
                end
         | 
| 668 | 
            +
             | 
| 669 | 
            +
                # @param [Node] node
         | 
| 670 | 
            +
                def emit_compound_stmt(node)
         | 
| 671 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 672 | 
            +
                  # SAVE
         | 
| 673 | 
            +
                  node.stmts.each do |stmt|
         | 
| 674 | 
            +
                    emit_expr(stmt)
         | 
| 675 | 
            +
                  end
         | 
| 676 | 
            +
                end
         | 
| 677 | 
            +
             | 
| 678 | 
            +
                # @param [Node] node
         | 
| 679 | 
            +
                def emit_computed_goto(node)
         | 
| 680 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 681 | 
            +
                  # SAVE;
         | 
| 682 | 
            +
                  emit_expr(node.operand)
         | 
| 683 | 
            +
                  emit("jmp *#rax")
         | 
| 684 | 
            +
                end
         | 
| 685 | 
            +
             | 
| 686 | 
            +
                # @param [Node]
         | 
| 687 | 
            +
                def emit_binop(node)
         | 
| 688 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 689 | 
            +
                  # SAVE
         | 
| 690 | 
            +
                  if node.ty.kind == Kind::PTR
         | 
| 691 | 
            +
                    emit_pointer_arith(node.kind, node.left, node.right)
         | 
| 692 | 
            +
                    return
         | 
| 693 | 
            +
                  end
         | 
| 694 | 
            +
             | 
| 695 | 
            +
                  case node.kind
         | 
| 696 | 
            +
                  when '<'    then emit_comp("setl", "setb", node); return
         | 
| 697 | 
            +
                  when OP::EQ then emit_comp("sete", "sete", node); return
         | 
| 698 | 
            +
                  when OP::LE then emit_comp("setle", "setna", node); return
         | 
| 699 | 
            +
                  when OP::NE then emit_comp("setne", "setne", node); return
         | 
| 700 | 
            +
                  end
         | 
| 701 | 
            +
             | 
| 702 | 
            +
                  if Type.is_inttype(node.ty)
         | 
| 703 | 
            +
                    emit_binop_int_arith(node)
         | 
| 704 | 
            +
                  elsif Type.is_flotype(node.ty)
         | 
| 705 | 
            +
                    emit_binop_float_arith(node)
         | 
| 706 | 
            +
                  else
         | 
| 707 | 
            +
                    raise "internal error: #{node}"
         | 
| 708 | 
            +
                  end
         | 
| 709 | 
            +
                end
         | 
| 710 | 
            +
             | 
| 711 | 
            +
                # @param [AST] kind
         | 
| 712 | 
            +
                # @param [Node] left
         | 
| 713 | 
            +
                # @param [Node] right
         | 
| 714 | 
            +
                def emit_pointer_arith(kind, left, right)
         | 
| 715 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 716 | 
            +
                  # SAVE
         | 
| 717 | 
            +
                  emit_expr(left)
         | 
| 718 | 
            +
                  push("rcx")
         | 
| 719 | 
            +
                  push("rax")
         | 
| 720 | 
            +
                  emit_expr(right)
         | 
| 721 | 
            +
                  size = left.ty.ptr.size
         | 
| 722 | 
            +
                  if size > 1
         | 
| 723 | 
            +
                    emit("imul $#{size}, #rax")
         | 
| 724 | 
            +
                  end
         | 
| 725 | 
            +
                  emit("mov #rax, #rcx")
         | 
| 726 | 
            +
                  pop("rax")
         | 
| 727 | 
            +
                  case kind
         | 
| 728 | 
            +
                  when '+' then emit("add #rcx, #rax")
         | 
| 729 | 
            +
                  when '-' then emit("sub #rcx, #rax")
         | 
| 730 | 
            +
                  else
         | 
| 731 | 
            +
                    raise "invalid operator '#{kind}'"
         | 
| 732 | 
            +
                    # error("invalid operator '%d'", kind)
         | 
| 733 | 
            +
                  end
         | 
| 734 | 
            +
                  pop("rcx")
         | 
| 735 | 
            +
                end
         | 
| 736 | 
            +
             | 
| 737 | 
            +
                # @param [Node] node
         | 
| 738 | 
            +
                def emit_binop_int_arith(node)
         | 
| 739 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 740 | 
            +
                  # SAVE
         | 
| 741 | 
            +
                  case node.kind
         | 
| 742 | 
            +
                  when '+'     then op = "add"
         | 
| 743 | 
            +
                  when '-'     then op = "sub"
         | 
| 744 | 
            +
                  when '*'     then op = "imul"
         | 
| 745 | 
            +
                  when '^'     then op = "xor"
         | 
| 746 | 
            +
                  when OP::SAL then op = "sal"
         | 
| 747 | 
            +
                  when OP::SAR then op = "sar"
         | 
| 748 | 
            +
                  when OP::SHR then op = "shr"
         | 
| 749 | 
            +
                  when '/', '%'
         | 
| 750 | 
            +
                    # Do nothing
         | 
| 751 | 
            +
                  else
         | 
| 752 | 
            +
                    raise "invalid operator '#{node.kind}'"
         | 
| 753 | 
            +
                  end
         | 
| 754 | 
            +
             | 
| 755 | 
            +
                  emit_expr(node.left)
         | 
| 756 | 
            +
                  push("rax")
         | 
| 757 | 
            +
                  emit_expr(node.right)
         | 
| 758 | 
            +
                  emit("mov #rax, #rcx")
         | 
| 759 | 
            +
                  pop("rax")
         | 
| 760 | 
            +
             | 
| 761 | 
            +
                  if (node.kind == '/') || (node.kind == '%')
         | 
| 762 | 
            +
                    if node.ty.usig
         | 
| 763 | 
            +
                      emit("xor #edx, #edx");
         | 
| 764 | 
            +
                      emit("div #rcx");
         | 
| 765 | 
            +
                    else
         | 
| 766 | 
            +
                      emit("cqto");
         | 
| 767 | 
            +
                      emit("idiv #rcx")
         | 
| 768 | 
            +
                    end
         | 
| 769 | 
            +
                    if node.kind == '%'
         | 
| 770 | 
            +
                      emit("mov #edx, #eax")
         | 
| 771 | 
            +
                    end
         | 
| 772 | 
            +
                  elsif (node.kind == OP::SAL) || (node.kind == OP::SAR) || (node.kind == OP::SHR)
         | 
| 773 | 
            +
                    emit("#{op} #cl, ##{get_int_reg(node.left.ty, 'a')}")
         | 
| 774 | 
            +
                  else
         | 
| 775 | 
            +
                    emit("#{op} #rcx, #rax")
         | 
| 776 | 
            +
                  end
         | 
| 777 | 
            +
                end
         | 
| 778 | 
            +
             | 
| 779 | 
            +
                # @param [Node] node
         | 
| 780 | 
            +
                def emit_binop_float_arith(node)
         | 
| 781 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 782 | 
            +
                  # SAVE
         | 
| 783 | 
            +
                  isdouble = node.ty.kind == Kind::DOUBLE
         | 
| 784 | 
            +
                  case node.kind
         | 
| 785 | 
            +
                  when '+' then op = (isdouble ? "addsd" : "addss")
         | 
| 786 | 
            +
                  when '-' then op = (isdouble ? "subsd" : "subss")
         | 
| 787 | 
            +
                  when '*' then op = (isdouble ? "mulsd" : "mulss")
         | 
| 788 | 
            +
                  when '/' then op = (isdouble ? "divsd" : "divss")
         | 
| 789 | 
            +
                  else
         | 
| 790 | 
            +
                    raise "invalid operator '#{node.kind}'"
         | 
| 791 | 
            +
                  end
         | 
| 792 | 
            +
             | 
| 793 | 
            +
                  emit_expr(node.left)
         | 
| 794 | 
            +
                  push_xmm(0)
         | 
| 795 | 
            +
                  emit_expr(node.right)
         | 
| 796 | 
            +
                  emit("#{(isdouble ? "movsd" : "movss")} #xmm0, #xmm1")
         | 
| 797 | 
            +
                  pop_xmm(0);
         | 
| 798 | 
            +
                  emit("#{op} #xmm1, #xmm0")
         | 
| 799 | 
            +
                end
         | 
| 800 | 
            +
             | 
| 801 | 
            +
                # @param [Node] node
         | 
| 802 | 
            +
                def emit_decl(node)
         | 
| 803 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 804 | 
            +
                  # SAVE;
         | 
| 805 | 
            +
                  return if (!node.declinit)
         | 
| 806 | 
            +
                  emit_decl_init(node.declinit, node.declvar.loff, node.declvar.ty.size)
         | 
| 807 | 
            +
                end
         | 
| 808 | 
            +
             | 
| 809 | 
            +
                # @param [Array] inits
         | 
| 810 | 
            +
                # @param [Integer] off
         | 
| 811 | 
            +
                # @param [Integer] totalsize
         | 
| 812 | 
            +
                def emit_decl_init(inits, off, totalsize)
         | 
| 813 | 
            +
                  emit_fill_holes(inits, off, totalsize)
         | 
| 814 | 
            +
                  inits.each do |node|
         | 
| 815 | 
            +
                    Util.assert!{ node.kind == AST::INIT }
         | 
| 816 | 
            +
                    isbitfield = (node.totype.bitsize && node.totype.bitsize > 0)
         | 
| 817 | 
            +
                    if node.initval.kind == AST::LITERAL && !isbitfield
         | 
| 818 | 
            +
                      emit_save_literal(node.initval, node.totype, node.initoff + off)
         | 
| 819 | 
            +
                    else
         | 
| 820 | 
            +
                      emit_expr(node.initval)
         | 
| 821 | 
            +
                      emit_lsave(node.totype, node.initoff + off)
         | 
| 822 | 
            +
                    end
         | 
| 823 | 
            +
                  end
         | 
| 824 | 
            +
                end
         | 
| 825 | 
            +
             | 
| 826 | 
            +
                # @param [Array] inits
         | 
| 827 | 
            +
                # @param [Integer] off
         | 
| 828 | 
            +
                # @param [Integer] totalsize
         | 
| 829 | 
            +
                def emit_fill_holes(inits, off, totalsize)
         | 
| 830 | 
            +
                  # If at least one of the fields in a variable are initialized,
         | 
| 831 | 
            +
                  # unspecified fields has to be initialized with 0.
         | 
| 832 | 
            +
                  lastend = 0
         | 
| 833 | 
            +
                  inits.sort_by(&:initoff).each do |node|
         | 
| 834 | 
            +
                    if lastend < node.initoff
         | 
| 835 | 
            +
                      emit_zero_filler(lastend + off, node.initoff + off)
         | 
| 836 | 
            +
                    end
         | 
| 837 | 
            +
                    lastend = node.initoff + node.totype.size
         | 
| 838 | 
            +
                  end
         | 
| 839 | 
            +
                  emit_zero_filler(lastend + off, totalsize + off)
         | 
| 840 | 
            +
                end
         | 
| 841 | 
            +
             | 
| 842 | 
            +
                # @param [Integer] s
         | 
| 843 | 
            +
                # @param [Integer] e
         | 
| 844 | 
            +
                def emit_zero_filler(s, e)
         | 
| 845 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 846 | 
            +
                  # SAVE;
         | 
| 847 | 
            +
                  while s <= (e- 4) do
         | 
| 848 | 
            +
                    emit("movl $0, #{s}(#rbp)")
         | 
| 849 | 
            +
                    s += 4
         | 
| 850 | 
            +
                  end
         | 
| 851 | 
            +
                  while s < e
         | 
| 852 | 
            +
                    emit("movb $0, #{s}(#rbp)")
         | 
| 853 | 
            +
                    s += 1
         | 
| 854 | 
            +
                  end
         | 
| 855 | 
            +
                end
         | 
| 856 | 
            +
             | 
| 857 | 
            +
                # @param [Node] node
         | 
| 858 | 
            +
                # @param [Type] totype
         | 
| 859 | 
            +
                # @param [Integer] off
         | 
| 860 | 
            +
                def emit_save_literal(node, totype, off)
         | 
| 861 | 
            +
                  case totype.kind
         | 
| 862 | 
            +
                  when Kind::BOOL  then emit("movb $#{node.ival}, #{off}(#rbp)")
         | 
| 863 | 
            +
                  when Kind::CHAR  then emit("movb $#{node.ival}, #{off}(#rbp)")
         | 
| 864 | 
            +
                  when Kind::SHORT then emit("movw $#{node.ival}, #{off}(#rbp)")
         | 
| 865 | 
            +
                  when Kind::INT   then emit("movl $#{node.ival}, #{off}(#rbp)")
         | 
| 866 | 
            +
                  when Kind::LONG, Kind::LLONG, Kind::PTR
         | 
| 867 | 
            +
                    emit("movl $#{node.ival & ((1 << 32) - 1)}, #{off    }(#rbp)")
         | 
| 868 | 
            +
                    emit("movl $#{node.ival >> 32            }, #{off + 4}(#rbp)")
         | 
| 869 | 
            +
                  when Kind::FLOAT
         | 
| 870 | 
            +
                    val = [node.fval].pack('f').unpack('I')[0]
         | 
| 871 | 
            +
                    emit("movl $#{val}, #{off}(#rbp)")
         | 
| 872 | 
            +
                  when Kind::DOUBLE, Kind::LDOUBLE
         | 
| 873 | 
            +
                    val = [node.fval].pack('d').unpack('Q')[0]
         | 
| 874 | 
            +
                    emit("movl $#{val & ((1 << 32) - 1)}, #{off    }(#rbp)")
         | 
| 875 | 
            +
                    emit("movl $#{val >> 32            }, #{off + 4}(#rbp)")
         | 
| 876 | 
            +
                  else
         | 
| 877 | 
            +
                    raise "internal error: <#{node}> <#{totype}> <#{off}>"
         | 
| 878 | 
            +
                  end
         | 
| 879 | 
            +
                end
         | 
| 880 | 
            +
             | 
| 881 | 
            +
                # @param [Type] ty
         | 
| 882 | 
            +
                # @param [Integer] off
         | 
| 883 | 
            +
                def emit_lsave(ty, off)
         | 
| 884 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 885 | 
            +
                  # SAVE;
         | 
| 886 | 
            +
                  if ty.kind == Kind::FLOAT
         | 
| 887 | 
            +
                    emit("movss #xmm0, #{off}(#rbp)")
         | 
| 888 | 
            +
                  elsif ty.kind == Kind::DOUBLE
         | 
| 889 | 
            +
                    emit("movsd #xmm0, #{off}(#rbp)")
         | 
| 890 | 
            +
                  else
         | 
| 891 | 
            +
                    maybe_convert_bool(ty)
         | 
| 892 | 
            +
                    addr = "#{off}(%rbp)"
         | 
| 893 | 
            +
                    maybe_emit_bitshift_save(ty, addr)
         | 
| 894 | 
            +
                    reg = get_int_reg(ty, 'a')
         | 
| 895 | 
            +
                    emit("mov ##{reg}, %s", addr)
         | 
| 896 | 
            +
                  end
         | 
| 897 | 
            +
                end
         | 
| 898 | 
            +
             | 
| 899 | 
            +
                # @param [String] varname
         | 
| 900 | 
            +
                # @param [Type] ty
         | 
| 901 | 
            +
                # @param [Integer] off
         | 
| 902 | 
            +
                def emit_gsave(varname, ty, off)
         | 
| 903 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 904 | 
            +
                  # SAVE;
         | 
| 905 | 
            +
                  Util.assert!{ ty.kind != Kind::ARRAY }
         | 
| 906 | 
            +
                  maybe_convert_bool(ty)
         | 
| 907 | 
            +
                  reg = get_int_reg(ty, 'a')
         | 
| 908 | 
            +
                  addr = "#{varname}+#{off}(%rip)"
         | 
| 909 | 
            +
                  maybe_emit_bitshift_save(ty, addr)
         | 
| 910 | 
            +
                  emit("mov ##{reg}, %s", addr)
         | 
| 911 | 
            +
                end
         | 
| 912 | 
            +
             | 
| 913 | 
            +
                # @param [Type] ty
         | 
| 914 | 
            +
                def maybe_convert_bool(ty)
         | 
| 915 | 
            +
                  if ty.kind == Kind::BOOL
         | 
| 916 | 
            +
                    emit("test #rax, #rax")
         | 
| 917 | 
            +
                    emit("setne #al")
         | 
| 918 | 
            +
                  end
         | 
| 919 | 
            +
                end
         | 
| 920 | 
            +
             | 
| 921 | 
            +
                # @param [Type] ty
         | 
| 922 | 
            +
                # @param [Char] r
         | 
| 923 | 
            +
                # @return [Integer]
         | 
| 924 | 
            +
                def get_int_reg(ty, r)
         | 
| 925 | 
            +
                  Util.assert!{ r == 'a' || r == 'c' }
         | 
| 926 | 
            +
                  case ty.size
         | 
| 927 | 
            +
                  when 1 then return (r == 'a') ? "al" : "cl"
         | 
| 928 | 
            +
                  when 2 then return (r == 'a') ? "ax" : "cx"
         | 
| 929 | 
            +
                  when 4 then return (r == 'a') ? "eax" : "ecx"
         | 
| 930 | 
            +
                  when 8 then return (r == 'a') ? "rax" : "rcx"
         | 
| 931 | 
            +
                  else
         | 
| 932 | 
            +
                    raise "Unknown data size: #{ty}: #{ty.size}"
         | 
| 933 | 
            +
                  end
         | 
| 934 | 
            +
                end
         | 
| 935 | 
            +
             | 
| 936 | 
            +
                # @param [Type] ty
         | 
| 937 | 
            +
                # @param [String] addr
         | 
| 938 | 
            +
                def maybe_emit_bitshift_save(ty, addr)
         | 
| 939 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 940 | 
            +
                  # SAVE;
         | 
| 941 | 
            +
                  return if ty.bitsize.nil? || ty.bitsize < 0
         | 
| 942 | 
            +
                  push("rcx")
         | 
| 943 | 
            +
                  push("rdi")
         | 
| 944 | 
            +
                  v = (1 << ty.bitsize) - 1
         | 
| 945 | 
            +
                  emit("mov $#{sprintf("%#x", v)}, #rdi")
         | 
| 946 | 
            +
                  emit("and #rdi, #rax")
         | 
| 947 | 
            +
                  emit("shl $#{ty.bitoff}, #rax")
         | 
| 948 | 
            +
                  emit("mov %s, ##{get_int_reg(ty, 'c')}", addr)
         | 
| 949 | 
            +
                  # TODO(south37): Consider bit size. Use 32 bit temporary here
         | 
| 950 | 
            +
                  v = 0xffffffff - (((1 << ty.bitsize) - 1) << ty.bitoff)
         | 
| 951 | 
            +
                  #v = ~(((1 << ty.bitsize) - 1) << ty.bitoff)
         | 
| 952 | 
            +
                  emit("mov $#{sprintf("%#x", v)}, #rdi")
         | 
| 953 | 
            +
                  emit("and #rdi, #rcx")
         | 
| 954 | 
            +
                  emit("or #rcx, #rax")
         | 
| 955 | 
            +
                  pop("rdi")
         | 
| 956 | 
            +
                  pop("rcx")
         | 
| 957 | 
            +
                end
         | 
| 958 | 
            +
             | 
| 959 | 
            +
                # @param [Node] node
         | 
| 960 | 
            +
                def emit_assign(node)
         | 
| 961 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 962 | 
            +
                  # SAVE;
         | 
| 963 | 
            +
                  if (node.left.ty.kind == Kind::STRUCT) && (node.left.ty.size > 8)
         | 
| 964 | 
            +
                    emit_copy_struct(node.left, node.right)
         | 
| 965 | 
            +
                  else
         | 
| 966 | 
            +
                    emit_expr(node.right)
         | 
| 967 | 
            +
                    emit_load_convert(node.ty, node.right.ty)
         | 
| 968 | 
            +
                    emit_store(node.left)
         | 
| 969 | 
            +
                  end
         | 
| 970 | 
            +
                end
         | 
| 971 | 
            +
             | 
| 972 | 
            +
                # @param [Node] node
         | 
| 973 | 
            +
                def emit_label_addr(node)
         | 
| 974 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 975 | 
            +
                  # SAVE;
         | 
| 976 | 
            +
                  emit("mov $%s, #rax", node.newlabel)
         | 
| 977 | 
            +
                end
         | 
| 978 | 
            +
             | 
| 979 | 
            +
                # @param [Node] left
         | 
| 980 | 
            +
                # @param [Node] right
         | 
| 981 | 
            +
                def emit_copy_struct(left, right)
         | 
| 982 | 
            +
                  push("rcx")
         | 
| 983 | 
            +
                  push("r11")
         | 
| 984 | 
            +
                  emit_addr(right)
         | 
| 985 | 
            +
                  emit("mov #rax, #rcx")
         | 
| 986 | 
            +
                  emit_addr(left)
         | 
| 987 | 
            +
                  i = 0
         | 
| 988 | 
            +
                  while (i < left.ty.size) do
         | 
| 989 | 
            +
                    emit("movq #{i}(#rcx), #r11")
         | 
| 990 | 
            +
                    emit("movq #r11, #{i}(#rax)")
         | 
| 991 | 
            +
                    i += 8
         | 
| 992 | 
            +
                  end
         | 
| 993 | 
            +
                  while (i < left.ty.size) do
         | 
| 994 | 
            +
                    emit("movl #{i}(#rcx), #r11")
         | 
| 995 | 
            +
                    emit("movl #r11, #{i}(#rax)")
         | 
| 996 | 
            +
                    i += 4
         | 
| 997 | 
            +
                  end
         | 
| 998 | 
            +
                  while (i < left.ty.size) do
         | 
| 999 | 
            +
                    emit("movb #{i}(#rcx), #r11")
         | 
| 1000 | 
            +
                    emit("movb #r11, #{i}(#rax)")
         | 
| 1001 | 
            +
                    i += 1
         | 
| 1002 | 
            +
                  end
         | 
| 1003 | 
            +
                  pop("r11")
         | 
| 1004 | 
            +
                  pop("rcx")
         | 
| 1005 | 
            +
                end
         | 
| 1006 | 
            +
             | 
| 1007 | 
            +
                # @param [Node] node
         | 
| 1008 | 
            +
                def emit_addr(node)
         | 
| 1009 | 
            +
                  case node.kind
         | 
| 1010 | 
            +
                  when AST::LVAR
         | 
| 1011 | 
            +
                    ensure_lvar_init(node)
         | 
| 1012 | 
            +
                    emit("lea #{node.loff}(#rbp), #rax")
         | 
| 1013 | 
            +
                  when AST::GVAR
         | 
| 1014 | 
            +
                    emit("lea #{node.glabel}(#rip), #rax")
         | 
| 1015 | 
            +
                  when AST::DEREF
         | 
| 1016 | 
            +
                    emit_expr(node.operand)
         | 
| 1017 | 
            +
                  when AST::STRUCT_REF
         | 
| 1018 | 
            +
                    emit_addr(node.struct)
         | 
| 1019 | 
            +
                    emit("add $#{node.ty.offset}, #rax")
         | 
| 1020 | 
            +
                  when AST::FUNCDESG
         | 
| 1021 | 
            +
                    emit("lea #{node.fname}(#rip), #rax")
         | 
| 1022 | 
            +
                  else
         | 
| 1023 | 
            +
                    raise "internal error: #{node}"
         | 
| 1024 | 
            +
                  end
         | 
| 1025 | 
            +
                end
         | 
| 1026 | 
            +
             | 
| 1027 | 
            +
                # @param [Node] var
         | 
| 1028 | 
            +
                def emit_store(var)
         | 
| 1029 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1030 | 
            +
                  # SAVE;
         | 
| 1031 | 
            +
                  case var.kind
         | 
| 1032 | 
            +
                  when AST::DEREF
         | 
| 1033 | 
            +
                    emit_assign_deref(var)
         | 
| 1034 | 
            +
                  when AST::STRUCT_REF
         | 
| 1035 | 
            +
                    emit_assign_struct_ref(var.struct, var.ty, 0)
         | 
| 1036 | 
            +
                  when AST::LVAR
         | 
| 1037 | 
            +
                    ensure_lvar_init(var)
         | 
| 1038 | 
            +
                    emit_lsave(var.ty, var.loff)
         | 
| 1039 | 
            +
                  when AST::GVAR
         | 
| 1040 | 
            +
                    emit_gsave(var.glabel, var.ty, 0)
         | 
| 1041 | 
            +
                  else
         | 
| 1042 | 
            +
                    raise "internal error"
         | 
| 1043 | 
            +
                  end
         | 
| 1044 | 
            +
                end
         | 
| 1045 | 
            +
             | 
| 1046 | 
            +
                # @param [Node] var
         | 
| 1047 | 
            +
                def emit_assign_deref(var)
         | 
| 1048 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1049 | 
            +
                  # SAVE;
         | 
| 1050 | 
            +
                  push("rax")
         | 
| 1051 | 
            +
                  emit_expr(var.operand)
         | 
| 1052 | 
            +
                  do_emit_assign_deref(var.operand.ty.ptr, 0)
         | 
| 1053 | 
            +
                end
         | 
| 1054 | 
            +
             | 
| 1055 | 
            +
                # @param [Type] ty
         | 
| 1056 | 
            +
                # @param [Integer] off
         | 
| 1057 | 
            +
                def do_emit_assign_deref(ty, off)
         | 
| 1058 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1059 | 
            +
                  # SAVE;
         | 
| 1060 | 
            +
                  emit("mov (#rsp), #rcx")
         | 
| 1061 | 
            +
                  reg = get_int_reg(ty, 'c')
         | 
| 1062 | 
            +
                  if off > 0
         | 
| 1063 | 
            +
                    emit("mov ##{reg}, #{off}(#rax)")
         | 
| 1064 | 
            +
                  else
         | 
| 1065 | 
            +
                    emit("mov ##{reg}, (#rax)")
         | 
| 1066 | 
            +
                  end
         | 
| 1067 | 
            +
                  pop("rax")
         | 
| 1068 | 
            +
                end
         | 
| 1069 | 
            +
             | 
| 1070 | 
            +
                # @param [Node] struct
         | 
| 1071 | 
            +
                # @param [Type] field
         | 
| 1072 | 
            +
                # @param [Integer] off
         | 
| 1073 | 
            +
                def emit_assign_struct_ref(struct, field, off)
         | 
| 1074 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1075 | 
            +
                  # SAVE;
         | 
| 1076 | 
            +
                  case struct.kind
         | 
| 1077 | 
            +
                  when AST::LVAR
         | 
| 1078 | 
            +
                    ensure_lvar_init(struct)
         | 
| 1079 | 
            +
                    emit_lsave(field, struct.loff + field.offset + off)
         | 
| 1080 | 
            +
                  when AST::GVAR
         | 
| 1081 | 
            +
                    emit_gsave(struct.glabel, field, field.offset + off)
         | 
| 1082 | 
            +
                  when AST::STRUCT_REF
         | 
| 1083 | 
            +
                    emit_assign_struct_ref(struct.struct, field, off + struct.ty.offset)
         | 
| 1084 | 
            +
                  when AST::DEREF
         | 
| 1085 | 
            +
                    push("rax")
         | 
| 1086 | 
            +
                    emit_expr(struct.operand)
         | 
| 1087 | 
            +
                    do_emit_assign_deref(field, field.offset + off)
         | 
| 1088 | 
            +
                  else
         | 
| 1089 | 
            +
                    raise "internal error: #{struct}"
         | 
| 1090 | 
            +
                    # error("internal error: %s", node2s(struct));
         | 
| 1091 | 
            +
                  end
         | 
| 1092 | 
            +
                end
         | 
| 1093 | 
            +
             | 
| 1094 | 
            +
                # @param [Node] node
         | 
| 1095 | 
            +
                def ensure_lvar_init(node)
         | 
| 1096 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1097 | 
            +
                  # SAVE;
         | 
| 1098 | 
            +
                  Util.assert!{ node.kind == AST::LVAR }
         | 
| 1099 | 
            +
                  if node.lvarinit
         | 
| 1100 | 
            +
                    emit_decl_init(node.lvarinit, node.loff, node.ty.size)
         | 
| 1101 | 
            +
                  end
         | 
| 1102 | 
            +
                  node.lvarinit = nil
         | 
| 1103 | 
            +
                end
         | 
| 1104 | 
            +
             | 
| 1105 | 
            +
                # @param [Node] node
         | 
| 1106 | 
            +
                def emit_deref(node)
         | 
| 1107 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1108 | 
            +
                  # SAVE;
         | 
| 1109 | 
            +
                  emit_expr(node.operand)
         | 
| 1110 | 
            +
                  emit_lload(node.operand.ty.ptr, "rax", 0)
         | 
| 1111 | 
            +
                  emit_load_convert(node.ty, node.operand.ty.ptr)
         | 
| 1112 | 
            +
                end
         | 
| 1113 | 
            +
             | 
| 1114 | 
            +
                # @param [Type] ty
         | 
| 1115 | 
            +
                # @param [String] base
         | 
| 1116 | 
            +
                # @param [Integer] off
         | 
| 1117 | 
            +
                def emit_lload(ty, base, off)
         | 
| 1118 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1119 | 
            +
                  # SAVE;
         | 
| 1120 | 
            +
                  if ty.kind == Kind::ARRAY
         | 
| 1121 | 
            +
                    emit("lea #{off}(##{base}), #rax")
         | 
| 1122 | 
            +
                  elsif ty.kind == Kind::FLOAT
         | 
| 1123 | 
            +
                    emit("movss #{off}(##{base}), #xmm0")
         | 
| 1124 | 
            +
                  elsif (ty.kind == Kind::DOUBLE) || (ty.kind == Kind::LDOUBLE)
         | 
| 1125 | 
            +
                    emit("movsd %d(#%s), #xmm0", off, base)
         | 
| 1126 | 
            +
                  else
         | 
| 1127 | 
            +
                    inst = get_load_inst(ty)
         | 
| 1128 | 
            +
                    emit("#{inst} #{off}(##{base}), #rax")
         | 
| 1129 | 
            +
                    maybe_emit_bitshift_load(ty)
         | 
| 1130 | 
            +
                  end
         | 
| 1131 | 
            +
                end
         | 
| 1132 | 
            +
             | 
| 1133 | 
            +
                # @param [Type] ty
         | 
| 1134 | 
            +
                def get_load_inst(ty)
         | 
| 1135 | 
            +
                  case ty.size
         | 
| 1136 | 
            +
                  when 1 then return "movsbq"
         | 
| 1137 | 
            +
                  when 2 then return "movswq"
         | 
| 1138 | 
            +
                  when 4 then return "movslq"
         | 
| 1139 | 
            +
                  when 8 then return "mov"
         | 
| 1140 | 
            +
                  else
         | 
| 1141 | 
            +
                    raise "Unknown data size: #{ty}: #{ty.size}"
         | 
| 1142 | 
            +
                  end
         | 
| 1143 | 
            +
                end
         | 
| 1144 | 
            +
             | 
| 1145 | 
            +
                # @param [Type] ty
         | 
| 1146 | 
            +
                def maybe_emit_bitshift_load(ty)
         | 
| 1147 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1148 | 
            +
                  # SAVE;
         | 
| 1149 | 
            +
                  return if ty.bitsize.nil? || ty.bitsize <= 0
         | 
| 1150 | 
            +
                  emit("shr $#{ty.bitoff}, #rax")
         | 
| 1151 | 
            +
                  push("rcx")
         | 
| 1152 | 
            +
                  emit("mov $#{sprintf("%#x", (1 << ty.bitsize) - 1)}, #rcx")
         | 
| 1153 | 
            +
                  emit("and #rcx, #rax")
         | 
| 1154 | 
            +
                  pop("rcx")
         | 
| 1155 | 
            +
                end
         | 
| 1156 | 
            +
             | 
| 1157 | 
            +
                # @param [Node] node
         | 
| 1158 | 
            +
                def emit_ternary(node)
         | 
| 1159 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1160 | 
            +
                  # SAVE;
         | 
| 1161 | 
            +
                  emit_expr(node.cond)
         | 
| 1162 | 
            +
                  ne = @label_gen.next
         | 
| 1163 | 
            +
                  emit_je(ne)
         | 
| 1164 | 
            +
                  if node.thn
         | 
| 1165 | 
            +
                    emit_expr(node.thn)
         | 
| 1166 | 
            +
                  end
         | 
| 1167 | 
            +
                  if node.els
         | 
| 1168 | 
            +
                    e = @label_gen.next
         | 
| 1169 | 
            +
                    emit_jmp(e)
         | 
| 1170 | 
            +
                    emit_label(ne)
         | 
| 1171 | 
            +
                    emit_expr(node.els)
         | 
| 1172 | 
            +
                    emit_label(e)
         | 
| 1173 | 
            +
                  else
         | 
| 1174 | 
            +
                    emit_label(ne)
         | 
| 1175 | 
            +
                  end
         | 
| 1176 | 
            +
                end
         | 
| 1177 | 
            +
             | 
| 1178 | 
            +
                # @param [String] label
         | 
| 1179 | 
            +
                def emit_je(label)
         | 
| 1180 | 
            +
                  emit("test #rax, #rax")
         | 
| 1181 | 
            +
                  emit("je #{label}")
         | 
| 1182 | 
            +
                end
         | 
| 1183 | 
            +
             | 
| 1184 | 
            +
                # @param [String] label
         | 
| 1185 | 
            +
                def emit_jmp(label)
         | 
| 1186 | 
            +
                  emit("jmp #{label}")
         | 
| 1187 | 
            +
                end
         | 
| 1188 | 
            +
             | 
| 1189 | 
            +
                # @param [Node] node
         | 
| 1190 | 
            +
                def emit_goto(node)
         | 
| 1191 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1192 | 
            +
                  # SAVE;
         | 
| 1193 | 
            +
                  Util.assert!{ node.newlabel }
         | 
| 1194 | 
            +
                  emit_jmp(node.newlabel)
         | 
| 1195 | 
            +
                end
         | 
| 1196 | 
            +
             | 
| 1197 | 
            +
                # @param [Node] node
         | 
| 1198 | 
            +
                # @return [Boolean]
         | 
| 1199 | 
            +
                def maybe_emit_builtin(node)
         | 
| 1200 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1201 | 
            +
                  # SAVE;
         | 
| 1202 | 
            +
                  if "__builtin_return_address" == node.fname
         | 
| 1203 | 
            +
                    emit_builtin_return_address(node)
         | 
| 1204 | 
            +
                    return true
         | 
| 1205 | 
            +
                  end
         | 
| 1206 | 
            +
                  if "__builtin_reg_class" == node.fname
         | 
| 1207 | 
            +
                    emit_builtin_reg_class(node)
         | 
| 1208 | 
            +
                    return true
         | 
| 1209 | 
            +
                  end
         | 
| 1210 | 
            +
                  if "__builtin_va_start" == node.fname
         | 
| 1211 | 
            +
                    emit_builtin_va_start(node)
         | 
| 1212 | 
            +
                    return true
         | 
| 1213 | 
            +
                  end
         | 
| 1214 | 
            +
                  false
         | 
| 1215 | 
            +
                end
         | 
| 1216 | 
            +
             | 
| 1217 | 
            +
                # @param [Node] node
         | 
| 1218 | 
            +
                def emit_builtin_return_address(node)
         | 
| 1219 | 
            +
                  push("r11");
         | 
| 1220 | 
            +
                  Util.assert!{ node.args.size == 1 }
         | 
| 1221 | 
            +
                  emit_expr(node.args[0])
         | 
| 1222 | 
            +
                  l = @label_gen.next
         | 
| 1223 | 
            +
                  e = @label_gen.next
         | 
| 1224 | 
            +
                  emit("mov #rbp, #r11")
         | 
| 1225 | 
            +
                  emit_label(l)
         | 
| 1226 | 
            +
                  emit("test #rax, #rax")
         | 
| 1227 | 
            +
                  emit("jz %s", e)
         | 
| 1228 | 
            +
                  emit("mov (#r11), #r11")
         | 
| 1229 | 
            +
                  emit("sub $1, #rax")
         | 
| 1230 | 
            +
                  emit_jmp(l)
         | 
| 1231 | 
            +
                  emit_label(e)
         | 
| 1232 | 
            +
                  emit("mov 8(#r11), #rax")
         | 
| 1233 | 
            +
                  pop("r11")
         | 
| 1234 | 
            +
                end
         | 
| 1235 | 
            +
             | 
| 1236 | 
            +
                # Set the register class for parameter passing to RAX.
         | 
| 1237 | 
            +
                # 0 is INTEGER, 1 is SSE, 2 is MEMORY.
         | 
| 1238 | 
            +
                #
         | 
| 1239 | 
            +
                # @param [Node] node
         | 
| 1240 | 
            +
                def emit_builtin_reg_class(node)
         | 
| 1241 | 
            +
                  arg = node.args[0]
         | 
| 1242 | 
            +
                  Util.assert!{ arg.ty.kind == Kind::PTR }
         | 
| 1243 | 
            +
                  ty = arg.ty.ptr
         | 
| 1244 | 
            +
                  if ty.kind == Kind::STRUCT
         | 
| 1245 | 
            +
                    emit("mov $2, #eax")
         | 
| 1246 | 
            +
                  elsif Type.is_flotype(ty)
         | 
| 1247 | 
            +
                    emit("mov $1, #eax")
         | 
| 1248 | 
            +
                  else
         | 
| 1249 | 
            +
                    emit("mov $0, #eax")
         | 
| 1250 | 
            +
                  end
         | 
| 1251 | 
            +
                end
         | 
| 1252 | 
            +
             | 
| 1253 | 
            +
                # @param [Node] node
         | 
| 1254 | 
            +
                def emit_builtin_va_start(node)
         | 
| 1255 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1256 | 
            +
                  # SAVE;
         | 
| 1257 | 
            +
                  Util.assert!{ node.args.size == 1 }
         | 
| 1258 | 
            +
                  emit_expr(node.args[0])
         | 
| 1259 | 
            +
                  push("rcx")
         | 
| 1260 | 
            +
                  emit("movl $%d, (#rax)", @numgp * 8)
         | 
| 1261 | 
            +
                  emit("movl $%d, 4(#rax)", 48 + @numfp * 16)
         | 
| 1262 | 
            +
                  emit("lea %d(#rbp), #rcx", -REGAREA_SIZE)
         | 
| 1263 | 
            +
                  emit("mov #rcx, 16(#rax)")
         | 
| 1264 | 
            +
                  pop("rcx")
         | 
| 1265 | 
            +
                end
         | 
| 1266 | 
            +
             | 
| 1267 | 
            +
                # Functions in shared library
         | 
| 1268 | 
            +
                # TODO(sout37) Fix this dirty hack.
         | 
| 1269 | 
            +
                SHARED_LIBRARY_FUNCTIONS  = ["printf", "calloc"]
         | 
| 1270 | 
            +
             | 
| 1271 | 
            +
                # @param [Node] node
         | 
| 1272 | 
            +
                def emit_func_call(node)
         | 
| 1273 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1274 | 
            +
                  # SAVE;
         | 
| 1275 | 
            +
                  opos = @stackpos
         | 
| 1276 | 
            +
                  isptr = (node.kind == AST::FUNCPTR_CALL)
         | 
| 1277 | 
            +
                  ftype = isptr ? node.fptr.ty.ptr : node.ftype
         | 
| 1278 | 
            +
             | 
| 1279 | 
            +
                  ints = []
         | 
| 1280 | 
            +
                  floats = []
         | 
| 1281 | 
            +
                  rest = []
         | 
| 1282 | 
            +
                  classify_args(ints, floats, rest, node.args)
         | 
| 1283 | 
            +
                  save_arg_regs(ints.size, floats.size)
         | 
| 1284 | 
            +
             | 
| 1285 | 
            +
                  padding = @stackpos % 16
         | 
| 1286 | 
            +
                  if (padding > 0)
         | 
| 1287 | 
            +
                    emit("sub $8, #rsp")
         | 
| 1288 | 
            +
                    @stackpos += 8
         | 
| 1289 | 
            +
                  end
         | 
| 1290 | 
            +
             | 
| 1291 | 
            +
                  restsize = emit_args(rest.reverse)
         | 
| 1292 | 
            +
                  if isptr
         | 
| 1293 | 
            +
                    emit_expr(node.fptr)
         | 
| 1294 | 
            +
                    push("rax")
         | 
| 1295 | 
            +
                  end
         | 
| 1296 | 
            +
                  emit_args(ints)
         | 
| 1297 | 
            +
                  emit_args(floats)
         | 
| 1298 | 
            +
                  pop_float_args(floats.size)
         | 
| 1299 | 
            +
                  pop_int_args(ints.size)
         | 
| 1300 | 
            +
             | 
| 1301 | 
            +
                  if isptr
         | 
| 1302 | 
            +
                    pop("r11")
         | 
| 1303 | 
            +
                  end
         | 
| 1304 | 
            +
                  if ftype.hasva
         | 
| 1305 | 
            +
                    emit("mov $#{floats.size}, #eax")
         | 
| 1306 | 
            +
                  end
         | 
| 1307 | 
            +
             | 
| 1308 | 
            +
                  if isptr
         | 
| 1309 | 
            +
                    emit("call *#r11")
         | 
| 1310 | 
            +
                  else
         | 
| 1311 | 
            +
                    fname = node.fname
         | 
| 1312 | 
            +
                    # Add `@PLT` suffix to functions in shared library here.
         | 
| 1313 | 
            +
                    if SHARED_LIBRARY_FUNCTIONS.include?(fname)
         | 
| 1314 | 
            +
                      fname += "@PLT"
         | 
| 1315 | 
            +
                    end
         | 
| 1316 | 
            +
                    emit("call #{fname}")
         | 
| 1317 | 
            +
                  end
         | 
| 1318 | 
            +
                  maybe_booleanize_retval(node.ty)
         | 
| 1319 | 
            +
                  if restsize > 0
         | 
| 1320 | 
            +
                    emit("add $#{restsize}, #rsp")
         | 
| 1321 | 
            +
                    @stackpos -= restsize
         | 
| 1322 | 
            +
                  end
         | 
| 1323 | 
            +
                  if padding > 0
         | 
| 1324 | 
            +
                    emit("add $8, #rsp")
         | 
| 1325 | 
            +
                    @stackpos -= 8
         | 
| 1326 | 
            +
                  end
         | 
| 1327 | 
            +
                  restore_arg_regs(ints.size, floats.size)
         | 
| 1328 | 
            +
                  Util.assert!{ opos == @stackpos }
         | 
| 1329 | 
            +
                end
         | 
| 1330 | 
            +
             | 
| 1331 | 
            +
                # @param(return) [Array] ints
         | 
| 1332 | 
            +
                # @param(return) [Array] floats
         | 
| 1333 | 
            +
                # @param(return) [Array] rest
         | 
| 1334 | 
            +
                # @param [Array] args
         | 
| 1335 | 
            +
                def classify_args(ints, floats, rest, args)
         | 
| 1336 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1337 | 
            +
                  # SAVE;
         | 
| 1338 | 
            +
                  ireg = 0
         | 
| 1339 | 
            +
                  xreg = 0
         | 
| 1340 | 
            +
                  imax = 6
         | 
| 1341 | 
            +
                  xmax = 8
         | 
| 1342 | 
            +
                  args.each do |v|
         | 
| 1343 | 
            +
                    if v.ty.kind == Kind::STRUCT
         | 
| 1344 | 
            +
                      rest.push(v)
         | 
| 1345 | 
            +
                    elsif Type.is_flotype(v.ty)
         | 
| 1346 | 
            +
                      if xreg < xmax
         | 
| 1347 | 
            +
                        floats.push(v)
         | 
| 1348 | 
            +
                      else
         | 
| 1349 | 
            +
                        rest.push(v)
         | 
| 1350 | 
            +
                      end
         | 
| 1351 | 
            +
                      xreg += 1
         | 
| 1352 | 
            +
                    else
         | 
| 1353 | 
            +
                      if ireg < imax
         | 
| 1354 | 
            +
                        ints.push(v)
         | 
| 1355 | 
            +
                      else
         | 
| 1356 | 
            +
                        rest.push(v)
         | 
| 1357 | 
            +
                      end
         | 
| 1358 | 
            +
                      ireg += 1
         | 
| 1359 | 
            +
                    end
         | 
| 1360 | 
            +
                  end
         | 
| 1361 | 
            +
                end
         | 
| 1362 | 
            +
             | 
| 1363 | 
            +
                # @param [Integer] nints
         | 
| 1364 | 
            +
                # @param [Integer] nfloats
         | 
| 1365 | 
            +
                def save_arg_regs(nints, nfloats)
         | 
| 1366 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1367 | 
            +
                  # SAVE;
         | 
| 1368 | 
            +
                  Util.assert!{ nints <= 6 }
         | 
| 1369 | 
            +
                  Util.assert!{ nfloats <= 8 }
         | 
| 1370 | 
            +
                  0.upto(nints - 1) do |i|
         | 
| 1371 | 
            +
                    push(REGS[i])
         | 
| 1372 | 
            +
                  end
         | 
| 1373 | 
            +
                  1.upto(nfloats - 1) do |i|
         | 
| 1374 | 
            +
                    push_xmm(i)
         | 
| 1375 | 
            +
                  end
         | 
| 1376 | 
            +
                end
         | 
| 1377 | 
            +
             | 
| 1378 | 
            +
                # @param [Integer] nints
         | 
| 1379 | 
            +
                # @param [Integer] nfloats
         | 
| 1380 | 
            +
                def restore_arg_regs(nints, nfloats)
         | 
| 1381 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1382 | 
            +
                  # SAVE;
         | 
| 1383 | 
            +
                  (nfloats - 1).downto(1) do |i|
         | 
| 1384 | 
            +
                    pop_xmm(i);
         | 
| 1385 | 
            +
                  end
         | 
| 1386 | 
            +
                  (nints - 1).downto(0) do |i|
         | 
| 1387 | 
            +
                    pop(REGS[i])
         | 
| 1388 | 
            +
                  end
         | 
| 1389 | 
            +
                end
         | 
| 1390 | 
            +
             | 
| 1391 | 
            +
                # @param [Array] vals
         | 
| 1392 | 
            +
                # @return [Integer]
         | 
| 1393 | 
            +
                def emit_args(vals)
         | 
| 1394 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1395 | 
            +
                  # SAVE;
         | 
| 1396 | 
            +
                  r = 0
         | 
| 1397 | 
            +
                  vals.each do |v|
         | 
| 1398 | 
            +
                    if v.ty.kind == Kind::STRUCT
         | 
| 1399 | 
            +
                      emit_addr(v);
         | 
| 1400 | 
            +
                      r += push_struct(v.ty.size)
         | 
| 1401 | 
            +
                    elsif Type.is_flotype(v.ty)
         | 
| 1402 | 
            +
                      emit_expr(v)
         | 
| 1403 | 
            +
                      push_xmm(0)
         | 
| 1404 | 
            +
                      r += 8
         | 
| 1405 | 
            +
                    else
         | 
| 1406 | 
            +
                      emit_expr(v)
         | 
| 1407 | 
            +
                      push("rax")
         | 
| 1408 | 
            +
                      r += 8
         | 
| 1409 | 
            +
                    end
         | 
| 1410 | 
            +
                  end
         | 
| 1411 | 
            +
                  r
         | 
| 1412 | 
            +
                end
         | 
| 1413 | 
            +
             | 
| 1414 | 
            +
                # @param [Integer] nints
         | 
| 1415 | 
            +
                def pop_int_args(nints)
         | 
| 1416 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1417 | 
            +
                  # SAVE;
         | 
| 1418 | 
            +
                  (nints - 1).downto(0) do |i|
         | 
| 1419 | 
            +
                    pop(REGS[i]);
         | 
| 1420 | 
            +
                  end
         | 
| 1421 | 
            +
                end
         | 
| 1422 | 
            +
             | 
| 1423 | 
            +
                # @param [Integer] nfloats
         | 
| 1424 | 
            +
                def pop_float_args(nfloats)
         | 
| 1425 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1426 | 
            +
                  # SAVE;
         | 
| 1427 | 
            +
                  (nfloats - 1).downto(0) do |i|
         | 
| 1428 | 
            +
                    pop_xmm(i)
         | 
| 1429 | 
            +
                  end
         | 
| 1430 | 
            +
                end
         | 
| 1431 | 
            +
             | 
| 1432 | 
            +
                # @param [String] inst
         | 
| 1433 | 
            +
                # @param [String] usiginst
         | 
| 1434 | 
            +
                # @param [Node] node
         | 
| 1435 | 
            +
                def emit_comp(inst, usiginst, node)
         | 
| 1436 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1437 | 
            +
                  # SAVE;
         | 
| 1438 | 
            +
                  if Type.is_flotype(node.left.ty)
         | 
| 1439 | 
            +
                    emit_expr(node.left)
         | 
| 1440 | 
            +
                    push_xmm(0)
         | 
| 1441 | 
            +
                    emit_expr(node.right)
         | 
| 1442 | 
            +
                    pop_xmm(1)
         | 
| 1443 | 
            +
                    if node.left.ty.kind == Kind::FLOAT
         | 
| 1444 | 
            +
                      emit("ucomiss #xmm0, #xmm1")
         | 
| 1445 | 
            +
                    else
         | 
| 1446 | 
            +
                      emit("ucomisd #xmm0, #xmm1")
         | 
| 1447 | 
            +
                    end
         | 
| 1448 | 
            +
                  else
         | 
| 1449 | 
            +
                    emit_expr(node.left)
         | 
| 1450 | 
            +
                    push("rax")
         | 
| 1451 | 
            +
                    emit_expr(node.right)
         | 
| 1452 | 
            +
                    pop("rcx")
         | 
| 1453 | 
            +
                    kind = node.left.ty.kind
         | 
| 1454 | 
            +
                    if (kind == Kind::LONG) || (kind == Kind::LLONG)
         | 
| 1455 | 
            +
                      emit("cmp #rax, #rcx")
         | 
| 1456 | 
            +
                    else
         | 
| 1457 | 
            +
                      emit("cmp #eax, #ecx")
         | 
| 1458 | 
            +
                    end
         | 
| 1459 | 
            +
                  end
         | 
| 1460 | 
            +
                  if Type.is_flotype(node.left.ty) || node.left.ty.usig
         | 
| 1461 | 
            +
                    emit("#{usiginst} #al")
         | 
| 1462 | 
            +
                  else
         | 
| 1463 | 
            +
                    emit("#{inst} #al")
         | 
| 1464 | 
            +
                  end
         | 
| 1465 | 
            +
                  emit("movzb #al, #eax")
         | 
| 1466 | 
            +
                end
         | 
| 1467 | 
            +
             | 
| 1468 | 
            +
                # @param [Node] node
         | 
| 1469 | 
            +
                # @param [String] op
         | 
| 1470 | 
            +
                def emit_pre_inc_dec(node, op)
         | 
| 1471 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1472 | 
            +
                  # SAVE;
         | 
| 1473 | 
            +
                  emit_expr(node.operand)
         | 
| 1474 | 
            +
                  emit("#{op} $#{node.ty.ptr ? node.ty.ptr.size : 1}, #rax")
         | 
| 1475 | 
            +
                  emit_store(node.operand)
         | 
| 1476 | 
            +
                end
         | 
| 1477 | 
            +
             | 
| 1478 | 
            +
                # @param [Node] node
         | 
| 1479 | 
            +
                # @param [String] op
         | 
| 1480 | 
            +
                def emit_post_inc_dec(node, op)
         | 
| 1481 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1482 | 
            +
                  # SAVE;
         | 
| 1483 | 
            +
                  emit_expr(node.operand)
         | 
| 1484 | 
            +
                  push("rax")
         | 
| 1485 | 
            +
                  emit("#{op} $#{node.ty.ptr ? node.ty.ptr.size : 1}, #rax")
         | 
| 1486 | 
            +
                  emit_store(node.operand)
         | 
| 1487 | 
            +
                  pop("rax")
         | 
| 1488 | 
            +
                end
         | 
| 1489 | 
            +
             | 
| 1490 | 
            +
                # @param [Node] node
         | 
| 1491 | 
            +
                def emit_lognot(node)
         | 
| 1492 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1493 | 
            +
                  # SAVE;
         | 
| 1494 | 
            +
                  emit_expr(node.operand)
         | 
| 1495 | 
            +
                  emit("cmp $0, #rax")
         | 
| 1496 | 
            +
                  emit("sete #al")
         | 
| 1497 | 
            +
                  emit("movzb #al, #eax")
         | 
| 1498 | 
            +
                end
         | 
| 1499 | 
            +
             | 
| 1500 | 
            +
                # @param [Node] node
         | 
| 1501 | 
            +
                def emit_logand(node)
         | 
| 1502 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1503 | 
            +
                  # SAVE;
         | 
| 1504 | 
            +
                  e = @label_gen.next
         | 
| 1505 | 
            +
                  emit_expr(node.left)
         | 
| 1506 | 
            +
                  emit("test #rax, #rax")
         | 
| 1507 | 
            +
                  emit("mov $0, #rax")
         | 
| 1508 | 
            +
                  emit("je #{e}")
         | 
| 1509 | 
            +
                  emit_expr(node.right)
         | 
| 1510 | 
            +
                  emit("test #rax, #rax")
         | 
| 1511 | 
            +
                  emit("mov $0, #rax")
         | 
| 1512 | 
            +
                  emit("je #{e}")
         | 
| 1513 | 
            +
                  emit("mov $1, #rax")
         | 
| 1514 | 
            +
                  emit_label(e)
         | 
| 1515 | 
            +
                end
         | 
| 1516 | 
            +
             | 
| 1517 | 
            +
                # @param [Node] node
         | 
| 1518 | 
            +
                def emit_logor(node)
         | 
| 1519 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1520 | 
            +
                  # SAVE;
         | 
| 1521 | 
            +
                  e = @label_gen.next
         | 
| 1522 | 
            +
                  emit_expr(node.left)
         | 
| 1523 | 
            +
                  emit("test #rax, #rax")
         | 
| 1524 | 
            +
                  emit("mov $1, #rax")
         | 
| 1525 | 
            +
                  emit("jne #{e}")
         | 
| 1526 | 
            +
                  emit_expr(node.right)
         | 
| 1527 | 
            +
                  emit("test #rax, #rax")
         | 
| 1528 | 
            +
                  emit("mov $1, #rax")
         | 
| 1529 | 
            +
                  emit("jne #{e}")
         | 
| 1530 | 
            +
                  emit("mov $0, #rax")
         | 
| 1531 | 
            +
                  emit_label(e)
         | 
| 1532 | 
            +
                end
         | 
| 1533 | 
            +
             | 
| 1534 | 
            +
                # @param [Node] node
         | 
| 1535 | 
            +
                def emit_cast(node)
         | 
| 1536 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1537 | 
            +
                  # SAVE;
         | 
| 1538 | 
            +
                  emit_expr(node.operand)
         | 
| 1539 | 
            +
                  emit_load_convert(node.ty, node.operand.ty)
         | 
| 1540 | 
            +
                end
         | 
| 1541 | 
            +
             | 
| 1542 | 
            +
                # @param [Node]
         | 
| 1543 | 
            +
                def emit_bitand(node)
         | 
| 1544 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1545 | 
            +
                  # SAVE;
         | 
| 1546 | 
            +
                  emit_expr(node.left)
         | 
| 1547 | 
            +
                  push("rax")
         | 
| 1548 | 
            +
                  emit_expr(node.right)
         | 
| 1549 | 
            +
                  pop("rcx")
         | 
| 1550 | 
            +
                  emit("and #rcx, #rax")
         | 
| 1551 | 
            +
                end
         | 
| 1552 | 
            +
             | 
| 1553 | 
            +
                # @param [Node]
         | 
| 1554 | 
            +
                def emit_bitor(node)
         | 
| 1555 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1556 | 
            +
                  # SAVE;
         | 
| 1557 | 
            +
                  emit_expr(node.left)
         | 
| 1558 | 
            +
                  push("rax")
         | 
| 1559 | 
            +
                  emit_expr(node.right)
         | 
| 1560 | 
            +
                  pop("rcx")
         | 
| 1561 | 
            +
                  emit("or #rcx, #rax")
         | 
| 1562 | 
            +
                end
         | 
| 1563 | 
            +
             | 
| 1564 | 
            +
                # @param [Node] node
         | 
| 1565 | 
            +
                def emit_bitnot(node)
         | 
| 1566 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1567 | 
            +
                  # SAVE;
         | 
| 1568 | 
            +
                  emit_expr(node.operand)
         | 
| 1569 | 
            +
                  emit("not #rax")
         | 
| 1570 | 
            +
                end
         | 
| 1571 | 
            +
             | 
| 1572 | 
            +
                # @param [Node] struct
         | 
| 1573 | 
            +
                # @param [Type] field
         | 
| 1574 | 
            +
                # @param [Integer] off
         | 
| 1575 | 
            +
                def emit_load_struct_ref(struct, field, off)
         | 
| 1576 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1577 | 
            +
                  # SAVE;
         | 
| 1578 | 
            +
                  case struct.kind
         | 
| 1579 | 
            +
                  when AST::LVAR
         | 
| 1580 | 
            +
                    ensure_lvar_init(struct)
         | 
| 1581 | 
            +
                    emit_lload(field, "rbp", struct.loff + field.offset + off)
         | 
| 1582 | 
            +
                  when AST::GVAR
         | 
| 1583 | 
            +
                    emit_gload(field, struct.glabel, field.offset + off)
         | 
| 1584 | 
            +
                  when AST::STRUCT_REF
         | 
| 1585 | 
            +
                    emit_load_struct_ref(struct.struct, field, struct.ty.offset + off)
         | 
| 1586 | 
            +
                  when AST::DEREF
         | 
| 1587 | 
            +
                    emit_expr(struct.operand)
         | 
| 1588 | 
            +
                    emit_lload(field, "rax", field.offset + off)
         | 
| 1589 | 
            +
                  else
         | 
| 1590 | 
            +
                    raise "internal error: #{struct}"
         | 
| 1591 | 
            +
                  end
         | 
| 1592 | 
            +
                end
         | 
| 1593 | 
            +
             | 
| 1594 | 
            +
                # @param [Node] node
         | 
| 1595 | 
            +
                def emit_comma(node)
         | 
| 1596 | 
            +
                  # TODO(south37) impl SAVE when necessary
         | 
| 1597 | 
            +
                  # SAVE;
         | 
| 1598 | 
            +
                  emit_expr(node.left)
         | 
| 1599 | 
            +
                  emit_expr(node.right)
         | 
| 1600 | 
            +
                end
         | 
| 1601 | 
            +
              end
         | 
| 1602 | 
            +
            end
         |