Mercurial > hg > octave-lyh
comparison src/pt-jit.cc @ 14906:3f81e8b42955
JIT for loops over ranges
* src/pt-eval.cc (tree_evaluator::visit_statment): Removed jit.
(tree_evaluator::visit_simple_for_command): Added jit.
* src/pt-jit.cc: Implement JIT of range based for loops.
* src/pt-jit.h: Implement JI of range based for loops.
* src/pt-loop.h (tree_simple_for_command::get_info,
tree_simple_for_command::stash_info): New functions.
* src/pt-loop.cc (tree_simple_for_command::~tree_simple_for_command):
Delete stashed info.
author | Max Brister <max@2bass.com> |
---|---|
date | Thu, 17 May 2012 16:07:21 -0600 |
parents | 54ea692b8ab5 |
children | a8f1e08de8fc |
comparison
equal
deleted
inserted
replaced
14905:05bf75eaea2a | 14906:3f81e8b42955 |
---|---|
59 static const bool debug_print = false; | 59 static const bool debug_print = false; |
60 | 60 |
61 //FIXME: Move into tree_jit | 61 //FIXME: Move into tree_jit |
62 static llvm::IRBuilder<> builder (llvm::getGlobalContext ()); | 62 static llvm::IRBuilder<> builder (llvm::getGlobalContext ()); |
63 | 63 |
64 // thrown when we should give up on JIT and interpret | |
65 class jit_fail_exception : public std::exception {}; | |
66 | |
67 static void | |
68 fail (void) | |
69 { | |
70 throw jit_fail_exception (); | |
71 } | |
72 | |
64 // function that jit code calls | 73 // function that jit code calls |
65 extern "C" void | 74 extern "C" void |
66 octave_jit_print_any (const char *name, octave_base_value *obv) | 75 octave_jit_print_any (const char *name, octave_base_value *obv) |
67 { | 76 { |
68 obv->print_with_name (octave_stdout, name, true); | 77 obv->print_with_name (octave_stdout, name, true); |
175 | 184 |
176 return idx; | 185 return idx; |
177 } | 186 } |
178 | 187 |
179 // -------------------- jit_typeinfo -------------------- | 188 // -------------------- jit_typeinfo -------------------- |
180 jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e, llvm::Type *ov) | 189 jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e) |
181 : module (m), engine (e), next_id (0), ov_t (ov) | 190 : module (m), engine (e), next_id (0) |
182 { | 191 { |
183 // FIXME: We should be registering types like in octave_value_typeinfo | 192 // FIXME: We should be registering types like in octave_value_typeinfo |
184 llvm::LLVMContext &ctx = m->getContext (); | 193 llvm::LLVMContext &ctx = m->getContext (); |
185 | 194 |
195 ov_t = llvm::StructType::create (ctx, "octave_base_value"); | |
196 ov_t = ov_t->getPointerTo (); | |
197 | |
198 llvm::Type *dbl = llvm::Type::getDoubleTy (ctx); | |
199 llvm::Type *bool_t = llvm::Type::getInt1Ty (ctx); | |
200 llvm::Type *index_t = 0; | |
201 switch (sizeof(octave_idx_type)) | |
202 { | |
203 case 4: | |
204 index_t = llvm::Type::getInt32Ty (ctx); | |
205 break; | |
206 case 8: | |
207 index_t = llvm::Type::getInt64Ty (ctx); | |
208 break; | |
209 default: | |
210 assert (false && "Unrecognized index type size"); | |
211 } | |
212 | |
213 llvm::StructType *range_t = llvm::StructType::create (ctx, "range"); | |
214 std::vector<llvm::Type *> range_contents (4, dbl); | |
215 range_contents[3] = index_t; | |
216 range_t->setBody (range_contents); | |
217 | |
186 // create types | 218 // create types |
187 any = new_type ("any", true, 0, ov_t); | 219 any = new_type ("any", true, 0, ov_t); |
188 scalar = new_type ("scalar", false, any, llvm::Type::getDoubleTy (ctx)); | 220 scalar = new_type ("scalar", false, any, dbl); |
221 range = new_type ("range", false, any, range_t); | |
222 boolean = new_type ("bool", false, any, bool_t); | |
223 index = new_type ("index", false, any, index_t); | |
189 | 224 |
190 // any with anything is an any op | 225 // any with anything is an any op |
191 llvm::IRBuilder<> fn_builder (ctx); | |
192 | |
193 llvm::Type *binary_op_type | 226 llvm::Type *binary_op_type |
194 = llvm::Type::getIntNTy (ctx, sizeof (octave_value::binary_op)); | 227 = llvm::Type::getIntNTy (ctx, sizeof (octave_value::binary_op)); |
195 std::vector<llvm::Type*> args (3); | 228 std::vector<llvm::Type*> args (3); |
196 args[0] = binary_op_type; | 229 args[0] = binary_op_type; |
197 args[1] = args[2] = any->to_llvm (); | 230 args[1] = args[2] = any->to_llvm (); |
209 | 242 |
210 binary_ops.resize (octave_value::num_binary_ops); | 243 binary_ops.resize (octave_value::num_binary_ops); |
211 for (int op = 0; op < octave_value::num_binary_ops; ++op) | 244 for (int op = 0; op < octave_value::num_binary_ops; ++op) |
212 { | 245 { |
213 llvm::FunctionType *ftype = llvm::FunctionType::get (ov_t, args, false); | 246 llvm::FunctionType *ftype = llvm::FunctionType::get (ov_t, args, false); |
214 | 247 |
215 llvm::Twine fn_name ("octave_jit_binary_any_any_"); | 248 llvm::Twine fn_name ("octave_jit_binary_any_any_"); |
216 fn_name = fn_name + llvm::Twine (op); | 249 fn_name = fn_name + llvm::Twine (op); |
217 llvm::Function *fn = llvm::Function::Create (ftype, | 250 llvm::Function *fn = llvm::Function::Create (ftype, |
218 llvm::Function::ExternalLinkage, | 251 llvm::Function::ExternalLinkage, |
219 fn_name, module); | 252 fn_name, module); |
220 llvm::BasicBlock *block = llvm::BasicBlock::Create (ctx, "body", fn); | 253 llvm::BasicBlock *block = llvm::BasicBlock::Create (ctx, "body", fn); |
221 fn_builder.SetInsertPoint (block); | 254 builder.SetInsertPoint (block); |
222 llvm::APInt op_int(sizeof (octave_value::binary_op), op, | 255 llvm::APInt op_int(sizeof (octave_value::binary_op), op, |
223 std::numeric_limits<octave_value::binary_op>::is_signed); | 256 std::numeric_limits<octave_value::binary_op>::is_signed); |
224 llvm::Value *op_as_llvm = llvm::ConstantInt::get (binary_op_type, op_int); | 257 llvm::Value *op_as_llvm = llvm::ConstantInt::get (binary_op_type, op_int); |
225 llvm::Value *ret = fn_builder.CreateCall3 (any_binary, | 258 llvm::Value *ret = builder.CreateCall3 (any_binary, |
226 op_as_llvm, | 259 op_as_llvm, |
227 fn->arg_begin (), | 260 fn->arg_begin (), |
228 ++fn->arg_begin ()); | 261 ++fn->arg_begin ()); |
229 fn_builder.CreateRet (ret); | 262 builder.CreateRet (ret); |
230 | 263 |
231 jit_function::overload overload (fn, true, any, any, any); | 264 jit_function::overload overload (fn, true, any, any, any); |
232 for (octave_idx_type i = 0; i < next_id; ++i) | 265 for (octave_idx_type i = 0; i < next_id; ++i) |
233 binary_ops[op].add_overload (overload); | 266 binary_ops[op].add_overload (overload); |
234 } | 267 } |
235 | 268 |
236 // assign any = any | 269 // assign any = any |
237 llvm::Type *tvoid = llvm::Type::getVoidTy (ctx); | 270 llvm::Type *void_t = llvm::Type::getVoidTy (ctx); |
238 args.resize (2); | 271 args.resize (2); |
239 args[0] = any->to_llvm (); | 272 args[0] = any->to_llvm (); |
240 args[1] = any->to_llvm (); | 273 args[1] = any->to_llvm (); |
241 llvm::FunctionType *ft = llvm::FunctionType::get (tvoid, args, false); | 274 llvm::FunctionType *ft = llvm::FunctionType::get (void_t, args, false); |
242 llvm::Function *fn_help = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | 275 llvm::Function *fn_help = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, |
243 "octave_jit_assign_any_any_help", | 276 "octave_jit_assign_any_any_help", |
244 module); | 277 module); |
245 engine->addGlobalMapping (fn_help, | 278 engine->addGlobalMapping (fn_help, |
246 reinterpret_cast<void*>(&octave_jit_assign_any_any_help)); | 279 reinterpret_cast<void*>(&octave_jit_assign_any_any_help)); |
247 | 280 |
248 args.resize (2); | 281 args.resize (2); |
249 args[0] = any->to_llvm_arg (); | 282 args[0] = any->to_llvm_arg (); |
250 args[1] = any->to_llvm (); | 283 args[1] = any->to_llvm (); |
251 ft = llvm::FunctionType::get (tvoid, args, false); | 284 ft = llvm::FunctionType::get (void_t, args, false); |
252 llvm::Function *fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | 285 llvm::Function *fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, |
253 "octave_jit_assign_any_any", | 286 "octave_jit_assign_any_any", |
254 module); | 287 module); |
255 fn->addFnAttr (llvm::Attribute::AlwaysInline); | 288 fn->addFnAttr (llvm::Attribute::AlwaysInline); |
256 llvm::BasicBlock *body = llvm::BasicBlock::Create (ctx, "body", fn); | 289 llvm::BasicBlock *body = llvm::BasicBlock::Create (ctx, "body", fn); |
257 fn_builder.SetInsertPoint (body); | 290 builder.SetInsertPoint (body); |
258 llvm::Value *value = fn_builder.CreateLoad (fn->arg_begin ()); | 291 llvm::Value *value = builder.CreateLoad (fn->arg_begin ()); |
259 fn_builder.CreateCall2 (fn_help, value, ++fn->arg_begin ()); | 292 builder.CreateCall2 (fn_help, value, ++fn->arg_begin ()); |
260 fn_builder.CreateStore (++fn->arg_begin (), fn->arg_begin ()); | 293 builder.CreateStore (++fn->arg_begin (), fn->arg_begin ()); |
261 fn_builder.CreateRetVoid (); | 294 builder.CreateRetVoid (); |
262 llvm::verifyFunction (*fn); | 295 llvm::verifyFunction (*fn); |
263 assign_fn.add_overload (fn, false, 0, any, any); | 296 assign_fn.add_overload (fn, false, 0, any, any); |
264 | 297 |
265 // assign scalar = scalar | 298 // assign scalar = scalar |
266 args.resize (2); | 299 args.resize (2); |
267 args[0] = scalar->to_llvm_arg (); | 300 args[0] = scalar->to_llvm_arg (); |
268 args[1] = scalar->to_llvm (); | 301 args[1] = scalar->to_llvm (); |
269 ft = llvm::FunctionType::get (tvoid, args, false); | 302 ft = llvm::FunctionType::get (void_t, args, false); |
270 fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | 303 fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, |
271 "octave_jit_assign_scalar_scalar", module); | 304 "octave_jit_assign_scalar_scalar", module); |
272 fn->addFnAttr (llvm::Attribute::AlwaysInline); | 305 fn->addFnAttr (llvm::Attribute::AlwaysInline); |
273 body = llvm::BasicBlock::Create (ctx, "body", fn); | 306 body = llvm::BasicBlock::Create (ctx, "body", fn); |
274 fn_builder.SetInsertPoint (body); | 307 builder.SetInsertPoint (body); |
275 fn_builder.CreateStore (++fn->arg_begin (), fn->arg_begin ()); | 308 builder.CreateStore (++fn->arg_begin (), fn->arg_begin ()); |
276 fn_builder.CreateRetVoid (); | 309 builder.CreateRetVoid (); |
277 llvm::verifyFunction (*fn); | 310 llvm::verifyFunction (*fn); |
278 assign_fn.add_overload (fn, false, 0, scalar, scalar); | 311 assign_fn.add_overload (fn, false, 0, scalar, scalar); |
279 | 312 |
280 // now for binary scalar operations | 313 // now for binary scalar operations |
281 // FIXME: Finish all operations | 314 // FIXME: Finish all operations |
289 add_binary_op (scalar, octave_value::op_el_div, llvm::Instruction::FDiv); | 322 add_binary_op (scalar, octave_value::op_el_div, llvm::Instruction::FDiv); |
290 | 323 |
291 // now for printing functions | 324 // now for printing functions |
292 add_print (any, reinterpret_cast<void*> (&octave_jit_print_any)); | 325 add_print (any, reinterpret_cast<void*> (&octave_jit_print_any)); |
293 add_print (scalar, reinterpret_cast<void*> (&octave_jit_print_double)); | 326 add_print (scalar, reinterpret_cast<void*> (&octave_jit_print_double)); |
327 | |
328 // bounds check for for loop | |
329 args.resize (2); | |
330 args[0] = range->to_llvm (); | |
331 args[1] = index->to_llvm (); | |
332 ft = llvm::FunctionType::get (bool_t, args, false); | |
333 fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | |
334 "octave_jit_simple_for_range", module); | |
335 fn->addFnAttr (llvm::Attribute::AlwaysInline); | |
336 body = llvm::BasicBlock::Create (ctx, "body", fn); | |
337 builder.SetInsertPoint (body); | |
338 { | |
339 llvm::Value *nelem | |
340 = builder.CreateExtractValue (fn->arg_begin (), 3); | |
341 // llvm::Value *idx = builder.CreateLoad (++fn->arg_begin ()); | |
342 llvm::Value *idx = ++fn->arg_begin (); | |
343 llvm::Value *ret = builder.CreateICmpULT (idx, nelem); | |
344 builder.CreateRet (ret); | |
345 } | |
346 llvm::verifyFunction (*fn); | |
347 simple_for_check.add_overload (fn, false, boolean, range, index); | |
348 | |
349 // increment for for loop | |
350 args.resize (1); | |
351 args[0] = index->to_llvm (); | |
352 ft = llvm::FunctionType::get (index->to_llvm (), args, false); | |
353 fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | |
354 "octave_jit_imple_for_range_incr", module); | |
355 fn->addFnAttr (llvm::Attribute::AlwaysInline); | |
356 body = llvm::BasicBlock::Create (ctx, "body", fn); | |
357 builder.SetInsertPoint (body); | |
358 { | |
359 llvm::Value *one = llvm::ConstantInt::get (index_t, 1); | |
360 llvm::Value *idx = fn->arg_begin (); | |
361 llvm::Value *ret = builder.CreateAdd (idx, one); | |
362 builder.CreateRet (ret); | |
363 } | |
364 llvm::verifyFunction (*fn); | |
365 simple_for_incr.add_overload (fn, false, index, index); | |
366 | |
367 // index variabe for for loop | |
368 args.resize (2); | |
369 args[0] = range->to_llvm (); | |
370 args[1] = index->to_llvm (); | |
371 ft = llvm::FunctionType::get (dbl, args, false); | |
372 fn = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, | |
373 "octave_jit_simple_for_idx", module); | |
374 fn->addFnAttr (llvm::Attribute::AlwaysInline); | |
375 body = llvm::BasicBlock::Create (ctx, "body", fn); | |
376 builder.SetInsertPoint (body); | |
377 { | |
378 llvm::Value *idx = ++fn->arg_begin (); | |
379 llvm::Value *didx = builder.CreateUIToFP (idx, dbl); | |
380 llvm::Value *rng = fn->arg_begin (); | |
381 llvm::Value *base = builder.CreateExtractValue (rng, 0); | |
382 llvm::Value *inc = builder.CreateExtractValue (rng, 2); | |
383 | |
384 llvm::Value *ret = builder.CreateFMul (didx, inc); | |
385 ret = builder.CreateFAdd (base, ret); | |
386 builder.CreateRet (ret); | |
387 } | |
388 llvm::verifyFunction (*fn); | |
389 simple_for_index.add_overload (fn, false, scalar, range, index); | |
294 } | 390 } |
295 | 391 |
296 void | 392 void |
297 jit_typeinfo::add_print (jit_type *ty, void *call) | 393 jit_typeinfo::add_print (jit_type *ty, void *call) |
298 { | 394 { |
299 llvm::LLVMContext& ctx = llvm::getGlobalContext (); | 395 llvm::LLVMContext& ctx = llvm::getGlobalContext (); |
300 llvm::Type *tvoid = llvm::Type::getVoidTy (ctx); | 396 llvm::Type *void_t = llvm::Type::getVoidTy (ctx); |
301 std::vector<llvm::Type *> args (2); | 397 std::vector<llvm::Type *> args (2); |
302 args[0] = llvm::Type::getInt8PtrTy (ctx); | 398 args[0] = llvm::Type::getInt8PtrTy (ctx); |
303 args[1] = ty->to_llvm (); | 399 args[1] = ty->to_llvm (); |
304 | 400 |
305 std::stringstream name; | 401 std::stringstream name; |
306 name << "octave_jit_print_" << ty->name (); | 402 name << "octave_jit_print_" << ty->name (); |
307 | 403 |
308 llvm::FunctionType *print_ty = llvm::FunctionType::get (tvoid, args, false); | 404 llvm::FunctionType *print_ty = llvm::FunctionType::get (void_t, args, false); |
309 llvm::Function *fn = llvm::Function::Create (print_ty, | 405 llvm::Function *fn = llvm::Function::Create (print_ty, |
310 llvm::Function::ExternalLinkage, | 406 llvm::Function::ExternalLinkage, |
311 name.str (), module); | 407 name.str (), module); |
312 engine->addGlobalMapping (fn, call); | 408 engine->addGlobalMapping (fn, call); |
313 | 409 |
325 | 421 |
326 std::stringstream fname; | 422 std::stringstream fname; |
327 octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op); | 423 octave_value::binary_op ov_op = static_cast<octave_value::binary_op>(op); |
328 fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op) | 424 fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op) |
329 << "_" << ty->name (); | 425 << "_" << ty->name (); |
330 | 426 |
331 llvm::Function *fn = llvm::Function::Create (ft, | 427 llvm::Function *fn = llvm::Function::Create (ft, |
332 llvm::Function::ExternalLinkage, | 428 llvm::Function::ExternalLinkage, |
333 fname.str (), | 429 fname.str (), |
334 module); | 430 module); |
335 fn->addFnAttr (llvm::Attribute::AlwaysInline); | 431 fn->addFnAttr (llvm::Attribute::AlwaysInline); |
353 return 0; | 449 return 0; |
354 | 450 |
355 if (ov.is_double_type () && ov.is_real_scalar ()) | 451 if (ov.is_double_type () && ov.is_real_scalar ()) |
356 return get_scalar (); | 452 return get_scalar (); |
357 | 453 |
454 if (ov.is_range ()) | |
455 return get_range (); | |
456 | |
358 return get_any (); | 457 return get_any (); |
359 } | 458 } |
360 | 459 |
361 const jit_function& | 460 const jit_function& |
362 jit_typeinfo::binary_op (int op) const | 461 jit_typeinfo::binary_op (int op) const |
383 // duplication here can probably be removed somehow | 482 // duplication here can probably be removed somehow |
384 if (type == any) | 483 if (type == any) |
385 to_generic (type, gv, octave_value ()); | 484 to_generic (type, gv, octave_value ()); |
386 else if (type == scalar) | 485 else if (type == scalar) |
387 to_generic (type, gv, octave_value (0)); | 486 to_generic (type, gv, octave_value (0)); |
487 else if (type == range) | |
488 to_generic (type, gv, octave_value (Range ())); | |
388 else | 489 else |
389 assert (false && "Type not supported yet"); | 490 assert (false && "Type not supported yet"); |
390 } | 491 } |
391 | 492 |
392 void | 493 void |
394 { | 495 { |
395 if (type == any) | 496 if (type == any) |
396 { | 497 { |
397 octave_base_value *obv = ov.internal_rep (); | 498 octave_base_value *obv = ov.internal_rep (); |
398 obv->grab (); | 499 obv->grab (); |
399 ov_out[ov_out_idx] = obv; | 500 ov_out[ov_idx] = obv; |
400 gv.PointerVal = &ov_out[ov_out_idx++]; | 501 gv.PointerVal = &ov_out[ov_idx++]; |
502 } | |
503 else if (type == scalar) | |
504 { | |
505 scalar_out[scalar_idx] = ov.double_value (); | |
506 gv.PointerVal = &scalar_out[scalar_idx++]; | |
507 } | |
508 else if (type == range) | |
509 { | |
510 range_out[range_idx] = ov.range_value (); | |
511 gv.PointerVal = &range_out[range_idx++]; | |
401 } | 512 } |
402 else | 513 else |
403 { | 514 assert (false && "Type not supported yet"); |
404 scalar_out[scalar_out_idx] = ov.double_value (); | |
405 gv.PointerVal = &scalar_out[scalar_out_idx++]; | |
406 } | |
407 } | 515 } |
408 | 516 |
409 octave_value | 517 octave_value |
410 jit_typeinfo::to_octave_value (jit_type *type, llvm::GenericValue& gv) | 518 jit_typeinfo::to_octave_value (jit_type *type, llvm::GenericValue& gv) |
411 { | 519 { |
412 if (type == any) | 520 if (type == any) |
413 { | 521 { |
414 octave_base_value **ptr = reinterpret_cast<octave_base_value**>(gv.PointerVal); | 522 octave_base_value **ptr = reinterpret_cast<octave_base_value **>(gv.PointerVal); |
415 return octave_value (*ptr); | 523 return octave_value (*ptr); |
416 } | 524 } |
417 else if (type == scalar) | 525 else if (type == scalar) |
418 { | 526 { |
419 double *ptr = reinterpret_cast<double*>(gv.PointerVal); | 527 double *ptr = reinterpret_cast<double *>(gv.PointerVal); |
420 return octave_value (*ptr); | 528 return octave_value (*ptr); |
529 } | |
530 else if (type == range) | |
531 { | |
532 jit_range *ptr = reinterpret_cast<jit_range *>(gv.PointerVal); | |
533 Range rng = *ptr; | |
534 return octave_value (rng); | |
421 } | 535 } |
422 else | 536 else |
423 assert (false && "Type not supported yet"); | 537 assert (false && "Type not supported yet"); |
424 } | 538 } |
425 | 539 |
426 void | 540 void |
427 jit_typeinfo::reset_generic (size_t nargs) | 541 jit_typeinfo::reset_generic (size_t nargs) |
428 { | 542 { |
429 scalar_out_idx = 0; | 543 scalar_idx = 0; |
430 ov_out_idx = 0; | 544 ov_idx = 0; |
545 range_idx = 0; | |
431 | 546 |
432 if (scalar_out.size () < nargs) | 547 if (scalar_out.size () < nargs) |
433 scalar_out.resize (nargs); | 548 scalar_out.resize (nargs); |
434 | 549 |
435 if (ov_out.size () < nargs) | 550 if (ov_out.size () < nargs) |
436 ov_out.resize (nargs); | 551 ov_out.resize (nargs); |
552 | |
553 if (range_out.size () < nargs) | |
554 range_out.resize (nargs); | |
437 } | 555 } |
438 | 556 |
439 jit_type* | 557 jit_type* |
440 jit_typeinfo::new_type (const std::string& name, bool force_init, | 558 jit_typeinfo::new_type (const std::string& name, bool force_init, |
441 jit_type *parent, llvm::Type *llvm_type) | 559 jit_type *parent, llvm::Type *llvm_type) |
443 jit_type *ret = new jit_type (name, force_init, parent, llvm_type, next_id++); | 561 jit_type *ret = new jit_type (name, force_init, parent, llvm_type, next_id++); |
444 id_to_type.push_back (ret); | 562 id_to_type.push_back (ret); |
445 return ret; | 563 return ret; |
446 } | 564 } |
447 | 565 |
448 tree_jit::tree_jit (void) : context (llvm::getGlobalContext ()), engine (0) | 566 // -------------------- jit_infer -------------------- |
449 { | 567 void |
450 llvm::InitializeNativeTarget (); | 568 jit_infer::infer (tree_simple_for_command& cmd, jit_type *bounds) |
451 module = new llvm::Module ("octave", context); | 569 { |
452 assert (module); | 570 argin.insert ("#bounds"); |
453 } | 571 types["#bounds"] = bounds; |
454 | 572 |
455 tree_jit::~tree_jit (void) | 573 infer_simple_for (cmd, bounds); |
456 { | 574 } |
457 for (compiled_map::iterator iter = compiled.begin (); iter != compiled.end (); | 575 |
458 ++iter) | 576 void |
459 { | 577 jit_infer::visit_anon_fcn_handle (tree_anon_fcn_handle&) |
460 function_list& flist = iter->second; | 578 { |
461 for (function_list::iterator fiter = flist.begin (); fiter != flist.end (); | 579 fail (); |
462 ++fiter) | 580 } |
463 delete *fiter; | 581 |
464 } | 582 void |
465 | 583 jit_infer::visit_argument_list (tree_argument_list&) |
466 delete tinfo; | 584 { |
467 } | 585 fail (); |
468 | 586 } |
469 bool | 587 |
470 tree_jit::execute (tree& tee) | 588 void |
471 { | 589 jit_infer::visit_binary_expression (tree_binary_expression& be) |
472 // something funny happens during initialization with the engine | |
473 bool need_init = false; | |
474 if (! engine) | |
475 { | |
476 need_init = true; | |
477 engine = llvm::ExecutionEngine::createJIT (module); | |
478 } | |
479 | |
480 if (! engine) | |
481 return false; | |
482 | |
483 if (need_init) | |
484 { | |
485 module_pass_manager = new llvm::PassManager (); | |
486 module_pass_manager->add (llvm::createAlwaysInlinerPass ()); | |
487 | |
488 pass_manager = new llvm::FunctionPassManager (module); | |
489 pass_manager->add (new llvm::TargetData(*engine->getTargetData ())); | |
490 pass_manager->add (llvm::createBasicAliasAnalysisPass ()); | |
491 pass_manager->add (llvm::createPromoteMemoryToRegisterPass ()); | |
492 pass_manager->add (llvm::createInstructionCombiningPass ()); | |
493 pass_manager->add (llvm::createReassociatePass ()); | |
494 pass_manager->add (llvm::createGVNPass ()); | |
495 pass_manager->add (llvm::createCFGSimplificationPass ()); | |
496 pass_manager->doInitialization (); | |
497 | |
498 llvm::Type *ov_t = llvm::StructType::create (context, "octave_base_value"); | |
499 ov_t = ov_t->getPointerTo (); | |
500 | |
501 tinfo = new jit_typeinfo (module, engine, ov_t); | |
502 } | |
503 | |
504 function_list& fnlist = compiled[&tee]; | |
505 for (function_list::iterator iter = fnlist.begin (); iter != fnlist.end (); | |
506 ++iter) | |
507 { | |
508 function_info& fi = **iter; | |
509 if (fi.match ()) | |
510 return fi.execute (); | |
511 } | |
512 | |
513 function_info *fi = new function_info (*this, tee); | |
514 fnlist.push_back (fi); | |
515 | |
516 return fi->execute (); | |
517 } | |
518 | |
519 void | |
520 tree_jit::type_infer::visit_anon_fcn_handle (tree_anon_fcn_handle&) | |
521 { | |
522 fail (); | |
523 } | |
524 | |
525 void | |
526 tree_jit::type_infer::visit_argument_list (tree_argument_list&) | |
527 { | |
528 fail (); | |
529 } | |
530 | |
531 void | |
532 tree_jit::type_infer::visit_binary_expression (tree_binary_expression& be) | |
533 { | 590 { |
534 if (is_lvalue) | 591 if (is_lvalue) |
535 fail (); | 592 fail (); |
536 | 593 |
537 tree_expression *lhs = be.lhs (); | 594 tree_expression *lhs = be.lhs (); |
549 | 606 |
550 type_stack.push_back (result); | 607 type_stack.push_back (result); |
551 } | 608 } |
552 | 609 |
553 void | 610 void |
554 tree_jit::type_infer::visit_break_command (tree_break_command&) | 611 jit_infer::visit_break_command (tree_break_command&) |
555 { | 612 { |
556 fail (); | 613 fail (); |
557 } | 614 } |
558 | 615 |
559 void | 616 void |
560 tree_jit::type_infer::visit_colon_expression (tree_colon_expression&) | 617 jit_infer::visit_colon_expression (tree_colon_expression&) |
561 { | 618 { |
562 fail (); | 619 fail (); |
563 } | 620 } |
564 | 621 |
565 void | 622 void |
566 tree_jit::type_infer::visit_continue_command (tree_continue_command&) | 623 jit_infer::visit_continue_command (tree_continue_command&) |
567 { | 624 { |
568 fail (); | 625 fail (); |
569 } | 626 } |
570 | 627 |
571 void | 628 void |
572 tree_jit::type_infer::visit_global_command (tree_global_command&) | 629 jit_infer::visit_global_command (tree_global_command&) |
573 { | 630 { |
574 fail (); | 631 fail (); |
575 } | 632 } |
576 | 633 |
577 void | 634 void |
578 tree_jit::type_infer::visit_persistent_command (tree_persistent_command&) | 635 jit_infer::visit_persistent_command (tree_persistent_command&) |
579 { | 636 { |
580 fail (); | 637 fail (); |
581 } | 638 } |
582 | 639 |
583 void | 640 void |
584 tree_jit::type_infer::visit_decl_elt (tree_decl_elt&) | 641 jit_infer::visit_decl_elt (tree_decl_elt&) |
585 { | 642 { |
586 fail (); | 643 fail (); |
587 } | 644 } |
588 | 645 |
589 void | 646 void |
590 tree_jit::type_infer::visit_decl_init_list (tree_decl_init_list&) | 647 jit_infer::visit_decl_init_list (tree_decl_init_list&) |
591 { | 648 { |
592 fail (); | 649 fail (); |
593 } | 650 } |
594 | 651 |
595 void | 652 void |
596 tree_jit::type_infer::visit_simple_for_command (tree_simple_for_command&) | 653 jit_infer::visit_simple_for_command (tree_simple_for_command& cmd) |
597 { | 654 { |
598 fail (); | 655 tree_expression *control = cmd.control_expr (); |
599 } | 656 control->accept (*this); |
600 | 657 |
601 void | 658 jit_type *control_t = type_stack.back (); |
602 tree_jit::type_infer::visit_complex_for_command (tree_complex_for_command&) | 659 type_stack.pop_back (); |
603 { | 660 |
604 fail (); | 661 infer_simple_for (cmd, control_t); |
605 } | 662 } |
606 | 663 |
607 void | 664 void |
608 tree_jit::type_infer::visit_octave_user_script (octave_user_script&) | 665 jit_infer::visit_complex_for_command (tree_complex_for_command&) |
609 { | 666 { |
610 fail (); | 667 fail (); |
611 } | 668 } |
612 | 669 |
613 void | 670 void |
614 tree_jit::type_infer::visit_octave_user_function (octave_user_function&) | 671 jit_infer::visit_octave_user_script (octave_user_script&) |
615 { | 672 { |
616 fail (); | 673 fail (); |
617 } | 674 } |
618 | 675 |
619 void | 676 void |
620 tree_jit::type_infer::visit_octave_user_function_header (octave_user_function&) | 677 jit_infer::visit_octave_user_function (octave_user_function&) |
621 { | 678 { |
622 fail (); | 679 fail (); |
623 } | 680 } |
624 | 681 |
625 void | 682 void |
626 tree_jit::type_infer::visit_octave_user_function_trailer (octave_user_function&) | 683 jit_infer::visit_octave_user_function_header (octave_user_function&) |
627 { | 684 { |
628 fail (); | 685 fail (); |
629 } | 686 } |
630 | 687 |
631 void | 688 void |
632 tree_jit::type_infer::visit_function_def (tree_function_def&) | 689 jit_infer::visit_octave_user_function_trailer (octave_user_function&) |
633 { | 690 { |
634 fail (); | 691 fail (); |
635 } | 692 } |
636 | 693 |
637 void | 694 void |
638 tree_jit::type_infer::visit_identifier (tree_identifier& ti) | 695 jit_infer::visit_function_def (tree_function_def&) |
696 { | |
697 fail (); | |
698 } | |
699 | |
700 void | |
701 jit_infer::visit_identifier (tree_identifier& ti) | |
639 { | 702 { |
640 handle_identifier (ti.name (), ti.do_lookup ()); | 703 handle_identifier (ti.name (), ti.do_lookup ()); |
641 } | 704 } |
642 | 705 |
643 void | 706 void |
644 tree_jit::type_infer::visit_if_clause (tree_if_clause&) | 707 jit_infer::visit_if_clause (tree_if_clause&) |
645 { | 708 { |
646 fail (); | 709 fail (); |
647 } | 710 } |
648 | 711 |
649 void | 712 void |
650 tree_jit::type_infer::visit_if_command (tree_if_command&) | 713 jit_infer::visit_if_command (tree_if_command&) |
651 { | 714 { |
652 fail (); | 715 fail (); |
653 } | 716 } |
654 | 717 |
655 void | 718 void |
656 tree_jit::type_infer::visit_if_command_list (tree_if_command_list&) | 719 jit_infer::visit_if_command_list (tree_if_command_list&) |
657 { | 720 { |
658 fail (); | 721 fail (); |
659 } | 722 } |
660 | 723 |
661 void | 724 void |
662 tree_jit::type_infer::visit_index_expression (tree_index_expression&) | 725 jit_infer::visit_index_expression (tree_index_expression&) |
663 { | 726 { |
664 fail (); | 727 fail (); |
665 } | 728 } |
666 | 729 |
667 void | 730 void |
668 tree_jit::type_infer::visit_matrix (tree_matrix&) | 731 jit_infer::visit_matrix (tree_matrix&) |
669 { | 732 { |
670 fail (); | 733 fail (); |
671 } | 734 } |
672 | 735 |
673 void | 736 void |
674 tree_jit::type_infer::visit_cell (tree_cell&) | 737 jit_infer::visit_cell (tree_cell&) |
675 { | 738 { |
676 fail (); | 739 fail (); |
677 } | 740 } |
678 | 741 |
679 void | 742 void |
680 tree_jit::type_infer::visit_multi_assignment (tree_multi_assignment&) | 743 jit_infer::visit_multi_assignment (tree_multi_assignment&) |
681 { | 744 { |
682 fail (); | 745 fail (); |
683 } | 746 } |
684 | 747 |
685 void | 748 void |
686 tree_jit::type_infer::visit_no_op_command (tree_no_op_command&) | 749 jit_infer::visit_no_op_command (tree_no_op_command&) |
687 { | 750 { |
688 fail (); | 751 fail (); |
689 } | 752 } |
690 | 753 |
691 void | 754 void |
692 tree_jit::type_infer::visit_constant (tree_constant& tc) | 755 jit_infer::visit_constant (tree_constant& tc) |
693 { | 756 { |
694 if (is_lvalue) | 757 if (is_lvalue) |
695 fail (); | 758 fail (); |
696 | 759 |
697 octave_value v = tc.rvalue1 (); | 760 octave_value v = tc.rvalue1 (); |
701 | 764 |
702 type_stack.push_back (type); | 765 type_stack.push_back (type); |
703 } | 766 } |
704 | 767 |
705 void | 768 void |
706 tree_jit::type_infer::visit_fcn_handle (tree_fcn_handle&) | 769 jit_infer::visit_fcn_handle (tree_fcn_handle&) |
707 { | 770 { |
708 fail (); | 771 fail (); |
709 } | 772 } |
710 | 773 |
711 void | 774 void |
712 tree_jit::type_infer::visit_parameter_list (tree_parameter_list&) | 775 jit_infer::visit_parameter_list (tree_parameter_list&) |
713 { | 776 { |
714 fail (); | 777 fail (); |
715 } | 778 } |
716 | 779 |
717 void | 780 void |
718 tree_jit::type_infer::visit_postfix_expression (tree_postfix_expression&) | 781 jit_infer::visit_postfix_expression (tree_postfix_expression&) |
719 { | 782 { |
720 fail (); | 783 fail (); |
721 } | 784 } |
722 | 785 |
723 void | 786 void |
724 tree_jit::type_infer::visit_prefix_expression (tree_prefix_expression&) | 787 jit_infer::visit_prefix_expression (tree_prefix_expression&) |
725 { | 788 { |
726 fail (); | 789 fail (); |
727 } | 790 } |
728 | 791 |
729 void | 792 void |
730 tree_jit::type_infer::visit_return_command (tree_return_command&) | 793 jit_infer::visit_return_command (tree_return_command&) |
731 { | 794 { |
732 fail (); | 795 fail (); |
733 } | 796 } |
734 | 797 |
735 void | 798 void |
736 tree_jit::type_infer::visit_return_list (tree_return_list&) | 799 jit_infer::visit_return_list (tree_return_list&) |
737 { | 800 { |
738 fail (); | 801 fail (); |
739 } | 802 } |
740 | 803 |
741 void | 804 void |
742 tree_jit::type_infer::visit_simple_assignment (tree_simple_assignment& tsa) | 805 jit_infer::visit_simple_assignment (tree_simple_assignment& tsa) |
743 { | 806 { |
744 if (is_lvalue) | 807 if (is_lvalue) |
745 fail (); | 808 fail (); |
746 | 809 |
747 // resolve rhs | 810 // resolve rhs |
767 is_lvalue = false; | 830 is_lvalue = false; |
768 rvalue_type = 0; | 831 rvalue_type = 0; |
769 } | 832 } |
770 | 833 |
771 void | 834 void |
772 tree_jit::type_infer::visit_statement (tree_statement& stmt) | 835 jit_infer::visit_statement (tree_statement& stmt) |
773 { | 836 { |
774 if (is_lvalue) | 837 if (is_lvalue) |
775 fail (); | 838 fail (); |
776 | 839 |
777 tree_command *cmd = stmt.command (); | 840 tree_command *cmd = stmt.command (); |
812 type_stack.pop_back (); | 875 type_stack.pop_back (); |
813 } | 876 } |
814 } | 877 } |
815 | 878 |
816 void | 879 void |
817 tree_jit::type_infer::visit_statement_list (tree_statement_list&) | 880 jit_infer::visit_statement_list (tree_statement_list& lst) |
818 { | 881 { |
819 fail (); | 882 tree_statement_list::iterator iter; |
820 } | 883 for (iter = lst.begin (); iter != lst.end (); ++iter) |
821 | 884 { |
822 void | 885 tree_statement *stmt = *iter; |
823 tree_jit::type_infer::visit_switch_case (tree_switch_case&) | 886 assert (stmt); // FIXME: jwe can this be null? |
824 { | 887 stmt->accept (*this); |
825 fail (); | 888 } |
826 } | 889 } |
827 | 890 |
828 void | 891 void |
829 tree_jit::type_infer::visit_switch_case_list (tree_switch_case_list&) | 892 jit_infer::visit_switch_case (tree_switch_case&) |
830 { | 893 { |
831 fail (); | 894 fail (); |
832 } | 895 } |
833 | 896 |
834 void | 897 void |
835 tree_jit::type_infer::visit_switch_command (tree_switch_command&) | 898 jit_infer::visit_switch_case_list (tree_switch_case_list&) |
836 { | 899 { |
837 fail (); | 900 fail (); |
838 } | 901 } |
839 | 902 |
840 void | 903 void |
841 tree_jit::type_infer::visit_try_catch_command (tree_try_catch_command&) | 904 jit_infer::visit_switch_command (tree_switch_command&) |
842 { | 905 { |
843 fail (); | 906 fail (); |
844 } | 907 } |
845 | 908 |
846 void | 909 void |
847 tree_jit::type_infer::visit_unwind_protect_command (tree_unwind_protect_command&) | 910 jit_infer::visit_try_catch_command (tree_try_catch_command&) |
848 { | 911 { |
849 fail (); | 912 fail (); |
850 } | 913 } |
851 | 914 |
852 void | 915 void |
853 tree_jit::type_infer::visit_while_command (tree_while_command&) | 916 jit_infer::visit_unwind_protect_command (tree_unwind_protect_command&) |
854 { | 917 { |
855 fail (); | 918 fail (); |
856 } | 919 } |
857 | 920 |
858 void | 921 void |
859 tree_jit::type_infer::visit_do_until_command (tree_do_until_command&) | 922 jit_infer::visit_while_command (tree_while_command&) |
860 { | 923 { |
861 fail (); | 924 fail (); |
862 } | 925 } |
863 | 926 |
864 void | 927 void |
865 tree_jit::type_infer::handle_identifier (const std::string& name, octave_value v) | 928 jit_infer::visit_do_until_command (tree_do_until_command&) |
929 { | |
930 fail (); | |
931 } | |
932 | |
933 void | |
934 jit_infer::infer_simple_for (tree_simple_for_command& cmd, | |
935 jit_type *bounds) | |
936 { | |
937 if (is_lvalue) | |
938 fail (); | |
939 | |
940 jit_type *iter = tinfo->get_simple_for_index_result (bounds); | |
941 if (! iter) | |
942 fail (); | |
943 | |
944 is_lvalue = true; | |
945 rvalue_type = iter; | |
946 tree_expression *lhs = cmd.left_hand_side (); | |
947 lhs->accept (*this); | |
948 if (type_stack.back () != iter) | |
949 fail (); | |
950 type_stack.pop_back (); | |
951 is_lvalue = false; | |
952 rvalue_type = 0; | |
953 | |
954 tree_statement_list *body = cmd.body (); | |
955 body->accept (*this); | |
956 } | |
957 | |
958 void | |
959 jit_infer::handle_identifier (const std::string& name, octave_value v) | |
866 { | 960 { |
867 type_map::iterator iter = types.find (name); | 961 type_map::iterator iter = types.find (name); |
868 if (iter == types.end ()) | 962 if (iter == types.end ()) |
869 { | 963 { |
870 jit_type *ty = tinfo->type_of (v); | 964 jit_type *ty = tinfo->type_of (v); |
886 } | 980 } |
887 else | 981 else |
888 type_stack.push_back (iter->second); | 982 type_stack.push_back (iter->second); |
889 } | 983 } |
890 | 984 |
891 tree_jit::code_generator::code_generator (jit_typeinfo *ti, llvm::Module *module, | 985 // -------------------- jit_generator -------------------- |
892 tree &tee, | 986 jit_generator::jit_generator (jit_typeinfo *ti, llvm::Module *module, tree &tee, |
893 const std::set<std::string>& argin, | 987 const std::set<std::string>& argin, |
894 const type_map& infered_types) | 988 const type_map& infered_types, bool have_bounds) |
895 : tinfo (ti), is_lvalue (false) | 989 : tinfo (ti), is_lvalue (false) |
896 | |
897 { | 990 { |
898 // determine the function type through the type of all variables | 991 // determine the function type through the type of all variables |
899 std::vector<llvm::Type *> arg_types (infered_types.size ()); | 992 std::vector<llvm::Type *> arg_types (infered_types.size ()); |
900 size_t idx = 0; | 993 size_t idx = 0; |
901 type_map::const_iterator iter; | 994 type_map::const_iterator iter; |
913 llvm::BasicBlock *body = llvm::BasicBlock::Create (ctx, "body", function); | 1006 llvm::BasicBlock *body = llvm::BasicBlock::Create (ctx, "body", function); |
914 builder.SetInsertPoint (body); | 1007 builder.SetInsertPoint (body); |
915 llvm::Function::arg_iterator arg_iter = function->arg_begin(); | 1008 llvm::Function::arg_iterator arg_iter = function->arg_begin(); |
916 for (iter = infered_types.begin (); iter != infered_types.end (); | 1009 for (iter = infered_types.begin (); iter != infered_types.end (); |
917 ++iter, ++arg_iter) | 1010 ++iter, ++arg_iter) |
918 | 1011 |
919 { | 1012 { |
920 llvm::Type *vartype = iter->second->to_llvm (); | 1013 llvm::Type *vartype = iter->second->to_llvm (); |
921 llvm::Value *var = builder.CreateAlloca (vartype, 0, iter->first); | 1014 llvm::Value *var = builder.CreateAlloca (vartype, 0, iter->first); |
922 variables[iter->first] = value (iter->second, var); | 1015 variables[iter->first] = value (iter->second, var); |
923 | 1016 |
929 } | 1022 } |
930 | 1023 |
931 // generate body | 1024 // generate body |
932 try | 1025 try |
933 { | 1026 { |
934 tee.accept (*this); | 1027 tree_simple_for_command *cmd = dynamic_cast<tree_simple_for_command*>(&tee); |
1028 if (have_bounds && cmd) | |
1029 { | |
1030 value bounds = variables["#bounds"]; | |
1031 bounds.second = builder.CreateLoad (bounds.second); | |
1032 emit_simple_for (*cmd, bounds, true); | |
1033 } | |
1034 else | |
1035 tee.accept (*this); | |
935 } | 1036 } |
936 catch (const jit_fail_exception&) | 1037 catch (const jit_fail_exception&) |
937 { | 1038 { |
938 function->eraseFromParent (); | 1039 function->eraseFromParent (); |
939 function = 0; | 1040 function = 0; |
951 } | 1052 } |
952 builder.CreateRetVoid (); | 1053 builder.CreateRetVoid (); |
953 } | 1054 } |
954 | 1055 |
955 void | 1056 void |
956 tree_jit::code_generator::visit_anon_fcn_handle (tree_anon_fcn_handle&) | 1057 jit_generator::visit_anon_fcn_handle (tree_anon_fcn_handle&) |
957 { | 1058 { |
958 fail (); | 1059 fail (); |
959 } | 1060 } |
960 | 1061 |
961 void | 1062 void |
962 tree_jit::code_generator::visit_argument_list (tree_argument_list&) | 1063 jit_generator::visit_argument_list (tree_argument_list&) |
963 { | 1064 { |
964 fail (); | 1065 fail (); |
965 } | 1066 } |
966 | 1067 |
967 void | 1068 void |
968 tree_jit::code_generator::visit_binary_expression (tree_binary_expression& be) | 1069 jit_generator::visit_binary_expression (tree_binary_expression& be) |
969 { | 1070 { |
970 tree_expression *lhs = be.lhs (); | 1071 tree_expression *lhs = be.lhs (); |
971 lhs->accept (*this); | 1072 lhs->accept (*this); |
972 value lhsv = value_stack.back (); | 1073 value lhsv = value_stack.back (); |
973 value_stack.pop_back (); | 1074 value_stack.pop_back (); |
987 rhsv.second); | 1088 rhsv.second); |
988 push_value (ol.result, result); | 1089 push_value (ol.result, result); |
989 } | 1090 } |
990 | 1091 |
991 void | 1092 void |
992 tree_jit::code_generator::visit_break_command (tree_break_command&) | 1093 jit_generator::visit_break_command (tree_break_command&) |
993 { | 1094 { |
994 fail (); | 1095 fail (); |
995 } | 1096 } |
996 | 1097 |
997 void | 1098 void |
998 tree_jit::code_generator::visit_colon_expression (tree_colon_expression&) | 1099 jit_generator::visit_colon_expression (tree_colon_expression&) |
999 { | 1100 { |
1000 fail (); | 1101 fail (); |
1001 } | 1102 } |
1002 | 1103 |
1003 void | 1104 void |
1004 tree_jit::code_generator::visit_continue_command (tree_continue_command&) | 1105 jit_generator::visit_continue_command (tree_continue_command&) |
1005 { | 1106 { |
1006 fail (); | 1107 fail (); |
1007 } | 1108 } |
1008 | 1109 |
1009 void | 1110 void |
1010 tree_jit::code_generator::visit_global_command (tree_global_command&) | 1111 jit_generator::visit_global_command (tree_global_command&) |
1011 { | 1112 { |
1012 fail (); | 1113 fail (); |
1013 } | 1114 } |
1014 | 1115 |
1015 void | 1116 void |
1016 tree_jit::code_generator::visit_persistent_command (tree_persistent_command&) | 1117 jit_generator::visit_persistent_command (tree_persistent_command&) |
1017 { | 1118 { |
1018 fail (); | 1119 fail (); |
1019 } | 1120 } |
1020 | 1121 |
1021 void | 1122 void |
1022 tree_jit::code_generator::visit_decl_elt (tree_decl_elt&) | 1123 jit_generator::visit_decl_elt (tree_decl_elt&) |
1023 { | 1124 { |
1024 fail (); | 1125 fail (); |
1025 } | 1126 } |
1026 | 1127 |
1027 void | 1128 void |
1028 tree_jit::code_generator::visit_decl_init_list (tree_decl_init_list&) | 1129 jit_generator::visit_decl_init_list (tree_decl_init_list&) |
1029 { | 1130 { |
1030 fail (); | 1131 fail (); |
1031 } | 1132 } |
1032 | 1133 |
1033 void | 1134 void |
1034 tree_jit::code_generator::visit_simple_for_command (tree_simple_for_command&) | 1135 jit_generator::visit_simple_for_command (tree_simple_for_command& cmd) |
1035 { | 1136 { |
1036 fail (); | 1137 if (is_lvalue) |
1037 } | 1138 fail (); |
1038 | 1139 |
1039 void | 1140 tree_expression *control = cmd.control_expr (); |
1040 tree_jit::code_generator::visit_complex_for_command (tree_complex_for_command&) | 1141 assert (control); // FIXME: jwe, can this be null? |
1041 { | 1142 |
1042 fail (); | 1143 control->accept (*this); |
1043 } | 1144 value over = value_stack.back (); |
1044 | 1145 value_stack.pop_back (); |
1045 void | 1146 |
1046 tree_jit::code_generator::visit_octave_user_script (octave_user_script&) | 1147 emit_simple_for (cmd, over, false); |
1047 { | 1148 } |
1048 fail (); | 1149 |
1049 } | 1150 void |
1050 | 1151 jit_generator::visit_complex_for_command (tree_complex_for_command&) |
1051 void | 1152 { |
1052 tree_jit::code_generator::visit_octave_user_function (octave_user_function&) | 1153 fail (); |
1053 { | 1154 } |
1054 fail (); | 1155 |
1055 } | 1156 void |
1056 | 1157 jit_generator::visit_octave_user_script (octave_user_script&) |
1057 void | 1158 { |
1058 tree_jit::code_generator::visit_octave_user_function_header (octave_user_function&) | 1159 fail (); |
1059 { | 1160 } |
1060 fail (); | 1161 |
1061 } | 1162 void |
1062 | 1163 jit_generator::visit_octave_user_function (octave_user_function&) |
1063 void | 1164 { |
1064 tree_jit::code_generator::visit_octave_user_function_trailer (octave_user_function&) | 1165 fail (); |
1065 { | 1166 } |
1066 fail (); | 1167 |
1067 } | 1168 void |
1068 | 1169 jit_generator::visit_octave_user_function_header (octave_user_function&) |
1069 void | 1170 { |
1070 tree_jit::code_generator::visit_function_def (tree_function_def&) | 1171 fail (); |
1071 { | 1172 } |
1072 fail (); | 1173 |
1073 } | 1174 void |
1074 | 1175 jit_generator::visit_octave_user_function_trailer (octave_user_function&) |
1075 void | 1176 { |
1076 tree_jit::code_generator::visit_identifier (tree_identifier& ti) | 1177 fail (); |
1178 } | |
1179 | |
1180 void | |
1181 jit_generator::visit_function_def (tree_function_def&) | |
1182 { | |
1183 fail (); | |
1184 } | |
1185 | |
1186 void | |
1187 jit_generator::visit_identifier (tree_identifier& ti) | |
1077 { | 1188 { |
1078 std::string name = ti.name (); | 1189 std::string name = ti.name (); |
1079 value variable = variables[name]; | 1190 value variable = variables[name]; |
1080 if (is_lvalue) | 1191 if (is_lvalue) |
1081 value_stack.push_back (variable); | 1192 value_stack.push_back (variable); |
1085 push_value (variable.first, load); | 1196 push_value (variable.first, load); |
1086 } | 1197 } |
1087 } | 1198 } |
1088 | 1199 |
1089 void | 1200 void |
1090 tree_jit::code_generator::visit_if_clause (tree_if_clause&) | 1201 jit_generator::visit_if_clause (tree_if_clause&) |
1091 { | 1202 { |
1092 fail (); | 1203 fail (); |
1093 } | 1204 } |
1094 | 1205 |
1095 void | 1206 void |
1096 tree_jit::code_generator::visit_if_command (tree_if_command&) | 1207 jit_generator::visit_if_command (tree_if_command&) |
1097 { | 1208 { |
1098 fail (); | 1209 fail (); |
1099 } | 1210 } |
1100 | 1211 |
1101 void | 1212 void |
1102 tree_jit::code_generator::visit_if_command_list (tree_if_command_list&) | 1213 jit_generator::visit_if_command_list (tree_if_command_list&) |
1103 { | 1214 { |
1104 fail (); | 1215 fail (); |
1105 } | 1216 } |
1106 | 1217 |
1107 void | 1218 void |
1108 tree_jit::code_generator::visit_index_expression (tree_index_expression&) | 1219 jit_generator::visit_index_expression (tree_index_expression&) |
1109 { | 1220 { |
1110 fail (); | 1221 fail (); |
1111 } | 1222 } |
1112 | 1223 |
1113 void | 1224 void |
1114 tree_jit::code_generator::visit_matrix (tree_matrix&) | 1225 jit_generator::visit_matrix (tree_matrix&) |
1115 { | 1226 { |
1116 fail (); | 1227 fail (); |
1117 } | 1228 } |
1118 | 1229 |
1119 void | 1230 void |
1120 tree_jit::code_generator::visit_cell (tree_cell&) | 1231 jit_generator::visit_cell (tree_cell&) |
1121 { | 1232 { |
1122 fail (); | 1233 fail (); |
1123 } | 1234 } |
1124 | 1235 |
1125 void | 1236 void |
1126 tree_jit::code_generator::visit_multi_assignment (tree_multi_assignment&) | 1237 jit_generator::visit_multi_assignment (tree_multi_assignment&) |
1127 { | 1238 { |
1128 fail (); | 1239 fail (); |
1129 } | 1240 } |
1130 | 1241 |
1131 void | 1242 void |
1132 tree_jit::code_generator::visit_no_op_command (tree_no_op_command&) | 1243 jit_generator::visit_no_op_command (tree_no_op_command&) |
1133 { | 1244 { |
1134 fail (); | 1245 fail (); |
1135 } | 1246 } |
1136 | 1247 |
1137 void | 1248 void |
1138 tree_jit::code_generator::visit_constant (tree_constant& tc) | 1249 jit_generator::visit_constant (tree_constant& tc) |
1139 { | 1250 { |
1140 octave_value v = tc.rvalue1 (); | 1251 octave_value v = tc.rvalue1 (); |
1252 llvm::LLVMContext& ctx = llvm::getGlobalContext (); | |
1141 if (v.is_real_scalar () && v.is_double_type ()) | 1253 if (v.is_real_scalar () && v.is_double_type ()) |
1142 { | 1254 { |
1143 llvm::LLVMContext& ctx = llvm::getGlobalContext (); | |
1144 double dv = v.double_value (); | 1255 double dv = v.double_value (); |
1145 llvm::Value *lv = llvm::ConstantFP::get (ctx, llvm::APFloat (dv)); | 1256 llvm::Value *lv = llvm::ConstantFP::get (ctx, llvm::APFloat (dv)); |
1146 push_value (tinfo->get_scalar (), lv); | 1257 push_value (tinfo->get_scalar (), lv); |
1147 } | 1258 } |
1259 else if (v.is_range ()) | |
1260 { | |
1261 Range rng = v.range_value (); | |
1262 llvm::Type *range = tinfo->get_range_llvm (); | |
1263 llvm::Type *scalar = tinfo->get_scalar_llvm (); | |
1264 llvm::Type *index = tinfo->get_index_llvm (); | |
1265 | |
1266 std::vector<llvm::Constant *> values (4); | |
1267 values[0] = llvm::ConstantFP::get (scalar, rng.base ()); | |
1268 values[1] = llvm::ConstantFP::get (scalar, rng.limit ()); | |
1269 values[2] = llvm::ConstantFP::get (scalar, rng.inc ()); | |
1270 values[3] = llvm::ConstantInt::get (index, rng.nelem ()); | |
1271 | |
1272 llvm::StructType *llvm_range = llvm::cast<llvm::StructType>(range); | |
1273 llvm::Value *lv = llvm::ConstantStruct::get (llvm_range, values); | |
1274 push_value (tinfo->get_range (), lv); | |
1275 } | |
1148 else | 1276 else |
1149 fail (); | 1277 fail (); |
1150 } | 1278 } |
1151 | 1279 |
1152 void | 1280 void |
1153 tree_jit::code_generator::visit_fcn_handle (tree_fcn_handle&) | 1281 jit_generator::visit_fcn_handle (tree_fcn_handle&) |
1154 { | 1282 { |
1155 fail (); | 1283 fail (); |
1156 } | 1284 } |
1157 | 1285 |
1158 void | 1286 void |
1159 tree_jit::code_generator::visit_parameter_list (tree_parameter_list&) | 1287 jit_generator::visit_parameter_list (tree_parameter_list&) |
1160 { | 1288 { |
1161 fail (); | 1289 fail (); |
1162 } | 1290 } |
1163 | 1291 |
1164 void | 1292 void |
1165 tree_jit::code_generator::visit_postfix_expression (tree_postfix_expression&) | 1293 jit_generator::visit_postfix_expression (tree_postfix_expression&) |
1166 { | 1294 { |
1167 fail (); | 1295 fail (); |
1168 } | 1296 } |
1169 | 1297 |
1170 void | 1298 void |
1171 tree_jit::code_generator::visit_prefix_expression (tree_prefix_expression&) | 1299 jit_generator::visit_prefix_expression (tree_prefix_expression&) |
1172 { | 1300 { |
1173 fail (); | 1301 fail (); |
1174 } | 1302 } |
1175 | 1303 |
1176 void | 1304 void |
1177 tree_jit::code_generator::visit_return_command (tree_return_command&) | 1305 jit_generator::visit_return_command (tree_return_command&) |
1178 { | 1306 { |
1179 fail (); | 1307 fail (); |
1180 } | 1308 } |
1181 | 1309 |
1182 void | 1310 void |
1183 tree_jit::code_generator::visit_return_list (tree_return_list&) | 1311 jit_generator::visit_return_list (tree_return_list&) |
1184 { | 1312 { |
1185 fail (); | 1313 fail (); |
1186 } | 1314 } |
1187 | 1315 |
1188 void | 1316 void |
1189 tree_jit::code_generator::visit_simple_assignment (tree_simple_assignment& tsa) | 1317 jit_generator::visit_simple_assignment (tree_simple_assignment& tsa) |
1190 { | 1318 { |
1191 if (is_lvalue) | 1319 if (is_lvalue) |
1192 fail (); | 1320 fail (); |
1193 | 1321 |
1194 // resolve lhs | 1322 // resolve lhs |
1216 | 1344 |
1217 value_stack.push_back (rhsv); | 1345 value_stack.push_back (rhsv); |
1218 } | 1346 } |
1219 | 1347 |
1220 void | 1348 void |
1221 tree_jit::code_generator::visit_statement (tree_statement& stmt) | 1349 jit_generator::visit_statement (tree_statement& stmt) |
1222 { | 1350 { |
1223 tree_command *cmd = stmt.command (); | 1351 tree_command *cmd = stmt.command (); |
1224 tree_expression *expr = stmt.expression (); | 1352 tree_expression *expr = stmt.expression (); |
1225 | 1353 |
1226 if (cmd) | 1354 if (cmd) |
1264 value_stack.pop_back (); | 1392 value_stack.pop_back (); |
1265 } | 1393 } |
1266 } | 1394 } |
1267 | 1395 |
1268 void | 1396 void |
1269 tree_jit::code_generator::visit_statement_list (tree_statement_list&) | 1397 jit_generator::visit_statement_list (tree_statement_list& lst) |
1270 { | 1398 { |
1271 fail (); | 1399 tree_statement_list::iterator iter; |
1272 } | 1400 for (iter = lst.begin (); iter != lst.end (); ++iter) |
1273 | 1401 { |
1274 void | 1402 tree_statement *stmt = *iter; |
1275 tree_jit::code_generator::visit_switch_case (tree_switch_case&) | 1403 assert (stmt); // FIXME: jwe can this be null? |
1276 { | 1404 stmt->accept (*this); |
1277 fail (); | 1405 } |
1278 } | 1406 } |
1279 | 1407 |
1280 void | 1408 void |
1281 tree_jit::code_generator::visit_switch_case_list (tree_switch_case_list&) | 1409 jit_generator::visit_switch_case (tree_switch_case&) |
1282 { | 1410 { |
1283 fail (); | 1411 fail (); |
1284 } | 1412 } |
1285 | 1413 |
1286 void | 1414 void |
1287 tree_jit::code_generator::visit_switch_command (tree_switch_command&) | 1415 jit_generator::visit_switch_case_list (tree_switch_case_list&) |
1288 { | 1416 { |
1289 fail (); | 1417 fail (); |
1290 } | 1418 } |
1291 | 1419 |
1292 void | 1420 void |
1293 tree_jit::code_generator::visit_try_catch_command (tree_try_catch_command&) | 1421 jit_generator::visit_switch_command (tree_switch_command&) |
1294 { | 1422 { |
1295 fail (); | 1423 fail (); |
1296 } | 1424 } |
1297 | 1425 |
1298 void | 1426 void |
1299 tree_jit::code_generator::visit_unwind_protect_command (tree_unwind_protect_command&) | 1427 jit_generator::visit_try_catch_command (tree_try_catch_command&) |
1300 { | 1428 { |
1301 fail (); | 1429 fail (); |
1302 } | 1430 } |
1303 | 1431 |
1304 void | 1432 void |
1305 tree_jit::code_generator::visit_while_command (tree_while_command&) | 1433 jit_generator::visit_unwind_protect_command (tree_unwind_protect_command&) |
1306 { | 1434 { |
1307 fail (); | 1435 fail (); |
1308 } | 1436 } |
1309 | 1437 |
1310 void | 1438 void |
1311 tree_jit::code_generator::visit_do_until_command (tree_do_until_command&) | 1439 jit_generator::visit_while_command (tree_while_command&) |
1312 { | 1440 { |
1313 fail (); | 1441 fail (); |
1314 } | 1442 } |
1315 | 1443 |
1316 void | 1444 void |
1317 tree_jit::code_generator::emit_print (const std::string& name, const value& v) | 1445 jit_generator::visit_do_until_command (tree_do_until_command&) |
1446 { | |
1447 fail (); | |
1448 } | |
1449 | |
1450 void | |
1451 jit_generator::emit_simple_for (tree_simple_for_command& cmd, value over, | |
1452 bool atleast_once) | |
1453 { | |
1454 if (is_lvalue) | |
1455 fail (); | |
1456 | |
1457 jit_type *index = tinfo->get_index (); | |
1458 llvm::Value *init_index = 0; | |
1459 if (over.first == tinfo->get_range ()) | |
1460 init_index = llvm::ConstantInt::get (index->to_llvm (), 0); | |
1461 else | |
1462 fail (); | |
1463 | |
1464 llvm::Value *llvm_index = builder.CreateAlloca (index->to_llvm (), 0, "index"); | |
1465 builder.CreateStore (init_index, llvm_index); | |
1466 | |
1467 // FIXME: Support break | |
1468 llvm::LLVMContext &ctx = llvm::getGlobalContext (); | |
1469 llvm::BasicBlock *body = llvm::BasicBlock::Create (ctx, "for_body", function); | |
1470 llvm::BasicBlock *cond_check = llvm::BasicBlock::Create (ctx, "for_check", function); | |
1471 llvm::BasicBlock *tail = llvm::BasicBlock::Create (ctx, "for_tail", function); | |
1472 | |
1473 // initialize the iter from the index | |
1474 if (atleast_once) | |
1475 builder.CreateBr (body); | |
1476 else | |
1477 builder.CreateBr (cond_check); | |
1478 | |
1479 builder.SetInsertPoint (body); | |
1480 | |
1481 is_lvalue = true; | |
1482 tree_expression *lhs = cmd.left_hand_side (); | |
1483 lhs->accept (*this); | |
1484 is_lvalue = false; | |
1485 | |
1486 value lhsv = value_stack.back (); | |
1487 value_stack.pop_back (); | |
1488 | |
1489 const jit_function::overload& index_ol = tinfo->get_simple_for_index (over.first); | |
1490 llvm::Value *lindex = builder.CreateLoad (llvm_index); | |
1491 llvm::Value *llvm_iter = builder.CreateCall2 (index_ol.function, over.second, lindex); | |
1492 value iter(index_ol.result, llvm_iter); | |
1493 | |
1494 jit_function::overload assign = tinfo->assign_op (lhsv.first, iter.first); | |
1495 builder.CreateCall2 (assign.function, lhsv.second, iter.second); | |
1496 | |
1497 tree_statement_list *lst = cmd.body (); | |
1498 lst->accept (*this); | |
1499 | |
1500 llvm::Value *one = llvm::ConstantInt::get (index->to_llvm (), 1); | |
1501 lindex = builder.CreateLoad (llvm_index); | |
1502 lindex = builder.CreateAdd (lindex, one); | |
1503 builder.CreateStore (lindex, llvm_index); | |
1504 builder.CreateBr (cond_check); | |
1505 | |
1506 builder.SetInsertPoint (cond_check); | |
1507 lindex = builder.CreateLoad (llvm_index); | |
1508 const jit_function::overload& check_ol = tinfo->get_simple_for_check (over.first); | |
1509 llvm::Value *cond = builder.CreateCall2 (check_ol.function, over.second, lindex); | |
1510 builder.CreateCondBr (cond, body, tail); | |
1511 | |
1512 builder.SetInsertPoint (tail); | |
1513 } | |
1514 | |
1515 void | |
1516 jit_generator::emit_print (const std::string& name, const value& v) | |
1318 { | 1517 { |
1319 const jit_function::overload& ol = tinfo->print_value (v.first); | 1518 const jit_function::overload& ol = tinfo->print_value (v.first); |
1320 if (! ol.function) | 1519 if (! ol.function) |
1321 fail (); | 1520 fail (); |
1322 | 1521 |
1323 llvm::Value *str = builder.CreateGlobalStringPtr (name); | 1522 llvm::Value *str = builder.CreateGlobalStringPtr (name); |
1324 builder.CreateCall2 (ol.function, str, v.second); | 1523 builder.CreateCall2 (ol.function, str, v.second); |
1325 } | 1524 } |
1326 | 1525 |
1327 tree_jit::function_info::function_info (tree_jit& tjit, tree& tee) : | 1526 // -------------------- tree_jit -------------------- |
1328 tinfo (tjit.tinfo), engine (tjit.engine) | 1527 |
1329 { | 1528 tree_jit::tree_jit (void) : context (llvm::getGlobalContext ()), engine (0) |
1330 type_infer infer(tjit.tinfo); | 1529 { |
1530 llvm::InitializeNativeTarget (); | |
1531 module = new llvm::Module ("octave", context); | |
1532 } | |
1533 | |
1534 tree_jit::~tree_jit (void) | |
1535 { | |
1536 delete tinfo; | |
1537 } | |
1538 | |
1539 bool | |
1540 tree_jit::execute (tree_simple_for_command& cmd, const octave_value& bounds) | |
1541 { | |
1542 if (! initialize ()) | |
1543 return false; | |
1544 | |
1545 jit_type *bounds_t = tinfo->type_of (bounds); | |
1546 jit_info *jinfo = cmd.get_info (bounds_t); | |
1547 if (! jinfo) | |
1548 { | |
1549 jinfo = new jit_info (*this, cmd, bounds_t); | |
1550 cmd.stash_info (bounds_t, jinfo); | |
1551 } | |
1552 | |
1553 return jinfo->execute (bounds); | |
1554 } | |
1555 | |
1556 bool | |
1557 tree_jit::initialize (void) | |
1558 { | |
1559 if (engine) | |
1560 return true; | |
1561 | |
1562 // sometimes this fails pre main | |
1563 engine = llvm::ExecutionEngine::createJIT (module); | |
1564 | |
1565 if (! engine) | |
1566 return false; | |
1567 | |
1568 module_pass_manager = new llvm::PassManager (); | |
1569 module_pass_manager->add (llvm::createAlwaysInlinerPass ()); | |
1570 | |
1571 pass_manager = new llvm::FunctionPassManager (module); | |
1572 pass_manager->add (new llvm::TargetData(*engine->getTargetData ())); | |
1573 pass_manager->add (llvm::createBasicAliasAnalysisPass ()); | |
1574 pass_manager->add (llvm::createPromoteMemoryToRegisterPass ()); | |
1575 pass_manager->add (llvm::createInstructionCombiningPass ()); | |
1576 pass_manager->add (llvm::createReassociatePass ()); | |
1577 pass_manager->add (llvm::createGVNPass ()); | |
1578 pass_manager->add (llvm::createCFGSimplificationPass ()); | |
1579 pass_manager->doInitialization (); | |
1580 | |
1581 tinfo = new jit_typeinfo (module, engine); | |
1582 | |
1583 return true; | |
1584 } | |
1585 | |
1586 | |
1587 void | |
1588 tree_jit::optimize (llvm::Function *fn) | |
1589 { | |
1590 module_pass_manager->run (*module); | |
1591 pass_manager->run (*fn); | |
1592 } | |
1593 | |
1594 // -------------------- jit_info -------------------- | |
1595 jit_info::jit_info (tree_jit& tjit, tree_simple_for_command& cmd, | |
1596 jit_type *bounds) : tinfo (tjit.get_typeinfo ()), | |
1597 engine (tjit.get_engine ()) | |
1598 { | |
1599 jit_infer infer(tinfo); | |
1331 | 1600 |
1332 try | 1601 try |
1333 { | 1602 { |
1334 tee.accept (infer); | 1603 infer.infer (cmd, bounds); |
1335 } | 1604 } |
1336 catch (const jit_fail_exception&) | 1605 catch (const jit_fail_exception&) |
1337 { | 1606 { |
1338 function = 0; | 1607 function = 0; |
1339 return; | 1608 return; |
1340 } | 1609 } |
1341 | 1610 |
1342 argin = infer.get_argin (); | 1611 argin = infer.get_argin (); |
1343 types = infer.get_types (); | 1612 types = infer.get_types (); |
1344 | 1613 |
1345 code_generator gen(tjit.tinfo, tjit.module, tee, argin, types); | 1614 jit_generator gen(tinfo, tjit.get_module (), cmd, argin, types); |
1346 function = gen.get_function (); | 1615 function = gen.get_function (); |
1347 | 1616 |
1348 if (function) | 1617 if (function) |
1349 { | 1618 { |
1350 llvm::verifyFunction (*function); | |
1351 tjit.module_pass_manager->run (*tjit.module); | |
1352 tjit.pass_manager->run (*function); | |
1353 | |
1354 if (debug_print) | 1619 if (debug_print) |
1355 { | 1620 { |
1356 std::cout << "Compiled:\n"; | 1621 std::cout << "Compiled code:\n"; |
1357 std::cout << tee.str_print_code () << std::endl; | 1622 std::cout << cmd.str_print_code () << std::endl; |
1358 | 1623 |
1359 std::cout << "Code:\n"; | 1624 std::cout << "Before optimization:\n"; |
1360 | 1625 |
1361 llvm::raw_os_ostream os (std::cout); | 1626 llvm::raw_os_ostream os (std::cout); |
1362 function->print (os); | 1627 function->print (os); |
1363 } | 1628 } |
1629 llvm::verifyFunction (*function); | |
1630 tjit.optimize (function); | |
1631 | |
1632 if (debug_print) | |
1633 { | |
1634 std::cout << "After optimization:\n"; | |
1635 | |
1636 llvm::raw_os_ostream os (std::cout); | |
1637 function->print (os); | |
1638 } | |
1364 } | 1639 } |
1365 } | 1640 } |
1366 | 1641 |
1367 bool | 1642 bool |
1368 tree_jit::function_info::execute () const | 1643 jit_info::execute (const octave_value& bounds) const |
1369 { | 1644 { |
1370 if (! function) | 1645 if (! function) |
1371 return false; | 1646 return false; |
1372 | 1647 |
1373 tinfo->reset_generic (types.size ()); | 1648 tinfo->reset_generic (types.size ()); |
1377 type_map::const_iterator iter; | 1652 type_map::const_iterator iter; |
1378 for (idx = 0, iter = types.begin (); iter != types.end (); ++iter, ++idx) | 1653 for (idx = 0, iter = types.begin (); iter != types.end (); ++iter, ++idx) |
1379 { | 1654 { |
1380 if (argin.count (iter->first)) | 1655 if (argin.count (iter->first)) |
1381 { | 1656 { |
1382 octave_value ov = symbol_table::varval (iter->first); | 1657 octave_value ov; |
1658 if (iter->first == "#bounds") | |
1659 ov = bounds; | |
1660 else | |
1661 ov = symbol_table::varval (iter->first); | |
1662 | |
1383 tinfo->to_generic (iter->second, args[idx], ov); | 1663 tinfo->to_generic (iter->second, args[idx], ov); |
1384 } | 1664 } |
1385 else | 1665 else |
1386 tinfo->to_generic (iter->second, args[idx]); | 1666 tinfo->to_generic (iter->second, args[idx]); |
1387 } | 1667 } |
1396 | 1676 |
1397 return true; | 1677 return true; |
1398 } | 1678 } |
1399 | 1679 |
1400 bool | 1680 bool |
1401 tree_jit::function_info::match () const | 1681 jit_info::match () const |
1402 { | 1682 { |
1403 for (std::set<std::string>::iterator iter = argin.begin (); | 1683 for (std::set<std::string>::iterator iter = argin.begin (); |
1404 iter != argin.end (); ++iter) | 1684 iter != argin.end (); ++iter) |
1405 { | 1685 { |
1686 if (*iter == "#bounds") | |
1687 continue; | |
1688 | |
1406 jit_type *required_type = types.find (*iter)->second; | 1689 jit_type *required_type = types.find (*iter)->second; |
1407 octave_value val = symbol_table::varref (*iter); | 1690 octave_value val = symbol_table::varref (*iter); |
1408 jit_type *current_type = tinfo->type_of (val); | 1691 jit_type *current_type = tinfo->type_of (val); |
1409 | 1692 |
1410 // FIXME: should be: ! required_type->is_parent (current_type) | 1693 // FIXME: should be: ! required_type->is_parent (current_type) |