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