Search code examples
cc99xc8

Can I optimize memory usage of function that returns 12-byte struct?


I have code like this:

// my struct size is 12 bytes
typedef struct timer_entry_t {
    uint16_t t1_time_setting;
    uint16_t t2_time_setting;
    uint8_t time_range;
    uint8_t timer_mode;
    uint8_t relay_output_mask;
    uint8_t failure_relay_output_mask;
    uint8_t activating_scheduler_rule_id;
    uint8_t deactivation_inputs_mask;
    uint8_t activation_inputs_mask;
    uint8_t p12;
} timer_entry_t;

timer_entry_t GetTimerEntry(uint8_t e_idx) // uint8_t e_idx: 1 byte Local
{
    uint16_t mb_reg_idx; // 2 bytes Local
    uint16_t mb_reg;     // 2 bytes Local

    timer_entry_t entry; // 12 bytes Local

    // (...) fill timer_entry_t struct content

    return entry;        // 12 bytes Params
}

My compiler (XC8 for 8-bit Microchip microcontrollers) produces .lst file with information like this:

 49215 ;; Data sizes:     COMRAM   BANK0   BANK1   BANK2   BANK3   BANK4   BANK5   BANK6   BANK7   BANK8   BANK9  BANK10  BANK1
      +1  BANK12  BANK13
 49216 ;;      Params:         0      12       0       0       0       0       0       0       0       0       0       0       
      +0       0       0
 49217 ;;      Locals:         0      17       0       0       0       0       0       0       0       0       0       0       
      +0       0       0
 49218 ;;      Temps:          0       2       0       0       0       0       0       0       0       0       0       0       
      +0       0       0
 49219 ;;      Totals:         0      31       0       0       0       0       0       0       0       0       0       0       
      +0       0       0
 49220 ;;Total ram usage:       31 bytes

So, this function uses 12 bytes for local timer_entry_t entry; variable AND 12 bytes to return value. It also wastes some time to move data.

Can I avoid this "double allocation" and moving data somehow?


Solution

  • Change the function so it takes a pointer to the struct as a parameter, rather than returning it as a value. It still has to pass something, but it's probably only 4 bytes rather than 12.

    void GetTimerEntry(uint8_t e_idx, timer_entry_t *entry) // uint8_t e_idx: 1 byte Local
    {
        uint16_t mb_reg_idx; // 2 bytes Local
        uint16_t mb_reg;     // 2 bytes Local
    
    
        // (...) fill timer_entry_t struct content
    
        return;
    }
    

    Then instead of

    timer_entry_t entry = GetTimerEntry(idx);
    

    you use

    timer_entry_t entry;
    GetTimerEntry(idx, &entry);