This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/MSP430-GCC-OPENSOURCE: MSP430-GCC 9.2.0.0 Suboptimal register marshalling when a function is called multiple times with the same arguments within the same scope

Part Number: MSP430-GCC-OPENSOURCE

Tool/software: TI C/C++ Compiler

In my situation I have a bitbang i2c function gathering data from 2 modules with different addresses.

The only parameter that changes is the i2c address.

I compiled with the following flags:

CFLAGS = -mmcu=$(MCU) -std=gnu11 -g -Os -fno-ipa-icf-functions \
-Wall -Wunused -ffunction-sections -fdata-sections -fomit-frame-pointer -fwrapv -MMD

    {
      static const uint8_t wr_data[1] = {P64P_INPUT};
INIT_GPIO1_READ:
      mod_mask = 1;
      s_idx = 2;
      bbi2c_start(GPIO1_ADDR, wr_data, sizeof(wr_data), 3);
      return;

INIT_GPIO1_READ_SUCCESS:
      input_bits[0] = *((uint16_t*)bbi2c_recv_buffer);

INIT_GPIO2_READ:
      mod_mask = 2;
      s_idx = 3;
      bbi2c_start(GPIO2_ADDR, wr_data, sizeof(wr_data), 3);
      return;
    }

However, the code as produced by gcc duplicates the r13-r15 register assignments when invoking the function.

The instructions at f2c0, f2c4 and f2c6 are redundant.

The instruction at f2a6 should precede f29c and the jmp at f2ce should target the r15 assignment, not the call.

0000f29c <.Loc.484.2>:
      bbi2c_start(GPIO1_ADDR, wr_data, sizeof(wr_data), 3);
    f29c: 7f 40 03 00   mov.b #3, r15 ;
    f2a0: 5e 43         mov.b #1, r14 ;r3 As==01
    f2a2: 3d 40 29 e3   mov #-7383, r13 ;#0xe329
    f2a6: 7c 40 21 00   mov.b #33,  r12 ;#0x0021

0000f2aa <.L287>:
      bbi2c_start(GPIO2_ADDR, wr_data, sizeof(wr_data), 3);
    f2aa: b0 12 04 ec   call  #-5116    ;#0xec04

0000f2ae <.LVL226>:
      return;
    f2ae: e7 3f         jmp $-48      ;abs 0xf27e

0000f2b0 <.L251>:
      input_bits[0] = *((uint16_t*)bbi2c_recv_buffer);
    f2b0: 92 42 c0 26   mov &0x26c0,&0x26b8 ;0x26c0
    f2b4: b8 26

0000f2b6 <.L252>:
      mod_mask = 2;
    f2b6: e2 43 93 26   mov.b #2, &0x2693 ;r3 As==10

0000f2ba <.Loc.492.2>:
      s_idx = 3;
    f2ba: b2 40 03 00   mov #3, &0x2028 ;
    f2be: 28 20

0000f2c0 <.Loc.493.2>:
      bbi2c_start(GPIO2_ADDR, wr_data, sizeof(wr_data), 3);
    f2c0: 7f 40 03 00   mov.b #3, r15 ;
    f2c4: 5e 43         mov.b #1, r14 ;r3 As==01
    f2c6: 3d 40 29 e3   mov #-7383, r13 ;#0xe329
    f2ca: 7c 40 20 00   mov.b #32,  r12 ;#0x0020
    f2ce: ed 3f         jmp $-36      ;abs 0xf2aa

  • Sorry, but as usual I need a self-contained test case to investigate this.

    In the past I have sunk a lot of time into trying to recreate test cases using the snippets of code posted in bug reports, only for some key information to have been omitted from the snippet, rendering my test case invalid.

    If you compile your program with -E so only the preprocessor is invoked, it should be relatively straightforward to extract the definitions required for your function to compile on its own.

    Thanks,

  • I don't see this as a problem. Fixing it would require calling an intermediate function created by the compiler. That wouldn't be too bad unless the parameters didn't fit in registers and it had to start mucking about with the stack.

    If space is such an issue for you that this makes a difference, you could use assembly or provide your own intermediate function. Compilers will never produce optimal (for some value of optimal) code.

  • Couldn't add to text to my upload for some reason.

    I attempted to recreate the issue but as it turns out the compiler is removing the last bbi2c_start call from loop().

    The intent of the loop code is that the bbi2c_start calls are alternated between loop calls.

    Before any of you start accusing me of code heresy, this is valid gcc and should compile as such.

    void loop(){
      static const uint8_t wr_data[1] = {10};
    
      const void* st = &&INIT_GPIO1_READ;
      goto *st;
    
    INIT_GPIO1_READ:
      st = &&INIT_GPIO1_READ_SUCCESS;
      bbi2c_start(32, wr_data, sizeof(wr_data), 3);
      return;
    
    INIT_GPIO1_READ_SUCCESS:
      input_bits[0] = *((uint16_t*)bbi2c_recv_buffer);
    
      st = &&INIT_GPIO1_READ;
      bbi2c_start(33, wr_data, sizeof(wr_data), 3);
    }
    

    0000e36c <loop>:
      goto *st;
    
      static const uint8_t wr_data[1] = {10};
    INIT_GPIO1_READ:
      st = &&INIT_GPIO1_READ_SUCCESS;
      bbi2c_start(32, wr_data, sizeof(wr_data), 3);
        e36c: 7f 40 03 00   mov.b #3, r15 ;
        e370: 5e 43         mov.b #1, r14 ;r3 As==01
        e372: 3d 40 00 e3   mov #-7424, r13 ;#0xe300
        e376: 7c 40 20 00   mov.b #32,  r12 ;#0x0020
        e37a: b0 12 1a e3   call  #-7398    ;#0xe31a
    
    0000e37e <.LVL12>:
    INIT_GPIO1_READ_SUCCESS:
      input_bits[0] = *((uint16_t*)bbi2c_recv_buffer);
    
      st = &&INIT_GPIO1_READ;
      bbi2c_start(33, wr_data, sizeof(wr_data), 3);
    }
        e37e: 30 41         ret
    

  • Thanks for the test case, I'll have a proper look at it soon and let you know if it looks like there's something that could be improved in a future release of MSP430-GCC.

**Attention** This is a public forum