1 /*
2 * Copyright © 2024 Intel Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <ctype.h>
7
8 #include "util/ralloc.h"
9 #include "intel/compiler/brw_asm.h"
10
11 #include "executor.h"
12
13 static bool
startswith(const char * prefix,const char * s)14 startswith(const char *prefix, const char *s)
15 {
16 return !strncmp(prefix, s, strlen(prefix));
17 }
18
19 static char *
skip_prefix(char * prefix,char * start)20 skip_prefix(char *prefix, char *start)
21 {
22 assert(startswith(prefix, start));
23 char *c = start += strlen(prefix);
24 return c;
25 }
26
27 typedef struct {
28 char **args;
29 int count;
30 } parse_args_result;
31
32 static parse_args_result
parse_args(void * mem_ctx,char * c)33 parse_args(void *mem_ctx, char *c)
34 {
35 parse_args_result r = {0};
36
37 while (*c) {
38 /* Skip spaces. */
39 while (*c && isspace(*c))
40 c++;
41 if (!*c)
42 break;
43
44 /* Copy non-spaces. */
45 char *start = c;
46 while (*c && !isspace(*c))
47 c++;
48 r.args = reralloc_array_size(mem_ctx, r.args, sizeof(char *), r.count + 1);
49 r.args[r.count++] = ralloc_strndup(mem_ctx, start, c - start);
50 }
51
52 return r;
53 }
54
55 static void
executor_macro_mov(executor_context * ec,char ** src,char * line)56 executor_macro_mov(executor_context *ec, char **src, char *line)
57 {
58 char *c = skip_prefix("@mov", line);
59 parse_args_result r = parse_args(ec->mem_ctx, c);
60
61 if (r.count != 2)
62 failf("@mov needs 2 arguments, found %d\n", r.count);
63
64 const char *reg = r.args[0];
65 char *value = r.args[1];
66
67 if (strchr(value, '.')) {
68 union {
69 float f;
70 uint32_t u;
71 } val;
72
73 val.f = strtof(value, NULL);
74
75 switch (ec->devinfo->verx10) {
76 case 90:
77 case 110:
78 case 120:
79 case 125: {
80 ralloc_asprintf_append(src, "mov(8) %s<1>F 0x%08xF /* %f */ { align1 1Q };\n", reg, val.u, val.f);
81 break;
82 }
83 case 200: {
84 ralloc_asprintf_append(src, "mov(16) %s<1>F 0x%08xF /* %f */ { align1 1H };\n", reg, val.u, val.f);
85 break;
86 }
87 default:
88 unreachable("invalid gfx version");
89 }
90
91 } else {
92 for (char *c = value; *c; c++)
93 *c = tolower(*c);
94 switch (ec->devinfo->verx10) {
95 case 90:
96 case 110:
97 case 120:
98 case 125: {
99 ralloc_asprintf_append(src, "mov(8) %s<1>UD %sUD { align1 1Q };\n", reg, value);
100 break;
101 }
102
103 case 200: {
104 ralloc_asprintf_append(src, "mov(16) %s<1>UD %sUD { align1 1H };\n", reg, value);
105 break;
106 }
107
108 default:
109 unreachable("invalid gfx version");
110 }
111 }
112 }
113
114 static void
executor_macro_syncnop(executor_context * ec,char ** src,char * line)115 executor_macro_syncnop(executor_context *ec, char **src, char *line)
116 {
117 switch (ec->devinfo->verx10) {
118 case 90:
119 case 110: {
120 /* Not needed. */
121 break;
122 }
123
124 case 120: {
125 ralloc_strcat(src, "sync nop(8) null<0,1,0>UD { align1 WE_all 1H @1 $1.dst };\n");
126 break;
127 }
128
129 case 125:
130 case 200: {
131 ralloc_strcat(src, "sync nop(8) null<0,1,0>UD { align1 WE_all 1H A@1 $1.dst };\n");
132 break;
133 }
134
135 default:
136 unreachable("invalid gfx version");
137 }
138 }
139
140 static void
executor_macro_eot(executor_context * ec,char ** src,char * line)141 executor_macro_eot(executor_context *ec, char **src, char *line)
142 {
143 switch (ec->devinfo->verx10) {
144 case 90:
145 case 110: {
146 ralloc_strcat(src,
147 "mov(8) g127<1>UD g0<8;8,1>UD { align1 WE_all 1Q };\n"
148 "send(8) null<1>UW g127<0,1,0>UD 0x82000010\n"
149 " thread_spawner MsgDesc: mlen 1 rlen 0 { align1 WE_all 1Q EOT };\n");
150 break;
151 }
152 case 120: {
153 ralloc_strcat(src,
154 "mov(8) g127<1>UD g0<8;8,1>UD { align1 WE_all 1Q };\n"
155 "send(8) nullUD g127UD nullUD 0x02000000 0x00000000\n"
156 " thread_spawner MsgDesc: mlen 1 ex_mlen 0 rlen 0 { align1 WE_all 1Q @1 EOT };\n");
157 break;
158 }
159
160 case 125: {
161 ralloc_strcat(src,
162 "mov(8) g127<1>UD g0<8;8,1>UD { align1 WE_all 1Q };\n"
163 "send(8) nullUD g127UD nullUD 0x02000000 0x00000000\n"
164 " gateway MsgDesc: (open) mlen 1 ex_mlen 0 rlen 0 { align1 WE_all 1Q A@1 EOT };\n");
165 break;
166 }
167
168 case 200: {
169 ralloc_strcat(src,
170 "mov(16) g127<1>UD g0<1,1,0>UD { align1 WE_all 1H };\n"
171 "send(16) nullUD g127UD nullUD 0x02000000 0x00000000\n"
172 " gateway MsgDesc: (open) mlen 1 ex_mlen 0 rlen 0 { align1 WE_all 1H I@1 EOT };\n");
173 break;
174 }
175 default:
176 unreachable("invalid gfx version");
177 }
178 }
179
180 static void
executor_macro_id(executor_context * ec,char ** src,char * line)181 executor_macro_id(executor_context *ec, char **src, char *line)
182 {
183 char *c = skip_prefix("@id", line);
184 parse_args_result r = parse_args(ec->mem_ctx, c);
185
186 if (r.count != 1)
187 failf("@id needs 1 argument, found %d\n", r.count);
188
189 const char *reg = r.args[0];
190
191 switch (ec->devinfo->verx10) {
192 case 90:
193 case 110:
194 case 120:
195 case 125: {
196 ralloc_asprintf_append(src,
197 "mov(8) g127<1>UW 0x76543210V { align1 WE_all 1Q };\n"
198 "mov(8) %s<1>UD g127<8,8,1>UW { align1 WE_all 1Q @1 };\n", reg);
199 break;
200 }
201
202 case 200: {
203 ralloc_asprintf_append(src,
204 "mov(8) g127<1>UW 0x76543210V { align1 WE_all 1Q };\n"
205 "add(8) g127.8<1>UW g127<1,1,0>UW 8UW { align1 WE_all 1Q @1 };\n"
206 "mov(16) %s<1>UD g127<8,8,1>UW { align1 WE_all 1Q @1 };\n", reg);
207 break;
208 }
209
210 default:
211 unreachable("invalid gfx version");
212 }
213 }
214
215 static void
executor_macro_write(executor_context * ec,char ** src,char * line)216 executor_macro_write(executor_context *ec, char **src, char *line)
217 {
218 char *c = skip_prefix("@write", line);
219 parse_args_result r = parse_args(ec->mem_ctx, c);
220
221 if (r.count != 2)
222 failf("@write needs 2 arguments, found %d\n", r.count);
223
224 const char *offset_reg = r.args[0];
225 const char *data_reg = r.args[1];
226
227 assert(ec->bo.data.addr <= 0xFFFFFFFF);
228 uint32_t base_addr = ec->bo.data.addr;
229
230 switch (ec->devinfo->verx10) {
231 case 90:
232 case 110:
233 case 120: {
234 const char *send_suffix = ec->devinfo->verx10 < 120 ? "s" : "";
235 ralloc_asprintf_append(src,
236 "mul(8) g127<1>UD %s<8;8,1>UD 0x4UW { align1 @1 1Q };\n"
237 "add(8) g127<1>UD g127<8;8,1>UD 0x%08xUD { align1 @1 1Q };\n"
238 "send%s(8) nullUD g127UD %sUD 0x2026efd 0x00000040\n"
239 " dp data 1 MsgDesc: (DC untyped surface write, Surface = 253, "
240 " SIMD8, Mask = 0xe) mlen 1 ex_mlen 1 rlen 0 "
241 " { align1 1Q @1 $1 };\n",
242 offset_reg, base_addr, send_suffix, data_reg);
243 executor_macro_syncnop(ec, src, "@syncnop");
244 break;
245 }
246
247 case 125: {
248 ralloc_asprintf_append(src,
249 "mul(8) g127<1>UD %s<1;1,0>UD 0x4UW { align1 @1 1Q };\n"
250 "add(8) g127<1>UD g127<1;1,0>UD 0x%08xUD { align1 @1 1Q };\n"
251 "send(8) nullUD g127UD %sUD 0x02000504 0x00000040\n"
252 " ugm MsgDesc: ( store, a32, d32, x, L1STATE_L3MOCS dst_len = 0, "
253 " src0_len = 1, src1_len = 1, flat ) base_offset 0 "
254 " { align1 1Q A@1 $1 };\n",
255 offset_reg, base_addr, data_reg);
256 executor_macro_syncnop(ec, src, "@syncnop");
257 break;
258 }
259
260 case 200: {
261 ralloc_asprintf_append(src,
262 "mul(16) g127<1>UD %s<1;1,0>UD 0x4UW { align1 @1 1Q };\n"
263 "add(16) g127<1>UD g127<1;1,0>UD 0x%08xUD { align1 @1 1Q };\n"
264 "send(16) nullUD g127UD %sUD 0x02000504 0x00000040\n"
265 " ugm MsgDesc: ( store, a32, d32, x, L1STATE_L3MOCS dst_len = 0, "
266 " src0_len = 1, src1_len = 1, flat ) base_offset 0 "
267 " { align1 1Q A@1 $1 };\n",
268 offset_reg, base_addr, data_reg);
269 executor_macro_syncnop(ec, src, "@syncnop");
270 break;
271 }
272
273 default:
274 unreachable("invalid gfx version");
275 }
276 }
277
278 static void
executor_macro_read(executor_context * ec,char ** src,char * line)279 executor_macro_read(executor_context *ec, char **src, char *line)
280 {
281 char *c = skip_prefix("@read", line);
282 parse_args_result r = parse_args(ec->mem_ctx, c);
283
284 if (r.count != 2)
285 failf("@read needs 2 arguments, found %d\n", r.count);
286
287 /* Order follows underlying SEND, destination first. */
288 const char *data_reg = r.args[0];
289 const char *offset_reg = r.args[1];
290
291 assert(ec->bo.data.addr <= 0xFFFFFFFF);
292 uint32_t base_addr = ec->bo.data.addr;
293
294 switch (ec->devinfo->verx10) {
295 case 90:
296 case 110:
297 case 120: {
298 const char *send_suffix = ec->devinfo->verx10 < 120 ? "s" : "";
299 ralloc_asprintf_append(src,
300 "mul(8) g127<1>UD %s<8;8,1>UD 0x4UW { align1 @1 1Q };\n"
301 "add(8) g127<1>UD g127<8;8,1>UD 0x%08xUD { align1 @1 1Q };\n"
302 "send%s(8) %sUD g127UD nullUD 0x2106efd 0x00000000\n"
303 " dp data 1 MsgDesc: (DC untyped surface read, Surface = 253, "
304 " SIMD8, Mask = 0xe) mlen 1 ex_mlen 0 rlen 1 "
305 " { align1 1Q @1 $1 };\n",
306 offset_reg, base_addr, send_suffix, data_reg);
307 executor_macro_syncnop(ec, src, "@syncnop");
308 break;
309 }
310
311 case 125: {
312 ralloc_asprintf_append(src,
313 "mul(8) g127<1>UD %s<1;1,0>UD 0x4UW { align1 @1 1Q };\n"
314 "add(8) g127<1>UD g127<1;1,0>UD 0x%08xUD { align1 @1 1Q };\n"
315 "send(8) %sUD g127UD nullUD 0x02100500 0x00000000\n"
316 " ugm MsgDesc: ( load, a32, d32, x, L1STATE_L3MOCS dst_len = 1, "
317 " src0_len = 1, flat ) src1_len = 0 base_offset 0 "
318 " { align1 1Q A@1 $1 };\n",
319 offset_reg, base_addr, data_reg);
320 executor_macro_syncnop(ec, src, "@syncnop");
321 break;
322 }
323
324 case 200: {
325 ralloc_asprintf_append(src,
326 "mul(8) g127<1>UD %s<1;1,0>UD 0x4UW { align1 @1 1Q };\n"
327 "add(8) g127<1>UD g127<1;1,0>UD 0x%08xUD { align1 @1 1Q };\n"
328 "send(8) %sUD g127UD nullUD 0x02100500 0x00000000\n"
329 " ugm MsgDesc: ( load, a32, d32, x, L1STATE_L3MOCS dst_len = 1, "
330 " src0_len = 1, flat ) src1_len = 0 base_offset 0 "
331 " { align1 1Q A@1 $1 };\n",
332 offset_reg, base_addr, data_reg);
333 executor_macro_syncnop(ec, src, "@syncnop");
334 break;
335 }
336
337 default:
338 unreachable("invalid gfx version");
339 }
340 }
341
342 static char *
find_macro_symbol(char * line)343 find_macro_symbol(char *line)
344 {
345 char *c = line;
346 while (isspace(*c)) c++;
347 return *c == '@' ? c : NULL;
348 }
349
350 static bool
match_macro_name(const char * name,const char * line)351 match_macro_name(const char *name, const char *line)
352 {
353 if (!startswith(name, line))
354 return false;
355 line += strlen(name);
356 return !*line || isspace(*line);
357 }
358
359 const char *
executor_apply_macros(executor_context * ec,const char * original_src)360 executor_apply_macros(executor_context *ec, const char *original_src)
361 {
362 char *scratch = ralloc_strdup(ec->mem_ctx, original_src);
363
364 /* Create a ralloc'ed empty string so can call append to it later. */
365 char *src = ralloc_strdup(ec->mem_ctx, "");
366
367 /* TODO: Create a @send macro for common combinations of MsgDesc. */
368 static const struct {
369 const char *name;
370 void (*func)(executor_context *ec, char **output, char *line);
371 } macros[] = {
372 { "@eot", executor_macro_eot },
373 { "@mov", executor_macro_mov },
374 { "@write", executor_macro_write },
375 { "@read", executor_macro_read },
376 { "@id", executor_macro_id },
377 { "@syncnop", executor_macro_syncnop },
378 };
379
380 char *next = scratch;
381 while (next) {
382 char *line = next;
383 char *end = line;
384
385 while (*end && *end != '\n') end++;
386 next = *end ? end + 1 : NULL;
387 *end = '\0';
388
389 char *macro = find_macro_symbol(line);
390 if (!macro) {
391 ralloc_asprintf_append(&src, "%s\n", line);
392 } else {
393 bool found = false;
394 for (int i = 0; i < ARRAY_SIZE(macros); i++) {
395 if (match_macro_name(macros[i].name, macro)) {
396 macros[i].func(ec, &src, macro);
397 found = true;
398 break;
399 }
400 }
401 if (!found)
402 failf("unsupported macro line: %s", macro);
403 }
404 }
405
406 return src;
407 }
408