Extra (useless) instructions involving r7 and accumulator

Why would the following line in C:

XRAM00 |= 0x01;

compile into this:

mov dptr, #XRAM00
movx a, @dptr
mov r7, a
mov a, r7
orl a, #1
mov r7, a
mov dptr, #XRAM00
mov a, r7
movx @dptr, a

I would have expected this:

mov dptr, #XRAM00
movx a, @dptr
orl a, #1
movx @dptr, a

Parents
  • Imagine you're a compiler. You see the statement

    XRAM00 |= 0x01;

    So you think to yourself, "Fine. Let's break that down."

    load XRAM00
    Or with 0x01
    Store XRAM00

    1. Load XRAM00. Hm, need a register for the temporary. R7 is free. So load XRAM00 into R7. XRAM00 is in xdata. That means I have to use the DPTR and go through the accumulator. Grumble, grumble, stupid 8051 architecture, grumble.

    mov dtpr, #XRAM00
    movx a, @dptr
    mov r7, a

    Well, there's that step done.

    2. Or with 0x01. Hm, where'd I leave that temporary. That's right, R7. I can't OR directly in a register, so I'll have to use the accumulator and put it back when I'm done. Grumble, grumble, stupid 8051 architecture, grumble.

    mov a, r7
    orl a, #1
    mov r7, a

    3. It was an |=, so I've got to save the temp back to allocated storage. That's in xdata. That means I have to use the DTPR and go through the accumulator. Grumble, grumble, stupid 8051 architecture, grumble.

    mov dptr, #XRAM00
    mov a, r7
    movx @dptr, a

    Finally, all done.

    In short, it's exactly how most code geneators for most compilers work. Compilers have optimizers not because they have brilliant insight into the problem and can magically make the code smaller. (That's your job.) Compilers have optimizers because basic code generation is generally very focussed, even short-sighted. And it turns out it's a lot easier to generate code that's correct, if inefficient, and then optimize away inefficiency than it is to try to write a code generator that is smarter in the first place. It's a form of modularity; the code generator is responsible for semantics, the optimizer for getting rid of the silliness that occurs when you don't pay global attention to that sort of thing.

Reply
  • Imagine you're a compiler. You see the statement

    XRAM00 |= 0x01;

    So you think to yourself, "Fine. Let's break that down."

    load XRAM00
    Or with 0x01
    Store XRAM00

    1. Load XRAM00. Hm, need a register for the temporary. R7 is free. So load XRAM00 into R7. XRAM00 is in xdata. That means I have to use the DPTR and go through the accumulator. Grumble, grumble, stupid 8051 architecture, grumble.

    mov dtpr, #XRAM00
    movx a, @dptr
    mov r7, a

    Well, there's that step done.

    2. Or with 0x01. Hm, where'd I leave that temporary. That's right, R7. I can't OR directly in a register, so I'll have to use the accumulator and put it back when I'm done. Grumble, grumble, stupid 8051 architecture, grumble.

    mov a, r7
    orl a, #1
    mov r7, a

    3. It was an |=, so I've got to save the temp back to allocated storage. That's in xdata. That means I have to use the DTPR and go through the accumulator. Grumble, grumble, stupid 8051 architecture, grumble.

    mov dptr, #XRAM00
    mov a, r7
    movx @dptr, a

    Finally, all done.

    In short, it's exactly how most code geneators for most compilers work. Compilers have optimizers not because they have brilliant insight into the problem and can magically make the code smaller. (That's your job.) Compilers have optimizers because basic code generation is generally very focussed, even short-sighted. And it turns out it's a lot easier to generate code that's correct, if inefficient, and then optimize away inefficiency than it is to try to write a code generator that is smarter in the first place. It's a form of modularity; the code generator is responsible for semantics, the optimizer for getting rid of the silliness that occurs when you don't pay global attention to that sort of thing.

Children
More questions in this forum