This case looks like this:

typedef struct
{
  unsigned char a  : 2;
  unsigned char b  : 3;
  unsigned char c  : 1;
  unsigned char d  : 1;
  unsigned char e  : 1;
} a_struct;

foo (flags)
     a_struct *flags;
{
  return (flags->c != 0
          || flags->d != 1
          || flags->e != 1
          || flags->a != 2
          || flags->b != 3);
}

main ()
{
  a_struct flags;

  flags.c  = 0;
  flags.d  = 1;
  flags.e  = 1;
  flags.a  = 2;
  flags.b  = 3;

  if (foo (&flags) != 0)
    abort ();
  else
    exit (0);

}

at Os, foo gets inlined into main, so after tree opts, we have:


;; Function main (main)

main ()
{
  struct a_struct flags;

<bb 0>:
  flags.c = 0;
  flags.d = 1;
  flags.e = 1;
  flags.a = 2;
  flags.b = 3;
  if (BIT_FIELD_REF <flags, 8, 0> != 206) goto <L0>; else goto <L1>;

<L0>:;
  abort ();

<L1>:;
  exit (0);

}

The *initial* RTL (ie from 00.expand), looks like this:

;;
;; Full RTL generated for this function:
;;
(note 2 0 5 NOTE_INSN_DELETED)

;; Start of basic block 0, registers live: (nil)
(note 5 2 3 0 [bb 0] NOTE_INSN_BASIC_BLOCK)

(note 3 5 4 0 NOTE_INSN_FUNCTION_BEG)

(note 4 3 6 0 NOTE_INSN_DELETED)
;; End of basic block 0, registers live:
 (nil)

;; Start of basic block 1, registers live: (nil)
(note 6 4 8 1 [bb 1] NOTE_INSN_BASIC_BLOCK)

(insn 8 6 10 1 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (and:QI (reg/v:QI 58 [ flags ])
                    (const_int -33 [0xffffffdf])))
            (clobber (reg:CC 17 flags))
        ]) -1 (nil)
    (nil))

(insn 10 8 12 1 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (ior:QI (reg/v:QI 58 [ flags ])
                    (const_int 64 [0x40])))
            (clobber (reg:CC 17 flags))
                                                                    

This is *already* wrong, AFAICT, because reg:QI 58 is uninitialized, and
we are trying to use it's value.  Why do we do this?

This causes problems on the dataflow branch (or will RSN when kenny
commits the latest upates).  We don't mark 58 as live at the beginning
of block 0 (because it isn't special in any way, isn't set in entry, and
isn't a hard reg, so there is no reason to mark it live incoming to bb
0).

Marking uninitialized registers live everywhere gives you very imprecise
dataflow information when they are only initialized along some paths
(which is why things like "make_accurate_live_analysis" compute liveness
without them.  Dataflow-branch does the equivalent of
make_accurate_live_analysis *all the time*).

Liveness on mainline looks like 

;; Start of basic block 0, registers live: 7 [sp] 16 [argp] 20 [frame]
58
(note 6 3 8 0 [bb 0] NOTE_INSN_BASIC_BLOCK)

(insn 8 6 10 0 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (and:QI (reg/v:QI 58 [ flags ])
                    (const_int -33 [0xffffffdf])))
            (clobber (reg:CC 17 flags))
        ]) 212 {*andqi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(insn 10 8 12 0 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (ior:QI (reg/v:QI 58 [ flags ])
                    (const_int 64 [0x40])))
            (clobber (reg:CC 17 flags))
        ]) 227 {*iorqi_1} (insn_list:REG_DEP_TRUE 8 (nil))
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(insn 12 10 15 0 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (ior:QI (reg/v:QI 58 [ flags ])
                    (const_int -64 [0xffffffc0])))
            (clobber (reg:CC 17 flags))
        ]) 227 {*iorqi_1} (nil)


(Note 58 ends up live because the dataflow isn't smart enough to know
that it isn't *set anywhere*)

On dataflow, we have (note bbs are renumbered so exit and entry are no
longer negative, a patch is forthcoming for this):

;; Start of basic block 2, registers live: 7 [sp] 16 [argp] 20 [frame] 
(note 6 3 8 2 [bb 2] NOTE_INSN_BASIC_BLOCK)

(insn 8 6 10 2 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (and:QI (reg/v:QI 58 [ flags ])
                    (const_int -33 [0xffffffdf])))
            (clobber (reg:CC 17 flags))
        ]) 212 {*andqi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(insn 10 8 12 2 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (ior:QI (reg/v:QI 58 [ flags ])
                    (const_int 64 [0x40])))
            (clobber (reg:CC 17 flags))
        ]) 227 {*iorqi_1} (insn_list:REG_DEP_TRUE 8 (nil))
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(insn 12 10 15 2 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (ior:QI (reg/v:QI 58 [ flags ])
                    (const_int -128 [0xffffff80])))
            (clobber (reg:CC 17 flags))
        ]) 227 {*iorqi_1} (insn_list:REG_DEP_TRUE 10 (nil))
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

Combine, now freed of its shackles, does this:

(note 8 6 10 2 NOTE_INSN_DELETED)

(note 10 8 12 2 NOTE_INSN_DELETED)

(insn 12 10 15 2 (parallel [
            (set (reg/v:QI 58 [ flags ])
                (ior:QI (reg/v:QI 58 [ flags ])
                    (const_int -64 [0xffffffc0])))
            (clobber (reg:CC 17 flags))
        ]) 227 {*iorqi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

and then the test program crashes depending on what value eax ends up
getting at the start of main (IE if you run it 10 times, it will abort
probably twice).






Reply via email to