https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69049
Bug ID: 69049 Summary: [avr] strange/unnecessary commands in compiled code Product: gcc Version: 4.9.2 Status: UNCONFIRMED Severity: major Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: night_ghost at ykoctpa dot ru Target Milestone: --- small code void deepSleep(uint16_t milliseconds) { uint32_t microseconds = milliseconds * 1000L; uint16_t sleep_periods = (microseconds - watchdogTime_us) / watchdogTime_us; while (sleep_periods >= 512) { narcoleptic_sleep_down(WDTO_8S); sleep_periods -= 512; } if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); /* xxx */ } compiled as (see comments) void deepSleep(uint16_t milliseconds) { uint32_t microseconds = milliseconds * 1000L; 2fb2: 9c 01 movw r18, r24 2fb4: a8 ee ldi r26, 0xE8 ; 232 2fb6: b3 e0 ldi r27, 0x03 ; 3 2fb8: 0e 94 b8 33 call 0x6770 ; 0x6770 <__umulhisi3> uint16_t sleep_periods = (microseconds - watchdogTime_us) / watchdogTime_us; 2fbc: 6c 19 sub r22, r12 2fbe: 7d 09 sbc r23, r13 2fc0: 8e 09 sbc r24, r14 2fc2: 9f 09 sbc r25, r15 2fc4: a7 01 movw r20, r14 2fc6: 96 01 movw r18, r12 2fc8: 0e 94 71 33 call 0x66e2 ; 0x66e2 <__udivmodsi4> 2fcc: 69 01 movw r12, r18 // r12r13 === sleep_periods, is'nt it? while (sleep_periods >= 512) { //{ why GCC adds 0 before comparison? 2fce: e1 2c mov r14, r1 2fd0: f1 2c mov r15, r1 2fd2: c7 01 movw r24, r14 2fd4: 8c 0d add r24, r12 2fd6: 9d 1d adc r25, r13 // carry NEVER can be set - r1===0 2fd8: 81 15 cp r24, r1 //} 2fda: 92 40 sbci r25, 0x02 ; 2 2fdc: 70 f0 brcs .+28 ; 0x2ffa <_Z9deepSleepj+0x6c> narcoleptic_sleep_down(WDTO_8S); 2fde: 89 e0 ldi r24, 0x09 ; 9 //{ why GCC saves unneeded LONG? 2fe0: 29 83 std Y+1, r18 ; 0x01 2fe2: 3a 83 std Y+2, r19 ; 0x02 2fe4: 4b 83 std Y+3, r20 ; 0x03 2fe6: 5c 83 std Y+4, r21 ; 0x04 //} 2fe8: 0e 94 c4 17 call 0x2f88 ; 0x2f88 <_Z22narcoleptic_sleep_downh> 2fec: 62 e0 ldi r22, 0x02 ; 2 2fee: f6 1a sub r15, r22 //{ why GCC restores unneeded LONG? 2ff0: 5c 81 ldd r21, Y+4 ; 0x04 2ff2: 4b 81 ldd r20, Y+3 ; 0x03 2ff4: 3a 81 ldd r19, Y+2 ; 0x02 2ff6: 29 81 ldd r18, Y+1 ; 0x01 //} 2ff8: ec cf rjmp .-40 ; 0x2fd2 <_Z9deepSleepj+0x44> //{ what the hell here? where such calculations in C code? 2ffa: f9 01 movw r30, r18 2ffc: ef 2f mov r30, r31 2ffe: ff 27 eor r31, r31 3000: e6 95 lsr r30 3002: 60 e0 ldi r22, 0x00 ; 0 3004: 7e ef ldi r23, 0xFE ; 254 3006: e6 9f mul r30, r22 3008: c0 01 movw r24, r0 300a: e7 9f mul r30, r23 300c: 90 0d add r25, r0 300e: f6 9f mul r31, r22 3010: 90 0d add r25, r0 3012: 11 24 eor r1, r1 3014: 82 0f add r24, r18 3016: 93 1f adc r25, r19 //} sleep_periods -= 512; } if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); 3018: 90 ff sbrs r25, 0 301a: 0d c0 rjmp .+26 ; 0x3036 <_Z9deepSleepj+0xa8> 301c: 88 e0 ldi r24, 0x08 ; 8 } //{ optimization on size but GCC generates 2nd epilogue to escape tail recursion while simple CALL takes less memory 301e: 0f 90 pop r0 3020: 0f 90 pop r0 3022: 0f 90 pop r0 3024: 0f 90 pop r0 3026: df 91 pop r29 3028: cf 91 pop r28 302a: ff 90 pop r15 302c: ef 90 pop r14 302e: df 90 pop r13 3030: cf 90 pop r12 while (sleep_periods >= 512) { narcoleptic_sleep_down(WDTO_8S); sleep_periods -= 512; } if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); /* xxx */ 3032: 0c 94 c4 17 jmp 0x2f88 ; 0x2f88 <_Z22narcoleptic_sleep_downh> //} } 3036: 0f 90 pop r0 3038: 0f 90 pop r0 303a: 0f 90 pop r0 303c: 0f 90 pop r0 303e: df 91 pop r29 3040: cf 91 pop r28 3042: ff 90 pop r15 3044: ef 90 pop r14 3046: df 90 pop r13 3048: cf 90 pop r12 304a: 08 95 ret But when line commented with "xxx" removed then hell code gone void deepSleep(uint16_t milliseconds) { uint32_t microseconds = milliseconds * 1000L; 2faa: 9c 01 movw r18, r24 2fac: a8 ee ldi r26, 0xE8 ; 232 2fae: b3 e0 ldi r27, 0x03 ; 3 2fb0: 0e 94 8a 33 call 0x6714 ; 0x6714 <__umulhisi3> uint16_t sleep_periods = (microseconds - watchdogTime_us) / watchdogTime_us; 2fb4: 6c 19 sub r22, r12 2fb6: 7d 09 sbc r23, r13 2fb8: 8e 09 sbc r24, r14 2fba: 9f 09 sbc r25, r15 2fbc: a7 01 movw r20, r14 2fbe: 96 01 movw r18, r12 2fc0: 0e 94 43 33 call 0x6686 ; 0x6686 <__udivmodsi4> 2fc4: e9 01 movw r28, r18 while (sleep_periods >= 512) { //{ adding 0 still here 2fc6: e1 2c mov r14, r1 2fc8: f1 2c mov r15, r1 2fca: c7 01 movw r24, r14 2fcc: 8c 0f add r24, r28 2fce: 9d 1f adc r25, r29 2fd0: 81 15 cp r24, r1 //} 2fd2: 92 40 sbci r25, 0x02 ; 2 2fd4: 30 f0 brcs .+12 ; 0x2fe2 <_Z9deepSleepj+0x54> narcoleptic_sleep_down(WDTO_8S); 2fd6: 89 e0 ldi r24, 0x09 ; 9 2fd8: 0e 94 c4 17 call 0x2f88 ; 0x2f88 <_Z22narcoleptic_sleep_downh> 2fdc: 22 e0 ldi r18, 0x02 ; 2 2fde: f2 1a sub r15, r18 2fe0: f4 cf rjmp .-24 ; 0x2fca <_Z9deepSleepj+0x3c> sleep_periods -= 512; } // if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); /* xxx */ } 2fe2: df 91 pop r29 2fe4: cf 91 pop r28 2fe6: ff 90 pop r15 2fe8: ef 90 pop r14 2fea: df 90 pop r13 2fec: cf 90 pop r12 2fee: 08 95 ret if to move uint32_t variable to a different function, hell code gone too and "add 0" code also void doSleep(uint16_t sleep_periods){ while (sleep_periods >= 512) { narcoleptic_sleep_down(WDTO_8S); sleep_periods -= 512; } if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); } void deepSleep(uint16_t milliseconds) { uint32_t microseconds = milliseconds * 1000L; doSleep((microseconds - watchdogTime_us) / watchdogTime_us); } void doSleep(uint16_t sleep_periods){ 2f8e: 0f 93 push r16 2f90: 1f 93 push r17 2f92: cf 93 push r28 2f94: df 93 push r29 2f96: 8c 01 movw r16, r24 while (sleep_periods >= 512) { 2f98: ec 01 movw r28, r24 2f9a: c1 15 cp r28, r1 2f9c: 82 e0 ldi r24, 0x02 ; 2 2f9e: d8 07 cpc r29, r24 2fa0: 28 f0 brcs .+10 ; 0x2fac <_Z7doSleepj+0x1e> narcoleptic_sleep_down(WDTO_8S); 2fa2: 89 e0 ldi r24, 0x09 ; 9 2fa4: 0e 94 c4 17 call 0x2f88 ; 0x2f88 <_Z22narcoleptic_sleep_downh> sleep_periods -= 512; 2fa8: d2 50 subi r29, 0x02 ; 2 2faa: f7 cf rjmp .-18 ; 0x2f9a <_Z7doSleepj+0xc> } if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); 2fac: 10 ff sbrs r17, 0 2fae: 07 c0 rjmp .+14 ; 0x2fbe <_Z7doSleepj+0x30> 2fb0: 88 e0 ldi r24, 0x08 ; 8 } 2fb2: df 91 pop r29 2fb4: cf 91 pop r28 2fb6: 1f 91 pop r17 2fb8: 0f 91 pop r16 while (sleep_periods >= 512) { narcoleptic_sleep_down(WDTO_8S); sleep_periods -= 512; } if (sleep_periods & 256) narcoleptic_sleep_down(WDTO_4S); 2fba: 0c 94 c4 17 jmp 0x2f88 ; 0x2f88 <_Z22narcoleptic_sleep_downh> } 2fbe: df 91 pop r29 2fc0: cf 91 pop r28 2fc2: 1f 91 pop r17 2fc4: 0f 91 pop r16 2fc6: 08 95 ret for chip with liliputian memory this bug is very annoying