int tcg_gen_code(TCGContext *s, TranslationBlock *tb) { #ifdef CONFIG_PROFILER TCGProfile *prof = &s->prof; #endif int i, oi, oi_next, num_insns; #ifdef CONFIG_PROFILER { int n; n = s->gen_op_buf[0].prev + 1; atomic_set(&prof->op_count, prof->op_count + n); if (n > prof->op_count_max) { atomic_set(&prof->op_count_max, n); } n = s->nb_temps; atomic_set(&prof->temp_count, prof->temp_count + n); if (n > prof->temp_count_max) { atomic_set(&prof->temp_count_max, n); } } #endif #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) && qemu_log_in_addr_range(tb->pc))) { qemu_log_lock(); qemu_log("OP:\n"); tcg_dump_ops(s); qemu_log("\n"); qemu_log_unlock(); } #endif #ifdef CONFIG_PROFILER atomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); #endif #ifdef USE_TCG_OPTIMIZATIONS tcg_optimize(s); #endif #ifdef CONFIG_PROFILER atomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); atomic_set(&prof->la_time, prof->la_time - profile_getclock()); #endif liveness_pass_1(s); if (s->nb_indirects > 0) { #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) && qemu_log_in_addr_range(tb->pc))) { qemu_log_lock(); qemu_log("OP before indirect lowering:\n"); tcg_dump_ops(s); qemu_log("\n"); qemu_log_unlock(); } #endif /* Replace indirect temps with direct temps. */ if (liveness_pass_2(s)) { /* If changes were made, re-run liveness. */ liveness_pass_1(s); } } #ifdef CONFIG_PROFILER atomic_set(&prof->la_time, prof->la_time + profile_getclock()); #endif #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) && qemu_log_in_addr_range(tb->pc))) { qemu_log_lock(); qemu_log("OP after optimization and liveness analysis:\n"); tcg_dump_ops(s); qemu_log("\n"); qemu_log_unlock(); } #endif tcg_reg_alloc_start(s); s->code_buf = tb->tc.ptr; s->code_ptr = tb->tc.ptr; #ifdef TCG_TARGET_NEED_LDST_LABELS s->ldst_labels = NULL; #endif #ifdef TCG_TARGET_NEED_POOL_LABELS s->pool_labels = NULL; #endif num_insns = -1; for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { TCGOp * const op = &s->gen_op_buf[oi]; TCGOpcode opc = op->opc; oi_next = op->next; #ifdef CONFIG_PROFILER atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); #endif switch (opc) { case INDEX_op_mov_i32: case INDEX_op_mov_i64: tcg_reg_alloc_mov(s, op); break; case INDEX_op_movi_i32: case INDEX_op_movi_i64: tcg_reg_alloc_movi(s, op); break; case INDEX_op_insn_start: if (num_insns >= 0) { s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); } num_insns++; for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { target_ulong a; #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); #else a = op->args[i]; #endif s->gen_insn_data[num_insns][i] = a; } break; case INDEX_op_discard: temp_dead(s, arg_temp(op->args[0])); break; case INDEX_op_set_label: tcg_reg_alloc_bb_end(s, s->reserved_regs); tcg_out_label(s, arg_label(op->args[0]), s->code_ptr); break; case INDEX_op_call: tcg_reg_alloc_call(s, op); break; default: /* Sanity check that we've not introduced any unhandled opcodes. */ tcg_debug_assert(tcg_op_supported(opc)); /* Note: in order to speed up the code, it would be much faster to have specialized register allocator functions for some common argument patterns */ tcg_reg_alloc_op(s, op); break; } #ifdef CONFIG_DEBUG_TCG check_regs(s); #endif /* Test for (pending) buffer overflow. The assumption is that any one operation beginning below the high water mark cannot overrun the buffer completely. Thus we can test for overflow after generating code without having to check during generation. */ if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { return -1; } } tcg_debug_assert(num_insns >= 0); s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); /* Generate TB finalization at the end of block */ #ifdef TCG_TARGET_NEED_LDST_LABELS if (!tcg_out_ldst_finalize(s)) { return -1; } #endif #ifdef TCG_TARGET_NEED_POOL_LABELS if (!tcg_out_pool_finalize(s)) { return -1; } #endif /* flush instruction cache */ flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); return tcg_current_code_size(s); }
int tcg_gen_code(TCGContext *s, TranslationBlock *tb) { #ifdef CONFIG_PROFILER TCGProfile *prof = &s->prof; #endif int i, oi, oi_next, num_insns; #ifdef CONFIG_PROFILER { int n; n = s->gen_op_buf[0].prev + 1; atomic_set(&prof->op_count, prof->op_count + n); if (n > prof->op_count_max) { atomic_set(&prof->op_count_max, n); } n = s->nb_temps; atomic_set(&prof->temp_count, prof->temp_count + n); if (n > prof->temp_count_max) { atomic_set(&prof->temp_count_max, n); } } #endif #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) && qemu_log_in_addr_range(tb->pc))) { qemu_log_lock(); qemu_log("OP:\n"); tcg_dump_ops(s); qemu_log("\n"); qemu_log_unlock(); } #endif #ifdef CONFIG_PROFILER atomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); #endif #ifdef USE_TCG_OPTIMIZATIONS tcg_optimize(s); #endif #ifdef CONFIG_PROFILER atomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); atomic_set(&prof->la_time, prof->la_time - profile_getclock()); #endif liveness_pass_1(s); if (s->nb_indirects > 0) { #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) && qemu_log_in_addr_range(tb->pc))) { qemu_log_lock(); qemu_log("OP before indirect lowering:\n"); tcg_dump_ops(s); qemu_log("\n"); qemu_log_unlock(); } #endif   if (liveness_pass_2(s)) {   liveness_pass_1(s); } } #ifdef CONFIG_PROFILER atomic_set(&prof->la_time, prof->la_time + profile_getclock()); #endif #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) && qemu_log_in_addr_range(tb->pc))) { qemu_log_lock(); qemu_log("OP after optimization and liveness analysis:\n"); tcg_dump_ops(s); qemu_log("\n"); qemu_log_unlock(); } #endif tcg_reg_alloc_start(s); s->code_buf = tb->tc.ptr; s->code_ptr = tb->tc.ptr; #ifdef TCG_TARGET_NEED_LDST_LABELS s->ldst_labels = NULL; #endif #ifdef TCG_TARGET_NEED_POOL_LABELS s->pool_labels = NULL; #endif num_insns = -1; for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { TCGOp * const op = &s->gen_op_buf[oi]; TCGOpcode opc = op->opc; oi_next = op->next; #ifdef CONFIG_PROFILER atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); #endif switch (opc) { case INDEX_op_mov_i32: case INDEX_op_mov_i64: tcg_reg_alloc_mov(s, op); break; case INDEX_op_movi_i32: case INDEX_op_movi_i64: tcg_reg_alloc_movi(s, op); break; case INDEX_op_insn_start: if (num_insns >= 0) { s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); } num_insns++; for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { target_ulong a; #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS a = deposit64(op->args[i * 2], 32, 32, op->args[i * 2 + 1]); #else a = op->args[i]; #endif s->gen_insn_data[num_insns][i] = a; } break; case INDEX_op_discard: temp_dead(s, arg_temp(op->args[0])); break; case INDEX_op_set_label: tcg_reg_alloc_bb_end(s, s->reserved_regs); tcg_out_label(s, arg_label(op->args[0]), s->code_ptr); break; case INDEX_op_call: tcg_reg_alloc_call(s, op); break; default:   tcg_debug_assert(tcg_op_supported(opc));   tcg_reg_alloc_op(s, op); break; } #ifdef CONFIG_DEBUG_TCG check_regs(s); #endif   if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { return -1; } } tcg_debug_assert(num_insns >= 0); s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);   #ifdef TCG_TARGET_NEED_LDST_LABELS if (!tcg_out_ldst_finalize(s)) { return -1; } #endif #ifdef TCG_TARGET_NEED_POOL_LABELS if (!tcg_out_pool_finalize(s)) { return -1; } #endif   flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); return tcg_current_code_size(s); }