While looking at some MIPS code I found that GCC was not making optimal use of the MIPS nor instruction. If you compile this function:
int f (int a, int b) { return ~(a|b); } It generates: or $2,$4,$5 nor $2,$0,$2 instead of just: nor $2,$4,$5 The problem is that mips_rtx_costs does not know that (AND (NOT op1) (NOT op2)) can be done in a single operation so it calculates the cost of the expression as the cost of 3 operations, this results in combine thinking that (NOT (OR op1 op2) is cheaper. This patch changes mips_rtx_costs to change the cost calculation of a nor to be the cost of one operation (plus the cost of getting the operands into registers) instead of the cost of three operations. Tested with no regressions, OK to checkin? Steve Ellcey sell...@mips.com 2013-10-22 Steve Ellcey <sell...@mips.com> * config/mips/mips.c (mips_rtx_costs): Fix cost estimate for nor (AND (NOT OP1) (NOT OP2)). 2013-10-22 Steve Ellcey <sell...@mips.com> * gcc.target/mips/nor.c: New. diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 5993aab..ffb0b53 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -3796,6 +3796,18 @@ mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, return true; } } + /* (AND (NOT op0) (NOT op1) is a nor operation that can be done in + a single instruction. */ + if (!TARGET_MIPS16 && (GET_CODE (XEXP (x, 0)) == NOT) + && (GET_CODE (XEXP (x, 1)) == NOT)) + { + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + cost = GET_MODE_SIZE (mode) > UNITS_PER_WORD ? 2 : 1; + *total = COSTS_N_INSNS (cost) + set_src_cost (XEXP (op0, 0), speed) + + rtx_cost (XEXP (op1, 0), GET_CODE (op1), 1, speed); + return true; + } /* Fall through. */ diff --git a/gcc/testsuite/gcc.target/mips/nor.c b/gcc/testsuite/gcc.target/mips/nor.c new file mode 100644 index 0000000..e71791b --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/nor.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ +/* { dg-final { scan-assembler-times "\tnor\t" 1 } } */ +/* { dg-final { scan-assembler-not "\tor" } } */ + +/* Test that we generate a 'nor' instruction and no 'or' instructions. */ + +NOMIPS16 int f (int a, int b) +{ + return ~(a|b); +}