ruby-libjit 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.
data/lib/jit/value.rb ADDED
@@ -0,0 +1,199 @@
1
+ require 'jit'
2
+
3
+ module JIT
4
+ class Value
5
+ module UNINITIALIZED; end
6
+
7
+ # Create a new JIT::Value. If value is specified, the value will be
8
+ # variable, otherwise it will be a constant with the given value.
9
+ #
10
+ # +function+:: The function to which this value will belong.
11
+ # +type+:: The type of the new value.
12
+ # +value+: The value to use, if this is a constant.
13
+ #
14
+ def self.new(function, type, value=UNINITIALIZED)
15
+ # TODO: Not sure if I like this...
16
+ if value == UNINITIALIZED then
17
+ return function.value(type)
18
+ else
19
+ return function.const(type, value)
20
+ end
21
+ end
22
+
23
+ # Assign +value+ to this JIT::Value.
24
+ #
25
+ # +value+:: The value to assign.
26
+ #
27
+ def store(value)
28
+ lhs, rhs = coerce(value)
29
+ self.function.insn_store(lhs, rhs)
30
+ end
31
+
32
+ # Return the address of this value.
33
+ def address
34
+ return self.function.insn_address_of(self)
35
+ end
36
+
37
+ # Add this value to another and return the result.
38
+ #
39
+ # +rhs+:: The right hand side of the addition operator.
40
+ #
41
+ def +(rhs)
42
+ lhs, rhs = coerce(rhs)
43
+ return self.function.insn_add(lhs, rhs)
44
+ end
45
+
46
+ # Subtract another value from this one and return the result.
47
+ #
48
+ # +rhs+:: The right hand side of the subtraction operator.
49
+ #
50
+ def -(rhs)
51
+ lhs, rhs = coerce(rhs)
52
+ return self.function.insn_sub(lhs, rhs)
53
+ end
54
+
55
+ # Multiply this value by another and return the result.
56
+ #
57
+ # +rhs+:: The right hand side of the multiplication operator.
58
+ #
59
+ def *(rhs)
60
+ lhs, rhs = coerce(rhs)
61
+ return self.function.insn_mul(lhs, rhs)
62
+ end
63
+
64
+ # Divide this value by another and return the quotient.
65
+ #
66
+ # +rhs+:: The right hand side of the division operator.
67
+ #
68
+ def /(rhs)
69
+ lhs, rhs = coerce(rhs)
70
+ return self.function.insn_div(lhs, rhs)
71
+ end
72
+
73
+ # Return the additive inverse (negation) of this value.
74
+ def -@()
75
+ rhs, lhs = coerce(0) # inverted, since we are subtracting from 0
76
+ return lhs - rhs
77
+ end
78
+
79
+ # Divide this value by another and return the remainder.
80
+ #
81
+ # +rhs+:: The right hand side of the modulus operator.
82
+ #
83
+ def %(rhs)
84
+ lhs, rhs = coerce(rhs)
85
+ return self.function.insn_rem(lhs, rhs)
86
+ end
87
+
88
+ # Perform a bitwise and between this value and another.
89
+ #
90
+ # +rhs+:: The right hand side of the operator.
91
+ #
92
+ def &(rhs)
93
+ lhs, rhs = coerce(rhs)
94
+ return self.function.insn_and(lhs, rhs)
95
+ end
96
+
97
+ # Perform a bitwise or between this value and another.
98
+ #
99
+ # +rhs+:: The right hand side of the operator.
100
+ #
101
+ def |(rhs)
102
+ lhs, rhs = coerce(rhs)
103
+ return self.function.insn_or(lhs, rhs)
104
+ end
105
+
106
+ # Perform a bitwise xor between this value and another.
107
+ #
108
+ # +rhs+:: The right hand side of the operator.
109
+ #
110
+ def ^(rhs)
111
+ lhs, rhs = coerce(rhs)
112
+ return self.function.insn_xor(lhs, rhs)
113
+ end
114
+
115
+ # Compare this value to another, returning 1 if the left hand is
116
+ # less than the right hand side or 0 otherwise.
117
+ #
118
+ # +rhs+:: The right hand side of the comparison.
119
+ #
120
+ def <(rhs)
121
+ lhs, rhs = coerce(rhs)
122
+ return self.function.insn_lt(lhs, rhs)
123
+ end
124
+
125
+ # Compare this value to another, returning 1 if the left hand is
126
+ # greater than the right hand side or 0 otherwise.
127
+ #
128
+ # +rhs+:: The right hand side of the comparison.
129
+ #
130
+ def >(rhs)
131
+ lhs, rhs = coerce(rhs)
132
+ return self.function.insn_gt(lhs, rhs)
133
+ end
134
+
135
+ # Compare this value to another, returning 1 if the left hand is
136
+ # equal to the right hand side or 0 otherwise.
137
+ #
138
+ # +rhs+:: The right hand side of the comparison.
139
+ #
140
+ def ==(rhs)
141
+ lhs, rhs = coerce(rhs)
142
+ return self.function.insn_eq(lhs, rhs)
143
+ end
144
+
145
+ # Compare this value to another, returning 1 if the left hand is
146
+ # not equal to the right hand side or 0 otherwise.
147
+ #
148
+ # +rhs+:: The right hand side of the comparison.
149
+ #
150
+ def neq(rhs)
151
+ lhs, rhs = coerce(rhs)
152
+ return self.function.insn_ne(lhs, rhs)
153
+ end
154
+
155
+ # Compare this value to another, returning 1 if the left hand is
156
+ # less than or equal to the right hand side or 0 otherwise.
157
+ #
158
+ # +rhs+:: The right hand side of the comparison.
159
+ #
160
+ def <=(rhs)
161
+ lhs, rhs = coerce(rhs)
162
+ return self.function.insn_le(lhs, rhs)
163
+ end
164
+
165
+ # Compare this value to another, returning 1 if the left hand is
166
+ # greater than or equal to the right hand side or 0 otherwise.
167
+ #
168
+ # +rhs+:: The right hand side of the comparison.
169
+ #
170
+ def >=(rhs)
171
+ lhs, rhs = coerce(rhs)
172
+ return self.function.insn_ge(lhs, rhs)
173
+ end
174
+
175
+ # Shift this value left by the given number of bits.
176
+ #
177
+ # +rhs+:: The number of bits to shift by.
178
+ #
179
+ def <<(rhs)
180
+ lhs, rhs = coerce(rhs)
181
+ return self.function.insn_shl(lhs, rhs)
182
+ end
183
+
184
+ # Shift this value right by the given number of bits.
185
+ #
186
+ # +rhs+:: The number of bits to shift by.
187
+ #
188
+ def >>(rhs)
189
+ lhs, rhs = coerce(rhs)
190
+ return self.function.insn_shr(lhs, rhs)
191
+ end
192
+
193
+ # Return the logical inverse of this value.
194
+ def ~()
195
+ return self.function.insn_not(self)
196
+ end
197
+ end
198
+ end
199
+
data/lib/jit.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'jit.so'
2
+ require 'jit/array'
3
+ require 'jit/function'
4
+ require 'jit/struct'
5
+ require 'jit/value'
data/sample/fib.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'jit'
2
+
3
+ fib = nil
4
+ signature = JIT::Type.create_signature(
5
+ JIT::ABI::CDECL,
6
+ JIT::Type::INT,
7
+ [ JIT::Type::INT ])
8
+ fib = JIT::Function.build(signature) do |f|
9
+ n = f.param(0)
10
+
11
+ a = f.value(JIT::Type::INT, 0)
12
+ b = f.value(JIT::Type::INT, 1)
13
+ c = f.value(JIT::Type::INT, 1)
14
+
15
+ i = f.value(JIT::Type::INT, 0)
16
+
17
+ f.while(proc { i < n }) {
18
+ c.store(a + b)
19
+ a.store(b)
20
+ b.store(c)
21
+ i.store(i + 1)
22
+ }.end
23
+
24
+ f.return(c)
25
+ end
26
+
27
+ values = (0...10).collect { |x| fib.apply(x) }
28
+ p values #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
29
+
@@ -0,0 +1,117 @@
1
+ require 'jit'
2
+ require 'benchmark'
3
+
4
+ # GCD, JIT-compiled
5
+
6
+ jit_gcd = nil
7
+
8
+ JIT::Context.build do |context|
9
+ signature = JIT::Type.create_signature(
10
+ JIT::ABI::CDECL,
11
+ JIT::Type::INT,
12
+ [ JIT::Type::INT, JIT::Type::INT ])
13
+ jit_gcd = JIT::Function.compile(context, signature) do |f|
14
+ x = f.get_param(0)
15
+ y = f.get_param(1)
16
+ temp1 = f.insn_eq(x, y)
17
+ label1 = JIT::Label.new
18
+ f.insn_branch_if_not(temp1, label1)
19
+ f.insn_return(x)
20
+ f.insn_label(label1)
21
+ temp2 = f.insn_lt(x, y)
22
+ label2 = JIT::Label.new
23
+ f.insn_branch_if_not(temp2, label2)
24
+ s1 = f.insn_sub(y, x)
25
+ temp3 = f.insn_call("gcd", f, 0, x, s1)
26
+ f.insn_return(temp3)
27
+ f.insn_label(label2)
28
+ s2 = f.insn_sub(x, y)
29
+ temp4 = f.insn_call("gcd", f, 0, s2, y)
30
+ f.insn_return(temp4)
31
+
32
+ f.optimization_level = 3
33
+ end
34
+ end
35
+
36
+ if jit_gcd.apply(28, 21) != 7 then
37
+ puts "jit_gcd is broken"
38
+ exit 1
39
+ end
40
+
41
+
42
+ # GCD with tail recursion optimization
43
+
44
+ jit_gcd_tail = nil
45
+
46
+ JIT::Context.build do |context|
47
+ signature = JIT::Type.create_signature(
48
+ JIT::ABI::CDECL,
49
+ JIT::Type::INT,
50
+ [ JIT::Type::INT, JIT::Type::INT ])
51
+ jit_gcd_tail = JIT::Function.compile(context, signature) do |f|
52
+ x = f.get_param(0)
53
+ y = f.get_param(1)
54
+ temp1 = f.insn_eq(x, y)
55
+ label1 = JIT::Label.new
56
+ f.insn_branch_if_not(temp1, label1)
57
+ f.insn_return(x)
58
+ f.insn_label(label1)
59
+ temp2 = f.insn_lt(x, y)
60
+ label2 = JIT::Label.new
61
+ f.insn_branch_if_not(temp2, label2)
62
+ s1 = f.insn_sub(y, x)
63
+ temp3 = f.insn_call("gcd", f, JIT::Call::TAIL, x, s1)
64
+ # f.insn_return(temp3)
65
+ f.insn_label(label2)
66
+ s2 = f.insn_sub(x, y)
67
+ temp4 = f.insn_call("gcd", f, JIT::Call::TAIL, s2, x)
68
+ # f.insn_return(temp4)
69
+
70
+ f.optimization_level = 3
71
+ end
72
+ end
73
+
74
+ if jit_gcd_tail.apply(28, 21) != 7 then
75
+ puts "jit_gcd_tail is broken"
76
+ exit 1
77
+ end
78
+
79
+
80
+ # GCD in ruby with recursion
81
+
82
+ def gcd(x, y)
83
+ if x == y
84
+ return x
85
+ elsif x < y
86
+ return gcd(x, y - x)
87
+ else
88
+ return gcd(x - y, y)
89
+ end
90
+ end
91
+
92
+
93
+ # GCD in ruby without recursion
94
+
95
+ def gcd2(x, y)
96
+ while x != y do
97
+ if x < y
98
+ y -= x
99
+ else
100
+ x -= y
101
+ end
102
+ end
103
+ return x
104
+ end
105
+
106
+ N = 1000
107
+
108
+ X = 1000
109
+ Y = 1005
110
+
111
+ Benchmark.bm(16) do |x|
112
+ x.report("jit") { N.times { jit_gcd.apply(X, Y) } }
113
+ x.report("jit tail:") { N.times { jit_gcd_tail.apply(X, Y) } }
114
+ x.report("ruby recur:") { N.times { gcd(X, Y) } }
115
+ x.report("ruby iter:") { N.times { gcd2(X, Y) } }
116
+ end
117
+
data/sample/simple.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'jit'
2
+
3
+ function = nil
4
+ JIT::Context.build do |context|
5
+ signature = JIT::Type.create_signature(
6
+ JIT::ABI::CDECL,
7
+ JIT::Type::INT, # returns an integer
8
+ [ JIT::Type::INT ]) # and tages an integer as a parameter
9
+ function = JIT::Function.compile(context, signature) do |f|
10
+ value = f.get_param(0)
11
+ f.insn_return(value)
12
+ end
13
+ end
14
+
15
+ p function.apply(42) #=> 42
@@ -0,0 +1,70 @@
1
+ require 'jit/array'
2
+ require 'jit/function'
3
+ require 'test/unit'
4
+ require 'assertions'
5
+
6
+ class TestJitArray < Test::Unit::TestCase
7
+ include JitAssertions
8
+
9
+ def test_new_array
10
+ a_type = JIT::Array.new(JIT::Type::INT, 12)
11
+ assert_equal JIT::Type::INT, a_type.type
12
+ assert_equal 12, a_type.length
13
+ end
14
+
15
+ # TODO: wrap
16
+
17
+ def test_create
18
+ p = proc { |f|
19
+ a_type = JIT::Array.new(JIT::Type::INT, 4)
20
+ a = a_type.create(f)
21
+ f.return f.const(JIT::Type::INT, 0)
22
+ }
23
+ assert_function_result(
24
+ :result => [ JIT::Type::INT, 0 ],
25
+ &p)
26
+ end
27
+
28
+ def test_offset_of
29
+ a_type = JIT::Array.new(JIT::Type::INT, 4)
30
+ assert_equal 0, a_type.offset_of(0)
31
+ assert_equal 4, a_type.offset_of(1)
32
+ assert_equal 8, a_type.offset_of(2)
33
+ assert_equal 12, a_type.offset_of(3)
34
+ # TODO: check out of bounds
35
+ end
36
+
37
+ def test_type_of
38
+ a_type = JIT::Array.new(JIT::Type::INT, 4)
39
+ assert_equal JIT::Type::INT, a_type.type_of(0)
40
+ assert_equal JIT::Type::INT, a_type.type_of(1)
41
+ assert_equal JIT::Type::INT, a_type.type_of(2)
42
+ assert_equal JIT::Type::INT, a_type.type_of(3)
43
+ # TODO: check out of bounds
44
+ end
45
+
46
+ def test_instance_bracket
47
+ p = proc { |f|
48
+ a_type = JIT::Array.new(JIT::Type::INT, 4)
49
+ a = a_type.create(f)
50
+ f.insn_store_relative(a.ptr, 4, f.const(JIT::Type::INT, 42))
51
+ f.return a[1]
52
+ }
53
+ assert_function_result(
54
+ :result => [ JIT::Type::INT, 42 ],
55
+ &p)
56
+ end
57
+
58
+ def test_instance_bracket_eq
59
+ p = proc { |f|
60
+ a_type = JIT::Array.new(JIT::Type::INT, 4)
61
+ a = a_type.create(f)
62
+ a[1] = f.const(JIT::Type::INT, 42)
63
+ f.return a[1]
64
+ }
65
+ assert_function_result(
66
+ :result => [ JIT::Type::INT, 42 ],
67
+ &p)
68
+ end
69
+ end
70
+