From patchwork Tue Oct 9 19:56:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 190440 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 2471E2C0096 for ; Wed, 10 Oct 2012 07:42:18 +1100 (EST) Received: from localhost ([::1]:46503 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLfvV-00017z-VM for incoming@patchwork.ozlabs.org; Tue, 09 Oct 2012 15:57:13 -0400 Received: from eggs.gnu.org ([208.118.235.92]:39513) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLfuu-0008HQ-WD for qemu-devel@nongnu.org; Tue, 09 Oct 2012 15:56:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TLfuo-0004XM-JO for qemu-devel@nongnu.org; Tue, 09 Oct 2012 15:56:36 -0400 Received: from hall.aurel32.net ([88.191.126.93]:55988) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLfuo-0004Ve-9G 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-0005JW-Hw; Tue, 09 Oct 2012 21:56:28 +0200 Received: from aurel32 by ohm.aurel32.net with local (Exim 4.80) (envelope-from ) id 1TLfuj-00059b-LB; Tue, 09 Oct 2012 21:56:25 +0200 From: Aurelien Jarno To: qemu-devel@nongnu.org Date: Tue, 9 Oct 2012 21:56:05 +0200 Message-Id: <1349812584-19551-8-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 07/26] 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 Reviewed-by: Richard Henderson --- tcg/tcg.c | 108 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 328df56..e320022 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1667,64 +1667,80 @@ 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]; + + /* If the source value is not in a register, and we're going to be + forced to have it in a register in order to perform the copy, + then copy the SOURCE value into its own register first. That way + we don't have to reload SOURCE the next time it is used. */ + if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && 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); + ts->mem_coherent = 1; + } 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; + } - /* 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; + 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]); + } + tcg_out_st(s, ots->type, ts->reg, ots->mem_reg, ots->mem_offset); + if (IS_DEAD_ARG(1)) { 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); - } } - } else if (ts->val_type == TEMP_VAL_MEM) { + temp_dead(s, args[0]); + } else if (ts->val_type == TEMP_VAL_CONST) { + /* propagate constant */ if (ots->val_type == TEMP_VAL_REG) { - reg = ots->reg; - } else { - reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + s->reg_to_temp[ots->reg] = -1; } - tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); - } else if (ts->val_type == TEMP_VAL_CONST) { - if (ots->fixed_reg) { - reg = ots->reg; - tcg_out_movi(s, ots->type, reg, ts->val); + ots->val_type = TEMP_VAL_CONST; + ots->val = ts->val; + } else { + /* The code in the first if block 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 { - /* propagate constant */ - 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); + 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); } - return; + 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); } - } 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); } }