Bug 18065

Summary: usual arithmetic conversion not applying correctly
Product: gcc Reporter: Paul Schlie <schlie>
Component: tree-optimizationAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: enhancement CC: abnikant.singh, berndtrog, eric.weddington, gcc-bugs, sascha-web-gcc.gnu.org
Priority: P3 Keywords: missed-optimization
Version: 3.4.3   
Target Milestone: ---   
Host: Target: avr-unknown-none
Build: Known to work:
Known to fail: Last reconfirmed: 2005-05-01 04:18:52
Attachments: main.c (with embedded commented out main.lss and makefile)
proposed patch

Description Paul Schlie 2004-10-19 20:21:44 UTC
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---

*/
Comment 1 Paul Schlie 2004-10-19 20:27:42 UTC
Created attachment 7378 [details]
main.c (with embedded commented out main.lss and makefile)
Comment 2 Andrew Pinski 2004-10-19 20:39:41 UTC
    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.
Comment 3 Paul Schlie 2004-10-19 21:18:15 UTC
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.


Comment 4 Paul Schlie 2004-10-19 21:31:35 UTC
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.


Comment 5 Andrew Pinski 2004-10-19 21:39:26 UTC
I don't know but as I said this is correct code and not a wrong code problem but just a missed 
optimization somewhere.
Comment 6 Paul Schlie 2004-10-19 21:53:32 UTC
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.


Comment 7 Eric Weddington 2004-10-19 22:08:14 UTC
Bug #10733 is related.
Comment 8 Paul Schlie 2004-10-19 22:31:25 UTC
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.


Comment 9 Eric Weddington 2004-10-19 23:13:19 UTC
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
Comment 10 Paul Schlie 2004-10-20 18:34:44 UTC
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.


Comment 11 Andrew Pinski 2004-10-20 18:50:00 UTC
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.
Comment 12 Paul Schlie 2004-10-20 19:14:15 UTC
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.


Comment 13 Andrew Pinski 2004-10-20 19:18:54 UTC
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).
Comment 14 Andrew Pinski 2004-10-20 19:25:17 UTC
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 ....
Comment 15 Andrew Pinski 2004-10-20 19:29:13 UTC
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.
Comment 16 Paul Schlie 2004-10-20 19:33:44 UTC
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.


Comment 17 Andrew Pinski 2004-10-20 19:54:54 UTC
When I am talking about promoting means that we add casts. aka sc%sc gets changed to (signed char) 
(((int)sc)%((int)sc)).
Comment 18 Paul Schlie 2004-10-20 21:19:33 UTC
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.


Comment 19 Andrew Pinski 2004-10-20 21:25:04 UTC
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.
Comment 20 Joseph S. Myers 2004-10-20 21:31:13 UTC
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.

Comment 21 Paul Schlie 2004-10-20 21:46:48 UTC
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.


Comment 22 Paul Schlie 2004-10-20 22:27:25 UTC
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.


Comment 23 Andrew Pinski 2004-10-20 22:31:54 UTC
That was not me writting that but a C front-end person so why did you write Andrew?
Comment 24 Joseph S. Myers 2004-10-20 22:41:58 UTC
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.

Comment 25 Joseph S. Myers 2004-10-20 23:03:13 UTC
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.

Comment 26 Paul Schlie 2004-10-20 23:28:35 UTC
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.


Comment 27 Paul Schlie 2004-10-21 01:04:46 UTC
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.


Comment 28 Paul Schlie 2004-10-21 01:28:13 UTC
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.


Comment 29 Wolfgang Bangerth 2004-10-21 12:47:11 UTC
> 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. 
Comment 30 Paul Schlie 2004-10-28 09:27:15 UTC
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).
Comment 31 Paul Schlie 2004-12-21 20:50:11 UTC
(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 ***
Comment 32 Paul Schlie 2005-01-16 07:16:54 UTC
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


Comment 33 Paul Schlie 2005-01-16 17:39:03 UTC
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.


Comment 34 abnikant 2010-09-14 07:06:14 UTC
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.
Comment 35 abnikant 2010-09-14 07:13:35 UTC
In the head c-common.c is placed in gcc/c-family/c-common.c
Comment 36 online games 2012-05-24 14:02:07 UTC Comment hidden (spam)
Comment 37 online games 2012-05-24 14:03:12 UTC Comment hidden (spam)
Comment 38 online games 2012-05-24 14:03:48 UTC Comment hidden (spam)
Comment 39 online games 2012-05-24 14:04:22 UTC Comment hidden (spam)