-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathemitter.rb
executable file
·172 lines (139 loc) · 2.81 KB
/
emitter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
class Emitter
PTR_SIZE = 4
attr_accessor :seq
def initialize
@seq = 0
end
def export(label,type=nil)
puts ".globl #{label}"
puts "\t.type\t#{label}, @#{type.to_s}"
end
def rodata
emit(".section",".rodata")
yield
end
def local_arg(aparam)
"#{PTR_SIZE*(aparam+2)}(%ebp)"
end
def local_var(aparam)
"-#{PTR_SIZE*(aparam+2)}(%ebp)"
end
def label(l)
puts "#{l.to_s}:"
l
end
def local(l=nil)
l = get_local if !l
label(l)
end
def int_value param
return "$#{param.to_i}"
end
def addr_value param
return "$#{param.to_s}"
end
def result_value
return :eax
end
def to_operand_value src
return int_value(src) if src.is_a?(Fixnum)
return "%#{src.to_s}" if src.is_a?(Symbol)
return src.to_s
end
# Store "param" in stack slot "i"
def save_to_stack param,i
movl(param,"#{i>0 ? i*4 : ""}(%esp)")
end
def save_result(param)
movl(param,:eax) if param != :eax
end
def load_arg(aparam)
movl(local_arg(aparam),:eax)
end
def load_arg_address(aparam)
leal(local_arg(aparam),:eax)
end
def load_local_var(aparam)
movl(local_var(aparam),:eax)
end
def save_to_local_var(arg,aparam)
movl(arg,local_var(aparam))
end
def save_to_arg(arg,aparam)
movl(arg,local_arg(aparam))
end
def load_address(label)
save_result(addr_value(label))
end
def with_local(args)
# FIXME: The "+1" is a hack because main contains a pushl %ecx
with_stack(args+1) { yield }
end
def with_stack(args,numargs=false)
adj = PTR_SIZE + (((args+0.5)*PTR_SIZE/(4.0*PTR_SIZE)).round) * (4*PTR_SIZE)
subl(adj,:esp)
movl(args,:ebx) if numargs
yield
addl(adj,:esp)
end
def emit op,*args
puts "\t#{op}\t"+args.collect{|a|to_operand_value(a)}.join(', ')
end
def method_missing(sym,*args)
emit(sym,*args)
end
def call loc
if loc.is_a?(Symbol)
emit(:call,"*"+to_operand_value(loc))
else
emit(:call,loc)
end
end
def string l,str
local(l)
emit(".string","\"#{str}\"")
end
def jmp_on_false(label,op=:eax)
testl(op,op)
je(label)
end
def get_local
@seq +=1
".L#{@seq-1}"
end
def loop
br = get_local
l = local
yield(br)
jmp(l)
local(br)
end
def func name, save_numargs = false
export(name,:function) if name.to_s[0] != ?.
label(name)
pushl(:ebp)
movl(:esp,:ebp)
pushl(:ebx) if save_numargs
yield
leave
ret
emit(".size",name.to_s, ".-#{name}")
end
def main
puts ".text"
export(:main,:function)
label(:main)
leal("4(%esp)",:ecx)
andl(-16,:esp)
pushl("-4(%ecx)")
pushl(:ebp)
movl(:esp,:ebp)
pushl(:ecx)
yield
popl(:ecx)
popl(:ebp)
leal("-4(%ecx)",:esp)
ret()
emit(".size","main",".-main")
end
end