undefined reference to `__popcnt'

General FreeBASIC programming questions.
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

undefined reference to `__popcnt'

Post by Iczer »

I'm trying to compile curl library with http3 support, so I compiled and added nghttp3 and ngtcp2 static libraries - it compiled successfully under mingw64 7.2.
But when I added resulted curl static library to FreeBasic 1.09 (gcc 5.2, gcc 8.1) project - compilation fails with:

Code: Select all

C:/Temp/nghttp3-0.7.0/lib/nghttp3_ringbuf.c:50: undefined reference to `__popcnt'
E:\Program Files\FreeBASIC\libPlusN3/libnghttp3.a(nghttp3_ringbuf.c.obj): In function `nghttp3_ringbuf_reserve':
C:/Temp/nghttp3-0.7.0/lib/nghttp3_ringbuf.c:130: undefined reference to `__popcnt'
E:\Program Files\FreeBASIC\libPlusN3/libngtcp2.a(ngtcp2_ringbuf.c.obj): In function `ngtcp2_ringbuf_buf_init':
C:/Temp/ngtcp2-0.8.1/lib/ngtcp2_ringbuf.c:59: undefined reference to `__popcnt'
As I understand "__popcnt" - is macro/function that compiler should know (at least mingw64 7.2 know it). What I should do with it? Its internal functions - I'm not using them from my project (at least directly).
In sources there a replacement for arm defined like this:

Code: Select all

#if defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
	unsigned int __popcnt(unsigned int x) {
	  unsigned int c = 0;
	  for (; x; ++c) {
		x &= x - 1;
	  }
	  return c;
	}
#endif
But I'm not sure how I should translate it to FreeBasic...
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: undefined reference to `__popcnt'

Post by deltarho[1859] »

Perhaps your CPU does not support popcnt; introduced in 2007 and 2008 with AMD and Intel respectively.

Try this:

Code: Select all

Extern "c"
  Declare Function __builtin_cpu_supports (ByVal As Const ZString Ptr) As Long
End Extern
If __builtin_cpu_supports ("popcnt") Then
  Print "Your CPU supports the POPCNT instruction."
Else
  Print "Your CPU does not support the POPCNT instruction."
End If
Sleep
SARG
Posts: 1756
Joined: May 27, 2005 7:15
Location: FRANCE

Re: undefined reference to `__popcnt'

Post by SARG »

You can use this function. It's one way to do thing. Don't forget to remove the print.

Code: Select all

'This function calculates the number of bits set to 1 
function bit_count(prm as uinteger) as integer
	dim as string strg=bin(prm)
	dim as integer cnt
	print prm,strg
	for i as integer = 0 to sizeof(uinteger)*8-1
		if strg[i]=49 then
			cnt+=1
		EndIf
	Next
	return cnt
End Function

print bit_count(15)
print bit_count(1)
print bit_count(2)
print bit_count(3)

print bit_count(-15)
print bit_count(-1)
print bit_count(-2)
print bit_count(-3)
sleep
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: undefined reference to `__popcnt'

Post by dodicat »

Here are a couple more for popcount.

Code: Select all

declare function popcount cdecl alias "__popcountdi2"(as ulongint) as ulong '<---- library function, gas or gcc

for n as long=1 to 10
      var num=int(rnd*500)
print popcount(num),bin(num)
next


Function popcount2(x As Ulongint) As Ulong
      If x=18446744073709551615 Then Return 64
      x -= ((x Shr 1) And &h5555555555555555ull)
      x = (((x Shr 2) And &h3333333333333333ull) + (x And &h3333333333333333ull))
      x = (((x Shr 4) + x) And &hf0f0f0f0f0f0f0full)
      x += (x Shr 8)
      x += (x Shr 16)
      x+= (x Shr 32)
     return  x And &h0000003full
End function

print
for n as long=1 to 10
      var num=int(rnd*500)
print popcount2(num),bin(num)
next


sleep

 
Deltarho
I get
undefined reference to `__builtin_cpu_supports'
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: undefined reference to `__popcnt'

Post by deltarho[1859] »

dodicat wrote:Deltarho
I get
undefined reference to `__builtin_cpu_supports'
What a nuisance. :)

Here is another way:

Code: Select all

#Include Once "windows.bi"
Function IsPopcnt() As Long
Dim CPUManID As String * 12
Dim CPUManIDPtr As ULong Ptr

' Get Manufactures Id String
CPUManIDPtr = CPtr(ULong Ptr, StrPtr( CPUManID ))
Asm
  mov eax, 0 ' Get Vendor Id
  cpuid
  mov eax, [CPUManIDPtr]
  mov [eax], ebx
  mov [eax + 4], edx
  mov [eax + 8], ecx
End Asm
If CPUManID = "GenuineIntel" Or CPUManID = "AuthenticAMD" Then
  ' Is popcnt supported?
  Asm
    mov eax, 1 ' Get features
    cpuid
    test ecx, &h800000 ' Bit 23
    jz NoPopcnt
    mov [Function], -1
NoPopcnt:
  End Asm
End If
End Function

If IsPopcnt Then
  Messagebox( NULL, "Yes, it is.", "Is popcnt supported?", MB_OK )
Else
  Messagebox( NULL, "No, it is not.", "Is popcnt supported?", MB_OK )
End If
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: undefined reference to `__popcnt'

Post by deltarho[1859] »

Will __popcountdi2 work on an 'old' CPU or is it a popcnt emulator?
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: undefined reference to `__popcnt'

Post by dodicat »

Deltarho[~]
Your asm code:
:40: Error: incorrect register `eax' used with `q' suffix (64 bits)

:56: Error: ambiguous operand size for `mov' (32 bits)

We did all this popcount stuff in September last year.
adeyblue also contributed, but he has gone now it seems.

"Will __popcountdi2 work on an 'old' CPU or is it a popcnt emulator?"
I am using an old cpu
HP Compaq 8200 Elite SFF PC
2011 I think.
Probably time for an Ebay browse.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: undefined reference to `__popcnt'

Post by deltarho[1859] »

From Microsoft: "64-bit popcnt isn't supported."

The simplest and safest solution is SARG's code above. There are faster BASIC solutions, but they are not worth pursuing unless we go past 'bit_count' millions of times. It works with gas, gas64 and gcc 32/64.
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: undefined reference to `__popcnt'

Post by dodicat »

I agree.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: undefined reference to `__popcnt'

Post by deltarho[1859] »

Tighter code, but only a little faster.

Code: Select all

Function bit_count(prm As UInteger) As Integer
Dim As Integer cnt
For i As Integer = 0 To SizeOf(UInteger)*8-1
  cnt-=Bit(prm, i)
Next
Return cnt
End Function
SARG
Posts: 1756
Joined: May 27, 2005 7:15
Location: FRANCE

Re: undefined reference to `__popcnt'

Post by SARG »

@dodicat
I guess deltarho's code is to be run on 32bit. However adaptable for 64bit.

deltarho[1859] wrote: Sep 13, 2022 12:26 but they are not worth pursuing unless we go past 'bit_count' millions of times
I agree.

edit : I rarely play with bits. Nice improvement
SARG
Posts: 1756
Joined: May 27, 2005 7:15
Location: FRANCE

Re: undefined reference to `__popcnt'

Post by SARG »

Removing the test ;-)

Code: Select all

'This function calculates the number of bits set to 1 
function bit_count(prm as uinteger) as integer
	dim as string strg=bin(prm,sizeof(uinteger)*8)
	dim as integer cnt
	for i as integer = 0 to sizeof(uinteger)*8-1
		cnt+=strg[i]-48
	Next
	return cnt
End Function
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: undefined reference to `__popcnt'

Post by deltarho[1859] »

Reduce For count to actual length. :wink:

Code: Select all

Function bit_count(prm As UInteger) As Integer
Dim As Integer cnt
For i As Integer = 0 To Len(Bin(prm))-1
  cnt-=Bit(prm, i)
Next
Return cnt
End Function
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: undefined reference to `__popcnt'

Post by marcov »

(it could be that __popcnt is the fallback for if the selected arch doesn't understand the decade old popcnt instruction, which probably be inlined if you configure the minimal architecture correctly)
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: undefined reference to `__popcnt'

Post by dodicat »

Here is the translation from the first post, skipping the _M_ARM stuff

Code: Select all

#macro hide
#if defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
	unsigned int __popcnt(unsigned int x) {
	  unsigned int c = 0;
	  for (; x; ++c) {
		x &= x - 1;
	  }
	  return c;
	}
#endif
#endmacro

function __popcnt(x as ulongint) as ulongint
    dim as ulongint c=0
    do
        c+=1
        x and= x-1
        loop until x=0
    return c
end function

for n as long=1 to 200
    var num=int(rnd*5000)
print __popcnt(num),bin(num),num
next n
sleep 
Post Reply