Mercurial > octave-nkf
comparison libinterp/corefcn/pt-jit.cc @ 16892:68fc671a9339
maint: Collapse interpfcn and interpfcn-core directories into corefcn directory.
* libgui/src/module.mk: Remove -I references to interp-core, interpfcn, add
reference to corefcn.
* libinterp/Makefile.am: Remove -I references to interp-core, interpfcn, add
reference to corefcn.
* libinterp/corefcn/module.mk: Add files from interp-core, interpfcn to
build system. Copy over special rules from module.mk files in interp-core
andd interpfcn.
* src/Makefile.am: Replace references to interp-core, interpfcn with those
to corefcn.
* libinterp/corefcn/Cell.cc, libinterp/corefcn/Cell.h,
libinterp/corefcn/action-container.h, libinterp/corefcn/c-file-ptr-stream.cc,
libinterp/corefcn/c-file-ptr-stream.h, libinterp/corefcn/comment-list.cc,
libinterp/corefcn/comment-list.h, libinterp/corefcn/cutils.c,
libinterp/corefcn/cutils.h, libinterp/corefcn/data.cc,
libinterp/corefcn/data.h, libinterp/corefcn/debug.cc,
libinterp/corefcn/debug.h, libinterp/corefcn/defaults.cc,
libinterp/corefcn/defaults.in.h, libinterp/corefcn/defun-dld.h,
libinterp/corefcn/defun-int.h, libinterp/corefcn/defun.cc,
libinterp/corefcn/defun.h, libinterp/corefcn/dirfns.cc,
libinterp/corefcn/dirfns.h, libinterp/corefcn/display.cc,
libinterp/corefcn/display.h, libinterp/corefcn/dynamic-ld.cc,
libinterp/corefcn/dynamic-ld.h, libinterp/corefcn/error.cc,
libinterp/corefcn/error.h, libinterp/corefcn/event-queue.h,
libinterp/corefcn/file-io.cc, libinterp/corefcn/file-io.h,
libinterp/corefcn/gl-render.cc, libinterp/corefcn/gl-render.h,
libinterp/corefcn/gl2ps-renderer.cc, libinterp/corefcn/gl2ps-renderer.h,
libinterp/corefcn/gl2ps.c, libinterp/corefcn/gl2ps.h,
libinterp/corefcn/graphics.cc, libinterp/corefcn/graphics.in.h,
libinterp/corefcn/gripes.cc, libinterp/corefcn/gripes.h,
libinterp/corefcn/help.cc, libinterp/corefcn/help.h,
libinterp/corefcn/hook-fcn.cc, libinterp/corefcn/hook-fcn.h,
libinterp/corefcn/input.cc, libinterp/corefcn/input.h,
libinterp/corefcn/jit-ir.cc, libinterp/corefcn/jit-ir.h,
libinterp/corefcn/jit-typeinfo.cc, libinterp/corefcn/jit-typeinfo.h,
libinterp/corefcn/jit-util.cc, libinterp/corefcn/jit-util.h,
libinterp/corefcn/load-path.cc, libinterp/corefcn/load-path.h,
libinterp/corefcn/load-save.cc, libinterp/corefcn/load-save.h,
libinterp/corefcn/ls-ascii-helper.cc, libinterp/corefcn/ls-ascii-helper.h,
libinterp/corefcn/ls-hdf5.cc, libinterp/corefcn/ls-hdf5.h,
libinterp/corefcn/ls-mat-ascii.cc, libinterp/corefcn/ls-mat-ascii.h,
libinterp/corefcn/ls-mat4.cc, libinterp/corefcn/ls-mat4.h,
libinterp/corefcn/ls-mat5.cc, libinterp/corefcn/ls-mat5.h,
libinterp/corefcn/ls-oct-ascii.cc, libinterp/corefcn/ls-oct-ascii.h,
libinterp/corefcn/ls-oct-binary.cc, libinterp/corefcn/ls-oct-binary.h,
libinterp/corefcn/ls-utils.cc, libinterp/corefcn/ls-utils.h,
libinterp/corefcn/matherr.c, libinterp/corefcn/mex.cc, libinterp/corefcn/mex.h,
libinterp/corefcn/mexproto.h, libinterp/corefcn/mxarray.in.h,
libinterp/corefcn/oct-errno.h, libinterp/corefcn/oct-errno.in.cc,
libinterp/corefcn/oct-fstrm.cc, libinterp/corefcn/oct-fstrm.h,
libinterp/corefcn/oct-hdf5.h, libinterp/corefcn/oct-hist.cc,
libinterp/corefcn/oct-hist.h, libinterp/corefcn/oct-iostrm.cc,
libinterp/corefcn/oct-iostrm.h, libinterp/corefcn/oct-lvalue.cc,
libinterp/corefcn/oct-lvalue.h, libinterp/corefcn/oct-map.cc,
libinterp/corefcn/oct-map.h, libinterp/corefcn/oct-obj.cc,
libinterp/corefcn/oct-obj.h, libinterp/corefcn/oct-prcstrm.cc,
libinterp/corefcn/oct-prcstrm.h, libinterp/corefcn/oct-procbuf.cc,
libinterp/corefcn/oct-procbuf.h, libinterp/corefcn/oct-stdstrm.h,
libinterp/corefcn/oct-stream.cc, libinterp/corefcn/oct-stream.h,
libinterp/corefcn/oct-strstrm.cc, libinterp/corefcn/oct-strstrm.h,
libinterp/corefcn/oct.h, libinterp/corefcn/octave-link.cc,
libinterp/corefcn/octave-link.h, libinterp/corefcn/pager.cc,
libinterp/corefcn/pager.h, libinterp/corefcn/pr-output.cc,
libinterp/corefcn/pr-output.h, libinterp/corefcn/procstream.cc,
libinterp/corefcn/procstream.h, libinterp/corefcn/profiler.cc,
libinterp/corefcn/profiler.h, libinterp/corefcn/pt-jit.cc,
libinterp/corefcn/pt-jit.h, libinterp/corefcn/sighandlers.cc,
libinterp/corefcn/sighandlers.h, libinterp/corefcn/siglist.c,
libinterp/corefcn/siglist.h, libinterp/corefcn/sparse-xdiv.cc,
libinterp/corefcn/sparse-xdiv.h, libinterp/corefcn/sparse-xpow.cc,
libinterp/corefcn/sparse-xpow.h, libinterp/corefcn/symtab.cc,
libinterp/corefcn/symtab.h, libinterp/corefcn/sysdep.cc,
libinterp/corefcn/sysdep.h, libinterp/corefcn/toplev.cc,
libinterp/corefcn/toplev.h, libinterp/corefcn/txt-eng-ft.cc,
libinterp/corefcn/txt-eng-ft.h, libinterp/corefcn/txt-eng.h,
libinterp/corefcn/unwind-prot.cc, libinterp/corefcn/unwind-prot.h,
libinterp/corefcn/utils.cc, libinterp/corefcn/utils.h,
libinterp/corefcn/variables.cc, libinterp/corefcn/variables.h,
libinterp/corefcn/workspace-element.h, libinterp/corefcn/xdiv.cc,
libinterp/corefcn/xdiv.h, libinterp/corefcn/xgl2ps.c,
libinterp/corefcn/xnorm.cc, libinterp/corefcn/xnorm.h,
libinterp/corefcn/xpow.cc, libinterp/corefcn/xpow.h,
libinterp/corefcn/zfstream.cc, libinterp/corefcn/zfstream.h:
Files moved from interp-core and interpfcn directories.
* libinterp/interp-core/Cell.cc, libinterp/interp-core/Cell.h,
libinterp/interp-core/action-container.h,
libinterp/interp-core/c-file-ptr-stream.cc,
libinterp/interp-core/c-file-ptr-stream.h,
libinterp/interp-core/comment-list.cc, libinterp/interp-core/comment-list.h,
libinterp/interp-core/cutils.c, libinterp/interp-core/cutils.h,
libinterp/interp-core/defun-dld.h, libinterp/interp-core/defun-int.h,
libinterp/interp-core/display.cc, libinterp/interp-core/display.h,
libinterp/interp-core/dynamic-ld.cc, libinterp/interp-core/dynamic-ld.h,
libinterp/interp-core/event-queue.h, libinterp/interp-core/gl-render.cc,
libinterp/interp-core/gl-render.h, libinterp/interp-core/gl2ps-renderer.cc,
libinterp/interp-core/gl2ps-renderer.h, libinterp/interp-core/gl2ps.c,
libinterp/interp-core/gl2ps.h, libinterp/interp-core/gripes.cc,
libinterp/interp-core/gripes.h, libinterp/interp-core/jit-ir.cc,
libinterp/interp-core/jit-ir.h, libinterp/interp-core/jit-typeinfo.cc,
libinterp/interp-core/jit-typeinfo.h, libinterp/interp-core/jit-util.cc,
libinterp/interp-core/jit-util.h, libinterp/interp-core/ls-ascii-helper.cc,
libinterp/interp-core/ls-ascii-helper.h, libinterp/interp-core/ls-hdf5.cc,
libinterp/interp-core/ls-hdf5.h, libinterp/interp-core/ls-mat-ascii.cc,
libinterp/interp-core/ls-mat-ascii.h, libinterp/interp-core/ls-mat4.cc,
libinterp/interp-core/ls-mat4.h, libinterp/interp-core/ls-mat5.cc,
libinterp/interp-core/ls-mat5.h, libinterp/interp-core/ls-oct-binary.cc,
libinterp/interp-core/ls-oct-binary.h, libinterp/interp-core/ls-utils.cc,
libinterp/interp-core/ls-utils.h, libinterp/interp-core/matherr.c,
libinterp/interp-core/mex.cc, libinterp/interp-core/mex.h,
libinterp/interp-core/mexproto.h, libinterp/interp-core/module.mk,
libinterp/interp-core/mxarray.in.h, libinterp/interp-core/oct-errno.h,
libinterp/interp-core/oct-errno.in.cc, libinterp/interp-core/oct-fstrm.cc,
libinterp/interp-core/oct-fstrm.h, libinterp/interp-core/oct-hdf5.h,
libinterp/interp-core/oct-iostrm.cc, libinterp/interp-core/oct-iostrm.h,
libinterp/interp-core/oct-lvalue.cc, libinterp/interp-core/oct-lvalue.h,
libinterp/interp-core/oct-map.cc, libinterp/interp-core/oct-map.h,
libinterp/interp-core/oct-obj.cc, libinterp/interp-core/oct-obj.h,
libinterp/interp-core/oct-prcstrm.cc, libinterp/interp-core/oct-prcstrm.h,
libinterp/interp-core/oct-procbuf.cc, libinterp/interp-core/oct-procbuf.h,
libinterp/interp-core/oct-stdstrm.h, libinterp/interp-core/oct-stream.cc,
libinterp/interp-core/oct-stream.h, libinterp/interp-core/oct-strstrm.cc,
libinterp/interp-core/oct-strstrm.h, libinterp/interp-core/oct.h,
libinterp/interp-core/procstream.cc, libinterp/interp-core/procstream.h,
libinterp/interp-core/pt-jit.cc, libinterp/interp-core/pt-jit.h,
libinterp/interp-core/siglist.c, libinterp/interp-core/siglist.h,
libinterp/interp-core/sparse-xdiv.cc, libinterp/interp-core/sparse-xdiv.h,
libinterp/interp-core/sparse-xpow.cc, libinterp/interp-core/sparse-xpow.h,
libinterp/interp-core/txt-eng-ft.cc, libinterp/interp-core/txt-eng-ft.h,
libinterp/interp-core/txt-eng.h, libinterp/interp-core/unwind-prot.cc,
libinterp/interp-core/unwind-prot.h, libinterp/interp-core/xdiv.cc,
libinterp/interp-core/xdiv.h, libinterp/interp-core/xgl2ps.c,
libinterp/interp-core/xnorm.cc, libinterp/interp-core/xnorm.h,
libinterp/interp-core/xpow.cc, libinterp/interp-core/xpow.h,
libinterp/interp-core/zfstream.cc, libinterp/interp-core/zfstream.h,
libinterp/interpfcn/data.cc, libinterp/interpfcn/data.h,
libinterp/interpfcn/debug.cc, libinterp/interpfcn/debug.h,
libinterp/interpfcn/defaults.cc, libinterp/interpfcn/defaults.in.h,
libinterp/interpfcn/defun.cc, libinterp/interpfcn/defun.h,
libinterp/interpfcn/dirfns.cc, libinterp/interpfcn/dirfns.h,
libinterp/interpfcn/error.cc, libinterp/interpfcn/error.h,
libinterp/interpfcn/file-io.cc, libinterp/interpfcn/file-io.h,
libinterp/interpfcn/graphics.cc, libinterp/interpfcn/graphics.in.h,
libinterp/interpfcn/help.cc, libinterp/interpfcn/help.h,
libinterp/interpfcn/hook-fcn.cc, libinterp/interpfcn/hook-fcn.h,
libinterp/interpfcn/input.cc, libinterp/interpfcn/input.h,
libinterp/interpfcn/load-path.cc, libinterp/interpfcn/load-path.h,
libinterp/interpfcn/load-save.cc, libinterp/interpfcn/load-save.h,
libinterp/interpfcn/ls-oct-ascii.cc, libinterp/interpfcn/ls-oct-ascii.h,
libinterp/interpfcn/module.mk, libinterp/interpfcn/oct-hist.cc,
libinterp/interpfcn/oct-hist.h, libinterp/interpfcn/octave-link.cc,
libinterp/interpfcn/octave-link.h, libinterp/interpfcn/pager.cc,
libinterp/interpfcn/pager.h, libinterp/interpfcn/pr-output.cc,
libinterp/interpfcn/pr-output.h, libinterp/interpfcn/profiler.cc,
libinterp/interpfcn/profiler.h, libinterp/interpfcn/sighandlers.cc,
libinterp/interpfcn/sighandlers.h, libinterp/interpfcn/symtab.cc,
libinterp/interpfcn/symtab.h, libinterp/interpfcn/sysdep.cc,
libinterp/interpfcn/sysdep.h, libinterp/interpfcn/toplev.cc,
libinterp/interpfcn/toplev.h, libinterp/interpfcn/utils.cc,
libinterp/interpfcn/utils.h, libinterp/interpfcn/variables.cc,
libinterp/interpfcn/variables.h, libinterp/interpfcn/workspace-element.h:
deleted files.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 03 Jul 2013 17:43:48 -0700 |
parents | libinterp/interp-core/pt-jit.cc@5482cd26311a |
children | 498b2dd1bd56 c2a57f9c6a2e |
comparison
equal
deleted
inserted
replaced
16891:486c3e2731ff | 16892:68fc671a9339 |
---|---|
1 /* | |
2 | |
3 Copyright (C) 2012 Max Brister | |
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 // Author: Max Brister <max@2bass.com> | |
24 | |
25 #define __STDC_LIMIT_MACROS | |
26 #define __STDC_CONSTANT_MACROS | |
27 | |
28 #ifdef HAVE_CONFIG_H | |
29 #include <config.h> | |
30 #endif | |
31 | |
32 #include "debug.h" | |
33 #include "defun.h" | |
34 #include "ov.h" | |
35 #include "pt-all.h" | |
36 #include "pt-jit.h" | |
37 #include "sighandlers.h" | |
38 #include "symtab.h" | |
39 #include "variables.h" | |
40 | |
41 #ifdef HAVE_LLVM | |
42 | |
43 static bool Vdebug_jit = false; | |
44 | |
45 static bool Vjit_enable = true; | |
46 | |
47 #include <llvm/Analysis/CallGraph.h> | |
48 #include <llvm/Analysis/Passes.h> | |
49 #include <llvm/Analysis/Verifier.h> | |
50 #include <llvm/Bitcode/ReaderWriter.h> | |
51 #include <llvm/LLVMContext.h> | |
52 #include <llvm/ExecutionEngine/ExecutionEngine.h> | |
53 #include <llvm/ExecutionEngine/JIT.h> | |
54 #include <llvm/Module.h> | |
55 #include <llvm/PassManager.h> | |
56 #include <llvm/Support/IRBuilder.h> | |
57 #include <llvm/Support/raw_os_ostream.h> | |
58 #include <llvm/Support/TargetSelect.h> | |
59 #include <llvm/Target/TargetData.h> | |
60 #include <llvm/Transforms/IPO.h> | |
61 #include <llvm/Transforms/Scalar.h> | |
62 | |
63 static llvm::IRBuilder<> builder (llvm::getGlobalContext ()); | |
64 | |
65 static llvm::LLVMContext& context = llvm::getGlobalContext (); | |
66 | |
67 // -------------------- jit_break_exception -------------------- | |
68 | |
69 // jit_break is thrown whenever a branch we are converting has only breaks or | |
70 // continues. This is because all code that follows a break or continue is dead. | |
71 class jit_break_exception : public std::exception {}; | |
72 | |
73 // -------------------- jit_convert -------------------- | |
74 jit_convert::jit_convert (tree &tee, jit_type *for_bounds) | |
75 : converting_function (false) | |
76 { | |
77 initialize (symbol_table::current_scope ()); | |
78 | |
79 if (for_bounds) | |
80 create_variable (next_for_bounds (false), for_bounds); | |
81 | |
82 try | |
83 { | |
84 visit (tee); | |
85 } | |
86 catch (const jit_break_exception&) | |
87 {} | |
88 | |
89 // breaks must have been handled by the top level loop | |
90 assert (breaks.empty ()); | |
91 assert (continues.empty ()); | |
92 | |
93 block->append (factory.create<jit_branch> (final_block)); | |
94 blocks.push_back (final_block); | |
95 | |
96 for (variable_map::iterator iter = vmap.begin (); iter != vmap.end (); ++iter) | |
97 { | |
98 jit_variable *var = iter->second; | |
99 const std::string& name = var->name (); | |
100 if (name.size () && name[0] != '#') | |
101 final_block->append (factory.create<jit_store_argument> (var)); | |
102 } | |
103 | |
104 final_block->append (factory.create<jit_return> ()); | |
105 } | |
106 | |
107 jit_convert::jit_convert (octave_user_function& fcn, | |
108 const std::vector<jit_type *>& args) | |
109 : converting_function (true) | |
110 { | |
111 initialize (fcn.scope ()); | |
112 | |
113 tree_parameter_list *plist = fcn.parameter_list (); | |
114 tree_parameter_list *rlist = fcn.return_list (); | |
115 if (plist && plist->takes_varargs ()) | |
116 throw jit_fail_exception ("varags not supported"); | |
117 | |
118 if (rlist && (rlist->size () > 1 || rlist->takes_varargs ())) | |
119 throw jit_fail_exception ("multiple returns not supported"); | |
120 | |
121 if (plist) | |
122 { | |
123 tree_parameter_list::iterator piter = plist->begin (); | |
124 for (size_t i = 0; i < args.size (); ++i, ++piter) | |
125 { | |
126 if (piter == plist->end ()) | |
127 throw jit_fail_exception ("Too many parameter to function"); | |
128 | |
129 tree_decl_elt *elt = *piter; | |
130 std::string name = elt->name (); | |
131 create_variable (name, args[i]); | |
132 } | |
133 } | |
134 | |
135 jit_value *return_value = 0; | |
136 bool all_breaking = false; | |
137 if (fcn.is_special_expr ()) | |
138 { | |
139 tree_expression *expr = fcn.special_expr (); | |
140 if (expr) | |
141 { | |
142 jit_variable *retvar = get_variable ("#return"); | |
143 jit_value *retval; | |
144 try | |
145 { | |
146 retval = visit (expr); | |
147 } | |
148 catch (const jit_break_exception&) | |
149 {} | |
150 | |
151 if (breaks.size () || continues.size ()) | |
152 throw jit_fail_exception ("break/continue not supported in " | |
153 "anonymous functions"); | |
154 | |
155 block->append (factory.create<jit_assign> (retvar, retval)); | |
156 return_value = retvar; | |
157 } | |
158 } | |
159 else | |
160 { | |
161 try | |
162 { | |
163 visit_statement_list (*fcn.body ()); | |
164 } | |
165 catch (const jit_break_exception&) | |
166 { | |
167 all_breaking = true; | |
168 } | |
169 | |
170 // the user may use break or continue to exit the function | |
171 finish_breaks (final_block, continues); | |
172 finish_breaks (final_block, breaks); | |
173 } | |
174 | |
175 if (! all_breaking) | |
176 block->append (factory.create<jit_branch> (final_block)); | |
177 | |
178 blocks.push_back (final_block); | |
179 block = final_block; | |
180 | |
181 if (! return_value && rlist && rlist->size () == 1) | |
182 { | |
183 tree_decl_elt *elt = rlist->front (); | |
184 return_value = get_variable (elt->name ()); | |
185 } | |
186 | |
187 // FIXME: We should use live range analysis to delete variables where needed. | |
188 // For now we just delete everything at the end of the function. | |
189 for (variable_map::iterator iter = vmap.begin (); iter != vmap.end (); ++iter) | |
190 { | |
191 if (iter->second != return_value) | |
192 { | |
193 jit_call *call; | |
194 call = factory.create<jit_call> (&jit_typeinfo::destroy, | |
195 iter->second); | |
196 final_block->append (call); | |
197 } | |
198 } | |
199 | |
200 if (return_value) | |
201 final_block->append (factory.create<jit_return> (return_value)); | |
202 else | |
203 final_block->append (factory.create<jit_return> ()); | |
204 } | |
205 | |
206 void | |
207 jit_convert::visit_anon_fcn_handle (tree_anon_fcn_handle&) | |
208 { | |
209 throw jit_fail_exception (); | |
210 } | |
211 | |
212 void | |
213 jit_convert::visit_argument_list (tree_argument_list&) | |
214 { | |
215 throw jit_fail_exception (); | |
216 } | |
217 | |
218 void | |
219 jit_convert::visit_binary_expression (tree_binary_expression& be) | |
220 { | |
221 if (be.op_type () >= octave_value::num_binary_ops) | |
222 { | |
223 tree_boolean_expression *boole; | |
224 boole = dynamic_cast<tree_boolean_expression *> (&be); | |
225 assert (boole); | |
226 bool is_and = boole->op_type () == tree_boolean_expression::bool_and; | |
227 | |
228 std::string short_name = next_shortcircut_result (); | |
229 jit_variable *short_result = factory.create<jit_variable> (short_name); | |
230 vmap[short_name] = short_result; | |
231 | |
232 jit_block *done = factory.create<jit_block> (block->name ()); | |
233 tree_expression *lhs = be.lhs (); | |
234 jit_value *lhsv = visit (lhs); | |
235 lhsv = create_checked (&jit_typeinfo::logically_true, lhsv); | |
236 | |
237 jit_block *short_early = factory.create<jit_block> ("short_early"); | |
238 blocks.push_back (short_early); | |
239 | |
240 jit_block *short_cont = factory.create<jit_block> ("short_cont"); | |
241 | |
242 if (is_and) | |
243 block->append (factory.create<jit_cond_branch> (lhsv, short_cont, short_early)); | |
244 else | |
245 block->append (factory.create<jit_cond_branch> (lhsv, short_early, short_cont)); | |
246 | |
247 block = short_early; | |
248 | |
249 jit_value *early_result = factory.create<jit_const_bool> (! is_and); | |
250 block->append (factory.create<jit_assign> (short_result, early_result)); | |
251 block->append (factory.create<jit_branch> (done)); | |
252 | |
253 blocks.push_back (short_cont); | |
254 block = short_cont; | |
255 | |
256 tree_expression *rhs = be.rhs (); | |
257 jit_value *rhsv = visit (rhs); | |
258 rhsv = create_checked (&jit_typeinfo::logically_true, rhsv); | |
259 block->append (factory.create<jit_assign> (short_result, rhsv)); | |
260 block->append (factory.create<jit_branch> (done)); | |
261 | |
262 blocks.push_back (done); | |
263 block = done; | |
264 result = short_result; | |
265 } | |
266 else | |
267 { | |
268 tree_expression *lhs = be.lhs (); | |
269 jit_value *lhsv = visit (lhs); | |
270 | |
271 tree_expression *rhs = be.rhs (); | |
272 jit_value *rhsv = visit (rhs); | |
273 | |
274 const jit_operation& fn = jit_typeinfo::binary_op (be.op_type ()); | |
275 result = create_checked (fn, lhsv, rhsv); | |
276 } | |
277 } | |
278 | |
279 void | |
280 jit_convert::visit_break_command (tree_break_command&) | |
281 { | |
282 breaks.push_back (block); | |
283 throw jit_break_exception (); | |
284 } | |
285 | |
286 void | |
287 jit_convert::visit_colon_expression (tree_colon_expression& expr) | |
288 { | |
289 // in the futher we need to add support for classes and deal with rvalues | |
290 jit_value *base = visit (expr.base ()); | |
291 jit_value *limit = visit (expr.limit ()); | |
292 jit_value *increment; | |
293 tree_expression *tinc = expr.increment (); | |
294 | |
295 if (tinc) | |
296 increment = visit (tinc); | |
297 else | |
298 increment = factory.create<jit_const_scalar> (1); | |
299 | |
300 result = block->append (factory.create<jit_call> (jit_typeinfo::make_range, base, | |
301 limit, increment)); | |
302 } | |
303 | |
304 void | |
305 jit_convert::visit_continue_command (tree_continue_command&) | |
306 { | |
307 continues.push_back (block); | |
308 throw jit_break_exception (); | |
309 } | |
310 | |
311 void | |
312 jit_convert::visit_global_command (tree_global_command&) | |
313 { | |
314 throw jit_fail_exception (); | |
315 } | |
316 | |
317 void | |
318 jit_convert::visit_persistent_command (tree_persistent_command&) | |
319 { | |
320 throw jit_fail_exception (); | |
321 } | |
322 | |
323 void | |
324 jit_convert::visit_decl_elt (tree_decl_elt&) | |
325 { | |
326 throw jit_fail_exception (); | |
327 } | |
328 | |
329 void | |
330 jit_convert::visit_decl_init_list (tree_decl_init_list&) | |
331 { | |
332 throw jit_fail_exception (); | |
333 } | |
334 | |
335 void | |
336 jit_convert::visit_simple_for_command (tree_simple_for_command& cmd) | |
337 { | |
338 // Note we do an initial check to see if the loop will run atleast once. | |
339 // This allows us to get better type inference bounds on variables defined | |
340 // and used only inside the for loop (e.g. the index variable) | |
341 | |
342 // If we are a nested for loop we need to store the previous breaks | |
343 unwind_protect prot; | |
344 prot.protect_var (breaks); | |
345 prot.protect_var (continues); | |
346 breaks.clear (); | |
347 continues.clear (); | |
348 | |
349 // we need a variable for our iterator, because it is used in multiple blocks | |
350 std::string iter_name = next_iterator (); | |
351 jit_variable *iterator = factory.create<jit_variable> (iter_name); | |
352 factory.create<jit_variable> (iter_name); | |
353 vmap[iter_name] = iterator; | |
354 | |
355 jit_block *body = factory.create<jit_block> ("for_body"); | |
356 jit_block *tail = factory.create<jit_block> ("for_tail"); | |
357 | |
358 // do control expression, iter init, and condition check in prev_block (block) | |
359 // if we are the top level for loop, the bounds is an input argument. | |
360 jit_value *control = find_variable (next_for_bounds ()); | |
361 if (! control) | |
362 control = visit (cmd.control_expr ()); | |
363 jit_call *init_iter = factory.create<jit_call> (jit_typeinfo::for_init, | |
364 control); | |
365 block->append (init_iter); | |
366 block->append (factory.create<jit_assign> (iterator, init_iter)); | |
367 | |
368 jit_call *check = factory.create<jit_call> (jit_typeinfo::for_check, control, | |
369 iterator); | |
370 block->append (check); | |
371 block->append (factory.create<jit_cond_branch> (check, body, tail)); | |
372 | |
373 blocks.push_back (body); | |
374 block = body; | |
375 | |
376 // compute the syntactical iterator | |
377 jit_call *idx_rhs = factory.create<jit_call> (jit_typeinfo::for_index, | |
378 control, iterator); | |
379 block->append (idx_rhs); | |
380 do_assign (cmd.left_hand_side (), idx_rhs); | |
381 | |
382 // do loop | |
383 tree_statement_list *pt_body = cmd.body (); | |
384 bool all_breaking = false; | |
385 try | |
386 { | |
387 pt_body->accept (*this); | |
388 } | |
389 catch (const jit_break_exception&) | |
390 { | |
391 if (continues.empty ()) | |
392 { | |
393 // WTF are you doing user? Every branch was a break, why did you have | |
394 // a loop??? Users are silly people... | |
395 finish_breaks (tail, breaks); | |
396 blocks.push_back (tail); | |
397 block = tail; | |
398 return; | |
399 } | |
400 | |
401 all_breaking = true; | |
402 } | |
403 | |
404 // check our condition, continues jump to this block | |
405 jit_block *check_block = factory.create<jit_block> ("for_check"); | |
406 blocks.push_back (check_block); | |
407 | |
408 jit_block *interrupt_check = factory.create<jit_block> ("for_interrupt"); | |
409 blocks.push_back (interrupt_check); | |
410 | |
411 if (! all_breaking) | |
412 block->append (factory.create<jit_branch> (check_block)); | |
413 finish_breaks (check_block, continues); | |
414 | |
415 block = check_block; | |
416 const jit_operation& add_fn = jit_typeinfo::binary_op (octave_value::op_add); | |
417 jit_value *one = factory.create<jit_const_index> (1); | |
418 jit_call *iter_inc = factory.create<jit_call> (add_fn, iterator, one); | |
419 block->append (iter_inc); | |
420 block->append (factory.create<jit_assign> (iterator, iter_inc)); | |
421 check = block->append (factory.create<jit_call> (jit_typeinfo::for_check, | |
422 control, iterator)); | |
423 block->append (factory.create<jit_cond_branch> (check, interrupt_check, | |
424 tail)); | |
425 | |
426 block = interrupt_check; | |
427 jit_error_check *ec | |
428 = factory.create<jit_error_check> (jit_error_check::var_interrupt, | |
429 body, final_block); | |
430 block->append (ec); | |
431 | |
432 // breaks will go to our tail | |
433 blocks.push_back (tail); | |
434 finish_breaks (tail, breaks); | |
435 block = tail; | |
436 } | |
437 | |
438 void | |
439 jit_convert::visit_complex_for_command (tree_complex_for_command&) | |
440 { | |
441 throw jit_fail_exception (); | |
442 } | |
443 | |
444 void | |
445 jit_convert::visit_octave_user_script (octave_user_script&) | |
446 { | |
447 throw jit_fail_exception (); | |
448 } | |
449 | |
450 void | |
451 jit_convert::visit_octave_user_function (octave_user_function&) | |
452 { | |
453 throw jit_fail_exception (); | |
454 } | |
455 | |
456 void | |
457 jit_convert::visit_octave_user_function_header (octave_user_function&) | |
458 { | |
459 throw jit_fail_exception (); | |
460 } | |
461 | |
462 void | |
463 jit_convert::visit_octave_user_function_trailer (octave_user_function&) | |
464 { | |
465 throw jit_fail_exception (); | |
466 } | |
467 | |
468 void | |
469 jit_convert::visit_function_def (tree_function_def&) | |
470 { | |
471 throw jit_fail_exception (); | |
472 } | |
473 | |
474 void | |
475 jit_convert::visit_identifier (tree_identifier& ti) | |
476 { | |
477 if (ti.has_magic_end ()) | |
478 { | |
479 if (!end_context.size ()) | |
480 throw jit_fail_exception ("Illegal end"); | |
481 result = block->append (factory.create<jit_magic_end> (end_context)); | |
482 } | |
483 else | |
484 { | |
485 jit_variable *var = get_variable (ti.name ()); | |
486 jit_instruction *instr; | |
487 instr = factory.create<jit_call> (&jit_typeinfo::grab, var); | |
488 result = block->append (instr); | |
489 } | |
490 } | |
491 | |
492 void | |
493 jit_convert::visit_if_clause (tree_if_clause&) | |
494 { | |
495 throw jit_fail_exception (); | |
496 } | |
497 | |
498 void | |
499 jit_convert::visit_if_command (tree_if_command& cmd) | |
500 { | |
501 tree_if_command_list *lst = cmd.cmd_list (); | |
502 assert (lst); // jwe: Can this be null? | |
503 lst->accept (*this); | |
504 } | |
505 | |
506 void | |
507 jit_convert::visit_if_command_list (tree_if_command_list& lst) | |
508 { | |
509 tree_if_clause *last = lst.back (); | |
510 size_t last_else = static_cast<size_t> (last->is_else_clause ()); | |
511 | |
512 // entry_blocks represents the block you need to enter in order to execute | |
513 // the condition check for the ith clause. For the else, it is simple the | |
514 // else body. If there is no else body, then it is padded with the tail | |
515 std::vector<jit_block *> entry_blocks (lst.size () + 1 - last_else); | |
516 std::vector<jit_block *> branch_blocks (lst.size (), 0); // final blocks | |
517 entry_blocks[0] = block; | |
518 | |
519 // we need to construct blocks first, because they have jumps to eachother | |
520 tree_if_command_list::iterator iter = lst.begin (); | |
521 ++iter; | |
522 for (size_t i = 1; iter != lst.end (); ++iter, ++i) | |
523 { | |
524 tree_if_clause *tic = *iter; | |
525 if (tic->is_else_clause ()) | |
526 entry_blocks[i] = factory.create<jit_block> ("else"); | |
527 else | |
528 entry_blocks[i] = factory.create<jit_block> ("ifelse_cond"); | |
529 } | |
530 | |
531 jit_block *tail = factory.create<jit_block> ("if_tail"); | |
532 if (! last_else) | |
533 entry_blocks[entry_blocks.size () - 1] = tail; | |
534 | |
535 | |
536 // each branch in the if statement will have different breaks/continues | |
537 block_list current_breaks = breaks; | |
538 block_list current_continues = continues; | |
539 breaks.clear (); | |
540 continues.clear (); | |
541 | |
542 size_t num_incomming = 0; // number of incomming blocks to our tail | |
543 iter = lst.begin (); | |
544 for (size_t i = 0; iter != lst.end (); ++iter, ++i) | |
545 { | |
546 tree_if_clause *tic = *iter; | |
547 block = entry_blocks[i]; | |
548 assert (block); | |
549 | |
550 if (i) // the first block is prev_block, so it has already been added | |
551 blocks.push_back (entry_blocks[i]); | |
552 | |
553 if (! tic->is_else_clause ()) | |
554 { | |
555 tree_expression *expr = tic->condition (); | |
556 jit_value *cond = visit (expr); | |
557 jit_call *check = create_checked (&jit_typeinfo::logically_true, | |
558 cond); | |
559 jit_block *body = factory.create<jit_block> (i == 0 ? "if_body" | |
560 : "ifelse_body"); | |
561 blocks.push_back (body); | |
562 | |
563 jit_instruction *br = factory.create<jit_cond_branch> (check, body, | |
564 entry_blocks[i + 1]); | |
565 block->append (br); | |
566 block = body; | |
567 } | |
568 | |
569 tree_statement_list *stmt_lst = tic->commands (); | |
570 assert (stmt_lst); // jwe: Can this be null? | |
571 | |
572 try | |
573 { | |
574 stmt_lst->accept (*this); | |
575 ++num_incomming; | |
576 block->append (factory.create<jit_branch> (tail)); | |
577 } | |
578 catch(const jit_break_exception&) | |
579 {} | |
580 | |
581 current_breaks.splice (current_breaks.end (), breaks); | |
582 current_continues.splice (current_continues.end (), continues); | |
583 } | |
584 | |
585 breaks.splice (breaks.end (), current_breaks); | |
586 continues.splice (continues.end (), current_continues); | |
587 | |
588 if (num_incomming || ! last_else) | |
589 { | |
590 blocks.push_back (tail); | |
591 block = tail; | |
592 } | |
593 else | |
594 // every branch broke, so we don't have a tail | |
595 throw jit_break_exception (); | |
596 } | |
597 | |
598 void | |
599 jit_convert::visit_index_expression (tree_index_expression& exp) | |
600 { | |
601 result = resolve (exp); | |
602 } | |
603 | |
604 void | |
605 jit_convert::visit_matrix (tree_matrix&) | |
606 { | |
607 throw jit_fail_exception (); | |
608 } | |
609 | |
610 void | |
611 jit_convert::visit_cell (tree_cell&) | |
612 { | |
613 throw jit_fail_exception (); | |
614 } | |
615 | |
616 void | |
617 jit_convert::visit_multi_assignment (tree_multi_assignment&) | |
618 { | |
619 throw jit_fail_exception (); | |
620 } | |
621 | |
622 void | |
623 jit_convert::visit_no_op_command (tree_no_op_command&) | |
624 { | |
625 throw jit_fail_exception (); | |
626 } | |
627 | |
628 void | |
629 jit_convert::visit_constant (tree_constant& tc) | |
630 { | |
631 octave_value v = tc.rvalue1 (); | |
632 jit_type *ty = jit_typeinfo::type_of (v); | |
633 | |
634 if (ty == jit_typeinfo::get_scalar ()) | |
635 { | |
636 double dv = v.double_value (); | |
637 result = factory.create<jit_const_scalar> (dv); | |
638 } | |
639 else if (ty == jit_typeinfo::get_range ()) | |
640 { | |
641 Range rv = v.range_value (); | |
642 result = factory.create<jit_const_range> (rv); | |
643 } | |
644 else if (ty == jit_typeinfo::get_complex ()) | |
645 { | |
646 Complex cv = v.complex_value (); | |
647 result = factory.create<jit_const_complex> (cv); | |
648 } | |
649 else | |
650 throw jit_fail_exception ("Unknown constant"); | |
651 } | |
652 | |
653 void | |
654 jit_convert::visit_fcn_handle (tree_fcn_handle&) | |
655 { | |
656 throw jit_fail_exception (); | |
657 } | |
658 | |
659 void | |
660 jit_convert::visit_parameter_list (tree_parameter_list&) | |
661 { | |
662 throw jit_fail_exception (); | |
663 } | |
664 | |
665 void | |
666 jit_convert::visit_postfix_expression (tree_postfix_expression& tpe) | |
667 { | |
668 octave_value::unary_op etype = tpe.op_type (); | |
669 tree_expression *operand = tpe.operand (); | |
670 jit_value *operandv = visit (operand); | |
671 | |
672 const jit_operation& fn = jit_typeinfo::unary_op (etype); | |
673 result = create_checked (fn, operandv); | |
674 | |
675 if (etype == octave_value::op_incr || etype == octave_value::op_decr) | |
676 { | |
677 jit_value *ret = create_checked (&jit_typeinfo::grab, operandv); | |
678 do_assign (operand, result); | |
679 result = ret; | |
680 } | |
681 } | |
682 | |
683 void | |
684 jit_convert::visit_prefix_expression (tree_prefix_expression& tpe) | |
685 { | |
686 octave_value::unary_op etype = tpe.op_type (); | |
687 tree_expression *operand = tpe.operand (); | |
688 const jit_operation& fn = jit_typeinfo::unary_op (etype); | |
689 result = create_checked (fn, visit (operand)); | |
690 | |
691 if (etype == octave_value::op_incr || etype == octave_value::op_decr) | |
692 do_assign (operand, result); | |
693 } | |
694 | |
695 void | |
696 jit_convert::visit_return_command (tree_return_command&) | |
697 { | |
698 throw jit_fail_exception (); | |
699 } | |
700 | |
701 void | |
702 jit_convert::visit_return_list (tree_return_list&) | |
703 { | |
704 throw jit_fail_exception (); | |
705 } | |
706 | |
707 void | |
708 jit_convert::visit_simple_assignment (tree_simple_assignment& tsa) | |
709 { | |
710 tree_expression *rhs = tsa.right_hand_side (); | |
711 jit_value *rhsv = visit (rhs); | |
712 octave_value::assign_op op = tsa.op_type (); | |
713 | |
714 if (op != octave_value::op_asn_eq) | |
715 { | |
716 // do the equivlent binary operation, then assign. This is always correct, | |
717 // but isn't always optimal. | |
718 tree_expression *lhs = tsa.left_hand_side (); | |
719 jit_value *lhsv = visit (lhs); | |
720 octave_value::binary_op bop = octave_value::assign_op_to_binary_op (op); | |
721 const jit_operation& fn = jit_typeinfo::binary_op (bop); | |
722 rhsv = create_checked (fn, lhsv, rhsv); | |
723 } | |
724 | |
725 result = do_assign (tsa.left_hand_side (), rhsv); | |
726 } | |
727 | |
728 void | |
729 jit_convert::visit_statement (tree_statement& stmt) | |
730 { | |
731 tree_command *cmd = stmt.command (); | |
732 tree_expression *expr = stmt.expression (); | |
733 | |
734 if (cmd) | |
735 visit (cmd); | |
736 else | |
737 { | |
738 // stolen from tree_evaluator::visit_statement | |
739 bool do_bind_ans = false; | |
740 | |
741 if (expr->is_identifier ()) | |
742 { | |
743 tree_identifier *id = dynamic_cast<tree_identifier *> (expr); | |
744 | |
745 do_bind_ans = (! id->is_variable ()); | |
746 } | |
747 else | |
748 do_bind_ans = (! expr->is_assignment_expression ()); | |
749 | |
750 jit_value *expr_result = visit (expr); | |
751 | |
752 if (do_bind_ans) | |
753 do_assign ("ans", expr_result, expr->print_result ()); | |
754 else if (expr->is_identifier () && expr->print_result ()) | |
755 { | |
756 // FIXME: ugly hack, we need to come up with a way to pass | |
757 // nargout to visit_identifier | |
758 const jit_operation& fn = jit_typeinfo::print_value (); | |
759 jit_const_string *name = factory.create<jit_const_string> (expr->name ()); | |
760 block->append (factory.create<jit_call> (fn, name, expr_result)); | |
761 } | |
762 } | |
763 } | |
764 | |
765 void | |
766 jit_convert::visit_statement_list (tree_statement_list& lst) | |
767 { | |
768 for (tree_statement_list::iterator iter = lst.begin (); iter != lst.end(); | |
769 ++iter) | |
770 { | |
771 tree_statement *elt = *iter; | |
772 // jwe: Can this ever be null? | |
773 assert (elt); | |
774 elt->accept (*this); | |
775 } | |
776 } | |
777 | |
778 void | |
779 jit_convert::visit_switch_case (tree_switch_case&) | |
780 { | |
781 throw jit_fail_exception (); | |
782 } | |
783 | |
784 void | |
785 jit_convert::visit_switch_case_list (tree_switch_case_list&) | |
786 { | |
787 throw jit_fail_exception (); | |
788 } | |
789 | |
790 void | |
791 jit_convert::visit_switch_command (tree_switch_command&) | |
792 { | |
793 throw jit_fail_exception (); | |
794 } | |
795 | |
796 void | |
797 jit_convert::visit_try_catch_command (tree_try_catch_command&) | |
798 { | |
799 throw jit_fail_exception (); | |
800 } | |
801 | |
802 void | |
803 jit_convert::visit_unwind_protect_command (tree_unwind_protect_command&) | |
804 { | |
805 throw jit_fail_exception (); | |
806 } | |
807 | |
808 void | |
809 jit_convert::visit_while_command (tree_while_command& wc) | |
810 { | |
811 unwind_protect prot; | |
812 prot.protect_var (breaks); | |
813 prot.protect_var (continues); | |
814 breaks.clear (); | |
815 continues.clear (); | |
816 | |
817 jit_block *cond_check = factory.create<jit_block> ("while_cond_check"); | |
818 block->append (factory.create<jit_branch> (cond_check)); | |
819 blocks.push_back (cond_check); | |
820 block = cond_check; | |
821 | |
822 tree_expression *expr = wc.condition (); | |
823 assert (expr && "While expression can not be null"); | |
824 jit_value *check = visit (expr); | |
825 check = create_checked (&jit_typeinfo::logically_true, check); | |
826 | |
827 jit_block *body = factory.create<jit_block> ("while_body"); | |
828 blocks.push_back (body); | |
829 | |
830 jit_block *tail = factory.create<jit_block> ("while_tail"); | |
831 block->append (factory.create<jit_cond_branch> (check, body, tail)); | |
832 block = body; | |
833 | |
834 tree_statement_list *loop_body = wc.body (); | |
835 bool all_breaking = false; | |
836 if (loop_body) | |
837 { | |
838 try | |
839 { | |
840 loop_body->accept (*this); | |
841 } | |
842 catch (const jit_break_exception&) | |
843 { | |
844 all_breaking = true; | |
845 } | |
846 } | |
847 | |
848 finish_breaks (tail, breaks); | |
849 | |
850 if (! all_breaking || continues.size ()) | |
851 { | |
852 jit_block *interrupt_check | |
853 = factory.create<jit_block> ("interrupt_check"); | |
854 blocks.push_back (interrupt_check); | |
855 finish_breaks (interrupt_check, continues); | |
856 if (! all_breaking) | |
857 block->append (factory.create<jit_branch> (interrupt_check)); | |
858 | |
859 block = interrupt_check; | |
860 jit_error_check *ec | |
861 = factory.create<jit_error_check> (jit_error_check::var_interrupt, | |
862 cond_check, final_block); | |
863 block->append (ec); | |
864 } | |
865 | |
866 blocks.push_back (tail); | |
867 block = tail; | |
868 } | |
869 | |
870 void | |
871 jit_convert::visit_do_until_command (tree_do_until_command&) | |
872 { | |
873 throw jit_fail_exception (); | |
874 } | |
875 | |
876 void | |
877 jit_convert::initialize (symbol_table::scope_id s) | |
878 { | |
879 scope = s; | |
880 iterator_count = 0; | |
881 for_bounds_count = 0; | |
882 short_count = 0; | |
883 jit_instruction::reset_ids (); | |
884 | |
885 entry_block = factory.create<jit_block> ("body"); | |
886 final_block = factory.create<jit_block> ("final"); | |
887 blocks.push_back (entry_block); | |
888 entry_block->mark_alive (); | |
889 block = entry_block; | |
890 } | |
891 | |
892 jit_call * | |
893 jit_convert::create_checked_impl (jit_call *ret) | |
894 { | |
895 block->append (ret); | |
896 | |
897 jit_block *normal = factory.create<jit_block> (block->name ()); | |
898 jit_error_check *check | |
899 = factory.create<jit_error_check> (jit_error_check::var_error_state, ret, | |
900 normal, final_block); | |
901 block->append (check); | |
902 blocks.push_back (normal); | |
903 block = normal; | |
904 | |
905 return ret; | |
906 } | |
907 | |
908 jit_variable * | |
909 jit_convert::find_variable (const std::string& vname) const | |
910 { | |
911 variable_map::const_iterator iter; | |
912 iter = vmap.find (vname); | |
913 return iter != vmap.end () ? iter->second : 0; | |
914 } | |
915 | |
916 jit_variable * | |
917 jit_convert::get_variable (const std::string& vname) | |
918 { | |
919 jit_variable *ret = find_variable (vname); | |
920 if (ret) | |
921 return ret; | |
922 | |
923 symbol_table::symbol_record record = symbol_table::find_symbol (vname, scope); | |
924 if (record.is_persistent () || record.is_global ()) | |
925 throw jit_fail_exception ("Persistent and global not yet supported"); | |
926 | |
927 if (converting_function) | |
928 return create_variable (vname, jit_typeinfo::get_any (), false); | |
929 else | |
930 { | |
931 octave_value val = record.varval (); | |
932 jit_type *type = jit_typeinfo::type_of (val); | |
933 bounds.push_back (type_bound (type, vname)); | |
934 | |
935 return create_variable (vname, type); | |
936 } | |
937 } | |
938 | |
939 jit_variable * | |
940 jit_convert::create_variable (const std::string& vname, jit_type *type, | |
941 bool isarg) | |
942 { | |
943 jit_variable *var = factory.create<jit_variable> (vname); | |
944 | |
945 if (isarg) | |
946 { | |
947 jit_extract_argument *extract; | |
948 extract = factory.create<jit_extract_argument> (type, var); | |
949 entry_block->prepend (extract); | |
950 } | |
951 else | |
952 { | |
953 jit_call *init = factory.create<jit_call> (&jit_typeinfo::create_undef); | |
954 jit_assign *assign = factory.create<jit_assign> (var, init); | |
955 entry_block->prepend (assign); | |
956 entry_block->prepend (init); | |
957 } | |
958 | |
959 return vmap[vname] = var; | |
960 } | |
961 | |
962 std::string | |
963 jit_convert::next_name (const char *prefix, size_t& count, bool inc) | |
964 { | |
965 std::stringstream ss; | |
966 ss << prefix << count; | |
967 if (inc) | |
968 ++count; | |
969 return ss.str (); | |
970 } | |
971 | |
972 jit_instruction * | |
973 jit_convert::resolve (tree_index_expression& exp, jit_value *extra_arg, | |
974 bool lhs) | |
975 { | |
976 std::string type = exp.type_tags (); | |
977 if (! (type.size () == 1 && type[0] == '(')) | |
978 throw jit_fail_exception ("Unsupported index operation"); | |
979 | |
980 std::list<tree_argument_list *> args = exp.arg_lists (); | |
981 if (args.size () != 1) | |
982 throw jit_fail_exception ("Bad number of arguments in " | |
983 "tree_index_expression"); | |
984 | |
985 tree_argument_list *arg_list = args.front (); | |
986 if (! arg_list) | |
987 throw jit_fail_exception ("null argument list"); | |
988 | |
989 if (arg_list->size () < 1) | |
990 throw jit_fail_exception ("Empty arg_list"); | |
991 | |
992 tree_expression *tree_object = exp.expression (); | |
993 jit_value *object; | |
994 if (lhs) | |
995 { | |
996 tree_identifier *id = dynamic_cast<tree_identifier *> (tree_object); | |
997 if (! id) | |
998 throw jit_fail_exception ("expected identifier"); | |
999 object = get_variable (id->name ()); | |
1000 } | |
1001 else | |
1002 object = visit (tree_object); | |
1003 | |
1004 size_t narg = arg_list->size (); | |
1005 tree_argument_list::iterator iter = arg_list->begin (); | |
1006 bool have_extra = extra_arg; | |
1007 std::vector<jit_value *> call_args (narg + 1 + have_extra); | |
1008 call_args[0] = object; | |
1009 | |
1010 for (size_t idx = 0; iter != arg_list->end (); ++idx, ++iter) | |
1011 { | |
1012 unwind_protect prot; | |
1013 prot.add_method (&end_context, | |
1014 &std::vector<jit_magic_end::context>::pop_back); | |
1015 | |
1016 jit_magic_end::context ctx (factory, object, idx, narg); | |
1017 end_context.push_back (ctx); | |
1018 call_args[idx + 1] = visit (*iter); | |
1019 } | |
1020 | |
1021 if (extra_arg) | |
1022 call_args[call_args.size () - 1] = extra_arg; | |
1023 | |
1024 const jit_operation& fres = lhs ? jit_typeinfo::paren_subsasgn () | |
1025 : jit_typeinfo::paren_subsref (); | |
1026 | |
1027 return create_checked (fres, call_args); | |
1028 } | |
1029 | |
1030 jit_value * | |
1031 jit_convert::do_assign (tree_expression *exp, jit_value *rhs, bool artificial) | |
1032 { | |
1033 if (! exp) | |
1034 throw jit_fail_exception ("NULL lhs in assign"); | |
1035 | |
1036 if (isa<tree_identifier> (exp)) | |
1037 return do_assign (exp->name (), rhs, exp->print_result (), artificial); | |
1038 else if (tree_index_expression *idx | |
1039 = dynamic_cast<tree_index_expression *> (exp)) | |
1040 { | |
1041 jit_value *new_object = resolve (*idx, rhs, true); | |
1042 do_assign (idx->expression (), new_object, true); | |
1043 | |
1044 // FIXME: Will not work for values that must be release/grabed | |
1045 return rhs; | |
1046 } | |
1047 else | |
1048 throw jit_fail_exception ("Unsupported assignment"); | |
1049 } | |
1050 | |
1051 jit_value * | |
1052 jit_convert::do_assign (const std::string& lhs, jit_value *rhs, | |
1053 bool print, bool artificial) | |
1054 { | |
1055 jit_variable *var = get_variable (lhs); | |
1056 jit_assign *assign = block->append (factory.create<jit_assign> (var, rhs)); | |
1057 | |
1058 if (artificial) | |
1059 assign->mark_artificial (); | |
1060 | |
1061 if (print) | |
1062 { | |
1063 const jit_operation& print_fn = jit_typeinfo::print_value (); | |
1064 jit_const_string *name = factory.create<jit_const_string> (lhs); | |
1065 block->append (factory.create<jit_call> (print_fn, name, var)); | |
1066 } | |
1067 | |
1068 return var; | |
1069 } | |
1070 | |
1071 jit_value * | |
1072 jit_convert::visit (tree& tee) | |
1073 { | |
1074 unwind_protect prot; | |
1075 prot.protect_var (result); | |
1076 | |
1077 tee.accept (*this); | |
1078 return result; | |
1079 } | |
1080 | |
1081 void | |
1082 jit_convert::finish_breaks (jit_block *dest, const block_list& lst) | |
1083 { | |
1084 for (block_list::const_iterator iter = lst.begin (); iter != lst.end (); | |
1085 ++iter) | |
1086 { | |
1087 jit_block *b = *iter; | |
1088 b->append (factory.create<jit_branch> (dest)); | |
1089 } | |
1090 } | |
1091 | |
1092 // -------------------- jit_convert_llvm -------------------- | |
1093 llvm::Function * | |
1094 jit_convert_llvm::convert_loop (llvm::Module *module, | |
1095 const jit_block_list& blocks, | |
1096 const std::list<jit_value *>& constants) | |
1097 { | |
1098 converting_function = false; | |
1099 | |
1100 // for now just init arguments from entry, later we will have to do something | |
1101 // more interesting | |
1102 jit_block *entry_block = blocks.front (); | |
1103 for (jit_block::iterator iter = entry_block->begin (); | |
1104 iter != entry_block->end (); ++iter) | |
1105 if (jit_extract_argument *extract | |
1106 = dynamic_cast<jit_extract_argument *> (*iter)) | |
1107 argument_vec.push_back (std::make_pair (extract->name (), true)); | |
1108 | |
1109 | |
1110 jit_type *any = jit_typeinfo::get_any (); | |
1111 | |
1112 // argument is an array of octave_base_value*, or octave_base_value** | |
1113 llvm::Type *arg_type = any->to_llvm (); // this is octave_base_value* | |
1114 arg_type = arg_type->getPointerTo (); | |
1115 llvm::FunctionType *ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context), | |
1116 arg_type, false); | |
1117 function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | |
1118 "foobar", module); | |
1119 | |
1120 try | |
1121 { | |
1122 prelude = llvm::BasicBlock::Create (context, "prelude", function); | |
1123 builder.SetInsertPoint (prelude); | |
1124 | |
1125 llvm::Value *arg = function->arg_begin (); | |
1126 for (size_t i = 0; i < argument_vec.size (); ++i) | |
1127 { | |
1128 llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg, i); | |
1129 arguments[argument_vec[i].first] = loaded_arg; | |
1130 } | |
1131 | |
1132 convert (blocks, constants); | |
1133 } catch (const jit_fail_exception& e) | |
1134 { | |
1135 function->eraseFromParent (); | |
1136 throw; | |
1137 } | |
1138 | |
1139 return function; | |
1140 } | |
1141 | |
1142 | |
1143 jit_function | |
1144 jit_convert_llvm::convert_function (llvm::Module *module, | |
1145 const jit_block_list& blocks, | |
1146 const std::list<jit_value *>& constants, | |
1147 octave_user_function& fcn, | |
1148 const std::vector<jit_type *>& args) | |
1149 { | |
1150 converting_function = true; | |
1151 | |
1152 jit_block *final_block = blocks.back (); | |
1153 jit_return *ret = dynamic_cast<jit_return *> (final_block->back ()); | |
1154 assert (ret); | |
1155 | |
1156 creating = jit_function (module, jit_convention::internal, | |
1157 "foobar", ret->result_type (), args); | |
1158 function = creating.to_llvm (); | |
1159 | |
1160 try | |
1161 { | |
1162 prelude = creating.new_block ("prelude"); | |
1163 builder.SetInsertPoint (prelude); | |
1164 | |
1165 tree_parameter_list *plist = fcn.parameter_list (); | |
1166 if (plist) | |
1167 { | |
1168 tree_parameter_list::iterator piter = plist->begin (); | |
1169 tree_parameter_list::iterator pend = plist->end (); | |
1170 for (size_t i = 0; i < args.size () && piter != pend; ++i, ++piter) | |
1171 { | |
1172 tree_decl_elt *elt = *piter; | |
1173 std::string arg_name = elt->name (); | |
1174 arguments[arg_name] = creating.argument (builder, i); | |
1175 } | |
1176 } | |
1177 | |
1178 convert (blocks, constants); | |
1179 } catch (const jit_fail_exception& e) | |
1180 { | |
1181 function->eraseFromParent (); | |
1182 throw; | |
1183 } | |
1184 | |
1185 return creating; | |
1186 } | |
1187 | |
1188 void | |
1189 jit_convert_llvm::convert (const jit_block_list& blocks, | |
1190 const std::list<jit_value *>& constants) | |
1191 { | |
1192 std::list<jit_block *>::const_iterator biter; | |
1193 for (biter = blocks.begin (); biter != blocks.end (); ++biter) | |
1194 { | |
1195 jit_block *jblock = *biter; | |
1196 llvm::BasicBlock *block = llvm::BasicBlock::Create (context, | |
1197 jblock->name (), | |
1198 function); | |
1199 jblock->stash_llvm (block); | |
1200 } | |
1201 | |
1202 jit_block *first = *blocks.begin (); | |
1203 builder.CreateBr (first->to_llvm ()); | |
1204 | |
1205 // constants aren't in the IR, we visit those first | |
1206 for (std::list<jit_value *>::const_iterator iter = constants.begin (); | |
1207 iter != constants.end (); ++iter) | |
1208 if (! isa<jit_instruction> (*iter)) | |
1209 visit (*iter); | |
1210 | |
1211 // convert all instructions | |
1212 for (biter = blocks.begin (); biter != blocks.end (); ++biter) | |
1213 visit (*biter); | |
1214 | |
1215 // now finish phi nodes | |
1216 for (biter = blocks.begin (); biter != blocks.end (); ++biter) | |
1217 { | |
1218 jit_block& block = **biter; | |
1219 for (jit_block::iterator piter = block.begin (); | |
1220 piter != block.end () && isa<jit_phi> (*piter); ++piter) | |
1221 { | |
1222 jit_instruction *phi = *piter; | |
1223 finish_phi (static_cast<jit_phi *> (phi)); | |
1224 } | |
1225 } | |
1226 } | |
1227 | |
1228 void | |
1229 jit_convert_llvm::finish_phi (jit_phi *phi) | |
1230 { | |
1231 llvm::PHINode *llvm_phi = phi->to_llvm (); | |
1232 for (size_t i = 0; i < phi->argument_count (); ++i) | |
1233 { | |
1234 llvm::BasicBlock *pred = phi->incomming_llvm (i); | |
1235 llvm_phi->addIncoming (phi->argument_llvm (i), pred); | |
1236 } | |
1237 } | |
1238 | |
1239 void | |
1240 jit_convert_llvm::visit (jit_const_string& cs) | |
1241 { | |
1242 cs.stash_llvm (builder.CreateGlobalStringPtr (cs.value ())); | |
1243 } | |
1244 | |
1245 void | |
1246 jit_convert_llvm::visit (jit_const_bool& cb) | |
1247 { | |
1248 cb.stash_llvm (llvm::ConstantInt::get (cb.type_llvm (), cb.value ())); | |
1249 } | |
1250 | |
1251 void | |
1252 jit_convert_llvm::visit (jit_const_scalar& cs) | |
1253 { | |
1254 cs.stash_llvm (llvm::ConstantFP::get (cs.type_llvm (), cs.value ())); | |
1255 } | |
1256 | |
1257 void | |
1258 jit_convert_llvm::visit (jit_const_complex& cc) | |
1259 { | |
1260 llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); | |
1261 Complex value = cc.value (); | |
1262 llvm::Value *real = llvm::ConstantFP::get (scalar_t, value.real ()); | |
1263 llvm::Value *imag = llvm::ConstantFP::get (scalar_t, value.imag ()); | |
1264 cc.stash_llvm (jit_typeinfo::create_complex (real, imag)); | |
1265 } | |
1266 | |
1267 void jit_convert_llvm::visit (jit_const_index& ci) | |
1268 { | |
1269 ci.stash_llvm (llvm::ConstantInt::get (ci.type_llvm (), ci.value ())); | |
1270 } | |
1271 | |
1272 void | |
1273 jit_convert_llvm::visit (jit_const_range& cr) | |
1274 { | |
1275 llvm::StructType *stype = llvm::cast<llvm::StructType>(cr.type_llvm ()); | |
1276 llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); | |
1277 llvm::Type *idx = jit_typeinfo::get_index_llvm (); | |
1278 const jit_range& rng = cr.value (); | |
1279 | |
1280 llvm::Constant *constants[4]; | |
1281 constants[0] = llvm::ConstantFP::get (scalar_t, rng.base); | |
1282 constants[1] = llvm::ConstantFP::get (scalar_t, rng.limit); | |
1283 constants[2] = llvm::ConstantFP::get (scalar_t, rng.inc); | |
1284 constants[3] = llvm::ConstantInt::get (idx, rng.nelem); | |
1285 | |
1286 llvm::Value *as_llvm; | |
1287 as_llvm = llvm::ConstantStruct::get (stype, | |
1288 llvm::makeArrayRef (constants, 4)); | |
1289 cr.stash_llvm (as_llvm); | |
1290 } | |
1291 | |
1292 void | |
1293 jit_convert_llvm::visit (jit_block& b) | |
1294 { | |
1295 llvm::BasicBlock *block = b.to_llvm (); | |
1296 builder.SetInsertPoint (block); | |
1297 for (jit_block::iterator iter = b.begin (); iter != b.end (); ++iter) | |
1298 visit (*iter); | |
1299 } | |
1300 | |
1301 void | |
1302 jit_convert_llvm::visit (jit_branch& b) | |
1303 { | |
1304 b.stash_llvm (builder.CreateBr (b.successor_llvm ())); | |
1305 } | |
1306 | |
1307 void | |
1308 jit_convert_llvm::visit (jit_cond_branch& cb) | |
1309 { | |
1310 llvm::Value *cond = cb.cond_llvm (); | |
1311 llvm::Value *br; | |
1312 br = builder.CreateCondBr (cond, cb.successor_llvm (0), | |
1313 cb.successor_llvm (1)); | |
1314 cb.stash_llvm (br); | |
1315 } | |
1316 | |
1317 void | |
1318 jit_convert_llvm::visit (jit_call& call) | |
1319 { | |
1320 const jit_function& ol = call.overload (); | |
1321 | |
1322 std::vector<jit_value *> args (call.arguments ().size ()); | |
1323 for (size_t i = 0; i < args.size (); ++i) | |
1324 args[i] = call.argument (i); | |
1325 | |
1326 llvm::Value *ret = ol.call (builder, args); | |
1327 call.stash_llvm (ret); | |
1328 } | |
1329 | |
1330 void | |
1331 jit_convert_llvm::visit (jit_extract_argument& extract) | |
1332 { | |
1333 llvm::Value *arg = arguments[extract.name ()]; | |
1334 assert (arg); | |
1335 | |
1336 if (converting_function) | |
1337 extract.stash_llvm (arg); | |
1338 else | |
1339 { | |
1340 arg = builder.CreateLoad (arg); | |
1341 | |
1342 const jit_function& ol = extract.overload (); | |
1343 extract.stash_llvm (ol.call (builder, arg)); | |
1344 } | |
1345 } | |
1346 | |
1347 void | |
1348 jit_convert_llvm::visit (jit_store_argument& store) | |
1349 { | |
1350 const jit_function& ol = store.overload (); | |
1351 llvm::Value *arg_value = ol.call (builder, store.result ()); | |
1352 llvm::Value *arg = arguments[store.name ()]; | |
1353 store.stash_llvm (builder.CreateStore (arg_value, arg)); | |
1354 } | |
1355 | |
1356 void | |
1357 jit_convert_llvm::visit (jit_return& ret) | |
1358 { | |
1359 jit_value *res = ret.result (); | |
1360 | |
1361 if (converting_function) | |
1362 creating.do_return (builder, res->to_llvm (), false); | |
1363 else | |
1364 { | |
1365 if (res) | |
1366 builder.CreateRet (res->to_llvm ()); | |
1367 else | |
1368 builder.CreateRetVoid (); | |
1369 } | |
1370 } | |
1371 | |
1372 void | |
1373 jit_convert_llvm::visit (jit_phi& phi) | |
1374 { | |
1375 // we might not have converted all incoming branches, so we don't | |
1376 // set incomming branches now | |
1377 llvm::PHINode *node = llvm::PHINode::Create (phi.type_llvm (), | |
1378 phi.argument_count ()); | |
1379 builder.Insert (node); | |
1380 phi.stash_llvm (node); | |
1381 } | |
1382 | |
1383 void | |
1384 jit_convert_llvm::visit (jit_variable&) | |
1385 { | |
1386 throw jit_fail_exception ("ERROR: SSA construction should remove all variables"); | |
1387 } | |
1388 | |
1389 void | |
1390 jit_convert_llvm::visit (jit_error_check& check) | |
1391 { | |
1392 llvm::Value *cond; | |
1393 | |
1394 switch (check.check_variable ()) | |
1395 { | |
1396 case jit_error_check::var_error_state: | |
1397 cond = jit_typeinfo::insert_error_check (builder); | |
1398 break; | |
1399 case jit_error_check::var_interrupt: | |
1400 cond = jit_typeinfo::insert_interrupt_check (builder); | |
1401 break; | |
1402 default: | |
1403 panic_impossible (); | |
1404 } | |
1405 | |
1406 llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0), | |
1407 check.successor_llvm (1)); | |
1408 check.stash_llvm (br); | |
1409 } | |
1410 | |
1411 void | |
1412 jit_convert_llvm::visit (jit_assign& assign) | |
1413 { | |
1414 jit_value *new_value = assign.src (); | |
1415 assign.stash_llvm (new_value->to_llvm ()); | |
1416 | |
1417 if (assign.artificial ()) | |
1418 return; | |
1419 | |
1420 jit_value *overwrite = assign.overwrite (); | |
1421 if (isa<jit_assign_base> (overwrite)) | |
1422 { | |
1423 const jit_function& ol = jit_typeinfo::get_release (overwrite->type ()); | |
1424 if (ol.valid ()) | |
1425 ol.call (builder, overwrite); | |
1426 } | |
1427 } | |
1428 | |
1429 void | |
1430 jit_convert_llvm::visit (jit_argument&) | |
1431 {} | |
1432 | |
1433 void | |
1434 jit_convert_llvm::visit (jit_magic_end& me) | |
1435 { | |
1436 const jit_function& ol = me.overload (); | |
1437 | |
1438 jit_magic_end::context ctx = me.resolve_context (); | |
1439 llvm::Value *ret = ol.call (builder, ctx.value, ctx.index, ctx.count); | |
1440 me.stash_llvm (ret); | |
1441 } | |
1442 | |
1443 // -------------------- jit_infer -------------------- | |
1444 jit_infer::jit_infer (jit_factory& afactory, jit_block_list& ablocks, | |
1445 const variable_map& avmap) | |
1446 : blocks (ablocks), factory (afactory), vmap (avmap) {} | |
1447 | |
1448 void | |
1449 jit_infer::infer (void) | |
1450 { | |
1451 construct_ssa (); | |
1452 | |
1453 // initialize the worklist to instructions derived from constants | |
1454 const std::list<jit_value *>& constants = factory.constants (); | |
1455 for (std::list<jit_value *>::const_iterator iter = constants.begin (); | |
1456 iter != constants.end (); ++iter) | |
1457 append_users (*iter); | |
1458 | |
1459 // the entry block terminator may be a regular branch statement | |
1460 if (entry_block ().terminator ()) | |
1461 push_worklist (entry_block ().terminator ()); | |
1462 | |
1463 // FIXME: Describe algorithm here | |
1464 while (worklist.size ()) | |
1465 { | |
1466 jit_instruction *next = worklist.front (); | |
1467 worklist.pop_front (); | |
1468 next->stash_in_worklist (false); | |
1469 | |
1470 if (next->infer ()) | |
1471 { | |
1472 // terminators need to be handles specially | |
1473 if (jit_terminator *term = dynamic_cast<jit_terminator *> (next)) | |
1474 append_users_term (term); | |
1475 else | |
1476 append_users (next); | |
1477 } | |
1478 } | |
1479 | |
1480 remove_dead (); | |
1481 blocks.label (); | |
1482 place_releases (); | |
1483 simplify_phi (); | |
1484 } | |
1485 | |
1486 void | |
1487 jit_infer::append_users (jit_value *v) | |
1488 { | |
1489 for (jit_use *use = v->first_use (); use; use = use->next ()) | |
1490 push_worklist (use->user ()); | |
1491 } | |
1492 | |
1493 void | |
1494 jit_infer::append_users_term (jit_terminator *term) | |
1495 { | |
1496 for (size_t i = 0; i < term->successor_count (); ++i) | |
1497 { | |
1498 if (term->alive (i)) | |
1499 { | |
1500 jit_block *succ = term->successor (i); | |
1501 for (jit_block::iterator iter = succ->begin (); iter != succ->end () | |
1502 && isa<jit_phi> (*iter); ++iter) | |
1503 push_worklist (*iter); | |
1504 | |
1505 jit_terminator *sterm = succ->terminator (); | |
1506 if (sterm) | |
1507 push_worklist (sterm); | |
1508 } | |
1509 } | |
1510 } | |
1511 | |
1512 void | |
1513 jit_infer::construct_ssa (void) | |
1514 { | |
1515 blocks.label (); | |
1516 final_block ().compute_idom (entry_block ()); | |
1517 entry_block ().compute_df (); | |
1518 entry_block ().create_dom_tree (); | |
1519 | |
1520 // insert phi nodes where needed, this is done on a per variable basis | |
1521 for (variable_map::const_iterator iter = vmap.begin (); iter != vmap.end (); | |
1522 ++iter) | |
1523 { | |
1524 jit_block::df_set visited, added_phi; | |
1525 std::list<jit_block *> ssa_worklist; | |
1526 iter->second->use_blocks (visited); | |
1527 ssa_worklist.insert (ssa_worklist.begin (), visited.begin (), | |
1528 visited.end ()); | |
1529 | |
1530 while (ssa_worklist.size ()) | |
1531 { | |
1532 jit_block *b = ssa_worklist.front (); | |
1533 ssa_worklist.pop_front (); | |
1534 | |
1535 for (jit_block::df_iterator diter = b->df_begin (); | |
1536 diter != b->df_end (); ++diter) | |
1537 { | |
1538 jit_block *dblock = *diter; | |
1539 if (! added_phi.count (dblock)) | |
1540 { | |
1541 jit_phi *phi = factory.create<jit_phi> (iter->second, | |
1542 dblock->use_count ()); | |
1543 dblock->prepend (phi); | |
1544 added_phi.insert (dblock); | |
1545 } | |
1546 | |
1547 if (! visited.count (dblock)) | |
1548 { | |
1549 ssa_worklist.push_back (dblock); | |
1550 visited.insert (dblock); | |
1551 } | |
1552 } | |
1553 } | |
1554 } | |
1555 | |
1556 do_construct_ssa (entry_block (), entry_block ().visit_count ()); | |
1557 } | |
1558 | |
1559 void | |
1560 jit_infer::do_construct_ssa (jit_block& ablock, size_t avisit_count) | |
1561 { | |
1562 if (ablock.visited (avisit_count)) | |
1563 return; | |
1564 | |
1565 // replace variables with their current SSA value | |
1566 for (jit_block::iterator iter = ablock.begin (); iter != ablock.end (); | |
1567 ++iter) | |
1568 { | |
1569 jit_instruction *instr = *iter; | |
1570 instr->construct_ssa (); | |
1571 instr->push_variable (); | |
1572 } | |
1573 | |
1574 // finish phi nodes of successors | |
1575 for (size_t i = 0; i < ablock.successor_count (); ++i) | |
1576 { | |
1577 jit_block *finish = ablock.successor (i); | |
1578 | |
1579 for (jit_block::iterator iter = finish->begin (); iter != finish->end () | |
1580 && isa<jit_phi> (*iter);) | |
1581 { | |
1582 jit_phi *phi = static_cast<jit_phi *> (*iter); | |
1583 jit_variable *var = phi->dest (); | |
1584 ++iter; | |
1585 | |
1586 if (var->has_top ()) | |
1587 phi->add_incomming (&ablock, var->top ()); | |
1588 else | |
1589 { | |
1590 // temporaries may have extranious phi nodes which can be removed | |
1591 assert (! phi->use_count ()); | |
1592 assert (var->name ().size () && var->name ()[0] == '#'); | |
1593 phi->remove (); | |
1594 } | |
1595 } | |
1596 } | |
1597 | |
1598 for (size_t i = 0; i < ablock.dom_successor_count (); ++i) | |
1599 do_construct_ssa (*ablock.dom_successor (i), avisit_count); | |
1600 | |
1601 ablock.pop_all (); | |
1602 } | |
1603 | |
1604 void | |
1605 jit_infer::place_releases (void) | |
1606 { | |
1607 std::set<jit_value *> temporaries; | |
1608 for (jit_block_list::iterator iter = blocks.begin (); iter != blocks.end (); | |
1609 ++iter) | |
1610 { | |
1611 jit_block& ablock = **iter; | |
1612 if (ablock.id () != jit_block::NO_ID) | |
1613 { | |
1614 release_temp (ablock, temporaries); | |
1615 release_dead_phi (ablock); | |
1616 } | |
1617 } | |
1618 } | |
1619 | |
1620 void | |
1621 jit_infer::push_worklist (jit_instruction *instr) | |
1622 { | |
1623 if (! instr->in_worklist ()) | |
1624 { | |
1625 instr->stash_in_worklist (true); | |
1626 worklist.push_back (instr); | |
1627 } | |
1628 } | |
1629 | |
1630 void | |
1631 jit_infer::remove_dead () | |
1632 { | |
1633 jit_block_list::iterator biter; | |
1634 for (biter = blocks.begin (); biter != blocks.end (); ++biter) | |
1635 { | |
1636 jit_block *b = *biter; | |
1637 if (b->alive ()) | |
1638 { | |
1639 for (jit_block::iterator iter = b->begin (); iter != b->end () | |
1640 && isa<jit_phi> (*iter);) | |
1641 { | |
1642 jit_phi *phi = static_cast<jit_phi *> (*iter); | |
1643 if (phi->prune ()) | |
1644 iter = b->remove (iter); | |
1645 else | |
1646 ++iter; | |
1647 } | |
1648 } | |
1649 } | |
1650 | |
1651 for (biter = blocks.begin (); biter != blocks.end ();) | |
1652 { | |
1653 jit_block *b = *biter; | |
1654 if (b->alive ()) | |
1655 { | |
1656 // FIXME: A special case for jit_error_check, if we generalize to | |
1657 // we will need to change! | |
1658 jit_terminator *term = b->terminator (); | |
1659 if (term && term->successor_count () == 2 && ! term->alive (0)) | |
1660 { | |
1661 jit_block *succ = term->successor (1); | |
1662 term->remove (); | |
1663 jit_branch *abreak = factory.create<jit_branch> (succ); | |
1664 b->append (abreak); | |
1665 abreak->infer (); | |
1666 } | |
1667 | |
1668 ++biter; | |
1669 } | |
1670 else | |
1671 { | |
1672 jit_terminator *term = b->terminator (); | |
1673 if (term) | |
1674 term->remove (); | |
1675 biter = blocks.erase (biter); | |
1676 } | |
1677 } | |
1678 } | |
1679 | |
1680 void | |
1681 jit_infer::release_dead_phi (jit_block& ablock) | |
1682 { | |
1683 jit_block::iterator iter = ablock.begin (); | |
1684 while (iter != ablock.end () && isa<jit_phi> (*iter)) | |
1685 { | |
1686 jit_phi *phi = static_cast<jit_phi *> (*iter); | |
1687 ++iter; | |
1688 | |
1689 jit_use *use = phi->first_use (); | |
1690 if (phi->use_count () == 1 && isa<jit_assign> (use->user ())) | |
1691 { | |
1692 // instead of releasing on assign, release on all incomming branches, | |
1693 // this can get rid of casts inside loops | |
1694 for (size_t i = 0; i < phi->argument_count (); ++i) | |
1695 { | |
1696 jit_value *arg = phi->argument (i); | |
1697 if (! arg->needs_release ()) | |
1698 continue; | |
1699 | |
1700 jit_block *inc = phi->incomming (i); | |
1701 jit_block *split = inc->maybe_split (factory, blocks, ablock); | |
1702 jit_terminator *term = split->terminator (); | |
1703 jit_call *release | |
1704 = factory.create<jit_call> (jit_typeinfo::release, arg); | |
1705 release->infer (); | |
1706 split->insert_before (term, release); | |
1707 } | |
1708 | |
1709 phi->replace_with (0); | |
1710 phi->remove (); | |
1711 } | |
1712 } | |
1713 } | |
1714 | |
1715 void | |
1716 jit_infer::release_temp (jit_block& ablock, std::set<jit_value *>& temp) | |
1717 { | |
1718 for (jit_block::iterator iter = ablock.begin (); iter != ablock.end (); | |
1719 ++iter) | |
1720 { | |
1721 jit_instruction *instr = *iter; | |
1722 | |
1723 // check for temporaries that require release and live across | |
1724 // multiple blocks | |
1725 if (instr->needs_release ()) | |
1726 { | |
1727 jit_block *fu_block = instr->first_use_block (); | |
1728 if (fu_block && fu_block != &ablock && instr->needs_release ()) | |
1729 temp.insert (instr); | |
1730 } | |
1731 | |
1732 if (isa<jit_call> (instr)) | |
1733 { | |
1734 // place releases for temporary arguments | |
1735 for (size_t i = 0; i < instr->argument_count (); ++i) | |
1736 { | |
1737 jit_value *arg = instr->argument (i); | |
1738 if (! arg->needs_release ()) | |
1739 continue; | |
1740 | |
1741 jit_call *release | |
1742 = factory.create<jit_call> (&jit_typeinfo::release, arg); | |
1743 release->infer (); | |
1744 ablock.insert_after (iter, release); | |
1745 ++iter; | |
1746 temp.erase (arg); | |
1747 } | |
1748 } | |
1749 } | |
1750 | |
1751 if (! temp.size () || ! isa<jit_error_check> (ablock.terminator ())) | |
1752 return; | |
1753 | |
1754 // FIXME: If we support try/catch or unwind_protect final_block may not be the | |
1755 // destination | |
1756 jit_block *split = ablock.maybe_split (factory, blocks, final_block ()); | |
1757 jit_terminator *term = split->terminator (); | |
1758 for (std::set<jit_value *>::const_iterator iter = temp.begin (); | |
1759 iter != temp.end (); ++iter) | |
1760 { | |
1761 jit_value *value = *iter; | |
1762 jit_call *release | |
1763 = factory.create<jit_call> (&jit_typeinfo::release, value); | |
1764 split->insert_before (term, release); | |
1765 release->infer (); | |
1766 } | |
1767 } | |
1768 | |
1769 void | |
1770 jit_infer::simplify_phi (void) | |
1771 { | |
1772 for (jit_block_list::iterator biter = blocks.begin (); biter != blocks.end (); | |
1773 ++biter) | |
1774 { | |
1775 jit_block &ablock = **biter; | |
1776 for (jit_block::iterator iter = ablock.begin (); iter != ablock.end () | |
1777 && isa<jit_phi> (*iter); ++iter) | |
1778 simplify_phi (*static_cast<jit_phi *> (*iter)); | |
1779 } | |
1780 } | |
1781 | |
1782 void | |
1783 jit_infer::simplify_phi (jit_phi& phi) | |
1784 { | |
1785 jit_block& pblock = *phi.parent (); | |
1786 const jit_operation& cast_fn = jit_typeinfo::cast (phi.type ()); | |
1787 jit_variable *dest = phi.dest (); | |
1788 for (size_t i = 0; i < phi.argument_count (); ++i) | |
1789 { | |
1790 jit_value *arg = phi.argument (i); | |
1791 if (arg->type () != phi.type ()) | |
1792 { | |
1793 jit_block *pred = phi.incomming (i); | |
1794 jit_block *split = pred->maybe_split (factory, blocks, pblock); | |
1795 jit_terminator *term = split->terminator (); | |
1796 jit_instruction *cast = factory.create<jit_call> (cast_fn, arg); | |
1797 jit_assign *assign = factory.create<jit_assign> (dest, cast); | |
1798 | |
1799 split->insert_before (term, cast); | |
1800 split->insert_before (term, assign); | |
1801 cast->infer (); | |
1802 assign->infer (); | |
1803 phi.stash_argument (i, assign); | |
1804 } | |
1805 } | |
1806 } | |
1807 | |
1808 // -------------------- tree_jit -------------------- | |
1809 | |
1810 tree_jit::tree_jit (void) : module (0), engine (0) | |
1811 { | |
1812 } | |
1813 | |
1814 tree_jit::~tree_jit (void) | |
1815 {} | |
1816 | |
1817 bool | |
1818 tree_jit::execute (tree_simple_for_command& cmd, const octave_value& bounds) | |
1819 { | |
1820 return instance ().do_execute (cmd, bounds); | |
1821 } | |
1822 | |
1823 bool | |
1824 tree_jit::execute (tree_while_command& cmd) | |
1825 { | |
1826 return instance ().do_execute (cmd); | |
1827 } | |
1828 | |
1829 bool | |
1830 tree_jit::execute (octave_user_function& fcn, const octave_value_list& args, | |
1831 octave_value_list& retval) | |
1832 { | |
1833 return instance ().do_execute (fcn, args, retval); | |
1834 } | |
1835 | |
1836 tree_jit& | |
1837 tree_jit::instance (void) | |
1838 { | |
1839 static tree_jit ret; | |
1840 return ret; | |
1841 } | |
1842 | |
1843 bool | |
1844 tree_jit::initialize (void) | |
1845 { | |
1846 if (engine) | |
1847 return true; | |
1848 | |
1849 if (! module) | |
1850 { | |
1851 llvm::InitializeNativeTarget (); | |
1852 module = new llvm::Module ("octave", context); | |
1853 } | |
1854 | |
1855 // sometimes this fails pre main | |
1856 engine = llvm::ExecutionEngine::createJIT (module); | |
1857 | |
1858 if (! engine) | |
1859 return false; | |
1860 | |
1861 module_pass_manager = new llvm::PassManager (); | |
1862 module_pass_manager->add (llvm::createAlwaysInlinerPass ()); | |
1863 | |
1864 pass_manager = new llvm::FunctionPassManager (module); | |
1865 pass_manager->add (new llvm::TargetData(*engine->getTargetData ())); | |
1866 pass_manager->add (llvm::createCFGSimplificationPass ()); | |
1867 pass_manager->add (llvm::createBasicAliasAnalysisPass ()); | |
1868 pass_manager->add (llvm::createPromoteMemoryToRegisterPass ()); | |
1869 pass_manager->add (llvm::createInstructionCombiningPass ()); | |
1870 pass_manager->add (llvm::createReassociatePass ()); | |
1871 pass_manager->add (llvm::createGVNPass ()); | |
1872 pass_manager->add (llvm::createCFGSimplificationPass ()); | |
1873 pass_manager->doInitialization (); | |
1874 | |
1875 jit_typeinfo::initialize (module, engine); | |
1876 | |
1877 return true; | |
1878 } | |
1879 | |
1880 bool | |
1881 tree_jit::do_execute (tree_simple_for_command& cmd, const octave_value& bounds) | |
1882 { | |
1883 const size_t MIN_TRIP_COUNT = 1000; | |
1884 | |
1885 size_t tc = trip_count (bounds); | |
1886 if (! tc || ! initialize () || ! enabled ()) | |
1887 return false; | |
1888 | |
1889 jit_info::vmap extra_vars; | |
1890 extra_vars["#for_bounds0"] = &bounds; | |
1891 | |
1892 jit_info *info = cmd.get_info (); | |
1893 if (! info || ! info->match (extra_vars)) | |
1894 { | |
1895 if (tc < MIN_TRIP_COUNT) | |
1896 return false; | |
1897 | |
1898 delete info; | |
1899 info = new jit_info (*this, cmd, bounds); | |
1900 cmd.stash_info (info); | |
1901 } | |
1902 | |
1903 return info->execute (extra_vars); | |
1904 } | |
1905 | |
1906 bool | |
1907 tree_jit::do_execute (tree_while_command& cmd) | |
1908 { | |
1909 if (! initialize () || ! enabled ()) | |
1910 return false; | |
1911 | |
1912 jit_info *info = cmd.get_info (); | |
1913 if (! info || ! info->match ()) | |
1914 { | |
1915 delete info; | |
1916 info = new jit_info (*this, cmd); | |
1917 cmd.stash_info (info); | |
1918 } | |
1919 | |
1920 return info->execute (); | |
1921 } | |
1922 | |
1923 bool | |
1924 tree_jit::do_execute (octave_user_function& fcn, const octave_value_list& args, | |
1925 octave_value_list& retval) | |
1926 { | |
1927 if (! initialize () || ! enabled ()) | |
1928 return false; | |
1929 | |
1930 jit_function_info *info = fcn.get_info (); | |
1931 if (! info || ! info->match (args)) | |
1932 { | |
1933 delete info; | |
1934 info = new jit_function_info (*this, fcn, args); | |
1935 fcn.stash_info (info); | |
1936 } | |
1937 | |
1938 return info->execute (args, retval); | |
1939 } | |
1940 | |
1941 bool | |
1942 tree_jit::enabled (void) | |
1943 { | |
1944 // Ideally, we should only disable JIT if there is a breakpoint in the code we | |
1945 // are about to run. However, we can't figure this out in O(1) time, so we | |
1946 // conservatively check for the existence of any breakpoints. | |
1947 return Vjit_enable && ! bp_table::have_breakpoints () | |
1948 && ! Vdebug_on_interrupt && ! Vdebug_on_error; | |
1949 } | |
1950 | |
1951 size_t | |
1952 tree_jit::trip_count (const octave_value& bounds) const | |
1953 { | |
1954 if (bounds.is_range ()) | |
1955 { | |
1956 Range rng = bounds.range_value (); | |
1957 return rng.nelem (); | |
1958 } | |
1959 | |
1960 // unsupported type | |
1961 return 0; | |
1962 } | |
1963 | |
1964 | |
1965 void | |
1966 tree_jit::optimize (llvm::Function *fn) | |
1967 { | |
1968 if (Vdebug_jit) | |
1969 llvm::verifyModule (*module); | |
1970 | |
1971 module_pass_manager->run (*module); | |
1972 pass_manager->run (*fn); | |
1973 | |
1974 if (Vdebug_jit) | |
1975 { | |
1976 std::string error; | |
1977 llvm::raw_fd_ostream fout ("test.bc", error, | |
1978 llvm::raw_fd_ostream::F_Binary); | |
1979 llvm::WriteBitcodeToFile (module, fout); | |
1980 } | |
1981 } | |
1982 | |
1983 // -------------------- jit_function_info -------------------- | |
1984 jit_function_info::jit_function_info (tree_jit& tjit, | |
1985 octave_user_function& fcn, | |
1986 const octave_value_list& ov_args) | |
1987 : argument_types (ov_args.length ()), function (0) | |
1988 { | |
1989 size_t nargs = ov_args.length (); | |
1990 for (size_t i = 0; i < nargs; ++i) | |
1991 argument_types[i] = jit_typeinfo::type_of (ov_args(i)); | |
1992 | |
1993 jit_function raw_fn; | |
1994 jit_function wrapper; | |
1995 | |
1996 try | |
1997 { | |
1998 jit_convert conv (fcn, argument_types); | |
1999 jit_infer infer (conv.get_factory (), conv.get_blocks (), | |
2000 conv.get_variable_map ()); | |
2001 infer.infer (); | |
2002 | |
2003 if (Vdebug_jit) | |
2004 { | |
2005 jit_block_list& blocks = infer.get_blocks (); | |
2006 blocks.label (); | |
2007 std::cout << "-------------------- Compiling function "; | |
2008 std::cout << "--------------------\n"; | |
2009 | |
2010 tree_print_code tpc (std::cout); | |
2011 tpc.visit_octave_user_function_header (fcn); | |
2012 tpc.visit_statement_list (*fcn.body ()); | |
2013 tpc.visit_octave_user_function_trailer (fcn); | |
2014 blocks.print (std::cout, "octave jit ir"); | |
2015 } | |
2016 | |
2017 jit_factory& factory = conv.get_factory (); | |
2018 llvm::Module *module = tjit.get_module (); | |
2019 jit_convert_llvm to_llvm; | |
2020 raw_fn = to_llvm.convert_function (module, infer.get_blocks (), | |
2021 factory.constants (), fcn, | |
2022 argument_types); | |
2023 | |
2024 if (Vdebug_jit) | |
2025 { | |
2026 std::cout << "-------------------- raw function "; | |
2027 std::cout << "--------------------\n"; | |
2028 std::cout << *raw_fn.to_llvm () << std::endl; | |
2029 llvm::verifyFunction (*raw_fn.to_llvm ()); | |
2030 } | |
2031 | |
2032 std::string wrapper_name = fcn.name () + "_wrapper"; | |
2033 jit_type *any_t = jit_typeinfo::get_any (); | |
2034 std::vector<jit_type *> wrapper_args (1, jit_typeinfo::get_any_ptr ()); | |
2035 wrapper = jit_function (module, jit_convention::internal, wrapper_name, | |
2036 any_t, wrapper_args); | |
2037 | |
2038 llvm::BasicBlock *wrapper_body = wrapper.new_block (); | |
2039 builder.SetInsertPoint (wrapper_body); | |
2040 | |
2041 llvm::Value *wrapper_arg = wrapper.argument (builder, 0); | |
2042 std::vector<llvm::Value *> raw_args (nargs); | |
2043 for (size_t i = 0; i < nargs; ++i) | |
2044 { | |
2045 llvm::Value *arg; | |
2046 arg = builder.CreateConstInBoundsGEP1_32 (wrapper_arg, i); | |
2047 arg = builder.CreateLoad (arg); | |
2048 | |
2049 jit_type *arg_type = argument_types[i]; | |
2050 const jit_function& cast = jit_typeinfo::cast (arg_type, any_t); | |
2051 raw_args[i] = cast.call (builder, arg); | |
2052 } | |
2053 | |
2054 llvm::Value *result = raw_fn.call (builder, raw_args); | |
2055 if (raw_fn.result ()) | |
2056 { | |
2057 jit_type *raw_result_t = raw_fn.result (); | |
2058 const jit_function& cast = jit_typeinfo::cast (any_t, raw_result_t); | |
2059 result = cast.call (builder, result); | |
2060 } | |
2061 else | |
2062 { | |
2063 llvm::Value *zero = builder.getInt32 (0); | |
2064 result = builder.CreateBitCast (zero, any_t->to_llvm ()); | |
2065 } | |
2066 | |
2067 wrapper.do_return (builder, result); | |
2068 | |
2069 llvm::Function *llvm_function = wrapper.to_llvm (); | |
2070 tjit.optimize (llvm_function); | |
2071 | |
2072 if (Vdebug_jit) | |
2073 { | |
2074 std::cout << "-------------------- optimized and wrapped "; | |
2075 std::cout << "--------------------\n"; | |
2076 std::cout << *llvm_function << std::endl; | |
2077 llvm::verifyFunction (*llvm_function); | |
2078 } | |
2079 | |
2080 llvm::ExecutionEngine* engine = tjit.get_engine (); | |
2081 void *void_fn = engine->getPointerToFunction (llvm_function); | |
2082 function = reinterpret_cast<jited_function> (void_fn); | |
2083 } | |
2084 catch (const jit_fail_exception& e) | |
2085 { | |
2086 argument_types.clear (); | |
2087 | |
2088 if (Vdebug_jit) | |
2089 { | |
2090 if (e.known ()) | |
2091 std::cout << "jit fail: " << e.what () << std::endl; | |
2092 } | |
2093 | |
2094 wrapper.erase (); | |
2095 raw_fn.erase (); | |
2096 } | |
2097 } | |
2098 | |
2099 bool | |
2100 jit_function_info::execute (const octave_value_list& ov_args, | |
2101 octave_value_list& retval) const | |
2102 { | |
2103 if (! function) | |
2104 return false; | |
2105 | |
2106 // TODO figure out a way to delete ov_args so we avoid duplicating refcount | |
2107 size_t nargs = ov_args.length (); | |
2108 std::vector<octave_base_value *> args (nargs); | |
2109 for (size_t i = 0; i < nargs; ++i) | |
2110 { | |
2111 octave_base_value *obv = ov_args(i).internal_rep (); | |
2112 obv->grab (); | |
2113 args[i] = obv; | |
2114 } | |
2115 | |
2116 octave_base_value *ret = function (&args[0]); | |
2117 if (ret) | |
2118 retval(0) = octave_value (ret); | |
2119 | |
2120 octave_quit (); | |
2121 | |
2122 return true; | |
2123 } | |
2124 | |
2125 bool | |
2126 jit_function_info::match (const octave_value_list& ov_args) const | |
2127 { | |
2128 if (! function) | |
2129 return true; | |
2130 | |
2131 size_t nargs = ov_args.length (); | |
2132 if (nargs != argument_types.size ()) | |
2133 return false; | |
2134 | |
2135 for (size_t i = 0; i < nargs; ++i) | |
2136 if (jit_typeinfo::type_of (ov_args(i)) != argument_types[i]) | |
2137 return false; | |
2138 | |
2139 return true; | |
2140 } | |
2141 | |
2142 // -------------------- jit_info -------------------- | |
2143 jit_info::jit_info (tree_jit& tjit, tree& tee) | |
2144 : engine (tjit.get_engine ()), function (0), llvm_function (0) | |
2145 { | |
2146 compile (tjit, tee); | |
2147 } | |
2148 | |
2149 jit_info::jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds) | |
2150 : engine (tjit.get_engine ()), function (0), llvm_function (0) | |
2151 { | |
2152 compile (tjit, tee, jit_typeinfo::type_of (for_bounds)); | |
2153 } | |
2154 | |
2155 jit_info::~jit_info (void) | |
2156 { | |
2157 if (llvm_function) | |
2158 llvm_function->eraseFromParent (); | |
2159 } | |
2160 | |
2161 bool | |
2162 jit_info::execute (const vmap& extra_vars) const | |
2163 { | |
2164 if (! function) | |
2165 return false; | |
2166 | |
2167 std::vector<octave_base_value *> real_arguments (arguments.size ()); | |
2168 for (size_t i = 0; i < arguments.size (); ++i) | |
2169 { | |
2170 if (arguments[i].second) | |
2171 { | |
2172 octave_value current = find (extra_vars, arguments[i].first); | |
2173 octave_base_value *obv = current.internal_rep (); | |
2174 obv->grab (); | |
2175 real_arguments[i] = obv; | |
2176 } | |
2177 } | |
2178 | |
2179 function (&real_arguments[0]); | |
2180 | |
2181 for (size_t i = 0; i < arguments.size (); ++i) | |
2182 { | |
2183 const std::string& name = arguments[i].first; | |
2184 | |
2185 // do not store for loop bounds temporary | |
2186 if (name.size () && name[0] != '#') | |
2187 symbol_table::assign (arguments[i].first, real_arguments[i]); | |
2188 } | |
2189 | |
2190 octave_quit (); | |
2191 | |
2192 return true; | |
2193 } | |
2194 | |
2195 bool | |
2196 jit_info::match (const vmap& extra_vars) const | |
2197 { | |
2198 if (! function) | |
2199 return true; | |
2200 | |
2201 for (size_t i = 0; i < bounds.size (); ++i) | |
2202 { | |
2203 const std::string& arg_name = bounds[i].second; | |
2204 octave_value value = find (extra_vars, arg_name); | |
2205 jit_type *type = jit_typeinfo::type_of (value); | |
2206 | |
2207 // FIXME: Check for a parent relationship | |
2208 if (type != bounds[i].first) | |
2209 return false; | |
2210 } | |
2211 | |
2212 return true; | |
2213 } | |
2214 | |
2215 void | |
2216 jit_info::compile (tree_jit& tjit, tree& tee, jit_type *for_bounds) | |
2217 { | |
2218 try | |
2219 { | |
2220 jit_convert conv (tee, for_bounds); | |
2221 jit_infer infer (conv.get_factory (), conv.get_blocks (), | |
2222 conv.get_variable_map ()); | |
2223 | |
2224 infer.infer (); | |
2225 | |
2226 if (Vdebug_jit) | |
2227 { | |
2228 jit_block_list& blocks = infer.get_blocks (); | |
2229 blocks.label (); | |
2230 std::cout << "-------------------- Compiling tree --------------------\n"; | |
2231 std::cout << tee.str_print_code () << std::endl; | |
2232 blocks.print (std::cout, "octave jit ir"); | |
2233 } | |
2234 | |
2235 jit_factory& factory = conv.get_factory (); | |
2236 jit_convert_llvm to_llvm; | |
2237 llvm_function = to_llvm.convert_loop (tjit.get_module (), | |
2238 infer.get_blocks (), | |
2239 factory.constants ()); | |
2240 arguments = to_llvm.get_arguments (); | |
2241 bounds = conv.get_bounds (); | |
2242 } | |
2243 catch (const jit_fail_exception& e) | |
2244 { | |
2245 if (Vdebug_jit) | |
2246 { | |
2247 if (e.known ()) | |
2248 std::cout << "jit fail: " << e.what () << std::endl; | |
2249 } | |
2250 } | |
2251 | |
2252 if (llvm_function) | |
2253 { | |
2254 if (Vdebug_jit) | |
2255 { | |
2256 std::cout << "-------------------- llvm ir --------------------"; | |
2257 std::cout << *llvm_function << std::endl; | |
2258 llvm::verifyFunction (*llvm_function); | |
2259 } | |
2260 | |
2261 tjit.optimize (llvm_function); | |
2262 | |
2263 if (Vdebug_jit) | |
2264 { | |
2265 std::cout << "-------------------- optimized llvm ir " | |
2266 << "--------------------\n"; | |
2267 std::cout << *llvm_function << std::endl; | |
2268 } | |
2269 | |
2270 void *void_fn = engine->getPointerToFunction (llvm_function); | |
2271 function = reinterpret_cast<jited_function> (void_fn); | |
2272 } | |
2273 } | |
2274 | |
2275 octave_value | |
2276 jit_info::find (const vmap& extra_vars, const std::string& vname) const | |
2277 { | |
2278 vmap::const_iterator iter = extra_vars.find (vname); | |
2279 return iter == extra_vars.end () ? symbol_table::varval (vname) | |
2280 : *iter->second; | |
2281 } | |
2282 | |
2283 #endif | |
2284 | |
2285 DEFUN (debug_jit, args, nargout, | |
2286 "-*- texinfo -*-\n\ | |
2287 @deftypefn {Built-in Function} {@var{val} =} debug_jit ()\n\ | |
2288 @deftypefnx {Built-in Function} {@var{old_val} =} debug_jit (@var{new_val})\n\ | |
2289 @deftypefnx {Built-in Function} {} debug_jit (@var{new_val}, \"local\")\n\ | |
2290 Query or set the internal variable that determines whether\n\ | |
2291 debugging/tracing is enabled for Octave's JIT compiler.\n\ | |
2292 \n\ | |
2293 When called from inside a function with the \"local\" option, the variable is\n\ | |
2294 changed locally for the function and any subroutines it calls. The original\n\ | |
2295 variable value is restored when exiting the function.\n\ | |
2296 @seealso{jit_enable}\n\ | |
2297 @end deftypefn") | |
2298 { | |
2299 #if defined (HAVE_LLVM) | |
2300 return SET_INTERNAL_VARIABLE (debug_jit); | |
2301 #else | |
2302 warning ("debug_jit: JIT compiling not available in this version of Octave"); | |
2303 return octave_value (); | |
2304 #endif | |
2305 } | |
2306 | |
2307 DEFUN (jit_enable, args, nargout, | |
2308 "-*- texinfo -*-\n\ | |
2309 @deftypefn {Built-in Function} {@var{val} =} jit_enable ()\n\ | |
2310 @deftypefnx {Built-in Function} {@var{old_val} =} jit_enable (@var{new_val})\n\ | |
2311 @deftypefnx {Built-in Function} {} jit_enable (@var{new_val}, \"local\")\n\ | |
2312 Query or set the internal variable that enables Octave's JIT compiler.\n\ | |
2313 \n\ | |
2314 When called from inside a function with the \"local\" option, the variable is\n\ | |
2315 changed locally for the function and any subroutines it calls. The original\n\ | |
2316 variable value is restored when exiting the function.\n\ | |
2317 @seealso{debug_jit}\n\ | |
2318 @end deftypefn") | |
2319 { | |
2320 #if defined (HAVE_LLVM) | |
2321 return SET_INTERNAL_VARIABLE (jit_enable); | |
2322 #else | |
2323 warning ("jit_enable: JIT compiling not available in this version of Octave"); | |
2324 return octave_value (); | |
2325 #endif | |
2326 } | |
2327 | |
2328 /* | |
2329 Test some simple cases that compile. | |
2330 | |
2331 %!test | |
2332 %! for i=1:1e6 | |
2333 %! if i < 5 | |
2334 %! break | |
2335 %! else | |
2336 %! break | |
2337 %! endif | |
2338 %! endfor | |
2339 %! assert (i, 1); | |
2340 | |
2341 %!test | |
2342 %! while 1 | |
2343 %! if 1 | |
2344 %! break | |
2345 %! else | |
2346 %! break | |
2347 %! endif | |
2348 %! endwhile | |
2349 | |
2350 %!test | |
2351 %! for i=1:1e6 | |
2352 %! if i == 100 | |
2353 %! break | |
2354 %! endif | |
2355 %! endfor | |
2356 %! assert (i, 100); | |
2357 | |
2358 %!test | |
2359 %! inc = 1e-5; | |
2360 %! result = 0; | |
2361 %! for ii = 0:inc:1 | |
2362 %! result = result + inc * (1/3 * ii * ii); | |
2363 %! endfor | |
2364 %! assert (abs (result - 1/9) < 1e-5); | |
2365 | |
2366 %!test | |
2367 %! inc = 1e-5; | |
2368 %! result = 0; | |
2369 %! for ii = 0:inc:1 | |
2370 %! # the ^ operator's result is complex | |
2371 %! result = result + inc * (1/3 * ii ^ 2); | |
2372 %! endfor | |
2373 %! assert (abs (result - 1/9) < 1e-5); | |
2374 | |
2375 %!test | |
2376 %! temp = 1+1i; | |
2377 %! nan = NaN; | |
2378 %! while 1 | |
2379 %! temp = temp - 1i; | |
2380 %! temp = temp * nan; | |
2381 %! break; | |
2382 %! endwhile | |
2383 %! assert (imag (temp), 0); | |
2384 | |
2385 %!test | |
2386 %! temp = 1+1i; | |
2387 %! nan = NaN+1i; | |
2388 %! while 1 | |
2389 %! nan = nan - 1i; | |
2390 %! temp = temp - 1i; | |
2391 %! temp = temp * nan; | |
2392 %! break; | |
2393 %! endwhile | |
2394 %! assert (imag (temp), 0); | |
2395 | |
2396 %!test | |
2397 %! temp = 1+1i; | |
2398 %! while 1 | |
2399 %! temp = temp * 5; | |
2400 %! break; | |
2401 %! endwhile | |
2402 %! assert (temp, 5+5i); | |
2403 | |
2404 %!test | |
2405 %! nr = 1001; | |
2406 %! mat = zeros (1, nr); | |
2407 %! for i = 1:nr | |
2408 %! mat(i) = i; | |
2409 %! endfor | |
2410 %! assert (mat == 1:nr); | |
2411 | |
2412 %!test | |
2413 %! nr = 1001; | |
2414 %! mat = 1:nr; | |
2415 %! mat(end) = 0; # force mat to a matrix | |
2416 %! total = 0; | |
2417 %! for i = 1:nr | |
2418 %! total = mat(i) + total; | |
2419 %! endfor | |
2420 %! assert (sum (mat) == total); | |
2421 | |
2422 %!test | |
2423 %! nr = 1001; | |
2424 %! mat = [3 1 5]; | |
2425 %! try | |
2426 %! for i = 1:nr | |
2427 %! if i > 500 | |
2428 %! result = mat(100); | |
2429 %! else | |
2430 %! result = i; | |
2431 %! endif | |
2432 %! endfor | |
2433 %! catch | |
2434 %! end | |
2435 %! assert (result == 500); | |
2436 | |
2437 %!function result = gen_test (n) | |
2438 %! result = double (rand (1, n) > .01); | |
2439 %!endfunction | |
2440 | |
2441 %!function z = vectorized (A, K) | |
2442 %! temp = ones (1, K); | |
2443 %! z = conv (A, temp); | |
2444 %! z = z > K-1; | |
2445 %! z = conv (z, temp); | |
2446 %! z = z(K:end-K+1); | |
2447 %! z = z >= 1; | |
2448 %!endfunction | |
2449 | |
2450 %!function z = loopy (A, K) | |
2451 %! z = A; | |
2452 %! n = numel (A); | |
2453 %! counter = 0; | |
2454 %! for ii=1:n | |
2455 %! if z(ii) | |
2456 %! counter = counter + 1; | |
2457 %! else | |
2458 %! if counter > 0 && counter < K | |
2459 %! z(ii-counter:ii-1) = 0; | |
2460 %! endif | |
2461 %! counter = 0; | |
2462 %! endif | |
2463 %! endfor | |
2464 %! | |
2465 %! if counter > 0 && counter < K | |
2466 %! z(end-counter+1:end) = 0; | |
2467 %! endif | |
2468 %!endfunction | |
2469 | |
2470 %!test | |
2471 %! test_set = gen_test (10000); | |
2472 %! assert (all (vectorized (test_set, 3) == loopy (test_set, 3))); | |
2473 | |
2474 %!test | |
2475 %! niter = 1001; | |
2476 %! i = 0; | |
2477 %! while (i < niter) | |
2478 %! i = i + 1; | |
2479 %! endwhile | |
2480 %! assert (i == niter); | |
2481 | |
2482 %!test | |
2483 %! niter = 1001; | |
2484 %! result = 0; | |
2485 %! m = [5 10]; | |
2486 %! for i=1:niter | |
2487 %! result = result + m(end); | |
2488 %! endfor | |
2489 %! assert (result == m(end) * niter); | |
2490 | |
2491 %!test | |
2492 %! ndim = 100; | |
2493 %! result = 0; | |
2494 %! m = zeros (ndim); | |
2495 %! m(:) = 1:ndim^2; | |
2496 %! i = 1; | |
2497 %! while (i <= ndim) | |
2498 %! for j = 1:ndim | |
2499 %! result = result + m(i, j); | |
2500 %! endfor | |
2501 %! i = i + 1; | |
2502 %! endwhile | |
2503 %! assert (result == sum (sum (m))); | |
2504 | |
2505 %!test | |
2506 %! ndim = 100; | |
2507 %! m = zeros (ndim); | |
2508 %! i = 1; | |
2509 %! while (i <= ndim) | |
2510 %! for j = 1:ndim | |
2511 %! m(i, j) = (j - 1) * ndim + i; | |
2512 %! endfor | |
2513 %! i = i + 1; | |
2514 %! endwhile | |
2515 %! m2 = zeros (ndim); | |
2516 %! m2(:) = 1:(ndim^2); | |
2517 %! assert (all (m == m2)); | |
2518 | |
2519 %!test | |
2520 %! ndim = 2; | |
2521 %! m = zeros (ndim, ndim, ndim, ndim); | |
2522 %! result = 0; | |
2523 %! i0 = 1; | |
2524 %! while (i0 <= ndim) | |
2525 %! for i1 = 1:ndim | |
2526 %! for i2 = 1:ndim | |
2527 %! for i3 = 1:ndim | |
2528 %! m(i0, i1, i2, i3) = 1; | |
2529 %! m(i0, i1, i2, i3, 1, 1, 1, 1, 1, 1) = 1; | |
2530 %! result = result + m(i0, i1, i2, i3); | |
2531 %! endfor | |
2532 %! endfor | |
2533 %! endfor | |
2534 %! i0 = i0 + 1; | |
2535 %! endwhile | |
2536 %! expected = ones (ndim, ndim, ndim, ndim); | |
2537 %! assert (all (m == expected)); | |
2538 %! assert (result == sum (expected (:))); | |
2539 | |
2540 %!function test_divide () | |
2541 %! state = warning ("query", "Octave:divide-by-zero").state; | |
2542 %! unwind_protect | |
2543 %! warning ("error", "Octave:divide-by-zero"); | |
2544 %! for i=1:1e5 | |
2545 %! a = 1; | |
2546 %! a / 0; | |
2547 %! endfor | |
2548 %! unwind_protect_cleanup | |
2549 %! warning (state, "Octave:divide-by-zero"); | |
2550 %! end_unwind_protect | |
2551 %!endfunction | |
2552 | |
2553 %!error <division by zero> test_divide () | |
2554 | |
2555 %!test | |
2556 %! while 1 | |
2557 %! a = 0; | |
2558 %! result = a / 1; | |
2559 %! break; | |
2560 %! endwhile | |
2561 %! assert (result, 0); | |
2562 | |
2563 %!test | |
2564 %! m = zeros (2, 1001); | |
2565 %! for i=1:1001 | |
2566 %! m(end, i) = i; | |
2567 %! m(end - 1, end - i + 1) = i; | |
2568 %! endfor | |
2569 %! m2 = zeros (2, 1001); | |
2570 %! m2(1, :) = fliplr (1:1001); | |
2571 %! m2(2, :) = 1:1001; | |
2572 %! assert (m, m2); | |
2573 | |
2574 %!test | |
2575 %! m = [1 2 3]; | |
2576 %! for i=1:1001 | |
2577 %! m = sin (m); | |
2578 %! break; | |
2579 %! endfor | |
2580 %! assert (m == sin ([1 2 3])); | |
2581 | |
2582 %!test | |
2583 %! i = 0; | |
2584 %! while i < 10 | |
2585 %! i += 1; | |
2586 %! endwhile | |
2587 %! assert (i == 10); | |
2588 | |
2589 %!test | |
2590 %! i = 0; | |
2591 %! while i < 10 | |
2592 %! a = ++i; | |
2593 %! endwhile | |
2594 %! assert (i == 10); | |
2595 %! assert (a == 10); | |
2596 %!test | |
2597 %! i = 0; | |
2598 %! while i < 10 | |
2599 %! a = i++; | |
2600 %! endwhile | |
2601 %! assert (i == 10); | |
2602 %! assert (a == 9); | |
2603 | |
2604 %!test | |
2605 %! num = 2; | |
2606 %! a = zeros (1, num); | |
2607 %! i = 1; | |
2608 %! while i <= num | |
2609 %! a(i) = norm (eye (i)); | |
2610 %! ++i; | |
2611 %! endwhile | |
2612 %! assert (a, ones (1, num)); | |
2613 | |
2614 %!function test_compute_idom () | |
2615 %! while (li <= length (l1) && si <= length (s1)) | |
2616 %! if (l1 (li) < s1 (si)) | |
2617 %! if (li == si) | |
2618 %! break; | |
2619 %! endif; | |
2620 %! li++; | |
2621 %! else | |
2622 %! si++; | |
2623 %! endif; | |
2624 %! endwhile | |
2625 | |
2626 %!error test_compute_idom () | |
2627 | |
2628 %!function x = test_overload (a) | |
2629 %! while 1 | |
2630 %! x = a; | |
2631 %! break; | |
2632 %! endwhile | |
2633 %!endfunction | |
2634 | |
2635 %!assert (test_overload (1), 1); | |
2636 %!assert (test_overload ([1 2]), [1 2]); | |
2637 | |
2638 %!function a = bubble (a = [3 2 1]) | |
2639 %! swapped = 1; | |
2640 %! n = length (a); | |
2641 %! while (swapped) | |
2642 %! swapped = 0; | |
2643 %! for i = 1:n-1 | |
2644 %! if a(i) > a(i + 1) | |
2645 %! swapped = 1; | |
2646 %! temp = a(i); | |
2647 %! a(i) = a(i + 1); | |
2648 %! a(i + 1) = temp; | |
2649 %! endif | |
2650 %! endfor | |
2651 %! endwhile | |
2652 %!endfunction | |
2653 | |
2654 %!assert (bubble (), [1 2 3]); | |
2655 | |
2656 %!test | |
2657 %! a = 0; | |
2658 %! b = 1; | |
2659 %! for i=1:1e3 | |
2660 %! for j=1:2 | |
2661 %! a = a + b; | |
2662 %! endfor | |
2663 %! endfor | |
2664 %! assert (a, 2000); | |
2665 %! assert (b, 1); | |
2666 | |
2667 %!test | |
2668 %! a = [1+1i 1+2i]; | |
2669 %! b = 0; | |
2670 %! while 1 | |
2671 %! b = a(1); | |
2672 %! break; | |
2673 %! endwhile | |
2674 %! assert (b, a(1)); | |
2675 | |
2676 %!function test_undef () | |
2677 %! for i=1:1e7 | |
2678 %! XXX; | |
2679 %! endfor | |
2680 %!endfunction | |
2681 | |
2682 %!error <undefined near> (test_undef); | |
2683 | |
2684 %!shared id | |
2685 %! id = @(x) x; | |
2686 | |
2687 %!assert (id (1), 1); | |
2688 %!assert (id (1+1i), 1+1i) | |
2689 %!assert (id (1, 2), 1) | |
2690 %!error <undefined> (id ()) | |
2691 | |
2692 | |
2693 */ |