diff options
author | sandra <sandra@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-07-05 17:08:37 +0000 |
---|---|---|
committer | sandra <sandra@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-07-05 17:08:37 +0000 |
commit | 122a697832d3f4ee948f12fd2676840cdbb37a9b (patch) | |
tree | 412155942760389b80c2e11cd433bae27b0a1df4 /gcc/optabs.c | |
parent | 81e6afc2ae19f1ae98d1bad1f2ed79f583325b3c (diff) | |
download | gcc-122a697832d3f4ee948f12fd2676840cdbb37a9b.tar.gz |
2007-07-05 Sandra Loosemore <sandra@codesourcery.com>
David Ung <davidu@mips.com>
Add support for SmartMIPS ASE.
gcc/
* optabs.c (expand_binop_directly): New, broken out from...
(expand_binop): Here. Make it try rotating in the other
direction even when the second operand isn't constant.
* config/mips/mips.md (*lwxs): New.
* config/mips/mips.opt (msmartmips): New.
* config/mips/mips.c (mips_lwxs_address_p): New.
(mips_rtx_costs): Make it recognize scaled indexed addressing.
* config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Define
__mips_smartmips when compiling for TARGET_SMARTMIPS.
(ISA_HAS_ROR): Define for TARGET_SMARTMIPS.
(ISA_HAS_LWXS): New.
(ASM_SPEC): Add -msmartmips/-mno-smartmips.
* doc/invoke.texi (MIPS Options): Document -msmartmips/-mno-smartmips.
* testsuite/gcc.target/mips/smartmips-lwxs.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-1.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-2.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-3.c: New test case.
* testsuite/gcc.target/mips/smartmips-ror-4.c: New test case.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126370 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 246 |
1 files changed, 136 insertions, 110 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index dd146da8b6d..c07cc06abd6 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -1246,6 +1246,113 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1) } +/* Helper function for expand_binop: handle the case where there + is an insn that directly implements the indicated operation. + Returns null if this is not possible. */ +static rtx +expand_binop_directly (enum machine_mode mode, optab binoptab, + rtx op0, rtx op1, + rtx target, int unsignedp, enum optab_methods methods, + int commutative_op, rtx last) +{ + int icode = (int) binoptab->handlers[(int) mode].insn_code; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; + enum machine_mode mode1 = insn_data[icode].operand[2].mode; + enum machine_mode tmp_mode; + rtx pat; + rtx xop0 = op0, xop1 = op1; + rtx temp; + + if (target) + temp = target; + else + temp = gen_reg_rtx (mode); + + /* If it is a commutative operator and the modes would match + if we would swap the operands, we can save the conversions. */ + if (commutative_op) + { + if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 + && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) + { + rtx tmp; + + tmp = op0; op0 = op1; op1 = tmp; + tmp = xop0; xop0 = xop1; xop1 = tmp; + } + } + + /* In case the insn wants input operands in modes different from + those of the actual operands, convert the operands. It would + seem that we don't need to convert CONST_INTs, but we do, so + that they're properly zero-extended, sign-extended or truncated + for their mode. */ + + if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) + xop0 = convert_modes (mode0, + GET_MODE (op0) != VOIDmode + ? GET_MODE (op0) + : mode, + xop0, unsignedp); + + if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) + xop1 = convert_modes (mode1, + GET_MODE (op1) != VOIDmode + ? GET_MODE (op1) + : mode, + xop1, unsignedp); + + /* Now, if insn's predicates don't allow our operands, put them into + pseudo regs. */ + + if (!insn_data[icode].operand[1].predicate (xop0, mode0) + && mode0 != VOIDmode) + xop0 = copy_to_mode_reg (mode0, xop0); + + if (!insn_data[icode].operand[2].predicate (xop1, mode1) + && mode1 != VOIDmode) + xop1 = copy_to_mode_reg (mode1, xop1); + + if (binoptab == vec_pack_trunc_optab + || binoptab == vec_pack_usat_optab + || binoptab == vec_pack_ssat_optab + || binoptab == vec_pack_ufix_trunc_optab + || binoptab == vec_pack_sfix_trunc_optab) + { + /* The mode of the result is different then the mode of the + arguments. */ + tmp_mode = insn_data[icode].operand[0].mode; + if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode)) + return 0; + } + else + tmp_mode = mode; + + if (!insn_data[icode].operand[0].predicate (temp, tmp_mode)) + temp = gen_reg_rtx (tmp_mode); + + pat = GEN_FCN (icode) (temp, xop0, xop1); + if (pat) + { + /* If PAT is composed of more than one insn, try to add an appropriate + REG_EQUAL note to it. If we can't because TEMP conflicts with an + operand, call expand_binop again, this time without a target. */ + if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX + && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) + { + delete_insns_since (last); + return expand_binop (mode, binoptab, op0, op1, NULL_RTX, + unsignedp, methods); + } + + emit_insn (pat); + return temp; + } + + delete_insns_since (last); + return NULL_RTX; +} + /* Generate code to perform an operation specified by BINOPTAB on operands OP0 and OP1, with result having machine-mode MODE. @@ -1275,7 +1382,6 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, || binoptab->code == ROTATERT); rtx entry_last = get_last_insn (); rtx last; - bool first_pass_p = true; class = GET_MODE_CLASS (mode); @@ -1329,123 +1435,43 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, } } - retry: - /* If we can do it with a three-operand insn, do so. */ if (methods != OPTAB_MUST_WIDEN && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) { - int icode = (int) binoptab->handlers[(int) mode].insn_code; - enum machine_mode mode0 = insn_data[icode].operand[1].mode; - enum machine_mode mode1 = insn_data[icode].operand[2].mode; - enum machine_mode tmp_mode; - rtx pat; - rtx xop0 = op0, xop1 = op1; - - if (target) - temp = target; - else - temp = gen_reg_rtx (mode); - - /* If it is a commutative operator and the modes would match - if we would swap the operands, we can save the conversions. */ - if (commutative_op) - { - if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 - && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) - { - rtx tmp; - - tmp = op0; op0 = op1; op1 = tmp; - tmp = xop0; xop0 = xop1; xop1 = tmp; - } - } - - /* In case the insn wants input operands in modes different from - those of the actual operands, convert the operands. It would - seem that we don't need to convert CONST_INTs, but we do, so - that they're properly zero-extended, sign-extended or truncated - for their mode. */ - - if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) - xop0 = convert_modes (mode0, - GET_MODE (op0) != VOIDmode - ? GET_MODE (op0) - : mode, - xop0, unsignedp); - - if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) - xop1 = convert_modes (mode1, - GET_MODE (op1) != VOIDmode - ? GET_MODE (op1) - : mode, - xop1, unsignedp); - - /* Now, if insn's predicates don't allow our operands, put them into - pseudo regs. */ - - if (!insn_data[icode].operand[1].predicate (xop0, mode0) - && mode0 != VOIDmode) - xop0 = copy_to_mode_reg (mode0, xop0); - - if (!insn_data[icode].operand[2].predicate (xop1, mode1) - && mode1 != VOIDmode) - xop1 = copy_to_mode_reg (mode1, xop1); - - if (binoptab == vec_pack_trunc_optab - || binoptab == vec_pack_usat_optab - || binoptab == vec_pack_ssat_optab - || binoptab == vec_pack_ufix_trunc_optab - || binoptab == vec_pack_sfix_trunc_optab) - { - /* The mode of the result is different then the mode of the - arguments. */ - tmp_mode = insn_data[icode].operand[0].mode; - if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode)) - return 0; - } - else - tmp_mode = mode; - - if (!insn_data[icode].operand[0].predicate (temp, tmp_mode)) - temp = gen_reg_rtx (tmp_mode); - - pat = GEN_FCN (icode) (temp, xop0, xop1); - if (pat) - { - /* If PAT is composed of more than one insn, try to add an appropriate - REG_EQUAL note to it. If we can't because TEMP conflicts with an - operand, call ourselves again, this time without a target. */ - if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX - && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) - { - delete_insns_since (last); - return expand_binop (mode, binoptab, op0, op1, NULL_RTX, - unsignedp, methods); - } - - emit_insn (pat); - return temp; - } - else - delete_insns_since (last); + temp = expand_binop_directly (mode, binoptab, op0, op1, target, + unsignedp, methods, commutative_op, last); + if (temp) + return temp; } - /* If we were trying to rotate by a constant value, and that didn't - work, try rotating the other direction before falling back to - shifts and bitwise-or. */ - if (first_pass_p - && (binoptab == rotl_optab || binoptab == rotr_optab) - && class == MODE_INT - && GET_CODE (op1) == CONST_INT - && INTVAL (op1) > 0 - && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode)) + /* If we were trying to rotate, and that didn't work, try rotating + the other direction before falling back to shifts and bitwise-or. */ + if (((binoptab == rotl_optab + && rotr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + || (binoptab == rotr_optab + && rotl_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)) + && class == MODE_INT) { - first_pass_p = false; - op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1)); - binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab; - goto retry; + optab otheroptab = (binoptab == rotl_optab ? rotr_optab : rotl_optab); + rtx newop1; + int bits = GET_MODE_BITSIZE (mode); + + if (GET_CODE (op1) == CONST_INT) + newop1 = GEN_INT (bits - INTVAL (op1)); + else if (targetm.shift_truncation_mask (mode) == bits - 1) + newop1 = negate_rtx (mode, op1); + else + newop1 = expand_binop (mode, sub_optab, + GEN_INT (bits), op1, + NULL_RTX, unsignedp, OPTAB_DIRECT); + + temp = expand_binop_directly (mode, otheroptab, op0, newop1, + target, unsignedp, methods, + commutative_op, last); + if (temp) + return temp; } /* If this is a multiply, see if we can do a widening operation that |