tcg: use tcg_debug_assert instead of assert (fix performance regression)
The TCG code is quite performance sensitive, but at the same time can
also be quite tricky. That is why asserts that can be enabled with the
--enable-debug-tcg configure option.
This used to work the following way:
| #include "config.h"
|
| ...
|
| #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
| /* define it to suppress various consistency checks (faster) */
| #define NDEBUG
| #endif
|
| ...
|
| #include <assert.h>
Since commit 757e725b (tcg: Clean up includes) "config.h" as been
replaced by "qemu/osdep.h" which itself includes <assert.h>. As a
consequence the assertions are always enabled, even when using
--disable-debug-tcg, causing a performance regression, especially on
targets with many registers. For instance on qemu-system-ppc the
speed difference is about 15%.
tcg_debug_assert is controlled directly by CONFIG_DEBUG_TCG and already
uses in some places. This patch replaces all the calls to assert into
calss to tcg_debug_assert.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Message-id: 1461228530-14852-1-git-send-email-aurelien@aurel32.net
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/tcg/tcg.c b/tcg/tcg.c
index b46bf1a..525d5c8 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -229,7 +229,7 @@
intptr_t value = (intptr_t)ptr;
TCGRelocation *r;
- assert(!l->has_value);
+ tcg_debug_assert(!l->has_value);
for (r = l->u.first_reloc; r != NULL; r = r->next) {
patch_reloc(r->ptr, r->type, value, r->addend);
@@ -645,9 +645,9 @@
}
#endif
- assert(idx >= s->nb_globals && idx < s->nb_temps);
+ tcg_debug_assert(idx >= s->nb_globals && idx < s->nb_temps);
ts = &s->temps[idx];
- assert(ts->temp_allocated != 0);
+ tcg_debug_assert(ts->temp_allocated != 0);
ts->temp_allocated = 0;
k = ts->base_type + (ts->temp_local ? TCG_TYPE_COUNT : 0);
@@ -948,7 +948,7 @@
static char *tcg_get_arg_str_idx(TCGContext *s, char *buf,
int buf_size, int idx)
{
- assert(idx >= 0 && idx < s->nb_temps);
+ tcg_debug_assert(idx >= 0 && idx < s->nb_temps);
return tcg_get_arg_str_ptr(s, buf, buf_size, &s->temps[idx]);
}
@@ -1191,25 +1191,25 @@
if (tdefs->op == (TCGOpcode)-1)
break;
op = tdefs->op;
- assert((unsigned)op < NB_OPS);
+ tcg_debug_assert((unsigned)op < NB_OPS);
def = &tcg_op_defs[op];
#if defined(CONFIG_DEBUG_TCG)
/* Duplicate entry in op definitions? */
- assert(!def->used);
+ tcg_debug_assert(!def->used);
def->used = 1;
#endif
nb_args = def->nb_iargs + def->nb_oargs;
for(i = 0; i < nb_args; i++) {
ct_str = tdefs->args_ct_str[i];
/* Incomplete TCGTargetOpDef entry? */
- assert(ct_str != NULL);
+ tcg_debug_assert(ct_str != NULL);
tcg_regset_clear(def->args_ct[i].u.regs);
def->args_ct[i].ct = 0;
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
int oarg;
oarg = ct_str[0] - '0';
- assert(oarg < def->nb_oargs);
- assert(def->args_ct[oarg].ct & TCG_CT_REG);
+ tcg_debug_assert(oarg < def->nb_oargs);
+ tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
/* TCG_CT_ALIAS is for the output arguments. The input
argument is tagged with TCG_CT_IALIAS. */
def->args_ct[i] = def->args_ct[oarg];
@@ -1238,7 +1238,7 @@
}
/* TCGTargetOpDef entry with too much information? */
- assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
+ tcg_debug_assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
/* sort the constraints (XXX: this is just an heuristic) */
sort_constraints(def, 0, def->nb_oargs);
@@ -1685,7 +1685,7 @@
{
TCGTemp *ts = s->reg_to_temp[reg];
- assert(ts->val_type == TEMP_VAL_REG);
+ tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
if (!ts->mem_coherent && !ts->fixed_reg) {
if (!ts->mem_allocated) {
temp_allocate_frame(s, temp_idx(s, ts));
@@ -1822,7 +1822,7 @@
/* ??? Liveness does not yet incorporate indirect bases. */
if (!ts->indirect_base) {
/* The liveness analysis already ensures that globals are back
- in memory. Keep an assert for safety. */
+ in memory. Keep an tcg_debug_assert for safety. */
tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg);
return;
}
@@ -1880,8 +1880,8 @@
/* ??? Liveness does not yet incorporate indirect bases. */
if (!ts->indirect_base) {
/* The liveness analysis already ensures that temps are dead.
- Keep an assert for safety. */
- assert(ts->val_type == TEMP_VAL_DEAD);
+ Keep an tcg_debug_assert for safety. */
+ tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
continue;
}
#endif
@@ -1952,9 +1952,9 @@
if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
/* mov to a non-saved dead register makes no sense (even with
liveness analysis disabled). */
- assert(NEED_SYNC_ARG(0));
+ tcg_debug_assert(NEED_SYNC_ARG(0));
/* The code above should have moved the temp to a register. */
- assert(ts->val_type == TEMP_VAL_REG);
+ tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
if (!ots->mem_allocated) {
temp_allocate_frame(s, args[0]);
}
@@ -1982,7 +1982,7 @@
} else {
/* The code in the first if block should have moved the
temp to a register. */
- assert(ts->val_type == TEMP_VAL_REG);
+ tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
/* the mov can be suppressed */
if (ots->val_type == TEMP_VAL_REG) {
@@ -2283,7 +2283,7 @@
arg = args[i];
ts = &s->temps[arg];
reg = tcg_target_call_oarg_regs[i];
- assert(s->reg_to_temp[reg] == NULL);
+ tcg_debug_assert(s->reg_to_temp[reg] == NULL);
if (ts->fixed_reg) {
if (ts->reg != reg) {