Hi, I have a question concerning the following C code

typedef unsigned char uint8_t;
#define SEARCHING (-2)
#define UCSR0A (*(volatile uint8_t *)((0x0B) + 0x20))
#define UDR0 (*(volatile uint8_t *)((0x0C) + 0x20))
void __vector_18(void)
{
    unsigned char status = UCSR0A;
    unsigned char data = UDR0;
    static volatile int slot;
    if (status & 0x10)
    {
        if (slot == SEARCHING)
            slot ++;
    }
}

and compiled with

$ avr-gcc-4.6.2 -Os -S -dp -fdump-rtl-combine-details -mmcu=atmega128

The problem is that the first SFR access (UCSR0A) is dragged over the second one (UDR0) during insn combine by means of the following pattern from avr.md. The pattern describes the "if (status & 0x10)" part:

;; Lower half of the I/O space - use sbic/sbis directly.
(define_insn "*sbix_branch"
  [(set (pc)
        (if_then_else
         (match_operator 0 "eqne_operator"
                 [(zero_extract:HI
                   (mem:QI (match_operand 1 "low_io_address_operand" "n"))
                   (const_int 1)
                   (match_operand 2 "const_int_operand" "n"))
                  (const_int 0)])
         (label_ref (match_operand 3 "" ""))
         (pc)))]

The CONST_INT address of UCSR0A matches low_io_address_operand and insn combine combines:

Trying 6 -> 12:
Successfully matched this instruction:
(set (pc)
(if_then_else (eq (zero_extract:HI (mem/v:QI (const_int 43 [0x2b]) [0 MEM[(volatile uint8_t *)43B]+0 S1 A8])
                (const_int 1 [0x1])
                (const_int 4 [0x4]))
            (const_int 0 [0]))
        (label_ref:HI 23)
        (pc)))
deferring deletion of insn with uid = 6.

In contrast to some memory_operand, the mem:QI is not sensitive to volatile_ok. However, using some memory_operand in the insn instead of
  (mem:QI ("low_io_address_operand"))
would imply that the insn never matches. The SBIC/SBIS instructions the insn is supposed to produce only work on some I/O memory and thus accesses are volatile.

As can be seen in the combine dump, there is still a /v flag with mem and combine is aware of what it is doing.

My question is:

Is insn combine allowed to match the insn because from combine's perspective just a CONST_INT (i.e. low_io_address_operand) is moved across the access of UDR0?

Or is this a bug in insn combine?

If combine is right -- and thus the pattern is wrong -- how must the insn be rewritten to produce respective instructions?

Johann

Reply via email to