Overall, the major problem is that the lhs operand object type, or most optimal compatible type in the case of immedite operands, is not being used to correcly select builtin functions; which is fairly important for a compiler for 8-bit target to get right; where (u)divmod(q/h)i4 signed and unsigned 8 and 16 bit builtin verions of the / and % functions corespondingly. (This bug is independant of bug #10733, which doesn't actually seem as a bug to me, unless the divmod built-in functions are coded incorrectly, implies the use of divmodhi4 16 bit signed builtin; just as t1% = 30 implies the use of the udivmodqi4 unsigned 8-bit builtin. per ref: <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10733> ) The following main.c and main.lss file listings demonstrate the failure: // main.c // // inspecting code using avr-gcc 3.4.3 & buinutils 2.15.x as of 10/16/04 snapshots: int main( void ){ volatile signed char s; volatile unsigned char u; // // Overall, the major problem is that the lhs operand object type, or most // optimal compatible type in the case of immedite operands, is not being // used to correcly select builtin functions; which is fairly important for // a compiler for 8-bit target to get right; where (u)divmod(q/h)i4 signed and // unsigned 8 and 16 bit builtin verions of the / and % functions corespondingly. // // (This bug is independant of bug #10733, which doesn't actually seem // as a bug to me, unless the divmod built-in functions are coded incorrectly, // as in t1 = (t1 + 40) % 30; the (t1 + 40) sub-exp returns an int, which then // implies the use of divmodhi4 16 bit signed builtin; just as t1% = 30 implies // the use of the udivmodqi4 unsigned 8-bit builtin. // per ref: <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10733> ) char ss = s % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> char su = s % u ; //<__divmodhi4> correct. char us = u % s ; //<__divmodhi4> correct. char uu = u % u ; //<__udivmodqi4> correct. // although optminally selecting the builtin's for rhs immediate's: char sn = s % -3 ; //<__divmodqi4> correct. char sp = s % +3 ; //<__divmodqi4> correct. char un = u % -3 ; //<__divmodhi4> correct. char up = u % +3 ; //<__udivmodqi4> correct. // it never recognizes any opportunites for lhs immeidate's ?: char ns = -3 % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> char ps = +3 % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> char nu = -3 % u ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> char pu = +3 % u ; //<__divmodhi4> wrong, should be 8-bit unsigned <__udivmodqi4> // but does optimally select based on expicitly cast immediate values: char uc = u % ( char)-3 ; //<__udivmodqi4> correct, :: unsigned char char ux = u % ( signed char)-3 ; //<__divmodhi4> correct. char uy = u % (unsigned char)-3 ; //<__udivmodqi4> correct. char cu = ( char)-3 % u ; //<__udivmodqi4> correct, :: unsigned char char xu = ( signed char)-3 % u ; //<__divmodhi4> correct. char yu = (unsigned char)-3 % u ; //<__udivmodqi4> correct. char sc = s % ( char)-3 ; //<__divmodhi4> correct, :: unsigned char char sx = s % ( signed char)-3 ; //<__divmodqi4> correct. char sy = s % (unsigned char)-3 ; //<__divmodhi4> correct. char cs = ( char)-3 % s ; //<__divmodhi4> correct, :: unsigned char char xs = ( signed char)-3 % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> char ys = (unsigned char)-3 % s ; //<__divmodhi4> correct. return ss + su + us + uu + sn + sp + un + up + ns + ps + nu + pu + uc + ux + uy + cu + xu + yu + sc + sx + sy + cs + xs + ys ; } /* main.lss file listing: --begin-- main.elf: file format elf32-avr Sections: Idx Name Size VMA LMA File off Algn 0 .data 00000000 00800100 0000034e 000003e2 2**0 CONTENTS, ALLOC, LOAD, DATA 1 .text 0000034e 00000000 00000000 00000094 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .bss 00000000 00800100 0000034e 000003e2 2**0 ALLOC 3 .noinit 00000000 00800100 00800100 000003e2 2**0 CONTENTS 4 .eeprom 00000000 00810000 00810000 000003e2 2**0 CONTENTS 5 .stab 00000600 00000000 00000000 000003e4 2**2 CONTENTS, READONLY, DEBUGGING 6 .stabstr 000004c6 00000000 00000000 000009e4 2**0 CONTENTS, READONLY, DEBUGGING Disassembly of section .text: 00000000 <__vectors>: 0: 0c 94 46 00 jmp 0x8c 4: 0c 94 61 00 jmp 0xc2 8: 0c 94 61 00 jmp 0xc2 c: 0c 94 61 00 jmp 0xc2 10: 0c 94 61 00 jmp 0xc2 14: 0c 94 61 00 jmp 0xc2 18: 0c 94 61 00 jmp 0xc2 1c: 0c 94 61 00 jmp 0xc2 20: 0c 94 61 00 jmp 0xc2 24: 0c 94 61 00 jmp 0xc2 28: 0c 94 61 00 jmp 0xc2 2c: 0c 94 61 00 jmp 0xc2 30: 0c 94 61 00 jmp 0xc2 34: 0c 94 61 00 jmp 0xc2 38: 0c 94 61 00 jmp 0xc2 3c: 0c 94 61 00 jmp 0xc2 40: 0c 94 61 00 jmp 0xc2 44: 0c 94 61 00 jmp 0xc2 48: 0c 94 61 00 jmp 0xc2 4c: 0c 94 61 00 jmp 0xc2 50: 0c 94 61 00 jmp 0xc2 54: 0c 94 61 00 jmp 0xc2 58: 0c 94 61 00 jmp 0xc2 5c: 0c 94 61 00 jmp 0xc2 60: 0c 94 61 00 jmp 0xc2 64: 0c 94 61 00 jmp 0xc2 68: 0c 94 61 00 jmp 0xc2 6c: 0c 94 61 00 jmp 0xc2 70: 0c 94 61 00 jmp 0xc2 74: 0c 94 61 00 jmp 0xc2 78: 0c 94 61 00 jmp 0xc2 7c: 0c 94 61 00 jmp 0xc2 80: 0c 94 61 00 jmp 0xc2 84: 0c 94 61 00 jmp 0xc2 88: 0c 94 61 00 jmp 0xc2 0000008c <__ctors_end>: 8c: 11 24 eor r1, r1 8e: 1f be out 0x3f, r1 ; 63 90: cf ef ldi r28, 0xFF ; 255 92: d0 e1 ldi r29, 0x10 ; 16 94: de bf out 0x3e, r29 ; 62 96: cd bf out 0x3d, r28 ; 61 00000098 <__do_copy_data>: 98: 11 e0 ldi r17, 0x01 ; 1 9a: a0 e0 ldi r26, 0x00 ; 0 9c: b1 e0 ldi r27, 0x01 ; 1 9e: ee e4 ldi r30, 0x4E ; 78 a0: f3 e0 ldi r31, 0x03 ; 3 a2: 02 c0 rjmp .+4 ; 0xa8 000000a4 <.do_copy_data_loop>: a4: 05 90 lpm r0, Z+ a6: 0d 92 st X+, r0 000000a8 <.do_copy_data_start>: a8: a0 30 cpi r26, 0x00 ; 0 aa: b1 07 cpc r27, r17 ac: d9 f7 brne .-10 ; 0xa4 000000ae <__do_clear_bss>: ae: 11 e0 ldi r17, 0x01 ; 1 b0: a0 e0 ldi r26, 0x00 ; 0 b2: b1 e0 ldi r27, 0x01 ; 1 b4: 01 c0 rjmp .+2 ; 0xb8 000000b6 <.do_clear_bss_loop>: b6: 1d 92 st X+, r1 000000b8 <.do_clear_bss_start>: b8: a0 30 cpi r26, 0x00 ; 0 ba: b1 07 cpc r27, r17 bc: e1 f7 brne .-8 ; 0xb6 be: 0c 94 63 00 jmp 0xc6 000000c2 <__bad_interrupt>: c2: 0c 94 00 00 jmp 0x0 000000c6 <main>: // inspecting code using avr-gcc 3.4.3 & buinutils 2.15.x as of 10/16/04 snapshots: int main( void ){ c6: c5 ef ldi r28, 0xF5 ; 245 c8: d0 e1 ldi r29, 0x10 ; 16 ca: de bf out 0x3e, r29 ; 62 cc: cd bf out 0x3d, r28 ; 61 volatile signed char s; volatile unsigned char u; // // Overall, the major problem is that the lhs operand object type, or most // optimal compatible type in the case of immedite operands, is not being // used to correcly select builtin functions; which is fairly important for // a compiler for 8-bit target to get right; where (u)divmod(q/h)i4 signed and // unsigned 8 and 16 bit builtin verions of the / and % functions corespondingly. // // (this bug is independant of bug #10733, which doesn't actually seem // as a bug to me, as in t1 = (t1 + 40) % 30; the (t1 + 40) sub-exp // returns an int, which then implies the use of divmodhi4 16 bit signed // builtin; just as t1% = 30 implies the use of the udivmodqi4 unsigned 8-bit // builtin. ref: <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10733> ) char ss = s % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> ce: 99 81 ldd r25, Y+1 ; 0x01 d0: 89 81 ldd r24, Y+1 ; 0x01 d2: 28 2f mov r18, r24 d4: 33 27 eor r19, r19 d6: 27 fd sbrc r18, 7 d8: 30 95 com r19 da: 89 2f mov r24, r25 dc: 99 27 eor r25, r25 de: 87 fd sbrc r24, 7 e0: 90 95 com r25 e2: b9 01 movw r22, r18 e4: 0e 94 7f 01 call 0x2fe e8: 8b 83 std Y+3, r24 ; 0x03 char su = s % u ; //<__divmodhi4> correct. ea: 99 81 ldd r25, Y+1 ; 0x01 ec: 8a 81 ldd r24, Y+2 ; 0x02 ee: 28 2f mov r18, r24 f0: 33 27 eor r19, r19 f2: 89 2f mov r24, r25 f4: 99 27 eor r25, r25 f6: 87 fd sbrc r24, 7 f8: 90 95 com r25 fa: b9 01 movw r22, r18 fc: 0e 94 7f 01 call 0x2fe 100: 8c 83 std Y+4, r24 ; 0x04 char us = u % s ; //<__divmodhi4> correct. 102: 9a 81 ldd r25, Y+2 ; 0x02 104: 89 81 ldd r24, Y+1 ; 0x01 106: 28 2f mov r18, r24 108: 33 27 eor r19, r19 10a: 27 fd sbrc r18, 7 10c: 30 95 com r19 10e: 89 2f mov r24, r25 110: 99 27 eor r25, r25 112: b9 01 movw r22, r18 114: 0e 94 7f 01 call 0x2fe 118: 8d 83 std Y+5, r24 ; 0x05 char uu = u % u ; //<__udivmodqi4> correct. 11a: 8a 81 ldd r24, Y+2 ; 0x02 11c: 9a 81 ldd r25, Y+2 ; 0x02 11e: 69 2f mov r22, r25 120: 0e 94 66 01 call 0x2cc 124: 9e 83 std Y+6, r25 ; 0x06 // although optminally selecting the builtin's for rhs immediate's: char sn = s % -3 ; //<__divmodqi4> correct. 126: 89 81 ldd r24, Y+1 ; 0x01 128: 93 e0 ldi r25, 0x03 ; 3 12a: f9 2e mov r15, r25 12c: 6f 2d mov r22, r15 12e: 0e 94 72 01 call 0x2e4 132: 9f 83 std Y+7, r25 ; 0x07 char sp = s % +3 ; //<__divmodqi4> correct. 134: 89 81 ldd r24, Y+1 ; 0x01 136: 6f 2d mov r22, r15 138: 0e 94 72 01 call 0x2e4 13c: 98 87 std Y+8, r25 ; 0x08 char un = u % -3 ; //<__divmodhi4> correct. 13e: 8a 81 ldd r24, Y+2 ; 0x02 140: e3 e0 ldi r30, 0x03 ; 3 142: f0 e0 ldi r31, 0x00 ; 0 144: 99 27 eor r25, r25 146: bf 01 movw r22, r30 148: 0e 94 7f 01 call 0x2fe 14c: 89 87 std Y+9, r24 ; 0x09 char up = u % +3 ; //<__udivmodqi4> correct. 14e: 8a 81 ldd r24, Y+2 ; 0x02 150: 6f 2d mov r22, r15 152: 0e 94 66 01 call 0x2cc 156: 9a 87 std Y+10, r25 ; 0x0a // it never recognizes any opportunites for lhs immeidate's ?: char ns = -3 % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> 158: 89 81 ldd r24, Y+1 ; 0x01 15a: 28 2f mov r18, r24 15c: 33 27 eor r19, r19 15e: 27 fd sbrc r18, 7 160: 30 95 com r19 162: 0d ef ldi r16, 0xFD ; 253 164: 1f ef ldi r17, 0xFF ; 255 166: c8 01 movw r24, r16 168: b9 01 movw r22, r18 16a: 0e 94 7f 01 call 0x2fe 16e: 28 2e mov r2, r24 char ps = +3 % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> 170: 89 81 ldd r24, Y+1 ; 0x01 172: 28 2f mov r18, r24 174: 33 27 eor r19, r19 176: 27 fd sbrc r18, 7 178: 30 95 com r19 17a: cf 01 movw r24, r30 17c: b9 01 movw r22, r18 17e: 0e 94 7f 01 call 0x2fe 182: 38 2e mov r3, r24 char nu = -3 % u ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> 184: 8a 81 ldd r24, Y+2 ; 0x02 186: 28 2f mov r18, r24 188: 33 27 eor r19, r19 18a: c8 01 movw r24, r16 18c: b9 01 movw r22, r18 18e: 0e 94 7f 01 call 0x2fe 192: 48 2e mov r4, r24 char pu = +3 % u ; //<__divmodhi4> wrong, should be 8-bit unsigned <__udivmodqi4> 194: 8a 81 ldd r24, Y+2 ; 0x02 196: 28 2f mov r18, r24 198: 33 27 eor r19, r19 19a: cf 01 movw r24, r30 19c: b9 01 movw r22, r18 19e: 0e 94 7f 01 call 0x2fe 1a2: 58 2e mov r5, r24 // but does optimally select based on expicitly cast immediate values: char uc = u % ( char)-3 ; //<__udivmodqi4> correct, :: unsigned char 1a4: 8a 81 ldd r24, Y+2 ; 0x02 1a6: 4d ef ldi r20, 0xFD ; 253 1a8: 64 2f mov r22, r20 1aa: 0e 94 66 01 call 0x2cc 1ae: 69 2e mov r6, r25 char ux = u % ( signed char)-3 ; //<__divmodhi4> correct. 1b0: 8a 81 ldd r24, Y+2 ; 0x02 1b2: 99 27 eor r25, r25 1b4: bf 01 movw r22, r30 1b6: 0e 94 7f 01 call 0x2fe 1ba: 78 2e mov r7, r24 char uy = u % (unsigned char)-3 ; //<__udivmodqi4> correct. 1bc: 8a 81 ldd r24, Y+2 ; 0x02 1be: 64 2f mov r22, r20 1c0: 0e 94 66 01 call 0x2cc 1c4: 89 2e mov r8, r25 char cu = ( char)-3 % u ; //<__udivmodqi4> correct, :: unsigned char 1c6: 9a 81 ldd r25, Y+2 ; 0x02 1c8: 84 2f mov r24, r20 1ca: 69 2f mov r22, r25 1cc: 0e 94 66 01 call 0x2cc 1d0: 99 2e mov r9, r25 char xu = ( signed char)-3 % u ; //<__divmodhi4> correct. 1d2: 8a 81 ldd r24, Y+2 ; 0x02 1d4: 28 2f mov r18, r24 1d6: 33 27 eor r19, r19 1d8: c8 01 movw r24, r16 1da: b9 01 movw r22, r18 1dc: 0e 94 7f 01 call 0x2fe 1e0: a8 2e mov r10, r24 char yu = (unsigned char)-3 % u ; //<__udivmodqi4> correct. 1e2: 9a 81 ldd r25, Y+2 ; 0x02 1e4: 84 2f mov r24, r20 1e6: 69 2f mov r22, r25 1e8: 0e 94 66 01 call 0x2cc 1ec: b9 2e mov r11, r25 char sc = s % ( char)-3 ; //<__divmodhi4> correct, :: unsigned char 1ee: 89 81 ldd r24, Y+1 ; 0x01 1f0: ed ef ldi r30, 0xFD ; 253 1f2: f0 e0 ldi r31, 0x00 ; 0 1f4: 99 27 eor r25, r25 1f6: 87 fd sbrc r24, 7 1f8: 90 95 com r25 1fa: bf 01 movw r22, r30 1fc: 0e 94 7f 01 call 0x2fe 200: c8 2e mov r12, r24 char sx = s % ( signed char)-3 ; //<__divmodqi4> correct. 202: 89 81 ldd r24, Y+1 ; 0x01 204: 6f 2d mov r22, r15 206: 0e 94 72 01 call 0x2e4 20a: d9 2e mov r13, r25 char sy = s % (unsigned char)-3 ; //<__divmodhi4> correct. 20c: 89 81 ldd r24, Y+1 ; 0x01 20e: 99 27 eor r25, r25 210: 87 fd sbrc r24, 7 212: 90 95 com r25 214: bf 01 movw r22, r30 216: 0e 94 7f 01 call 0x2fe 21a: e8 2e mov r14, r24 char cs = ( char)-3 % s ; //<__divmodhi4> correct, :: unsigned char 21c: 89 81 ldd r24, Y+1 ; 0x01 21e: 28 2f mov r18, r24 220: 33 27 eor r19, r19 222: 27 fd sbrc r18, 7 224: 30 95 com r19 226: cf 01 movw r24, r30 228: b9 01 movw r22, r18 22a: 0e 94 7f 01 call 0x2fe 22e: f8 2e mov r15, r24 char xs = ( signed char)-3 % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> 230: 89 81 ldd r24, Y+1 ; 0x01 232: 28 2f mov r18, r24 234: 33 27 eor r19, r19 236: 27 fd sbrc r18, 7 238: 30 95 com r19 23a: c8 01 movw r24, r16 23c: b9 01 movw r22, r18 23e: 0e 94 7f 01 call 0x2fe 242: 48 2f mov r20, r24 char ys = (unsigned char)-3 % s ; //<__divmodhi4> correct. 244: 89 81 ldd r24, Y+1 ; 0x01 246: 28 2f mov r18, r24 248: 33 27 eor r19, r19 24a: 27 fd sbrc r18, 7 24c: 30 95 com r19 24e: cf 01 movw r24, r30 250: b9 01 movw r22, r18 252: 0e 94 7f 01 call 0x2fe return ss + su + us + uu + 256: 6b 81 ldd r22, Y+3 ; 0x03 258: 9c 81 ldd r25, Y+4 ; 0x04 25a: 69 0f add r22, r25 25c: 71 2d mov r23, r1 25e: 71 1d adc r23, r1 260: 9b 01 movw r18, r22 262: 6d 81 ldd r22, Y+5 ; 0x05 264: 26 0f add r18, r22 266: 31 1d adc r19, r1 268: 7e 81 ldd r23, Y+6 ; 0x06 26a: 27 0f add r18, r23 26c: 31 1d adc r19, r1 26e: 9f 81 ldd r25, Y+7 ; 0x07 270: 29 0f add r18, r25 272: 31 1d adc r19, r1 274: 68 85 ldd r22, Y+8 ; 0x08 276: 26 0f add r18, r22 278: 31 1d adc r19, r1 27a: 79 85 ldd r23, Y+9 ; 0x09 27c: 27 0f add r18, r23 27e: 31 1d adc r19, r1 280: 9a 85 ldd r25, Y+10 ; 0x0a 282: 29 0f add r18, r25 284: 31 1d adc r19, r1 286: 22 0d add r18, r2 288: 31 1d adc r19, r1 28a: 23 0d add r18, r3 28c: 31 1d adc r19, r1 28e: 24 0d add r18, r4 290: 31 1d adc r19, r1 292: 25 0d add r18, r5 294: 31 1d adc r19, r1 296: 26 0d add r18, r6 298: 31 1d adc r19, r1 29a: 27 0d add r18, r7 29c: 31 1d adc r19, r1 29e: 28 0d add r18, r8 2a0: 31 1d adc r19, r1 2a2: 29 0d add r18, r9 2a4: 31 1d adc r19, r1 2a6: 2a 0d add r18, r10 2a8: 31 1d adc r19, r1 2aa: 2b 0d add r18, r11 2ac: 31 1d adc r19, r1 2ae: 2c 0d add r18, r12 2b0: 31 1d adc r19, r1 2b2: 2d 0d add r18, r13 2b4: 31 1d adc r19, r1 2b6: 2e 0d add r18, r14 2b8: 31 1d adc r19, r1 2ba: 2f 0d add r18, r15 2bc: 31 1d adc r19, r1 2be: 24 0f add r18, r20 2c0: 31 1d adc r19, r1 sn + sp + un + up + ns + ps + nu + pu + uc + ux + uy + cu + xu + yu + sc + sx + sy + cs + xs + ys ; } 2c2: 28 0f add r18, r24 2c4: 31 1d adc r19, r1 2c6: c9 01 movw r24, r18 2c8: 0c 94 a6 01 jmp 0x34c 000002cc <__udivmodqi4>: 2cc: 99 1b sub r25, r25 2ce: 79 e0 ldi r23, 0x09 ; 9 2d0: 04 c0 rjmp .+8 ; 0x2da 000002d2 <__udivmodqi4_loop>: 2d2: 99 1f adc r25, r25 2d4: 96 17 cp r25, r22 2d6: 08 f0 brcs .+2 ; 0x2da 2d8: 96 1b sub r25, r22 000002da <__udivmodqi4_ep>: 2da: 88 1f adc r24, r24 2dc: 7a 95 dec r23 2de: c9 f7 brne .-14 ; 0x2d2 2e0: 80 95 com r24 2e2: 08 95 ret 000002e4 <__divmodqi4>: 2e4: 87 fb bst r24, 7 2e6: 08 2e mov r0, r24 2e8: 06 26 eor r0, r22 2ea: 87 fd sbrc r24, 7 2ec: 81 95 neg r24 2ee: 67 fd sbrc r22, 7 2f0: 61 95 neg r22 2f2: ec df rcall .-40 ; 0x2cc 2f4: 0e f4 brtc .+2 ; 0x2f8 2f6: 91 95 neg r25 000002f8 <__divmodqi4_1>: 2f8: 07 fc sbrc r0, 7 2fa: 81 95 neg r24 000002fc <__divmodqi4_exit>: 2fc: 08 95 ret 000002fe <__divmodhi4>: 2fe: 97 fb bst r25, 7 300: 09 2e mov r0, r25 302: 07 26 eor r0, r23 304: 0a d0 rcall .+20 ; 0x31a 306: 77 fd sbrc r23, 7 308: 04 d0 rcall .+8 ; 0x312 30a: 0c d0 rcall .+24 ; 0x324 30c: 06 d0 rcall .+12 ; 0x31a 30e: 00 20 and r0, r0 310: 1a f4 brpl .+6 ; 0x318 00000312 <__divmodhi4_neg2>: 312: 70 95 com r23 314: 61 95 neg r22 316: 7f 4f sbci r23, 0xFF ; 255 00000318 <__divmodhi4_exit>: 318: 08 95 ret 0000031a <__divmodhi4_neg1>: 31a: f6 f7 brtc .-4 ; 0x318 31c: 90 95 com r25 31e: 81 95 neg r24 320: 9f 4f sbci r25, 0xFF ; 255 322: 08 95 ret 00000324 <__udivmodhi4>: 324: aa 1b sub r26, r26 326: bb 1b sub r27, r27 328: 51 e1 ldi r21, 0x11 ; 17 32a: 07 c0 rjmp .+14 ; 0x33a 0000032c <__udivmodhi4_loop>: 32c: aa 1f adc r26, r26 32e: bb 1f adc r27, r27 330: a6 17 cp r26, r22 332: b7 07 cpc r27, r23 334: 10 f0 brcs .+4 ; 0x33a 336: a6 1b sub r26, r22 338: b7 0b sbc r27, r23 0000033a <__udivmodhi4_ep>: 33a: 88 1f adc r24, r24 33c: 99 1f adc r25, r25 33e: 5a 95 dec r21 340: a9 f7 brne .-22 ; 0x32c 342: 80 95 com r24 344: 90 95 com r25 346: bc 01 movw r22, r24 348: cd 01 movw r24, r26 34a: 08 95 ret 0000034c <_exit>: 34c: ff cf rjmp .-2 ; 0x34c ---end--- makefile file listing: --begin-- # Hey Emacs, this is a -*- makefile -*- # # WinAVR Sample makefile written by Eric B. Weddington, Jˆrg Wunsch, et al. # Released to the Public Domain # Please read the make user manual! # # Additional material for this makefile was submitted by: # Tim Henigan # Peter Fleury # Reiner Patommel # Sander Pool # Frederik Rouleau # Markus Pfaff # # On command line: # # make all = Make software. # # make clean = Clean out built project files. # # make coff = Convert ELF to AVR COFF (for use with AVR Studio 3.x or VMLAB). # # make extcoff = Convert ELF to AVR Extended COFF (for use with AVR Studio # 4.07 or greater). # # make program = Download the hex file to the device, using avrdude. Please # customize the avrdude settings below first! # # make filename.s = Just compile filename.c into the assembler code only # # To rebuild project do "make clean" then "make all". # # MCU name MCU = atmega64 # Output format. (can be srec, ihex, binary) FORMAT = ihex # Target file name (without extension). TARGET = main # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c # List Assembler source files here. # Make them always end in a capital .S. Files ending in a lowercase .s # will not be considered source files but generated files (assembler # output from the compiler), and will be deleted upon "make clean"! # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. ASRC = # Optimization level, can be [0, 1, 2, 3, s]. # 0 = turn off optimization. s = optimize for size. # (Note: 3 is not always the best optimization level. See avr-libc FAQ.) OPT = s # Debugging format. # Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. # AVR (extended) COFF requires stabs, plus an avr-objcopy run. #DEBUG = dwarf-2 DEBUG = # List any extra directories to look for include files here. # Each directory must be seperated by a space. EXTRAINCDIRS = /usr/local/avr/include # Compiler flag to set the C Standard level. # c89 - "ANSI" C # gnu89 - c89 plus GCC extensions # c99 - ISO C99 standard (not yet fully implemented) # gnu99 - c99 plus GCC extensions CSTANDARD = -std=gnu99 # Place -D or -U options here CDEFS = # Place -I options here CINCS = # Compiler flags. # -g*: generate debugging information # -O*: optimization level # -f...: tuning, see GCC manual and avr-libc documentation # -Wall...: warning level # -Wa,...: tell GCC to pass this to the assembler. # -adhlns...: create assembler listing CFLAGS = -g$(DEBUG) CFLAGS += $(CDEFS) $(CINCS) CFLAGS += -O$(OPT) CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CFLAGS += -Wall -Wstrict-prototypes CFLAGS += -Wa,-adhlns=$(<:.c=.lst) CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) CFLAGS += $(CSTANDARD) # Assembler flags. # -Wa,...: tell GCC to pass this to the assembler. # -ahlms: create listing # -gstabs: have the assembler create line number information; note that # for use in COFF files, additional information about filenames # and function names needs to be present in the assembler source # files -- see avr-libc docs [FIXME: not yet described there] ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs #Additional libraries. # Minimalistic printf version PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min # Floating point printf version (requires MATH_LIB = -lm below) PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt PRINTF_LIB = # Minimalistic scanf version SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min # Floating point + %[ scanf version (requires MATH_LIB = -lm below) SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt SCANF_LIB = MATH_LIB = -lm # External memory options # 64 KB of external RAM, starting after internal RAM (ATmega128!), # used for variables (.data/.bss) and heap (malloc()). #EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff # 64 KB of external RAM, starting after internal RAM (ATmega128!), # only used for heap (malloc()). #EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff EXTMEMOPTS = # Linker flags. # -Wl,...: tell GCC to pass this to linker. # -Map: create map file # --cref: add cross reference to map file LDFLAGS = -Wl,-Map=$(TARGET).map,--cref LDFLAGS += $(EXTMEMOPTS) LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) # Programming support using avrdude. Settings and variables. # Programming hardware: alf avr910 avrisp bascom bsd # dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 # # Type: avrdude -c ? # to get a full listing. # AVRDUDE_PROGRAMMER = stk500 # com1 = serial port. Use lpt1 to connect to parallel port. AVRDUDE_PORT = com1 # programmer connected to serial device AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex #AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep # Uncomment the following if you want avrdude's erase cycle counter. # Note that this counter needs to be initialized first using -Yn, # see avrdude manual. #AVRDUDE_ERASE_COUNTER = -y # Uncomment the following if you do /not/ wish a verification to be # performed after programming the device. #AVRDUDE_NO_VERIFY = -V # Increase verbosity level. Please use this when submitting bug # reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> # to submit bug reports. #AVRDUDE_VERBOSE = -v -v AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) # --------------------------------------------------------------------------- # Define directories, if needed. #DIRAVR = c:/winavr #DIRAVRBIN = $(DIRAVR)/bin #DIRAVRUTILS = $(DIRAVR)/utils/bin #DIRINC = . #DIRLIB = $(DIRAVR)/avr/lib # Define programs and commands. SHELL = sh CC = avr-gcc OBJCOPY = avr-objcopy OBJDUMP = avr-objdump SIZE = avr-size NM = avr-nm AVRDUDE = avrdude REMOVE = rm -f COPY = cp # Define Messages # English MSG_ERRORS_NONE = Errors: none MSG_BEGIN = -------- begin -------- MSG_END = -------- end -------- MSG_SIZE_BEFORE = Size before: MSG_SIZE_AFTER = Size after: MSG_COFF = Converting to AVR COFF: MSG_EXTENDED_COFF = Converting to AVR Extended COFF: MSG_FLASH = Creating load file for Flash: MSG_EEPROM = Creating load file for EEPROM: MSG_EXTENDED_LISTING = Creating Extended Listing: MSG_SYMBOL_TABLE = Creating Symbol Table: MSG_LINKING = Linking: MSG_COMPILING = Compiling: MSG_ASSEMBLING = Assembling: MSG_CLEANING = Cleaning project: # Define all object files. OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) # Define all listing files. LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) # Compiler flags to generate dependency files. GENDEPFLAGS = -Wp,-M,-MP,-MT,$(*F).o,-MF,.dep/$(@F).d # Combine all necessary flags and optional flags. # Add target processor to flags. ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) # Default target. all: begin gccversion sizebefore build sizeafter finished end build: elf hex eep lss sym elf: $(TARGET).elf hex: $(TARGET).hex eep: $(TARGET).eep lss: $(TARGET).lss sym: $(TARGET).sym # Eye candy. # AVR Studio 3.x does not check make's exit code but relies on # the following magic strings to be generated by the compile job. begin: @echo @echo $(MSG_BEGIN) finished: @echo $(MSG_ERRORS_NONE) end: @echo $(MSG_END) @echo # Display size of file. HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex ELFSIZE = $(SIZE) -A $(TARGET).elf sizebefore: @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi sizeafter: @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi # Display compiler version information. gccversion : @$(CC) --version # Program the device. #program: $(TARGET).hex $(TARGET).eep # $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) #$(AVRDUDE_WRITE_EEPROM) # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. COFFCONVERT=$(OBJCOPY) --debugging \ --change-section-address .data-0x800000 \ --change-section-address .bss-0x800000 \ --change-section-address .noinit-0x800000 \ --change-section-address .eeprom-0x810000 coff: $(TARGET).elf @echo @echo $(MSG_COFF) $(TARGET).cof $(COFFCONVERT) -O coff-avr $< $(TARGET).cof extcoff: $(TARGET).elf @echo @echo $(MSG_EXTENDED_COFF) $(TARGET).cof $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof # Create final output files (.hex, .eep) from ELF output file. %.hex: %.elf @echo @echo $(MSG_FLASH) $@ $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ %.eep: %.elf @echo @echo $(MSG_EEPROM) $@ -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ # Create extended listing file from ELF output file. %.lss: %.elf @echo @echo $(MSG_EXTENDED_LISTING) $@ $(OBJDUMP) -h -S $< > $@ # Create a symbol table from ELF output file. %.sym: %.elf @echo @echo $(MSG_SYMBOL_TABLE) $@ $(NM) -n $< > $@ # Link: create ELF output file from object files. .SECONDARY : $(TARGET).elf .PRECIOUS : $(OBJ) %.elf: $(OBJ) @echo @echo $(MSG_LINKING) $@ $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) # Compile: create object files from C source files. %.o : %.c @echo @echo $(MSG_COMPILING) $< $(CC) -c $(ALL_CFLAGS) $< -o $@ # Compile: create assembler files from C source files. %.s : %.c $(CC) -S $(ALL_CFLAGS) $< -o $@ # Assemble: create object files from assembler source files. %.o : %.S @echo @echo $(MSG_ASSEMBLING) $< $(CC) -c $(ALL_ASFLAGS) $< -o $@ # Target: clean project. clean: begin clean_list finished end clean_list : @echo @echo $(MSG_CLEANING) $(REMOVE) $(TARGET).hex $(REMOVE) $(TARGET).eep $(REMOVE) $(TARGET).obj $(REMOVE) $(TARGET).cof $(REMOVE) $(TARGET).elf $(REMOVE) $(TARGET).map $(REMOVE) $(TARGET).obj $(REMOVE) $(TARGET).a90 $(REMOVE) $(TARGET).sym $(REMOVE) $(TARGET).lnk $(REMOVE) $(TARGET).lss $(REMOVE) $(OBJ) $(REMOVE) $(LST) $(REMOVE) $(SRC:.c=.s) $(REMOVE) $(SRC:.c=.d) $(REMOVE) .dep/* # Include the dependency files. -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) # Listing of phony targets. .PHONY : all begin finish end sizebefore sizeafter gccversion \ build elf hex eep lss sym coff extcoff \ clean clean_list #clean clean_list program ---end--- */
Created attachment 7378 [details] main.c (with embedded commented out main.lss and makefile)
char ss = s % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> This is not wrong as we sign extend the arguments as required by the C standard (to int). So this is just an missed-optimization.
Subject: Re: wrong built-in functions selected Nope, please look at the coded examples: - they demonstrate that: (signed char) % (signed char) => invokes (int) % (int), not correct. - and the compiler consistently treats rhs immediate value differently than lhs immediate values for some non-descript reason? (arguably, it should assume all immediate values are ints unless cast/specified otherwise, but that's not what it does, nor does it properly treat lhs operands as signed chars even if properly explicitly cast. Thanks, -paul- > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 19 Oct 2004 20:39:44 -0000 > To: <schlie@comcast.net> > Subject: [Bug target/18065] wrong built-in functions selected > > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-19 > 20:39 ------- > char ss = s % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> > This is not wrong as we sign extend the arguments as required by the C > standard (to int). > > So this is just an missed-optimization. > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Severity|critical |minor > Component|c |target > Keywords| |missed-optimization > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Subject: Re: wrong built-in functions selected As of course otherwise then, what's the purpose of s/u 8-bit / and % built-in functions, if not to enable their use when all the operands are type compatible, minimally explicitly and ideally when type compatible? -paul- > From: schlie at comcast dot net <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 19 Oct 2004 21:18:17 -0000 > To: <schlie@comcast.net> > Subject: [Bug target/18065] wrong built-in functions selected > > > ------- Additional Comments From schlie at comcast dot net 2004-10-19 21:18 > ------- > Subject: Re: wrong built-in functions selected > > Nope, please look at the coded examples: > > - they demonstrate that: > > (signed char) % (signed char) => invokes (int) % (int), not correct. > > - and the compiler consistently treats rhs immediate value differently > than lhs immediate values for some non-descript reason? (arguably, > it should assume all immediate values are ints unless cast/specified > otherwise, but that's not what it does, nor does it properly treat > lhs operands as signed chars even if properly explicitly cast. > > Thanks, -paul- > >> From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> >> Reply-To: <gcc-bugzilla@gcc.gnu.org> >> Date: 19 Oct 2004 20:39:44 -0000 >> To: <schlie@comcast.net> >> Subject: [Bug target/18065] wrong built-in functions selected >> >> >> ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-19 >> 20:39 ------- >> char ss = s % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> >> This is not wrong as we sign extend the arguments as required by the C >> standard (to int). >> >> So this is just an missed-optimization. >> >> -- >> What |Removed |Added >> ---------------------------------------------------------------------------- >> Severity|critical |minor >> Component|c |target >> Keywords| |missed-optimization >> >> >> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 >> >> ------- You are receiving this mail because: ------- >> You reported the bug, or are watching the reporter. > > > > > -- > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
I don't know but as I said this is correct code and not a wrong code problem but just a missed optimization somewhere.
Subject: Re: not using qi version of divmod I agree that the missed optimizations won't produce incorrect results, just very inefficient ones. As all rhs argument optimizations seem to be properly identified, and yet no lhs's are; it would imply to me that where ever in gcc argument signatures are being computed or used for the purpose of built-in function selection, it's inappropriately ignoring lhs argument type compatibility; would you agree with that somewhat crude assessment? Thanks again,-paul- > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 19 Oct 2004 21:39:27 -0000 > To: <schlie@comcast.net> > Subject: [Bug target/18065] not using qi version of divmod > > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-19 > 21:39 ------- > I don't know but as I said this is correct code and not a wrong code problem > but just a missed > optimization somewhere. > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Status|UNCONFIRMED |NEW > Ever Confirmed| |1 > GCC build triplet|powerpc-apple-darwin7.5.0 | > GCC host triplet|powerpc-apple-darwin7.5.0 | > Last reconfirmed|0000-00-00 00:00:00 |2004-10-19 21:39:26 > date| | > Summary|wrong built-in functions |not using qi version of > |selected |divmod > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Bug #10733 is related.
Subject: Re: not using qi version of divmod Hi Eric, Out of curiosity, what exactly is the 10733 bug, is wrong result computed? If so, that implies that divmodhi is broken; otherwise it's not a bug, as the intermediate (t1 + 40) expression yields an int result, as within the context of the expression, although t1 is an unsigned char, there's no guarantee that (t1 + 40) will not overflow an unsigned char size, therefore properly assumed to be an int; unlike t1 = t1 % 3 or whatever, where all operands are clearly type compatible with unsigned char, and a valid optimization. -paul- > From: ericw at evcohs dot com <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 19 Oct 2004 22:08:15 -0000 > To: <schlie@comcast.net> > Subject: [Bug target/18065] not using qi version of divmod > > > ------- Additional Comments From ericw at evcohs dot com 2004-10-19 22:08 > ------- > Bug #10733 is related. > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > CC| |ericw at evcohs dot com > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Subject: Re: not using qi version of divmod schlie at comcast dot net wrote: >------- Additional Comments From schlie at comcast dot net 2004-10-19 22:31 ------- >Subject: Re: not using qi version of divmod > >Hi Eric, > >Out of curiosity, what exactly is the 10733 bug, is wrong result computed? > >If so, that implies that divmodhi is broken; otherwise it's not a bug, as >the intermediate (t1 + 40) expression yields an int result, as within the >context of the expression, although t1 is an unsigned char, there's no >guarantee that (t1 + 40) will not overflow an unsigned char size, therefore >properly assumed to be an int; unlike t1 = t1 % 3 or whatever, where all >operands are clearly type compatible with unsigned char, and a valid >optimization. > > Bug #10733 is a wrong-code bug involving the modulus operator on the AVR target. See the bug report itself for more information. Eric
Subject: Re: wrong code emitted Hi Andrew, Please correct the failure mode description to " critical, wrong code", as upon reviewing the avr.md file, it's now clear that this isn't a "missed optimization"; GCC is failing to properly emit the instruction explicitly matching it's specified QI mode operand constraints as specified by a corresponding identically constrained C statement; more specifically: (this behavior should be deterministic, and relies on no optimizations) The explicit C declaration statement (which also fails for %): signed char ss = (signed char)s / (signed char)s ; Incorrectly emits an HI vs. QI mode instruction as specified avr.md //uses <__divmodhi4> wrong, should be 8-bit <__divmodqi4> ce: 99 81 ldd r25, Y+1 ; 0x01 d0: 89 81 ldd r24, Y+1 ; 0x01 d2: 28 2f mov r18, r24 d4: 33 27 eor r19, r19 d6: 27 fd sbrc r18, 7 d8: 30 95 com r19 da: 89 2f mov r24, r25 dc: 99 27 eor r25, r25 de: 87 fd sbrc r24, 7 e0: 90 95 com r25 e2: b9 01 movw r22, r18 e4: 0e 94 81 01 call __divmodhi4 e8: 6b 83 std Y+3, r22 ; 0x03 Where the corresponding avr.md specifications are: (define_expand "divmodqi4" [(set (reg:QI 24) (match_operand:QI 1 "register_operand" "")) (set (reg:QI 22) (match_operand:QI 2 "register_operand" "")) (parallel [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22))) (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 22)) (clobber (reg:QI 23))]) (set (match_operand:QI 0 "register_operand" "") (reg:QI 24)) (set (match_operand:QI 3 "register_operand" "") (reg:QI 25))] "" "") (define_insn "*divmodqi4_call" [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22))) (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 22)) (clobber (reg:QI 23))] "" "%~call __divmodqi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) (define_expand "divmodhi4" [(set (reg:HI 24) (match_operand:HI 1 "register_operand" "")) (set (reg:HI 22) (match_operand:HI 2 "register_operand" "")) (parallel [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22))) (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 26)) (clobber (reg:QI 21))]) (set (match_operand:HI 0 "register_operand" "") (reg:HI 22)) (set (match_operand:HI 3 "register_operand" "") (reg:HI 24))] "" "") (define_insn "*divmodhi4_call" [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22))) (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 26)) (clobber (reg:QI 21))] "" "%~call __divmodhi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) Which seems correct, but for some reason GCC is not able to recognize when it's lhs operand is a QI mode operand when attempting to match this specification when emitting code? Thanks again, -paul- > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 19 Oct 2004 20:39:44 -0000 > To: <schlie@comcast.net> > Subject: [Bug target/18065] wrong built-in functions selected > > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-19 > 20:39 ------- > char ss = s % s ; //<__divmodhi4> wrong, should be 8-bit <__divmodqi4> > This is not wrong as we sign extend the arguments as required by the C > standard (to int). > > So this is just an missed-optimization. > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Severity|critical |minor > Component|c |target > Keywords| |missed-optimization > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
From C99 (6.5.5/3): The usual arithmetic conversions are performed on the operands. 6.3.1.8 Usual arithmetic conversions Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands: If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank. Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type. Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type. Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type. This is still not wrong code as signed char signed extended to int is still the same number but this is not a target problem but a front-end problem now. To make sure that I read the statement correctly from the standard, it says if the types are the same there is no need to promote the value at all.
Subject: Re: usual arithmetic conversion not applying correctly Please read rule 1: "If both operands have the same type, then no further conversion is needed." (no promotion to int is specified or implied as being required) Seems plain enough to me, what makes you think that: char + char => int + int ? short + short => int + int ? That would imply, QI mode (and HI mode typical of shorts on 32 bit machines) rtl instruction definitions are meaningless which isn't the case; as their definition defines the char and short operand rtl operator -> code transformation. The front end has no business promoting all char and short arithmetic operands to ints, and in fact it doesn't; so am not sure what your thinking? -paul- > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 20 Oct 2004 18:50:01 -0000 > To: <schlie@comcast.net> > Subject: [Bug c/18065] usual arithmetic conversion not applying correctly > > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-20 > 18:50 ------- > From C99 > (6.5.5/3): The usual arithmetic conversions are performed on the operands. > > 6.3.1.8 Usual arithmetic conversions > Otherwise, the integer promotions are performed on both operands. Then the > following rules are > applied to the promoted operands: If both operands have the same type, then no > further conversion is > needed. Otherwise, if both operands have signed integer types or both have > unsigned integer types, the > operand with the type of lesser integer conversion rank is converted to the > type of the operand with > greater rank. Otherwise, if the operand that has unsigned integer type has > rank greater or equal to the > rank of the type of the other operand, then the operand with signed integer > type is converted to the > type of the operand with unsigned integer type. Otherwise, if the type of the > operand with signed > integer type can represent all of the values of the type of the operand with > unsigned integer type, then > the operand with unsigned integer type is converted to the type of the operand > with signed integer > type. Otherwise, both operands are converted to the unsigned integer type > corresponding to the type of > the operand with signed integer type. > > This is still not wrong code as signed char signed extended to int is still > the same number but this is > not a target problem but a front-end problem now. > > To make sure that I read the statement correctly from the standard, it says if > the types are the same > there is no need to promote the value at all. > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Severity|minor |normal > Component|target |c > Summary|not using qi version of |usual arithmetic conversion > |divmod |not applying correctly > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
But the front-end is doing the promotions where the problem comes from, nowhere else (I am using 4.0 to verify my claim that the front-end is actually doing the promotion).
The promotion is coming from: if (convert_p) { op0 = default_conversion (orig_op0); op1 = default_conversion (orig_op1); } else { op0 = orig_op0; op1 = orig_op1; } Maybe this should be changed ....
And the reason why we don't shoten back to signed char % signed char: /* Although it would be tempting to shorten always here, that loses on some targets, since the modulo instruction is undefined if the quotient can't be represented in the computation mode. We shorten only if unsigned or if dividing by something we know != -1. */ So maybe this is correct.
Subject: Re: usual arithmetic conversion not applying correctly Maybe the confusion is that you're not recognizing that: char, short, int, long, long long, are all integer types, with different storage formats. As opposed to enum or bit-field for example which should likely be converted to an "integer type" with ideally the smallest and/or most efficient representation specified for the machine, prior to an "integer" oriented operation being performed. ??? -paul- > From: Paul Schlie <schlie@comcast.net> > Date: Wed, 20 Oct 2004 15:14:08 -0400 > To: <gcc-bugzilla@gcc.gnu.org> > Subject: Re: [Bug c/18065] usual arithmetic conversion not applying correctly > > Please read rule 1: > > "If both operands have the same type, then no further conversion is > needed." (no promotion to int is specified or implied as being required) > > Seems plain enough to me, what makes you think that: > > char + char => int + int ? > short + short => int + int ? > > That would imply, QI mode (and HI mode typical of shorts on 32 bit machines) > rtl instruction definitions are meaningless which isn't the case; as their > definition defines the char and short operand rtl operator -> code > transformation. > > The front end has no business promoting all char and short arithmetic operands > to ints, and in fact it doesn't; so am not sure what your thinking? > > -paul- > >> From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> >> Reply-To: <gcc-bugzilla@gcc.gnu.org> >> Date: 20 Oct 2004 18:50:01 -0000 >> To: <schlie@comcast.net> >> Subject: [Bug c/18065] usual arithmetic conversion not applying correctly >> >> >> ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-20 >> 18:50 ------- >> From C99 >> (6.5.5/3): The usual arithmetic conversions are performed on the operands. >> >> 6.3.1.8 Usual arithmetic conversions >> Otherwise, the integer promotions are performed on both operands. Then the >> following rules are >> applied to the promoted operands: If both operands have the same type, then >> no >> further conversion is >> needed. Otherwise, if both operands have signed integer types or both have >> unsigned integer types, the >> operand with the type of lesser integer conversion rank is converted to the >> type of the operand with >> greater rank. Otherwise, if the operand that has unsigned integer type has >> rank greater or equal to the >> rank of the type of the other operand, then the operand with signed integer >> type is converted to the >> type of the operand with unsigned integer type. Otherwise, if the type of the >> operand with signed >> integer type can represent all of the values of the type of the operand with >> unsigned integer type, then >> the operand with unsigned integer type is converted to the type of the >> operand >> with signed integer >> type. Otherwise, both operands are converted to the unsigned integer type >> corresponding to the type of >> the operand with signed integer type. >> >> This is still not wrong code as signed char signed extended to int is still >> the same number but this is >> not a target problem but a front-end problem now. >> >> To make sure that I read the statement correctly from the standard, it says >> if >> the types are the same >> there is no need to promote the value at all. >> >> -- >> What |Removed |Added >> ---------------------------------------------------------------------------- >> Severity|minor |normal >> Component|target |c >> Summary|not using qi version of |usual arithmetic conversion >> |divmod |not applying correctly >> >> >> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 >> >> ------- You are receiving this mail because: ------- >> You reported the bug, or are watching the reporter.
When I am talking about promoting means that we add casts. aka sc%sc gets changed to (signed char) (((int)sc)%((int)sc)).
Subject: Re: usual arithmetic conversion not applying correctly Andrew, Yes, and with respect to / and % operations: - the modulo/reminder result can always be represented in the same type and size as its divisor/modulus operand, regardless of the dividend's type and size. - the quotient result can always be represented in the same type and size as it's dividend, if it's divisor/modulus operand is unsigned, otherwise ideally to be promoted to it's next larger signed type to preserve accuracy if useful, but typically irrelevant, as operator result precision is in most practical circumstances determined by the precision of the result's need, therefore in typical cases like int = int / int no value is derived from pretending to preserve idealized accuracy, therefore CPU's typically implement instructions to yield the equivalent results that would have been attained if the precision were maintained, and then simply truncated when assigned to it's destination type for typical integer operations but mark an under or overflow flag, just as int = int + int; would overflow; therefore for all practical purposes, integer operands should never be promoted beyond their need, nor should operation precision be required beyond it's result's need. (and just to double check, this needs to get fixed on 3.4.3 too, which I honestly suspect is related to the rtl interpretation, as other QI mode instruction specifications are properly matched as expected.) (also it's likely that these type of problems predominantly express themselves on small target machines, as on larger 32/64 bit machines, operations physically occur on correspondingly wide cpu's, therefore don't enable inappropriate operand promotion errors to be easily observable.) -paul- > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 20 Oct 2004 19:29:13 -0000 > To: <schlie@comcast.net> > Subject: [Bug c/18065] usual arithmetic conversion not applying correctly > > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-20 > 19:29 ------- > And the reason why we don't shoten back to signed char % signed char: > > /* Although it would be tempting to shorten always here, that loses > on some targets, since the modulo instruction is undefined if the > quotient can't be represented in the computation mode. We shorten > only if unsigned or if dividing by something we know != -1. */ > > So maybe this is correct. > > -- > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
As I have said before, this has nothing to RTL, only the front-end. Read the code which I copied from the GCC, this is in the front-end.
Subject: Re: usual arithmetic conversion not applying correctly On Wed, 20 Oct 2004, pinskia at gcc dot gnu dot org wrote: > Otherwise, the integer promotions are performed on both operands. Then > the following rules are applied to the promoted operands: If both > operands have the same type, then no further conversion is needed. The integer promotions are where signed char is promoted to int. Only after then are types compared. It is not the job of the front end to optimise code. The front end should generate datastructures corresponding exactly to the specified semantics of the language, including the promotions in this case. Subsequent passes, preferably on GIMPLE but maybe including fold at present, can deal with eliminating conversions not needed for code generation.
Subject: Re: usual arithmetic conversion not applying correctly Andrew, And if it's already declared as, or cast to signed char's in the code? unsigned char x, y ; (signed char)x = (signed char)x / (signed char)y ; -or- (should yield identical code, and require no promotions or conversions) signed char x, y ; x = x / y ; the only arguable possible type conversion that may be required ; would be to convert the result of (x / y) which may have been ; implemented by the target machine as having a wider result, but ; not required if it's destination storage does not require it. (there's no reason to ever muck with specified object types unless it's value needs to converted as required for assignment, or the specified semantics of an operation; but even then, the type of the object doesn't change, although the its value's representation may if required.) -paul- > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 20 Oct 2004 19:54:55 -0000 > To: <schlie@comcast.net> > Subject: [Bug c/18065] usual arithmetic conversion not applying correctly > > > ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-20 > 19:54 ------- > When I am talking about promoting means that we add casts. aka sc%sc gets > changed to (signed char) > (((int)sc)%((int)sc)). > > -- > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Subject: Re: usual arithmetic conversion not applying correctly Andrew, It has nothing to do with "optimizing code", if the 3.X and 4.X front-ends are promoting the size of anything other than bool, enum, or bit-field operand values without explicit need, they're doing so in error, and in contradiction to the standard's semantics. (could you please check on this, as it should be clear that it's wrong, although may have gone unnoticed as most of GCC's targets are 32+ bit machines, and would have escaped detection, as on most larger machines most operations are converted by default to int as that's all they know about, it's only when the result is stored, does the operations required size express itself. It's a pretty major screw-up to presume all target machines are large, and then to encode that presumption into C's front end; not to mention it seems pretty stupid to do, and then worry about trying to optimize operand values into smaller sizes when subsequently realizing that their size promotion was not required, and calling it an optimization; the whole mess is more accurately a de-optimization, and perversion of C's semantics.) Thanks, -paul- > From: jsm at polyomino dot org dot uk <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 20 Oct 2004 21:31:15 -0000 > To: <schlie@comcast.net> > Subject: [Bug c/18065] usual arithmetic conversion not applying correctly > > > ------- Additional Comments From jsm at polyomino dot org dot uk 2004-10-20 > 21:31 ------- > Subject: Re: usual arithmetic conversion not applying correctly > > On Wed, 20 Oct 2004, pinskia at gcc dot gnu dot org wrote: > >> Otherwise, the integer promotions are performed on both operands. Then >> the following rules are applied to the promoted operands: If both >> operands have the same type, then no further conversion is needed. > > The integer promotions are where signed char is promoted to int. Only > after then are types compared. > > It is not the job of the front end to optimise code. The front end should > generate datastructures corresponding exactly to the specified semantics > of the language, including the promotions in this case. Subsequent > passes, preferably on GIMPLE but maybe including fold at present, can deal > with eliminating conversions not needed for code generation. > > -- > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
That was not me writting that but a C front-end person so why did you write Andrew?
Subject: Re: usual arithmetic conversion not applying correctly On Wed, 20 Oct 2004, schlie at comcast dot net wrote: > It's a pretty major screw-up to presume > all target machines are large, and then to encode that presumption into > C's front end; not to mention it seems pretty stupid to do, and then This is not a GCC presumption, it is a property of the C language that there are certain promotions that may not be optimally efficient for 8-bit targets. If there is a "major screw-up", it is either in the choice to use a language designed for systems that are at least 16-bit on an 8-bit target, or in the language design if you think 8-bit targets should have been given greater importance when the language was being standardised in the 1980s; it is nothing to do with the front end. The AVR target has a -mint8 option which puts the compiler in a nonconforming mode with 8-bit int, which might however give you better code than you can get with standard C on an 8-bit target.
Subject: Re: C integer promotion semantics / front end problems. I presume you sent your message directly to me by mistake, so am sending the reply back to the bug database so it can benefit more than one person. Technical messages about public GCC versions should, absent any more specific support arrangements in a particular case, go to the mailing lists, not individuals; questions are answered in public GCC development for the benefit of the public. On Wed, 20 Oct 2004, Paul Schlie wrote: > Sorry to do this to you again, but where do you see in the standard the > requirement to promote, or license to needlessly promote all operands > to int? C99 subclause 6.3.1.1 paragraph 2. signed char has rank less than that of int, so it *must* be promoted to int. What happens afterwards is nothing to do with the front end. The front end does *too many* optimisations; it should purely generate GIMPLE representing the standard meaning of the code and leave it to the later stages to tell that such conversions - or indeed conversions between int and long where they are the same size - can be optimised away in some cases.
Subject: Re: usual arithmetic conversion not applying correctly What size promotion is required for char sized integer operations? I see none? What size promotion is required for short sized integer operations? I see none? The standard's refers to (as below earlier already referenced by Andrew): - "integer" promotion is performed on both operands, and then further size and/or sign-type converted as required if the operands aren't already of the same "integer" type. "integer type" not "int"; char, short, int, long are "integer types" of different rank, yes? The only primitive storage classes in C which aren't intrinsically an "integer type" are: bool, enum, and bit-fields to my knowledge, which require implicit promotion to an "integer type" to be operated on. Even if you said that char's aren't "integer types" it's easy enough to define short as having the same size as char, thereby promote char->short which is surely an "integer type", although char's already are. Where am I missing it? From C99 (6.5.5/3): The usual arithmetic conversions are performed on the operands. 6.3.1.8 Usual arithmetic conversions Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands: If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank. Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type. Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type. Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type. > From: jsm at polyomino dot org dot uk <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 20 Oct 2004 22:41:59 -0000 > To: <schlie@comcast.net> > Subject: [Bug tree-optimization/18065] usual arithmetic conversion not > applying correctly > > > ------- Additional Comments From jsm at polyomino dot org dot uk 2004-10-20 > 22:41 ------- > Subject: Re: usual arithmetic conversion not applying correctly > > On Wed, 20 Oct 2004, schlie at comcast dot net wrote: > >> It's a pretty major screw-up to presume >> all target machines are large, and then to encode that presumption into >> C's front end; not to mention it seems pretty stupid to do, and then > > This is not a GCC presumption, it is a property of the C language that > there are certain promotions that may not be optimally efficient for 8-bit > targets. If there is a "major screw-up", it is either in the choice to > use a language designed for systems that are at least 16-bit on an 8-bit > target, or in the language design if you think 8-bit targets should have > been given greater importance when the language was being standardised in > the 1980s; it is nothing to do with the front end. The AVR target has a > -mint8 option which puts the compiler in a nonconforming mode with 8-bit > int, which might however give you better code than you can get with > standard C on an 8-bit target. > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Subject: Re: usual arithmetic conversion not applying correctly Ok, a more basic observation/recommendation: the front end should not be masking true operand types by promoting them prematurely, as it generates very little value, while needlessly complicating the back-end's ability to easily generate optimal code for non-integer width machines; as with efficient access to the true source operand precision, and true operation result precision requirements, the back end can then easily and directly leverage the target's rtl machine description to generate fully conforming precision code, with out the burden of having to back-out prematurely applied type conversions (which seem wholly counterproductive). (which of course is the point of being able to specify optimal QI, and in many cases HI mode rtl instruction mappings, which have been made much less efficient by the front-end's choice to needlessly prematurely type promote operands prior to the literal requirement to do so.) Thanks for hearing me out, and by the way this whole discussion began by observing that GCC was not utilizing efficient rtl QI mode instruction descriptions, resulting in the classification of the bug as a "missed optimization" bug, as opposed to an "incorrect code" bug, with the explanation that although the source and destination operands specified in C could be implemented as specified in the rtl instruction mapping specification and be fully conforming, it wasn't recognized because the back-end didn't find the "optimization" because the front-end needlessly prematurely type converted all operands passed to the back-end. And for what little it may be worth, for good or bad, the factual reality is that there are 100's of times more small processors programmed and deployed in products than there are 32+ bit processors, therefore it would be nice if GCC didn't needless restrict itself to being most optimally applicable to larger machines at the expense of smaller machines (as there far more commercial 8 and 16 bit processors available from companies interested in support than their are 32-64 bit processor companies, and likely to remain that way, so it's not likely good business to bite the hand that may feed you). -paul- > From: jsm at polyomino dot org dot uk <gcc-bugzilla@gcc.gnu.org> > Reply-To: <gcc-bugzilla@gcc.gnu.org> > Date: 20 Oct 2004 23:03:15 -0000 > To: <schlie@comcast.net> > Subject: [Bug tree-optimization/18065] usual arithmetic conversion not > applying correctly > > > ------- Additional Comments From jsm at polyomino dot org dot uk 2004-10-20 > 23:03 ------- > Subject: Re: C integer promotion semantics / > front end problems. > > I presume you sent your message directly to me by mistake, so am sending > the reply back to the bug database so it can benefit more than one person. > Technical messages about public GCC versions should, absent any more > specific support arrangements in a particular case, go to the mailing > lists, not individuals; questions are answered in public GCC development > for the benefit of the public. > > On Wed, 20 Oct 2004, Paul Schlie wrote: > >> Sorry to do this to you again, but where do you see in the standard the >> requirement to promote, or license to needlessly promote all operands >> to int? > > C99 subclause 6.3.1.1 paragraph 2. signed char has rank less than that of > int, so it *must* be promoted to int. What happens afterwards is nothing > to do with the front end. The front end does *too many* optimisations; it > should purely generate GIMPLE representing the standard meaning of the > code and leave it to the later stages to tell that such conversions - or > indeed conversions between int and long where they are the same size - can > be optimised away in some cases. > > -- > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Subject: Re: usual arithmetic conversion not applying correctly Andrew, So regardless of the all other things, it seems minimally clear that the promotion code as it stands now should allow the required result type to be shortened to the size and type of the modulus operand for modulus operations; and to the size and type of the dividend operand if the divisor is unsigned, and the required result precision promoted to the next larger signed type otherwise (although not strictly required if the true destination's precision requirement is less). Which should address the short term problem associated with type promotion being done by the front end. -paul- > From: Paul Schlie <schlie@comcast.net> > Date: Wed, 20 Oct 2004 17:19:24 -0400 > To: <gcc-bugzilla@gcc.gnu.org> > Subject: Re: [Bug c/18065] usual arithmetic conversion not applying correctly > > Andrew, > > Yes, and with respect to / and % operations: > > - the modulo/reminder result can always be represented in the same type > and size as its divisor/modulus operand, regardless of the dividend's > type and size. > > - the quotient result can always be represented in the same type and size > as it's dividend, if it's divisor/modulus operand is unsigned, otherwise > ideally to be promoted to it's next larger signed type to preserve > accuracy if useful, but typically irrelevant, as operator result > precision is in most practical circumstances determined by the precision > of the result's need, therefore in typical cases like int = int / int > no value is derived from pretending to preserve idealized accuracy, > therefore CPU's typically implement instructions to yield the equivalent > results that would have been attained if the precision were maintained, > and then simply truncated when assigned to it's destination type for > typical integer operations but mark an under or overflow flag, just as > int = int + int; would overflow; therefore for all practical purposes, > integer operands should never be promoted beyond their need, nor should > operation precision be required beyond it's result's need. > > (and just to double check, this needs to get fixed on 3.4.3 too, which > I honestly suspect is related to the rtl interpretation, as other QI > mode instruction specifications are properly matched as expected.) > > (also it's likely that these type of problems predominantly express > themselves on small target machines, as on larger 32/64 bit machines, > operations physically occur on correspondingly wide cpu's, therefore > don't enable inappropriate operand promotion errors to be easily > observable.) > > -paul- > >> From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> >> Reply-To: <gcc-bugzilla@gcc.gnu.org> >> Date: 20 Oct 2004 19:29:13 -0000 >> To: <schlie@comcast.net> >> Subject: [Bug c/18065] usual arithmetic conversion not applying correctly >> >> >> ------- Additional Comments From pinskia at gcc dot gnu dot org 2004-10-20 >> 19:29 ------- >> And the reason why we don't shoten back to signed char % signed char: >> >> /* Although it would be tempting to shorten always here, that loses >> on some targets, since the modulo instruction is undefined if the >> quotient can't be represented in the computation mode. We shorten >> only if unsigned or if dividing by something we know != -1. */ >> >> So maybe this is correct. >> >> -- >> >> >> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 >> >> ------- You are receiving this mail because: ------- >> You reported the bug, or are watching the reporter.
> And for what little it may be worth, for good or bad, the factual reality > is that there are 100's of times more small processors programmed and > deployed in products than there are 32+ bit processors, therefore it would > be nice if GCC didn't needless restrict itself to being most optimally > applicable to larger machines at the expense of smaller machines (as there > far more commercial 8 and 16 bit processors available from companies > interested in support than their are 32-64 bit processor companies, and > likely to remain that way, so it's not likely good business to bite the > hand that may feed you). Just to have this (obvious) fact mentioned in this thread also: as a developer starved project, we are always grateful for patches people may send that improve the behavior of gcc. Your company may also be interested in hiring gcc developers to implement features you need. W.
Created attachment 7421 [details] proposed patch This fixes most of the missed div/mod operation shortening opportunites, execept those which GCC's shortening logic misses the opportunity to perform. (sorry, but the patch needs to me semi-manually applied to two different nearly identical locations to handle both div and mod ops within the switch cases within build_binary_op() within c-typeck.c).
(although not the most elegant fix) This fixes the rest of the problem, as there's no reaon to default promote smaller than int sized integers to int, they will end up being promoted if required by the back-end if the target requires them to be (also should not need to litterally promote enum's and bool beyond the smallest int type with suffecient to represent it's value range): (called via default_conversion() to determine if an expression should be converted by default to int) *** In File: c-common.c *** bool c_promoting_integer_type_p (tree t) { switch (TREE_CODE (t)) { - case INTEGER_TYPE: - return (TYPE_MAIN_VARIANT (t) == char_type_node - || TYPE_MAIN_VARIANT (t) == signed_char_type_node - || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node - || TYPE_MAIN_VARIANT (t) == short_integer_type_node - || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node - || TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node)); pws--*/ - case ENUMERAL_TYPE: /* ??? Technically all enumerations not larger than an int promote to an int. But this is used along code paths that only want to notice a size change. */ return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node); case BOOLEAN_TYPE: return 1; default: return 0; } } *** end ***
Subject: Re: usual arithmetic conversion not applying correctly Wonder if this PR could still be considered a missed optimization, as the present logic which determines if an / or % expression's operands may be shortened, misses the case where if the lhs operand is a constant, it may be verified as not being INT_MIN; as if it's not, then it's impossible for the operation to overflow, i.e. INT_MIN / -1 => INT_MAX+1, therefore may be shortened. As noted as being absent in it's comment on shortening: /* Although it would be tempting to shorten always here, that loses on some targets, since the modulo instruction is undefined if the quotient can't be represented in the computation mode. We shorten only if unsigned or if dividing by something we know != -1. */ > From: pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> > Subject: [Bug tree-optimization/18065] usual arithmetic conversion not > applying correctly > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Severity|normal |enhancement > Priority|P1 |P3 > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065
Subject: Re: usual arithmetic conversion not applying correctly > From: schlie at comcast dot net <gcc-bugzilla@gcc.gnu.org> > ------- Additional Comments From schlie at comcast dot net 2005-01-16 07:16 > Subject: Re: usual arithmetic conversion not applying correctly > > Wonder if this PR could still be considered a missed optimization, as the > present logic which determines if an / or % expression's operands may be > shortened, misses the case where if the lhs operand is a constant, it may > be verified as not being INT_MIN; as if it's not, then it's impossible for > the operation to overflow, i.e. INT_MIN / -1 => INT_MAX+1, therefore > may be shortened. As noted as being absent in it's comment on shortening: > > /* Although it would be tempting to shorten always here, that loses > on some targets, since the modulo instruction is undefined if the > quotient can't be represented in the computation mode. We shorten > only if unsigned or if dividing by something we know != -1. */ - It would be unfortunate if / and % couldn't be somewhat further optimized prior to 4.0 when their lhs operands are known not to be INT_MIN, as they tend to be typically relatively expensive operations, likely benefiting from shortening more than most. > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18065 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter.
Yeah, this is happening because of the type promotion in gcc/c-common.c in the function c_promoting_integer_type_p. See this: /* Nonzero if the type T promotes to int. This is (nearly) the integral promotions defined in ISO C99 6.3.1.1/2. */ bool c_promoting_integer_type_p (const_tree t) { switch (TREE_CODE (t)) { case INTEGER_TYPE: return (TYPE_MAIN_VARIANT (t) == char_type_node || TYPE_MAIN_VARIANT (t) == signed_char_type_node || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node || TYPE_MAIN_VARIANT (t) == short_integer_type_node || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node || TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node)); case ENUMERAL_TYPE: /* ??? Technically all enumerations not larger than an int promote to an int. But this is used along code paths that only want to notice a size change. */ return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node); case BOOLEAN_TYPE: return 1; default: return 0; } } So by commenting the case INTEGER_TYPE, we will get the call to _divmodqi4, but I don't think this is the right thing to do.
In the head c-common.c is placed in gcc/c-family/c-common.c
http://free-online-games-mmorpg.blogspot.co.uk/