From patchwork Thu Mar 31 10:19:57 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 860 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:46:32 -0000 Delivered-To: patches@linaro.org Received: by 10.42.161.68 with SMTP id s4cs121308icx; Thu, 31 Mar 2011 03:20:02 -0700 (PDT) Received: by 10.227.147.196 with SMTP id m4mr2523059wbv.179.1301566801423; Thu, 31 Mar 2011 03:20:01 -0700 (PDT) Received: from mail-wy0-f178.google.com (mail-wy0-f178.google.com [74.125.82.178]) by mx.google.com with ESMTPS id gb6si2145720wbb.32.2011.03.31.03.20.01 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 31 Mar 2011 03:20:01 -0700 (PDT) Received-SPF: neutral (google.com: 74.125.82.178 is neither permitted nor denied by best guess record for domain of richard.sandiford@linaro.org) client-ip=74.125.82.178; Authentication-Results: mx.google.com; spf=neutral (google.com: 74.125.82.178 is neither permitted nor denied by best guess record for domain of richard.sandiford@linaro.org) smtp.mail=richard.sandiford@linaro.org Received: by wyb33 with SMTP id 33so2234211wyb.37 for ; Thu, 31 Mar 2011 03:20:00 -0700 (PDT) Received: by 10.227.139.14 with SMTP id c14mr2545173wbu.55.1301566800768; Thu, 31 Mar 2011 03:20:00 -0700 (PDT) Received: from richards-thinkpad (gbibp9ph1--blueice2n1.emea.ibm.com [195.212.29.75]) by mx.google.com with ESMTPS id o6sm561628wbo.3.2011.03.31.03.19.58 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 31 Mar 2011 03:19:59 -0700 (PDT) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, patches@linaro.org, richard.sandiford@linaro.org Cc: patches@linaro.org Subject: Try simplifying memory operands during optabs expansion Date: Thu, 31 Mar 2011 11:19:57 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 This is the main change that motivated the less-than-successful optabs interface "cleanup". Tree expansion yields MEMs that are legitimiate memory_operands, but it's not uncommon for some optabs to need a more restricted type of address. This patch records whether operands can be memories, and makes maybe_legitimize_operand try to simplify memory addresses if the original MEM doesn't match. allows_mem is really a property of the predicate, rather than the operand itself, so in some ways it might be cleaner to have a "predicate" type that contains the function and some information about it. However, that seems like overkill here, and would just mean more pointer chasing. allows_mem sits neatly in an unused part of the existing operand structure, and these chars could be converted to bitfields if more flags were added in future. A quick search revealed one potential use in h8300.md: (define_expand "movstr" [(use (match_operand 0 "register_operand" "")) (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:BLK 2 "memory_operand" ""))] "TARGET_H8300SX" { operands[1] = replace_equiv_address (operands[1], copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); operands[2] = replace_equiv_address (operands[2], copy_to_mode_reg (Pmode, XEXP (operands[2], 0))); emit_insn (gen_movsd (operands[1], operands[2], gen_reg_rtx (Pmode))); emit_insn (gen_add3_insn (operands[0], XEXP (operands[1], 0), constm1_rtx)); DONE; }) x86's cmpstrnsi and pa's movmemsi might be candidates too. There's a port in the works where this occurs much more often, but my personal motivation was that, if the ARM's load/store-lane instructions were exposed as optabs, they too would need this handling. Tested on arm-linux-gnueabi with the WIP ARM optabs changes. OK to install? Richard gcc/ * recog.h (insn_operand_data): Add an "allows_mem" field. * genoutput.c (output_operand_data): Initialize it. * optabs.c (maybe_legitimize_operand_same_code): New function. (maybe_legitimize_operand): Use it when matching the original op->value. Index: gcc/recog.h =================================================================== --- gcc/recog.h 2011-03-31 10:57:29.000000000 +0100 +++ gcc/recog.h 2011-03-31 11:01:19.000000000 +0100 @@ -272,6 +272,8 @@ struct insn_operand_data const char is_operator; const char eliminable; + + const char allows_mem; }; /* Legal values for insn_data.output_format. Indicate what type of data Index: gcc/genoutput.c =================================================================== --- gcc/genoutput.c 2011-03-31 10:57:29.000000000 +0100 +++ gcc/genoutput.c 2011-03-31 11:01:19.000000000 +0100 @@ -66,6 +66,8 @@ Software Foundation; either version 3, o MATCH_OPERAND; it is zero for operands that should not be changed during register elimination such as MATCH_OPERATORs. + g. `allows_mem', is true for operands that accept MEM rtxes. + The code number of an insn is simply its position in the machine description; code numbers are assigned sequentially to entries in the description, starting with code number 0. @@ -255,6 +257,8 @@ output_operand_data (void) for (d = odata; d; d = d->next) { + struct pred_data *pred; + printf (" {\n"); printf (" %s,\n", @@ -268,7 +272,12 @@ output_operand_data (void) printf (" %d,\n", d->constraint == NULL ? 1 : 0); - printf (" %d\n", d->eliminable); + printf (" %d,\n", d->eliminable); + + pred = NULL; + if (d->predicate) + pred = lookup_predicate (d->predicate); + printf (" %d\n", pred && pred->codes[MEM]); printf(" },\n"); } Index: gcc/optabs.c =================================================================== --- gcc/optabs.c 2011-03-31 10:57:29.000000000 +0100 +++ gcc/optabs.c 2011-03-31 11:01:19.000000000 +0100 @@ -7001,6 +7001,36 @@ insn_operand_matches (enum insn_code ico (operand, insn_data[(int) icode].operand[opno].mode))); } +/* Like maybe_legitimize_operand, but do not change the code of the + current rtx value. */ + +static bool +maybe_legitimize_operand_same_code (enum insn_code icode, unsigned int opno, + struct expand_operand *op) +{ + /* See if the operand matches in its current form. */ + if (insn_operand_matches (icode, opno, op->value)) + return true; + + /* If the operand is a memory, try forcing the address into a register. */ + if (MEM_P (op->value) && insn_data[(int) icode].operand[opno].allows_mem) + { + rtx addr, mem, last; + + last = get_last_insn (); + addr = force_reg (Pmode, XEXP (op->value, 0)); + mem = replace_equiv_address (op->value, addr); + if (insn_operand_matches (icode, opno, mem)) + { + op->value = mem; + return true; + } + delete_insns_since (last); + } + + return false; +} + /* Try to make OP match operand OPNO of instruction ICODE. Return true on success, storing the new operand value back in OP. */ @@ -7013,31 +7043,35 @@ maybe_legitimize_operand (enum insn_code old_volatile_ok = volatile_ok; mode = op->mode; - result = false; switch (op->type) { case EXPAND_FIXED: volatile_ok = true; - break; + result = maybe_legitimize_operand_same_code (icode, opno, op); + volatile_ok = old_volatile_ok; + return result; case EXPAND_OUTPUT: gcc_assert (mode != VOIDmode); - if (!op->value - || op->value == const0_rtx - || GET_MODE (op->value) != mode - || !insn_operand_matches (icode, opno, op->value)) - op->value = gen_reg_rtx (mode); - break; + if (op->value + && op->value != const0_rtx + && GET_MODE (op->value) == mode + && maybe_legitimize_operand_same_code (icode, opno, op)) + return true; + + op->value = gen_reg_rtx (mode); + return insn_operand_matches (icode, opno, op->value); case EXPAND_INPUT: input: gcc_assert (mode != VOIDmode); gcc_assert (GET_MODE (op->value) == VOIDmode || GET_MODE (op->value) == mode); - result = insn_operand_matches (icode, opno, op->value); - if (!result) - op->value = copy_to_mode_reg (mode, op->value); - break; + if (maybe_legitimize_operand_same_code (icode, opno, op)) + return true; + + op->value = copy_to_mode_reg (mode, op->value); + return insn_operand_matches (icode, opno, op->value); case EXPAND_CONVERT_TO: gcc_assert (mode != VOIDmode); @@ -7068,12 +7102,9 @@ maybe_legitimize_operand (enum insn_code mode = insn_data[(int) icode].operand[opno].mode; if (mode != VOIDmode && const_int_operand (op->value, mode)) goto input; - break; + return insn_operand_matches (icode, opno, op->value); } - if (!result) - result = insn_operand_matches (icode, opno, op->value); - volatile_ok = old_volatile_ok; - return result; + gcc_unreachable (); } /* Make OP describe an input operand that should have the same value