Coverage Report

Created: 2025-07-23 06:50

/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-x86.c
Line
Count
Source (jump to first uncovered line)
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
#if defined(USE_X86_MMX) || defined (USE_SSE2) || defined (USE_SSSE3)
29
30
/* The CPU detection code needs to be in a file not compiled with
31
 * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
32
 * that would lead to SIGILL instructions on old CPUs that don't have
33
 * it.
34
 */
35
36
typedef enum
37
{
38
    X86_MMX     = (1 << 0),
39
    X86_MMX_EXTENSIONS    = (1 << 1),
40
    X86_SSE     = (1 << 2) | X86_MMX_EXTENSIONS,
41
    X86_SSE2      = (1 << 3),
42
    X86_CMOV      = (1 << 4),
43
    X86_SSSE3     = (1 << 5)
44
} cpu_features_t;
45
46
#ifdef HAVE_GETISAX
47
48
#include <sys/auxv.h>
49
50
static cpu_features_t
51
detect_cpu_features (void)
52
{
53
    cpu_features_t features = 0;
54
    unsigned int result = 0;
55
56
    if (getisax (&result, 1))
57
    {
58
  if (result & AV_386_CMOV)
59
      features |= X86_CMOV;
60
  if (result & AV_386_MMX)
61
      features |= X86_MMX;
62
  if (result & AV_386_AMD_MMX)
63
      features |= X86_MMX_EXTENSIONS;
64
  if (result & AV_386_SSE)
65
      features |= X86_SSE;
66
  if (result & AV_386_SSE2)
67
      features |= X86_SSE2;
68
  if (result & AV_386_SSSE3)
69
      features |= X86_SSSE3;
70
    }
71
72
    return features;
73
}
74
75
#else
76
77
#if defined (__GNUC__)
78
#include <cpuid.h>
79
#elif defined(_MSC_VER)
80
#include <intrin.h>
81
#endif
82
83
static void
84
pixman_cpuid (uint32_t feature,
85
        uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
86
10
{
87
10
#if defined (__GNUC__)
88
10
    *a = *b = *c = *d = 0;
89
10
    __get_cpuid(feature, a, b, c, d);
90
#elif defined (_MSC_VER)
91
    int info[4];
92
93
    __cpuid (info, feature);
94
95
    *a = info[0];
96
    *b = info[1];
97
    *c = info[2];
98
    *d = info[3];
99
#else
100
#error Unknown compiler
101
#endif
102
10
}
103
104
static cpu_features_t
105
detect_cpu_features (void)
106
10
{
107
10
    uint32_t a, b, c, d;
108
10
    cpu_features_t features = 0;
109
110
    /* Get feature bits */
111
10
    pixman_cpuid (0x01, &a, &b, &c, &d);
112
10
    if (d & (1 << 15))
113
10
  features |= X86_CMOV;
114
10
    if (d & (1 << 23))
115
10
  features |= X86_MMX;
116
10
    if (d & (1 << 25))
117
10
  features |= X86_SSE;
118
10
    if (d & (1 << 26))
119
10
  features |= X86_SSE2;
120
10
    if (c & (1 << 9))
121
10
  features |= X86_SSSE3;
122
123
    /* Check for AMD specific features */
124
10
    if ((features & X86_MMX) && !(features & X86_SSE))
125
0
    {
126
0
  char vendor[13];
127
128
  /* Get vendor string */
129
0
  memset (vendor, 0, sizeof vendor);
130
131
0
  pixman_cpuid (0x00, &a, &b, &c, &d);
132
0
  memcpy (vendor + 0, &b, 4);
133
0
  memcpy (vendor + 4, &d, 4);
134
0
  memcpy (vendor + 8, &c, 4);
135
136
0
  if (strcmp (vendor, "AuthenticAMD") == 0 ||
137
0
      strcmp (vendor, "HygonGenuine") == 0 ||
138
0
      strcmp (vendor, "Geode by NSC") == 0)
139
0
  {
140
0
      pixman_cpuid (0x80000000, &a, &b, &c, &d);
141
0
      if (a >= 0x80000001)
142
0
      {
143
0
    pixman_cpuid (0x80000001, &a, &b, &c, &d);
144
145
0
    if (d & (1 << 22))
146
0
        features |= X86_MMX_EXTENSIONS;
147
0
      }
148
0
  }
149
0
    }
150
151
10
    return features;
152
10
}
153
154
#endif
155
156
static pixman_bool_t
157
have_feature (cpu_features_t feature)
158
30
{
159
30
    static pixman_bool_t initialized;
160
30
    static cpu_features_t features;
161
162
30
    if (!initialized)
163
10
    {
164
10
  features = detect_cpu_features();
165
10
  initialized = TRUE;
166
10
    }
167
168
30
    return (features & feature) == feature;
169
30
}
170
171
#endif
172
173
pixman_implementation_t *
174
_pixman_x86_get_implementations (pixman_implementation_t *imp)
175
10
{
176
10
#define MMX_BITS  (X86_MMX | X86_MMX_EXTENSIONS)
177
10
#define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
178
10
#define SSSE3_BITS (X86_SSE | X86_SSE2 | X86_SSSE3)
179
180
10
#ifdef USE_X86_MMX
181
10
    if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
182
10
  imp = _pixman_implementation_create_mmx (imp);
183
10
#endif
184
185
10
#ifdef USE_SSE2
186
10
    if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
187
10
  imp = _pixman_implementation_create_sse2 (imp);
188
10
#endif
189
190
10
#ifdef USE_SSSE3
191
10
    if (!_pixman_disabled ("ssse3") && have_feature (SSSE3_BITS))
192
10
  imp = _pixman_implementation_create_ssse3 (imp);
193
10
#endif
194
195
10
    return imp;
196
10
}