]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/loongarch/loongarch-cpu.cc
LoongArch: Define builtin macros for ISA evolutions
[thirdparty/gcc.git] / gcc / config / loongarch / loongarch-cpu.cc
1 /* Definitions for LoongArch CPU properties.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #define IN_TARGET_CODE 1
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "diagnostic-core.h"
27
28 #include "loongarch-def.h"
29 #include "loongarch-opts.h"
30 #include "loongarch-cpu.h"
31 #include "loongarch-str.h"
32 #include "loongarch-evolution.h"
33
34
35 /* Native CPU detection with "cpucfg" */
36 static uint32_t cpucfg_cache[N_CPUCFG_WORDS] = { 0 };
37
38 static uint32_t
39 read_cpucfg_word (int wordno)
40 {
41 /* To make cross-compiler shut up. */
42 (void) wordno;
43 uint32_t ret = 0;
44
45 #ifdef __loongarch__
46 __asm__ __volatile__ ("cpucfg %0,%1\n\t"
47 :"=r"(ret)
48 :"r"(wordno)
49 :);
50 #endif
51
52 return ret;
53 }
54
55 void
56 cache_cpucfg (void)
57 {
58 for (int idx: cpucfg_useful_idx)
59 cpucfg_cache[idx] = read_cpucfg_word (idx);
60 }
61
62 uint32_t
63 get_native_prid (void)
64 {
65 /* Fill loongarch_cpu_default_config[ARCH_NATIVE] with cpucfg data,
66 see "Loongson Architecture Reference Manual"
67 (Volume 1, Section 2.2.10.5) */
68 return cpucfg_cache[0];
69 }
70
71 const char*
72 get_native_prid_str (void)
73 {
74 static char prid_str[9];
75 sprintf (prid_str, "%08x", cpucfg_cache[0]);
76 return (const char*) prid_str;
77 }
78
79 /* Fill property tables for ARCH_NATIVE / TUNE_NATIVE. */
80 void
81 fill_native_cpu_config (struct loongarch_target *tgt)
82 {
83 int arch_native_p = tgt->cpu_arch == ARCH_NATIVE;
84 int tune_native_p = tgt->cpu_tune == TUNE_NATIVE;
85 int native_cpu_arch = ARCH_NATIVE;
86 int native_cpu_tune = TUNE_NATIVE;
87
88 /* Nothing needs to be done unless "-march/tune=native"
89 is given or implied. */
90 if (!arch_native_p && !tune_native_p)
91 return;
92
93 /* Fill cpucfg_cache with the "cpucfg" instruction. */
94 cache_cpucfg ();
95
96 /* Fill: tgt->cpu_arch | tgt->cpu_tune
97 With: processor ID (PRID)
98 At: cpucfg_words[0][31:0] */
99
100 switch (cpucfg_cache[0] & 0x00ffff00)
101 {
102 case 0x0014c000: /* LA464 */
103 native_cpu_arch = ARCH_LA464;
104 native_cpu_tune = TUNE_LA464;
105 break;
106
107 case 0x0014d000: /* LA664 */
108 native_cpu_arch = ARCH_LA664;
109 native_cpu_tune = TUNE_LA664;
110 break;
111
112 default:
113 /* Unknown PRID. */
114 if (tune_native_p)
115 inform (UNKNOWN_LOCATION, "unknown processor ID %<0x%x%>, "
116 "some tuning parameters will fall back to default",
117 cpucfg_cache[0]);
118 break;
119 }
120
121 /* if -march=native */
122 if (arch_native_p)
123 {
124 int tmp;
125 tgt->cpu_arch = native_cpu_arch;
126
127 auto &preset = loongarch_cpu_default_isa[tgt->cpu_arch];
128
129 /* Fill: loongarch_cpu_default_isa[tgt->cpu_arch].base
130 With: base architecture (ARCH)
131 At: cpucfg_words[1][1:0] */
132
133 if (native_cpu_arch != ARCH_NATIVE)
134 tmp = loongarch_cpu_default_isa[native_cpu_arch].base;
135 else
136 switch (cpucfg_cache[1] & 0x3)
137 {
138 case 0x02:
139 tmp = ISA_BASE_LA64;
140 break;
141
142 default:
143 fatal_error (UNKNOWN_LOCATION,
144 "unknown native base architecture %<0x%x%>, "
145 "%qs failed",
146 (unsigned int) (cpucfg_cache[1] & 0x3),
147 "-m" OPTSTR_ARCH "=" STR_CPU_NATIVE);
148 }
149
150 /* Use the native value anyways. */
151 preset.base = tmp;
152
153 /* Fill: loongarch_cpu_default_isa[tgt->cpu_arch].fpu
154 With: FPU type (FP, FP_SP, FP_DP)
155 At: cpucfg_words[2][2:0] */
156
157 switch (cpucfg_cache[2] & 0x7)
158 {
159 case 0x07:
160 tmp = ISA_EXT_FPU64;
161 break;
162
163 case 0x03:
164 tmp = ISA_EXT_FPU32;
165 break;
166
167 case 0x00:
168 tmp = ISA_EXT_NONE;
169 break;
170
171 default:
172 fatal_error (UNKNOWN_LOCATION,
173 "unknown native FPU type %<0x%x%>, %qs failed",
174 (unsigned int) (cpucfg_cache[2] & 0x7),
175 "-m" OPTSTR_ARCH "=" STR_CPU_NATIVE);
176 }
177
178 /* Check consistency with PRID presets. */
179 if (native_cpu_arch != ARCH_NATIVE && tmp != preset.fpu)
180 warning (0, "floating-point unit %qs differs from PRID preset %qs",
181 loongarch_isa_ext_strings[tmp],
182 loongarch_isa_ext_strings[preset.fpu]);
183
184 /* Use the native value anyways. */
185 preset.fpu = tmp;
186
187
188 /* Fill: loongarch_cpu_default_isa[ARCH_NATIVE].simd
189 With: SIMD extension type (LSX, LASX)
190 At: cpucfg_words[2][7:6] */
191
192 switch (cpucfg_cache[2] & 0xc0)
193 {
194 case 0xc0:
195 tmp = ISA_EXT_SIMD_LASX;
196 break;
197
198 case 0x40:
199 tmp = ISA_EXT_SIMD_LSX;
200 break;
201
202 case 0x80:
203 tmp = 0;
204 warning (0, "unknown SIMD extension "
205 "(%qs disabled while %qs is enabled), disabling SIMD",
206 loongarch_isa_ext_strings[ISA_EXT_SIMD_LSX],
207 loongarch_isa_ext_strings[ISA_EXT_SIMD_LASX]);
208 break;
209
210 case 0x00:
211 tmp = 0;
212 break;
213 }
214
215 /* Check consistency with PRID presets. */
216
217 /*
218 if (native_cpu_arch != ARCH_NATIVE && tmp != preset.simd)
219 warning (0, "SIMD extension %qs differs from PRID preset %qs",
220 loongarch_isa_ext_strings[tmp],
221 loongarch_isa_ext_strings[preset.simd]);
222 */
223
224 /* Use the native value anyways. */
225 preset.simd = tmp;
226
227
228 int64_t hw_isa_evolution = 0;
229
230 /* Features added during ISA evolution. */
231 for (const auto &entry: cpucfg_map)
232 if (cpucfg_cache[entry.cpucfg_word] & entry.cpucfg_bit)
233 hw_isa_evolution |= entry.isa_evolution_bit;
234
235 if (native_cpu_arch != ARCH_NATIVE)
236 {
237 /* Check if the local CPU really supports the features of the base
238 ISA of probed native_cpu_arch. If any feature is not detected,
239 either GCC or the hardware is buggy. */
240 if ((preset.evolution & hw_isa_evolution) != hw_isa_evolution)
241 warning (0,
242 "detected base architecture %qs, but some of its "
243 "features are not detected; the detected base "
244 "architecture may be unreliable, only detected "
245 "features will be enabled",
246 loongarch_isa_base_strings[preset.base]);
247 }
248 preset.evolution = hw_isa_evolution;
249 }
250
251 if (tune_native_p)
252 {
253 tgt->cpu_tune = native_cpu_tune;
254
255 /* Fill: loongarch_cpu_cache[tgt->cpu_tune]
256 With: cache size info
257 At: cpucfg_words[16:20][31:0] */
258
259 auto &preset_cache = loongarch_cpu_cache[tgt->cpu_tune];
260 struct loongarch_cache native_cache;
261 int l1d_present = 0, l1u_present = 0;
262 int l2d_present = 0;
263 uint32_t l1_szword, l2_szword;
264
265 l1u_present |= cpucfg_cache[16] & 3; /* bit[1:0]: unified l1 */
266 l1d_present |= cpucfg_cache[16] & 4; /* bit[2:2]: l1d */
267 l1_szword = l1d_present ? 18 : (l1u_present ? 17 : 0);
268 l1_szword = l1_szword ? cpucfg_cache[l1_szword]: 0;
269
270 l2d_present |= cpucfg_cache[16] & 24; /* bit[4:3]: unified l2 */
271 l2d_present |= cpucfg_cache[16] & 128; /* bit[7:7]: l2d */
272 l2_szword = l2d_present ? cpucfg_cache[19]: 0;
273
274 native_cache.l1d_line_size
275 = 1 << ((l1_szword & 0x7f000000) >> 24); /* bit[30:24]: log2(line) */
276
277 native_cache.l1d_size
278 = (1 << ((l1_szword & 0x00ff0000) >> 16)) /* bit[23:16]: log2(idx) */
279 * ((l1_szword & 0x0000ffff) + 1) /* bit[15:0]: sets - 1 */
280 * (1 << ((l1_szword & 0x7f000000) >> 24)) /* bit[30:24]: log2(line) */
281 >> 10; /* in kibibytes */
282
283 native_cache.l2d_size
284 = (1 << ((l2_szword & 0x00ff0000) >> 16)) /* bit[23:16]: log2(idx) */
285 * ((l2_szword & 0x0000ffff) + 1) /* bit[15:0]: sets - 1 */
286 * (1 << ((l2_szword & 0x7f000000) >> 24)) /* bit[30:24]: log2(linesz) */
287 >> 10; /* in kibibytes */
288
289 /* Use the native value anyways. */
290 preset_cache.l1d_line_size = native_cache.l1d_line_size;
291 preset_cache.l1d_size = native_cache.l1d_size;
292 preset_cache.l2d_size = native_cache.l2d_size;
293 }
294 }