+static void
+_do_setup(jit_state_t *_jit)
+{
+ jit_block_t *block;
+ jit_word_t offset;
+
+ /* create initial mapping of live register values
+ * at the start of a basic block */
+ for (offset = 0; offset < _jitc->blocks.offset; offset++) {
+ block = _jitc->blocks.ptr + offset;
+ if (!block->label)
+ continue;
+ if (block->label->code == jit_code_epilog) {
+ jit_regset_setbit(&block->reglive, JIT_RET);
+ jit_regset_setbit(&block->reglive, JIT_FRET);
+ jit_regset_com(&block->regmask, &block->reglive);
+ continue;
+ }
+ jit_setup(block);
+ }
+}
+
+static jit_bool_t
+_block_update_set(jit_state_t *_jit,
+ jit_block_t *block, jit_block_t *target)
+{
+ jit_regset_t regmask;
+
+ jit_regset_ior(®mask, &block->reglive, &target->reglive);
+ jit_regset_and(®mask, ®mask, &block->regmask);
+ if (jit_regset_set_p(®mask)) {
+ jit_regset_ior(&block->reglive, &block->reglive, ®mask);
+ jit_regset_and(®mask, &block->reglive, &block->regmask);
+ jit_regset_com(®mask, ®mask);
+ jit_regset_and(&block->regmask, &block->regmask, ®mask);
+ block->again = 1;
+ return (1);
+ }
+ return (0);
+}
+
+static void
+_propagate_backward(jit_state_t *_jit, jit_block_t *block)
+{
+ jit_block_t *prev;
+ jit_word_t offset;
+
+ for (offset = block->label->v.w - 1;
+ offset >= 0; --offset) {
+ prev = _jitc->blocks.ptr + offset;
+ if (!block_update_set(prev, block) ||
+ !(prev->label->flag & jit_flag_head))
+ break;
+ }
+}
+
+static jit_bool_t
+_check_block_again(jit_state_t *_jit)
+{
+ jit_int32_t todo;
+ jit_word_t offset;
+ jit_node_t *node, *label;
+ jit_block_t *block, *target;
+
+ todo = 0;
+ for (offset = 0; offset < _jitc->blocks.offset; offset++) {
+ block = _jitc->blocks.ptr + offset;
+ if (block->again) {
+ todo = 1;
+ break;
+ }
+ }
+ /* If no block changed state */
+ if (!todo)
+ return (0);
+
+ do {
+ todo = 0;
+ block = NULL;
+ for (node = _jitc->head; node; node = node->next) {
+ /* Special jumps that match jit_cc_a0_jmp */
+ if (node->code == jit_code_calli || node->code == jit_code_callr)
+ continue;
+
+ /* Remember current label */
+ if (node->code == jit_code_label ||
+ node->code == jit_code_prolog ||
+ node->code == jit_code_epilog) {
+
+ /* If previous block does not pass through */
+ if (!(node->flag & jit_flag_head))
+ block = NULL;
+
+ target = _jitc->blocks.ptr + node->v.w;
+ if (block && target->again && block_update_set(block, target)) {
+ propagate_backward(block);
+ todo = 1;
+ }
+ block = target;
+ }
+ /* If not the first jmpi */
+ else if (block) {
+ /* If a jump to dynamic address or if a jump to raw address */
+ if (!(jit_classify(node->code) & jit_cc_a0_jmp) ||
+ !(node->flag & jit_flag_node))
+ continue;
+ label = node->u.n;
+ /* Mark predecessor needs updating due to target change */
+ target = _jitc->blocks.ptr + label->v.w;
+ if (target->again && block_update_set(block, target)) {
+ propagate_backward(block);
+ todo = 1;
+ }
+ }
+ }
+ }
+ while (todo);
+
+ return (todo);
+}
+
+static void
+_do_follow(jit_state_t *_jit, jit_bool_t always)
+{
+ jit_block_t *block;
+ jit_word_t offset;
+
+ /* set live state of registers not referenced in a block, but
+ * referenced in a jump target or normal flow */
+ for (offset = 0; offset < _jitc->blocks.offset; offset++) {
+ block = _jitc->blocks.ptr + offset;
+ if (!block->label || block->label->code == jit_code_epilog)
+ continue;
+ if (always || block->again) {
+ block->again = 0;
+ jit_follow(block);
+ }
+ }
+}
+