]> git.friedersdorff.com Git - max/tmk_keyboard.git/commitdiff
tmk_core/common/timer.h: Improve code generation for TIMER_DIFF* macros
authorPurdea Andrei <andrei@purdea.ro>
Wed, 1 Apr 2020 04:46:18 +0000 (07:46 +0300)
committerPurdea Andrei <andrei@purdea.ro>
Wed, 1 Apr 2020 04:46:18 +0000 (07:46 +0300)
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.

tmk_core/common/timer.h

index a8c50fe7ca54cf06867d2899e4ffc9ea98fe02b9..3bd72e4a254abcb84a6249144a3ef719c23498eb 100644 (file)
@@ -25,7 +25,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #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)