Coverage Report

Created: 2025-07-23 08:13

/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-arm.c
Line
Count
Source
1
/*
2
 * Copyright © 2000 SuSE, Inc.
3
 * Copyright © 2007 Red Hat, Inc.
4
 *
5
 * Permission to use, copy, modify, distribute, and sell this software and its
6
 * documentation for any purpose is hereby granted without fee, provided that
7
 * the above copyright notice appear in all copies and that both that
8
 * copyright notice and this permission notice appear in supporting
9
 * documentation, and that the name of SuSE not be used in advertising or
10
 * publicity pertaining to distribution of the software without specific,
11
 * written prior permission.  SuSE makes no representations about the
12
 * suitability of this software for any purpose.  It is provided "as is"
13
 * without express or implied warranty.
14
 *
15
 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
 */
22
#ifdef HAVE_CONFIG_H
23
#include <pixman-config.h>
24
#endif
25
26
#include "pixman-private.h"
27
28
typedef enum
29
{
30
    ARM_V7    = (1 << 0),
31
    ARM_V6    = (1 << 1),
32
    ARM_VFP   = (1 << 2),
33
    ARM_NEON    = (1 << 3)
34
} arm_cpu_features_t;
35
36
#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON)
37
38
#if defined(_MSC_VER)
39
40
/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
41
#include <windows.h>
42
43
extern int pixman_msvc_try_arm_neon_op ();
44
extern int pixman_msvc_try_arm_simd_op ();
45
46
static arm_cpu_features_t
47
detect_cpu_features (void)
48
{
49
    arm_cpu_features_t features = 0;
50
51
    __try
52
    {
53
  pixman_msvc_try_arm_simd_op ();
54
  features |= ARM_V6;
55
    }
56
    __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
57
    {
58
    }
59
60
    __try
61
    {
62
  pixman_msvc_try_arm_neon_op ();
63
  features |= ARM_NEON;
64
    }
65
    __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
66
    {
67
    }
68
69
    return features;
70
}
71
72
#elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) /* iOS */
73
74
#include "TargetConditionals.h"
75
76
static arm_cpu_features_t
77
detect_cpu_features (void)
78
{
79
    arm_cpu_features_t features = 0;
80
81
    features |= ARM_V6;
82
83
    /* Detection of ARM NEON on iOS is fairly simple because iOS binaries
84
     * contain separate executable images for each processor architecture.
85
     * So all we have to do is detect the armv7 architecture build. The
86
     * operating system automatically runs the armv7 binary for armv7 devices
87
     * and the armv6 binary for armv6 devices.
88
     */
89
#if defined(__ARM_NEON__)
90
    features |= ARM_NEON;
91
#endif
92
93
    return features;
94
}
95
96
#elif defined(__ANDROID__) || defined(ANDROID) /* Android */
97
98
#include <cpu-features.h>
99
100
static arm_cpu_features_t
101
detect_cpu_features (void)
102
{
103
    arm_cpu_features_t features = 0;
104
    AndroidCpuFamily cpu_family;
105
    uint64_t cpu_features;
106
107
    cpu_family = android_getCpuFamily();
108
    cpu_features = android_getCpuFeatures();
109
110
    if (cpu_family == ANDROID_CPU_FAMILY_ARM)
111
    {
112
  if (cpu_features & ANDROID_CPU_ARM_FEATURE_ARMv7)
113
      features |= ARM_V7;
114
115
  if (cpu_features & ANDROID_CPU_ARM_FEATURE_VFPv3)
116
      features |= ARM_VFP;
117
118
  if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON)
119
      features |= ARM_NEON;
120
    }
121
122
    return features;
123
}
124
125
#elif defined (__linux__) /* linux ELF */
126
127
#include <unistd.h>
128
#include <sys/types.h>
129
#include <sys/stat.h>
130
#include <sys/mman.h>
131
#include <fcntl.h>
132
#include <string.h>
133
#include <elf.h>
134
135
static arm_cpu_features_t
136
detect_cpu_features (void)
137
{
138
    arm_cpu_features_t features = 0;
139
    Elf32_auxv_t aux;
140
    int fd;
141
142
    fd = open ("/proc/self/auxv", O_RDONLY);
143
    if (fd >= 0)
144
    {
145
  while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
146
  {
147
      if (aux.a_type == AT_HWCAP)
148
      {
149
    uint32_t hwcap = aux.a_un.a_val;
150
151
    /* hardcode these values to avoid depending on specific
152
     * versions of the hwcap header, e.g. HWCAP_NEON
153
     */
154
    if ((hwcap & 64) != 0)
155
        features |= ARM_VFP;
156
    /* this flag is only present on kernel 2.6.29 */
157
    if ((hwcap & 4096) != 0)
158
        features |= ARM_NEON;
159
      }
160
      else if (aux.a_type == AT_PLATFORM)
161
      {
162
    const char *plat = (const char*) aux.a_un.a_val;
163
164
    if (strncmp (plat, "v7l", 3) == 0)
165
        features |= (ARM_V7 | ARM_V6);
166
    else if (strncmp (plat, "v6l", 3) == 0)
167
        features |= ARM_V6;
168
      }
169
  }
170
  close (fd);
171
    }
172
173
    return features;
174
}
175
176
#elif defined (_3DS) /* 3DS homebrew (devkitARM) */
177
178
static arm_cpu_features_t
179
detect_cpu_features (void)
180
{
181
    arm_cpu_features_t features = 0;
182
183
    features |= ARM_V6;
184
185
    return features;
186
}
187
188
#elif defined (PSP2) || defined (__SWITCH__)
189
/* Vita (VitaSDK) or Switch (devkitA64) homebrew */
190
191
static arm_cpu_features_t
192
detect_cpu_features (void)
193
{
194
    arm_cpu_features_t features = 0;
195
196
    features |= ARM_NEON;
197
198
    return features;
199
}
200
201
#else /* Unknown */
202
203
static arm_cpu_features_t
204
detect_cpu_features (void)
205
{
206
    return 0;
207
}
208
209
#endif /* Linux elf */
210
211
static pixman_bool_t
212
have_feature (arm_cpu_features_t feature)
213
{
214
    static pixman_bool_t initialized;
215
    static arm_cpu_features_t features;
216
217
    if (!initialized)
218
    {
219
  features = detect_cpu_features();
220
  initialized = TRUE;
221
    }
222
223
    return (features & feature) == feature;
224
}
225
226
#endif /* USE_ARM_SIMD || USE_ARM_NEON */
227
228
pixman_implementation_t *
229
_pixman_arm_get_implementations (pixman_implementation_t *imp)
230
12
{
231
#ifdef USE_ARM_SIMD
232
    if (!_pixman_disabled ("arm-simd") && have_feature (ARM_V6))
233
  imp = _pixman_implementation_create_arm_simd (imp);
234
#endif
235
236
#ifdef USE_ARM_NEON
237
    if (!_pixman_disabled ("arm-neon") && have_feature (ARM_NEON))
238
  imp = _pixman_implementation_create_arm_neon (imp);
239
#endif
240
241
#ifdef USE_ARM_A64_NEON
242
    /* neon is a part of aarch64 */
243
    if (!_pixman_disabled ("arm-neon"))
244
        imp = _pixman_implementation_create_arm_neon (imp);
245
#endif
246
247
12
    return imp;
248
12
}