Mercurial > hg > octave-lyh
annotate src/pt-jit.cc @ 14901:516b4a15b775
doc: Copyright fix in pt-jit.h and pt-jit.cc
author | Max Brister <max@2bass.com> |
---|---|
date | Mon, 07 May 2012 18:37:31 -0600 |
parents | f25d2224fa02 |
children | 54ea692b8ab5 |
rev | line source |
---|---|
14899 | 1 /* |
2 | |
14901
516b4a15b775
doc: Copyright fix in pt-jit.h and pt-jit.cc
Max Brister <max@2bass.com>
parents:
14899
diff
changeset
|
3 Copyright (C) 2012 Max Brister <max@2bass.com> |
14899 | 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 #define __STDC_LIMIT_MACROS | |
24 #define __STDC_CONSTANT_MACROS | |
25 | |
26 #ifdef HAVE_CONFIG_H | |
27 #include <config.h> | |
28 #endif | |
29 | |
30 #include "pt-jit.h" | |
31 | |
32 #include <typeinfo> | |
33 | |
34 #include <llvm/LLVMContext.h> | |
35 #include <llvm/Module.h> | |
36 #include <llvm/Function.h> | |
37 #include <llvm/BasicBlock.h> | |
38 #include <llvm/Support/IRBuilder.h> | |
39 #include <llvm/ExecutionEngine/ExecutionEngine.h> | |
40 #include <llvm/ExecutionEngine/JIT.h> | |
41 #include <llvm/PassManager.h> | |
42 #include <llvm/Analysis/Verifier.h> | |
43 #include <llvm/Analysis/Passes.h> | |
44 #include <llvm/Target/TargetData.h> | |
45 #include <llvm/Transforms/Scalar.h> | |
46 #include <llvm/Support/TargetSelect.h> | |
47 #include <llvm/Support/raw_os_ostream.h> | |
48 | |
49 #include "ov-fcn-handle.h" | |
50 #include "ov-usr-fcn.h" | |
51 #include "pt-all.h" | |
52 | |
53 using namespace llvm; | |
54 | |
55 //FIXME: Move into tree_jit | |
56 static IRBuilder<> builder (getGlobalContext ()); | |
57 | |
58 extern "C" void | |
59 octave_print_double (const char *name, double value) | |
60 { | |
61 // FIXME: We should avoid allocating a new octave_scalar each time | |
62 octave_value ov (value); | |
63 ov.print_with_name (octave_stdout, name); | |
64 } | |
65 | |
66 tree_jit::tree_jit (void) : context (getGlobalContext ()), engine (0) | |
67 { | |
68 InitializeNativeTarget (); | |
69 InitializeNativeTargetAsmPrinter (); | |
70 module = new Module ("octave", context); | |
71 } | |
72 | |
73 tree_jit::~tree_jit (void) | |
74 { | |
75 delete module; | |
76 } | |
77 | |
78 bool | |
79 tree_jit::execute (tree& tee) | |
80 { | |
81 if (!engine) | |
82 { | |
83 engine = ExecutionEngine::createJIT (module); | |
84 | |
85 // initialize pass manager | |
86 pass_manager = new FunctionPassManager (module); | |
87 pass_manager->add (new TargetData(*engine->getTargetData ())); | |
88 pass_manager->add (createBasicAliasAnalysisPass ()); | |
89 pass_manager->add (createPromoteMemoryToRegisterPass ()); | |
90 pass_manager->add (createInstructionCombiningPass ()); | |
91 pass_manager->add (createReassociatePass ()); | |
92 pass_manager->add (createGVNPass ()); | |
93 pass_manager->add (createCFGSimplificationPass ()); | |
94 pass_manager->doInitialization (); | |
95 | |
96 // create external functions | |
97 Type *vtype = Type::getVoidTy (context); | |
98 std::vector<Type*> pd_args (2); | |
99 pd_args[0] = Type::getInt8PtrTy (context); | |
100 pd_args[1] = Type::getDoubleTy (context); | |
101 FunctionType *print_double_ty = FunctionType::get (vtype, pd_args, false); | |
102 print_double = Function::Create (print_double_ty, | |
103 Function::ExternalLinkage, | |
104 "octave_print_double", module); | |
105 engine->addGlobalMapping (print_double, | |
106 reinterpret_cast<void*>(&octave_print_double)); | |
107 } | |
108 | |
109 if (!engine) | |
110 // sometimes this fails during early initialization | |
111 return false; | |
112 | |
113 // find function | |
114 function_info *finfo; | |
115 finfo_map_iterator iter = compiled_functions.find (&tee); | |
116 | |
117 if (iter == compiled_functions.end ()) | |
118 finfo = compile (tee); | |
119 else | |
120 finfo = iter->second; | |
121 | |
122 return finfo->execute (); | |
123 } | |
124 | |
125 tree_jit::function_info* | |
126 tree_jit::compile (tree& tee) | |
127 { | |
128 value_stack.clear (); | |
129 variables.clear (); | |
130 | |
131 // setup function | |
132 std::vector<Type*> args (2); | |
133 args[0] = Type::getInt1PtrTy (context); | |
134 args[1] = Type::getDoublePtrTy (context); | |
135 FunctionType *ft = FunctionType::get (Type::getVoidTy (context), args, false); | |
136 Function *compiling = Function::Create (ft, Function::ExternalLinkage, | |
137 "test_fn", module); | |
138 | |
139 entry_block = BasicBlock::Create (context, "entry", compiling); | |
140 BasicBlock *body = BasicBlock::Create (context, "body", | |
141 compiling); | |
142 builder.SetInsertPoint (body); | |
143 | |
144 // convert tree to LLVM IR | |
145 try | |
146 { | |
147 tee.accept (*this); | |
148 } | |
149 catch (const jit_fail_exception&) | |
150 { | |
151 //FIXME: cleanup | |
152 return compiled_functions[&tee] = new function_info (); | |
153 } | |
154 | |
155 // copy input arguments | |
156 builder.SetInsertPoint (entry_block); | |
157 | |
158 Function::arg_iterator arg_iter = compiling->arg_begin (); | |
159 Value *arg_defined = arg_iter; | |
160 Value *arg_value = ++arg_iter; | |
161 | |
162 arg_defined->setName ("arg_defined"); | |
163 arg_value->setName ("arg_value"); | |
164 | |
165 size_t idx = 0; | |
166 std::vector<std::string> arg_names; | |
167 std::vector<bool> arg_used; | |
168 for (var_map_iterator iter = variables.begin (); iter != variables.end (); | |
169 ++iter, ++idx) | |
170 { | |
171 arg_names.push_back (iter->first); | |
172 arg_used.push_back (iter->second.use); | |
173 | |
174 Value *gep_defined = builder.CreateConstInBoundsGEP1_32 (arg_defined, idx); | |
175 Value *defined = builder.CreateLoad (gep_defined); | |
176 builder.CreateStore (defined, iter->second.defined); | |
177 | |
178 Value *gep_value = builder.CreateConstInBoundsGEP1_32 (arg_value, idx); | |
179 Value *value = builder.CreateLoad (gep_value); | |
180 builder.CreateStore (value, iter->second.value); | |
181 } | |
182 builder.CreateBr (body); | |
183 | |
184 // copy output arguments | |
185 BasicBlock *cleanup = BasicBlock::Create (context, "cleanup", compiling); | |
186 builder.SetInsertPoint (body); | |
187 builder.CreateBr (cleanup); | |
188 builder.SetInsertPoint (cleanup); | |
189 | |
190 idx = 0; | |
191 for (var_map_iterator iter = variables.begin (); iter != variables.end (); | |
192 ++iter, ++idx) | |
193 { | |
194 Value *gep_defined = builder.CreateConstInBoundsGEP1_32 (arg_defined, idx); | |
195 Value *defined = builder.CreateLoad (iter->second.defined); | |
196 builder.CreateStore (defined, gep_defined); | |
197 | |
198 Value *gep_value = builder.CreateConstInBoundsGEP1_32 (arg_value, idx); | |
199 Value *value = builder.CreateLoad (iter->second.value, iter->first); | |
200 builder.CreateStore (value, gep_value); | |
201 } | |
202 | |
203 builder.CreateRetVoid (); | |
204 | |
205 // print what we compiled (for debugging) | |
206 // we leave this in for now, as other people might want to view the ir created | |
207 // should be removed eventually though | |
208 const bool debug_print_ir = false; | |
209 if (debug_print_ir) | |
210 { | |
211 raw_os_ostream os (std::cout); | |
212 std::cout << "Compiling --------------------\n"; | |
213 tree_print_code tpc (std::cout); | |
214 std::cout << typeid (tee).name () << std::endl; | |
215 tee.accept (tpc); | |
216 std::cout << "\n--------------------\n"; | |
217 | |
218 std::cout << "llvm_ir\n"; | |
219 compiling->print (os); | |
220 std::cout << "--------------------\n"; | |
221 } | |
222 | |
223 // compile code | |
224 verifyFunction (*compiling); | |
225 pass_manager->run (*compiling); | |
226 | |
227 if (debug_print_ir) | |
228 { | |
229 raw_os_ostream os (std::cout); | |
230 std::cout << "optimized llvm_ir\n"; | |
231 compiling->print (os); | |
232 std::cout << "--------------------\n"; | |
233 } | |
234 | |
235 jit_function fun = | |
236 reinterpret_cast<jit_function> (engine->getPointerToFunction (compiling)); | |
237 | |
238 return compiled_functions[&tee] = new function_info (fun, arg_names, arg_used); | |
239 } | |
240 | |
241 tree_jit::variable_info | |
242 tree_jit::find (const std::string &name, bool use) | |
243 { | |
244 var_map_iterator iter = variables.find (name); | |
245 if (iter == variables.end ()) | |
246 { | |
247 // we currently just assume everything is a double | |
248 Type *dbl = Type::getDoubleTy (context); | |
249 Type *bol = Type::getInt1Ty (context); | |
250 IRBuilder<> tmpB (entry_block, entry_block->begin ()); | |
251 | |
252 variable_info vinfo; | |
253 vinfo.defined = tmpB.CreateAlloca (bol, 0); | |
254 vinfo.value = tmpB.CreateAlloca (dbl, 0, name); | |
255 vinfo.use = use; | |
256 variables[name] = vinfo; | |
257 return vinfo; | |
258 } | |
259 else | |
260 { | |
261 iter->second.use = iter->second.use || use; | |
262 return iter->second; | |
263 } | |
264 } | |
265 | |
266 void | |
267 tree_jit::do_assign (variable_info vinfo, llvm::Value *value) | |
268 { | |
269 // create assign expression | |
270 Value *result = builder.CreateStore (value, vinfo.value); | |
271 value_stack.push_back (result); | |
272 | |
273 // update defined for lhs | |
274 Type *btype = Type::getInt1Ty (context); | |
275 Value *btrue = ConstantInt::get (btype, APInt (1, 1)); | |
276 builder.CreateStore (btrue, vinfo.defined); | |
277 } | |
278 | |
279 void | |
280 tree_jit::emit_print (const std::string& vname, llvm::Value *value) | |
281 { | |
282 Value *pname = builder.CreateGlobalStringPtr (vname); | |
283 builder.CreateCall2 (print_double, pname, value); | |
284 } | |
285 | |
286 void | |
287 tree_jit::visit_anon_fcn_handle (tree_anon_fcn_handle&) | |
288 { | |
289 fail (); | |
290 } | |
291 | |
292 void | |
293 tree_jit::visit_argument_list (tree_argument_list&) | |
294 { | |
295 fail (); | |
296 } | |
297 | |
298 void | |
299 tree_jit::visit_binary_expression (tree_binary_expression& be) | |
300 { | |
301 tree_expression *lhs = be.lhs (); | |
302 tree_expression *rhs = be.rhs (); | |
303 if (lhs && rhs) | |
304 { | |
305 lhs->accept (*this); | |
306 rhs->accept (*this); | |
307 | |
308 Value *lhsv = value_stack.back (); | |
309 value_stack.pop_back (); | |
310 | |
311 Value *rhsv = value_stack.back (); | |
312 value_stack.pop_back (); | |
313 | |
314 Value *result; | |
315 switch (be.op_type ()) | |
316 { | |
317 case octave_value::op_add: | |
318 result = builder.CreateFAdd (lhsv, rhsv); | |
319 break; | |
320 case octave_value::op_sub: | |
321 result = builder.CreateFSub (lhsv, rhsv); | |
322 break; | |
323 case octave_value::op_mul: | |
324 result = builder.CreateFMul (lhsv, rhsv); | |
325 break; | |
326 case octave_value::op_div: | |
327 result = builder.CreateFDiv (lhsv, rhsv); | |
328 break; | |
329 default: | |
330 fail (); | |
331 } | |
332 | |
333 value_stack.push_back (result); | |
334 } | |
335 else | |
336 fail (); | |
337 } | |
338 | |
339 void | |
340 tree_jit::visit_break_command (tree_break_command&) | |
341 { | |
342 fail (); | |
343 } | |
344 | |
345 void | |
346 tree_jit::visit_colon_expression (tree_colon_expression&) | |
347 { | |
348 fail (); | |
349 } | |
350 | |
351 void | |
352 tree_jit::visit_continue_command (tree_continue_command&) | |
353 { | |
354 fail (); | |
355 } | |
356 | |
357 void | |
358 tree_jit::visit_global_command (tree_global_command&) | |
359 { | |
360 fail (); | |
361 } | |
362 | |
363 void | |
364 tree_jit::visit_persistent_command (tree_persistent_command&) | |
365 { | |
366 fail (); | |
367 } | |
368 | |
369 void | |
370 tree_jit::visit_decl_elt (tree_decl_elt&) | |
371 { | |
372 fail (); | |
373 } | |
374 | |
375 void | |
376 tree_jit::visit_decl_init_list (tree_decl_init_list&) | |
377 { | |
378 fail (); | |
379 } | |
380 | |
381 void | |
382 tree_jit::visit_simple_for_command (tree_simple_for_command&) | |
383 { | |
384 fail (); | |
385 } | |
386 | |
387 void | |
388 tree_jit::visit_complex_for_command (tree_complex_for_command&) | |
389 { | |
390 fail (); | |
391 } | |
392 | |
393 void | |
394 tree_jit::visit_octave_user_script (octave_user_script&) | |
395 { | |
396 fail (); | |
397 } | |
398 | |
399 void | |
400 tree_jit::visit_octave_user_function (octave_user_function&) | |
401 { | |
402 fail (); | |
403 } | |
404 | |
405 void | |
406 tree_jit::visit_octave_user_function_header (octave_user_function&) | |
407 { | |
408 fail (); | |
409 } | |
410 | |
411 void | |
412 tree_jit::visit_octave_user_function_trailer (octave_user_function&) | |
413 { | |
414 fail (); | |
415 } | |
416 | |
417 void | |
418 tree_jit::visit_function_def (tree_function_def&) | |
419 { | |
420 fail (); | |
421 } | |
422 | |
423 void | |
424 tree_jit::visit_identifier (tree_identifier& ti) | |
425 { | |
426 octave_value ov = ti.do_lookup (); | |
427 if (ov.is_function ()) | |
428 fail (); | |
429 | |
430 std::string name = ti.name (); | |
431 variable_info vinfo = find (ti.name (), true); | |
432 | |
433 // TODO check defined | |
434 | |
435 Value *load_value = builder.CreateLoad (vinfo.value, name); | |
436 value_stack.push_back (load_value); | |
437 } | |
438 | |
439 void | |
440 tree_jit::visit_if_clause (tree_if_clause&) | |
441 { | |
442 fail (); | |
443 } | |
444 | |
445 void | |
446 tree_jit::visit_if_command (tree_if_command&) | |
447 { | |
448 fail (); | |
449 } | |
450 | |
451 void | |
452 tree_jit::visit_if_command_list (tree_if_command_list&) | |
453 { | |
454 fail (); | |
455 } | |
456 | |
457 void | |
458 tree_jit::visit_index_expression (tree_index_expression&) | |
459 { | |
460 fail (); | |
461 } | |
462 | |
463 void | |
464 tree_jit::visit_matrix (tree_matrix&) | |
465 { | |
466 fail (); | |
467 } | |
468 | |
469 void | |
470 tree_jit::visit_cell (tree_cell&) | |
471 { | |
472 fail (); | |
473 } | |
474 | |
475 void | |
476 tree_jit::visit_multi_assignment (tree_multi_assignment&) | |
477 { | |
478 fail (); | |
479 } | |
480 | |
481 void | |
482 tree_jit::visit_no_op_command (tree_no_op_command&) | |
483 { | |
484 fail (); | |
485 } | |
486 | |
487 void | |
488 tree_jit::visit_constant (tree_constant& tc) | |
489 { | |
490 octave_value v = tc.rvalue1 (); | |
491 if (v.is_real_scalar () && v.is_double_type ()) | |
492 { | |
493 double dv = v.double_value (); | |
494 Value *lv = ConstantFP::get (context, APFloat (dv)); | |
495 value_stack.push_back (lv); | |
496 } | |
497 else | |
498 fail (); | |
499 } | |
500 | |
501 void | |
502 tree_jit::visit_fcn_handle (tree_fcn_handle&) | |
503 { | |
504 fail (); | |
505 } | |
506 | |
507 void | |
508 tree_jit::visit_parameter_list (tree_parameter_list&) | |
509 { | |
510 fail (); | |
511 } | |
512 | |
513 void | |
514 tree_jit::visit_postfix_expression (tree_postfix_expression&) | |
515 { | |
516 fail (); | |
517 } | |
518 | |
519 void | |
520 tree_jit::visit_prefix_expression (tree_prefix_expression&) | |
521 { | |
522 fail (); | |
523 } | |
524 | |
525 void | |
526 tree_jit::visit_return_command (tree_return_command&) | |
527 { | |
528 fail (); | |
529 } | |
530 | |
531 void | |
532 tree_jit::visit_return_list (tree_return_list&) | |
533 { | |
534 fail (); | |
535 } | |
536 | |
537 void | |
538 tree_jit::visit_simple_assignment (tree_simple_assignment& tsa) | |
539 { | |
540 // only support an identifier as lhs | |
541 tree_identifier *lhs = dynamic_cast<tree_identifier*> (tsa.left_hand_side ()); | |
542 if (!lhs) | |
543 fail (); | |
544 | |
545 variable_info lhsv = find (lhs->name (), false); | |
546 | |
547 // resolve rhs as normal | |
548 tree_expression *rhs = tsa.right_hand_side (); | |
549 rhs->accept (*this); | |
550 | |
551 Value *rhsv = value_stack.back (); | |
552 value_stack.pop_back (); | |
553 | |
554 do_assign (lhsv, rhsv); | |
555 | |
556 if (tsa.print_result ()) | |
557 emit_print (lhs->name (), rhsv); | |
558 } | |
559 | |
560 void | |
561 tree_jit::visit_statement (tree_statement& stmt) | |
562 { | |
563 tree_command *cmd = stmt.command (); | |
564 tree_expression *expr = stmt.expression (); | |
565 | |
566 if (cmd) | |
567 cmd->accept (*this); | |
568 else | |
569 { | |
570 // TODO deal with printing | |
571 | |
572 // stolen from tree_evaluator::visit_statement | |
573 bool do_bind_ans = false; | |
574 | |
575 if (expr->is_identifier ()) | |
576 { | |
577 tree_identifier *id = dynamic_cast<tree_identifier *> (expr); | |
578 | |
579 do_bind_ans = (! id->is_variable ()); | |
580 } | |
581 else | |
582 do_bind_ans = (! expr->is_assignment_expression ()); | |
583 | |
584 expr->accept (*this); | |
585 | |
586 if (do_bind_ans) | |
587 { | |
588 Value *rhs = value_stack.back (); | |
589 value_stack.pop_back (); | |
590 | |
591 variable_info ans = find ("ans", false); | |
592 do_assign (ans, rhs); | |
593 } | |
594 else if (expr->is_identifier () && expr->print_result ()) | |
595 { | |
596 // FIXME: ugly hack, we need to come up with a way to pass | |
597 // nargout to visit_identifier | |
598 emit_print (expr->name (), value_stack.back ()); | |
599 } | |
600 | |
601 | |
602 value_stack.pop_back (); | |
603 } | |
604 } | |
605 | |
606 void | |
607 tree_jit::visit_statement_list (tree_statement_list&) | |
608 { | |
609 fail (); | |
610 } | |
611 | |
612 void | |
613 tree_jit::visit_switch_case (tree_switch_case&) | |
614 { | |
615 fail (); | |
616 } | |
617 | |
618 void | |
619 tree_jit::visit_switch_case_list (tree_switch_case_list&) | |
620 { | |
621 fail (); | |
622 } | |
623 | |
624 void | |
625 tree_jit::visit_switch_command (tree_switch_command&) | |
626 { | |
627 fail (); | |
628 } | |
629 | |
630 void | |
631 tree_jit::visit_try_catch_command (tree_try_catch_command&) | |
632 { | |
633 fail (); | |
634 } | |
635 | |
636 void | |
637 tree_jit::visit_unwind_protect_command (tree_unwind_protect_command&) | |
638 { | |
639 fail (); | |
640 } | |
641 | |
642 void | |
643 tree_jit::visit_while_command (tree_while_command&) | |
644 { | |
645 fail (); | |
646 } | |
647 | |
648 void | |
649 tree_jit::visit_do_until_command (tree_do_until_command&) | |
650 { | |
651 fail (); | |
652 } | |
653 | |
654 void | |
655 tree_jit::fail (void) | |
656 { | |
657 throw jit_fail_exception (); | |
658 } | |
659 | |
660 tree_jit::function_info::function_info (void) : function (0) | |
661 {} | |
662 | |
663 tree_jit::function_info::function_info (jit_function fun, | |
664 const std::vector<std::string>& args, | |
665 const std::vector<bool>& arg_used) : | |
666 function (fun), arguments (args), argument_used (arg_used) | |
667 {} | |
668 | |
669 bool tree_jit::function_info::execute () | |
670 { | |
671 if (! function) | |
672 return false; | |
673 | |
674 // FIXME: we are doing hash lookups every time, this has got to be slow | |
675 unwind_protect up; | |
676 bool *args_defined = new bool[arguments.size ()]; // vector<bool> sucks | |
677 up.add_delete (args_defined); | |
678 | |
679 std::vector<double> args_values (arguments.size ()); | |
680 for (size_t i = 0; i < arguments.size (); ++i) | |
681 { | |
682 octave_value ov = symbol_table::varval (arguments[i]); | |
683 | |
684 if (argument_used[i]) | |
685 { | |
686 if (! (ov.is_double_type () && ov.is_real_scalar ())) | |
687 return false; | |
688 | |
689 args_defined[i] = ov.is_defined (); | |
690 args_values[i] = ov.double_value (); | |
691 } | |
692 else | |
693 args_defined[i] = false; | |
694 } | |
695 | |
696 function (args_defined, &args_values[0]); | |
697 | |
698 for (size_t i = 0; i < arguments.size (); ++i) | |
699 if (args_defined[i]) | |
700 symbol_table::varref (arguments[i]) = octave_value (args_values[i]); | |
701 | |
702 return true; | |
703 } |