/* Compute and initialize all basic blocks. */
static basic_block_t *
-compute_blocks (ptrdiff_t bytestr_length, unsigned char *bytestr_data)
+compute_blocks (ptrdiff_t bytestr_length, unsigned char *bytestr_data,
+ Lisp_Object *vectorp, ptrdiff_t const_length)
{
ptrdiff_t pc = 0;
unsigned op;
case Breturn:
new_bb = true;
break;
+ case Bswitch:
+ /* Handled in Bconstant case. */
+ emacs_abort ();
+ break;
+ case Bconstant:
+ {
+ if (!(Bconstant <= op && op < Bconstant + const_length))
+ emacs_abort ();
+
+ if (bytestr_data[pc] != Bswitch)
+ break;
+ /* Jump table with following Bswitch. */
+ ++pc;
+ op -= Bconstant;
+ struct Lisp_Hash_Table *h = XHASH_TABLE (vectorp[op]);
+ for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
+ if (!NILP (HASH_HASH (h, i)))
+ {
+ Lisp_Object pc = HASH_VALUE (h, i);
+ bb_start_pc[bb_n++] = XFIXNUM (pc);
+ }
+ bb_start_pc[bb_n++] = pc;
+ ++pc;
+ }
default:
break;
}
compile_f (const char *lisp_f_name, const char *c_f_name,
ptrdiff_t bytestr_length, unsigned char *bytestr_data,
EMACS_INT stack_depth, Lisp_Object *vectorp,
- ptrdiff_t vector_size, Lisp_Object args_template)
+ ptrdiff_t const_length, Lisp_Object args_template)
{
USE_SAFE_ALLOCA;
gcc_jit_rvalue *res;
DECL_AND_SAFE_ALLOCA_BLOCK(prologue, comp.func);
comp.block = prologue;
- basic_block_t *bb_map = compute_blocks (bytestr_length, bytestr_data);
+ basic_block_t *bb_map =
+ compute_blocks (bytestr_length, bytestr_data, vectorp, const_length);
if (!parse_args)
{
DISCARD (op);
break;
CASE (Bswitch);
- error ("Bswitch not supported");
/* The cases of Bswitch that we handle (which in theory is
all of them) are done in Bconstant, below. This is done
due to a design issue with Bswitch -- it should have
default:
CASE (Bconstant);
{
- if (op < Bconstant || op > Bconstant + vector_size)
+ if (op < Bconstant || op > Bconstant + const_length)
goto fail;
op -= Bconstant;
break;
}
- /* We're compiling Bswitch instead. */
+ /* Jump table with following Bswitch. */
++pc;
+
+ struct Lisp_Hash_Table *h = XHASH_TABLE (vectorp[op]);
+ POP1;
+ basic_block_t *jump_block;
+ for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
+ if (!NILP (HASH_HASH (h, i)))
+ {
+ SAFE_ALLOCA_BLOCK (jump_block,
+ comp.func,
+ format_string ("jump_t_%ld",
+ i));
+ ptrdiff_t target_pc = XFIXNUM (HASH_VALUE (h, i));
+ gcc_jit_rvalue *val =
+ emit_lisp_obj_from_ptr (HASH_KEY (h, i));
+ emit_cond_jump (emit_EQ (args[0], val), &bb_map[target_pc],
+ jump_block);
+ comp.block = jump_block;
+ }
+
break;
}
}
(should (= (comp-tests-ffuncall-lambda-f 1) 2)))
+(ert-deftest comp-tests-jump-table ()
+ "Testing jump tables"
+ (defun comp-tests-jump-table-1-f (x)
+ (pcase x
+ ('x 'a)
+ ('y 'b)
+ (_ 'c)))
+
+ (byte-compile #'comp-tests-jump-table-1-f)
+ (byte-compile #'comp-tests-jump-table-1-f)
+
+ (should (eq (comp-tests-jump-table-1-f 'x) 'a))
+ (should (eq (comp-tests-jump-table-1-f 'y) 'b))
+ (should (eq (comp-tests-jump-table-1-f 'xxx) 'c)))
+
(ert-deftest comp-tests-conditionals ()
"Testing conditionals."
(defun comp-tests-conditionals-1-f (x)