# HG changeset patch # User Stefan Mahr # Date 1388940712 -3600 # Node ID 421bed6994f061bde32424cf5c4b94ac8208b38c # Parent 2a8243d8327a042560b39f62650bfbec6f0aeecb jit compiler: Add support for switch statement * libinterp/corefcn/pt-jit.cc (jit_convert::visit_switch_command): JIT compile switch statement. * test/jit.tst: Add tests for switch statement diff -r 2a8243d8327a -r 421bed6994f0 libinterp/corefcn/pt-jit.cc --- a/libinterp/corefcn/pt-jit.cc Fri Dec 27 13:01:39 2013 +0100 +++ b/libinterp/corefcn/pt-jit.cc Sun Jan 05 17:51:52 2014 +0100 @@ -823,9 +823,110 @@ } void -jit_convert::visit_switch_command (tree_switch_command&) +jit_convert::visit_switch_command (tree_switch_command& cmd) { - throw jit_fail_exception (); + tree_switch_case_list *lst = cmd.case_list (); + + // always visit switch expression + tree_expression *expr = cmd.switch_value (); + assert (expr && "Switch value can not be null"); + jit_value *value = visit (expr); + assert (value); + + size_t case_blocks_num = lst->size (); + + if (! case_blocks_num) // there's nothing to do + return; + + // check for otherwise, it's interpreted as last 'else' condition + size_t has_otherwise = 0; + tree_switch_case *last = lst->back (); + if (last->is_default_case ()) + has_otherwise = 1; + + std::vector entry_blocks (case_blocks_num + 1 - has_otherwise); + + // the first entry point is always the actual block. afterward new blocks + // are created for every case and the otherwise branch + entry_blocks[0] = block; + for (size_t i = 1; i < case_blocks_num; ++i) + entry_blocks[i] = factory.create ("case_cond"); + + jit_block *tail = factory.create ("switch_tail"); + + // if there's no otherwise branch, the the 'else' of the last branch + // has to point to the tail + if (! has_otherwise) + entry_blocks[entry_blocks.size()-1] = tail; + + // each branch in the case statement will have different breaks/continues + block_list current_breaks = breaks; + block_list current_continues = continues; + breaks.clear (); + continues.clear (); + + size_t num_incomming = 0; // number of incomming blocks to our tail + + tree_switch_case_list::iterator iter = lst->begin (); + for (size_t i = 0; i < case_blocks_num; ++iter, ++i) + { + tree_switch_case *twc = *iter; + block = entry_blocks[i]; // case_cond + assert (block); + + if (i) + blocks.push_back (entry_blocks[i]); // first block already pushed + + if (! twc->is_default_case ()) + { + // compare result of switch expression with actual case label + tree_expression *te = twc->case_label (); + jit_value *label = visit (te); + assert(label); + + const jit_operation& fn = jit_typeinfo::binary_op (octave_value::op_eq); + jit_value *cond = create_checked (fn, value, label); + assert(cond); + + jit_call *check = create_checked (&jit_typeinfo::logically_true, + cond); + + jit_block *body = factory.create ("case_body"); + blocks.push_back (body); + + block->append (factory.create (check, body, + entry_blocks[i+1])); + block = body; // case_body + } + + tree_statement_list *stmt_lst = twc->commands (); + assert(stmt_lst); + + try + { + stmt_lst->accept (*this); + num_incomming++; + block->append (factory.create (tail)); + } + catch (const jit_break_exception&) + { } + + // each branch in the case statement will have different breaks/continues + current_breaks.splice (current_breaks.end (), breaks); + current_continues.splice (current_continues.end (), continues); + } + + // each branch in the case statement will have different breaks/continues + breaks.splice (breaks.end (), current_breaks); + continues.splice (continues.end (), current_continues); + + if (num_incomming || ! has_otherwise) + { + blocks.push_back (tail); + block = tail; // switch_tail + } + else + throw jit_break_exception (); // every branch broke } void diff -r 2a8243d8327a -r 421bed6994f0 test/jit.tst --- a/test/jit.tst Fri Dec 27 13:01:39 2013 +0100 +++ b/test/jit.tst Sun Jan 05 17:51:52 2014 +0100 @@ -26,7 +26,6 @@ %! __old_jit_startcnt__ = jit_startcnt (1000); ## Test some simple cases that compile. - %!testif HAVE_LLVM %! jit_failure_count (0) %! for i=1:1e6 @@ -96,9 +95,75 @@ %! endparfor %! assert (i, 100); %! assert (jit_failure_count, 0); +## Test some switch statements +%!testif HAVE_LLVM +%! jit_failure_count (0) +%! do +%! switch (1) +%! end; +%! until(1) +%! assert (jit_failure_count, 0); %!testif HAVE_LLVM %! jit_failure_count (0) +%! do +%! switch (1) +%! case 1 +%! break; +%! end; +%! until(1) +%! assert (jit_failure_count, 0); + +%!testif HAVE_LLVM +%! jit_failure_count (0) +%! do +%! switch (1) +%! otherwise +%! break; +%! end; +%! until(1) +%! assert (jit_failure_count, 0); + +%!testif HAVE_LLVM +%! jit_failure_count (0) +%! do +%! switch (1) +%! case 1 +%! break; +%! otherwise +%! break; +%! end; +%! until(1) +%! assert (jit_failure_count, 0); + +%!testif HAVE_LLVM +%! jit_failure_count (0) +%! i=0; +%! a=0; +%! b=0; +%! do +%! i=i+1; +%! switch (i) +%! case 1 +%! continue; +%! case 2 +%! b=1; +%! continue; +%! case 4 +%! break; +%! otherwise +%! a=a+5; +%! end; +%! a=a+1; +%! until(0); +%! assert (i, 4); +%! assert (a, 6); +%! assert (b, 1); +%! assert (jit_failure_count, 0); + +## Some more complex calculations +%!testif HAVE_LLVM +%! jit_failure_count (0) %! inc = 1e-5; %! result = 0; %! for ii = 0:inc:1