From patchwork Tue Oct 9 19:56:03 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 190436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 845862C00A8 for ; Wed, 10 Oct 2012 07:32:15 +1100 (EST) Received: from localhost ([::1]:47773 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLfw7-0001oW-T0 for incoming@patchwork.ozlabs.org; Tue, 09 Oct 2012 15:57:51 -0400 Received: from eggs.gnu.org ([208.118.235.92]:39454) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLfus-0008Cy-DH for qemu-devel@nongnu.org; Tue, 09 Oct 2012 15:56:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TLfuo-0004XQ-Je for qemu-devel@nongnu.org; Tue, 09 Oct 2012 15:56:34 -0400 Received: from hall.aurel32.net ([88.191.126.93]:55989) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLfuo-0004Vg-91 for qemu-devel@nongnu.org; Tue, 09 Oct 2012 15:56:30 -0400 Received: from watt.aurel32.net ([82.228.202.134] helo=ohm.aurel32.net) by hall.aurel32.net with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.72) (envelope-from ) id 1TLful-0005JU-Hp; Tue, 09 Oct 2012 21:56:28 +0200 Received: from aurel32 by ohm.aurel32.net with local (Exim 4.80) (envelope-from ) id 1TLfuj-00059R-IE; Tue, 09 Oct 2012 21:56:25 +0200 From: Aurelien Jarno To: qemu-devel@nongnu.org Date: Tue, 9 Oct 2012 21:56:03 +0200 Message-Id: <1349812584-19551-6-git-send-email-aurelien@aurel32.net> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1349812584-19551-1-git-send-email-aurelien@aurel32.net> References: <1349812584-19551-1-git-send-email-aurelien@aurel32.net> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 88.191.126.93 Cc: Aurelien Jarno Subject: [Qemu-devel] [PATCH v2 05/26] tcg: rework liveness analysis X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Rework the liveness analysis by tracking temps that need to go back to memory in addition to dead temps tracking. This allows to mark output arguments as "need sync", and to synchronize them back to memory as soon as they are not written anymore. This way even arguments mapping to globals can be marked as "dead", avoiding moves to a new register when input and outputs are aliased. In addition it means that registers are freed as soon as temps are not used anymore, instead of waiting for a basic block end or an op with side effects. This reduces register spilling especially on CPUs with few registers, and spread the mov over all the TB, increasing the performances on in-order CPUs. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/tcg.c | 64 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 76cca27..400581f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1184,31 +1184,27 @@ static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, } } -/* liveness analysis: end of function: globals are live, temps are - dead. */ -/* XXX: at this stage, not used as there would be little gains because - most TBs end with a conditional jump. */ -static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) +/* liveness analysis: end of function: all temps are dead, and globals + should be in memory. */ +static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps, + uint8_t *mem_temps) { - memset(dead_temps, 0, s->nb_globals); - memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); + memset(dead_temps, 1, s->nb_temps); + memset(mem_temps, 1, s->nb_globals); + memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals); } -/* liveness analysis: end of basic block: globals are live, temps are - dead, local temps are live. */ -static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) +/* liveness analysis: end of basic block: all temps are dead, globals + and local temps should be in memory. */ +static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, + uint8_t *mem_temps) { int i; - TCGTemp *ts; - memset(dead_temps, 0, s->nb_globals); - ts = &s->temps[s->nb_globals]; + memset(dead_temps, 1, s->nb_temps); + memset(mem_temps, 1, s->nb_globals); for(i = s->nb_globals; i < s->nb_temps; i++) { - if (ts->temp_local) - dead_temps[i] = 0; - else - dead_temps[i] = 1; - ts++; + mem_temps[i] = s->temps[i].temp_local; } } @@ -1221,7 +1217,7 @@ static void tcg_liveness_analysis(TCGContext *s) TCGOpcode op; TCGArg *args; const TCGOpDef *def; - uint8_t *dead_temps; + uint8_t *dead_temps, *mem_temps; uint16_t dead_args; uint8_t sync_args; @@ -1233,7 +1229,8 @@ static void tcg_liveness_analysis(TCGContext *s) s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t)); dead_temps = tcg_malloc(s->nb_temps); - memset(dead_temps, 1, s->nb_temps); + mem_temps = tcg_malloc(s->nb_temps); + tcg_la_func_end(s, dead_temps, mem_temps); args = gen_opparam_ptr; op_index = nb_ops - 1; @@ -1257,8 +1254,9 @@ static void tcg_liveness_analysis(TCGContext *s) if (call_flags & TCG_CALL_PURE) { for(i = 0; i < nb_oargs; i++) { arg = args[i]; - if (!dead_temps[arg]) + if (!dead_temps[arg] || mem_temps[arg]) { goto do_not_remove_call; + } } tcg_set_nop(s, gen_opc_buf + op_index, args - 1, nb_args); @@ -1273,12 +1271,17 @@ static void tcg_liveness_analysis(TCGContext *s) if (dead_temps[arg]) { dead_args |= (1 << i); } + if (mem_temps[arg]) { + sync_args |= (1 << i); + } dead_temps[arg] = 1; + mem_temps[arg] = 0; } if (!(call_flags & TCG_CALL_CONST)) { - /* globals are live (they may be used by the call) */ - memset(dead_temps, 0, s->nb_globals); + /* globals should go back to memory */ + memset(dead_temps, 1, s->nb_globals); + memset(mem_temps, 1, s->nb_globals); } /* input args are live */ @@ -1308,6 +1311,7 @@ static void tcg_liveness_analysis(TCGContext *s) args--; /* mark the temporary as dead */ dead_temps[args[0]] = 1; + mem_temps[args[0]] = 0; break; case INDEX_op_end: break; @@ -1323,8 +1327,9 @@ static void tcg_liveness_analysis(TCGContext *s) if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { for(i = 0; i < nb_oargs; i++) { arg = args[i]; - if (!dead_temps[arg]) + if (!dead_temps[arg] || mem_temps[arg]) { goto do_not_remove; + } } tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); #ifdef CONFIG_PROFILER @@ -1341,15 +1346,20 @@ static void tcg_liveness_analysis(TCGContext *s) if (dead_temps[arg]) { dead_args |= (1 << i); } + if (mem_temps[arg]) { + sync_args |= (1 << i); + } dead_temps[arg] = 1; + mem_temps[arg] = 0; } /* if end of basic block, update */ if (def->flags & TCG_OPF_BB_END) { - tcg_la_bb_end(s, dead_temps); + tcg_la_bb_end(s, dead_temps, mem_temps); } else if (def->flags & TCG_OPF_CALL_CLOBBER) { - /* globals are live */ - memset(dead_temps, 0, s->nb_globals); + /* globals should go back to memory */ + memset(dead_temps, 1, s->nb_globals); + memset(mem_temps, 1, s->nb_globals); } /* input args are live */