static void parse_features()

in src/arm/linux/cpuinfo.c [100:309]


static void parse_features(
	const char* features_start,
	const char* features_end,
	struct cpuinfo_arm_linux_processor processor[restrict static 1])
{
	const char* feature_start = features_start;
	const char* feature_end;

	/* Mark the features as valid */
	processor->flags |= CPUINFO_ARM_LINUX_VALID_FEATURES | CPUINFO_ARM_LINUX_VALID_PROCESSOR;

	do {
		feature_end = feature_start + 1;
		for (; feature_end != features_end; feature_end++) {
			if (*feature_end == ' ') {
				break;
			}
		}
		const size_t feature_length = (size_t) (feature_end - feature_start);

		switch (feature_length) {
			case 2:
				if (memcmp(feature_start, "fp", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_FP;
#endif
#if CPUINFO_ARCH_ARM
				} else if (memcmp(feature_start, "wp", feature_length) == 0) {
					/*
					 * Some AArch64 kernels, including the one on Nexus 5X,
					 * erroneously report "swp" as "wp" to AArch32 programs
					 */
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_SWP;
#endif
				} else {
					goto unexpected;
				}
				break;
			case 3:
				if (memcmp(feature_start, "aes", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM
						processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_AES;
					#elif CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_AES;
					#endif
#if CPUINFO_ARCH_ARM
				} else if (memcmp(feature_start, "swp", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_SWP;
				} else if (memcmp(feature_start, "fpa", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_FPA;
				} else if (memcmp(feature_start, "vfp", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFP;
				} else if (memcmp(feature_start, "tls", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_TLS;
#endif /* CPUINFO_ARCH_ARM */
				} else {
					goto unexpected;
				}
				break;
			case 4:
				if (memcmp(feature_start, "sha1", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM
						processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_SHA1;
					#elif CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_SHA1;
					#endif
				} else if (memcmp(feature_start, "sha2", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM
						processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_SHA2;
					#elif CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_SHA2;
					#endif
				} else if (memcmp(feature_start, "fphp", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_FPHP;
					#endif
				} else if (memcmp(feature_start, "fcma", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_FCMA;
					#endif
#if CPUINFO_ARCH_ARM
				} else if (memcmp(feature_start, "half", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_HALF;
				} else if (memcmp(feature_start, "edsp", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_EDSP;
				} else if (memcmp(feature_start, "java", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_JAVA;
				} else if (memcmp(feature_start, "neon", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_NEON;
				} else if (memcmp(feature_start, "lpae", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_LPAE;
				} else if (memcmp(feature_start, "tlsi", feature_length) == 0) {
					/*
					 * Some AArch64 kernels, including the one on Nexus 5X,
					 * erroneously report "tls" as "tlsi" to AArch32 programs
					 */
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_TLS;
#endif /* CPUINFO_ARCH_ARM */
				} else {
					goto unexpected;
				}
				break;
			case 5:
				if (memcmp(feature_start, "pmull", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM
						processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_PMULL;
					#elif CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_PMULL;
					#endif
				} else if (memcmp(feature_start, "crc32", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM
						processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_CRC32;
					#elif CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_CRC32;
					#endif
				} else if (memcmp(feature_start, "asimd", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_ASIMD;
					#endif
				} else if (memcmp(feature_start, "cpuid", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_CPUID;
					#endif
				} else if (memcmp(feature_start, "jscvt", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_JSCVT;
					#endif
				} else if (memcmp(feature_start, "lrcpc", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_LRCPC;
					#endif
#if CPUINFO_ARCH_ARM
				} else if (memcmp(feature_start, "thumb", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_THUMB;
				} else if (memcmp(feature_start, "26bit", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_26BIT;
				} else if (memcmp(feature_start, "vfpv3", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPV3;
				} else if (memcmp(feature_start, "vfpv4", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPV4;
				} else if (memcmp(feature_start, "idiva", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_IDIVA;
				} else if (memcmp(feature_start, "idivt", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_IDIVT;
#endif /* CPUINFO_ARCH_ARM */
				} else {
					goto unexpected;
				}
 				break;
#if CPUINFO_ARCH_ARM
			case 6:
				if (memcmp(feature_start, "iwmmxt", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_IWMMXT;
				} else if (memcmp(feature_start, "crunch", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_CRUNCH;
				} else if (memcmp(feature_start, "vfpd32", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPD32;
				} else {
					goto unexpected;
				}
				break;
#endif /* CPUINFO_ARCH_ARM */
			case 7:
				if (memcmp(feature_start, "evtstrm", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_EVTSTRM;
				} else if (memcmp(feature_start, "atomics", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_ATOMICS;
					#endif
				} else if (memcmp(feature_start, "asimdhp", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_ASIMDHP;
					#endif
#if CPUINFO_ARCH_ARM
				} else if (memcmp(feature_start, "thumbee", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_THUMBEE;
#endif /* CPUINFO_ARCH_ARM */
				} else {
					goto unexpected;
				}
				break;
			case 8:
				if (memcmp(feature_start, "asimdrdm", feature_length) == 0) {
					#if CPUINFO_ARCH_ARM64
						processor->features |= CPUINFO_ARM_LINUX_FEATURE_ASIMDRDM;
					#endif
#if CPUINFO_ARCH_ARM
				} else if (memcmp(feature_start, "fastmult", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_FASTMULT;
				} else if (memcmp(feature_start, "vfpv3d16", feature_length) == 0) {
					processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPV3D16;
#endif /* CPUINFO_ARCH_ARM */
				} else {
					goto unexpected;
				}
				break;
			default:
			unexpected:
				cpuinfo_log_warning("unexpected /proc/cpuinfo feature \"%.*s\" is ignored",
					(int) feature_length, feature_start);
				break;
		}
		feature_start = feature_end;
		for (; feature_start != features_end; feature_start++) {
			if (*feature_start != ' ') {
				break;
			}
		}
	} while (feature_start != feature_end);
}