# Find specific Neoverse features

## In this learning path

- [Introduction](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cplusplus_compilers_flags/)
- [Compiler basics](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cplusplus_compilers_flags/1/)
- [Set up Your Environment](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cplusplus_compilers_flags/2/)
- [Find specific Neoverse features](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cplusplus_compilers_flags/3/)
- [Try an example application](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cplusplus_compilers_flags/4/)
- [Next Steps](https://learn.arm.com/learning-paths/servers-and-cloud-computing/cplusplus_compilers_flags/_next-steps/)

## Versions of Arm-based instances on Neoverse
To confirm the CPU architecture on your system, use the following command to extract a human-readable string:

```
lscpu | grep -i model
```

The output will include a line such as `Model name: Neoverse-V3-AE` or similar, depending on your hardware. This string is important if you need to specify the CPU type for cross-compiling and passing the `-mcpu` flag to compilers. If the model name is not output, which can occur due to the `lscpu` utility not being aware of recent CPUs, you can extract the CPU part number with the tip below.

### Tip
If you are using a very recent CPU and `lscpu` does not report a human readable model name. You can manually extract the unique CPU part numbers with the following command.

```
grep "CPU part" /proc/cpuinfo | sort -u
```

For example on the Arm AGI CPU. We observe the following:

```
__output__
CPU part        : 0xd83
```

To map this value to a more memorable human readable name which a compiler can parse, there is a [convenient community generated table](https://gpages.juszkiewicz.com.pl/arm-socs-table/arm-cpu-cores.html) maintained by Marcin Juszkiewicz, with data available under an MIT license. To confirm, cross referencing the CPU part number with the `MIDR_EL1` register in technical reference manual of the architecture.

The command above was executed on the Arm AGI CPU with the part number corresponding to the [Neoverse V3-AE architecture](https://developer.arm.com/documentation/101595/0002/AArch64-registers/AArch64-Identification-registers-summary/MIDR-EL1--Main-ID-Register?lang=en).

## Identify supported CPU features
To identify Arm architecture features at runtime in a C program, you can use the Linux hardware capabilities (HWCAP) vector. The source code below reads a specific vector that contains this information.

Use a text editor to copy and paste the C program below into a file named `hw_cap.c`:

```
#include <stdio.h>
#include <sys/auxv.h>
#include <asm/hwcap.h>

int main() {
    long hwcaps = getauxval(AT_HWCAP);

    if (hwcaps & HWCAP_AES) {
        printf("AES instructions are available\n");
    } else {
        printf("AES instructions are not available\n");
    }
    if (hwcaps & HWCAP_CRC32) {
        printf("CRC32 instructions are available\n");
    } else {
        printf("CRC32 instructions are not available\n");
    }
    if (hwcaps & HWCAP_PMULL) {
        printf("PMULL/PMULL2 instructions that operate on 64-bit data are available\n");
    } else {
        printf("PMULL/PMULL2 instructions are not available\n");
    }
    if (hwcaps & HWCAP_SHA1) {
        printf("SHA1 instructions are available\n");
    } else {
        printf("SHA1 instructions are not available\n");
    }
    if (hwcaps & HWCAP_SHA2) {
        printf("SHA2 instructions are available\n");
    } else {
        printf("SHA2 instructions are not available\n");
    }
    if (hwcaps & HWCAP_SVE) {
        printf("Scalable Vector Extension (SVE) instructions are available\n");
    } else {
        printf("Scalable Vector Extension (SVE) instructions are not available\n");
    }

    return 0;
}
```

Compile and run the program with the compiler installed in the previous section:

```
gcc-16 hw_cap.c -o hw_cap
./hw_cap
```

The output below confirms that Scalable Vector Extensions (SVE) are available:

```
__output__
AES instructions are available
__output__
CRC32 instructions are available
__output__
PMULL/PMULL2 instructions that operate on 64-bit data are available
__output__
SHA1 instructions are available
__output__
SHA2 instructions are available
__output__
Scalable Vector Extension (SVE) instructions are available
```

For the latest list of all hardware capabilities available for a specific Linux kernel version, see the `arch/arm/include/uapi/asm/hwcap.h` header file in the Linux Kernel source code.

Additionally, knowing the SVE vector width is useful for optimizing software performance.

Use a text editor to copy and paste the following C code into a file named `sve_width.c`:

```
#include <arm_sve.h>
#include <stdio.h>

int main() {
    int sve_width = svcntb();
    printf("SVE vector length: %d bytes\n", sve_width);
    return 0;
}
```

Compile and run the program with the following commands:

```
g++-16 -mcpu=neoverse-v3ae sve_width.c -o sve_width
./sve_width
```

The output shows that the Arm AGI CPU has a SVE width of 16 bytes (128 bits).

```
__output__
SVE vector length: 16 bytes
```

## Supported Compiler Features
Fortunately, the g++ compiler automatically identifies the host system’s capability. You can use the `-###` argument to show the full options used when compiling.

You can observe which processors are potential targets for compiling your code using the following g++ command:

```
g++ -E -mcpu=help -xc /dev/null
```

The output is:

```
__output__
cc1: note: valid arguments are: cortex-a34 cortex-a35 cortex-a53 cortex-a57 cortex-a72 cortex-a73 thunderx thunderxt88 thunderxt88p1 octeontx octeontx81 octeontx83 thunderxt81 thunderxt83 ampere1 ampere1a ampere1b ampere1c emag xgene1 falkor qdf24xx exynos-m1 phecda thunderx2t99p1 vulcan thunderx2t99 cortex-a55 cortex-a75 cortex-a76 cortex-a76ae cortex-a77 cortex-a78 cortex-a78ae cortex-a78c cortex-a65 cortex-a65ae cortex-x1 cortex-x1c neoverse-n1 ares neoverse-e1 octeontx2 octeontx2t98 octeontx2t96 octeontx2t93 octeontx2f95 octeontx2f95n octeontx2f95mm a64fx fujitsu-monaka hip12 tsv110 thunderx3t110 neoverse-v1 zeus neoverse-512tvb saphira oryon-1 cortex-a57.cortex-a53 cortex-a72.cortex-a53 cortex-a73.cortex-a35 cortex-a73.cortex-a53 cortex-a75.cortex-a55 cortex-a76.cortex-a55 cortex-r82 cortex-r82ae apple-a12 apple-m1 apple-m1 apple-m1 apple-m1 apple-m2 apple-m2 apple-m2 apple-m2 apple-m3 apple-m3 apple-m3 apple-m4 apple-m4 apple-m4 cortex-a510 cortex-a520 cortex-a520ae cortex-a710 cortex-a715 cortex-a720 cortex-a720ae cortex-a725 cortex-a320 cortex-x2 cortex-x3 cortex-x4 cortex-x925 neoverse-n2 cobalt-100 neoverse-n3 neoverse-v2 grace neoverse-v3 neoverse-v3ae c1-nano c1-pro c1-premium c1-ultra demeter olympus gb10 generic generic-armv8-a generic-armv9-a
```

Comparing the same command using default `g++` version 13.3.0 shows that there are fewer CPU targets available, with notably omission of Neoverse V3-AE architecture, used in the Arm AGI CPU.

```
g++ -E -mcpu=help -xc /dev/null
```

The output from version 13 is:

```
__output__
cc1: note: valid arguments are: cortex-a35 cortex-a53 cortex-a57 cortex-a72 cortex-a73 thunderx thunderxt88p1 thunderxt88 octeontx octeontx81 octeontx83 thunderxt81 thunderxt83 emag xgene1 falkor qdf24xx exynos-m1 phecda thunderx2t99p1 vulcan thunderx2t99 cortex-a55 cortex-a75 cortex-a76 ares neoverse-n1 neoverse-e1 a64fx tsv110 zeus neoverse-v1 neoverse-512tvb saphira neoverse-n2 cortex-a57.cortex-a53 cortex-a72.cortex-a53 cortex-a73.cortex-a35 cortex-a73.cortex-a53 cortex-a75.cortex-a55 cortex-a76.cortex-a55 generic
```

### Please Note
For the Arm AGI CPU, the `-mcpu=armagicpu` definition was added in [GCC 16.1.0](https://github.com/gcc-mirror/gcc/commit/0f5f728854d2ea93e6806a8632c04383502b0386). As of May 2026, this is the same as the `-march=neoverse-v3ae` option available from [GCC 15](https://gcc.gnu.org/gcc-15/changes.html) onwards. However, in the future there may be differences between `neoverse-v3ae` and `armagicpu`.

As such, we recommend installing the latest version of GCC/G++ if you are targeting the Arm AGI CPU. Use the `-mcpu=native` flag if compiling on the target machine or `-mcpu=armagicpu` if cross compiling.
