This is the mail archive of the
`gcc-patches@gcc.gnu.org`
mailing list for the GCC project.

Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|

Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |

Other format: | [Raw text] |

*From*: Roger Sayle <roger at eyesopen dot com>*To*: gcc-patches at gcc dot gnu dot org*Cc*: Falk Hueffner <falk dot hueffner at student dot uni-tuebingen dot de>*Date*: Wed, 24 Sep 2003 09:54:11 -0600 (MDT)*Subject*: [PATCH] PR opt/12260: Avoid (const (neg (const (plus X Y))))

The following patch is my proposed fix for PR optimization/12260 which is an ICE on legal compiling the attached testcase on alpha. I believe the fundamental problem, which this patch doesn't attempt to address is that the semantics of the RTL operator CONST, i.e. which expressions it is allowed to wrap, are insufficiently documented. Ultimately, alpha.md tries to call output_addr_const on the RTX (const:DI (neg:DI (const:DI (plus:DI (symbol_ref ...) (const_int ...))))) Unfortunately, output_addr_const can't handle NEG expressions [the assembler syntax would require parentheses] and so we abort. I'd like to assume the fault is in the alpha back-end somewhere for assuming that just because an expression matches CONSTANT_P that it is valid as an operand in assembler. Failing that it is fault of fold_rtx for calling gen_rtx_CONST to wrap arbitrary unary operations on line 3606. Perhaps the reviewer could cast an opinion either way. My contribution is to bypass the above issue altogether to resolve this failure by improving our RTL simplification routines so that we never create anything as hideous as (const (neg (const (plus X Y)))). Firstly, for any unary operator (op (const (foo))) should x-ray through the const and try to simplify "(op (foo))". Then in addition to our current "normalization" (neg (plus X Y)) -> (minus (neg X) Y), which doesn't automatically reduce operation count, i.e add the optimization that (neg (plus X C)) -> (minus -C X) for integer/real constants C, and then for good measure (minus (neg X) C) -> (minus -C X). Then finally, I discovered that simplify_plus_minus, we currently prefer the first form with more operations than the second! A quick tweak here avoids undoing all of our good work to improve code. For our testcase (taken from the bugzilla PR), our expression now becomes (const:DI (minus (const_int ...) (symbol_ref ...))) which is both far less ugly, but also happily handled by output_addr_const. There's more that can be done optimization wise, at one point we have: (insn 32 31 33 2 (set (reg:DI 77) (minus:DI (reg:DI 78) (reg:DI 85))) 22 {subdi3} (nil) (expr_list:REG_EQUAL (minus:DI (const_int 1 [0x1]) (symbol_ref:DI ("buf") [flags 0x2] <var_decl 0x4024db54 buf>)) (nil))) (insn 33 32 34 2 (set (reg:DI 79) (plus:DI (reg:DI 77) (reg:DI 85))) 7 {*adddi_internal} (nil) (expr_list:REG_EQUAL (plus:DI (reg:DI 77) (symbol_ref:DI ("buf") [flags 0x2] <var_decl 0x4024db54 buf>)) (nil))) Where clearly the expression (1-buf)+buf should simplify to just 1. Unfortunately, we ignore REG_EQUAL notes in local_cprop, and then the loop optimizers ruin everything by hoisting the first insn out of the loop but not the second. A craftsman's work is never done! The following patch has been tested on i686-pc-linux-gnu with a complete "make bootstrap", all languages except treelang, and regression tested with a top-level "make -k check" with no new failures. I've also confirmed that it fixes the ICE in the new gcc.c-torture/compile testcase in a cross-compiler gcc to alphaev68-unknown-linux-gnu hosted on the same system. Ok for mainline? 2003-09-24 Roger Sayle <roger@eyesopen.com> PR optimization/12260 * simplify-rtx.c (simplify_unary_operation): Simplify all unary operations through CONST nodes. Optimize (neg (plus X C)) as (minus -C X) for constant values C. (simplify_binary_operation): Optimize (minus (neg X) C) as (minus -C X) for constant values C. (simplify_plus_minus): Avoid creating (neg (const (plus X C)), instead create (minus -C X). * gcc.c-torture/compile/20030924-1.c: New test case. Index: simplify-rtx.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v retrieving revision 1.160 diff -c -3 -p -r1.160 simplify-rtx.c *** simplify-rtx.c 18 Sep 2003 19:07:04 -0000 1.160 --- simplify-rtx.c 24 Sep 2003 11:34:12 -0000 *************** simplify_unary_operation (enum rtx_code *** 407,412 **** --- 407,414 ---- return gen_rtx_CONST_VECTOR (mode, v); } } + else if (GET_CODE (op) == CONST) + return simplify_unary_operation (code, mode, XEXP (op, 0), op_mode); if (VECTOR_MODE_P (mode) && GET_CODE (trueop) == CONST_VECTOR) { *************** simplify_unary_operation (enum rtx_code *** 891,901 **** return simplify_gen_binary (MINUS, mode, XEXP (op, 1), XEXP (op, 0)); - /* (neg (plus A B)) is canonicalized to (minus (neg A) B). */ if (GET_CODE (op) == PLUS && !HONOR_SIGNED_ZEROS (mode) && !HONOR_SIGN_DEPENDENT_ROUNDING (mode)) { temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode); return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1)); } --- 893,914 ---- return simplify_gen_binary (MINUS, mode, XEXP (op, 1), XEXP (op, 0)); if (GET_CODE (op) == PLUS && !HONOR_SIGNED_ZEROS (mode) && !HONOR_SIGN_DEPENDENT_ROUNDING (mode)) { + /* (neg (plus A C)) is simplified to (minus -C A). */ + if (GET_CODE (XEXP (op, 1)) == CONST_INT + || GET_CODE (XEXP (op, 1)) == CONST_DOUBLE) + { + temp = simplify_unary_operation (NEG, mode, XEXP (op, 1), + mode); + if (temp) + return simplify_gen_binary (MINUS, mode, temp, + XEXP (op, 0)); + } + + /* (neg (plus A B)) is canonicalized to (minus (neg A) B). */ temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode); return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1)); } *************** simplify_binary_operation (enum rtx_code *** 1492,1497 **** --- 1505,1520 ---- if (GET_CODE (op1) == NEG) return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0)); + /* (-x - c) may be simplified as (-c - x). */ + if (GET_CODE (op0) == NEG + && (GET_CODE (op1) == CONST_INT + || GET_CODE (op1) == CONST_DOUBLE)) + { + tem = simplify_unary_operation (NEG, mode, op1, mode); + if (tem) + return simplify_gen_binary (MINUS, mode, tem, XEXP (op0, 0)); + } + /* If one of the operands is a PLUS or a MINUS, see if we can simplify this by the associative law. Don't use the associative law for floating point. *************** simplify_plus_minus (enum rtx_code code, *** 2295,2300 **** --- 2318,2330 ---- /* Sort the operations based on swap_commutative_operands_p. */ qsort (ops, n_ops, sizeof (*ops), simplify_plus_minus_op_data_cmp); + /* Create (minus -C X) instead of (neg (const (plus X C))). */ + if (n_ops == 2 + && GET_CODE (ops[1].op) == CONST_INT + && CONSTANT_P (ops[0].op) + && ops[0].neg) + return gen_rtx_fmt_ee (MINUS, mode, ops[1].op, ops[0].op); + /* We suppressed creation of trivial CONST expressions in the combination loop to avoid recursion. Create one manually now. The combination loop should have ensured that there is exactly /* PR optimization/12260. */ extern int f(void); extern int g(int); static char buf[512]; void h(int l) { while (l) { char *op = buf; if (f() == 0) break; if (g(op - buf + 1)) break; } } Roger -- Roger Sayle, E-mail: roger@eyesopen.com OpenEye Scientific Software, WWW: http://www.eyesopen.com/ Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385 Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833

Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|

Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |