From patchwork Thu Sep 27 17:15:07 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 187442 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 14DF82C00A8 for ; Fri, 28 Sep 2012 04:23:38 +1000 (EST) Received: from localhost ([::1]:36060 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THHht-0000x2-Qb for incoming@patchwork.ozlabs.org; Thu, 27 Sep 2012 13:17:01 -0400 Received: from eggs.gnu.org ([208.118.235.92]:56286) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THHgx-00073g-OW for qemu-devel@nongnu.org; Thu, 27 Sep 2012 13:16:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1THHgw-00024f-0f for qemu-devel@nongnu.org; Thu, 27 Sep 2012 13:16:03 -0400 Received: from hall.aurel32.net ([88.191.126.93]:41366) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THHgv-00023P-Nk for qemu-devel@nongnu.org; Thu, 27 Sep 2012 13:16:01 -0400 Received: from [37.160.60.195] (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 1THHgu-00056k-Bx; Thu, 27 Sep 2012 19:16:01 +0200 Received: from aurel32 by ohm.aurel32.net with local (Exim 4.80) (envelope-from ) id 1THHgC-0004pf-9c; Thu, 27 Sep 2012 19:15:16 +0200 From: Aurelien Jarno To: qemu-devel@nongnu.org Date: Thu, 27 Sep 2012 19:15:07 +0200 Message-Id: <1348766113-18373-8-git-send-email-aurelien@aurel32.net> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1348766113-18373-1-git-send-email-aurelien@aurel32.net> References: <1348766113-18373-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 07/13] tcg: rewrite tcg_reg_alloc_mov() 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 Now that the liveness analysis provides more information, rewrite tcg_reg_alloc_mov(). This changes the behaviour about propagating constants and memory accesses. We now take the assumption that once a value is loaded into a register (from memory or from a constant), it's better to keep it there than to reload it later. This assumption is now always almost correct given that we are now sure the corresponding temp is going to be used later (otherwise it would have been synchronized and marked as dead already). The assumption is wrong if one of the op after clobbers some registers including the one of the holding the temp (this can be avoided by allocating clobbered registers last, which is what most TCG target do), or in case of lack of available register. Signed-off-by: Aurelien Jarno --- tcg/tcg.c | 105 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index bfe6411..5fb4901 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1667,64 +1667,85 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, const TCGArg *args, uint16_t dead_args, uint8_t sync_args) { + TCGRegSet allocated_regs; TCGTemp *ts, *ots; - int reg; - const TCGArgConstraint *arg_ct; + const TCGArgConstraint *arg_ct, *oarg_ct; + tcg_regset_set(allocated_regs, s->reserved_regs); ots = &s->temps[args[0]]; ts = &s->temps[args[1]]; - arg_ct = &def->args_ct[0]; + oarg_ct = &def->args_ct[0]; + arg_ct = &def->args_ct[1]; + + /* We have to load the value in a register for moving it to another + or for saving it. We assume it's better to keep it there than to + reload it later. */ + if ((NEED_SYNC_ARG(0) && ts->val_type != TEMP_VAL_REG) + || ts->val_type == TEMP_VAL_MEM) { + ts->reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + if (ts->val_type == TEMP_VAL_MEM) { + tcg_out_ld(s, ts->type, ts->reg, ts->mem_reg, ts->mem_offset); + } else if (ts->val_type == TEMP_VAL_CONST) { + tcg_out_movi(s, ts->type, ts->reg, ts->val); + } + s->reg_to_temp[ts->reg] = args[1]; + ts->val_type = TEMP_VAL_REG; + ts->mem_coherent = 1; + } - /* XXX: always mark arg dead if IS_DEAD_ARG(1) */ - if (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) - s->reg_to_temp[ots->reg] = -1; - reg = ts->reg; - temp_dead(s, args[1]); - } else { - if (ots->val_type == TEMP_VAL_REG) { - reg = ots->reg; - } else { - reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); - } - if (ts->reg != reg) { - tcg_out_mov(s, ots->type, reg, ts->reg); - } + 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)); + /* The code above should have moved the temp to a register. */ + assert(ts->val_type == TEMP_VAL_REG); + if (!ots->mem_allocated) { + temp_allocate_frame(s, args[0]); } - } else if (ts->val_type == TEMP_VAL_MEM) { - if (ots->val_type == TEMP_VAL_REG) { - reg = ots->reg; - } else { - reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + if (ts->val_type == TEMP_VAL_REG) { + tcg_out_st(s, ots->type, ts->reg, ots->mem_reg, ots->mem_offset); + if (IS_DEAD_ARG(1)) { + temp_dead(s, args[1]); + } } - tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + temp_dead(s, args[0]); } else if (ts->val_type == TEMP_VAL_CONST) { if (ots->fixed_reg) { - reg = ots->reg; - tcg_out_movi(s, ots->type, reg, ts->val); + tcg_out_movi(s, ots->type, ots->reg, ts->val); + s->reg_to_temp[ots->reg] = args[0]; } else { /* propagate constant */ - if (ots->val_type == TEMP_VAL_REG) + if (ots->val_type == TEMP_VAL_REG) { s->reg_to_temp[ots->reg] = -1; + } ots->val_type = TEMP_VAL_CONST; ots->val = ts->val; - if (NEED_SYNC_ARG(0)) { - temp_sync(s, args[0], s->reserved_regs); - } - return; } } else { - tcg_abort(); - } - s->reg_to_temp[reg] = args[0]; - ots->reg = reg; - ots->val_type = TEMP_VAL_REG; - ots->mem_coherent = 0; - - if (NEED_SYNC_ARG(0)) { - tcg_reg_sync(s, reg); + /* The code above should have moved the temp to a register. */ + 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) { + s->reg_to_temp[ots->reg] = -1; + } + ots->reg = ts->reg; + temp_dead(s, args[1]); + } else { + if (ots->val_type != TEMP_VAL_REG) { + /* When allocating a new register, make sure to not spill the + input one. */ + tcg_regset_set_reg(allocated_regs, ts->reg); + ots->reg = tcg_reg_alloc(s, oarg_ct->u.regs, allocated_regs); + } + tcg_out_mov(s, ots->type, ots->reg, ts->reg); + } + ots->val_type = TEMP_VAL_REG; + ots->mem_coherent = 0; + s->reg_to_temp[ots->reg] = args[0]; + if (NEED_SYNC_ARG(0)) { + tcg_reg_sync(s, ots->reg); + } } }