1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2012-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if ! defined (octave_jit_typeinfo_h) 27 #define octave_jit_typeinfo_h 1 28 29 #include "octave-config.h" 30 31 #if defined (HAVE_LLVM) 32 33 #include <map> 34 #include <vector> 35 36 #include "Range.h" 37 #include "jit-util.h" 38 39 namespace octave 40 { 41 class jit_typeinfo; 42 class jit_module; 43 44 // Defines the type system used by jit and a singleton class, jit_typeinfo, to 45 // manage the types. 46 // 47 // FIXME: 48 // Operations are defined and implemented in jit_typeinfo. Eventually they 49 // should be moved elsewhere. (just like with octave_typeinfo) 50 51 // jit_range is compatible with the llvm range structure 52 struct 53 jit_range 54 { jit_rangejit_range55 jit_range (const Range& from) 56 : m_base (from.base ()), m_limit (from.limit ()), m_inc (from.inc ()), 57 m_nelem (from.numel ()) 58 { } 59 Rangejit_range60 operator Range () const 61 { 62 return Range (m_base, m_limit, m_inc); 63 } 64 65 bool all_elements_are_ints (void) const; 66 67 double m_base; 68 double m_limit; 69 double m_inc; 70 octave_idx_type m_nelem; 71 }; 72 73 std::ostream& operator << (std::ostream& os, const jit_range& rng); 74 75 // jit_array is compatible with the llvm array/matrix structures 76 template <typename T, typename U> 77 struct 78 jit_array 79 { jit_arrayjit_array80 jit_array (void) : m_array (0) { } 81 jit_arrayjit_array82 jit_array (T& from) : m_array (new T (from)) 83 { 84 update (); 85 } 86 updatejit_array87 void update (void) 88 { 89 m_ref_count = m_array->jit_ref_count (); 90 m_slice_data = m_array->jit_slice_data () - 1; 91 m_slice_len = m_array->numel (); 92 m_dimensions = m_array->jit_dimensions (); 93 } 94 updatejit_array95 void update (T *aarray) 96 { 97 m_array = aarray; 98 update (); 99 } 100 Tjit_array101 operator T () const 102 { 103 return *m_array; 104 } 105 106 int m_ref_count; 107 108 U *m_slice_data; 109 octave_idx_type m_slice_len; 110 octave_idx_type *m_dimensions; 111 112 T *m_array; 113 }; 114 115 typedef jit_array<NDArray, double> jit_matrix; 116 117 std::ostream& operator << (std::ostream& os, const jit_matrix& mat); 118 119 // calling convention 120 namespace jit_convention 121 { 122 enum 123 type 124 { 125 // internal to jit 126 internal, 127 128 // an external C call 129 external, 130 131 length 132 }; 133 } 134 135 // Used to keep track of estimated (infered) types during JIT. This is a 136 // hierarchical type system which includes both concrete and abstract types. 137 // 138 // The types form a lattice. Currently we only allow for one parent type, but 139 // eventually we may allow for multiple predecessors. 140 class 141 jit_type 142 { 143 public: 144 145 typedef llvm::Value *(*convert_fn) (llvm::IRBuilderD&, llvm::Value *); 146 147 jit_type (const std::string& aname, jit_type *aparent, llvm::Type *allvm_type, 148 bool askip_paren, int aid); 149 150 // a user readable type name name(void)151 const std::string& name (void) const { return m_name; } 152 153 // a unique id for the type type_id(void)154 int type_id (void) const { return m_id; } 155 156 // An abstract base type, may be null parent(void)157 jit_type * parent (void) const { return m_parent; } 158 159 // convert to an llvm type to_llvm(void)160 llvm::Type * to_llvm (void) const { return m_llvm_type; } 161 162 // how this type gets passed as a function argument 163 llvm::Type * to_llvm_arg (void) const; 164 depth(void)165 std::size_t depth (void) const { return m_depth; } 166 skip_paren(void)167 bool skip_paren (void) const { return m_skip_paren; } 168 169 // -------------------- Calling Convention information -------------------- 170 171 // A function declared like: mytype foo (int arg0, int arg1); 172 // Will be converted to: void foo (mytype *retval, int arg0, int arg1) 173 // if mytype is sret. The caller is responsible for allocating space for 174 // retval. (on the stack) sret(jit_convention::type cc)175 bool sret (jit_convention::type cc) const { return m_sret[cc]; } 176 mark_sret(jit_convention::type cc)177 void mark_sret (jit_convention::type cc) 178 { m_sret[cc] = true; } 179 180 // A function like: void foo (mytype arg0) 181 // Will be converted to: void foo (mytype *arg0) 182 // Basically just pass by reference. pointer_arg(jit_convention::type cc)183 bool pointer_arg (jit_convention::type cc) const { return m_pointer_arg[cc]; } 184 mark_pointer_arg(jit_convention::type cc)185 void mark_pointer_arg (jit_convention::type cc) 186 { m_pointer_arg[cc] = true; } 187 188 // Convert into an equivalent form before calling. For example, complex is 189 // represented as two values llvm vector, but we need to pass it as a two 190 // valued llvm structure to C functions. pack(jit_convention::type cc)191 convert_fn pack (jit_convention::type cc) { return m_pack[cc]; } 192 set_pack(jit_convention::type cc,convert_fn fn)193 void set_pack (jit_convention::type cc, convert_fn fn) { m_pack[cc] = fn; } 194 195 // The inverse operation of pack. unpack(jit_convention::type cc)196 convert_fn unpack (jit_convention::type cc) { return m_unpack[cc]; } 197 set_unpack(jit_convention::type cc,convert_fn fn)198 void set_unpack (jit_convention::type cc, convert_fn fn) 199 { m_unpack[cc] = fn; } 200 201 // The resulting type after pack is called. packed_type(jit_convention::type cc)202 llvm::Type * packed_type (jit_convention::type cc) 203 { return m_packed_type[cc]; } 204 set_packed_type(jit_convention::type cc,llvm::Type * ty)205 void set_packed_type (jit_convention::type cc, llvm::Type *ty) 206 { m_packed_type[cc] = ty; } 207 208 private: 209 210 std::string m_name; 211 jit_type *m_parent; 212 llvm::Type *m_llvm_type; 213 int m_id; 214 std::size_t m_depth; 215 bool m_skip_paren; 216 217 bool m_sret[jit_convention::length]; 218 bool m_pointer_arg[jit_convention::length]; 219 220 convert_fn m_pack[jit_convention::length]; 221 convert_fn m_unpack[jit_convention::length]; 222 223 llvm::Type *m_packed_type[jit_convention::length]; 224 }; 225 226 // separate print function to allow easy printing if type is null 227 std::ostream& jit_print (std::ostream& os, jit_type *atype); 228 229 // Find common type 230 jit_type* jit_type_join (jit_type *lhs, jit_type *rhs); 231 232 233 234 class jit_value; 235 236 // An abstraction for calling llvm functions with jit_values. Deals with 237 // calling convention details. 238 class 239 jit_function 240 { 241 friend std::ostream& operator << (std::ostream& os, const jit_function& fn); 242 243 public: 244 245 // create a function in an invalid state 246 jit_function (void); 247 248 jit_function (const jit_module *amodule, jit_convention::type acall_conv, 249 const llvm::Twine& aname, jit_type *aresult, 250 const std::vector<jit_type *>& aargs); 251 252 // Use an existing function, but change the argument types. The new argument 253 // types must behave the same for the current calling convention. 254 jit_function (const jit_function& fn, jit_type *aresult, 255 const std::vector<jit_type *>& aargs); 256 257 jit_function (const jit_function& fn); 258 259 // erase the internal LLVM function (if it exists). Will become invalid. 260 void erase (void); 261 valid(void)262 bool valid (void) const { return m_llvm_function; } 263 264 std::string name (void) const; 265 266 llvm::BasicBlock * new_block (const std::string& aname = "body", 267 llvm::BasicBlock *insert_before = nullptr); 268 269 typedef std::vector<llvm::Value *> arg_vec; 270 271 llvm::Value * call (llvm::IRBuilderD& builder, 272 const arg_vec& in_args = arg_vec ()) const; 273 274 llvm::Value * call (llvm::IRBuilderD& builder, 275 const std::vector<jit_value *>& in_args) const; 276 277 template <typename ...Args> call(llvm::IRBuilderD & builder,arg_vec & in_args,llvm::Value * arg1,Args...other_args)278 llvm::Value * call (llvm::IRBuilderD& builder, arg_vec& in_args, 279 llvm::Value * arg1, Args... other_args) const 280 { 281 in_args.push_back (arg1); 282 return call (builder, in_args, other_args...); 283 } 284 285 template <typename T, typename ...Args> call(llvm::IRBuilderD & builder,arg_vec & in_args,T * arg1,Args...other_args)286 llvm::Value * call (llvm::IRBuilderD& builder, arg_vec& in_args, 287 T * arg1, Args... other_args) const 288 { 289 in_args.push_back (arg1->to_llvm ()); 290 return call (builder, in_args, other_args...); 291 } 292 293 template <typename ...Args> call(llvm::IRBuilderD & builder,llvm::Value * arg1,Args...other_args)294 llvm::Value * call (llvm::IRBuilderD& builder, llvm::Value * arg1, 295 Args... other_args) const 296 { 297 arg_vec in_args; 298 in_args.reserve (1 + sizeof... (other_args)); 299 in_args.push_back (arg1); 300 return call (builder, in_args, other_args...); 301 } 302 303 template <typename T, typename ...Args> call(llvm::IRBuilderD & builder,T * arg1,Args...other_args)304 llvm::Value * call (llvm::IRBuilderD& builder, T * arg1, 305 Args... other_args) const 306 { 307 arg_vec in_args; 308 in_args.reserve (1 + sizeof... (other_args)); 309 in_args.push_back (arg1->to_llvm ()); 310 return call (builder, in_args, other_args...); 311 } 312 313 llvm::Value * argument (llvm::IRBuilderD& builder, std::size_t idx) const; 314 315 void do_return (llvm::IRBuilderD& builder, llvm::Value *rval = nullptr, 316 bool verify = true); 317 to_llvm(void)318 llvm::Function * to_llvm (void) const { return m_llvm_function; } 319 320 // If true, then the return value is passed as a pointer in the first argument sret(void)321 bool sret (void) const { return m_result && m_result->sret (m_call_conv); } 322 can_error(void)323 bool can_error (void) const { return m_can_error; } 324 mark_can_error(void)325 void mark_can_error (void) { m_can_error = true; } 326 result(void)327 jit_type * result (void) const { return m_result; } 328 argument_type(std::size_t idx)329 jit_type * argument_type (std::size_t idx) const 330 { 331 assert (idx < m_args.size ()); 332 return m_args[idx]; 333 } 334 arguments(void)335 const std::vector<jit_type *>& arguments (void) const { return m_args; } 336 337 private: 338 339 const jit_module *m_module; 340 llvm::Function *m_llvm_function; 341 jit_type *m_result; 342 std::vector<jit_type *> m_args; 343 jit_convention::type m_call_conv; 344 bool m_can_error; 345 }; 346 347 std::ostream& operator << (std::ostream& os, const jit_function& fn); 348 349 // Keeps track of information about how to implement operations (+, -, 350 // *, etc.) and their resulting types. 351 class 352 jit_operation 353 { 354 public: 355 jit_operation(const std::string & aname)356 jit_operation (const std::string& aname) { m_name = aname; } 357 358 // type signature vector 359 typedef std::vector<jit_type *> signature_vec; 360 361 virtual ~jit_operation (void); 362 add_overload(const jit_function & func)363 void add_overload (const jit_function& func) 364 { 365 add_overload (func, func.arguments ()); 366 } 367 368 void add_overload (const jit_function& func, 369 const signature_vec& args); 370 371 const jit_function& overload (const signature_vec& types) const; 372 373 template <typename ...Args> overload(signature_vec & args,jit_type * arg1,Args...other_args)374 const jit_function& overload (signature_vec& args, jit_type * arg1, 375 Args... other_args) const 376 { 377 args.push_back (arg1); 378 return overload (args, other_args...); 379 } 380 381 template <typename ...Args> overload(jit_type * arg1,Args...other_args)382 const jit_function& overload (jit_type * arg1, Args... other_args) const 383 { 384 signature_vec args; 385 args.reserve (1 + sizeof... (other_args)); 386 args.push_back (arg1); 387 return overload (args, other_args...); 388 } 389 result(const signature_vec & types)390 jit_type * result (const signature_vec& types) const 391 { 392 const jit_function& temp = overload (types); 393 return temp.result (); 394 } 395 396 template <typename ...Args> result(signature_vec & args,jit_type * arg1,Args...other_args)397 jit_type * result (signature_vec& args, jit_type * arg1, 398 Args... other_args) const 399 { 400 args.push_back (arg1); 401 return overload (args, other_args...); 402 } 403 404 template <typename ...Args> result(jit_type * arg1,Args...other_args)405 jit_type * result (jit_type * arg1, Args... other_args) const 406 { 407 signature_vec args; 408 args.reserve (1 + sizeof... (other_args)); 409 args.push_back (arg1); 410 return overload (args, other_args...); 411 } 412 name(void)413 const std::string& name (void) const { return m_name; } 414 stash_name(const std::string & aname)415 void stash_name (const std::string& aname) { m_name = aname; } 416 417 protected: 418 419 virtual jit_function * generate (const signature_vec& types) const; 420 421 private: 422 423 Array<octave_idx_type> to_idx (const signature_vec& types) const; 424 425 const jit_function& do_generate (const signature_vec& types) const; 426 427 struct signature_cmp 428 { 429 bool operator () (const signature_vec *lhs, const signature_vec *rhs) const; 430 }; 431 432 typedef std::map<const signature_vec *, jit_function *, signature_cmp> 433 generated_map; 434 435 mutable generated_map m_generated; 436 437 std::vector<Array<jit_function>> m_overloads; 438 439 std::string m_name; 440 }; 441 442 443 class 444 jit_index_operation : public jit_operation 445 { 446 public: 447 jit_index_operation(const jit_typeinfo & ti,const std::string & name)448 jit_index_operation (const jit_typeinfo& ti, const std::string& name) 449 : jit_operation (name), m_typeinfo (ti) { } 450 451 protected: 452 453 virtual jit_function * generate (const signature_vec& types) const; 454 455 virtual jit_function * generate_matrix (const signature_vec& types) const = 0; 456 457 // helper functions 458 // [start_idx, end_idx). 459 llvm::Value * create_arg_array (llvm::IRBuilderD& builder, 460 const jit_function& fn, std::size_t start_idx, 461 std::size_t end_idx) const; 462 463 const jit_typeinfo& m_typeinfo; 464 }; 465 466 class 467 jit_paren_subsref : public jit_index_operation 468 { 469 public: 470 471 // FIXME: Avoid creating object in an invalid state? 472 jit_paren_subsref (const jit_typeinfo& ti); 473 ~jit_paren_subsref (void); 474 void init_paren_scalar (void); 475 476 protected: 477 478 virtual jit_function * generate_matrix (const signature_vec& types) const; 479 480 private: 481 482 jit_function *m_paren_scalar; 483 }; 484 485 class 486 jit_paren_subsasgn : public jit_index_operation 487 { 488 public: 489 490 // FIXME: Avoid creating object in an invalid state? 491 jit_paren_subsasgn (const jit_typeinfo& ti); 492 ~jit_paren_subsasgn (void); 493 void init_paren_scalar (void); 494 495 protected: 496 497 jit_function * generate_matrix (const signature_vec& types) const; 498 499 private: 500 501 jit_function *m_paren_scalar; 502 }; 503 504 505 // A singleton class which handles the construction of jit_types 506 class 507 jit_typeinfo 508 { 509 // ----- Constructor/destructor (singleton pattern) ----- 510 511 public: 512 513 ~jit_typeinfo (void); 514 515 private: 516 517 static jit_typeinfo& instance (void); 518 jit_typeinfo (void); 519 static bool s_in_construction; 520 521 // ----- Registering types ----- 522 523 public: 524 525 static jit_type *register_new_type (const std::string& name, jit_type *parent, 526 llvm::Type *llvm_type, bool skip_paren = false) 527 { 528 return instance ().do_register_new_type (name, parent, llvm_type, skip_paren); 529 } 530 531 private: 532 533 // List of all registered types 534 std::vector<jit_type*> m_id_to_type; 535 536 // Register a new type 537 jit_type *do_register_new_type (const std::string& name, jit_type *parent, 538 llvm::Type *llvm_type, bool skip_paren = false); 539 540 // ----- Base types ----- 541 542 public: 543 get_any(void)544 static jit_type *get_any (void) { return instance ().m_any; } 545 get_matrix(void)546 static jit_type *get_matrix (void) { return instance ().m_matrix; } 547 get_scalar(void)548 static jit_type *get_scalar (void) { return instance ().m_scalar; } 549 get_scalar_ptr(void)550 static jit_type *get_scalar_ptr (void) { return instance ().m_scalar_ptr; } 551 get_any_ptr(void)552 static jit_type *get_any_ptr (void) { return instance ().m_any_ptr; } 553 get_range(void)554 static jit_type *get_range (void) { return instance ().m_range; } 555 get_string(void)556 static jit_type *get_string (void) { return instance ().m_string; } 557 get_bool(void)558 static jit_type *get_bool (void) { return instance ().m_boolean; } 559 get_index(void)560 static jit_type *get_index (void) { return instance ().m_index; } 561 get_complex(void)562 static jit_type *get_complex (void) { return instance ().m_complex; } 563 intN(std::size_t nbits)564 static jit_type *intN (std::size_t nbits) { return instance ().do_get_intN (nbits); } 565 566 // FIXME: do we really need these two ? get_scalar_llvm(void)567 static llvm::Type *get_scalar_llvm (void) { return instance ().m_scalar->to_llvm (); } // this one is weird 568 get_index_llvm(void)569 static llvm::Type *get_index_llvm (void) { return instance ().m_index->to_llvm (); } // this one is weird too 570 571 private: 572 573 // Base types as LLVM types 574 575 llvm::Type *m_any_t; 576 llvm::Type *m_bool_t; // FIXME: should be "boolean_t", for consistency 577 llvm::Type *m_complex_t; 578 llvm::Type *m_index_t; 579 llvm::Type *m_scalar_t; 580 llvm::Type *m_string_t; 581 582 llvm::StructType *m_range_t; 583 llvm::StructType *m_matrix_t; 584 585 // Base types as jit_type objects) 586 587 jit_type *m_any; 588 jit_type *m_boolean; 589 jit_type *m_complex; 590 jit_type *m_index; 591 jit_type *m_scalar; 592 jit_type *m_string; 593 594 jit_type *m_range; 595 jit_type *m_matrix; 596 597 jit_type *m_scalar_ptr; // a fake type for interfacing with C++ 598 jit_type *m_any_ptr; // a fake type for interfacing with C++ (bis) 599 jit_type *m_unknown_function; 600 601 // complex_ret is what is passed to C functions 602 // in order to get calling convention right 603 llvm::StructType *m_complex_ret; 604 605 // Get integer type from number of bits 606 jit_type *do_get_intN (std::size_t nbits) const; 607 608 // map container for integer types: int8, int16, etc. 609 // (note that they are also stored in id_to_types) 610 std::map<std::size_t, jit_type *> m_ints; 611 612 // ----- parenthesis subsref/subsasgn ----- 613 614 friend jit_paren_subsref; 615 friend jit_paren_subsasgn; 616 617 public: 618 paren_subsref(void)619 static const jit_operation& paren_subsref (void) { return instance ().paren_subsref_fn; } paren_subsasgn(void)620 static const jit_operation& paren_subsasgn (void) { return instance ().paren_subsasgn_fn; } 621 622 private: 623 624 jit_paren_subsref paren_subsref_fn; 625 jit_paren_subsasgn paren_subsasgn_fn; 626 627 // ----- Miscellaneous (FIXME: needs to be organized) ----- 628 629 public: 630 631 // Get the jit_type of an octave_value type_of(const octave_value & ov)632 static jit_type *type_of (const octave_value &ov) 633 { 634 return instance ().do_type_of (ov); 635 }; 636 637 // Get a unary or binary operation from its integer id binary_op(int op)638 static const jit_operation& binary_op (int op) 639 { 640 return instance ().do_binary_op (op); 641 } 642 unary_op(int op)643 static const jit_operation& unary_op (int op) 644 { 645 return instance ().do_unary_op (op); 646 } 647 grab(void)648 static const jit_operation& grab (void) 649 { 650 return instance ().m_grab_fn; 651 } 652 get_grab(jit_type * type)653 static const jit_function& get_grab (jit_type *type) 654 { 655 return instance ().m_grab_fn.overload (type); 656 } 657 release(void)658 static const jit_operation& release (void) 659 { 660 return instance ().m_release_fn; 661 } 662 get_release(jit_type * type)663 static const jit_function& get_release (jit_type *type) 664 { 665 return instance ().m_release_fn.overload (type); 666 } 667 destroy(void)668 static const jit_operation& destroy (void) 669 { 670 return instance ().m_destroy_fn; 671 } 672 print_value(void)673 static const jit_operation& print_value (void) 674 { 675 return instance ().m_print_fn; 676 } 677 for_init(void)678 static const jit_operation& for_init (void) 679 { 680 return instance ().m_for_init_fn; 681 } 682 for_check(void)683 static const jit_operation& for_check (void) 684 { 685 return instance ().m_for_check_fn; 686 } 687 for_index(void)688 static const jit_operation& for_index (void) 689 { 690 return instance ().m_for_index_fn; 691 } 692 make_range(void)693 static const jit_operation& make_range (void) 694 { 695 return instance ().m_make_range_fn; 696 } 697 logically_true(void)698 static const jit_operation& logically_true (void) 699 { 700 return instance ().m_logically_true_fn; 701 } 702 cast(jit_type * result)703 static const jit_operation& cast (jit_type *result) 704 { 705 return instance ().do_cast (result); 706 } 707 cast(jit_type * to,jit_type * from)708 static const jit_function& cast (jit_type *to, jit_type *from) 709 { 710 return instance ().do_cast (to, from); 711 } 712 insert_error_check(llvm::IRBuilderD & bld)713 static llvm::Value *insert_error_check (llvm::IRBuilderD& bld) 714 { 715 return instance ().do_insert_error_check (bld); 716 } 717 insert_interrupt_check(llvm::IRBuilderD & bld)718 static llvm::Value *insert_interrupt_check (llvm::IRBuilderD& bld) 719 { 720 return instance ().do_insert_interrupt_check (bld); 721 } 722 end(void)723 static const jit_operation& end (void) 724 { 725 return instance ().m_end_fn; 726 } 727 end(jit_value * value,jit_value * idx,jit_value * count)728 static const jit_function& end (jit_value *value, jit_value *idx, 729 jit_value *count) 730 { 731 return instance ().do_end (value, idx, count); 732 } 733 create_undef(void)734 static const jit_operation& create_undef (void) 735 { 736 return instance ().m_create_undef_fn; 737 } 738 create_complex(llvm::Value * real,llvm::Value * imag)739 static llvm::Value *create_complex (llvm::Value *real, llvm::Value *imag) 740 { 741 return instance ().complex_new (real, imag); 742 } 743 pack_complex(llvm::IRBuilderD & bld,llvm::Value * cplx)744 static llvm::Value *pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) 745 { 746 return instance ().do_pack_complex (bld, cplx); 747 } 748 749 static llvm::Value *unpack_complex (llvm::IRBuilderD& bld, 750 llvm::Value *result); 751 752 private: 753 754 jit_type * do_type_of (const octave_value& ov) const; 755 do_binary_op(int op)756 const jit_operation& do_binary_op (int op) const 757 { 758 assert (static_cast<std::size_t> (op) < m_binary_ops.size ()); 759 return m_binary_ops[op]; 760 } 761 do_unary_op(int op)762 const jit_operation& do_unary_op (int op) const 763 { 764 assert (static_cast<std::size_t> (op) < m_unary_ops.size ()); 765 return m_unary_ops[op]; 766 } 767 do_cast(jit_type * to)768 const jit_operation& do_cast (jit_type *to) 769 { 770 static jit_operation null_function ("null_function"); 771 if (! to) 772 return null_function; 773 774 std::size_t id = to->type_id (); 775 if (id >= m_casts.size ()) 776 return null_function; 777 return m_casts[id]; 778 } 779 do_cast(jit_type * to,jit_type * from)780 const jit_function& do_cast (jit_type *to, jit_type *from) 781 { 782 return do_cast (to).overload (from); 783 } 784 785 const jit_function& do_end (jit_value *value, jit_value *index, 786 jit_value *count); 787 788 void add_print (jit_type *ty, void *fptr); 789 790 void add_binary_op (jit_type *ty, int op, int llvm_op); 791 792 void add_binary_icmp (jit_type *ty, int op, int llvm_op); 793 794 void add_binary_fcmp (jit_type *ty, int op, int llvm_op); 795 796 // type signature vector 797 typedef std::vector<jit_type *> signature_vec; 798 799 // create a function with an external calling convention 800 // forces the function pointer to be specified 801 template <typename T> 802 jit_function create_external (T fn, const llvm::Twine& name, 803 jit_type * ret, const signature_vec& args 804 = signature_vec ()) const; 805 806 template <typename T, typename ...Args> create_external(T fn,const llvm::Twine & name,jit_type * ret,signature_vec & args,jit_type * arg1,Args...other_args)807 jit_function create_external (T fn, const llvm::Twine& name, 808 jit_type * ret, signature_vec& args, 809 jit_type * arg1, Args... other_args) const 810 { 811 args.push_back (arg1); 812 return create_external (fn, name, ret, args, other_args...); 813 } 814 815 template <typename T, typename ...Args> create_external(T fn,const llvm::Twine & name,jit_type * ret,jit_type * arg1,Args...other_args)816 jit_function create_external (T fn, const llvm::Twine& name, jit_type *ret, 817 jit_type * arg1, Args... other_args) const 818 { 819 signature_vec args; 820 args.reserve (1 + sizeof... (other_args)); 821 args.push_back (arg1); 822 return create_external (fn, name, ret, args, other_args...); 823 } 824 825 // create an internal calling convention (a function defined in llvm) 826 jit_function create_internal (const llvm::Twine& name, jit_type *ret, 827 const signature_vec& args 828 = signature_vec ()) const 829 { 830 return jit_function (m_base_jit_module, jit_convention::internal, 831 name, ret, args); 832 } 833 834 template <typename ...Args> create_internal(const llvm::Twine & name,jit_type * ret,signature_vec & args,jit_type * arg1,Args...other_args)835 jit_function create_internal (const llvm::Twine& name, jit_type *ret, 836 signature_vec& args, 837 jit_type * arg1, Args... other_args) const 838 { 839 args.push_back (arg1); 840 return create_internal (name, ret, args, other_args...); 841 } 842 843 template <typename ...Args> create_internal(const llvm::Twine & name,jit_type * ret,jit_type * arg1,Args...other_args)844 jit_function create_internal (const llvm::Twine& name, jit_type *ret, 845 jit_type * arg1, Args... other_args) const 846 { 847 signature_vec args; 848 args.reserve (1 + sizeof... (other_args)); 849 args.push_back (arg1); 850 return create_internal (name, ret, args, other_args...); 851 } 852 853 jit_function create_identity (jit_type *type); 854 855 llvm::Value * do_insert_error_check (llvm::IRBuilderD& bld); 856 857 llvm::Value * do_insert_interrupt_check (llvm::IRBuilderD& bld); 858 859 void add_builtin (const std::string& name); 860 register_intrinsic(const std::string & name,std::size_t id,jit_type * result,jit_type * arg0)861 void register_intrinsic (const std::string& name, std::size_t id, 862 jit_type *result, jit_type *arg0) 863 { 864 std::vector<jit_type *> args (1, arg0); 865 register_intrinsic (name, id, result, args); 866 } 867 868 void register_intrinsic (const std::string& name, std::size_t id, jit_type *result, 869 const std::vector<jit_type *>& args); 870 register_generic(const std::string & name,jit_type * result,jit_type * arg0)871 void register_generic (const std::string& name, jit_type *result, 872 jit_type *arg0) 873 { 874 std::vector<jit_type *> args (1, arg0); 875 register_generic (name, result, args); 876 } 877 878 void register_generic (const std::string& name, jit_type *result, 879 const std::vector<jit_type *>& args); 880 881 octave_builtin * find_builtin (const std::string& name); 882 883 jit_function mirror_binary (const jit_function& fn); 884 885 llvm::Function * wrap_complex (llvm::Function *wrap); 886 887 llvm::Value * complex_real (llvm::Value *cx); 888 889 llvm::Value * complex_real (llvm::Value *cx, llvm::Value *real); 890 891 llvm::Value * complex_imag (llvm::Value *cx); 892 893 llvm::Value * complex_imag (llvm::Value *cx, llvm::Value *imag); 894 895 llvm::Value * complex_new (llvm::Value *real, llvm::Value *imag); 896 897 llvm::Value *do_pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) const; 898 899 int m_next_id; 900 901 llvm::GlobalVariable *m_lerror_state; 902 llvm::GlobalVariable *m_loctave_interrupt_state; 903 904 llvm::Type *m_sig_atomic_type; 905 906 std::map<std::string, jit_type *> m_builtins; 907 908 std::vector<jit_operation> m_binary_ops; 909 std::vector<jit_operation> m_unary_ops; 910 jit_operation m_grab_fn; 911 jit_operation m_release_fn; 912 jit_operation m_destroy_fn; 913 jit_operation m_print_fn; 914 jit_operation m_for_init_fn; 915 jit_operation m_for_check_fn; 916 jit_operation m_for_index_fn; 917 jit_operation m_logically_true_fn; 918 jit_operation m_make_range_fn; 919 jit_operation m_end1_fn; 920 jit_operation m_end_fn; 921 jit_operation m_create_undef_fn; 922 923 jit_function m_any_call; 924 925 // type id -> cast function TO that type 926 std::vector<jit_operation> m_casts; 927 928 // type id -> identity function 929 std::vector<jit_function> m_identities; 930 931 jit_module *m_base_jit_module; 932 933 llvm::IRBuilderD *m_builder_ptr; 934 llvm::IRBuilderD& m_builder; 935 }; 936 } 937 938 #endif 939 #endif 940