1    	/*
2    	 * GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic
3    	 * James S. Plank, Ethan L. Miller, Kevin M. Greenan,
4    	 * Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride.
5    	 *
6    	 * gf_cpu.h
7    	 *
8    	 * Identifies whether the CPU supports SIMD instructions at runtime.
9    	 */
10   	
11   	#include <stdio.h>
12   	#include <stdlib.h>
13   	
14   	int gf_cpu_identified = 0;
15   	
16   	int gf_cpu_supports_intel_pclmul = 0;
17   	int gf_cpu_supports_intel_sse4 = 0;
18   	int gf_cpu_supports_intel_ssse3 = 0;
19   	int gf_cpu_supports_intel_sse3 = 0;
20   	int gf_cpu_supports_intel_sse2 = 0;
21   	int gf_cpu_supports_arm_neon = 0;
22   	
23   	#if defined(__x86_64__)
24   	
25   	/* CPUID Feature Bits */
26   	
27   	/* ECX */
28   	#define GF_CPU_SSE3     (1 << 0)
29   	#define GF_CPU_PCLMUL   (1 << 1)
30   	#define GF_CPU_SSSE3    (1 << 9)
31   	#define GF_CPU_SSE41    (1 << 19)
32   	#define GF_CPU_SSE42    (1 << 20)
33   	
34   	/* EDX */
35   	#define GF_CPU_SSE2     (1 << 26)
36   	
37   	#if defined(_MSC_VER)
38   	
39   	#define cpuid(info, x)    __cpuidex(info, x, 0)
40   	
41   	#elif defined(__GNUC__)
42   	
43   	#include <cpuid.h>
44   	void cpuid(int info[4], int InfoType){
45   	    __cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]);
46   	}
47   	
48   	#else
49   	
50   	#error please add a way to detect CPU SIMD support at runtime 
51   	
52   	#endif
53   	
54   	void gf_cpu_identify(void)
55   	{
56   	  if (gf_cpu_identified) {
57   	      return;
58   	  }
59   	
60   	  int reg[4];
61   	
62   	  cpuid(reg, 1);
63   	
64   	#if defined(INTEL_SSE4_PCLMUL)
65   	  if ((reg[2] & GF_CPU_PCLMUL) != 0 && !getenv("GF_COMPLETE_DISABLE_SSE4_PCLMUL")) {
66   	      gf_cpu_supports_intel_pclmul = 1;
67   	#ifdef DEBUG_CPU_DETECTION
68   	      printf("#gf_cpu_supports_intel_pclmul\n");
69   	#endif
70   	  }
71   	#endif
72   	
73   	#if defined(INTEL_SSE4)
74   	  if (((reg[2] & GF_CPU_SSE42) != 0 || (reg[2] & GF_CPU_SSE41) != 0) && !getenv("GF_COMPLETE_DISABLE_SSE4")) {
75   	      gf_cpu_supports_intel_sse4 = 1;
76   	#ifdef DEBUG_CPU_DETECTION
77   	      printf("#gf_cpu_supports_intel_sse4\n");
78   	#endif
79   	  }
80   	#endif
81   	
82   	#if defined(INTEL_SSSE3)
83   	  if ((reg[2] & GF_CPU_SSSE3) != 0 && !getenv("GF_COMPLETE_DISABLE_SSSE3")) {
84   	      gf_cpu_supports_intel_ssse3 = 1;
85   	#ifdef DEBUG_CPU_DETECTION
86   	      printf("#gf_cpu_supports_intel_ssse3\n");
87   	#endif
88   	  }
89   	#endif
90   	
91   	#if defined(INTEL_SSE3)
92   	  if ((reg[2] & GF_CPU_SSE3) != 0 && !getenv("GF_COMPLETE_DISABLE_SSE3")) {
93   	      gf_cpu_supports_intel_sse3 = 1;
94   	#ifdef DEBUG_CPU_DETECTION
95   	      printf("#gf_cpu_supports_intel_sse3\n");
96   	#endif
97   	  }
98   	#endif
99   	
100  	#if defined(INTEL_SSE2)
(12) Event example_checked: Example 5: "getenv("GF_COMPLETE_DISABLE_SSE2")" has its value checked in "getenv("GF_COMPLETE_DISABLE_SSE2")".
Also see events: [returned_null][example_assign][example_checked][example_assign][example_checked][example_checked][example_assign][example_checked][dereference]
101  	  if ((reg[3] & GF_CPU_SSE2) != 0 && !getenv("GF_COMPLETE_DISABLE_SSE2")) {
102  	      gf_cpu_supports_intel_sse2 = 1;
103  	#ifdef DEBUG_CPU_DETECTION
104  	      printf("#gf_cpu_supports_intel_sse2\n");
105  	#endif
106  	  }
107  	#endif
108  	
109  	  gf_cpu_identified = 1;
110  	}
111  	
112  	#elif defined(__arm__) || defined(__aarch64__)
113  	
114  	#ifdef __linux__
115  	
116  	#include <stdio.h>
117  	#include <unistd.h>
118  	#include <elf.h>
119  	#include <linux/auxvec.h>
120  	#include <asm/hwcap.h>
121  	#include <fcntl.h>
122  	
123  	unsigned long get_hwcap(unsigned long type) {
124  	    unsigned long hwcap = 0; 
125  	    int fd = open("/proc/self/auxv", O_RDONLY);
126  	    if (fd > 0) {
127  	        Elf32_auxv_t auxv;
128  	        while (read(fd, &auxv, sizeof(Elf32_auxv_t))) {
129  	            if (auxv.a_type == type) {
130  	                hwcap = auxv.a_un.a_val;
131  	                break;
132  	            }
133  	        }
134  	        close(fd);
135  	    }
136  	
137  	    return hwcap;
138  	}
139  	
140  	#endif // linux
141  	
142  	void gf_cpu_identify(void)
143  	{
144  	  if (gf_cpu_identified) {
145  	      return;
146  	  }
147  	
148  	#if defined(ARM_NEON)
149  	  if (!getenv("GF_COMPLETE_DISABLE_NEON")) {
150  	#if __linux__ && __arm__
151  		  gf_cpu_supports_arm_neon = (get_hwcap(AT_HWCAP) & HWCAP_NEON) > 0;
152  	#elif __aarch64__
153  	    // ASIMD is supported on all aarch64 architectures
154  		  gf_cpu_supports_arm_neon = 1;
155  	#else
156  	    // we assume that NEON is supported if the compiler supports
157  	    // NEON and we dont have a reliable way to detect runtime support.
158  		  gf_cpu_supports_arm_neon = 1;
159  	#endif
160  	
161  	#ifdef DEBUG_CPU_DETECTION
162  	    if (gf_cpu_supports_arm_neon) {
163  	      printf("#gf_cpu_supports_arm_neon\n");
164  	    }
165  	#endif
166  	  }
167  	#endif // defined(ARM_NEON)
168  	
169  	  gf_cpu_identified = 1;
170  	}
171  	
172  	#else // defined(__arm__) || defined(__aarch64__)
173  	
174  	int gf_cpu_identify(void)
175  	{
176  	    gf_cpu_identified = 1;
177  	    return 0;
178  	}
179  	
180  	#endif
181