Richard Sandiford <rdsandif...@googlemail.com> wrote: >PR 58079 is about the do_SUBST assert: > > /* Sanity check that we're replacing oldval with a CONST_INT > that is a valid sign-extension for the original mode. */ > gcc_assert (INTVAL (newval) > == trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval))); > >triggering while trying to optimise the temporary result: > > (eq (const_int -73 [0xffffffffffffffb7]) > (reg:QI 234 [ MEM[(const u8 *)buf_7(D) + 4B] ]) > >combine_simplify_rtx calls simplify_comparison, which first >canonicalises >the order so that the constant is second and then promotes the >comparison >to SImode (the first supported comparison mode on MIPS). So we end up >with: > > (eq (zero_extend:SI (reg:QI 234 [ MEM[(const u8 *)buf_7(D) + 4B] ])) > (const_int 183 [0xb7])) > >So far so good. But combine_simplify_rtx then tries to install the >new operands in-place, with the second part of: > > /* If the code changed, return a whole new comparison. */ > if (new_code != code) > return gen_rtx_fmt_ee (new_code, mode, op0, op1); > > /* Otherwise, keep this operation, but maybe change its operands. > This also converts (ne (compare FOO BAR) 0) to (ne FOO BAR). */ > SUBST (XEXP (x, 0), op0); > SUBST (XEXP (x, 1), op1); > >And this triggers the assert because we're replacing a QImode register >with the non-QImode constant 183. > >One fix would be to extend the new_code != code condition, as below. >This should avoid the problem cases without generating too much >garbage rtl. But if the condition's getting this complicated, >perhaps it'd be better just to avoid SUBST here? I.e. > > if (new_code != code || op0 != XEXP (x, 0) || op1 != XEXP (x, 1)) > return gen_rtx_fmt_ee (new_code, mode, op0, op1); > >Just asking though. :-) > >Tested on mipsisa64-elf. OK to install?
Looks reasonable to me. Thus ok if nobody objects within 24h. Thanks, Richard. >Thanks, >Richard > > >gcc/ > PR rtl-optimization/58079 > * combine.c (combine_simplify_rtx): Avoid using SUBST if > simplify_comparison has widened a comparison with an integer. > >gcc/testsuite/ > * gcc.dg/torture/pr58079.c: New test. > >Index: gcc/combine.c >=================================================================== >--- gcc/combine.c 2013-08-06 22:03:32.644642305 +0100 >+++ gcc/combine.c 2013-08-06 22:08:51.944653901 +0100 >@@ -5803,8 +5803,15 @@ combine_simplify_rtx (rtx x, enum machin > return x; > } > >- /* If the code changed, return a whole new comparison. */ >- if (new_code != code) >+ /* If the code changed, return a whole new comparison. >+ We also need to avoid using SUBST in cases where >+ simplify_comparison has widened a comparison with a CONST_INT, >+ since in that case the wider CONST_INT may fail the sanity >+ checks in do_SUBST. */ >+ if (new_code != code >+ || (CONST_INT_P (op1) >+ && GET_MODE (op0) != GET_MODE (XEXP (x, 0)) >+ && GET_MODE (op0) != GET_MODE (XEXP (x, 1)))) > return gen_rtx_fmt_ee (new_code, mode, op0, op1); > > /* Otherwise, keep this operation, but maybe change its operands. >Index: gcc/testsuite/gcc.dg/torture/pr58079.c >=================================================================== >--- /dev/null 2013-07-23 18:41:43.074412242 +0100 >+++ gcc/testsuite/gcc.dg/torture/pr58079.c 2013-08-06 >22:05:06.249523398 +0100 >@@ -0,0 +1,107 @@ >+/* { dg-options "-mlong-calls" { target mips*-*-* } } */ >+ >+typedef unsigned char u8; >+typedef unsigned short u16; >+typedef unsigned int __kernel_size_t; >+typedef __kernel_size_t size_t; >+struct list_head { >+ struct list_head *next; >+}; >+ >+struct dmx_ts_feed { >+ int is_filtering; >+}; >+struct dmx_section_feed { >+ u16 secbufp; >+ u16 seclen; >+ u16 tsfeedp; >+}; >+ >+typedef int (*dmx_ts_cb) ( >+ const u8 * buffer1, >+ size_t buffer1_length, >+ const u8 * buffer2, >+ size_t buffer2_length >+); >+ >+struct dvb_demux_feed { >+ union { >+ struct dmx_ts_feed ts; >+ struct dmx_section_feed sec; >+ } feed; >+ union { >+ dmx_ts_cb ts; >+ } cb; >+ int type; >+ u16 pid; >+ int ts_type; >+ struct list_head list_head; >+}; >+ >+struct dvb_demux { >+ int (*stop_feed)(struct dvb_demux_feed *feed); >+ struct list_head feed_list; >+}; >+ >+ >+static >+inline >+__attribute__((always_inline)) >+u8 >+payload(const u8 *tsp) >+{ >+ if (tsp[3] & 0x20) { >+ return 184 - 1 - tsp[4]; >+ } >+ return 184; >+} >+ >+static >+inline >+__attribute__((always_inline)) >+int >+dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, const u8 *buf) >+{ >+ int count = payload(buf); >+ int p; >+ if (count == 0) >+ return -1; >+ return feed->cb.ts(&buf[p], count, ((void *)0), 0); >+} >+ >+static >+inline >+__attribute__((always_inline)) >+void >+dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, const u8 >*buf) >+{ >+ switch (feed->type) { >+ case 0: >+ if (feed->ts_type & 1) { >+ dvb_dmx_swfilter_payload(feed, buf); >+ } >+ if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) >+ feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; >+ } >+} >+ >+static >+void >+dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) >+{ >+ struct dvb_demux_feed *feed; >+ int dvr_done = 0; >+ >+ for (feed = ({ const typeof( ((typeof(*feed) *)0)->list_head ) >*__mptr = ((&demux->feed_list)->next); (typeof(*feed) *)( (char >*)__mptr - __builtin_offsetof(typeof(*feed),list_head) );}); >__builtin_prefetch(feed->list_head.next), &feed->list_head != >(&demux->feed_list); feed = ({ const typeof( ((typeof(*feed) >*)0)->list_head ) *__mptr = (feed->list_head.next); (typeof(*feed) *)( >(char *)__mptr - __builtin_offsetof(typeof(*feed),list_head) );})) { >+ if (((((feed)->type == 0) && ((feed)->feed.ts.is_filtering) && >(((feed)->ts_type & (1 | 8)) == 1))) && (dvr_done++)) >+ dvb_dmx_swfilter_packet_type(feed, buf); >+ else if (feed->pid == 0x2000) >+ feed->cb.ts(buf, 188, ((void *)0), 0); >+ } >+} >+void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, >size_t count) >+{ >+ while (count--) { >+ dvb_dmx_swfilter_packet(demux, buf); >+ } >+}