Given a test case like this:

typedef struct {
       unsigned char no0 :1;
       unsigned char no1 :1;
       unsigned char no2 :1;
       unsigned char no3 :1;
       unsigned char no4 :1;
       unsigned char no5 :1;
       unsigned char no6 :1;
       unsigned char no7 :1;
} __BITS8;
#define SFR0_bit (*(volatile union __BITS9 *)0xFFFF0)
#define SFREN SFR0_bit.no4

foo() {
   SFREN = 1U;
   SFREN = 0U;
}


(i.e. any code that sets/clears one bit in a volatile memory-mapped
area, which the rl78 has instructions for)

Before:

(insn 5 2 7 2 (set (reg/f:HI 43)
        (const_int 240 [0xf0])) test.c:24 7 {*movhi_virt}
     (nil))
(insn 7 5 8 2 (set (reg:QI 45 [ MEM[(volatile union un_per0 *)240B].BIT.no4 ])
        (mem/v/j:QI (reg/f:HI 43) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])) test.c:24 5 {movqi_virt}
     (nil))
(insn 8 7 9 2 (set (reg:QI 46)
        (ior:QI (reg:QI 45 [ MEM[(volatile union un_per0 *)240B].BIT.no4 ])
            (const_int 16 [0x10]))) test.c:24 19 {*iorqi3_virt}
     (expr_list:REG_DEAD (reg:QI 45 [ MEM[(volatile union un_per0 
*)240B].BIT.no4 ])
        (nil)))
(insn 9 8 12 2 (set (mem/v/j:QI (reg/f:HI 43) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])
        (reg:QI 46)) test.c:24 5 {movqi_virt}
     (expr_list:REG_DEAD (reg:QI 46)
        (nil)))
(insn 12 9 13 2 (set (reg:QI 49 [ MEM[(volatile union un_per0 *)240B].BIT.no4 ])
        (mem/v/j:QI (reg/f:HI 43) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])) test.c:26 5 {movqi_virt}
     (nil))
(insn 13 12 14 2 (set (reg:QI 50)
        (and:QI (reg:QI 49 [ MEM[(volatile union un_per0 *)240B].BIT.no4 ])
            (const_int -17 [0xffffffffffffffef]))) test.c:26 18 {*andqi3_virt}
     (expr_list:REG_DEAD (reg:QI 49 [ MEM[(volatile union un_per0 
*)240B].BIT.no4 ])
        (nil)))
(insn 14 13 0 2 (set (mem/v/j:QI (reg/f:HI 43) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])
        (reg:QI 50)) test.c:26 5 {movqi_virt}
     (expr_list:REG_DEAD (reg:QI 50)
        (expr_list:REG_DEAD (reg/f:HI 43)
            (nil))))

Combine gets as far as this:

Trying 5 -> 9:
Failed to match this instruction:
(parallel [
        (set (mem/v/j:QI (const_int 240 [0xf0]) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])
            (ior:QI (mem/v/j:QI (const_int 240 [0xf0]) [0 MEM[(volatile union 
un_per0 *)240B].BIT.no4+0 S1 A16])
                (const_int 16 [0x10])))
        (set (reg/f:HI 43)
            (const_int 240 [0xf0]))
    ])

(the set is left behind because it's used for the second assignment)

Both of those insns in the parallel are valid rl78 insns.  I tried
adding that parallel as a define-and-split but combine doesn't split
it at the point where it inserts it, so it doesn't work right.  If it
reduced those four instructions to the two in the parallel, but
without the parallel, it would probably work too.

We end up with code like this:

        movw    r8, #240                 ; 5    *movhi_real/4           [length 
= 4]
        movw    ax, r8                   ; 19   *movhi_real/5           [length 
= 4]
        movw    hl, ax                   ; 21   *movhi_real/6           [length 
= 4]
        set1    [hl].4                   ; 9    *iorqi3_real/1          [length 
= 4]
        clr1    [hl].4                   ; 14   *andqi3_real/1          [length 
= 4]

but what we want is this:

        set1    !240.4                   ; 9    *iorqi3_real/1          [length 
= 4]
        clr1    !240.4                   ; 14   *andqi3_real/1          [length 
= 4]

( !240 means (mem (const_int 240)) )

(if there's only one such operation in a function, it combines
properly, likely because the address is not needed after the insn it
can combine, unlike the parallel above)

The common addresses are separated at least before lowering to RTL; as the 
initial
expansion has:

;; MEM[(volatile union un_per0 *)240B].BIT.no4 ={v} 1;

(insn 5 4 7 (set (reg/f:HI 43)
        (const_int 240 [0xf0])) test.c:24 -1
     (nil))

(insn 7 5 8 (set (reg:QI 45)
        (mem/v/j:QI (reg/f:HI 43) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])) test.c:24 -1
     (nil))

(insn 8 7 9 (set (reg:QI 46)
        (ior:QI (reg:QI 45)
            (const_int 16 [0x10]))) test.c:24 -1
     (nil))

(insn 9 8 0 (set (mem/v/j:QI (reg/f:HI 43) [0 MEM[(volatile union un_per0 
*)240B].BIT.no4+0 S1 A16])
        (reg:QI 46)) test.c:24 -1
     (nil))


Yes, I know gcc doesn't like combining volatile accesses into one
insn, but the rl78 backend (my copy at least) has predicates that
allow it, because it's safe on rl78.

Also, if I take out the "volatile" yet put some sort of barrier (like
a volatile asm) between the two assignments, it still fails, in the
same manner.

Reply via email to