Why is __ARM_FEATURE_CRC32 not being defined by the compiler? - c++

I've been working on this issue for some time now, and I hope someone can point out my mistake. I guess I can no longer see the forest through the trees.
I have a LeMaker HiKey dev board I use for testing. Its AArch64, so its has NEON and the other cpu features like AES, SHA and CRC32:
$ cat /proc/cpuinfo
Processor : AArch64 Processor rev 3 (aarch64)
...
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
...
When I attempt to compile a program:
$ cat test.cxx
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
# define NEON_INTRINSICS_AVAILABLE 1
#else
# define NEON_INTRINSICS_AVAILABLE 0
#endif
#if BOOL_NEON_INTRINSICS_AVAILABLE
# include <arm_neon.h>
# if defined(__ARM_FEATURE_CRC32) || (__ARM_ACLE >= 200)
# include <arm_acle.h>
# endif
#endif
#include <stdint.h>
int main(int argc, char* argv[])
{
uint32_t crc = 0;
crc = __crc32b(crc, (uint8_t)0);
return 0
}
It results in the following:
$ g++ test.cxx -o test.exe
test.cxx: In function ‘int main(int, char**)’:
test.cxx:20:33: error: ‘__crc32b’ was not declared in this scope
crc = __crc32b(crc, (uint8_t)0);
^
test.cxx:22:1: error: expected ‘;’ before ‘}’ token
}
^
$ clang++ test.cxx -o test.exe
test.cxx:20:9: error: use of undeclared identifier '__crc32b'
crc = __crc32b(crc, (uint8_t)0);
^
test.cxx:21:11: error: expected ';' after return statement
return 0
^
;
2 errors generated.
A grep of the file system reveals arm_acle.h is in fact the header:
$ grep -IR '__crc32' /usr/lib
/usr/lib/gcc/.../include/arm_acle.h:__crc32b (uint32_t __a, uint8_t __b)
...
And according to ARM® C Language Extensions, Section 9.7 CRC32 Intrinsics, the missing symbols are suppose be present when __ARM_FEATURE_CRC32 is defined. Inspecting arm_acle.h confirms it.
For completeness, I tried compiling with -march=native, but the compiler rejected it.
Why is __ARM_FEATURE_CRC32 not being defined by the compiler?
What can I do to get the program to compile with the native features available on the board?
$ gcc --version
gcc (Debian/Linaro 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ clang --version
Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: aarch64-unknown-linux-gnu
Thread model: posix
$ g++ -dM -E - </dev/null | egrep -i '(arm|neon|acle)'
#define __ARM_NEON 1
$ clang++ -dM -E - </dev/null | egrep -i '(arm|neon|acle)'
#define __ARM_64BIT_STATE 1
#define __ARM_ACLE 200
#define __ARM_ALIGN_MAX_STACK_PWR 4
#define __ARM_ARCH 8
#define __ARM_ARCH_ISA_A64 1
#define __ARM_ARCH_PROFILE 'A'
#define __ARM_FEATURE_CLZ 1
#define __ARM_FEATURE_DIV 1
#define __ARM_FEATURE_FMA 1
#define __ARM_FEATURE_UNALIGNED 1
#define __ARM_FP 0xe
#define __ARM_FP16_FORMAT_IEEE 1
#define __ARM_FP_FENV_ROUNDING 1
#define __ARM_NEON 1
#define __ARM_NEON_FP 0xe
#define __ARM_PCS_AAPCS64 1
#define __ARM_SIZEOF_MINIMAL_ENUM 4
#define __ARM_SIZEOF_WCHAR_T 4

As for why this feature isn't enabled by default; this is an optional feature not present in the baseline ABI that your compiler targets, i.e. the binaries that your compiler produces are expected to be able to run on devices lacking the CRC feature.
At least for gcc, you can enable this feature with the -march modifier crc, like this:
$ gcc -dM -E - -march=armv8-a+crc < /dev/null | egrep -i '(arm|neon|acle|crc)'
#define __ARM_FEATURE_CRC32 1
#define __ARM_NEON 1
See https://gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/AArch64-Options.html (or the same page for older gcc versions) for more docs on how to set this.
I guess one could expect -march=native to do the same, but that option currently only seems to be implemented for x86 architectures.

Related

Why isn't -mmacosx-version-min=10.10 preventing use of a function tagged as starting in 10.11?

By my understanding of how the availability macros and the -mmacosx-version-min flag works, the following code should fail to compile when targeting OS X 10.10:
#include <Availability.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
#error
#endif
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101000
#error __MAC_OSX_VERSION_MIN_REQUIRED too low
#endif
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101000
#error __MAC_OSX_VERSION_MIN_REQUIRED too high
#endif
int main() {
size_t len = 0;
SSLContextRef x{};
auto status = SSLCopyRequestedPeerNameLength(x, &len);
return status != 0;
}
because the function SSLCopyRequestedPeerNameLength is tagged as becoming available in 10.11 in SecureTransport.h:
$ grep -C5 ^SSLCopyRequestedPeerNameLength /System/Library/Frameworks//Security.framework/Headers/SecureTransport.h
/*
* Server Only: obtain the hostname specified by the client in the ServerName extension (SNI)
*/
OSStatus
SSLCopyRequestedPeerNameLength (SSLContextRef ctx,
size_t *peerNameLen)
__OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
Yet when I compile on the command line with -mmacosx-version-min=10.10 I get no warning at all, despite -Wall -Werror -Wextra:
$ clang++ -Wall -Werror -Wextra ./foo.cpp --std=c++11 -framework Security -mmacosx-version-min=10.10 --stdlib=libc++ ; echo $?
0
Is there some additional definition I need to provide or specific warning to enable to ensure that I don't pick up a dependency on APIs newer than 10.10? I really had expected that -mmacosx-version-min=10.10 would prevent usage of APIs tagged with higher version numbers.
What have I misunderstood here?
Using XCode 10.0 (10A255) on macOS 10.13.6 here.
Now that I can answer my own question, I will: you need to add -Wunguarded-availability to your compile flags. Only then will you get a warning/error.

warning: 'assume_aligned' attribute directive ignored

I just started with C++ and i think the best way is to look at source codes. I have code as follows in the header file.
#ifdef _MSC_VER
#define MYAPP_CACHE_ALIGNED_RETURN /* not supported */
#else
#define MYAPP_CACHE_ALIGNED_RETURN __attribute__((assume_aligned(64)))
#endif
I am using gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11) and its quite old. I get this warning during compilation:
warning: 'assume_aligned' attribute directiv e ignored [-Wattributes] –
How can I make the if statement more specific to fix the the warning during compilation?
It seems that assume_aligned is not supported in RHEL's GCC (it hasn't been backported to upstream gcc-4_8-branch and also not available in Ubuntu 14.04's GCC 4.8.4 so that wouldn't be surprising).
To emit a more user-friendly diagnostics you can do an explicit check for GCC version in one of your headers:
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
# warning "Your version of GCC does not support 'assume_aligned' attribute"
#endif
But this may not work if your distro vendor has back-ported assume_aligned from upstream (which is not the case for RedHat and Ubuntu but who knows about other distros). The most robust way to check this would be to do a build-time test in configure script or in Makefile:
CFLAGS += $(shell echo 'void* my_alloc1() __attribute__((assume_aligned(16)));' | gcc -x c - -c -o /dev/null -Werror && echo -DHAS_ASSUME_ALIGNED)
This will add HAS_ASSUME_ALIGNED to predefined macro if the attribute is supported by compiler.
Note that you can achieve similar effect with __builtin_assume_aligned function:
void foo() {
double *p = func_that_misses_assume_align();
p = __builtin_assume_aligned(p, 128);
...
}

Header for _blsr_u64 with Sun supplied GCC on Solaris 11?

We've got some code that runs on multiple platforms. The code uses BMI/BMI2 intrinsics when available, like a Core i7 5th gen. GCC supplied by Sun on Solaris 11.3 is defining __BMI__ and __BMI2__, but its having trouble locating BMI/BMI2 intrinsics:
$ cat test.cxx
#include <x86intrin.h>
int main(int argc, char* argv[])
{
unsigned long long t = argc;
#if defined(__BMI__) || defined(__BMI2__)
t = _blsr_u64(t);
#endif
return int(t);
}
$ /bin/g++ -march=native test.cxx -o test.exe
test.cxx: In function ‘int main(int, char**)’:
test.cxx:6:18: error: ‘_blsr_u64’ was not declared in this scope
t = _blsr_u64(t);
^
Including immintrin.h does not make a difference.
Which header do we include for _blsr_u64 when using GCC on Solaris 11.3?
Here are the relevant defines from GCC:
$ /bin/g++ -march=native -dM -E - < /dev/null | sort | \
/usr/gnu/bin/egrep -i '(sse|aes|rdrnd|rdseed|avx|bmi)'
#define __AES__ 1
#define __AVX__ 1
#define __AVX2__ 1
#define __BMI__ 1
#define __BMI2__ 1
#define __core_avx2 1
#define __core_avx2__ 1
#define __RDRND__ 1
#define __RDSEED__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSSE3__ 1
#define __tune_core_avx2__ 1
And CPU features:
$ isainfo -v
64-bit amd64 applications
avx xsave pclmulqdq aes movbe sse4.2 sse4.1 ssse3 amd_lzcnt popcnt tscp
ahf cx16 sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpu prfchw adx
rdseed efs rtm hle bmi2 avx2 bmi1 f16c fma rdrand
And GCC version:
$ /bin/g++ --version
g++ (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
Which header do we include for _blsr_u64 when using GCC on Solaris 11.3?
It looks like #include <x86intrin.h> is correct.
The problem was the compiler invocation required both -march=native -m64 even though 64-bit is native for the machine and the kernel is 64-bit:
$ /bin/g++ -march=native -m64 test.cxx -o test.exe

How can I reliably detect the version of clang at preprocessing time?

Apparently, the clang bundled with Xcode doesn't respect the upstream __clang_major__ and __clang_minor__ values, and instead reports an Xcode user-facing version of some sort.
Here are, for reference, the values for the various MacPorts installs of clang. They seem to respect the upstream release identifiers. I get similar values when testing on Linux.
➜ prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.2 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 2
➜ prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.3 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 3
➜ prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.4 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 4
However, for some reason, the Apple provided clang has __clang_major__ and __clang_minor__ versions that track the Xcode version, not the base clang revision:
➜ prohibit-clang-3.2
/Applications/Xcode-4.6.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 4
#define __clang_minor__ 2
➜ prohibit-clang-3.2
/Applications/Xcode-4.6.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
--version
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
➜ prohibit-clang-3.2
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 5
#define __clang_minor__ 0
➜ prohibit-clang-3.2
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
--version
Apple LLVM version 5.0 (clang-500.2.76) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
➜ prohibit-clang-3.2 /usr/bin/clang++ -dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 5
#define __clang_minor__ 0
This seems pretty awful, because it means you can't write conditional compilation lines like the following that will work accurately across both the Apple vendored clang, and clang built normally from the clang sources or from distro packages:
#if !defined(__clang__) || (__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ > 2))
// Thing that doesn't work for clang-3.2 due to an optimization bug.
#endif
I'd hate to need to extend that already pretty terrible preprocessor check to account for two different clang versioning schemes, one normal and one Apple. I'm not even sure how I could reliably detect that this is 'Xcode clang' rather than normal clang.
Does anyone have any suggestions on how to work around this? Is there a flag to pass to Apple's clang that will instruct it to report its 'true' version? Or has Apple doomed us to never be able to reliably use __clang_major__ and __clang_minor__? Are these not the macros I should be using here?
If the feature checking macros don't cover what you need to check for then you do need to treat vendor releases separately as they may have very different content from the open source LLVM releases. You can use __apple_build_version__ to check for a specific Apple LLVM version.

GNU C++ how to check when -std=c++0x is in effect?

My system compiler (gcc42) works fine with the TR1 features that I want, but trying to support newer compiler versions other than the systems, trying to accessing TR1 headers an #error demanding the -std=c++0x option because of how it interfaces with library or some hub bub like that.
/usr/local/lib/gcc45/include/c++/bits/c++0x_warning.h:31:2: error: #error This file requires compiler and library support for the upcoming ISO C++ standard, C++0x. This support is currently experimental, and must be enabled with the -std=c++0x or -std=gnu++0x compiler options.
Having to supply an extra switch is no problem, to support GCC 4.4 and 4.5 under this system (FreeBSD), but obviously it changes the picture!
Using my system compiler (g++ 4.2 default dialect):
#include <tr1/foo>
using std::tr1::foo;
Using newer (4.5) versions of the compiler with -std=c++0x:
#include <foo>
using std::foo;
Is there anyway using the pre processor, that I can tell if g++ is running with C++0x features enabled?
Something like this is what I'm looking for:
#ifdef __CXX0X_MODE__
#endif
but I have not found anything in the manual or off the web.
At this rate, I'm starting to think that life would just be easier, to use Boost as a dependency, and not worry about a new language standard arriving before TR4... hehe.
There seems, with gcc 4.4.4, to be only one predefined macro hinting that -std=c++0x is in effect:
#define __GXX_EXPERIMENTAL_CXX0X__ 1
I don't have access to gcc 4.5.0 , but you can check that one yourself:
[16:13:41 0 ~] $ g++ -E -dM -std=c++0x -x c++ /dev/null >b
[16:13:44 0 ~] $ g++ -E -dM -std=c++98 -x c++ /dev/null >a
[16:13:50 0 ~] $ diff -u a b
--- a 2010-06-02 16:13:50.200787591 +0200
+++ b 2010-06-02 16:13:44.456912378 +0200
## -20,6 +20,7 ##
#define __linux 1
#define __DEC32_EPSILON__ 1E-6DF
#define __unix 1
+#define __GXX_EXPERIMENTAL_CXX0X__ 1
#define __LDBL_MAX_EXP__ 16384
#define __linux__ 1
#define __SCHAR_MAX__ 127
For one-line command do,
g++ -E -dM -std=c++98 -x c++ /dev/null > std1 && g++ -E -dM -std=c++0x -x c++ /dev/null > std2 && diff -u std1 std2 | grep '[+|-]^*#define' && rm std1 std2
gives you something like:
+#define __GXX_EXPERIMENTAL_CXX0X__ 1
If you compile with -std=c++0x, then __GXX_EXPERIMENTAL_CXX0X__ will be defined.
Well, from gcc-4.7 onwards you'll be able to check __cplusplus:
"G++ now sets the predefined macro __cplusplus to the correct value, 199711L for C++98/03, and 201103L for C++11"
This should be the correct, standard-compliant way to do it. Unfortunately, it doesn't work for most gcc installed in the wild.