#2151 pic16 poor read-modify-write optimization

open
nobody
None
PIC16
5
2014-03-10
2013-04-01
BsAtHome
No

Code generation results are less than stellar when doing &= and |= operations on registers. If the right-hand-side (rhs) is constant, then a simple read-modify-write cycle can be performed, but it seems that this is not always done properly.

Attatched example compiles as:
$ sdcc -mpic16 -p18f66j11 --obanksel=0 --pstack-model=small --fomit-frame-pointer --optimize-cmp --optimize-df --denable-peeps --opt-code-speed --fverbose-asm --use-non-free --std-sdcc99 -I. -c -o poorcode.o poorcode.c

Removing all the optimization options or enabling --opt-code-size does not seem to have any effect.

Tested on latest sdcc version from SVN:
$ sdcc --version
SDCC : pic16/pic14 3.2.1 #8447 (Apr 1 2013) (Linux)

It seems that the detection of a constant rhs is not done properly, depending on what operators are used on the rhs. It comes to mind that it may be related to a potential size-promotion of the rhs, which then is messing with the code-generator. Casting does seem to do the trick.

The second problem is specific to the &= operation, where an explicit zero leaves a redundant load. The code will optimize to a "clrf" instruction, but a load is done regardless.

#include <pic18fregs.h>

#define poorcode()  do { LATC &= (~0x0f); } while(0)

void func(void)
{
    LATA |= 0x0a;           // good
    LATB |= ~0x05;          // bad
    LATA |= 0xff-0x05;      // good
    LATB |= (unsigned char)~0x05;   // good

    LATA &= 0xa0;           // good
    LATB &= ~0x50;          // bad
    LATA &= 0xff-0x50;      // good
    LATB &= (unsigned char)~0x05;   // good

    LATA &= 0;      // redundand read

    poorcode();     // still bad
}

The output of the above example is attached.

1 Attachments

Discussion

  • BsAtHome
    BsAtHome
    2013-04-01

    The redundant read with "x &= 0" could be interpreted as "you asked a read-modify-write cycle, so we give it to you". This is then related to the definition of LATx to be volatile.

    Anyway, the other problems still persist.

     
  • Diego Herranz
    Diego Herranz
    2013-04-01

    Why isn't this line shown on the .lst?

    LATA &= 0; // redundand read

     
    • BsAtHome
      BsAtHome
      2013-04-01

      Beats me! Sometimes a line gets dropped? I did not remove it (only leading and trailing lines arround the function).

      Anyway, the generated code is still wrong, eventhough the LATA is declared volatile.

      "LATA &= 0;" translates into:
      MOVF _LATA, W
      CLRF _LATA

      The proper version should read:
      MOVLW 0
      ANDWF _LATA, F

      The difference between the two is that the first allows for an interrupt to pass between the instructions, whereas the second is a true atomic read-modify-write.