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 */