Starting in armv8-a ISA, all instructions are hard-float, and therefore all CPUs have a floating-point unit. This was not the case before, and thus I found out about it while porting our software to QNX 6..0 for an armv7-based board.
This board comes with a Zynq-7000 CPU, which does have a hardware FPU, thus my assumption was that QNX knew that, and so to take advantage of it, I would build my libraries to make sure hardware instructions are used. But I run into problems. Turns out QNX did come with a soft-float flavor (LIBC that comes with it), and this was making things crash. My libraries would expect function parameters, and return values in certain memory locations while the system LIBC would expect them in actual CPU registers. This was a big no-no, of course. Specifically, LIBC would expect from the caller the first four arguments in R0-R3, excess arguments in the stack (in a reverse order for variadic subroutines, with variable number of parameters), and a return value in R0.
A way to find that out is to find out what the qcc front-end compiler driver supports, and then look into the corresponding configuration file.
$ /opt/qnx660/host/linux/x86/usr/bin/qcc -V cc: targets available in /opt/qnx660/host/linux/x86/etc/qcc: 4.7.3,gcc_ntox86_gpp 4.7.3,gcc_ntoarmv7le_cpp-ne 4.7.3,gcc_ntoarmv7le 4.7.3,gcc_ntox86_cpp 4.7.3,gcc_ntoarmv7le_gpp 4.7.3,gcc_ntox86_cpp-ne 4.7.3,gcc_ntoarmv7le_cpp 4.7.3,gcc_ntox86 (default)
From all of this, I was interested in 4.7.3,gcc_ntoarmv7le_cpp, which will tell the GCC 4.7.3 compiler what architecture to target, with which floating-point and all the relevant compilation options. The way qcc works is through configuration files that have the same nameas the options we provide to qcc, like above. That way, I found the following .conf file within the QNX toolchain:
qnx660/host/linux/x86/etc/qcc/gcc/4.7.3/gcc_ntoarmv7le_cpp.conf
This describes the build options that are supported, and we can see interesting things like this:
cpp_opt=-E -quiet %(pie:-fPIE) -nostdinc -D_LANGUAGE_C -D_LANGUAGE_C \ -DQNX_ -D_QNXNTO_ \ "-D_GNUC=4" "-DGNUC_MINOR=7" "-DGNUC_PATCHLEVEL=3" \ -Dunix_ -D_unix -DELF_ \ -D_ARM_ -D_arm_ %(!march=:%(!mcpu=:-march=armv7-a)) %(!mfpu=:-mfpu=vfpv3-d16) %(!mfloat-abi=:-mfloat-abi=softfp
So, when targetting ARMv7, I asked the compiler to target the armv7-a instruction set and generate hard-float instructions following the soft-float calling convention. This will be a good fit/option if the CPU that we will be using does actually have an FPU (cortex-a9 has an optional FPU, so it depends on the manufacturer. But if it does have it, this FPU is twice faster than previous ARM FPUs). So, decided to build my libraries the same way as the compiler does:
mfpu=vfpv3-d16
which supports only 16 registers (16 double-precision registers). An instruction which attempts to access any of the registers D16-D31 would generate an UNDEFINED exception.
-mfloat-abi=softfp
which means we will follow software floating point calling convention, going and returning from memory, rather than CPU registers, to be compliant with QNX libc soft-float.
Good learning!