@@ -26,6 +26,9 @@ function getenv(var::String)
26
26
bytestring (val)
27
27
end
28
28
29
+ julia_root = getenv (" JULIA_ROOT" )
30
+
31
+ # Force inline a function
29
32
function inline (function_name, signature)
30
33
m = methods (function_name, signature)
31
34
if length (m) < 1
@@ -38,15 +41,112 @@ function inline(function_name, signature)
38
41
def. j2cflag = convert (Int32, 1 )
39
42
end
40
43
44
+ function typeOfOpr (x)
45
+ if isa (x, Expr) x. typ
46
+ elseif isa (x, SymbolNode) x. typ
47
+ else typeof (x)
48
+ end
49
+ end
50
+
51
+ # Convert regular Julia types to make them appropriate for calling C code.
52
+ function convert_to_ccall_typ (typ)
53
+ # if there a better way to check for typ being an array DataType?
54
+ if isa (typ, DataType) && typ. name == Array. name
55
+ # If it is an Array type then convert to Ptr type.
56
+ return (Ptr{eltype (typ)},ndims (typ))
57
+ elseif is (typ, ())
58
+ return (Void, 0 )
59
+ else
60
+ # Else no conversion needed.
61
+ return (typ,0 )
62
+ end
63
+ end
64
+
65
+ # dims is array of arrays from converting the datatype signature
66
+ # ret_dims is an array of dimensions for the reurn type
67
+ function sig_dims_to_args (dims)
68
+ # add an Int64 argument for each array dimension we have
69
+ ret = DataType[]
70
+ for i = 1 : length (dims)
71
+ for j = 1 : dims[i]
72
+ push! (ret, Int64)
73
+ end
74
+ end
75
+ ret
76
+ end
77
+
78
+ # Convert a whole function signature in a form of a tuple to something appropriate for calling C code.
79
+ function convert_sig (sig)
80
+ assert (isa (typeof (sig),Tuple)) # make sure we got a tuple
81
+ new_tuple = Expr (:tuple ) # declare the new tuple
82
+ # fill in the new_tuple args/elements by converting the individual elements of the incoming signature
83
+ new_tuple. args = [ convert_to_ccall_typ (sig[i])[1 ] for i = 1 : length (sig) ]
84
+ sig_ndims = [ convert_to_ccall_typ (sig[i])[2 ] for i = 1 : length (sig) ]
85
+ append! (new_tuple. args,sig_dims_to_args (sig_ndims))
86
+ return (eval (new_tuple), sig_ndims)
87
+ end
88
+
41
89
function offload (function_name, signature)
90
+ # get information about code for the given function and signature
91
+ ct = code_typed (function_name, signature)
92
+ code = ct[1 ]
93
+ # set j2cflag properly
42
94
m = methods (function_name, signature)
43
95
def = m[1 ]. func. code
44
96
def. j2cflag = convert (Int32, 2 )
45
- end
97
+ # Same the number of statements so we can get the last one.
98
+ num_stmts = length (ct[1 ]. args[3 ]. args)
99
+ # Get the return type of the function by looking at the last statement
100
+ last_stmt = ct[1 ]. args[3 ]. args[num_stmts]
101
+ if isa (last_stmt, Expr) && is (last_stmt. head, :return )
102
+ typ = typeOfOpr (last_stmt. args[1 ])
103
+ (ret_type,ret_dims) = convert_to_ccall_typ (typ)
104
+ else
105
+ error (" Last statement is not a return: " , last_stmt)
106
+ end
46
107
47
- julia_root = getenv (" JULIA_ROOT" )
48
- libname = string (julia_root, " /j2c/libout.so.1.0" )
49
- println (libname)
108
+ proxy_name = string (function_name," _j2c_proxy" )
109
+ proxy_sym = symbol (proxy_name)
110
+ j2c_name = string (function_name," _" )
111
+ dyn_lib = string (julia_root, " /j2c/libout.so.1.0" )
112
+
113
+ # Convert Arrays in signature to Ptr and add extra arguments for array dimensions
114
+ (modified_sig, sig_dims) = convert_sig (signature)
115
+
116
+ # Create a set of expressions to pass as arguments to specify the array dimension sizes.
117
+ extra_args = Any[]
118
+ for (i = 1 : length (sig_dims))
119
+ for (j = 1 : sig_dims[i])
120
+ push! (extra_args, quote size ($ (code. args[1 ][i]),$ (j)) end )
121
+ end
122
+ end
123
+
124
+ # Are we returning an array?
125
+ if (ret_dims > 0 )
126
+ tuple_sig_expr = Expr (:tuple ,modified_sig... ,Cint,Ptr{Cint})
127
+ func = @eval function ($ proxy_sym)($ (code. args[1 ]. .. ))
128
+ ret_out_dims = zeros (Cint,$ ret_dims)
129
+ result = ccall (($ j2c_name, $ dyn_lib), $ ret_type, $ tuple_sig_expr,
130
+ $ (code. args[1 ]. .. ), $ (extra_args... ), $ ret_dims, ret_out_dims)
131
+ if (prod (ret_out_dims) == 0 )
132
+ throw (string (" j2c code did not fill in at least one dimension for proxy " , $ proxy_name))
133
+ end
134
+ rod64 = convert (Array{Int64,1 },ret_out_dims)
135
+ # Convert the result we get back from a pointer to an array.
136
+ # The total size is the prod of the dimensions in ret_out_dims.
137
+ # "true" says that Julia owns the returned memory and can free it with regular GC.
138
+ # After getting array the right size we then reshape it again using ret_out_dims.
139
+ reshape (pointer_to_array (result,prod (ret_out_dims),true ),tuple (rod64... ))
140
+ end
141
+ else
142
+ tuple_sig_expr = Expr (:tuple ,Cint,modified_sig... )
143
+ func = @eval function ($ proxy_sym)($ (code. args[1 ]. .. ))
144
+ ccall (($ j2c_name, $ dyn_lib), $ ret_type, $ tuple_sig_expr,
145
+ $ (code. args[1 ]. .. ), $ (extra_args... ))
146
+ end
147
+ end
148
+ return func
149
+ end
50
150
51
151
function sumOfThree (N:: Int )
52
152
a= [ (i* N+ j)* 11.0 for i= 1 : N, j= 1 : N]
@@ -56,21 +156,32 @@ function sumOfThree(N::Int)
56
156
return d
57
157
end
58
158
59
- offload (sumOfThree, (Int,))
60
- # warm up, will trigger j2c compilation, but will not run
61
- sumOfThree (1 )
62
-
63
- @eval function j2c_sumOfThree (N:: Int )
64
- ret_out_dims = zeros (Cint, 2 )
65
- result = ccall ((:sumOfThree_ , $ (libname)), Ptr{Float64}, (Int, Int, Int, Ptr{Cint},), - 1 , N, 1 , ret_out_dims)
66
- rod64 = convert (Array{Int,1 }, ret_out_dims)
67
- reshape (pointer_to_array (result,prod (ret_out_dims),true ),tuple (rod64... ))
159
+ function powOfTwo (a:: Array{Float64,2} )
160
+ return a .* a
68
161
end
69
162
70
- for sizea = 1 : 1 # 100
71
- N = sizea * 1000
163
+ # Here is a sample of calling j2c functions directly.
164
+ # libname = string(julia_root, "/j2c/libout.so.1.0")
165
+ # println(libname)
166
+ # @eval function j2c_sumOfThree(N::Int)
167
+ # ret_out_dims = zeros(Cint, 2)
168
+ # result = ccall((:sumOfThree_, $(libname)), Ptr{Float64}, (Int, Int, Ptr{Cint},), N, 1, ret_out_dims)
169
+ # rod64 = convert(Array{Int,1}, ret_out_dims)
170
+ # reshape(pointer_to_array(result,prod(ret_out_dims),true),tuple(rod64...))
171
+ # end
172
+
173
+ # Alternatively, we may use the offload function to automatically
174
+ # generate the above wrapper.
175
+ j2c_sumOfThree = offload (sumOfThree, (Int,))
176
+ j2c_powOfTwo = offload (powOfTwo, (Array{Float64,2 },))
177
+
178
+ # Warm up, will trigger j2c compilation
179
+ powOfTwo (sumOfThree (1 ))
180
+
181
+ for sizea = 1 : 10 # 100
182
+ N = sizea * 100
72
183
println (" \n ****Matrix size: " , N, " *" , N)
73
- d= j2c_sumOfThree (N)
74
- println (" sum=" , sum (d))
184
+ a= j2c_sumOfThree (N)
185
+ b= j2c_powOfTwo (a)
186
+ println (" checksum =" , sum (a), " " , sum (b))
75
187
end
76
-
0 commit comments