mersenneforum.org  

Go Back   mersenneforum.org > Extra Stuff > Programming

Reply
 
Thread Tools
Old 2019-03-01, 22:21   #1
ewmayer
2ω=0
 
ewmayer's Avatar
 
Sep 2002
República de California

262078 Posts
Default GCC 'incompatible type' C-union error

On 32-bit PowerPC, the following kind of union-based technique for managing 64-bit integer emulation via pairs of 32-bit ints used to work fine - uint32 and uint64 are obvious typedefs, and _x is a uint64 variable fed to a macro:
Code:
	union {\
		uint32 u32[2];	/* Due to PPC big-endian, MS 32 bits in [0]! */\
		uint64 u64;\
	} a;\
	uint32 ah,al;\
	a.u64 = _x;\
	ah = a.u32[0];	/* x_hi */\
	al = a.u32[1];	/* x_lo */\
This code now gives
Code:
error: assigning to 'uint64' (aka 'unsigned long long') from incompatible type
      'union <anonymous at [file,line]>'
	...
      note: instantiated from:
        a.u64 = _x;\
The wording of the error message is odd, as the code is assigning *from* a uint64 *to* the uint64-specialization of the union in question. Adding an explicit cast of _x, e.g. 'a.u64 = (uint64)_x;', gives a different error:

error: operand of type 'union <anonymous at [file,line]' where arithmetic or pointer type is required.

The '.u64' specializes to an arithmetic type, does it not?

Any light-shedding on the issue welcome!

Last fiddled with by ewmayer on 2019-03-01 at 22:24
ewmayer is offline   Reply With Quote
Old 2019-03-02, 00:02   #2
paulunderwood
 
paulunderwood's Avatar
 
Sep 2002
Database er0rr

3·11·101 Posts
Default

What is the declaration of "_x"? And exactly how is the function called?

Also, should there be a name after "union"? http://www.c4learn.com/c-programming...n-declaration/

Last fiddled with by paulunderwood on 2019-03-02 at 00:13
paulunderwood is online now   Reply With Quote
Old 2019-03-02, 04:28   #3
ewmayer
2ω=0
 
ewmayer's Avatar
 
Sep 2002
República de California

101100100001112 Posts
Default

Quote:
Originally Posted by paulunderwood View Post
What is the declaration of "_x"? And exactly how is the function called?

Also, should there be a name after "union"? http://www.c4learn.com/c-programming...n-declaration/
It's not a function, it's a construct used in several wide-mul macros ... args assumed 64-bit ints.

No-name union is the reason for the <anonymous> tag by GCC ... never needed a name before, but I tried several fiddles involving naming the union, no joy.

I've implemented a workaround that uses 32-bit pointers instead of a union, e.g.
Code:
		#define MUL_LOHI64(_x,_y,_lo,_hi)\
		{\
			uint32 ah,al,bh,bl;\
			uint64 a = _x, b = _y;\
			uint32 *aptr = (uint32 *)&a, *bptr = (uint32 *)&b;\
			/* PPC is big-endian, hence hi32 at aptr, lo32 at aptr+1: */\
			ah = *aptr;	/* x_hi */\
			al = *(aptr+1);	/* x_lo */\
			bh = *bptr;	/* y_hi */\
			bl = *(bptr+1);	/* y_lo */\
			...etc...

Last fiddled with by ewmayer on 2019-03-02 at 04:30
ewmayer is offline   Reply With Quote
Old 2019-03-02, 07:52   #4
paulunderwood
 
paulunderwood's Avatar
 
Sep 2002
Database er0rr

3×11×101 Posts
Default

This compiled okay:

Code:
#define uint32 unsigned int
#define uint64 unsigned long long

uint64 _x = 7;
uint32 ah;
uint32 al;
union bytes {
		uint32 u32[2];
		uint64 u64;
	} a;

void main(){
	a.u64 = _x;
	ah = a.u32[0];
	al = a.u32[1];
};

Last fiddled with by paulunderwood on 2019-03-02 at 07:57
paulunderwood is online now   Reply With Quote
Old 2019-03-02, 14:50   #5
GP2
 
GP2's Avatar
 
Sep 2003

2,579 Posts
Default

Maybe you could try the standard types defined in the include file inttypes.h: uint32_t and uint64_t

inttypes.h is part of the C99 standard, so nearly all compilers should implement it.

See https://en.wikibooks.org/wiki/C_Programming/inttypes.h or other references.

inttypes.h also has the PRI macros, which make printing portable. That would remove many of the large number of compiler warnings when compiling Mlucas.
GP2 is offline   Reply With Quote
Old 2019-03-02, 20:45   #6
ewmayer
2ω=0
 
ewmayer's Avatar
 
Sep 2002
República de California

101100100001112 Posts
Default

Quote:
Originally Posted by paulunderwood View Post
This compiled okay:

Code:
#define uint32 unsigned int
#define uint64 unsigned long long

uint64 _x = 7;
uint32 ah;
uint32 al;
union bytes {
		uint32 u32[2];
		uint64 u64;
	} a;

void main(){
	a.u64 = _x;
	ah = a.u32[0];
	al = a.u32[1];
};
Also for me - after I fiddled main to return int to fix a GCC "error: 'main' must return 'int'", that is. But trying to use the named union in my wide-mul macro fails:

error: assigning to 'uint64' (aka 'unsigned long long') from incompatible type 'union bytes'

I suspect the this-no-longer-builds issue is due to something related to the C99 standard - as I noted, it's been years since anyone tried a PowerPC 32-bit build, this arose as part of Debian-release freeware-portability issue. It's also possible that my particular usage of union inside a macro is exposing a bug in GCC, but in any case, gonna move forward with the pointer-based 32-bit-subfield-access workaround.

Gord, re. your suggestion - can you post a copy of some of the compiler warnings you mentioned, and check whether adding that header file to the set of includes at the top of masterdefs.h fixes them? The only printing-related warnings I see in the build.log files for my local machines are empty-print-strings for a handful of prints I use as placeholders to set breakpoints in debuggable builds, and this kind:
warning: ignoring return value of 'fgets', declared with attribute warn_unused_result
ewmayer is offline   Reply With Quote
Old 2019-03-02, 21:02   #7
paulunderwood
 
paulunderwood's Avatar
 
Sep 2002
Database er0rr

3×11×101 Posts
Default

Do you use/expand the (original) macro inside a function? The lines "a.u64 = _x;" etc must be used inside a function if I understand it.

This also compiles:

Code:
#define uint32 unsigned int
#define uint64 unsigned long long

uint64 _x;

#define MUL( _x )\
        union bytes {\
		uint32 u32[2];\
		uint64 u64;\
	} a;\
        uint32 ah,al;\
	a.u64 =  _x;\
	ah = a.u32[0];\
	al = a.u32[1];\

int main(){
       MUL(7);
};

Last fiddled with by paulunderwood on 2019-03-02 at 21:29
paulunderwood is online now   Reply With Quote
Old 2019-03-02, 22:54   #8
ewmayer
2ω=0
 
ewmayer's Avatar
 
Sep 2002
República de California

1139910 Posts
Default

That compiles for me in standalone-file mode, but again, when I try to use the union insise one of my wide-mul macros, it fails.
I notice your macro-syntax is a bit different than mine, so let's make things look more like my usage by wrapping the macro contents in {}:
Code:
#define uint32 unsigned int
#define uint64 unsigned long long

#define MUL_LOHI64(_x,_y,_lo,_hi)\
{\
	uint32 ah,al;\
	union bytes {\
		uint32 u32[2];\
		uint64 u64;\
	} a;\
	a.u64 = _x;\
	ah = a.u32[0];\
	al = a.u32[1];\
	_lo = _x*_y;/* Placeholder for actual 32-bit-based lo-part computation */\
	_hi = a;	/* Placeholder for actual 32-bit-based hi-part computation */\
}

int main(){
	uint64 a = 6,b = 7,lo,hi;
	MUL_LOHI64(a,b,lo,hi);
	return(0);
};
Et voilà:

MacBook:obj_sse2 ewmayer$ clang -c test.c
test.c:20:2: error: assigning to 'unsigned long long' from incompatible type 'union bytes'
MUL_LOHI64(a,b,lo,hi);
^~~~~~~~~~~~~~~~~~~~~
test.c:11:8: note: instantiated from:
a.u64 = _x;\
^
test.c:20:2: error: invalid operands to binary expression ('union bytes' and 'unsigned long long')
MUL_LOHI64(a,b,lo,hi);
^~~~~~~~~~~~~~~~~~~~~
test.c:14:10: note: instantiated from:
_lo = _x*_y;/* Placeholder for actual 32-bit-based lo-part computation */\
^
test.c:20:2: error: assigning to 'unsigned long long' from incompatible type 'union bytes'
MUL_LOHI64(a,b,lo,hi);
^~~~~~~~~~~~~~~~~~~~~
test.c:15:6: note: instantiated from:
_hi = a; /* Placeholder for actual 32-bit-based hi-part computation */\
^ ~
3 errors generated.

I prefer clang on my Mac for speed and better error-messaging, but here is gcc on the same test.c file:

MacBook:obj_sse2 ewmayer$ gcc -c test.c
test.c: In function ‘main’:
test.c:20: error: incompatible types in assignment
test.c:20: error: invalid operands to binary * (have ‘union bytes’ and ‘long long unsigned int’)
test.c:20: error: incompatible types in assignment
ewmayer is offline   Reply With Quote
Old 2019-03-03, 03:09   #9
axn
 
axn's Avatar
 
Jun 2003

13·359 Posts
Default

_hi = a;
This line. You're trying to assign a union to an int. Why? Can't you just do _hi = a.u64?
axn is offline   Reply With Quote
Old 2019-03-03, 03:29   #10
ewmayer
2ω=0
 
ewmayer's Avatar
 
Sep 2002
República de California

11,399 Posts
Default

Quote:
Originally Posted by axn View Post
_hi = a;
This line. You're trying to assign a union to an int. Why? Can't you just do _hi = a.u64?
My bad - in my cut-down version of the full ppc32 macro I left off the .u64 needed on that statement. Restoring it cures the last error, but I still get an error rleated to initial (union bytes).u64 = uint64 assignment, as well as one related - oddly enough - to the uint64*uint64 multiply I stuck in there to at least get the cut-down macro to produce the correct low 64 bits:

MacBook:obj_sse2 ewmayer$ clang -c test.c
test.c:20:2: error: assigning to 'unsigned long long' from incompatible type 'union bytes'
MUL_LOHI64(a,b,lo,hi);
^~~~~~~~~~~~~~~~~~~~~
test.c:11:8: note: instantiated from:
a.u64 = _x;\
^
test.c:20:2: error: invalid operands to binary expression ('union bytes' and 'unsigned long long')
MUL_LOHI64(a,b,lo,hi);
^~~~~~~~~~~~~~~~~~~~~
test.c:14:10: note: instantiated from:
_lo = _x*_y;/* Placeholder for actual 32-bit-based lo-part computation */\

By way of reference, here is the original version of the macro, including the asm-segments which do the add-with-carry subproducts accumulations:
Code:
		#define MUL_LOHI64(_x,_y,_lo,_hi)\
		{\
			union {\
				uint32 u32[2];	/* Due to PPC big-endian, MS 32 bits in [0]! */\
				uint64 u64;\
			} a,b;\
		\
			uint32 ah,al,bh,bl;\
			uint32 hahbh,hahbl,halbh,halbl,lahbh,lahbl,lalbh,lalbl;\
			uint32 sumhh,sumhl,sumlh;\
		\
			a.u64 = _x;\
			ah = a.u32[0];	/* x_hi */\
			al = a.u32[1];	/* x_lo */\
			b.u64 = _y;\
			bh = b.u32[0];	/* y_hi */\
			bl = b.u32[1];	/* y_lo */\
		\
		/* EWM: for 32-bit unsigned inputs these have a nominal latency of 10 cycles. */\
		/* For each MUL output we include the order in which it is used in the add/carry */\
		/* code below (6 steps, labeled (0)-(5)), in order to properly schedule the MUL: */\
			MULH32(ah,bh,hahbh);	/* (x_hi*y_hi)_hi (2) */\
			 MULL32(ah,bh,lahbh);	/* (x_hi*y_hi)_lo (4) */\
			MULH32(al,bh,halbh);	/* (x_lo*y_hi)_hi (1) */\
			 MULL32(al,bh,lalbh);	/* (x_lo*y_hi)_lo (0) */\
			MULH32(ah,bl,hahbl);	/* (x_hi*y_lo)_hi (1) */\
			 MULL32(ah,bl,lahbl);	/* (x_hi*y_lo)_lo (3) */\
			MULH32(al,bl,halbl);	/* (x_lo*y_lo)_hi (0) */\
			 MULL32(al,bl,lalbl);	/* (x_lo*y_lo)_lo (-) */\
		/* Bits   0- 31 : lalbl                           */\
		/* Bits  32- 63 :*halbl + lahbl +*lalbh   (sumlh) */\
		/* Bits  64- 95 :*hahbl +*halbh + lahbh   (sumhl) */\
		/* Bits  96-127 : hahbh                   (sumhh) */\
		\
			/* KK:  addc/adde/addze forces execution serialization! Other solution for carry propagation? */\
			/* EWM: these all have latency 1, so serialization not a problem... */\
		  __asm__(\
			"addc  %0,%3,%4\n\t"	/* (0) halbl + lalbh                       , result (partial sumlh) in %0, carryout in XER(CA) bit. */\
			"adde  %1,%5,%6\n\t"	/* (1) halbh + hahbl + (carryin from sumlh), result (partial sumhl) in %1, carryout in XER(CA) bit. */\
			"addze %2,%7"			/* (2)     0 + hahbh + (carryin from sumhl), result (partial sumhh) in %2, carryout in XER(CA) bit - should be zero! */\
			: "=r"(sumlh), "=r"(sumhl), "=r"(sumhh)\
			: "%r"(halbl), "r"(lalbh), "%r"(halbh), "r"(hahbl), "r"(hahbh));\
		\
		  __asm__(\
			"addc  %0,%3,%4\n\t"	/* (3) sumlh + lahbl                       , result (sumlh) in %0, carryout in XER(CA) bit. */\
			"adde  %1,%5,%6\n\t"	/* (4) sumhl + lahbh + (carryin from sumlh), result (sumhl) in %1, carryout in XER(CA) bit. */\
			"addze %2,%7"			/* (5)     0 + sumhh + (carryin from sumhl), result (sumhh) in %2, carryout in XER(CA) bit - should be zero! */\
			: "=r"(sumlh), "=r"(sumhl), "=r"(sumhh)\
			: "%0"(sumlh), "r"(lahbl), "%1"(sumhl), "r"(lahbh), "2"(sumhh));\
		\
			a.u32[0] = sumhh;\
			a.u32[1] = sumhl;\
			_hi= a.u64;\
			b.u32[0] = sumlh;\
			b.u32[1] = lalbl;\
			_lo= b.u64;\
		}
ewmayer is offline   Reply With Quote
Old 2019-03-03, 03:33   #11
paulunderwood
 
paulunderwood's Avatar
 
Sep 2002
Database er0rr

3·11·101 Posts
Default

This compiles:

Code:
#define uint32 unsigned int
#define uint64 unsigned long long

#define MUL_LOHI64(_x,_y,_lo,_hi)\
{\
	uint32 ah,al;\
	union bytes {\
		uint32 u32[2];\
		uint64 u64;\
	} Ua;\
	Ua.u64 = _x;\
	ah = Ua.u32[0];\
	al = Ua.u32[1];\
	_lo = _x*_y;/* Placeholder for actual 32-bit-based lo-part computation */\
	_hi = a;/* Placeholder for actual 32-bit-based hi-part computation */\
}

int main(){
	uint64 a = 6,b = 7,lo,hi;
	MUL_LOHI64(a,b,lo,hi);
	return(0);
};
Note that when your macro is expanded you have two definitions for "a" -- I have avoided this with "Ua". But does it function properly?

Last fiddled with by paulunderwood on 2019-03-03 at 03:38
paulunderwood is online now   Reply With Quote
Reply

Thread Tools


Similar Threads
Thread Thread Starter Forum Replies Last Post
Type of work to get? Bispen Information & Answers 3 2016-01-27 16:46
Refurb. Mac emits "Bad CPU type in executable" error ewmayer Hardware 15 2014-08-11 22:03
PSP servers incompatible with latest client? Punchy Prime Sierpinski Project 3 2013-11-30 03:46
Ram type JuanTutors Hardware 4 2004-08-14 23:04
Incompatible Hardy-Littlewood conjectures: a DC project? GP2 Math 2 2003-09-14 04:36

All times are UTC. The time now is 09:19.

Sat Aug 8 09:19:37 UTC 2020 up 22 days, 5:06, 1 user, load averages: 2.41, 2.34, 2.22

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.

This forum has received and complied with 0 (zero) government requests for information.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation.
A copy of the license is included in the FAQ.