Skip to content

Commit

Permalink
tmk_core/common: Improve code generation for TIMER_DIFF* macros
Browse files Browse the repository at this point in the history
Because of integer promotion the compiler is having a hard time generating
efficient code to calculate TIMER_DIFF* macros in some situations.
In the below example, the return value is "int", and this is causing the
trouble.

Example C code:

int __attribute__ ((noinline)) test(uint8_t current_timer, uint8_t start_timer)
{
    return TIMER_DIFF_8(current_timer, start_timer);
}

BEFORE: (with -Os)

00004c40 <test>:
    4c40:       28 2f           mov     r18, r24
    4c42:       30 e0           ldi     r19, 0x00       ; 0
    4c44:       46 2f           mov     r20, r22
    4c46:       50 e0           ldi     r21, 0x00       ; 0
    4c48:       86 17           cp      r24, r22
    4c4a:       20 f0           brcs    .+8             ; 0x4c54 <test+0x14>
    4c4c:       c9 01           movw    r24, r18
    4c4e:       84 1b           sub     r24, r20
    4c50:       95 0b           sbc     r25, r21
    4c52:       08 95           ret
    4c54:       c9 01           movw    r24, r18
    4c56:       84 1b           sub     r24, r20
    4c58:       95 0b           sbc     r25, r21
    4c5a:       93 95           inc     r25
    4c5c:       08 95           ret

AFTER: (with -Os)

00004c40 <test>:
    4c40:       86 1b           sub     r24, r22
    4c42:       90 e0           ldi     r25, 0x00       ; 0
    4c44:       08 95           ret

Note: the example is showing -Os but improvements can be seen at all optimization levels,
including -O0. We never use -O0, but I tested it to make sure that no extra code is
generated in that case.OA
  • Loading branch information
purdeaandrei committed Mar 28, 2020
1 parent 61e7b40 commit 8ad9899
Showing 1 changed file with 4 additions and 1 deletion.
5 changes: 4 additions & 1 deletion tmk_core/common/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "avr/timer_avr.h"
#endif

#define TIMER_DIFF(a, b, max) ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a))
#define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a)-(b))) : ( \
(max == UINT16_MAX) ? ((uint16_t)((a)-(b))) : ( \
(max == UINT32_MAX) ? ((uint32_t)((a)-(b))) : ( \
(a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a) ))))
#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
#define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX)
Expand Down

0 comments on commit 8ad9899

Please sign in to comment.