tombagby-llvmruby 0.0.1

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.
data/lib/llvm.rb ADDED
@@ -0,0 +1,142 @@
1
+ require 'llvmruby'
2
+
3
+ class Fixnum
4
+ def llvm(type = LLVM::MACHINE_WORD)
5
+ LLVM::Value.get_constant(type, self)
6
+ end
7
+ end
8
+
9
+ class Float
10
+ def llvm
11
+ LLVM::Value.get_float_constant(self)
12
+ end
13
+ end
14
+
15
+ class Object
16
+ def immediate
17
+ LLVM::Value.get_immediate_constant(self)
18
+ end
19
+ end
20
+
21
+ class LLVM::Value
22
+ def llvm
23
+ self
24
+ end
25
+
26
+ def immediate
27
+ self
28
+ end
29
+ end
30
+
31
+ module LLVM
32
+ class Builder
33
+ def self.add_bin_op(op)
34
+ define_method(op.downcase) do |x, y|
35
+ bin_op(Instruction.const_get(op), x, y)
36
+ end
37
+ end
38
+
39
+ bin_ops = ['Add', 'Sub', 'Mul', 'UDiv', 'SDiv', 'FDiv', 'URem', 'SRem', 'FRem']
40
+ bin_ops += ['Shl', 'LShr', 'AShr', 'And', 'Or', 'Xor']
41
+ bin_ops.each {|op| add_bin_op(op)}
42
+
43
+ Instruction.constants.grep(/^ICMP_/) do |pred|
44
+ define_method(pred.downcase) do |x, y|
45
+ icmp(Instruction.const_get(pred), x, y)
46
+ end
47
+ end
48
+
49
+ Instruction.constants.grep(/^FCMP_/) do |pred|
50
+ define_method(pred.downcase) do |x, y|
51
+ fcmp(Instruction.const_get(pred), x, y)
52
+ end
53
+ end
54
+
55
+ def self.define_cast(name, inst)
56
+ define_method(name) do |val, dest_type|
57
+ cast(inst, val, dest_type)
58
+ end
59
+ end
60
+
61
+ define_cast(:trunc, Instruction::Trunc)
62
+ define_cast(:zext, Instruction::ZExt)
63
+ define_cast(:sext, Instruction::SExt)
64
+ define_cast(:fp_to_si, Instruction::FPToSI)
65
+ define_cast(:fp_to_ui, Instruction::FPToUI)
66
+ define_cast(:ui_to_fp, Instruction::UIToFP)
67
+ define_cast(:si_to_fp, Instruction::SIToFP)
68
+ define_cast(:fp_trunc, Instruction::FPTrunc)
69
+ define_cast(:fp_ext, Instruction::FPExt)
70
+ define_cast(:ptr_to_int, Instruction::PtrToInt)
71
+ define_cast(:int_to_ptr, Instruction::IntToPtr)
72
+ define_cast(:bit_cast, Instruction::BitCast)
73
+
74
+ def write(&b)
75
+ instance_eval(&b)
76
+ end
77
+ end
78
+
79
+ # describe structures used by the ruby 1.8/1.9 interpreters
80
+ module RubyInternals
81
+ FIXNUM_FLAG = 0x1.llvm
82
+ CHAR = Type::Int8Ty
83
+ P_CHAR = Type::pointer(CHAR)
84
+ LONG = MACHINE_WORD
85
+ INT = Type::Int32Ty
86
+ VALUE = MACHINE_WORD
87
+ P_VALUE = Type::pointer(VALUE)
88
+ ID = MACHINE_WORD
89
+ RBASIC = Type::struct([VALUE, VALUE])
90
+ RARRAY = Type::struct([RBASIC, LONG, LONG, P_VALUE])
91
+ P_RARRAY = Type::pointer(RARRAY)
92
+ RSTRING = Type::struct([RBASIC, LONG, P_CHAR, VALUE])
93
+ P_RSTRING = Type::pointer(RSTRING)
94
+ end
95
+
96
+ # include this into the builder to get methods for manipulating ruby values
97
+ module RubyHelpers
98
+ include RubyInternals
99
+
100
+ def fixnum?(val)
101
+ self.and(FIXNUM_FLAG, val)
102
+ end
103
+
104
+ def num2fix(val)
105
+ shifted = shl(val, 1.llvm)
106
+ xor(FIXNUM_FLAG, shifted)
107
+ end
108
+
109
+ def fix2int(val)
110
+ x = xor(FIXNUM_FLAG, val)
111
+ lshr(val, 1.llvm)
112
+ end
113
+
114
+ def slen(str)
115
+ val_ptr = int_to_ptr(str, P_RSTRING)
116
+ len_ptr = struct_gep(val_ptr, 1)
117
+ load(len_ptr)
118
+ end
119
+
120
+ def alen(ary)
121
+ val_ptr = int_to_ptr(ary, P_RARRAY)
122
+ len_ptr = struct_gep(val_ptr, 1)
123
+ load(len_ptr)
124
+ end
125
+
126
+ def aref(ary, idx)
127
+ val_ptr = int_to_ptr(ary, P_RARRAY)
128
+ data_ptr = struct_gep(val_ptr, 3)
129
+ data_ptr = load(data_ptr)
130
+ slot_n = gep(data_ptr, idx.llvm)
131
+ load(slot_n)
132
+ end
133
+
134
+ def aset(ary, idx, set)
135
+ val_ptr = int_to_ptr(ary, P_RARRAY)
136
+ data_ptr = struct_gep(val_ptr, 3)
137
+ data_ptr = load(data_ptr)
138
+ slot_n = gep(data_ptr, idx.llvm)
139
+ store(set, slot_n)
140
+ end
141
+ end
142
+ end
data/lib/ruby_vm.rb ADDED
@@ -0,0 +1,352 @@
1
+ require 'llvm'
2
+ include LLVM
3
+ include RubyInternals
4
+
5
+ class Symbol
6
+ # turn a symbol object_id into a VALUE
7
+ # from gc.c, symbols object_id's are calculated like this:
8
+ # SYM2ID(x) = RSHIFT((unsigned long)x,8)
9
+ # object_id = (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
10
+ def llvm
11
+ (((object_id/20) << 8) | 0xe).llvm(MACHINE_WORD)
12
+ end
13
+ end
14
+
15
+ class Object
16
+ def llvm
17
+ LLVM::Value.get_immediate_constant(self)
18
+ end
19
+
20
+ def llvm_send(f)
21
+ # for now, pass the receiver as the first argument
22
+ ExecutionEngine.runFunction(f, self)
23
+ end
24
+ end
25
+
26
+ class Builder
27
+ include RubyHelpers
28
+
29
+ def self.set_globals(b)
30
+ @@stack = b.alloca(VALUE, 100)
31
+ @@stack_ptr = b.alloca(P_VALUE, 0)
32
+ b.store(@@stack, @@stack_ptr)
33
+ @@locals = b.alloca(VALUE, 100)
34
+ end
35
+
36
+ def stack
37
+ @@stack
38
+ end
39
+
40
+ def stack_ptr
41
+ @@stack_ptr
42
+ end
43
+
44
+ def push(val)
45
+ sp = load(stack_ptr)
46
+ store(val, sp)
47
+ new_sp = gep(sp, 1.llvm)
48
+ store(new_sp, stack_ptr)
49
+ end
50
+
51
+ def pop
52
+ sp = load(stack_ptr)
53
+ new_sp = gep(sp, -1.llvm)
54
+ store(new_sp, stack_ptr)
55
+ load(new_sp)
56
+ end
57
+
58
+ def peek(n = 1)
59
+ sp = load(stack_ptr)
60
+ peek_sp = gep(sp, (-n).llvm)
61
+ load(peek_sp)
62
+ end
63
+
64
+ def topn(n)
65
+ sp = load(stack_ptr)
66
+ idx = sub((-1).llvm(Type::Int32Ty), n)
67
+ top_sp = gep(sp, idx)
68
+ load(top_sp)
69
+ end
70
+
71
+ def locals
72
+ @@locals
73
+ end
74
+ end
75
+
76
+ class OpCodeBuilder
77
+ def initialize(mod, func, rb_funcs)
78
+ @mod = mod
79
+ @func = func
80
+ @rb_funcs = rb_funcs
81
+ end
82
+
83
+ def get_self
84
+ @func.arguments.first
85
+ end
86
+
87
+ def nop(b, oprnd)
88
+ end
89
+
90
+ def putnil(b, oprnd)
91
+ b.push(nil.immediate)
92
+ end
93
+
94
+ def putself(b, oprnd)
95
+ b.push(get_self)
96
+ end
97
+
98
+ def putobject(b, oprnd)
99
+ b.push(oprnd.llvm)
100
+ end
101
+
102
+ def pop(b, oprnd)
103
+ b.pop
104
+ end
105
+
106
+ def dup(b, oprnd)
107
+ b.push(b.peek)
108
+ end
109
+
110
+ def swap(b, oprn)
111
+ v1 = b.pop
112
+ v2 = b.pop
113
+ b.push(v1)
114
+ b.push(v2)
115
+ end
116
+
117
+ def setlocal(b, oprnd)
118
+ v = b.pop
119
+ local_slot = b.gep(b.locals, oprnd.llvm)
120
+ b.store(v, local_slot)
121
+ end
122
+
123
+ def getlocal(b, oprnd)
124
+ local_slot = b.gep(b.locals, oprnd.llvm)
125
+ val = b.load(local_slot)
126
+ b.push(val)
127
+ end
128
+
129
+ def opt_plus(b, oprnd)
130
+ v1 = b.fix2int(b.pop)
131
+ v2 = b.fix2int(b.pop)
132
+ sum = b.add(v1, v2)
133
+ b.push(b.num2fix(sum))
134
+ end
135
+
136
+ def opt_minus(b, oprnd)
137
+ v1 = b.fix2int(b.pop)
138
+ v2 = b.fix2int(b.pop)
139
+ sum = b.sub(v2, v1)
140
+ b.push(b.num2fix(sum))
141
+ end
142
+
143
+ def opt_mult(b, oprnd)
144
+ v1 = b.fix2int(b.pop)
145
+ v2 = b.fix2int(b.pop)
146
+ mul = b.mul(v1, v2)
147
+ b.push(b.num2fix(mul))
148
+ end
149
+
150
+ def opt_aref(b, oprnd)
151
+ idx = b.fix2int(b.pop)
152
+ ary = b.pop
153
+ out = b.aref(ary, idx)
154
+ b.push(out)
155
+ end
156
+
157
+ def opt_aset(b, oprnd)
158
+ set = b.pop
159
+ idx = b.fix2int(b.pop)
160
+ ary = b.pop
161
+ b.call(@rb_funcs[:rb_ary_store], ary, idx, set)
162
+ b.push(set)
163
+ end
164
+
165
+ def opt_length(b, oprnd)
166
+ recv = b.pop
167
+ len = b.alen(recv)
168
+ len = b.num2fix(len)
169
+ b.push(len)
170
+ end
171
+
172
+ def opt_lt(b, oprnd)
173
+ obj = b.pop
174
+ recv = b.pop
175
+ x = b.fix2int(recv)
176
+ y = b.fix2int(obj)
177
+ val = b.icmp_slt(x, y)
178
+ val = b.int_cast(val, LONG, false)
179
+ val = b.mul(val, 2.llvm)
180
+ b.push(val)
181
+ end
182
+
183
+ def opt_gt(b, oprnd)
184
+ obj = b.pop
185
+ recv = b.pop
186
+ x = b.fix2int(recv)
187
+ y = b.fix2int(obj)
188
+ val = b.icmp_sgt(x, y)
189
+ val = b.int_cast(val, LONG, false)
190
+ val = b.mul(val, 2.llvm)
191
+ b.push(val)
192
+ end
193
+
194
+ def opt_ge(b, oprnd)
195
+ obj = b.pop
196
+ recv = b.pop
197
+ x = b.fix2int(recv)
198
+ y = b.fix2int(obj)
199
+ val = b.icmp_sge(x, y)
200
+ val = b.int_cast(val, LONG, false)
201
+ val = b.mul(val, 2.llvm)
202
+ b.push(val)
203
+ end
204
+
205
+ def getinstancevariable(b, oprnd)
206
+ id = b.call(@rb_funcs[:rb_to_id], oprnd.llvm)
207
+ v = b.call(@rb_funcs[:rb_ivar_get], get_self, id)
208
+ b.push(v)
209
+ end
210
+
211
+ def setinstancevariable(b, oprnd)
212
+ new_val = b.peek
213
+ id = b.call(@rb_funcs[:rb_to_id], oprnd.llvm)
214
+ b.call(@rb_funcs[:rb_ivar_set], get_self, id, new_val)
215
+ end
216
+
217
+ def newarray(b, oprnd)
218
+ ary = b.call(@rb_funcs[:rb_ary_new])
219
+ b.push(ary)
220
+ end
221
+
222
+ def newhash(b, oprnd)
223
+ hash = b.call(@rb_funcs[:rb_hash_new])
224
+ i = oprnd.llvm(Type::Int32Ty) # This is an integer not a fixnum
225
+
226
+ entry_block = @func.create_block
227
+ loop_block = @func.create_block
228
+ exit_block = @func.create_block
229
+
230
+ b.br(entry_block)
231
+ b.set_insert_point(entry_block)
232
+ cmp = b.icmp_sgt(i, 0.llvm(Type::Int32Ty))
233
+ b.cond_br(cmp, loop_block, exit_block)
234
+
235
+ b.set_insert_point(loop_block)
236
+ idx = b.phi(Type::Int32Ty)
237
+ idx.add_incoming(i, entry_block)
238
+ next_idx = b.sub(idx, 2.llvm(Type::Int32Ty))
239
+ idx.add_incoming(next_idx, loop_block)
240
+
241
+ n_1 = b.sub(idx, 1.llvm(Type::Int32Ty))
242
+ n_2 = b.sub(idx, 2.llvm(Type::Int32Ty))
243
+ b.call(@rb_funcs[:rb_hash_aset], hash, b.topn(n_1), b.topn(n_2))
244
+
245
+ cmp = b.icmp_sgt(next_idx, 0.llvm(Type::Int32Ty))
246
+ b.cond_br(cmp, loop_block, exit_block)
247
+
248
+ b.set_insert_point(exit_block)
249
+ b.push(hash)
250
+ end
251
+
252
+ def send(b, oprnd)
253
+ recv = nil.immediate
254
+ id = b.call(@rb_funcs[:rb_to_id], :inspect.immediate)
255
+ argc = 0.llvm(Type::Int32Ty)
256
+ val = b.call(@rb_funcs[:rb_funcall2], recv, id, argc, b.stack)
257
+ b.push(val)
258
+ end
259
+ end
260
+
261
+ class RubyVM
262
+ def self.start
263
+ @module = LLVM::Module.new('ruby_vm')
264
+ ExecutionEngine.get(@module)
265
+
266
+ @rb_ary_new = @module.external_function('rb_ary_new', ftype(VALUE, []))
267
+ @rb_hash_new = @module.external_function('rb_hash_new', ftype(VALUE, []))
268
+ @rb_hash_aset = @module.external_function('rb_hash_aset', ftype(VALUE, [VALUE, VALUE, VALUE]))
269
+ @rb_ary_store = @module.external_function('rb_ary_store', ftype(VALUE, [VALUE, LONG, VALUE]))
270
+ @rb_to_id = @module.external_function('rb_to_id', ftype(VALUE, [VALUE]))
271
+ @rb_ivar_get = @module.external_function('rb_ivar_get', ftype(VALUE, [VALUE, ID]))
272
+ @rb_ivar_set = @module.external_function('rb_ivar_set', ftype(VALUE, [VALUE, ID, VALUE]))
273
+ @rb_funcall2 = @module.external_function('rb_funcall2', ftype(VALUE, [VALUE, ID, INT, P_VALUE]))
274
+
275
+ @rb_funcs = {
276
+ :rb_ary_new => @rb_ary_new,
277
+ :rb_hash_new => @rb_hash_new,
278
+ :rb_hash_aset => @rb_hash_aset,
279
+ :rb_ary_store => @rb_ary_store,
280
+ :rb_to_id => @rb_to_id,
281
+ :rb_ivar_get => @rb_ivar_get,
282
+ :rb_ivar_set => @rb_ivar_set,
283
+ :rb_funcall2 => @rb_funcall2
284
+ }
285
+
286
+ @func_n = 0
287
+ end
288
+
289
+ def self.ftype(ret, args)
290
+ Type.function(ret, args)
291
+ end
292
+
293
+ def self.call_bytecode(bytecode, farg)
294
+ f = compile_bytecode(bytecode)
295
+ ExecutionEngine.run_function(f, nil, farg)
296
+ end
297
+
298
+ def self.method_send(recv, compiled_method, farg = nil)
299
+ ExecutionEngine.run_function(compiled_method, recv, farg)
300
+ end
301
+
302
+ def self.compile_bytecode(bytecode)
303
+ f = @module.get_or_insert_function("vm_func#{@func_n}", Type.function(VALUE, [VALUE, VALUE]))
304
+ @func_n += 1
305
+
306
+ get_self = f.arguments[0]
307
+
308
+ entry_block = f.create_block
309
+ b = entry_block.builder
310
+ Builder.set_globals(b)
311
+ b.push(f.arguments[1])
312
+
313
+ blocks = bytecode.map { f.create_block }
314
+ exit_block = f.create_block
315
+ blocks << exit_block
316
+ b.br(blocks.first)
317
+
318
+ op_builder = OpCodeBuilder.new(@module, f, @rb_funcs)
319
+
320
+ bytecode.each_with_index do |opcode, i|
321
+ op, arg = opcode
322
+
323
+ block = blocks[i]
324
+ b.set_insert_point(block)
325
+
326
+ case op
327
+ when :jump
328
+ b.br(blocks[arg])
329
+ when :branchif
330
+ v = b.pop
331
+ cmp = b.icmp_eq(v, 0.llvm)
332
+ b.cond_br(cmp, blocks[i+1], blocks[arg])
333
+ when :branchunless
334
+ v = b.pop
335
+ cmp = b.icmp_eq(v, 0.llvm)
336
+ b.cond_br(cmp, blocks[arg], blocks[i+1])
337
+ else
338
+ op_builder.__send__(op, b, arg)
339
+ end
340
+
341
+ if op != :jump && op != :branchif && op != :branchunless
342
+ b.br(blocks[i+1])
343
+ end
344
+ end
345
+
346
+ b = exit_block.builder
347
+ ret_val = b.pop
348
+ b.return(ret_val)
349
+
350
+ f
351
+ end
352
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,11 @@
1
+ module LLVM
2
+
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 0
6
+ TINY = 1
7
+
8
+ STRING = [ MAJOR, MINOR, TINY ].join( "." )
9
+ end
10
+
11
+ end
data/test/byteswap.bc ADDED
Binary file