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
|