-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathextCall.Rdb
235 lines (219 loc) · 6.92 KB
/
extCall.Rdb
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
<?xml version="1.0"?>
<article xmlns:r="http://www.r-project.org"
xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns:c="http://www.C.org">
<articleinfo>
<title></title>
<author><firstname>Duncan</firstname><surname>Temple Lang</surname>
<affiliation><orgname>University of California at Davis</orgname>
<orgdiv>Department of Statistics</orgdiv>
</affiliation>
</author>
</articleinfo>
<section>
<title>Calling Existing Native Routines</title>
<para>
In this example, we illustrate how to generate a routine
via LLVM which calls a routine that exists in the R
executable. This shows how we can make use of existing
functions.
</para>
<para>
We create a compiled routine <r:func>tossCoin</r:func>
which returns either 1 for a head, or 0 for a tail.
The idea here is to use the native <r:func>runif</r:func>
routine to generate a real value uniformly between 0 and 1.
We then compare this value to 0.5.
If it is less that 0.5, we return 1 for a head; otherwise, we
return 0 for a tail.
The equivalent <r/> code is
<r:function><![CDATA[
toss =
function()
{
ans = 0L
if(runif() < 0.5)
ans = 1
else
ans = 0
ans
}
]]></r:function>
(Here <r:func>runif</r:func> is the <c/> routine that takes no arguments.)
</para>
<para>
We start by creating a <r:class>Module</r:class>:
<r:code>
library(Rllvm)
InitializeNativeTarget()
mod = Module("dotC")
</r:code>
Next, we create our routine, specifying
its return type and no parameters:
<r:code>
fun = Function("tossCoin", Int32Type, module = mod)
</r:code>
</para>
<para>
We are ready to create the instructions.
We create three <r:class>Block</r:class>s for the function.
The first (named <literal>entry</literal>) is the initial
block in which we start the computations.
The other two blocks are for store the head value, and another for storing the tail respectively.
We have a final <r:class>Block</r:class> for returning the value.
<r:code>
b = Block(fun, "entry")
head = Block(fun)
tail = Block(fun)
ret = Block(fun)
</r:code>
We should note that we do not need the final return block.
We can explicitly return 1 and 0 from each of the head and tail <r:class>Block</r:class>s.
This is an opportunity for optimization.
</para>
<para>
We also create an IRBuilder for creating the instructions
and we initially set it to create instructions in the entry <r:class>Block</r:class>:
<r:code>
ir = IRBuilder(b)
</r:code>
</para>
<para>
We will return 1 for a head and 0 for a tail.
So we define these as constants. This is not actually necessary as
we could explicitly return local values of these.<check/>
However, we'll create constants
<r:code>
zero = createIntegerConstant( 0L)
one = createIntegerConstant( 1L)
</r:code>
Note that these are <llvm/>-level constants, not in the <r:class>Module</r:class> or in the <r:func>Function</r:func>.
</para>
<para>
We are now ready to create instructions.
We create a local variable <r:var>ans</r:var>
in the entry <r:class>Block</r:class>.
This is an integer for storing the result, either 0 or 1.
<r:code>
ans = createLocalVariable(ir, Int32Type, "ans")
</r:code>
Since we are invoking <r/>'s <c:func>runif</c:func> routine,
we need to declare it so that <llvm/> can understand how to invoke
it and deal with its return value.
We do this with
<r:code>
runif = Function("runif", DoubleType, module = mod)
setLinkage(runif, ExternalLinkage)
</r:code>
We can now invoke <c:func>runif</c:func> with
<r:code>
toss = ir$createCall(runif)
</r:code>
<note><para>Say how to add arguments in the call</para></note>
The symbolic value of the call (i.e. not an actual call, but the call that will be made at run time)
is stored in the <r/> variable <r:var>toss</r:var>.
</para>
<para>
We compare the outcome of the call to <c:func>runif</c:func> 0.5 with
<r:code>
point5 = createDoubleConstant(0.5)
gt = ir$createFCmp(FCMP_ULT, toss, point5)
</r:code>
Depending on whether <r:var>gt</r:var> is true or false,
we branch to either the head <r:class>Block</r:class> or tail <r:class>Block</r:class>
that we created previously. We create the branch instruction using
<r:code>
ir$createCondBr(gt, head, tail)
</r:code>
This adds the terminator for the entry <r:class>Block</r:class>.
We can now move on to populating the head and tail <r:class>Block</r:class> with instructions.
</para>
<para>
We set the IRBuilder to create instructions in the head <r:class>Block</r:class> and then
assign the value one to our local variable <r:var>ans</r:var>.
Then we branch to the return <r:class>Block</r:class>.
We do these with 3 instructions:
<r:code>
ir$setInsertPoint(head)
ir$createStore(one, ans)
ir$createBr(ret)
</r:code>
</para>
<para>
Similarly, we create the instructions for the tail <r:class>Block</r:class>:
<r:code>
ir$setInsertPoint(tail)
ir$createStore(zero, ans)
ir$createBr(ret)
</r:code>
</para>
<para>
Finally, we complete the return <r:class>Block</r:class> by just
returning the value of <r:var>ans</r:var>. We
have to load the value and then return it.
<r:code>
ir$setInsertPoint(ret)
ans = ir$createLoad(ans)
ir$createRet(ans)
</r:code>
</para>
<para>
We have to tell LLVM how to find the external runif that is not part of the module
but is referenced in our routine. We can do this by explicitly finding
the address of the routine via the R function <r:func>getNativeSymbolInfo</r:func>
<r:code>
info = getNativeSymbolInfo("runif")
llvmAddSymbol(runif = info$address)
</r:code>
<ignore>
<r:code>
.Call("R_DynamicLibrary_LoadLibraryPermanently", info$package[["path"]])
</r:code>
</ignore>
We can then invoke the new routine using <r:func>.llvm</r:func>:
<r:code eval="false">
print(.llvm(fun))
</r:code>
</para>
<ignore>
<r:code eval="false">
llvmLoadDLL(system.file("libs", "Rllvm.so", package = "Rllvm"))
print(.llvm(fun))
</r:code>
</ignore>
<para>
For repeated calls, we can save a great deal of time by
creating the ExecutionEngine in which to evaluate the call
to the function just once and the passing it explicitly in the
call to run:
<r:code>
ee = ExecutionEngine(as(fun, "Module"))
finalizeEngine(ee)
system.time(replicate(1000, .llvm(fun, .ee = ee)))
</r:code>
We can time how long this takes for different number of calls
<r:code>
B = 200
n = 10^(2:5)
tt = sapply(n, function(n) system.time(replicate(B, .llvm(fun, .ee = ee))))
colnames(tt) = n
plot(n, tt["elapsed", ], type = "l")
</r:code>
</para>
<para>
Let's compare this to doing it in R.
Of course we would call runif just once to generate all n values,
but instead we mimic what we are doing with our tossCoin function.
<r:code eval="false">
tm2 = system.time(as.integer(replicate(n[length(n)], runif(1)) > .5))
</r:code>
This takes about 117 seconds, as opposed to the 880
for the call to tossCoin.
This may be due in part to the fact that runif uses
the <r:func>.Internal</r:func> mechanism, whereas <r:expr eval="false">.llvm(fun)</r:expr> involves
a non-trivial overhead of processing the arguments.
Of course, we also have the opportunity of compiling a loop to toss n coins
and avoiding the n calls to <r:func>.llvm</r:func>.
</para>
</section>
</article>