Mercurial > octave-nkf
annotate src/jit-typeinfo.cc @ 15019:ae3670d4df29
Update the execution engine's global mapping for external functions
* src/jit_typeinfo.cc: (octave_jit_print_double): Rename to
octave_jit_print_scalar
(jit_function::do_add_mapping): New function.
(jit_typeinfo::jit_typeinfo, jit_typeinfo::add_print): Add mappings.
(jit_typeinfo::do_insert_error_check): Rename builder argument.
* src/jit_typeinfo.h: (jit_function::add_mapping): New function.
(jit_function::do_add_mapping): New declaration.
(jit_typeinfo::add_print): Take function ptr as argument.
author | Max Brister <max@2bass.com> |
---|---|
date | Thu, 26 Jul 2012 10:40:26 -0500 |
parents | 005cb78e1dd1 |
children | 741d2dbcc117 |
rev | line source |
---|---|
15016 | 1 /* |
2 | |
3 Copyright (C) 2012 Max Brister <max@2bass.com> | |
4 | |
5 This file is part of Octave. | |
6 | |
7 Octave is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
9 Free Software Foundation; either version 3 of the License, or (at your | |
10 option) any later version. | |
11 | |
12 Octave is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with Octave; see the file COPYING. If not, see | |
19 <http://www.gnu.org/licenses/>. | |
20 | |
21 */ | |
22 | |
23 // defines required by llvm | |
24 #define __STDC_LIMIT_MACROS | |
25 #define __STDC_CONSTANT_MACROS | |
26 | |
27 #ifdef HAVE_CONFIG_H | |
28 #include <config.h> | |
29 #endif | |
30 | |
31 #ifdef HAVE_LLVM | |
32 | |
33 #include "jit-typeinfo.h" | |
34 | |
35 #include <llvm/Analysis/Verifier.h> | |
36 #include <llvm/GlobalVariable.h> | |
37 #include <llvm/ExecutionEngine/ExecutionEngine.h> | |
38 #include <llvm/LLVMContext.h> | |
39 #include <llvm/Function.h> | |
40 #include <llvm/Instructions.h> | |
41 #include <llvm/Intrinsics.h> | |
42 #include <llvm/Support/IRBuilder.h> | |
43 #include <llvm/Support/raw_os_ostream.h> | |
44 | |
45 #include "jit-ir.h" | |
46 #include "ov.h" | |
47 #include "ov-builtin.h" | |
48 #include "ov-complex.h" | |
49 #include "ov-scalar.h" | |
50 #include "pager.h" | |
51 | |
52 static llvm::LLVMContext& context = llvm::getGlobalContext (); | |
53 | |
54 jit_typeinfo *jit_typeinfo::instance = 0; | |
55 | |
56 std::ostream& jit_print (std::ostream& os, jit_type *atype) | |
57 { | |
58 if (! atype) | |
59 return os << "null"; | |
60 return os << atype->name (); | |
61 } | |
62 | |
63 // function that jit code calls | |
64 extern "C" void | |
65 octave_jit_print_any (const char *name, octave_base_value *obv) | |
66 { | |
67 obv->print_with_name (octave_stdout, name, true); | |
68 } | |
69 | |
70 extern "C" void | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
71 octave_jit_print_scalar (const char *name, double value) |
15016 | 72 { |
73 // FIXME: We should avoid allocating a new octave_scalar each time | |
74 octave_value ov (value); | |
75 ov.print_with_name (octave_stdout, name); | |
76 } | |
77 | |
78 extern "C" octave_base_value* | |
79 octave_jit_binary_any_any (octave_value::binary_op op, octave_base_value *lhs, | |
80 octave_base_value *rhs) | |
81 { | |
82 octave_value olhs (lhs, true); | |
83 octave_value orhs (rhs, true); | |
84 octave_value result = do_binary_op (op, olhs, orhs); | |
85 octave_base_value *rep = result.internal_rep (); | |
86 rep->grab (); | |
87 return rep; | |
88 } | |
89 | |
90 extern "C" octave_idx_type | |
91 octave_jit_compute_nelem (double base, double limit, double inc) | |
92 { | |
93 Range rng = Range (base, limit, inc); | |
94 return rng.nelem (); | |
95 } | |
96 | |
97 extern "C" void | |
98 octave_jit_release_any (octave_base_value *obv) | |
99 { | |
100 obv->release (); | |
101 } | |
102 | |
103 extern "C" void | |
104 octave_jit_release_matrix (jit_matrix *m) | |
105 { | |
106 delete m->array; | |
107 } | |
108 | |
109 extern "C" octave_base_value * | |
110 octave_jit_grab_any (octave_base_value *obv) | |
111 { | |
112 obv->grab (); | |
113 return obv; | |
114 } | |
115 | |
116 extern "C" void | |
117 octave_jit_grab_matrix (jit_matrix *result, jit_matrix *m) | |
118 { | |
119 *result = *m->array; | |
120 } | |
121 | |
122 extern "C" octave_base_value * | |
123 octave_jit_cast_any_matrix (jit_matrix *m) | |
124 { | |
125 octave_value ret (*m->array); | |
126 octave_base_value *rep = ret.internal_rep (); | |
127 rep->grab (); | |
128 delete m->array; | |
129 | |
130 return rep; | |
131 } | |
132 | |
133 extern "C" void | |
134 octave_jit_cast_matrix_any (jit_matrix *ret, octave_base_value *obv) | |
135 { | |
136 NDArray m = obv->array_value (); | |
137 *ret = m; | |
138 obv->release (); | |
139 } | |
140 | |
141 extern "C" double | |
142 octave_jit_cast_scalar_any (octave_base_value *obv) | |
143 { | |
144 double ret = obv->double_value (); | |
145 obv->release (); | |
146 return ret; | |
147 } | |
148 | |
149 extern "C" octave_base_value * | |
150 octave_jit_cast_any_scalar (double value) | |
151 { | |
152 return new octave_scalar (value); | |
153 } | |
154 | |
155 extern "C" Complex | |
156 octave_jit_cast_complex_any (octave_base_value *obv) | |
157 { | |
158 Complex ret = obv->complex_value (); | |
159 obv->release (); | |
160 return ret; | |
161 } | |
162 | |
163 extern "C" octave_base_value * | |
164 octave_jit_cast_any_complex (Complex c) | |
165 { | |
166 if (c.imag () == 0) | |
167 return new octave_scalar (c.real ()); | |
168 else | |
169 return new octave_complex (c); | |
170 } | |
171 | |
172 extern "C" void | |
173 octave_jit_gripe_nan_to_logical_conversion (void) | |
174 { | |
175 try | |
176 { | |
177 gripe_nan_to_logical_conversion (); | |
178 } | |
179 catch (const octave_execution_exception&) | |
180 { | |
181 gripe_library_execution_error (); | |
182 } | |
183 } | |
184 | |
185 extern "C" void | |
186 octave_jit_ginvalid_index (void) | |
187 { | |
188 try | |
189 { | |
190 gripe_invalid_index (); | |
191 } | |
192 catch (const octave_execution_exception&) | |
193 { | |
194 gripe_library_execution_error (); | |
195 } | |
196 } | |
197 | |
198 extern "C" void | |
199 octave_jit_gindex_range (int nd, int dim, octave_idx_type iext, | |
200 octave_idx_type ext) | |
201 { | |
202 try | |
203 { | |
204 gripe_index_out_of_range (nd, dim, iext, ext); | |
205 } | |
206 catch (const octave_execution_exception&) | |
207 { | |
208 gripe_library_execution_error (); | |
209 } | |
210 } | |
211 | |
212 extern "C" void | |
213 octave_jit_paren_subsasgn_impl (jit_matrix *mat, octave_idx_type index, | |
214 double value) | |
215 { | |
216 NDArray *array = mat->array; | |
217 if (array->nelem () < index) | |
218 array->resize1 (index); | |
219 | |
220 double *data = array->fortran_vec (); | |
221 data[index - 1] = value; | |
222 | |
223 mat->update (); | |
224 } | |
225 | |
226 extern "C" void | |
227 octave_jit_paren_subsasgn_matrix_range (jit_matrix *result, jit_matrix *mat, | |
228 jit_range *index, double value) | |
229 { | |
230 NDArray *array = mat->array; | |
231 bool done = false; | |
232 | |
233 // optimize for the simple case (no resizing and no errors) | |
234 if (*array->jit_ref_count () == 1 | |
235 && index->all_elements_are_ints ()) | |
236 { | |
237 // this code is similar to idx_vector::fill, but we avoid allocating an | |
238 // idx_vector and its associated rep | |
239 octave_idx_type start = static_cast<octave_idx_type> (index->base) - 1; | |
240 octave_idx_type step = static_cast<octave_idx_type> (index->inc); | |
241 octave_idx_type nelem = index->nelem; | |
242 octave_idx_type final = start + nelem * step; | |
243 if (step < 0) | |
244 { | |
245 step = -step; | |
246 std::swap (final, start); | |
247 } | |
248 | |
249 if (start >= 0 && final < mat->slice_len) | |
250 { | |
251 done = true; | |
252 | |
253 double *data = array->jit_slice_data (); | |
254 if (step == 1) | |
255 std::fill (data + start, data + start + nelem, value); | |
256 else | |
257 { | |
258 for (octave_idx_type i = start; i < final; i += step) | |
259 data[i] = value; | |
260 } | |
261 } | |
262 } | |
263 | |
264 if (! done) | |
265 { | |
266 idx_vector idx (*index); | |
267 NDArray avalue (dim_vector (1, 1)); | |
268 avalue.xelem (0) = value; | |
269 array->assign (idx, avalue); | |
270 } | |
271 | |
272 result->update (array); | |
273 } | |
274 | |
275 extern "C" Complex | |
276 octave_jit_complex_div (Complex lhs, Complex rhs) | |
277 { | |
278 // see src/OPERATORS/op-cs-cs.cc | |
279 if (rhs == 0.0) | |
280 gripe_divide_by_zero (); | |
281 | |
282 return lhs / rhs; | |
283 } | |
284 | |
285 // FIXME: CP form src/xpow.cc | |
286 static inline int | |
287 xisint (double x) | |
288 { | |
289 return (D_NINT (x) == x | |
290 && ((x >= 0 && x < INT_MAX) | |
291 || (x <= 0 && x > INT_MIN))); | |
292 } | |
293 | |
294 extern "C" Complex | |
295 octave_jit_pow_scalar_scalar (double lhs, double rhs) | |
296 { | |
297 // FIXME: almost CP from src/xpow.cc | |
298 if (lhs < 0.0 && ! xisint (rhs)) | |
299 return std::pow (Complex (lhs), rhs); | |
300 return std::pow (lhs, rhs); | |
301 } | |
302 | |
303 extern "C" Complex | |
304 octave_jit_pow_complex_complex (Complex lhs, Complex rhs) | |
305 { | |
306 if (lhs.imag () == 0 && rhs.imag () == 0) | |
307 return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ()); | |
308 return std::pow (lhs, rhs); | |
309 } | |
310 | |
311 extern "C" Complex | |
312 octave_jit_pow_complex_scalar (Complex lhs, double rhs) | |
313 { | |
314 if (lhs.imag () == 0) | |
315 return octave_jit_pow_scalar_scalar (lhs.real (), rhs); | |
316 return std::pow (lhs, rhs); | |
317 } | |
318 | |
319 extern "C" Complex | |
320 octave_jit_pow_scalar_complex (double lhs, Complex rhs) | |
321 { | |
322 if (rhs.imag () == 0) | |
323 return octave_jit_pow_scalar_scalar (lhs, rhs.real ()); | |
324 return std::pow (lhs, rhs); | |
325 } | |
326 | |
327 extern "C" void | |
328 octave_jit_print_matrix (jit_matrix *m) | |
329 { | |
330 std::cout << *m << std::endl; | |
331 } | |
332 | |
333 static void | |
334 gripe_bad_result (void) | |
335 { | |
336 error ("incorrect type information given to the JIT compiler"); | |
337 } | |
338 | |
339 // FIXME: Add support for multiple outputs | |
340 extern "C" octave_base_value * | |
341 octave_jit_call (octave_builtin::fcn fn, size_t nargin, | |
342 octave_base_value **argin, jit_type *result_type) | |
343 { | |
344 octave_value_list ovl (nargin); | |
345 for (size_t i = 0; i < nargin; ++i) | |
346 ovl.xelem (i) = octave_value (argin[i]); | |
347 | |
348 ovl = fn (ovl, 1); | |
349 | |
350 // These type checks are not strictly required, but I'm guessing that | |
351 // incorrect types will be entered on occasion. This will be very difficult to | |
352 // debug unless we do the sanity check here. | |
353 if (result_type) | |
354 { | |
355 if (ovl.length () != 1) | |
356 { | |
357 gripe_bad_result (); | |
358 return 0; | |
359 } | |
360 | |
361 octave_value& result = ovl.xelem (0); | |
362 jit_type *jtype = jit_typeinfo::join (jit_typeinfo::type_of (result), | |
363 result_type); | |
364 if (jtype != result_type) | |
365 { | |
366 gripe_bad_result (); | |
367 return 0; | |
368 } | |
369 | |
370 octave_base_value *ret = result.internal_rep (); | |
371 ret->grab (); | |
372 return ret; | |
373 } | |
374 | |
375 if (! (ovl.length () == 0 | |
376 || (ovl.length () == 1 && ovl.xelem (0).is_undefined ()))) | |
377 gripe_bad_result (); | |
378 | |
379 return 0; | |
380 } | |
381 | |
382 // -------------------- jit_range -------------------- | |
383 bool | |
384 jit_range::all_elements_are_ints () const | |
385 { | |
386 Range r (*this); | |
387 return r.all_elements_are_ints (); | |
388 } | |
389 | |
390 std::ostream& | |
391 operator<< (std::ostream& os, const jit_range& rng) | |
392 { | |
393 return os << "Range[" << rng.base << ", " << rng.limit << ", " << rng.inc | |
394 << ", " << rng.nelem << "]"; | |
395 } | |
396 | |
397 // -------------------- jit_matrix -------------------- | |
398 | |
399 std::ostream& | |
400 operator<< (std::ostream& os, const jit_matrix& mat) | |
401 { | |
402 return os << "Matrix[" << mat.ref_count << ", " << mat.slice_data << ", " | |
403 << mat.slice_len << ", " << mat.dimensions << ", " | |
404 << mat.array << "]"; | |
405 } | |
406 | |
407 // -------------------- jit_type -------------------- | |
408 jit_type::jit_type (const std::string& aname, jit_type *aparent, | |
409 llvm::Type *allvm_type, int aid) : | |
410 mname (aname), mparent (aparent), llvm_type (allvm_type), mid (aid), | |
411 mdepth (aparent ? aparent->mdepth + 1 : 0) | |
412 { | |
413 std::memset (msret, 0, sizeof (msret)); | |
414 std::memset (mpointer_arg, 0, sizeof (mpointer_arg)); | |
415 std::memset (mpack, 0, sizeof (mpack)); | |
416 std::memset (munpack, 0, sizeof (munpack)); | |
417 | |
418 for (size_t i = 0; i < jit_convention::length; ++i) | |
419 mpacked_type[i] = llvm_type; | |
420 } | |
421 | |
422 llvm::Type * | |
423 jit_type::to_llvm_arg (void) const | |
424 { | |
425 return llvm_type ? llvm_type->getPointerTo () : 0; | |
426 } | |
427 | |
428 // -------------------- jit_function -------------------- | |
429 jit_function::jit_function () : module (0), llvm_function (0), mresult (0), | |
430 call_conv (jit_convention::length), | |
431 mcan_error (false) | |
432 {} | |
433 | |
434 jit_function::jit_function (llvm::Module *amodule, | |
435 jit_convention::type acall_conv, | |
436 const llvm::Twine& aname, jit_type *aresult, | |
437 const std::vector<jit_type *>& aargs) | |
438 : module (amodule), mresult (aresult), args (aargs), call_conv (acall_conv), | |
439 mcan_error (false) | |
440 { | |
441 llvm::SmallVector<llvm::Type *, 15> llvm_args; | |
442 | |
443 llvm::Type *rtype = llvm::Type::getVoidTy (context); | |
444 if (mresult) | |
445 { | |
446 rtype = mresult->packed_type (call_conv); | |
447 if (sret ()) | |
448 { | |
449 llvm_args.push_back (rtype->getPointerTo ()); | |
450 rtype = llvm::Type::getVoidTy (context); | |
451 } | |
452 } | |
453 | |
454 for (std::vector<jit_type *>::const_iterator iter = args.begin (); | |
455 iter != args.end (); ++iter) | |
456 { | |
457 jit_type *ty = *iter; | |
458 assert (ty); | |
459 llvm::Type *argty = ty->packed_type (call_conv); | |
460 if (ty->pointer_arg (call_conv)) | |
461 argty = argty->getPointerTo (); | |
462 | |
463 llvm_args.push_back (argty); | |
464 } | |
465 | |
466 // we mark all functinos as external linkage because this prevents llvm | |
467 // from getting rid of always inline functions | |
468 llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false); | |
469 llvm_function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | |
470 aname, module); | |
471 if (call_conv == jit_convention::internal) | |
472 llvm_function->addFnAttr (llvm::Attribute::AlwaysInline); | |
473 } | |
474 | |
475 jit_function::jit_function (const jit_function& fn, jit_type *aresult, | |
476 const std::vector<jit_type *>& aargs) | |
477 : module (fn.module), llvm_function (fn.llvm_function), mresult (aresult), | |
478 args (aargs), call_conv (fn.call_conv), mcan_error (fn.mcan_error) | |
479 { | |
480 } | |
481 | |
482 jit_function::jit_function (const jit_function& fn) | |
483 : module (fn.module), llvm_function (fn.llvm_function), mresult (fn.mresult), | |
484 args (fn.args), call_conv (fn.call_conv), mcan_error (fn.mcan_error) | |
485 {} | |
486 | |
487 std::string | |
488 jit_function::name (void) const | |
489 { | |
490 return llvm_function->getName (); | |
491 } | |
492 | |
493 llvm::BasicBlock * | |
494 jit_function::new_block (const std::string& aname, | |
495 llvm::BasicBlock *insert_before) | |
496 { | |
497 return llvm::BasicBlock::Create (context, aname, llvm_function, | |
498 insert_before); | |
499 } | |
500 | |
501 llvm::Value * | |
502 jit_function::call (llvm::IRBuilderD& builder, | |
503 const std::vector<jit_value *>& in_args) const | |
504 { | |
505 assert (in_args.size () == args.size ()); | |
506 | |
507 std::vector<llvm::Value *> llvm_args (args.size ()); | |
508 for (size_t i = 0; i < in_args.size (); ++i) | |
509 llvm_args[i] = in_args[i]->to_llvm (); | |
510 | |
511 return call (builder, llvm_args); | |
512 } | |
513 | |
514 llvm::Value * | |
515 jit_function::call (llvm::IRBuilderD& builder, | |
516 const std::vector<llvm::Value *>& in_args) const | |
517 { | |
518 assert (valid ()); | |
519 assert (in_args.size () == args.size ()); | |
520 llvm::Function *stacksave | |
521 = llvm::Intrinsic::getDeclaration (module, llvm::Intrinsic::stacksave); | |
522 llvm::SmallVector<llvm::Value *, 10> llvm_args; | |
523 llvm_args.reserve (in_args.size () + sret ()); | |
524 | |
525 llvm::Value *sret_mem = 0; | |
526 llvm::Value *saved_stack = 0; | |
527 if (sret ()) | |
528 { | |
529 saved_stack = builder.CreateCall (stacksave); | |
530 sret_mem = builder.CreateAlloca (mresult->packed_type (call_conv)); | |
531 llvm_args.push_back (sret_mem); | |
532 } | |
533 | |
534 for (size_t i = 0; i < in_args.size (); ++i) | |
535 { | |
536 llvm::Value *arg = in_args[i]; | |
537 jit_type::convert_fn convert = args[i]->pack (call_conv); | |
538 if (convert) | |
539 arg = convert (builder, arg); | |
540 | |
541 if (args[i]->pointer_arg (call_conv)) | |
542 { | |
543 if (! saved_stack) | |
544 saved_stack = builder.CreateCall (stacksave); | |
545 | |
546 arg = builder.CreateAlloca (args[i]->to_llvm ()); | |
547 builder.CreateStore (in_args[i], arg); | |
548 } | |
549 | |
550 llvm_args.push_back (arg); | |
551 } | |
552 | |
553 llvm::Value *ret = builder.CreateCall (llvm_function, llvm_args); | |
554 if (sret_mem) | |
555 ret = builder.CreateLoad (sret_mem); | |
556 | |
557 if (mresult) | |
558 { | |
559 jit_type::convert_fn unpack = mresult->unpack (call_conv); | |
560 if (unpack) | |
561 ret = unpack (builder, ret); | |
562 } | |
563 | |
564 if (saved_stack) | |
565 { | |
566 llvm::Function *stackrestore | |
567 = llvm::Intrinsic::getDeclaration (module, | |
568 llvm::Intrinsic::stackrestore); | |
569 builder.CreateCall (stackrestore, saved_stack); | |
570 } | |
571 | |
572 return ret; | |
573 } | |
574 | |
575 llvm::Value * | |
576 jit_function::argument (llvm::IRBuilderD& builder, size_t idx) const | |
577 { | |
578 assert (idx < args.size ()); | |
579 | |
580 // FIXME: We should be treating arguments like a list, not a vector. Shouldn't | |
581 // matter much for now, as the number of arguments shouldn't be much bigger | |
582 // than 4 | |
583 llvm::Function::arg_iterator iter = llvm_function->arg_begin (); | |
584 if (sret ()) | |
585 ++iter; | |
586 | |
587 for (size_t i = 0; i < idx; ++i, ++iter); | |
588 | |
589 if (args[idx]->pointer_arg (call_conv)) | |
590 return builder.CreateLoad (iter); | |
591 | |
592 return iter; | |
593 } | |
594 | |
595 void | |
596 jit_function::do_return (llvm::IRBuilderD& builder, llvm::Value *rval) | |
597 { | |
598 assert (! rval == ! mresult); | |
599 | |
600 if (rval) | |
601 { | |
602 jit_type::convert_fn convert = mresult->pack (call_conv); | |
603 if (convert) | |
604 rval = convert (builder, rval); | |
605 | |
606 if (sret ()) | |
607 builder.CreateStore (rval, llvm_function->arg_begin ()); | |
608 else | |
609 builder.CreateRet (rval); | |
610 } | |
611 else | |
612 builder.CreateRetVoid (); | |
613 | |
614 llvm::verifyFunction (*llvm_function); | |
615 } | |
616 | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
617 void |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
618 jit_function::do_add_mapping (llvm::ExecutionEngine *engine, void *fn) |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
619 { |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
620 assert (valid ()); |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
621 engine->addGlobalMapping (llvm_function, fn); |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
622 } |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
623 |
15016 | 624 std::ostream& |
625 operator<< (std::ostream& os, const jit_function& fn) | |
626 { | |
627 llvm::Function *lfn = fn.to_llvm (); | |
628 os << "jit_function: cc=" << fn.call_conv; | |
629 llvm::raw_os_ostream llvm_out (os); | |
630 lfn->print (llvm_out); | |
631 llvm_out.flush (); | |
632 return os; | |
633 } | |
634 | |
635 // -------------------- jit_operation -------------------- | |
636 void | |
637 jit_operation::add_overload (const jit_function& func, | |
638 const std::vector<jit_type*>& args) | |
639 { | |
640 if (args.size () >= overloads.size ()) | |
641 overloads.resize (args.size () + 1); | |
642 | |
643 Array<jit_function>& over = overloads[args.size ()]; | |
644 dim_vector dv (over.dims ()); | |
645 Array<octave_idx_type> idx = to_idx (args); | |
646 bool must_resize = false; | |
647 | |
648 if (dv.length () != idx.numel ()) | |
649 { | |
650 dv.resize (idx.numel ()); | |
651 must_resize = true; | |
652 } | |
653 | |
654 for (octave_idx_type i = 0; i < dv.length (); ++i) | |
655 if (dv(i) <= idx(i)) | |
656 { | |
657 must_resize = true; | |
658 dv(i) = idx(i) + 1; | |
659 } | |
660 | |
661 if (must_resize) | |
662 over.resize (dv); | |
663 | |
664 over(idx) = func; | |
665 } | |
666 | |
667 const jit_function& | |
668 jit_operation::overload (const std::vector<jit_type*>& types) const | |
669 { | |
670 // FIXME: We should search for the next best overload on failure | |
671 static jit_function null_overload; | |
672 if (types.size () >= overloads.size ()) | |
673 return null_overload; | |
674 | |
675 for (size_t i =0; i < types.size (); ++i) | |
676 if (! types[i]) | |
677 return null_overload; | |
678 | |
679 const Array<jit_function>& over = overloads[types.size ()]; | |
680 dim_vector dv (over.dims ()); | |
681 Array<octave_idx_type> idx = to_idx (types); | |
682 for (octave_idx_type i = 0; i < dv.length (); ++i) | |
683 if (idx(i) >= dv(i)) | |
684 return null_overload; | |
685 | |
686 return over(idx); | |
687 } | |
688 | |
689 Array<octave_idx_type> | |
690 jit_operation::to_idx (const std::vector<jit_type*>& types) const | |
691 { | |
692 octave_idx_type numel = types.size (); | |
693 if (numel == 1) | |
694 numel = 2; | |
695 | |
696 Array<octave_idx_type> idx (dim_vector (1, numel)); | |
697 for (octave_idx_type i = 0; i < static_cast<octave_idx_type> (types.size ()); | |
698 ++i) | |
699 idx(i) = types[i]->type_id (); | |
700 | |
701 if (types.size () == 1) | |
702 { | |
703 idx(1) = idx(0); | |
704 idx(0) = 0; | |
705 } | |
706 | |
707 return idx; | |
708 } | |
709 | |
710 // -------------------- jit_typeinfo -------------------- | |
711 void | |
712 jit_typeinfo::initialize (llvm::Module *m, llvm::ExecutionEngine *e) | |
713 { | |
714 new jit_typeinfo (m, e); | |
715 } | |
716 | |
717 jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e) | |
718 : module (m), engine (e), next_id (0), | |
719 builder (*new llvm::IRBuilderD (context)) | |
720 { | |
721 instance = this; | |
722 | |
723 // FIXME: We should be registering types like in octave_value_typeinfo | |
724 llvm::Type *any_t = llvm::StructType::create (context, "octave_base_value"); | |
725 any_t = any_t->getPointerTo (); | |
726 | |
727 llvm::Type *scalar_t = llvm::Type::getDoubleTy (context); | |
728 llvm::Type *bool_t = llvm::Type::getInt1Ty (context); | |
729 llvm::Type *string_t = llvm::Type::getInt8Ty (context); | |
730 string_t = string_t->getPointerTo (); | |
731 llvm::Type *index_t = llvm::Type::getIntNTy (context, | |
732 sizeof(octave_idx_type) * 8); | |
733 | |
734 llvm::StructType *range_t = llvm::StructType::create (context, "range"); | |
735 std::vector<llvm::Type *> range_contents (4, scalar_t); | |
736 range_contents[3] = index_t; | |
737 range_t->setBody (range_contents); | |
738 | |
739 llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8); | |
740 | |
741 llvm::StructType *matrix_t = llvm::StructType::create (context, "matrix"); | |
742 llvm::Type *matrix_contents[5]; | |
743 matrix_contents[0] = refcount_t->getPointerTo (); | |
744 matrix_contents[1] = scalar_t->getPointerTo (); | |
745 matrix_contents[2] = index_t; | |
746 matrix_contents[3] = index_t->getPointerTo (); | |
747 matrix_contents[4] = string_t; | |
748 matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5)); | |
749 | |
750 llvm::Type *complex_t = llvm::VectorType::get (scalar_t, 2); | |
751 | |
752 // complex_ret is what is passed to C functions in order to get calling | |
753 // convention right | |
754 complex_ret = llvm::StructType::create (context, "complex_ret"); | |
755 llvm::Type *complex_ret_contents[] = {scalar_t, scalar_t}; | |
756 complex_ret->setBody (complex_ret_contents); | |
757 | |
758 // create types | |
759 any = new_type ("any", 0, any_t); | |
760 matrix = new_type ("matrix", any, matrix_t); | |
761 complex = new_type ("complex", any, complex_t); | |
762 scalar = new_type ("scalar", complex, scalar_t); | |
763 range = new_type ("range", any, range_t); | |
764 string = new_type ("string", any, string_t); | |
765 boolean = new_type ("bool", any, bool_t); | |
766 index = new_type ("index", any, index_t); | |
767 | |
768 create_int (8); | |
769 create_int (16); | |
770 create_int (32); | |
771 create_int (64); | |
772 | |
773 casts.resize (next_id + 1); | |
774 identities.resize (next_id + 1); | |
775 | |
776 // specify calling conventions | |
777 // FIXME: We should detect architecture and do something sane based on that | |
778 // here we assume x86 or x86_64 | |
779 matrix->mark_sret (); | |
780 matrix->mark_pointer_arg (); | |
781 | |
782 range->mark_sret (); | |
783 range->mark_pointer_arg (); | |
784 | |
785 complex->set_pack (jit_convention::external, &jit_typeinfo::pack_complex); | |
786 complex->set_unpack (jit_convention::external, &jit_typeinfo::unpack_complex); | |
787 complex->set_packed_type (jit_convention::external, complex_ret); | |
788 | |
789 if (sizeof (void *) == 4) | |
790 complex->mark_sret (); | |
791 | |
792 // bind global variables | |
793 lerror_state = new llvm::GlobalVariable (*module, bool_t, false, | |
794 llvm::GlobalValue::ExternalLinkage, | |
795 0, "error_state"); | |
796 engine->addGlobalMapping (lerror_state, | |
797 reinterpret_cast<void *> (&error_state)); | |
798 | |
799 // any with anything is an any op | |
800 jit_function fn; | |
801 jit_type *binary_op_type = intN (sizeof (octave_value::binary_op) * 8); | |
802 llvm::Type *llvm_bo_type = binary_op_type->to_llvm (); | |
803 jit_function any_binary = create_function (jit_convention::external, | |
804 "octave_jit_binary_any_any", | |
805 any, binary_op_type, any, any); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
806 any_binary.add_mapping (engine, &octave_jit_binary_any_any); |
15016 | 807 any_binary.mark_can_error (); |
808 binary_ops.resize (octave_value::num_binary_ops); | |
809 for (size_t i = 0; i < octave_value::num_binary_ops; ++i) | |
810 { | |
811 octave_value::binary_op op = static_cast<octave_value::binary_op> (i); | |
812 std::string op_name = octave_value::binary_op_as_string (op); | |
813 binary_ops[i].stash_name ("binary" + op_name); | |
814 } | |
815 | |
816 for (int op = 0; op < octave_value::num_binary_ops; ++op) | |
817 { | |
818 llvm::Twine fn_name ("octave_jit_binary_any_any_"); | |
819 fn_name = fn_name + llvm::Twine (op); | |
820 | |
821 fn = create_function (jit_convention::internal, fn_name, any, any, any); | |
822 fn.mark_can_error (); | |
823 llvm::BasicBlock *block = fn.new_block (); | |
824 builder.SetInsertPoint (block); | |
825 llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op, | |
826 std::numeric_limits<octave_value::binary_op>::is_signed); | |
827 llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int); | |
828 llvm::Value *ret = any_binary.call (builder, op_as_llvm, | |
829 fn.argument (builder, 0), | |
830 fn.argument (builder, 1)); | |
831 fn.do_return (builder, ret); | |
832 binary_ops[op].add_overload (fn); | |
833 } | |
834 | |
835 // grab any | |
836 fn = create_function (jit_convention::external, "octave_jit_grab_any", any, | |
837 any); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
838 fn.add_mapping (engine, &octave_jit_grab_any); |
15016 | 839 grab_fn.add_overload (fn); |
840 grab_fn.stash_name ("grab"); | |
841 | |
842 // grab matrix | |
843 fn = create_function (jit_convention::external, "octave_jit_grab_matrix", | |
844 matrix, matrix); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
845 fn.add_mapping (engine, &octave_jit_grab_matrix); |
15016 | 846 grab_fn.add_overload (fn); |
847 | |
848 // release any | |
849 fn = create_function (jit_convention::external, "octave_jit_release_any", 0, | |
850 any); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
851 fn.add_mapping (engine, &octave_jit_release_any); |
15016 | 852 release_fn.add_overload (fn); |
853 release_fn.stash_name ("release"); | |
854 | |
855 // release matrix | |
856 fn = create_function (jit_convention::external, "octave_jit_release_matrix", | |
857 0, matrix); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
858 fn.add_mapping (engine, &octave_jit_release_matrix); |
15016 | 859 release_fn.add_overload (fn); |
860 | |
861 // release scalar | |
862 fn = create_identity (scalar); | |
863 release_fn.add_overload (fn); | |
864 | |
865 // release complex | |
866 fn = create_identity (complex); | |
867 release_fn.add_overload (fn); | |
868 | |
869 // release index | |
870 fn = create_identity (index); | |
871 release_fn.add_overload (fn); | |
872 | |
873 // now for binary scalar operations | |
874 // FIXME: Finish all operations | |
875 add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd); | |
876 add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub); | |
877 add_binary_op (scalar, octave_value::op_mul, llvm::Instruction::FMul); | |
878 add_binary_op (scalar, octave_value::op_el_mul, llvm::Instruction::FMul); | |
879 | |
880 add_binary_fcmp (scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT); | |
881 add_binary_fcmp (scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE); | |
882 add_binary_fcmp (scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ); | |
883 add_binary_fcmp (scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE); | |
884 add_binary_fcmp (scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT); | |
885 add_binary_fcmp (scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE); | |
886 | |
887 jit_function gripe_div0 = create_function (jit_convention::external, | |
888 "gripe_divide_by_zero", 0); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
889 gripe_div0.add_mapping (engine, &gripe_divide_by_zero); |
15016 | 890 gripe_div0.mark_can_error (); |
891 | |
892 // divide is annoying because it might error | |
893 fn = create_function (jit_convention::internal, | |
894 "octave_jit_div_scalar_scalar", scalar, scalar, scalar); | |
895 fn.mark_can_error (); | |
896 | |
897 llvm::BasicBlock *body = fn.new_block (); | |
898 builder.SetInsertPoint (body); | |
899 { | |
900 llvm::BasicBlock *warn_block = fn.new_block ("warn"); | |
901 llvm::BasicBlock *normal_block = fn.new_block ("normal"); | |
902 | |
903 llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); | |
904 llvm::Value *check = builder.CreateFCmpUEQ (zero, fn.argument (builder, 0)); | |
905 builder.CreateCondBr (check, warn_block, normal_block); | |
906 | |
907 builder.SetInsertPoint (warn_block); | |
908 gripe_div0.call (builder); | |
909 builder.CreateBr (normal_block); | |
910 | |
911 builder.SetInsertPoint (normal_block); | |
912 llvm::Value *ret = builder.CreateFDiv (fn.argument (builder, 0), | |
913 fn.argument (builder, 1)); | |
914 fn.do_return (builder, ret); | |
915 } | |
916 binary_ops[octave_value::op_div].add_overload (fn); | |
917 binary_ops[octave_value::op_el_div].add_overload (fn); | |
918 | |
919 // ldiv is the same as div with the operators reversed | |
920 fn = mirror_binary (fn); | |
921 binary_ops[octave_value::op_ldiv].add_overload (fn); | |
922 binary_ops[octave_value::op_el_ldiv].add_overload (fn); | |
923 | |
924 // In general, the result of scalar ^ scalar is a complex number. We might be | |
925 // able to improve on this if we keep track of the range of values varaibles | |
926 // can take on. | |
927 fn = create_function (jit_convention::external, | |
928 "octave_jit_pow_scalar_scalar", complex, scalar, | |
929 scalar); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
930 fn.add_mapping (engine, &octave_jit_pow_scalar_scalar); |
15016 | 931 binary_ops[octave_value::op_pow].add_overload (fn); |
932 binary_ops[octave_value::op_el_pow].add_overload (fn); | |
933 | |
934 // now for binary complex operations | |
935 add_binary_op (complex, octave_value::op_add, llvm::Instruction::FAdd); | |
936 add_binary_op (complex, octave_value::op_sub, llvm::Instruction::FSub); | |
937 | |
938 fn = create_function (jit_convention::internal, | |
939 "octave_jit_*_complex_complex", complex, complex, | |
940 complex); | |
941 body = fn.new_block (); | |
942 builder.SetInsertPoint (body); | |
943 { | |
944 // (x0*x1 - y0*y1, x0*y1 + y0*x1) = (x0,y0) * (x1,y1) | |
945 // We compute this in one vectorized multiplication, a subtraction, and an | |
946 // addition. | |
947 llvm::Value *lhs = fn.argument (builder, 0); | |
948 llvm::Value *rhs = fn.argument (builder, 1); | |
949 | |
950 // FIXME: We need a better way of doing this, working with llvm's IR | |
951 // directly is sort of a pain. | |
952 llvm::Value *zero = builder.getInt32 (0); | |
953 llvm::Value *one = builder.getInt32 (1); | |
954 llvm::Value *two = builder.getInt32 (2); | |
955 llvm::Value *three = builder.getInt32 (3); | |
956 | |
957 llvm::Type *vec4 = llvm::VectorType::get (scalar_t, 4); | |
958 llvm::Value *mlhs = llvm::UndefValue::get (vec4); | |
959 llvm::Value *mrhs = mlhs; | |
960 | |
961 llvm::Value *temp = complex_real (lhs); | |
962 mlhs = builder.CreateInsertElement (mlhs, temp, zero); | |
963 mlhs = builder.CreateInsertElement (mlhs, temp, two); | |
964 temp = complex_imag (lhs); | |
965 mlhs = builder.CreateInsertElement (mlhs, temp, one); | |
966 mlhs = builder.CreateInsertElement (mlhs, temp, three); | |
967 | |
968 temp = complex_real (rhs); | |
969 mrhs = builder.CreateInsertElement (mrhs, temp, zero); | |
970 mrhs = builder.CreateInsertElement (mrhs, temp, three); | |
971 temp = complex_imag (rhs); | |
972 mrhs = builder.CreateInsertElement (mrhs, temp, one); | |
973 mrhs = builder.CreateInsertElement (mrhs, temp, two); | |
974 | |
975 llvm::Value *mres = builder.CreateFMul (mlhs, mrhs); | |
976 llvm::Value *tlhs = builder.CreateExtractElement (mres, zero); | |
977 llvm::Value *trhs = builder.CreateExtractElement (mres, one); | |
978 llvm::Value *ret_real = builder.CreateFSub (tlhs, trhs); | |
979 | |
980 tlhs = builder.CreateExtractElement (mres, two); | |
981 trhs = builder.CreateExtractElement (mres, three); | |
982 llvm::Value *ret_imag = builder.CreateFAdd (tlhs, trhs); | |
983 fn.do_return (builder, complex_new (ret_real, ret_imag)); | |
984 } | |
985 | |
986 binary_ops[octave_value::op_mul].add_overload (fn); | |
987 binary_ops[octave_value::op_el_mul].add_overload (fn); | |
988 | |
989 jit_function complex_div = create_function (jit_convention::external, | |
990 "octave_jit_complex_div", | |
991 complex, complex, complex); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
992 complex_div.add_mapping (engine, &octave_jit_complex_div); |
15016 | 993 complex_div.mark_can_error (); |
994 binary_ops[octave_value::op_div].add_overload (fn); | |
995 binary_ops[octave_value::op_ldiv].add_overload (fn); | |
996 | |
997 fn = mirror_binary (complex_div); | |
998 binary_ops[octave_value::op_ldiv].add_overload (fn); | |
999 binary_ops[octave_value::op_el_ldiv].add_overload (fn); | |
1000 | |
1001 fn = create_function (jit_convention::external, | |
1002 "octave_jit_pow_complex_complex", complex, complex, | |
1003 complex); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1004 fn.add_mapping (engine, &octave_jit_pow_complex_complex); |
15016 | 1005 binary_ops[octave_value::op_pow].add_overload (fn); |
1006 binary_ops[octave_value::op_el_pow].add_overload (fn); | |
1007 | |
1008 fn = create_function (jit_convention::internal, | |
1009 "octave_jit_*_scalar_complex", complex, scalar, | |
1010 complex); | |
1011 jit_function mul_scalar_complex = fn; | |
1012 body = fn.new_block (); | |
1013 builder.SetInsertPoint (body); | |
1014 { | |
1015 llvm::Value *lhs = fn.argument (builder, 0); | |
1016 llvm::Value *tlhs = complex_new (lhs, lhs); | |
1017 llvm::Value *rhs = fn.argument (builder, 1); | |
1018 fn.do_return (builder, builder.CreateFMul (tlhs, rhs)); | |
1019 } | |
1020 binary_ops[octave_value::op_mul].add_overload (fn); | |
1021 binary_ops[octave_value::op_el_mul].add_overload (fn); | |
1022 | |
1023 | |
1024 fn = mirror_binary (mul_scalar_complex); | |
1025 binary_ops[octave_value::op_mul].add_overload (fn); | |
1026 binary_ops[octave_value::op_el_mul].add_overload (fn); | |
1027 | |
1028 fn = create_function (jit_convention::internal, "octave_jit_+_scalar_complex", | |
1029 complex, scalar, complex); | |
1030 body = fn.new_block (); | |
1031 builder.SetInsertPoint (body); | |
1032 { | |
1033 llvm::Value *lhs = fn.argument (builder, 0); | |
1034 llvm::Value *rhs = fn.argument (builder, 1); | |
1035 llvm::Value *real = builder.CreateFAdd (lhs, complex_real (rhs)); | |
1036 fn.do_return (builder, complex_real (rhs, real)); | |
1037 } | |
1038 binary_ops[octave_value::op_add].add_overload (fn); | |
1039 | |
1040 fn = mirror_binary (fn); | |
1041 binary_ops[octave_value::op_add].add_overload (fn); | |
1042 | |
1043 fn = create_function (jit_convention::internal, "octave_jit_-_complex_scalar", | |
1044 complex, complex, scalar); | |
1045 body = fn.new_block (); | |
1046 builder.SetInsertPoint (body); | |
1047 { | |
1048 llvm::Value *lhs = fn.argument (builder, 0); | |
1049 llvm::Value *rhs = fn.argument (builder, 1); | |
1050 llvm::Value *real = builder.CreateFSub (complex_real (lhs), rhs); | |
1051 fn.do_return (builder, complex_real (lhs, real)); | |
1052 } | |
1053 binary_ops[octave_value::op_sub].add_overload (fn); | |
1054 | |
1055 fn = create_function (jit_convention::internal, "octave_jit_-_scalar_complex", | |
1056 complex, scalar, complex); | |
1057 body = fn.new_block (); | |
1058 builder.SetInsertPoint (body); | |
1059 { | |
1060 llvm::Value *lhs = fn.argument (builder, 0); | |
1061 llvm::Value *rhs = fn.argument (builder, 1); | |
1062 llvm::Value *real = builder.CreateFSub (lhs, complex_real (rhs)); | |
1063 fn.do_return (builder, complex_real (rhs, real)); | |
1064 } | |
1065 binary_ops[octave_value::op_sub].add_overload (fn); | |
1066 | |
1067 fn = create_function (jit_convention::external, | |
1068 "octave_jit_pow_scalar_complex", complex, scalar, | |
1069 complex); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1070 fn.add_mapping (engine, &octave_jit_pow_scalar_complex); |
15016 | 1071 binary_ops[octave_value::op_pow].add_overload (fn); |
1072 binary_ops[octave_value::op_el_pow].add_overload (fn); | |
1073 | |
1074 fn = create_function (jit_convention::external, | |
1075 "octave_jit_pow_complex_scalar", complex, complex, | |
1076 scalar); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1077 fn.add_mapping (engine, &octave_jit_pow_complex_scalar); |
15016 | 1078 binary_ops[octave_value::op_pow].add_overload (fn); |
1079 binary_ops[octave_value::op_el_pow].add_overload (fn); | |
1080 | |
1081 // now for binary index operators | |
1082 add_binary_op (index, octave_value::op_add, llvm::Instruction::Add); | |
1083 | |
1084 // and binary bool operators | |
1085 add_binary_op (boolean, octave_value::op_el_or, llvm::Instruction::Or); | |
1086 add_binary_op (boolean, octave_value::op_el_and, llvm::Instruction::And); | |
1087 | |
1088 // now for printing functions | |
1089 print_fn.stash_name ("print"); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1090 add_print (any, reinterpret_cast<void *> (&octave_jit_print_any)); |
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1091 add_print (scalar, reinterpret_cast<void *> (&octave_jit_print_scalar)); |
15016 | 1092 |
1093 // initialize for loop | |
1094 for_init_fn.stash_name ("for_init"); | |
1095 | |
1096 fn = create_function (jit_convention::internal, "octave_jit_for_range_init", | |
1097 index, range); | |
1098 body = fn.new_block (); | |
1099 builder.SetInsertPoint (body); | |
1100 { | |
1101 llvm::Value *zero = llvm::ConstantInt::get (index_t, 0); | |
1102 fn.do_return (builder, zero); | |
1103 } | |
1104 for_init_fn.add_overload (fn); | |
1105 | |
1106 // bounds check for for loop | |
1107 for_check_fn.stash_name ("for_check"); | |
1108 | |
1109 fn = create_function (jit_convention::internal, "octave_jit_for_range_check", | |
1110 boolean, range, index); | |
1111 body = fn.new_block (); | |
1112 builder.SetInsertPoint (body); | |
1113 { | |
1114 llvm::Value *nelem | |
1115 = builder.CreateExtractValue (fn.argument (builder, 0), 3); | |
1116 llvm::Value *idx = fn.argument (builder, 1); | |
1117 llvm::Value *ret = builder.CreateICmpULT (idx, nelem); | |
1118 fn.do_return (builder, ret); | |
1119 } | |
1120 for_check_fn.add_overload (fn); | |
1121 | |
1122 // index variabe for for loop | |
1123 for_index_fn.stash_name ("for_index"); | |
1124 | |
1125 fn = create_function (jit_convention::internal, "octave_jit_for_range_idx", | |
1126 scalar, range, index); | |
1127 body = fn.new_block (); | |
1128 builder.SetInsertPoint (body); | |
1129 { | |
1130 llvm::Value *idx = fn.argument (builder, 1); | |
1131 llvm::Value *didx = builder.CreateSIToFP (idx, scalar_t); | |
1132 llvm::Value *rng = fn.argument (builder, 0); | |
1133 llvm::Value *base = builder.CreateExtractValue (rng, 0); | |
1134 llvm::Value *inc = builder.CreateExtractValue (rng, 2); | |
1135 | |
1136 llvm::Value *ret = builder.CreateFMul (didx, inc); | |
1137 ret = builder.CreateFAdd (base, ret); | |
1138 fn.do_return (builder, ret); | |
1139 } | |
1140 for_index_fn.add_overload (fn); | |
1141 | |
1142 // logically true | |
1143 logically_true_fn.stash_name ("logically_true"); | |
1144 | |
1145 jit_function gripe_nantl | |
1146 = create_function (jit_convention::external, | |
1147 "octave_jit_gripe_nan_to_logical_conversion", 0); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1148 gripe_nantl.add_mapping (engine, &octave_jit_gripe_nan_to_logical_conversion); |
15016 | 1149 gripe_nantl.mark_can_error (); |
1150 | |
1151 fn = create_function (jit_convention::internal, | |
1152 "octave_jit_logically_true_scalar", boolean, scalar); | |
1153 fn.mark_can_error (); | |
1154 | |
1155 body = fn.new_block (); | |
1156 builder.SetInsertPoint (body); | |
1157 { | |
1158 llvm::BasicBlock *error_block = fn.new_block ("error"); | |
1159 llvm::BasicBlock *normal_block = fn.new_block ("normal"); | |
1160 | |
1161 llvm::Value *check = builder.CreateFCmpUNE (fn.argument (builder, 0), | |
1162 fn.argument (builder, 0)); | |
1163 builder.CreateCondBr (check, error_block, normal_block); | |
1164 | |
1165 builder.SetInsertPoint (error_block); | |
1166 gripe_nantl.call (builder); | |
1167 builder.CreateBr (normal_block); | |
1168 builder.SetInsertPoint (normal_block); | |
1169 | |
1170 llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); | |
1171 llvm::Value *ret = builder.CreateFCmpONE (fn.argument (builder, 0), zero); | |
1172 fn.do_return (builder, ret); | |
1173 } | |
1174 logically_true_fn.add_overload (fn); | |
1175 | |
1176 // logically_true boolean | |
1177 fn = create_identity (boolean); | |
1178 logically_true_fn.add_overload (fn); | |
1179 | |
1180 // make_range | |
1181 // FIXME: May be benificial to implement all in LLVM | |
1182 make_range_fn.stash_name ("make_range"); | |
1183 jit_function compute_nelem | |
1184 = create_function (jit_convention::external, "octave_jit_compute_nelem", | |
1185 index, scalar, scalar, scalar); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1186 compute_nelem.add_mapping (engine, &octave_jit_compute_nelem); |
15016 | 1187 |
1188 fn = create_function (jit_convention::internal, "octave_jit_make_range", | |
1189 range, scalar, scalar, scalar); | |
1190 body = fn.new_block (); | |
1191 builder.SetInsertPoint (body); | |
1192 { | |
1193 llvm::Value *base = fn.argument (builder, 0); | |
1194 llvm::Value *limit = fn.argument (builder, 1); | |
1195 llvm::Value *inc = fn.argument (builder, 2); | |
1196 llvm::Value *nelem = compute_nelem.call (builder, base, limit, inc); | |
1197 | |
1198 llvm::Value *dzero = llvm::ConstantFP::get (scalar_t, 0); | |
1199 llvm::Value *izero = llvm::ConstantInt::get (index_t, 0); | |
1200 llvm::Value *rng = llvm::ConstantStruct::get (range_t, dzero, dzero, dzero, | |
1201 izero, NULL); | |
1202 rng = builder.CreateInsertValue (rng, base, 0); | |
1203 rng = builder.CreateInsertValue (rng, limit, 1); | |
1204 rng = builder.CreateInsertValue (rng, inc, 2); | |
1205 rng = builder.CreateInsertValue (rng, nelem, 3); | |
1206 fn.do_return (builder, rng); | |
1207 } | |
1208 make_range_fn.add_overload (fn); | |
1209 | |
1210 // paren_subsref | |
1211 jit_type *jit_int = intN (sizeof (int) * 8); | |
1212 llvm::Type *int_t = jit_int->to_llvm (); | |
1213 jit_function ginvalid_index | |
1214 = create_function (jit_convention::external, "octave_jit_ginvalid_index", | |
1215 0); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1216 ginvalid_index.add_mapping (engine, &octave_jit_ginvalid_index); |
15016 | 1217 jit_function gindex_range = create_function (jit_convention::external, |
1218 "octave_jit_gindex_range", | |
1219 0, jit_int, jit_int, index, | |
1220 index); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1221 gindex_range.add_mapping (engine, &octave_jit_gindex_range); |
15016 | 1222 |
1223 fn = create_function (jit_convention::internal, "()subsref", scalar, matrix, | |
1224 scalar); | |
1225 fn.mark_can_error (); | |
1226 | |
1227 body = fn.new_block (); | |
1228 builder.SetInsertPoint (body); | |
1229 { | |
1230 llvm::Value *one = llvm::ConstantInt::get (index_t, 1); | |
1231 llvm::Value *ione; | |
1232 if (index_t == int_t) | |
1233 ione = one; | |
1234 else | |
1235 ione = llvm::ConstantInt::get (int_t, 1); | |
1236 | |
1237 llvm::Value *undef = llvm::UndefValue::get (scalar_t); | |
1238 llvm::Value *mat = fn.argument (builder, 0); | |
1239 llvm::Value *idx = fn.argument (builder, 1); | |
1240 | |
1241 // convert index to scalar to integer, and check index >= 1 | |
1242 llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t); | |
1243 llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t); | |
1244 llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx); | |
1245 llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one); | |
1246 llvm::Value *cond = builder.CreateOr (cond0, cond1); | |
1247 | |
1248 llvm::BasicBlock *done = fn.new_block ("done"); | |
1249 llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done); | |
1250 llvm::BasicBlock *normal = fn.new_block ("normal", done); | |
1251 builder.CreateCondBr (cond, conv_error, normal); | |
1252 | |
1253 builder.SetInsertPoint (conv_error); | |
1254 ginvalid_index.call (builder); | |
1255 builder.CreateBr (done); | |
1256 | |
1257 builder.SetInsertPoint (normal); | |
1258 llvm::Value *len = builder.CreateExtractValue (mat, | |
1259 llvm::ArrayRef<unsigned> (2)); | |
1260 cond = builder.CreateICmpSGT (int_idx, len); | |
1261 | |
1262 | |
1263 llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done); | |
1264 llvm::BasicBlock *success = fn.new_block ("success", done); | |
1265 builder.CreateCondBr (cond, bounds_error, success); | |
1266 | |
1267 builder.SetInsertPoint (bounds_error); | |
1268 gindex_range.call (builder, ione, ione, int_idx, len); | |
1269 builder.CreateBr (done); | |
1270 | |
1271 builder.SetInsertPoint (success); | |
1272 llvm::Value *data = builder.CreateExtractValue (mat, | |
1273 llvm::ArrayRef<unsigned> (1)); | |
1274 llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx); | |
1275 llvm::Value *ret = builder.CreateLoad (gep); | |
1276 builder.CreateBr (done); | |
1277 | |
1278 builder.SetInsertPoint (done); | |
1279 | |
1280 llvm::PHINode *merge = llvm::PHINode::Create (scalar_t, 3); | |
1281 builder.Insert (merge); | |
1282 merge->addIncoming (undef, conv_error); | |
1283 merge->addIncoming (undef, bounds_error); | |
1284 merge->addIncoming (ret, success); | |
1285 fn.do_return (builder, merge); | |
1286 } | |
1287 paren_subsref_fn.add_overload (fn); | |
1288 | |
1289 // paren subsasgn | |
1290 paren_subsasgn_fn.stash_name ("()subsasgn"); | |
1291 | |
1292 jit_function resize_paren_subsasgn | |
1293 = create_function (jit_convention::external, | |
1294 "octave_jit_paren_subsasgn_impl", matrix, index, scalar); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1295 resize_paren_subsasgn.add_mapping (engine, &octave_jit_paren_subsasgn_impl); |
15016 | 1296 fn = create_function (jit_convention::internal, "octave_jit_paren_subsasgn", |
1297 matrix, matrix, scalar, scalar); | |
1298 fn.mark_can_error (); | |
1299 body = fn.new_block (); | |
1300 builder.SetInsertPoint (body); | |
1301 { | |
1302 llvm::Value *one = llvm::ConstantInt::get (index_t, 1); | |
1303 | |
1304 llvm::Value *mat = fn.argument (builder, 0); | |
1305 llvm::Value *idx = fn.argument (builder, 1); | |
1306 llvm::Value *value = fn.argument (builder, 2); | |
1307 | |
1308 llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t); | |
1309 llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t); | |
1310 llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx); | |
1311 llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one); | |
1312 llvm::Value *cond = builder.CreateOr (cond0, cond1); | |
1313 | |
1314 llvm::BasicBlock *done = fn.new_block ("done"); | |
1315 | |
1316 llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done); | |
1317 llvm::BasicBlock *normal = fn.new_block ("normal", done); | |
1318 builder.CreateCondBr (cond, conv_error, normal); | |
1319 builder.SetInsertPoint (conv_error); | |
1320 ginvalid_index.call (builder); | |
1321 builder.CreateBr (done); | |
1322 | |
1323 builder.SetInsertPoint (normal); | |
1324 llvm::Value *len = builder.CreateExtractValue (mat, | |
1325 llvm::ArrayRef<unsigned> (2)); | |
1326 cond0 = builder.CreateICmpSGT (int_idx, len); | |
1327 | |
1328 llvm::Value *rcount = builder.CreateExtractValue (mat, 0); | |
1329 rcount = builder.CreateLoad (rcount); | |
1330 cond1 = builder.CreateICmpSGT (rcount, one); | |
1331 cond = builder.CreateOr (cond0, cond1); | |
1332 | |
1333 llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done); | |
1334 llvm::BasicBlock *success = fn.new_block ("success", done); | |
1335 builder.CreateCondBr (cond, bounds_error, success); | |
1336 | |
1337 // resize on out of bounds access | |
1338 builder.SetInsertPoint (bounds_error); | |
1339 llvm::Value *resize_result = resize_paren_subsasgn.call (builder, int_idx, | |
1340 value); | |
1341 builder.CreateBr (done); | |
1342 | |
1343 builder.SetInsertPoint (success); | |
1344 llvm::Value *data = builder.CreateExtractValue (mat, | |
1345 llvm::ArrayRef<unsigned> (1)); | |
1346 llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx); | |
1347 builder.CreateStore (value, gep); | |
1348 builder.CreateBr (done); | |
1349 | |
1350 builder.SetInsertPoint (done); | |
1351 | |
1352 llvm::PHINode *merge = llvm::PHINode::Create (matrix_t, 3); | |
1353 builder.Insert (merge); | |
1354 merge->addIncoming (mat, conv_error); | |
1355 merge->addIncoming (resize_result, bounds_error); | |
1356 merge->addIncoming (mat, success); | |
1357 fn.do_return (builder, merge); | |
1358 } | |
1359 paren_subsasgn_fn.add_overload (fn); | |
1360 | |
1361 fn = create_function (jit_convention::external, | |
1362 "octave_jit_paren_subsasgn_matrix_range", matrix, | |
1363 matrix, range, scalar); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1364 fn.add_mapping (engine, &octave_jit_paren_subsasgn_matrix_range); |
15016 | 1365 fn.mark_can_error (); |
1366 paren_subsasgn_fn.add_overload (fn); | |
1367 | |
1368 casts[any->type_id ()].stash_name ("(any)"); | |
1369 casts[scalar->type_id ()].stash_name ("(scalar)"); | |
1370 casts[complex->type_id ()].stash_name ("(complex)"); | |
1371 casts[matrix->type_id ()].stash_name ("(matrix)"); | |
1372 | |
1373 // cast any <- matrix | |
1374 fn = create_function (jit_convention::external, "octave_jit_cast_any_matrix", | |
1375 any, matrix); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1376 fn.add_mapping (engine, &octave_jit_cast_any_matrix); |
15016 | 1377 casts[any->type_id ()].add_overload (fn); |
1378 | |
1379 // cast matrix <- any | |
1380 fn = create_function (jit_convention::external, "octave_jit_cast_matrix_any", | |
1381 matrix, any); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1382 fn.add_mapping (engine, &octave_jit_cast_matrix_any); |
15016 | 1383 casts[matrix->type_id ()].add_overload (fn); |
1384 | |
1385 // cast any <- scalar | |
1386 fn = create_function (jit_convention::external, "octave_jit_cast_any_scalar", | |
1387 any, scalar); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1388 fn.add_mapping (engine, &octave_jit_cast_any_scalar); |
15016 | 1389 casts[any->type_id ()].add_overload (fn); |
1390 | |
1391 // cast scalar <- any | |
1392 fn = create_function (jit_convention::external, "octave_jit_cast_scalar_any", | |
1393 scalar, any); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1394 fn.add_mapping (engine, &octave_jit_cast_scalar_any); |
15016 | 1395 casts[scalar->type_id ()].add_overload (fn); |
1396 | |
1397 // cast any <- complex | |
1398 fn = create_function (jit_convention::external, "octave_jit_cast_any_complex", | |
1399 any, complex); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1400 fn.add_mapping (engine, &octave_jit_cast_any_complex); |
15016 | 1401 casts[any->type_id ()].add_overload (fn); |
1402 | |
1403 // cast complex <- any | |
1404 fn = create_function (jit_convention::external, "octave_jit_cast_complex_any", | |
1405 complex, any); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1406 fn.add_mapping (engine, &octave_jit_cast_complex_any); |
15016 | 1407 casts[complex->type_id ()].add_overload (fn); |
1408 | |
1409 // cast complex <- scalar | |
1410 fn = create_function (jit_convention::internal, | |
1411 "octave_jit_cast_complex_scalar", complex, scalar); | |
1412 body = fn.new_block (); | |
1413 builder.SetInsertPoint (body); | |
1414 { | |
1415 llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); | |
1416 fn.do_return (builder, complex_new (fn.argument (builder, 0), zero)); | |
1417 } | |
1418 casts[complex->type_id ()].add_overload (fn); | |
1419 | |
1420 // cast scalar <- complex | |
1421 fn = create_function (jit_convention::internal, | |
1422 "octave_jit_cast_scalar_complex", scalar, complex); | |
1423 body = fn.new_block (); | |
1424 builder.SetInsertPoint (body); | |
1425 fn.do_return (builder, complex_real (fn.argument (builder, 0))); | |
1426 casts[scalar->type_id ()].add_overload (fn); | |
1427 | |
1428 // cast any <- any | |
1429 fn = create_identity (any); | |
1430 casts[any->type_id ()].add_overload (fn); | |
1431 | |
1432 // cast scalar <- scalar | |
1433 fn = create_identity (scalar); | |
1434 casts[scalar->type_id ()].add_overload (fn); | |
1435 | |
1436 // cast complex <- complex | |
1437 fn = create_identity (complex); | |
1438 casts[complex->type_id ()].add_overload (fn); | |
1439 | |
1440 // -------------------- builtin functions -------------------- | |
1441 add_builtin ("#unknown_function"); | |
1442 unknown_function = builtins["#unknown_function"]; | |
1443 | |
1444 add_builtin ("sin"); | |
1445 register_intrinsic ("sin", llvm::Intrinsic::sin, scalar, scalar); | |
1446 register_generic ("sin", matrix, matrix); | |
1447 | |
1448 add_builtin ("cos"); | |
1449 register_intrinsic ("cos", llvm::Intrinsic::cos, scalar, scalar); | |
1450 register_generic ("cos", matrix, matrix); | |
1451 | |
1452 add_builtin ("exp"); | |
1453 register_intrinsic ("exp", llvm::Intrinsic::cos, scalar, scalar); | |
1454 register_generic ("exp", matrix, matrix); | |
1455 | |
1456 casts.resize (next_id + 1); | |
1457 jit_function any_id = create_identity (any); | |
1458 jit_function release_any = get_release (any); | |
1459 std::vector<jit_type *> args; | |
1460 args.resize (1); | |
1461 | |
1462 for (std::map<std::string, jit_type *>::iterator iter = builtins.begin (); | |
1463 iter != builtins.end (); ++iter) | |
1464 { | |
1465 jit_type *btype = iter->second; | |
1466 args[0] = btype; | |
1467 | |
1468 release_fn.add_overload (jit_function (release_any, 0, args)); | |
1469 casts[any->type_id ()].add_overload (jit_function (any_id, any, args)); | |
1470 | |
1471 args[0] = any; | |
1472 casts[btype->type_id ()].add_overload (jit_function (any_id, btype, | |
1473 args)); | |
1474 } | |
1475 } | |
1476 | |
1477 void | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1478 jit_typeinfo::add_print (jit_type *ty, void *fptr) |
15016 | 1479 { |
1480 std::stringstream name; | |
1481 name << "octave_jit_print_" << ty->name (); | |
1482 jit_function fn = create_function (jit_convention::external, name.str (), 0, | |
1483 intN (8), ty); | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1484 fn.add_mapping (engine, fptr); |
15016 | 1485 print_fn.add_overload (fn); |
1486 } | |
1487 | |
1488 // FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp | |
1489 void | |
1490 jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op) | |
1491 { | |
1492 std::stringstream fname; | |
1493 octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op); | |
1494 fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op) | |
1495 << "_" << ty->name (); | |
1496 | |
1497 jit_function fn = create_function (jit_convention::internal, fname.str (), | |
1498 ty, ty, ty); | |
1499 llvm::BasicBlock *block = fn.new_block (); | |
1500 builder.SetInsertPoint (block); | |
1501 llvm::Instruction::BinaryOps temp | |
1502 = static_cast<llvm::Instruction::BinaryOps>(llvm_op); | |
1503 | |
1504 llvm::Value *ret = builder.CreateBinOp (temp, fn.argument (builder, 0), | |
1505 fn.argument (builder, 1)); | |
1506 fn.do_return (builder, ret); | |
1507 binary_ops[op].add_overload (fn); | |
1508 } | |
1509 | |
1510 void | |
1511 jit_typeinfo::add_binary_icmp (jit_type *ty, int op, int llvm_op) | |
1512 { | |
1513 std::stringstream fname; | |
1514 octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op); | |
1515 fname << "octave_jit" << octave_value::binary_op_as_string (ov_op) | |
1516 << "_" << ty->name (); | |
1517 | |
1518 jit_function fn = create_function (jit_convention::internal, fname.str (), | |
1519 boolean, ty, ty); | |
1520 llvm::BasicBlock *block = fn.new_block (); | |
1521 builder.SetInsertPoint (block); | |
1522 llvm::CmpInst::Predicate temp | |
1523 = static_cast<llvm::CmpInst::Predicate>(llvm_op); | |
1524 llvm::Value *ret = builder.CreateICmp (temp, fn.argument (builder, 0), | |
1525 fn.argument (builder, 1)); | |
1526 fn.do_return (builder, ret); | |
1527 binary_ops[op].add_overload (fn); | |
1528 } | |
1529 | |
1530 void | |
1531 jit_typeinfo::add_binary_fcmp (jit_type *ty, int op, int llvm_op) | |
1532 { | |
1533 std::stringstream fname; | |
1534 octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op); | |
1535 fname << "octave_jit" << octave_value::binary_op_as_string (ov_op) | |
1536 << "_" << ty->name (); | |
1537 | |
1538 jit_function fn = create_function (jit_convention::internal, fname.str (), | |
1539 boolean, ty, ty); | |
1540 llvm::BasicBlock *block = fn.new_block (); | |
1541 builder.SetInsertPoint (block); | |
1542 llvm::CmpInst::Predicate temp | |
1543 = static_cast<llvm::CmpInst::Predicate>(llvm_op); | |
1544 llvm::Value *ret = builder.CreateFCmp (temp, fn.argument (builder, 0), | |
1545 fn.argument (builder, 1)); | |
1546 fn.do_return (builder, ret); | |
1547 binary_ops[op].add_overload (fn); | |
1548 } | |
1549 | |
1550 jit_function | |
1551 jit_typeinfo::create_function (jit_convention::type cc, const llvm::Twine& name, | |
1552 jit_type *ret, | |
1553 const std::vector<jit_type *>& args) | |
1554 { | |
1555 jit_function result (module, cc, name, ret, args); | |
1556 return result; | |
1557 } | |
1558 | |
1559 jit_function | |
1560 jit_typeinfo::create_identity (jit_type *type) | |
1561 { | |
1562 size_t id = type->type_id (); | |
1563 if (id >= identities.size ()) | |
1564 identities.resize (id + 1); | |
1565 | |
1566 if (! identities[id].valid ()) | |
1567 { | |
1568 jit_function fn = create_function (jit_convention::internal, "id", type, | |
1569 type); | |
1570 llvm::BasicBlock *body = fn.new_block (); | |
1571 builder.SetInsertPoint (body); | |
1572 fn.do_return (builder, fn.argument (builder, 0)); | |
1573 return identities[id] = fn; | |
1574 } | |
1575 | |
1576 return identities[id]; | |
1577 } | |
1578 | |
1579 llvm::Value * | |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1580 jit_typeinfo::do_insert_error_check (llvm::IRBuilderD& abuilder) |
15016 | 1581 { |
15019
ae3670d4df29
Update the execution engine's global mapping for external functions
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1582 return abuilder.CreateLoad (lerror_state); |
15016 | 1583 } |
1584 | |
1585 void | |
1586 jit_typeinfo::add_builtin (const std::string& name) | |
1587 { | |
1588 jit_type *btype = new_type (name, any, any->to_llvm ()); | |
1589 builtins[name] = btype; | |
1590 | |
1591 octave_builtin *ov_builtin = find_builtin (name); | |
1592 if (ov_builtin) | |
1593 ov_builtin->stash_jit (*btype); | |
1594 } | |
1595 | |
1596 void | |
1597 jit_typeinfo::register_intrinsic (const std::string& name, size_t iid, | |
1598 jit_type *result, | |
1599 const std::vector<jit_type *>& args) | |
1600 { | |
1601 jit_type *builtin_type = builtins[name]; | |
1602 size_t nargs = args.size (); | |
1603 llvm::SmallVector<llvm::Type *, 5> llvm_args (nargs); | |
1604 for (size_t i = 0; i < nargs; ++i) | |
1605 llvm_args[i] = args[i]->to_llvm (); | |
1606 | |
1607 llvm::Intrinsic::ID id = static_cast<llvm::Intrinsic::ID> (iid); | |
1608 llvm::Function *ifun = llvm::Intrinsic::getDeclaration (module, id, | |
1609 llvm_args); | |
1610 std::stringstream fn_name; | |
1611 fn_name << "octave_jit_" << name; | |
1612 | |
1613 std::vector<jit_type *> args1 (nargs + 1); | |
1614 args1[0] = builtin_type; | |
1615 std::copy (args.begin (), args.end (), args1.begin () + 1); | |
1616 | |
1617 // The first argument will be the Octave function, but we already know that | |
1618 // the function call is the equivalent of the intrinsic, so we ignore it and | |
1619 // call the intrinsic with the remaining arguments. | |
1620 jit_function fn = create_function (jit_convention::internal, fn_name.str (), | |
1621 result, args1); | |
1622 llvm::BasicBlock *body = fn.new_block (); | |
1623 builder.SetInsertPoint (body); | |
1624 | |
1625 llvm::SmallVector<llvm::Value *, 5> fargs (nargs); | |
1626 for (size_t i = 0; i < nargs; ++i) | |
1627 fargs[i] = fn.argument (builder, i + 1); | |
1628 | |
1629 llvm::Value *ret = builder.CreateCall (ifun, fargs); | |
1630 fn.do_return (builder, ret); | |
1631 paren_subsref_fn.add_overload (fn); | |
1632 } | |
1633 | |
1634 octave_builtin * | |
1635 jit_typeinfo::find_builtin (const std::string& name) | |
1636 { | |
1637 // FIXME: Finalize what we want to store in octave_builtin, then add functions | |
1638 // to access these values in octave_value | |
1639 octave_value ov_builtin = symbol_table::find (name); | |
1640 return dynamic_cast<octave_builtin *> (ov_builtin.internal_rep ()); | |
1641 } | |
1642 | |
1643 void | |
1644 jit_typeinfo::register_generic (const std::string&, jit_type *, | |
1645 const std::vector<jit_type *>&) | |
1646 { | |
1647 // FIXME: Implement | |
1648 } | |
1649 | |
1650 jit_function | |
1651 jit_typeinfo::mirror_binary (const jit_function& fn) | |
1652 { | |
1653 jit_function ret = create_function (jit_convention::internal, | |
1654 fn.name () + "_reverse", | |
1655 fn.result (), fn.argument_type (1), | |
1656 fn.argument_type (0)); | |
1657 if (fn.can_error ()) | |
1658 ret.mark_can_error (); | |
1659 | |
1660 llvm::BasicBlock *body = ret.new_block (); | |
1661 builder.SetInsertPoint (body); | |
1662 llvm::Value *result = fn.call (builder, ret.argument (builder, 1), | |
1663 ret.argument (builder, 0)); | |
1664 if (ret.result ()) | |
1665 ret.do_return (builder, result); | |
1666 else | |
1667 ret.do_return (builder); | |
1668 | |
1669 return ret; | |
1670 } | |
1671 | |
1672 llvm::Value * | |
1673 jit_typeinfo::pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) | |
1674 { | |
1675 llvm::Type *complex_ret = instance->complex_ret; | |
1676 llvm::Value *real = bld.CreateExtractElement (cplx, bld.getInt32 (0)); | |
1677 llvm::Value *imag = bld.CreateExtractElement (cplx, bld.getInt32 (1)); | |
1678 llvm::Value *ret = llvm::UndefValue::get (complex_ret); | |
1679 ret = bld.CreateInsertValue (ret, real, 0); | |
1680 return bld.CreateInsertValue (ret, imag, 1); | |
1681 } | |
1682 | |
1683 llvm::Value * | |
1684 jit_typeinfo::unpack_complex (llvm::IRBuilderD& bld, llvm::Value *result) | |
1685 { | |
1686 llvm::Type *complex_t = get_complex ()->to_llvm (); | |
1687 llvm::Value *real = bld.CreateExtractValue (result, 0); | |
1688 llvm::Value *imag = bld.CreateExtractValue (result, 1); | |
1689 llvm::Value *ret = llvm::UndefValue::get (complex_t); | |
1690 ret = bld.CreateInsertElement (ret, real, bld.getInt32 (0)); | |
1691 return bld.CreateInsertElement (ret, imag, bld.getInt32 (1)); | |
1692 } | |
1693 | |
1694 llvm::Value * | |
1695 jit_typeinfo::complex_real (llvm::Value *cx) | |
1696 { | |
1697 return builder.CreateExtractElement (cx, builder.getInt32 (0)); | |
1698 } | |
1699 | |
1700 llvm::Value * | |
1701 jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real) | |
1702 { | |
1703 return builder.CreateInsertElement (cx, real, builder.getInt32 (0)); | |
1704 } | |
1705 | |
1706 llvm::Value * | |
1707 jit_typeinfo::complex_imag (llvm::Value *cx) | |
1708 { | |
1709 return builder.CreateExtractElement (cx, builder.getInt32 (1)); | |
1710 } | |
1711 | |
1712 llvm::Value * | |
1713 jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag) | |
1714 { | |
1715 return builder.CreateInsertElement (cx, imag, builder.getInt32 (1)); | |
1716 } | |
1717 | |
1718 llvm::Value * | |
1719 jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag) | |
1720 { | |
1721 llvm::Value *ret = llvm::UndefValue::get (complex->to_llvm ()); | |
1722 ret = complex_real (ret, real); | |
1723 return complex_imag (ret, imag); | |
1724 } | |
1725 | |
1726 void | |
1727 jit_typeinfo::create_int (size_t nbits) | |
1728 { | |
1729 std::stringstream tname; | |
1730 tname << "int" << nbits; | |
1731 ints[nbits] = new_type (tname.str (), any, llvm::Type::getIntNTy (context, | |
1732 nbits)); | |
1733 } | |
1734 | |
1735 jit_type * | |
1736 jit_typeinfo::intN (size_t nbits) const | |
1737 { | |
1738 std::map<size_t, jit_type *>::const_iterator iter = ints.find (nbits); | |
1739 if (iter != ints.end ()) | |
1740 return iter->second; | |
1741 | |
1742 throw jit_fail_exception ("No such integer type"); | |
1743 } | |
1744 | |
1745 jit_type * | |
1746 jit_typeinfo::do_type_of (const octave_value &ov) const | |
1747 { | |
1748 if (ov.is_function ()) | |
1749 { | |
1750 // FIXME: This is ugly, we need to finalize how we want to to this, then | |
1751 // have octave_value fully support the needed functionality | |
1752 octave_builtin *builtin | |
1753 = dynamic_cast<octave_builtin *> (ov.internal_rep ()); | |
1754 return builtin && builtin->to_jit () ? builtin->to_jit () | |
1755 : unknown_function; | |
1756 } | |
1757 | |
1758 if (ov.is_range ()) | |
1759 return get_range (); | |
1760 | |
1761 if (ov.is_double_type ()) | |
1762 { | |
1763 if (ov.is_real_scalar ()) | |
1764 return get_scalar (); | |
1765 | |
1766 if (ov.is_matrix_type ()) | |
1767 return get_matrix (); | |
1768 } | |
1769 | |
1770 if (ov.is_complex_scalar ()) | |
1771 return get_complex (); | |
1772 | |
1773 return get_any (); | |
1774 } | |
1775 | |
1776 jit_type* | |
1777 jit_typeinfo::new_type (const std::string& name, jit_type *parent, | |
1778 llvm::Type *llvm_type) | |
1779 { | |
1780 jit_type *ret = new jit_type (name, parent, llvm_type, next_id++); | |
1781 id_to_type.push_back (ret); | |
1782 return ret; | |
1783 } | |
1784 | |
1785 #endif |