Gcc clumsiness with bitfields: typical or avoidable?

Go To Last Post
55 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I came across an example of GCC generating awkward code while tinkering with a technique for adding valid/invalid status to a subroutine's return value, and offer it for your amusement or suggested alternatives.

The usual approach that my colleagues take in such situations is to make the subroutine's return value carry the pass/fail/other status information, and then make the subroutine store its normal 'answer' through a reference argument that must be added to its parameter list. Pointers-to-variables (especially automatic variables) are expensive and awkward on gcc, though, so I've usually just enlarged the return data type of such routines so that the status can be carried in its 'upper half'. This is kind of kludgey, but picking a desired 8-bit return value out of a 16-bit composite of value-and-status isn't too bad. I thought I'd experiment with formalizing this arrangement with a defined data structure, rather than just using shift operators, so I wrote the following three files to try it out:

// test.c - Test of structure return
#include 
#include "Reception.h"
int main(void) {
    Reception datum = getIIC();
	while (1) {
	    PORTA = datum.valid ? datum.datum : 0;
    }
}
// Reception.h - A toy structure to explore structure-return with
//
#include 
typedef struct Reception {
    uint8_t datum;
    uint8_t sla:1;
    uint8_t valid:1;
} Reception;

extern Reception getIIC(void);
// getIIC.c - a routine that returns a structure
//
#include 
#include "Reception.h"
Reception getIIC(void)
{
    Reception answer;
    answer.datum = PINB;
    answer.sla = 0 != (PINA & (1<<3));
    answer.valid = 0 != (PIND & (1 << 5));

    return answer;
}

I separated the "getIIC()" function into its own file because I wanted to observe the compiler "in its naitive habitat", without it doing inlining.

The above code compiled OK, but I was kind of surprised at how poor the generated code was:

---- getIIC.c ----------------------------------------
7:        {
+00000040:   B386        IN        R24,0x16       In from I/O location
10:       	answer.sla = 0 != (PINA & (1<<3));
+00000041:   B349        IN        R20,0x19
11:       	answer.valid = 0 != (PIND & (1 << 5));
+00000042:   B320        IN        R18,0x10 
13:       	return answer;
+00000043:   E030        LDI       R19,0x00
+00000044:   E055        LDI       R21,0x05
+00000045:   9536        LSR       R19
+00000046:   9527        ROR       R18
+00000047:   955A        DEC       R21
+00000048:   F7E1        BRNE      PC-0x03
+00000049:   7021        ANDI      R18,0x01
+0000004A:   0F22        LSL       R18
+0000004B:   E050        LDI       R21,0x00
+0000004C:   E093        LDI       R25,0x03
+0000004D:   9556        LSR       R21
+0000004E:   9547        ROR       R20
+0000004F:   959A        DEC       R25
+00000050:   F7E1        BRNE      PC-0x03
+00000051:   7041        ANDI      R20,0x01
14:       }
+00000052:   2F92        MOV       R25,R18
+00000053:   2B94        OR        R25,R20
+00000054:   9508        RET
14:       }

, which looked way bloated to me. In assembler, it'd take three statements to handle each field: an "IN", and a "BST; BLD" pair. I experimented for awhile to see if I could find an alternate expression of the general idea that the compiler wouldn't trip over so badly, and came up with these replacements:

typedef struct Reception {
    uint8_t value;
        union info {
            uint8_t s;
            struct bitz {
                uint8_t sla:1;
                uint8_t valid:1;
            } bits;
        } info;
} Reception;

Reception getIIC(void)
{
    Reception answer;
    answer.value = PINB;
    answer.info.s = 0;
    if (PINA & (1 << 3))  answer.info.bits.sla = 1;
    if (PIND & (1 << 5))  answer.info.bits.valid = 1;

    return answer;
}

, which the compiler rendered far more sensibly as:

---- getIIC.c ---------------------------
7:        {
+00000040:   B386        IN        R24,0x16
10:       	answer.info.s = 0;
+00000041:   E090        LDI       R25,0x00
11:       	if (PINA & (1 << 3))  answer.info.bits.sla = 1;
+00000042:   99CB        SBIC      0x19,3 
+00000043:   E091        LDI       R25,0x01
12:       	if (PIND & (1 << 5))  answer.info.bits.valid = 1;
+00000044:   9985        SBIC      0x10,5
+00000045:   6092        ORI       R25,0x02
15:       }
+00000046:   9508        RET 

The code generated for main()'s test of the "valid" bit was pretty awkward, too, but at least it didn't use a runtime shift loop:

---- test.c -------------------------
8:        int main(void) {
+00000036:   940E0040    CALL      0x00000040
11:             PORTA = datum.info.bits.valid ? datum.value : 0;
+00000038:   7092        ANDI      R25,0x02
+00000039:   2399        TST       R25 
+0000003A:   F411        BRNE      PC+0x03
+0000003B:   E020        LDI       R18,0x00
+0000003C:   C001        RJMP      PC+0x0002
+0000003D:   2F28        MOV       R18,R24
+0000003E:   BB2B        OUT       0x1B,R18
+0000003F:   CFF9        RJMP      PC-0x0006
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

that's the price you pay for using a free product.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

millwood wrote:
that's the price you pay for using a free product.
Are you saying that all non-free products will do much better?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ezharkov wrote:
millwood wrote:
that's the price you pay for using a free product.
Are you saying that all non-free products will do much better?
Well, that depends on what do you mean by "product".

If "product" would be "competent assembler programmer" (which, when used regularly, comes at a cost undoubtedly), then yes, the result is invariably much better.

:-D

(Of course the real answer is "this is the price you pay for using a high(ish) level language, and paying for it might influence the frequency how often you come across inefficiency, but given there are infinite combinations of potential sources of inefficiency and only limited amount of money collectivelly paid, it's inevitable from time to time", but that's just the boring truth).

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Levenkay,

It was amusing, thank you.

But the experiment might be more instructive if you would try several versions of avr-gcc.

Jan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried :

#if defined(__GNUC__)
#include 
#elif defined(__CODEVISIONAVR__)
#include 
#elif defined(__IAR_SYSTEMS_ICC__)
#include 
#elif defined(__IMAGECRAFT__)
#include 
#endif
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;

typedef struct Reception {
    uint8_t datum;
    uint8_t sla:1;
    uint8_t valid:1;
} Reception;

extern Reception getIIC(void); 

Reception getIIC(void)
{
    Reception answer;
    answer.datum = PINB;
    answer.sla = 0 != (PINA & (1<<3));
    answer.valid = 0 != (PIND & (1 << 5));

    return answer;
}	  
	   
void main(void)
{
    volatile Reception foo;
    foo = getIIC();
    PORTC = foo.datum;
    while (1) ;
}

Both CV and ImageCraft avoid rotating the bits dynamically. Yes, I would think that avr-gcc could use more intelligence.

OTOH, the cycle count is 139, 162, 62, 42 for CV, ICC, GCC, IAR

CV:

@00000048: getIIC
---- cliff.c --------------------------------------------------------------------------------------
24:           answer.datum = PINB;
+00000048:   SBIW      R28,0x04       
+00000049:   IN        R30,0x16       
+0000004A:   STD       Y+0,R30        
25:           answer.sla = 0 != (PINA & (1<<3));
+0000004B:   IN        R30,0x19       
+0000004C:   ANDI      R30,0x08       
+0000004D:   LDI       R26,0x00       
+0000004E:   CALL      0x00000078     
+00000050:   ANDI      R30,0x01       
+00000051:   MOV       R0,R30         
+00000052:   LDD       R30,Y+1        
+00000053:   ANDI      R30,0xFE       
+00000054:   OR        R30,R0         
+00000055:   STD       Y+1,R30        
26:           answer.valid = 0 != (PIND & (1 << 5));
+00000056:   IN        R30,0x10       
+00000057:   ANDI      R30,0x20       
+00000058:   CALL      0x00000078     
+0000005A:   ANDI      R30,0x01       
+0000005B:   LSL       R30            
+0000005C:   MOV       R0,R30         
+0000005D:   LDD       R30,Y+1        
+0000005E:   ANDI      R30,0xFD       
+0000005F:   OR        R30,R0         
+00000060:   STD       Y+1,R30        
28:           return answer;
+00000061:   MOVW      R30,R28        
+00000062:   MOVW      R26,R28        
+00000063:   ADIW      R26,0x02       
+00000064:   LDI       R24,0x02       
+00000065:   CALL      0x0000007D     
+00000067:   MOVW      R30,R28        
+00000068:   ADIW      R30,0x02       
+00000069:   LDI       R24,0x02       
+0000006A:   IN        R1,0x3F        
+0000006B:   CLI                      
+0000006C:   ADIW      R28,0x04       
+0000006D:   RET                      

ICC:

@0000004D: getIIC
---- cliff.c --------------------------------------------------------------------------------------
21:       Reception getIIC(void)
+0000004D:   CALL      0x0000008D     
+0000004F:   MOVW      R10,R16        
+00000050:   SBIW      R28,0x02       
24:           answer.datum = PINB;
+00000051:   IN        R2,0x16        
+00000052:   STD       Y+0,R2         
25:           answer.sla = 0 != (PINA & (1<<3));
+00000053:   SBIS      0x19,3         
+00000054:   RJMP      PC+0x0004      
+00000055:   LDI       R20,0x01       
+00000056:   LDI       R21,0x00       
+00000057:   RJMP      PC+0x0003      
+00000058:   CLR       R20            
+00000059:   CLR       R21            
+0000005A:   MOVW      R24,R20        
+0000005B:   ANDI      R24,0x01       
+0000005C:   ANDI      R25,0x00       
+0000005D:   LDD       R30,Y+1        
+0000005E:   LDD       R31,Y+2        
+0000005F:   ANDI      R30,0xFE       
+00000060:   OR        R30,R24        
+00000061:   OR        R31,R25        
+00000062:   STD       Y+2,R31        
+00000063:   STD       Y+1,R30        
26:           answer.valid = 0 != (PIND & (1 << 5));
+00000064:   SBIS      0x10,5         
+00000065:   RJMP      PC+0x0004      
+00000066:   LDI       R20,0x01       
+00000067:   LDI       R21,0x00       
+00000068:   RJMP      PC+0x0003      
+00000069:   CLR       R20            
+0000006A:   CLR       R21            
+0000006B:   MOVW      R24,R20        
+0000006C:   ANDI      R24,0x01       
+0000006D:   ANDI      R25,0x00       
+0000006E:   LSL       R24            
+0000006F:   ROL       R25            
+00000070:   ANDI      R24,0x02       
+00000071:   ANDI      R25,0x00       
+00000072:   LDD       R30,Y+1        
+00000073:   LDD       R31,Y+2        
+00000074:   ANDI      R30,0xFD       
+00000075:   OR        R30,R24        
+00000076:   OR        R31,R25        
+00000077:   STD       Y+2,R31        
+00000078:   STD       Y+1,R30        
28:           return answer;
+00000079:   MOVW      R24,R28        
+0000007A:   LDI       R16,0x02       
+0000007B:   LDI       R17,0x00       
+0000007C:   ST        -Y,R11         
+0000007D:   ST        -Y,R10         
+0000007E:   ST        -Y,R25         
+0000007F:   ST        -Y,R24         
+00000080:   CALL      0x00000097     
+00000082:   ADIW      R28,0x02       
---- No Source ------------------------------------------------------------------------------------
+00000083:   JMP       0x00000092     

IAR:

23:       Reception getIIC(void)
24:       {
+0000002C:   SUBI      R28,0x02       
26:           answer.datum = PINB;
+0000002D:   IN        R16,0x16       
+0000002E:   STD       Y+0,R16        
27:           answer.sla = 0 != (PINA & (1<<3));
+0000002F:   SBIS      0x19,3         
@00000030: _..X_RSTACK_BASE
+00000030:   RJMP      PC+0x0003      
+00000031:   LDI       R16,0x01       
+00000032:   RJMP      PC+0x0002      
+00000033:   LDI       R16,0x00       
+00000034:   BST       R16,0          
+00000035:   LDD       R16,Y+1        
+00000036:   BLD       R16,0          
+00000037:   STD       Y+1,R16        
28:           answer.valid = 0 != (PIND & (1 << 5));
+00000038:   SBIS      0x10,5         
+00000039:   RJMP      PC+0x0003      
+0000003A:   LDI       R16,0x01       
+0000003B:   RJMP      PC+0x0002      
+0000003C:   LDI       R16,0x00       
+0000003D:   BST       R16,0          
+0000003E:   LDD       R16,Y+1        
+0000003F:   BLD       R16,1          
+00000040:   STD       Y+1,R16        
30:           return answer;
+00000041:   LDD       R16,Y+0        
+00000042:   LDD       R17,Y+1        
+00000043:   SUBI      R28,0xFE       
+00000044:   RET                      

Personally, I am not going to lose a lot of sleep over these anomalies. You are often advised to avoid bitfields from an efficiency point of view.

In fact, I suspect that you could re-write the source code if this is a limiting factor.

But let's face it. You use a high level language to keep your source code maintainable. If you lose some efficiency, this is a price you may think worth paying.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, David, just one question:

typedef unsigned char uint8_t;
typedef unsigned int uint16_t; 

Is there anything wrong with ? Any of the compilers you tried does not have it in the standard headers?

Jan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup. Neither IAR or ICC have .

I find this happens with several other CPUs and compilers.

You just have to live with the consequences of multiple Compiler Vendors, and a variable adherence to any standard. In fact, I am not sure that is an official C89 or C99 header anyway.

One of the advantages of Java is that it is within the control of one company. If something is 1.5 you know what the behaviour will be!

At least you are relieved of the C compiler world of the 1980's. Each vendor would deliberately introduce non-compatible standard libraries to tie their customers to their products.

I always attempt to avoid 'features' in the main code. I have no problem with any 'features' being exploited within a "Compiler.h" or "Compatibilty.h". But that is where they should stay!

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Yup. Neither IAR or ICC have .

I am shocked.

david.prentice wrote:
In fact, I am not sure that is an official C89 or C99 header anyway.
It is a C99 header, listed even in the relaxed requirements of so called freestanding implementations (i.e. which don't rely on an underlying OS on the target).

I am mostly shocked because it is that EASY to write that header - why would anybody trying to conform to C99 avoid such a trivial thing? They go to lengths to support structs passing - which is FAR from being trivial (and for example SDCC does not support it, for example, exactly because of this) - bitfields and whatnot, and they omit a single and trivial step?

david.prentice wrote:
At least you are relieved of the C compiler world of the 1980's.
Given my age and location... ;-)

david.prentice wrote:
Each vendor would deliberately introduce non-compatible standard libraries to tie their customers to their products.
Shame, shame, shame on them!

Thanks for the explanation.

Jan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Yup. Neither IAR or ICC have .

this reminds me of a discussion a short while ago when some highly knowledgeable individuals insisted that the sky would be blue if I were to use stdint.h in my code, :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tries a test across the compilers the other day and was very surprised that IAR (of all compilers!) didn't appear to have stdint.h but a quick search reveals:

C:\Program Files\IAR Systems\Embedded Workbench Kickstart 5.3\avr>dir std*.h /s
 Volume in drive C is ACER
 Volume Serial Number is C6B0-75D7

 Directory of C:\Program Files\IAR Systems\Embedded Workbench Kickstart 5.3\avr\
inc\clib

03/11/2008  17:49             6,910 stdarg.h
03/11/2008  17:49               527 stdbool.h
03/11/2008  17:49               741 stddef.h
09/01/2009  17:50             1,001 stdio.h
03/11/2008  17:49             2,446 stdlib.h
               5 File(s)         11,625 bytes

 Directory of C:\Program Files\IAR Systems\Embedded Workbench Kickstart 5.3\avr\
inc\dlib

03/11/2008  17:50             3,192 stdarg.h
03/11/2008  17:50               540 stdbool.h
03/11/2008  17:50             1,141 stddef.h
03/11/2008  17:50             6,480 stdint.h
03/11/2008  17:50             8,416 stdio.h
03/11/2008  17:50            11,318 stdlib.h
               6 File(s)         31,087 bytes

So it's there but only in "DLIB", not "CLIB". I couldn't be bothered to work out what was involved in switching from one to the other so I just typedef'd myself.

No such luck for ICC:

D:\iccv7avr>dir stdint.h /s
 Volume in drive D is DATA
 Volume Serial Number is 3636-53FD
File Not Found

but I'll admit that my installation is very old and I know they are now at V8, not V7 so maybe they've entered the third millennium in that?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
So it's there but only in "DLIB", not "CLIB".
Googling for "IAR CLIB DLIB" returns quite a couple of links leading to avrfreaks.net... ;-) e.g. this one.

Interesting; what leads IAR to supply two sets of libraries? Historical reasons, I guess?

JW

PS.

EWAVR_CompilerReference.pdf wrote:
There are two different sets of runtime libraries provided:
● The IAR DLIB Library, which supports ISO/ANSI C and C++. This library also
supports floating-point numbers in IEEE 754 format and it can be configured to
include different levels of support for locale, file descriptors, multibyte characters,
et cetera.
● The IAR CLIB Library is a light-weight library, which is not fully compliant with
ISO/ANSI C. Neither does it fully support floating-point numbers in IEEE 754
format or does it support Embedded C++. (This library is used by default).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have EW2.3\740, EW5.0\avr, EW5.3\avr, EW5.4\arm, EW6.0\430 on my PC.

Only the ARM edition provides as a routine. The AVR and MSP430 editions only provide it with dlib. The ancient Mitsubishi 740 edition does not at all.

Yes, it is a mystery. Life is so much simpler with , and is hardly difficult for them to have included.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Found it. In IAR the setting is in the picture below. With that, this successfully compiled:

#include 
#include 

int main(void) { 
	uint8_t a=0, b=255;
	DDRB = 0xFF; 
	while(1){
		PORTB = a * b;
		a++;
		b--;
	}
}

The real mystery is why they default to CLIB. I know I've never changed this setting so the Kickstart version came with CLIB as the default. This seems like madness to me. They describe the choices as:

CLIB
Use the legacy C runtime library.

Normal DLIB
Use the normal configuration of the C/EC++
runtime library. No locale interface,
C locale, no file descriptor support,
no multibytes in printf and scanf, and
no hex floats in strtod.

Full DLIB
Use the full configuration of the C/EC++
runtime library. Full locale interface,
C locale, file descriptor support,
multibytes in printf and scanf, and
hex floats in strtod.

There are also "custom" options where the path to the .90's and .h's can be user defined.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

millwood wrote:

> that's the price you pay for using a free product.

Ah, some nice FUD.

I think GCC did that particular thing better in the past. Anyway,
there's hope: I just built a stock (no patches) GCC 4.5.1, and
it produces the following code for the above snippet:

.global getIIC
        .type   getIIC, @function
getIIC:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
        in r24,35-0x20
        in r18,32-0x20
        in r19,41-0x20
        ldi r25,lo8(1)
        sbrs r18,3
        ldi r25,lo8(0)
.L2:
        ldi r18,lo8(1)
        sbrs r19,5
        ldi r18,lo8(0)
.L3:
        lsl r18
        andi r25,lo8(-3)
        or r25,r18
/* epilogue start */
        ret
        .size   getIIC, .-getIIC

Btw., as our troll wrote in the other forum that he "cannot afford any
bugs" (where it's certainly arguable whether other compilers really
don't have bugs): the resulting code here isn't buggy at all, it just
wasn't optimal.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I went further in the bitfield stuff.

typedef union {
  struct {
    uint8_t b0 : 1;
    uint8_t b1 : 1;
    uint8_t b2 : 1;
    uint8_t b3 : 1;
    uint8_t b4 : 1;
    uint8_t b5 : 1;
    uint8_t b6 : 1;
    uint8_t b7 : 1;
  };
  uint8_t all;
} TPort;

Reception getIIC(void)
{
    Reception answer;
    answer.datum = PINB;
    answer.sla = (((TPort)PINA).b3);
    answer.valid = (((TPort)PIND).b5);

    return answer;
}    

(full source in attachment)

This compiles to (gcc 4.2.2 from WinAVR 20071221):

  12               	getIIC:
  13               	/* prologue: frame size=0 */
  14               	/* prologue end (size=0) */
  15 0000 43B1      		in r20,35-0x20
  16 0002 30B1      		in r19,32-0x20
  17 0004 3695      		lsr r19
  18 0006 3695      		lsr r19
  19 0008 3695      		lsr r19
  20 000a 29B1      		in r18,41-0x20
  21 000c 2295      		swap r18
  22 000e 2270      		andi r18,lo8(2)
  23 0010 922F      		mov r25,r18
  24 0012 3170      		andi r19,lo8(1)
  25 0014 932B      		or r25,r19
  26 0016 842F      		mov r24,r20
  27               	/* epilogue: frame size=0 */
  28 0018 0895      		ret

So the rotations remain, but it does not perform the integer promotion.

JW

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay, so if you want to see some real clumsiness, this is what the AVR port of SDCC spits out:

	         .text
;------------------------------------------------------------
;Allocation info for local variables in function 'getIIC'
;------------------------------------------------------------
;answer                    Allocated to stack - offset -2
;------------------------------------------------------------
;	g.c 36
;	-----------------------------------------
;	 function getIIC
;	-----------------------------------------
	_getIIC:
	push	r26
	push	r27
	push	r30
	push	r31
	push	r28
	push	r29
	in	r28,__SP_L__
	in	r29,__SP_H__
	sbiw	r28,2
	out	__SP_L__,r28
	out	__SP_H__,r29
;	g.c 39
	movw	r26,r28
	subi	r26,lo8(2)
	sbci	r27,hi8(2)
	lds	r24,(_PINB)+0
	mov	r16,r24
	st	X,r16
;	g.c 40
	movw	r26,r28
	subi	r26,lo8(2)
	sbci	r27,hi8(2)
	mov	r30,r26
	subi	r30,lo8(-1)
	mov	r31,r27
	sbci	r31,hi8(-1)
	lds	r24,(_PINA)+0
	mov	r16,r24
	andi	r16,lo8(8)
	clr	r0
	ldi	r25,lo8(0x00)
	cp	r25,r16
	breq	.L00003
	inc	r0
	.L00003:
	mov	r16,r0
	mov	r24,r16
	ld	r1,Z
	andi	r24,0xfe
	or	r24,r1
	st	Z+,r24
;	g.c 41
	mov	r30,r26
	subi	r30,lo8(-1)
	mov	r31,r27
	sbci	r31,hi8(-1)
	lds	r24,(_PIND)+0
	mov	r16,r24
	andi	r16,lo8(32)
	clr	r0
	ldi	r25,lo8(0x00)
	cp	r25,r16
	breq	.L00004
	inc	r0
	.L00004:
	mov	r16,r0
	mov	r24,r16
	lsl	r24
	ld	r1,Z
	andi	r24,0xfd
	or	r24,r1
	st	Z+,r24
;	g.c 44
	ld	r16,X+
	ld	r17,X
	.L00001:
	adiw	r28,2
	out	__SP_L__,r28
	out	__SP_H__,r29
	pop	r29
	pop	r28
	pop	r31
	pop	r30
	pop	r27
	pop	r26
	ret

So, money DOES show up here: avr-gcc received undoubtedly more sponsorship than the long-defunct avr-port of SDCC ;-) (For those who would like to reproduce my result: I had to fix a couple of errors to be able to compile, so this is not the stock SDCC, which since a couple of months is not even configured for AVR anymore by default).

I could not use the function as David wrote it above, as SDCC does not allow to pass structs as return values, so my source was:

#if defined(__GNUC__)
#include 
#elif defined(__CODEVISIONAVR__)
#include 
#elif defined(__IAR_SYSTEMS_ICC__)
#include 
#elif defined(__IMAGECRAFT__)
#include 
#elif defined(SDCC)
  #if defined(__avr)
    volatile unsigned char PINA, PINB, PIND, PORTC;
  #else
    #include <8051.h>
    #define PINA P0
    #define PINB P1
    #define PIND P3
    #define PORTC P2
  #endif
#endif

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;

typedef union {
  struct {
    uint8_t datum;
    uint8_t sla:1;
    uint8_t valid:1;
  };
  uint16_t all;
} Reception;

extern uint16_t getIIC(void);
uint16_t getIIC(void)
{
    Reception answer;
    answer.datum = PINB;
    answer.sla = 0 != (PINA & (1<<3));
    answer.valid = 0 != (PIND & (1 << 5));

//    return (uint16_t)answer; // ! this leads to error - returns ADDRESS of answer ((uint16_t)&answer)!
    return answer.all;
}    

void main(void)
{
    volatile Reception foo;
    foo.all = getIIC();
    PORTC = foo.datum;
    while (1) ;
} 

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jan,

SDCC is not particularly perfect with 8051 code either.

avr-gcc works well enough for me. sdcc works well enough for me.

If I was to produce commercial products, IAR and Keil would be worth the money.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

answer.sla = 0 != (PINA & (1<<3));

Quote:

... the cycle count is 139 ... for CV ...

CV isn't as good at pure/classical optimizations, so if I recalculate .sla several times in a row as in the fragment below, it generates code for all of them.

That said, through experience I know that when you make complex/nested expressions with CV, it tends to call helper routines as was seen above. Ode to .sla: "How can I set thee? Let me count the ways..."

   answer.sla = 0 != (PINA & (1<<3));
    
    if (PINA & (1<<3))
        {
        answer.sla = 0;
        }
    else
        {
        answer.sla = 1;
        }

    answer.sla = (PINA & (1<<3)) ? 0 : 1;
    
    answer.sla = 0; // assume "success"
    if (PINA & (1<<3))
        {
        answer.sla = 1; // failure
        }
 

Only the original post format calls the helper routine.

NB: In general my approach would be the last fragment: Initialize the return status(es) to "success" (or maybe sometimes "failure"), and then override them as needed.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes. I think you will find the :

     clear_bit);
     if (condition) set_bit();

construction will work efficiently with the most brain-dead compiler.

In an ideal world, all compilers would be equally clever.

Personally, I can live in an imperfect world. Bitfields are seldom the most efficient way of coding. They are neat and tidy from the author's point of view.

In the AVR world, you tend to use bit-masks and compilers know this.
Hence you find they all produce efficient SBI, CBI sequences if possible.

The XMEGA uses bitfields extensively to describe its special function registers. As long as Compilers can generate reasonable code for SFR's, I can accept inefficiencies elsewhere.

Yes. Both CV and ICC generate and use helper functions. This is very useful for compact code, but not ideal on a racing track.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wek wrote:

So, money DOES show up here: avr-gcc received undoubtedly more sponsorship than the long-defunct avr-port of SDCC ;-)

It depends on how you define "sponsorship".

First, SDCC is not developing their AVR port anymore. Second, there was no influx of money, or people, into AVR GCC that suddenly made this issue work better on 4.5. AFAIK, there was just marginal input from developers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wek wrote:

So, money DOES show up here: avr-gcc received undoubtedly more sponsorship than the long-defunct avr-port of SDCC ;-)

EW wrote:

It depends on how you define "sponsorship".

The simple definition is "money".

Of course, it is not that straighforward: the issue is "people" more than "money". There certainly are unpaid contributors to gcc, including students and hobbyists. But I doubt they make the bulk of the development. That requires people devoted to the task, which means fully paid employees and contractual developers.

I don't have any exact numbers so if you know more, please correct me.

EW wrote:
First, SDCC is not developing their AVR port anymore.

This is not quite so. While a couple of months ago the SDCC crew announced they won't support the AVR port anymore, in fact it was *never* functional. Download an older binary of sdcc and try yourself.

In the last weeks, I spent around 20 hours to fix the most critical errors, just to be able to produce that snippet of code you've seen above and a few similar. That would be 3 days of work, would it be a full-time payed job, rather than several weeks.

I did not go for improvements - I don't understand most of the code - I just fixed obvious bugs. I think I started to see areas of potential improvement, and I could formulate a strategy how to move on from here. But I won't move on - I don't have time for this hobby at the moment and won't have in foreseable future.

And this is the issue. As a hobbyist, I work on a project when I feel like it, and I chose those items I like. I have no obligation to fulfill a request or to fix a bug. There is no demand for the AVR port of SDCC, but I decided I would like to see how does it work and why. And I spend as much time on it as much I can afford - or until I lose interest. It was fun, thank you very much.

The whole SDCC stuff is just like this. The '51 backend, from which the AVR backend was forked maybe 10 years ago, has evolved - I tried to compare and get inspired, but it is quite different now - but it is far far from being efficient yet. The limited time (read: money) the developers spend on it shows. They do a really good job in cleaning up the bugs list, but the requests list just grows.

On the other hand, avr-gcc does not work like this for quite a long time. Things get fixed and move on in quite a timely manner. This is clearly not a work of a couple (in the tightest meaning of the word) of dangling amateurs.

EW wrote:
Second, there was no influx of money, or people, into AVR GCC that suddenly made this issue work better on 4.5. AFAIK, there was just marginal input from developers.
Oh, so it just HAPPENED? Of course not. I don't say the developers deliberately implemented improvements targeted do optimize specifically our dear colleague Levenkay's code, but this is the result of a big, huge amount of work all over gcc (by which I mean "not only the avr-port of gcc"). And, if the developers did not put too much effort into it recently and the improvement showed, it means, they've just uncovered the huge effort made previously.

Don't get me wrong, I don't complain, I just state the facts.

All this said, this still does not justify millwood's assertion. The quality of compiler is NOT a direct function of money a customer PAYS for it individually.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Ah, some nice FUD
I can't contribute to this, but i would like to know what FUD is ( i'm confident about who the troll is ) ?

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

FUD used to be IBM's main business tactic when they were trying to combat all the clones of their PC design which they rather stupidly forgot to patent (well, everything but the keyboard interface which was patented so when we made PCs we had to devise our own keyboard interface).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wek wrote:

EW wrote:
Second, there was no influx of money, or people, into AVR GCC that suddenly made this issue work better on 4.5. AFAIK, there was just marginal input from developers.
Oh, so it just HAPPENED? Of course not. I don't say the developers deliberately implemented improvements targeted do optimize specifically our dear colleague Levenkay's code, but this is the result of a big, huge amount of work all over gcc (by which I mean "not only the avr-port of gcc"). And, if the developers did not put too much effort into it recently and the improvement showed, it means, they've just uncovered the huge effort made previously.

Yes, it just *happened*. I said specifically that it was not due to any work on *AVR* GCC (by developers on the AVR port). it was not due to any concerted effort or work on the AVR port, in this particular case.

Yes, of course, there is constant work being done on the bulk of GCC. It just so happens that this particular time we gained a benefit from it. This does happen occasionally, and I'm always thankful when that occurs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
In the last weeks, I spent around 20 hours to fix the most critical errors, ...

that's an example of how a free system can cost you lots of money. if I ran into an issue with my commercial compilers, I can always call and demand action from the vendors. here, you are on your own. the 20 hours you spent on the compiler could have translates into many thousands of dollars that you could have spent making money, or with your families and friends.

that's why you don't see businesses embracing free tools in mass. not because they are inferior, but they are not reliable in the sense that you are at someone else's mercy for support and quality.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Levenkay wrote:
I came across an example of GCC generating awkward code while tinkering with a technique for adding valid/invalid status to a subroutine's return value, and offer it for your amusement or suggested alternatives.

The reason is that avr-gcc lacks some patterns for zero-extraction (exzv) and insertion (insv) that could easyly handle that, perhaps some patterns to feed the insn combiner. gcc tends to reuse values which is good in most situations, but here it is not a good idea because to use tha value it has to be extracted. As there are no patterns in avr backend that describe it, loops and other things are used.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> if I ran into an issue with my commercial compilers,
> I can always call and demand action from the vendors.

Did you ever try it? Did you get more than just a ticket number?

If you read the fine-print, unless you are paying many extra bucks
(for a support contract), they don't promise you anything. Even with
a support contract, the only thing they are promising you is a
*response* time, i.e. someone just told you in time: "OK, we've got
your bug report, we are working on it." I've never seen anyone
promising a "time to fix" the bug (and obviously, they would be stupid
to sign such a contract).

(Btw., you might have noticed that wek's comment wasn't about GCC but
about SDCC, and wek also explained that SDCC for the AVR practically
never worked at all. Thus, it's a really easy target for your
attack.)

Don't get me wrong, IAR really is a good compiler (albeit it has its
weak points; the licensing stuff is horrible and can easily cause you
to waste more hours than you might ever save by the quality of the
compiler, and some might argue that the unavailability for any OS
other than Windows isn't one of its stronest points either), but your
generalized statements abou paid software being better than opensource
software has been proven wrong for many years now.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Did you ever try it?

I did once. With ARM SDT 2.50. I forget the exact details but it was something to do with structure packing/alignment or passing struct pointers or something. ARM confirmed it as a bug in their compiler. At that time we had bought twenty supported copies at $6,000 each (including one ICE per copy). They said they "hoped" it could be fixed for their next release in 3 months time but if it didn't make it for that it would definitely be in the next major release due in 6 months. Our project was scheduled to finish completely in about 5 months time. Oh dear. We had no option but to simply find a different way to do what we'd been attempting.

When we started to use Linux as the operating system on one of our ARM designs we switched (naturally) to using arm-gcc as the compiler. We never had a moment's trouble with it. That's what made me such a great fan of GCC to this day.

On another project we continued to use ARM - then switched to Realview - and bought another fifty copies at $6,000 each but one thing we've learned is that the price you pay for compilers guarantees nothing about response times to problems.

If we'd been using GCC rather than SDT when we had the problem I think amongst 20+ skilled engineers we could have worked out how to fix the openly available source (and later feed it back into the GCC project for others to benefit).

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Did you ever try it?

yes.

Quote:
Did you get more than just a ticket number?

yes.

Quote:
but your
generalized statements abou paid software being better than opensource
software has been proven wrong for many years now.

your generalized statements about my alleged "generalized statements" are simply wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

yes.

Which compiler/processor? What was the response time from issue of support ticket to resolution? Exactly what was the bug in the compiler? How did this affect your design? Was a new version of the compiler issued to correct this?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

millwood wrote:
my alleged "generalized statements"
Alleged? So you really do not think that the following are a little bit overgeneralized (just to show a few that I have seen)?
Quote:
that's the price you pay for using a free product
Quote:
the use of assert is very uncommon for 8-bit programming - because of over-confident and extremely exuberant (and mostly inexperienced) programmers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

He's an arrogant troll who blows smoke out of his ass. I bet he's never had a re-issued compiler (in a timely fashion) as a result of a compiler bug.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> He's an arrogant troll who blows smoke out of his ass.

Ouch. His attitude must have upset you even more than I expected. I've
never read such words written by a British so far... and while I certainly
only ever read a very small part of your > 36000 replies, I'm sure I've
read a lot from you already. ;-)

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

Last Edited: Mon. Nov 1, 2010 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ezharkov wrote:
millwood wrote:
my alleged "generalized statements"
Alleged? So you really do not think that the following are a little bit overgeneralized (just to show a few that I have seen)?
Quote:
that's the price you pay for using a free product
Quote:
the use of assert is very uncommon for 8-bit programming - because of over-confident and extremely exuberant (and mostly inexperienced) programmers

so what makes you think they are indeed overgeneralized?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> so what makes you think they are indeed overgeneralized?

These remarks show the attitude of someone who believes he's the only
person on earth being able to do things right, while all others around
are idiots.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
> so what makes you think they are indeed overgeneralized?

These remarks show the attitude of someone who believes he's the only
person on earth being able to do things right, while all others around
are idiots.

these remarks above show a person who cannot back up his statements. Instead, s/he has to resort to character assassination.

you apparently cannot find facts to convince yourself that those comments of mine are "overgeneralized". thank you for doing a fine job refuting yourself.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

millwood wrote:
so what makes you think they are indeed overgeneralized?
Well, it seems that you are indeed a troll, as Cliff suggests. So, I guess, I should stop feeding you from now on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ezharkov wrote:
millwood wrote:
so what makes you think they are indeed overgeneralized?
Well, it seems that you are indeed a troll, as Cliff suggests. So, I guess, I should stop feeding you from now on.

when people say that, they are usually on the losing end of an argument.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff wrote

Quote:
...they rather stupidly forgot to patent...
How could they do something so moronic ( i didn't know they had it in 'em... a lowdown dirty shame )?!!

ezharkov wrote

Quote:
as Cliff suggests
It's alot more than a suggestion, Jorg this isn't Cliff's first exposure to this attitude :

millwood wrote

Quote:
...even a novice programmer like me who is less than 6 months out of school can understand
https://www.avrfreaks.net/index.p...

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
millwood wrote
Quote:
...even a novice programmer like me who is less than 6 months out of school can understand
https://www.avrfreaks.net/index.p...
I guess that explains the type of statements that he makes. Then he is probably not a troll, after all. Not yet anyway. Just too young.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ezharkov wrote:
indianajones11 wrote:
millwood wrote
Quote:
...even a novice programmer like me who is less than 6 months out of school can understand
https://www.avrfreaks.net/index.p...
I guess that explains the type of statements that he makes. Then he is probably not a troll, after all. Not yet anyway. Just too young.

one good thing about living in a free society is that you can always think whatever you want, no matter how delusional that is.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> one good thing about living in a free society is that you can always
> think whatever you want, no matter how delusional that is.

Is it because I can always think whatever I want no matter how
delusional that is that you came to me?

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
> one good thing about living in a free society is that you can always
> think whatever you want, no matter how delusional that is.

Is it because I can always think whatever I want no matter how
delusional that is that you came to me?

it is because one can always think whatever one wants no matter how delusional one is.

hopefully it is more clear to you this time. if not, please let me know and I am happy to enlighten you.

ciao.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> it is because one can always think whatever one wants no matter
> how delusional one is.
> hopefully it is more clear to you this time. if not, please let me
> know and I am happy to enlighten you.

Do you get happy often?

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
> it is because one can always think whatever one wants no matter
> how delusional one is.
> hopefully it is more clear to you this time. if not, please let me
> know and I am happy to enlighten you.

Do you get happy often?

as often as you get delusional.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> as often as you get delusional.

Why do you say
as often as I get delusional?

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

millwood wrote:

it is because one can always think whatever one wants no matter how delusional one is.

hopefully it is more clear to you this time. if not, please let me know and I am happy to enlighten you.

ciao.

[moderator]
If this doesn't get back on topic then this thread will be locked. Take your schoolyard comments elsewhere.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

If this doesn't get back on topic then this thread will be locked. Take your schoolyard comments elsewhere.
I'd better hurry, then, and thank everyone for their very thoughtful replies to what grew from simple mild surprise over the departure from gcc's usually pretty fair implementation of bit tests like "x & (1 << n)". Most especially, thanks to David Prentice for testing and posting the code generated by such a variety of alternate compilers.

I also apologize for not having identified the compiler version and settings I'd used. Here's what an "avr-gcc -v" command gets me:

Using built-in specs.
Target: avr
Configured with: ../gcc-4.3.3/configure --enable-win32-registry=WinAVR-20100110
--with-gmp=/usr/local --with-mpfr=/usr/local --prefix=/c/WinAVR --target=avr --e
nable-languages=c,c++,objc --with-dwarf2 --enable-doc --disable-shared --disable
-libada --disable-libssp --disable-nls --with-pkgversion='WinAVR 20100110' --wit
h-bugurl='URL:http://sourceforge.net/tracker/?atid=520074&group_id=68108&func=br
owse'
Thread model: single
gcc version 4.3.3 (WinAVR 20100110)

. Optimization level was the default for a slapped-together AStudio Gcc project: '-Os', I believe.

Also many encouraged thanks to Jörg Wunsch for trying the toy example out on what I gather is a newer gcc version that might be showing up as a new WinAVR release sometime. I'd heard suggestions that there might be newer versions coming; gee, I hope they finally move their choice of the "permanently cleared" register away from R0 to something else (yeah, the libraries would have to be replaced. Good; I'd be more than happy to install new versions.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Levenkay wrote:
gee, I hope they finally move their choice of the "permanently cleared" register away from R0 to something else (yeah, the libraries would have to be replaced. Good; I'd be more than happy to install new versions.)

It's "on the list" to do just that, but there are ramifications with that all throughout the toolchain, including the library which is not insignificant, and will incur a high testing load to get it right. Volunteers to help out are always welcome.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Volunteers to help out are always welcome.

another reason to vote OUT a volunteer-based system: the bugs are fixed when some unknown volunteers get the time.

it is hard to bank your family's next Ferrari on that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

millwood wrote:
Quote:
Volunteers to help out are always welcome.

another reason to vote OUT a volunteer-based system: the bugs are fixed when some unknown volunteers get the time.

it is hard to bank your family's next Ferrari on that.


@millwood
This does make you feel good ... :-(
https://www.avrfreaks.net/index.p...

The quoted text below resembles your text in the url , doesn't it ?

Quote:
these remarks above show a person who cannot back up his statements. Instead, s/he has to resort to compiler assassination.

https://www.avrfreaks.net/index.p...

KAPLOOONNK.......

millwood you are now officially in my TROLL-filter

I expect i'm not the last one.

/Bingo

Ps: Why do you waste your apparent talent , on being an @ss on the personal plane ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Ps: Why do you waste your apparent talent , on being an @ss on the personal plane ?

Because he's clearly an arrogant school boy and hasn't yet learned to behave like an adult.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bingo600 wrote:

millwood you are now officially in my TROLL-filter

pleeeease, I am scared!

just couldn't resist.