authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-11 22:03:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-16 10:23:02-07:00
logfcafc63f3d5ce250e404871571aa3b26aeae6611
tree49e3354bb24dd1d8663127598e4f2f63942f2655
parent6002514b72cb2a571abc6ac4ac7fbec44d6302b1

inline assembly: use types

until now these were stringly typed. it's kinda obvious when you think about it.

25 files changed, 1576 insertions(+), 253 deletions(-)

lib/std/builtin.zig+4-3
...@@ -1,6 +1,10 @@...@@ -1,6 +1,10 @@
1//! Types and values provided by the Zig language.1//! Types and values provided by the Zig language.
22
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const std = @import("std.zig");
5const root = @import("root");
6
7pub const assembly = @import("builtin/assembly.zig");
48
5/// `explicit_subsystem` is missing when the subsystem is automatically detected,9/// `explicit_subsystem` is missing when the subsystem is automatically detected,
6/// so Zig standard library has the subsystem detection logic here. This should generally be10/// so Zig standard library has the subsystem detection logic here. This should generally be
...@@ -1100,6 +1104,3 @@ pub noinline fn returnError() void {...@@ -1100,6 +1104,3 @@ pub noinline fn returnError() void {
1100 st.instruction_addresses[st.index] = @returnAddress();1104 st.instruction_addresses[st.index] = @returnAddress();
1101 st.index += 1;1105 st.index += 1;
1102}1106}
1103
1104const std = @import("std.zig");
1105const root = @import("root");
lib/std/builtin/assembly.zig created+1026
...@@ -0,0 +1,1026 @@
1pub const Clobbers = switch (@import("builtin").cpu.arch) {
2 .x86, .x86_64 => packed struct {
3 /// Whether the inline assembly code may perform stores to memory
4 /// addresses other than those derived from input pointer provenance.
5 memory: bool = false,
6
7 cc: bool = false,
8 dirflag: bool = false,
9 eflags: bool = false,
10 flags: bool = false,
11 fpcr: bool = false,
12 fpsr: bool = false,
13 mxcsr: bool = false,
14 rflags: bool = false,
15
16 rax: bool = false,
17 rcx: bool = false,
18 rdx: bool = false,
19 rbx: bool = false,
20 rsp: bool = false,
21 rbp: bool = false,
22 rsi: bool = false,
23 rdi: bool = false,
24 r8: bool = false,
25 r9: bool = false,
26 r10: bool = false,
27 r11: bool = false,
28 r12: bool = false,
29 r13: bool = false,
30 r14: bool = false,
31 r15: bool = false,
32 eax: bool = false,
33 ecx: bool = false,
34 edx: bool = false,
35 ebx: bool = false,
36 esp: bool = false,
37 ebp: bool = false,
38 esi: bool = false,
39 edi: bool = false,
40 r8d: bool = false,
41 r9d: bool = false,
42 r10d: bool = false,
43 r11d: bool = false,
44 r12d: bool = false,
45 r13d: bool = false,
46 r14d: bool = false,
47 r15d: bool = false,
48 ax: bool = false,
49 cx: bool = false,
50 dx: bool = false,
51 bx: bool = false,
52 sp: bool = false,
53 bp: bool = false,
54 si: bool = false,
55 di: bool = false,
56 r8w: bool = false,
57 r9w: bool = false,
58 r10w: bool = false,
59 r11w: bool = false,
60 r12w: bool = false,
61 r13w: bool = false,
62 r14w: bool = false,
63 r15w: bool = false,
64 al: bool = false,
65 cl: bool = false,
66 dl: bool = false,
67 bl: bool = false,
68 spl: bool = false,
69 bpl: bool = false,
70 sil: bool = false,
71 dil: bool = false,
72 r8b: bool = false,
73 r9b: bool = false,
74 r10b: bool = false,
75 r11b: bool = false,
76 r12b: bool = false,
77 r13b: bool = false,
78 r14b: bool = false,
79 r15b: bool = false,
80 ah: bool = false,
81 ch: bool = false,
82 dh: bool = false,
83 bh: bool = false,
84 zmm0: bool = false,
85 zmm1: bool = false,
86 zmm2: bool = false,
87 zmm3: bool = false,
88 zmm4: bool = false,
89 zmm5: bool = false,
90 zmm6: bool = false,
91 zmm7: bool = false,
92 zmm8: bool = false,
93 zmm9: bool = false,
94 zmm10: bool = false,
95 zmm11: bool = false,
96 zmm12: bool = false,
97 zmm13: bool = false,
98 zmm14: bool = false,
99 zmm15: bool = false,
100 zmm16: bool = false,
101 zmm17: bool = false,
102 zmm18: bool = false,
103 zmm19: bool = false,
104 zmm20: bool = false,
105 zmm21: bool = false,
106 zmm22: bool = false,
107 zmm23: bool = false,
108 zmm24: bool = false,
109 zmm25: bool = false,
110 zmm26: bool = false,
111 zmm27: bool = false,
112 zmm28: bool = false,
113 zmm29: bool = false,
114 zmm30: bool = false,
115 zmm31: bool = false,
116 ymm0: bool = false,
117 ymm1: bool = false,
118 ymm2: bool = false,
119 ymm3: bool = false,
120 ymm4: bool = false,
121 ymm5: bool = false,
122 ymm6: bool = false,
123 ymm7: bool = false,
124 ymm8: bool = false,
125 ymm9: bool = false,
126 ymm10: bool = false,
127 ymm11: bool = false,
128 ymm12: bool = false,
129 ymm13: bool = false,
130 ymm14: bool = false,
131 ymm15: bool = false,
132 ymm16: bool = false,
133 ymm17: bool = false,
134 ymm18: bool = false,
135 ymm19: bool = false,
136 ymm20: bool = false,
137 ymm21: bool = false,
138 ymm22: bool = false,
139 ymm23: bool = false,
140 ymm24: bool = false,
141 ymm25: bool = false,
142 ymm26: bool = false,
143 ymm27: bool = false,
144 ymm28: bool = false,
145 ymm29: bool = false,
146 ymm30: bool = false,
147 ymm31: bool = false,
148 xmm0: bool = false,
149 xmm1: bool = false,
150 xmm2: bool = false,
151 xmm3: bool = false,
152 xmm4: bool = false,
153 xmm5: bool = false,
154 xmm6: bool = false,
155 xmm7: bool = false,
156 xmm8: bool = false,
157 xmm9: bool = false,
158 xmm10: bool = false,
159 xmm11: bool = false,
160 xmm12: bool = false,
161 xmm13: bool = false,
162 xmm14: bool = false,
163 xmm15: bool = false,
164 xmm16: bool = false,
165 xmm17: bool = false,
166 xmm18: bool = false,
167 xmm19: bool = false,
168 xmm20: bool = false,
169 xmm21: bool = false,
170 xmm22: bool = false,
171 xmm23: bool = false,
172 xmm24: bool = false,
173 xmm25: bool = false,
174 xmm26: bool = false,
175 xmm27: bool = false,
176 xmm28: bool = false,
177 xmm29: bool = false,
178 xmm30: bool = false,
179 xmm31: bool = false,
180 mm0: bool = false,
181 mm1: bool = false,
182 mm2: bool = false,
183 mm3: bool = false,
184 mm4: bool = false,
185 mm5: bool = false,
186 mm6: bool = false,
187 mm7: bool = false,
188 st0: bool = false,
189 st1: bool = false,
190 st2: bool = false,
191 st3: bool = false,
192 st4: bool = false,
193 st5: bool = false,
194 st6: bool = false,
195 st7: bool = false,
196 es: bool = false,
197 cs: bool = false,
198 ss: bool = false,
199 ds: bool = false,
200 fs: bool = false,
201 gs: bool = false,
202 rip: bool = false,
203 eip: bool = false,
204 ip: bool = false,
205 cr0: bool = false,
206 cr1: bool = false,
207 cr2: bool = false,
208 cr3: bool = false,
209 cr4: bool = false,
210 cr5: bool = false,
211 cr6: bool = false,
212 cr7: bool = false,
213 cr8: bool = false,
214 cr9: bool = false,
215 cr10: bool = false,
216 cr11: bool = false,
217 cr12: bool = false,
218 cr13: bool = false,
219 cr14: bool = false,
220 cr15: bool = false,
221 dr0: bool = false,
222 dr1: bool = false,
223 dr2: bool = false,
224 dr3: bool = false,
225 dr4: bool = false,
226 dr5: bool = false,
227 dr6: bool = false,
228 dr7: bool = false,
229 dr8: bool = false,
230 dr9: bool = false,
231 dr10: bool = false,
232 dr11: bool = false,
233 dr12: bool = false,
234 dr13: bool = false,
235 dr14: bool = false,
236 dr15: bool = false,
237 },
238 .aarch64, .aarch64_be => packed struct {
239 /// Whether the inline assembly code may perform stores to memory
240 /// addresses other than those derived from input pointer provenance.
241 memory: bool = false,
242
243 nzcv: bool = false,
244
245 x0: bool = false,
246 x1: bool = false,
247 x2: bool = false,
248 x3: bool = false,
249 x4: bool = false,
250 x5: bool = false,
251 x6: bool = false,
252 x7: bool = false,
253 x8: bool = false,
254 x9: bool = false,
255 x10: bool = false,
256 x11: bool = false,
257 x12: bool = false,
258 x13: bool = false,
259 x14: bool = false,
260 x15: bool = false,
261 x16: bool = false,
262 x17: bool = false,
263 x18: bool = false,
264 x19: bool = false,
265 x20: bool = false,
266 x21: bool = false,
267 x22: bool = false,
268 x23: bool = false,
269 x24: bool = false,
270 x25: bool = false,
271 x26: bool = false,
272 x27: bool = false,
273 x28: bool = false,
274 x29: bool = false,
275 x30: bool = false,
276
277 w0: bool = false,
278 w1: bool = false,
279 w2: bool = false,
280 w3: bool = false,
281 w4: bool = false,
282 w5: bool = false,
283 w6: bool = false,
284 w7: bool = false,
285 w8: bool = false,
286 w9: bool = false,
287 w10: bool = false,
288 w11: bool = false,
289 w12: bool = false,
290 w13: bool = false,
291 w14: bool = false,
292 w15: bool = false,
293 w16: bool = false,
294 w17: bool = false,
295 w18: bool = false,
296 w19: bool = false,
297 w20: bool = false,
298 w21: bool = false,
299 w22: bool = false,
300 w23: bool = false,
301 w24: bool = false,
302 w25: bool = false,
303 w26: bool = false,
304 w27: bool = false,
305 w28: bool = false,
306 w29: bool = false,
307 w30: bool = false,
308
309 lr: bool = false,
310 sp: bool = false,
311 wsp: bool = false,
312 fpcr: bool = false,
313 fpmr: bool = false,
314 fpsr: bool = false,
315 ffr: bool = false,
316
317 p0: bool = false,
318 p1: bool = false,
319 p2: bool = false,
320 p3: bool = false,
321 p4: bool = false,
322 p5: bool = false,
323 p6: bool = false,
324 p7: bool = false,
325 p8: bool = false,
326 p9: bool = false,
327 p10: bool = false,
328 p11: bool = false,
329 p12: bool = false,
330 p13: bool = false,
331 p14: bool = false,
332 p15: bool = false,
333
334 z0: bool = false,
335 z1: bool = false,
336 z2: bool = false,
337 z3: bool = false,
338 z4: bool = false,
339 z5: bool = false,
340 z6: bool = false,
341 z7: bool = false,
342 z8: bool = false,
343 z9: bool = false,
344 z10: bool = false,
345 z11: bool = false,
346 z12: bool = false,
347 z13: bool = false,
348 z14: bool = false,
349 z15: bool = false,
350 z16: bool = false,
351 z17: bool = false,
352 z18: bool = false,
353 z19: bool = false,
354 z20: bool = false,
355 z21: bool = false,
356 z22: bool = false,
357 z23: bool = false,
358 z24: bool = false,
359 z25: bool = false,
360 z26: bool = false,
361 z27: bool = false,
362 z28: bool = false,
363 z29: bool = false,
364 z30: bool = false,
365 z31: bool = false,
366
367 v0: bool = false,
368 v1: bool = false,
369 v2: bool = false,
370 v3: bool = false,
371 v4: bool = false,
372 v5: bool = false,
373 v6: bool = false,
374 v7: bool = false,
375 v8: bool = false,
376 v9: bool = false,
377 v10: bool = false,
378 v11: bool = false,
379 v12: bool = false,
380 v13: bool = false,
381 v14: bool = false,
382 v15: bool = false,
383 v16: bool = false,
384 v17: bool = false,
385 v18: bool = false,
386 v19: bool = false,
387 v20: bool = false,
388 v21: bool = false,
389 v22: bool = false,
390 v23: bool = false,
391 v24: bool = false,
392 v25: bool = false,
393 v26: bool = false,
394 v27: bool = false,
395 v28: bool = false,
396 v29: bool = false,
397 v30: bool = false,
398 v31: bool = false,
399
400 d0: bool = false,
401 d1: bool = false,
402 d2: bool = false,
403 d3: bool = false,
404 d4: bool = false,
405 d5: bool = false,
406 d6: bool = false,
407 d7: bool = false,
408 d8: bool = false,
409 d9: bool = false,
410 d10: bool = false,
411 d11: bool = false,
412 d12: bool = false,
413 d13: bool = false,
414 d14: bool = false,
415 d15: bool = false,
416 d16: bool = false,
417 d17: bool = false,
418 d18: bool = false,
419 d19: bool = false,
420 d20: bool = false,
421 d21: bool = false,
422 d22: bool = false,
423 d23: bool = false,
424 d24: bool = false,
425 d25: bool = false,
426 d26: bool = false,
427 d27: bool = false,
428 d28: bool = false,
429 d29: bool = false,
430 d30: bool = false,
431 d31: bool = false,
432
433 s0: bool = false,
434 s1: bool = false,
435 s2: bool = false,
436 s3: bool = false,
437 s4: bool = false,
438 s5: bool = false,
439 s6: bool = false,
440 s7: bool = false,
441 s8: bool = false,
442 s9: bool = false,
443 s10: bool = false,
444 s11: bool = false,
445 s12: bool = false,
446 s13: bool = false,
447 s14: bool = false,
448 s15: bool = false,
449 s16: bool = false,
450 s17: bool = false,
451 s18: bool = false,
452 s19: bool = false,
453 s20: bool = false,
454 s21: bool = false,
455 s22: bool = false,
456 s23: bool = false,
457 s24: bool = false,
458 s25: bool = false,
459 s26: bool = false,
460 s27: bool = false,
461 s28: bool = false,
462 s29: bool = false,
463 s30: bool = false,
464 s31: bool = false,
465
466 h0: bool = false,
467 h1: bool = false,
468 h2: bool = false,
469 h3: bool = false,
470 h4: bool = false,
471 h5: bool = false,
472 h6: bool = false,
473 h7: bool = false,
474 h8: bool = false,
475 h9: bool = false,
476 h10: bool = false,
477 h11: bool = false,
478 h12: bool = false,
479 h13: bool = false,
480 h14: bool = false,
481 h15: bool = false,
482 h16: bool = false,
483 h17: bool = false,
484 h18: bool = false,
485 h19: bool = false,
486 h20: bool = false,
487 h21: bool = false,
488 h22: bool = false,
489 h23: bool = false,
490 h24: bool = false,
491 h25: bool = false,
492 h26: bool = false,
493 h27: bool = false,
494 h28: bool = false,
495 h29: bool = false,
496 h30: bool = false,
497 h31: bool = false,
498
499 b0: bool = false,
500 b1: bool = false,
501 b2: bool = false,
502 b3: bool = false,
503 b4: bool = false,
504 b5: bool = false,
505 b6: bool = false,
506 b7: bool = false,
507 b8: bool = false,
508 b9: bool = false,
509 b10: bool = false,
510 b11: bool = false,
511 b12: bool = false,
512 b13: bool = false,
513 b14: bool = false,
514 b15: bool = false,
515 b16: bool = false,
516 b17: bool = false,
517 b18: bool = false,
518 b19: bool = false,
519 b20: bool = false,
520 b21: bool = false,
521 b22: bool = false,
522 b23: bool = false,
523 b24: bool = false,
524 b25: bool = false,
525 b26: bool = false,
526 b27: bool = false,
527 b28: bool = false,
528 b29: bool = false,
529 b30: bool = false,
530 b31: bool = false,
531
532 za0: bool = false,
533 za1: bool = false,
534 za2: bool = false,
535 za3: bool = false,
536 za4: bool = false,
537 za5: bool = false,
538 za6: bool = false,
539 za7: bool = false,
540 za8: bool = false,
541 za9: bool = false,
542 za10: bool = false,
543 za11: bool = false,
544 za12: bool = false,
545 za13: bool = false,
546 za14: bool = false,
547 za15: bool = false,
548
549 zt0: bool = false,
550 },
551 .arm, .armeb => packed struct {
552 /// Whether the inline assembly code may perform stores to memory
553 /// addresses other than those derived from input pointer provenance.
554 memory: bool = false,
555
556 apsr: bool = false,
557 cpsr: bool = false,
558 spsr: bool = false,
559 r0: bool = false,
560 r1: bool = false,
561 r2: bool = false,
562 r3: bool = false,
563 r4: bool = false,
564 r5: bool = false,
565 r6: bool = false,
566 r7: bool = false,
567 r8: bool = false,
568 r9: bool = false,
569 r10: bool = false,
570 r11: bool = false,
571 r12: bool = false,
572 r13: bool = false,
573 r14: bool = false,
574 r15: bool = false,
575
576 fpscr: bool = false,
577 vpr: bool = false,
578
579 d0: bool = false,
580 d1: bool = false,
581 d2: bool = false,
582 d3: bool = false,
583 d4: bool = false,
584 d5: bool = false,
585 d6: bool = false,
586 d7: bool = false,
587 d8: bool = false,
588 d9: bool = false,
589 d10: bool = false,
590 d11: bool = false,
591 d12: bool = false,
592 d13: bool = false,
593 d14: bool = false,
594 d15: bool = false,
595 d16: bool = false,
596 d17: bool = false,
597 d18: bool = false,
598 d19: bool = false,
599 d20: bool = false,
600 d21: bool = false,
601 d22: bool = false,
602 d23: bool = false,
603 d24: bool = false,
604 d25: bool = false,
605 d26: bool = false,
606 d27: bool = false,
607 d28: bool = false,
608 d29: bool = false,
609 d30: bool = false,
610 d31: bool = false,
611
612 s0: bool = false,
613 s1: bool = false,
614 s2: bool = false,
615 s3: bool = false,
616 s4: bool = false,
617 s5: bool = false,
618 s6: bool = false,
619 s7: bool = false,
620 s8: bool = false,
621 s9: bool = false,
622 s10: bool = false,
623 s11: bool = false,
624 s12: bool = false,
625 s13: bool = false,
626 s14: bool = false,
627 s15: bool = false,
628 s16: bool = false,
629 s17: bool = false,
630 s18: bool = false,
631 s19: bool = false,
632 s20: bool = false,
633 s21: bool = false,
634 s22: bool = false,
635 s23: bool = false,
636 s24: bool = false,
637 s25: bool = false,
638 s26: bool = false,
639 s27: bool = false,
640 s28: bool = false,
641 s29: bool = false,
642 s30: bool = false,
643 s31: bool = false,
644
645 q0: bool = false,
646 q1: bool = false,
647 q2: bool = false,
648 q3: bool = false,
649 q4: bool = false,
650 q5: bool = false,
651 q6: bool = false,
652 q7: bool = false,
653 q8: bool = false,
654 q9: bool = false,
655 q10: bool = false,
656 q11: bool = false,
657 q12: bool = false,
658 q13: bool = false,
659 q14: bool = false,
660 q15: bool = false,
661 },
662 .riscv32, .riscv64 => packed struct {
663 /// Whether the inline assembly code may perform stores to memory
664 /// addresses other than those derived from input pointer provenance.
665 memory: bool = false,
666
667 ssp: bool = false,
668
669 x1: bool = false,
670 x2: bool = false,
671 x3: bool = false,
672 x4: bool = false,
673 x5: bool = false,
674 x6: bool = false,
675 x7: bool = false,
676 x8: bool = false,
677 x9: bool = false,
678 x10: bool = false,
679 x11: bool = false,
680 x12: bool = false,
681 x13: bool = false,
682 x14: bool = false,
683 x15: bool = false,
684 x16: bool = false,
685 x17: bool = false,
686 x18: bool = false,
687 x19: bool = false,
688 x20: bool = false,
689 x21: bool = false,
690 x22: bool = false,
691 x23: bool = false,
692 x24: bool = false,
693 x25: bool = false,
694 x26: bool = false,
695 x27: bool = false,
696 x28: bool = false,
697 x29: bool = false,
698 x30: bool = false,
699 x31: bool = false,
700
701 fflags: bool = false,
702 frm: bool = false,
703
704 f0: bool = false,
705 f1: bool = false,
706 f2: bool = false,
707 f3: bool = false,
708 f4: bool = false,
709 f5: bool = false,
710 f6: bool = false,
711 f7: bool = false,
712 f8: bool = false,
713 f9: bool = false,
714 f10: bool = false,
715 f11: bool = false,
716 f12: bool = false,
717 f13: bool = false,
718 f14: bool = false,
719 f15: bool = false,
720 f16: bool = false,
721 f17: bool = false,
722 f18: bool = false,
723 f19: bool = false,
724 f20: bool = false,
725 f21: bool = false,
726 f22: bool = false,
727 f23: bool = false,
728 f24: bool = false,
729 f25: bool = false,
730 f26: bool = false,
731 f27: bool = false,
732 f28: bool = false,
733 f29: bool = false,
734 f30: bool = false,
735 f31: bool = false,
736
737 vtype: bool = false,
738 vl: bool = false,
739 vxsat: bool = false,
740 vxrm: bool = false,
741 vcsr: bool = false,
742
743 v0: bool = false,
744 v1: bool = false,
745 v2: bool = false,
746 v3: bool = false,
747 v4: bool = false,
748 v5: bool = false,
749 v6: bool = false,
750 v7: bool = false,
751 v8: bool = false,
752 v9: bool = false,
753 v10: bool = false,
754 v11: bool = false,
755 v12: bool = false,
756 v13: bool = false,
757 v14: bool = false,
758 v15: bool = false,
759 v16: bool = false,
760 v17: bool = false,
761 v18: bool = false,
762 v19: bool = false,
763 v20: bool = false,
764 v21: bool = false,
765 v22: bool = false,
766 v23: bool = false,
767 v24: bool = false,
768 v25: bool = false,
769 v26: bool = false,
770 v27: bool = false,
771 v28: bool = false,
772 v29: bool = false,
773 v30: bool = false,
774 v31: bool = false,
775 },
776 .xcore => packed struct {
777 /// Whether the inline assembly code may perform stores to memory
778 /// addresses other than those derived from input pointer provenance.
779 memory: bool = false,
780
781 r0: bool = false,
782 r1: bool = false,
783 r2: bool = false,
784 r3: bool = false,
785 r4: bool = false,
786 r5: bool = false,
787 r6: bool = false,
788 r7: bool = false,
789 r8: bool = false,
790 r9: bool = false,
791 r10: bool = false,
792 r11: bool = false,
793
794 cp: bool = false,
795 dp: bool = false,
796 sp: bool = false,
797 lr: bool = false,
798 sr: bool = false,
799 },
800 .xtensa => packed struct {
801 /// Whether the inline assembly code may perform stores to memory
802 /// addresses other than those derived from input pointer provenance.
803 memory: bool = false,
804
805 sar: bool = false,
806 lbeg: bool = false,
807 lend: bool = false,
808 lcount: bool = false,
809 atomctl: bool = false,
810 scompare1: bool = false,
811 threadptr: bool = false,
812 litbase: bool = false,
813 windowbase: bool = false,
814 windowstart: bool = false,
815 ps: bool = false,
816
817 a0: bool = false,
818 a1: bool = false,
819 a2: bool = false,
820 a3: bool = false,
821 a4: bool = false,
822 a5: bool = false,
823 a6: bool = false,
824 a7: bool = false,
825 a8: bool = false,
826 a9: bool = false,
827 a10: bool = false,
828 a11: bool = false,
829 a12: bool = false,
830 a13: bool = false,
831 a14: bool = false,
832 a15: bool = false,
833
834 b0: bool = false,
835 b1: bool = false,
836 b2: bool = false,
837 b3: bool = false,
838 b4: bool = false,
839 b5: bool = false,
840 b6: bool = false,
841 b7: bool = false,
842 b8: bool = false,
843 b9: bool = false,
844 b10: bool = false,
845 b11: bool = false,
846 b12: bool = false,
847 b13: bool = false,
848 b14: bool = false,
849 b15: bool = false,
850
851 br: bool = false,
852 acchi: bool = false,
853 acclo: bool = false,
854 m0: bool = false,
855 m1: bool = false,
856 m2: bool = false,
857 m3: bool = false,
858 fcr: bool = false,
859 fsr: bool = false,
860
861 f0: bool = false,
862 f1: bool = false,
863 f2: bool = false,
864 f3: bool = false,
865 f4: bool = false,
866 f5: bool = false,
867 f6: bool = false,
868 f7: bool = false,
869 f8: bool = false,
870 f9: bool = false,
871 f10: bool = false,
872 f11: bool = false,
873 f12: bool = false,
874 f13: bool = false,
875 f14: bool = false,
876 f15: bool = false,
877 },
878 .lanai => packed struct {
879 /// Whether the inline assembly code may perform stores to memory
880 /// addresses other than those derived from input pointer provenance.
881 memory: bool = false,
882 /// Condition flags which aren't accessible outside of conditional execution.
883 sw: bool = false,
884
885 r3: bool = false,
886 r4: bool = false,
887 r5: bool = false,
888 r6: bool = false,
889 r7: bool = false,
890 r8: bool = false,
891 r9: bool = false,
892 r10: bool = false,
893 r11: bool = false,
894 r12: bool = false,
895 r13: bool = false,
896 r14: bool = false,
897 r15: bool = false,
898 r16: bool = false,
899 r17: bool = false,
900 r18: bool = false,
901 r19: bool = false,
902 r20: bool = false,
903 r21: bool = false,
904 r22: bool = false,
905 r23: bool = false,
906 r24: bool = false,
907 r25: bool = false,
908 r26: bool = false,
909 r27: bool = false,
910 r28: bool = false,
911 r29: bool = false,
912 r30: bool = false,
913 r31: bool = false,
914 },
915 .avr => packed struct {
916 /// Whether the inline assembly code may perform stores to memory
917 /// addresses other than those derived from input pointer provenance.
918 memory: bool = false,
919 flags: bool = false,
920 r0: bool = false,
921 r1: bool = false,
922 r2: bool = false,
923 r3: bool = false,
924 r4: bool = false,
925 r5: bool = false,
926 r6: bool = false,
927 r7: bool = false,
928 r8: bool = false,
929 r9: bool = false,
930 r10: bool = false,
931 r11: bool = false,
932 r12: bool = false,
933 r13: bool = false,
934 r14: bool = false,
935 r15: bool = false,
936 r16: bool = false,
937 r17: bool = false,
938 r18: bool = false,
939 r19: bool = false,
940 r20: bool = false,
941 r21: bool = false,
942 r22: bool = false,
943 r23: bool = false,
944 r24: bool = false,
945 r25: bool = false,
946 r26: bool = false,
947 r27: bool = false,
948 r28: bool = false,
949 r29: bool = false,
950 r30: bool = false,
951 r31: bool = false,
952 },
953 .msp430 => packed struct {
954 /// Whether the inline assembly code may perform stores to memory
955 /// addresses other than those derived from input pointer provenance.
956 memory: bool = false,
957
958 r0: bool = false,
959 r1: bool = false,
960 r2: bool = false,
961
962 r4: bool = false,
963 r5: bool = false,
964 r6: bool = false,
965 r7: bool = false,
966 r8: bool = false,
967 r9: bool = false,
968 r10: bool = false,
969 r11: bool = false,
970 r12: bool = false,
971 r13: bool = false,
972 r14: bool = false,
973 r15: bool = false,
974 },
975 .m68k => packed struct {
976 /// Whether the inline assembly code may perform stores to memory
977 /// addresses other than those derived from input pointer provenance.
978 memory: bool = false,
979
980 ccr: bool = false,
981
982 d0: bool = false,
983 d1: bool = false,
984 d2: bool = false,
985 d3: bool = false,
986 d4: bool = false,
987 d5: bool = false,
988 d6: bool = false,
989 d7: bool = false,
990
991 a0: bool = false,
992 a1: bool = false,
993 a2: bool = false,
994 a3: bool = false,
995 a4: bool = false,
996 a5: bool = false,
997 a6: bool = false,
998 a7: bool = false,
999
1000 macsr: bool = false,
1001 acc: bool = false,
1002
1003 acc0: bool = false,
1004 acc1: bool = false,
1005 acc2: bool = false,
1006 acc3: bool = false,
1007
1008 mask: bool = false,
1009 fpcr: bool = false,
1010 fpsr: bool = false,
1011
1012 fp0: bool = false,
1013 fp1: bool = false,
1014 fp2: bool = false,
1015 fp3: bool = false,
1016 fp4: bool = false,
1017 fp5: bool = false,
1018 fp6: bool = false,
1019 fp7: bool = false,
1020 },
1021 else => packed struct {
1022 /// Whether the inline assembly code may perform stores to memory
1023 /// addresses other than those derived from input pointer provenance.
1024 memory: bool = false,
1025 },
1026};
lib/std/zig.zig+2
...@@ -740,6 +740,7 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -740,6 +740,7 @@ pub const SimpleComptimeReason = enum(u32) {
740 generic_call_target,740 generic_call_target,
741 wasm_memory_index,741 wasm_memory_index,
742 work_group_dim_index,742 work_group_dim_index,
743 clobber,
743744
744 // Evaluating at comptime because types must be comptime-known.745 // Evaluating at comptime because types must be comptime-known.
745 // Reasons other than `.type` are just more specific messages.746 // Reasons other than `.type` are just more specific messages.
...@@ -820,6 +821,7 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -820,6 +821,7 @@ pub const SimpleComptimeReason = enum(u32) {
820 .generic_call_target => "generic function being called must be comptime-known",821 .generic_call_target => "generic function being called must be comptime-known",
821 .wasm_memory_index => "wasm memory index must be comptime-known",822 .wasm_memory_index => "wasm memory index must be comptime-known",
822 .work_group_dim_index => "work group dimension index must be comptime-known",823 .work_group_dim_index => "work group dimension index must be comptime-known",
824 .clobber => "clobber must be comptime-known",
823825
824 .type => "types must be comptime-known",826 .type => "types must be comptime-known",
825 .array_sentinel => "array sentinel value must be comptime-known",827 .array_sentinel => "array sentinel value must be comptime-known",
lib/std/zig/Ast.zig+86-4
...@@ -634,6 +634,7 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {...@@ -634,6 +634,7 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
634 .@"nosuspend",634 .@"nosuspend",
635 .asm_simple,635 .asm_simple,
636 .@"asm",636 .@"asm",
637 .asm_legacy,
637 .array_type,638 .array_type,
638 .array_type_sentinel,639 .array_type_sentinel,
639 .error_value,640 .error_value,
...@@ -1047,6 +1048,11 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {...@@ -1047,6 +1048,11 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
1047 n = @enumFromInt(tree.extra_data[@intFromEnum(members.end) - 1]); // last parameter1048 n = @enumFromInt(tree.extra_data[@intFromEnum(members.end) - 1]); // last parameter
1048 }1049 }
1049 },1050 },
1051 .asm_legacy => {
1052 _, const extra_index = tree.nodeData(n).node_and_extra;
1053 const extra = tree.extraData(extra_index, Node.AsmLegacy);
1054 return extra.rparen + end_offset;
1055 },
1050 .@"asm" => {1056 .@"asm" => {
1051 _, const extra_index = tree.nodeData(n).node_and_extra;1057 _, const extra_index = tree.nodeData(n).node_and_extra;
1052 const extra = tree.extraData(extra_index, Node.Asm);1058 const extra = tree.extraData(extra_index, Node.Asm);
...@@ -1885,6 +1891,19 @@ pub fn asmSimple(tree: Ast, node: Node.Index) full.Asm {...@@ -1885,6 +1891,19 @@ pub fn asmSimple(tree: Ast, node: Node.Index) full.Asm {
1885 .template = template,1891 .template = template,
1886 .items = &.{},1892 .items = &.{},
1887 .rparen = rparen,1893 .rparen = rparen,
1894 .clobbers = .none,
1895 });
1896}
1897
1898pub fn asmLegacy(tree: Ast, node: Node.Index) full.AsmLegacy {
1899 const template, const extra_index = tree.nodeData(node).node_and_extra;
1900 const extra = tree.extraData(extra_index, Node.AsmLegacy);
1901 const items = tree.extraDataSlice(.{ .start = extra.items_start, .end = extra.items_end }, Node.Index);
1902 return tree.legacyAsmComponents(.{
1903 .asm_token = tree.nodeMainToken(node),
1904 .template = template,
1905 .items = items,
1906 .rparen = extra.rparen,
1888 });1907 });
1889}1908}
18901909
...@@ -1896,6 +1915,7 @@ pub fn asmFull(tree: Ast, node: Node.Index) full.Asm {...@@ -1896,6 +1915,7 @@ pub fn asmFull(tree: Ast, node: Node.Index) full.Asm {
1896 .asm_token = tree.nodeMainToken(node),1915 .asm_token = tree.nodeMainToken(node),
1897 .template = template,1916 .template = template,
1898 .items = items,1917 .items = items,
1918 .clobbers = extra.clobbers,
1899 .rparen = extra.rparen,1919 .rparen = extra.rparen,
1900 });1920 });
1901}1921}
...@@ -2192,8 +2212,8 @@ fn fullSwitchCaseComponents(tree: Ast, info: full.SwitchCase.Components, node: N...@@ -2192,8 +2212,8 @@ fn fullSwitchCaseComponents(tree: Ast, info: full.SwitchCase.Components, node: N
2192 return result;2212 return result;
2193}2213}
21942214
2195fn fullAsmComponents(tree: Ast, info: full.Asm.Components) full.Asm {2215fn legacyAsmComponents(tree: Ast, info: full.AsmLegacy.Components) full.AsmLegacy {
2196 var result: full.Asm = .{2216 var result: full.AsmLegacy = .{
2197 .ast = info,2217 .ast = info,
2198 .volatile_token = null,2218 .volatile_token = null,
2199 .inputs = &.{},2219 .inputs = &.{},
...@@ -2253,6 +2273,29 @@ fn fullAsmComponents(tree: Ast, info: full.Asm.Components) full.Asm {...@@ -2253,6 +2273,29 @@ fn fullAsmComponents(tree: Ast, info: full.Asm.Components) full.Asm {
2253 return result;2273 return result;
2254}2274}
22552275
2276fn fullAsmComponents(tree: Ast, info: full.Asm.Components) full.Asm {
2277 var result: full.Asm = .{
2278 .ast = info,
2279 .volatile_token = null,
2280 .inputs = &.{},
2281 .outputs = &.{},
2282 };
2283 if (tree.tokenTag(info.asm_token + 1) == .keyword_volatile) {
2284 result.volatile_token = info.asm_token + 1;
2285 }
2286 const outputs_end: usize = for (info.items, 0..) |item, i| {
2287 switch (tree.nodeTag(item)) {
2288 .asm_output => continue,
2289 else => break i,
2290 }
2291 } else info.items.len;
2292
2293 result.outputs = info.items[0..outputs_end];
2294 result.inputs = info.items[outputs_end..];
2295
2296 return result;
2297}
2298
2256fn fullWhileComponents(tree: Ast, info: full.While.Components) full.While {2299fn fullWhileComponents(tree: Ast, info: full.While.Components) full.While {
2257 var result: full.While = .{2300 var result: full.While = .{
2258 .ast = info,2301 .ast = info,
...@@ -2447,6 +2490,14 @@ pub fn fullAsm(tree: Ast, node: Node.Index) ?full.Asm {...@@ -2447,6 +2490,14 @@ pub fn fullAsm(tree: Ast, node: Node.Index) ?full.Asm {
2447 };2490 };
2448}2491}
24492492
2493/// To be deleted after 0.15.0 is tagged
2494pub fn legacyAsm(tree: Ast, node: Node.Index) ?full.AsmLegacy {
2495 return switch (tree.nodeTag(node)) {
2496 .asm_legacy => tree.asmLegacy(node),
2497 else => null,
2498 };
2499}
2500
2450pub fn fullCall(tree: Ast, buffer: *[1]Ast.Node.Index, node: Node.Index) ?full.Call {2501pub fn fullCall(tree: Ast, buffer: *[1]Ast.Node.Index, node: Node.Index) ?full.Call {
2451 return switch (tree.nodeTag(node)) {2502 return switch (tree.nodeTag(node)) {
2452 .call, .call_comma => tree.callFull(node),2503 .call, .call_comma => tree.callFull(node),
...@@ -2827,6 +2878,21 @@ pub const full = struct {...@@ -2827,6 +2878,21 @@ pub const full = struct {
2827 };2878 };
28282879
2829 pub const Asm = struct {2880 pub const Asm = struct {
2881 ast: Components,
2882 volatile_token: ?TokenIndex,
2883 outputs: []const Node.Index,
2884 inputs: []const Node.Index,
2885
2886 pub const Components = struct {
2887 asm_token: TokenIndex,
2888 template: Node.Index,
2889 items: []const Node.Index,
2890 clobbers: Node.OptionalIndex,
2891 rparen: TokenIndex,
2892 };
2893 };
2894
2895 pub const AsmLegacy = struct {
2830 ast: Components,2896 ast: Components,
2831 volatile_token: ?TokenIndex,2897 volatile_token: ?TokenIndex,
2832 first_clobber: ?TokenIndex,2898 first_clobber: ?TokenIndex,
...@@ -3833,15 +3899,22 @@ pub const Node = struct {...@@ -3833,15 +3899,22 @@ pub const Node = struct {
3833 /// Same as `block` except there is known to be a trailing comma before3899 /// Same as `block` except there is known to be a trailing comma before
3834 /// the final rbrace.3900 /// the final rbrace.
3835 block_semicolon,3901 block_semicolon,
3836 /// `asm(lhs)`.3902 /// `asm(a)`.
3837 ///3903 ///
3838 /// rhs is a `Token.Index` to the `)` token.
3839 /// The `main_token` field is the `asm` token.3904 /// The `main_token` field is the `asm` token.
3840 asm_simple,3905 asm_simple,
3841 /// `asm(lhs, a)`.3906 /// `asm(lhs, a)`.
3842 ///3907 ///
3843 /// The `data` field is a `.node_and_extra`:3908 /// The `data` field is a `.node_and_extra`:
3844 /// 1. a `Node.Index` to lhs.3909 /// 1. a `Node.Index` to lhs.
3910 /// 2. a `ExtraIndex` to `AsmLegacy`.
3911 ///
3912 /// The `main_token` field is the `asm` token.
3913 asm_legacy,
3914 /// `asm(a, b)`.
3915 ///
3916 /// The `data` field is a `.node_and_extra`:
3917 /// 1. a `Node.Index` to a.
3845 /// 2. a `ExtraIndex` to `Asm`.3918 /// 2. a `ExtraIndex` to `Asm`.
3846 ///3919 ///
3847 /// The `main_token` field is the `asm` token.3920 /// The `main_token` field is the `asm` token.
...@@ -4014,9 +4087,18 @@ pub const Node = struct {...@@ -4014,9 +4087,18 @@ pub const Node = struct {
4014 callconv_expr: OptionalIndex,4087 callconv_expr: OptionalIndex,
4015 };4088 };
40164089
4090 /// To be removed after 0.15.0 is tagged
4091 pub const AsmLegacy = struct {
4092 items_start: ExtraIndex,
4093 items_end: ExtraIndex,
4094 /// Needed to make lastToken() work.
4095 rparen: TokenIndex,
4096 };
4097
4017 pub const Asm = struct {4098 pub const Asm = struct {
4018 items_start: ExtraIndex,4099 items_start: ExtraIndex,
4019 items_end: ExtraIndex,4100 items_end: ExtraIndex,
4101 clobbers: OptionalIndex,
4020 /// Needed to make lastToken() work.4102 /// Needed to make lastToken() work.
4021 rparen: TokenIndex,4103 rparen: TokenIndex,
4022 };4104 };
lib/std/zig/AstGen.zig+27-41
...@@ -505,6 +505,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins...@@ -505,6 +505,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
505 .bool_or,505 .bool_or,
506 .@"asm",506 .@"asm",
507 .asm_simple,507 .asm_simple,
508 .asm_legacy,
508 .string_literal,509 .string_literal,
509 .number_literal,510 .number_literal,
510 .call,511 .call,
...@@ -811,6 +812,12 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -811,6 +812,12 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
811 .@"asm",812 .@"asm",
812 => return asmExpr(gz, scope, ri, node, tree.fullAsm(node).?),813 => return asmExpr(gz, scope, ri, node, tree.fullAsm(node).?),
813814
815 .asm_legacy => {
816 return astgen.failNodeNotes(node, "legacy asm clobbers syntax", .{}, &[_]u32{
817 try astgen.errNoteNode(node, "use 'zig fmt' to auto-upgrade", .{}),
818 });
819 },
820
814 .string_literal => return stringLiteral(gz, ri, node),821 .string_literal => return stringLiteral(gz, ri, node),
815 .multiline_string_literal => return multilineStringLiteral(gz, ri, node),822 .multiline_string_literal => return multilineStringLiteral(gz, ri, node),
816823
...@@ -8774,7 +8781,7 @@ fn asmExpr(...@@ -8774,7 +8781,7 @@ fn asmExpr(
8774 if (is_container_asm) {8781 if (is_container_asm) {
8775 if (full.volatile_token) |t|8782 if (full.volatile_token) |t|
8776 return astgen.failTok(t, "volatile is meaningless on global assembly", .{});8783 return astgen.failTok(t, "volatile is meaningless on global assembly", .{});
8777 if (full.outputs.len != 0 or full.inputs.len != 0 or full.first_clobber != null)8784 if (full.outputs.len != 0 or full.inputs.len != 0 or full.ast.clobbers != .none)
8778 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{});8785 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{});
8779 } else {8786 } else {
8780 if (full.outputs.len == 0 and full.volatile_token == null) {8787 if (full.outputs.len == 0 and full.volatile_token == null) {
...@@ -8839,32 +8846,12 @@ fn asmExpr(...@@ -8839,32 +8846,12 @@ fn asmExpr(
8839 };8846 };
8840 }8847 }
88418848
8842 var clobbers_buffer: [63]u32 = undefined;8849 const clobbers: Zir.Inst.Ref = if (full.ast.clobbers.unwrap()) |clobbers_node|
8843 var clobber_i: usize = 0;8850 try comptimeExpr(gz, scope, .{ .rl = .{
8844 if (full.first_clobber) |first_clobber| clobbers: {8851 .coerced_ty = try gz.addBuiltinValue(clobbers_node, .clobbers),
8845 // asm ("foo" ::: "a", "b")8852 } }, clobbers_node, .clobber)
8846 // asm ("foo" ::: "a", "b",)8853 else
8847 var tok_i = first_clobber;8854 .none;
8848 while (true) : (tok_i += 1) {
8849 if (clobber_i >= clobbers_buffer.len) {
8850 return astgen.failTok(tok_i, "too many asm clobbers", .{});
8851 }
8852 clobbers_buffer[clobber_i] = @intFromEnum((try astgen.strLitAsString(tok_i)).index);
8853 clobber_i += 1;
8854 tok_i += 1;
8855 switch (tree.tokenTag(tok_i)) {
8856 .r_paren => break :clobbers,
8857 .comma => {
8858 if (tree.tokenTag(tok_i + 1) == .r_paren) {
8859 break :clobbers;
8860 } else {
8861 continue;
8862 }
8863 },
8864 else => unreachable,
8865 }
8866 }
8867 }
88688855
8869 const result = try gz.addAsm(.{8856 const result = try gz.addAsm(.{
8870 .tag = tag_and_tmpl.tag,8857 .tag = tag_and_tmpl.tag,
...@@ -8874,7 +8861,7 @@ fn asmExpr(...@@ -8874,7 +8861,7 @@ fn asmExpr(
8874 .output_type_bits = output_type_bits,8861 .output_type_bits = output_type_bits,
8875 .outputs = outputs,8862 .outputs = outputs,
8876 .inputs = inputs,8863 .inputs = inputs,
8877 .clobbers = clobbers_buffer[0..clobber_i],8864 .clobbers = clobbers,
8878 });8865 });
8879 return rvalue(gz, ri, result, node);8866 return rvalue(gz, ri, result, node);
8880}8867}
...@@ -10332,6 +10319,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev...@@ -10332,6 +10319,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
1033210319
10333 .@"asm",10320 .@"asm",
10334 .asm_simple,10321 .asm_simple,
10322 .asm_legacy,
10335 .identifier,10323 .identifier,
10336 .field_access,10324 .field_access,
10337 .deref,10325 .deref,
...@@ -10575,6 +10563,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In...@@ -10575,6 +10563,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
10575 .tagged_union_enum_tag_trailing,10563 .tagged_union_enum_tag_trailing,
10576 .@"asm",10564 .@"asm",
10577 .asm_simple,10565 .asm_simple,
10566 .asm_legacy,
10578 .add,10567 .add,
10579 .add_wrap,10568 .add_wrap,
10580 .add_sat,10569 .add_sat,
...@@ -10813,6 +10802,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -10813,6 +10802,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
10813 .tagged_union_enum_tag_trailing,10802 .tagged_union_enum_tag_trailing,
10814 .@"asm",10803 .@"asm",
10815 .asm_simple,10804 .asm_simple,
10805 .asm_legacy,
10816 .add,10806 .add,
10817 .add_wrap,10807 .add_wrap,
10818 .add_sat,10808 .add_sat,
...@@ -12806,7 +12796,7 @@ const GenZir = struct {...@@ -12806,7 +12796,7 @@ const GenZir = struct {
12806 is_volatile: bool,12796 is_volatile: bool,
12807 outputs: []const Zir.Inst.Asm.Output,12797 outputs: []const Zir.Inst.Asm.Output,
12808 inputs: []const Zir.Inst.Asm.Input,12798 inputs: []const Zir.Inst.Asm.Input,
12809 clobbers: []const u32,12799 clobbers: Zir.Inst.Ref,
12810 },12800 },
12811 ) !Zir.Inst.Ref {12801 ) !Zir.Inst.Ref {
12812 const astgen = gz.astgen;12802 const astgen = gz.astgen;
...@@ -12816,13 +12806,13 @@ const GenZir = struct {...@@ -12816,13 +12806,13 @@ const GenZir = struct {
12816 try astgen.instructions.ensureUnusedCapacity(gpa, 1);12806 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
12817 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).@"struct".fields.len +12807 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).@"struct".fields.len +
12818 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).@"struct".fields.len +12808 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).@"struct".fields.len +
12819 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).@"struct".fields.len +12809 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).@"struct".fields.len);
12820 args.clobbers.len);
1282112810
12822 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{12811 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{
12823 .src_node = gz.nodeIndexToRelative(args.node),12812 .src_node = gz.nodeIndexToRelative(args.node),
12824 .asm_source = args.asm_source,12813 .asm_source = args.asm_source,
12825 .output_type_bits = args.output_type_bits,12814 .output_type_bits = args.output_type_bits,
12815 .clobbers = args.clobbers,
12826 });12816 });
12827 for (args.outputs) |output| {12817 for (args.outputs) |output| {
12828 _ = gz.astgen.addExtraAssumeCapacity(output);12818 _ = gz.astgen.addExtraAssumeCapacity(output);
...@@ -12830,23 +12820,19 @@ const GenZir = struct {...@@ -12830,23 +12820,19 @@ const GenZir = struct {
12830 for (args.inputs) |input| {12820 for (args.inputs) |input| {
12831 _ = gz.astgen.addExtraAssumeCapacity(input);12821 _ = gz.astgen.addExtraAssumeCapacity(input);
12832 }12822 }
12833 gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers);
1283412823
12835 // * 0b00000000_0000XXXX - `outputs_len`.12824 const small: Zir.Inst.Asm.Small = .{
12836 // * 0b0000000X_XXXX0000 - `inputs_len`.12825 .outputs_len = @intCast(args.outputs.len),
12837 // * 0b0XXXXXX0_00000000 - `clobbers_len`.12826 .inputs_len = @intCast(args.inputs.len),
12838 // * 0bX0000000_00000000 - is volatile12827 .is_volatile = args.is_volatile,
12839 const small: u16 = @as(u16, @as(u4, @intCast(args.outputs.len))) << 0 |12828 };
12840 @as(u16, @as(u5, @intCast(args.inputs.len))) << 4 |
12841 @as(u16, @as(u6, @intCast(args.clobbers.len))) << 9 |
12842 @as(u16, @intFromBool(args.is_volatile)) << 15;
1284312829
12844 const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);12830 const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
12845 astgen.instructions.appendAssumeCapacity(.{12831 astgen.instructions.appendAssumeCapacity(.{
12846 .tag = .extended,12832 .tag = .extended,
12847 .data = .{ .extended = .{12833 .data = .{ .extended = .{
12848 .opcode = args.tag,12834 .opcode = args.tag,
12849 .small = small,12835 .small = @bitCast(small),
12850 .operand = payload_index,12836 .operand = payload_index,
12851 } },12837 } },
12852 });12838 });
lib/std/zig/AstRlAnnotate.zig+1
...@@ -310,6 +310,7 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI...@@ -310,6 +310,7 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
310 .unreachable_literal,310 .unreachable_literal,
311 .asm_simple,311 .asm_simple,
312 .@"asm",312 .@"asm",
313 .asm_legacy,
313 .enum_literal,314 .enum_literal,
314 .error_value,315 .error_value,
315 .anyframe_literal,316 .anyframe_literal,
lib/std/zig/Parse.zig+27-4
...@@ -2801,7 +2801,7 @@ fn expectSwitchSuffix(p: *Parse, main_token: TokenIndex) !Node.Index {...@@ -2801,7 +2801,7 @@ fn expectSwitchSuffix(p: *Parse, main_token: TokenIndex) !Node.Index {
2801///2801///
2802/// AsmInput <- COLON AsmInputList AsmClobbers?2802/// AsmInput <- COLON AsmInputList AsmClobbers?
2803///2803///
2804/// AsmClobbers <- COLON StringList2804/// AsmClobbers <- COLON Expr
2805///2805///
2806/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?2806/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
2807///2807///
...@@ -2841,7 +2841,8 @@ fn expectAsmExpr(p: *Parse) !Node.Index {...@@ -2841,7 +2841,8 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
2841 else => try p.warnExpected(.comma),2841 else => try p.warnExpected(.comma),
2842 }2842 }
2843 }2843 }
2844 if (p.eatToken(.colon)) |_| {2844
2845 const clobbers: Node.OptionalIndex = if (p.eatToken(.colon)) |_| clobbers: {
2845 while (true) {2846 while (true) {
2846 const input_item = try p.parseAsmInputItem() orelse break;2847 const input_item = try p.parseAsmInputItem() orelse break;
2847 try p.scratch.append(p.gpa, input_item);2848 try p.scratch.append(p.gpa, input_item);
...@@ -2853,7 +2854,11 @@ fn expectAsmExpr(p: *Parse) !Node.Index {...@@ -2853,7 +2854,11 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
2853 else => try p.warnExpected(.comma),2854 else => try p.warnExpected(.comma),
2854 }2855 }
2855 }2856 }
2856 if (p.eatToken(.colon)) |_| {2857
2858 _ = p.eatToken(.colon) orelse break :clobbers .none;
2859
2860 // For automatic upgrades; delete after 0.15.0 released.
2861 if (p.tokenTag(p.tok_i) == .string_literal) {
2857 while (p.eatToken(.string_literal)) |_| {2862 while (p.eatToken(.string_literal)) |_| {
2858 switch (p.tokenTag(p.tok_i)) {2863 switch (p.tokenTag(p.tok_i)) {
2859 .comma => p.tok_i += 1,2864 .comma => p.tok_i += 1,
...@@ -2862,8 +2867,25 @@ fn expectAsmExpr(p: *Parse) !Node.Index {...@@ -2862,8 +2867,25 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
2862 else => try p.warnExpected(.comma),2867 else => try p.warnExpected(.comma),
2863 }2868 }
2864 }2869 }
2870 const rparen = try p.expectToken(.r_paren);
2871 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2872 return p.addNode(.{
2873 .tag = .asm_legacy,
2874 .main_token = asm_token,
2875 .data = .{ .node_and_extra = .{
2876 template,
2877 try p.addExtra(Node.AsmLegacy{
2878 .items_start = span.start,
2879 .items_end = span.end,
2880 .rparen = rparen,
2881 }),
2882 } },
2883 });
2865 }2884 }
2866 }2885
2886 break :clobbers (try p.expectExpr()).toOptional();
2887 } else .none;
2888
2867 const rparen = try p.expectToken(.r_paren);2889 const rparen = try p.expectToken(.r_paren);
2868 const span = try p.listToSpan(p.scratch.items[scratch_top..]);2890 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2869 return p.addNode(.{2891 return p.addNode(.{
...@@ -2874,6 +2896,7 @@ fn expectAsmExpr(p: *Parse) !Node.Index {...@@ -2874,6 +2896,7 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
2874 try p.addExtra(Node.Asm{2896 try p.addExtra(Node.Asm{
2875 .items_start = span.start,2897 .items_start = span.start,
2876 .items_end = span.end,2898 .items_end = span.end,
2899 .clobbers = clobbers,
2877 .rparen = rparen,2900 .rparen = rparen,
2878 }),2901 }),
2879 } },2902 } },
lib/std/zig/Zir.zig+8-6
...@@ -1939,11 +1939,6 @@ pub const Inst = struct {...@@ -1939,11 +1939,6 @@ pub const Inst = struct {
1939 /// `operand` is payload index to `BinNode`.1939 /// `operand` is payload index to `BinNode`.
1940 builtin_extern,1940 builtin_extern,
1941 /// Inline assembly.1941 /// Inline assembly.
1942 /// `small`:
1943 /// * 0b00000000_000XXXXX - `outputs_len`.
1944 /// * 0b000000XX_XXX00000 - `inputs_len`.
1945 /// * 0b0XXXXX00_00000000 - `clobbers_len`.
1946 /// * 0bX0000000_00000000 - is volatile
1947 /// `operand` is payload index to `Asm`.1942 /// `operand` is payload index to `Asm`.
1948 @"asm",1943 @"asm",
1949 /// Same as `asm` except the assembly template is not a string literal but a comptime1944 /// Same as `asm` except the assembly template is not a string literal but a comptime
...@@ -2495,7 +2490,6 @@ pub const Inst = struct {...@@ -2495,7 +2490,6 @@ pub const Inst = struct {
2495 /// Trailing:2490 /// Trailing:
2496 /// 0. Output for every outputs_len2491 /// 0. Output for every outputs_len
2497 /// 1. Input for every inputs_len2492 /// 1. Input for every inputs_len
2498 /// 2. clobber: NullTerminatedString // index into string_bytes (null terminated) for every clobbers_len.
2499 pub const Asm = struct {2493 pub const Asm = struct {
2500 src_node: Ast.Node.Offset,2494 src_node: Ast.Node.Offset,
2501 // null-terminated string index2495 // null-terminated string index
...@@ -2505,6 +2499,13 @@ pub const Inst = struct {...@@ -2505,6 +2499,13 @@ pub const Inst = struct {
2505 /// 0b1 - operand is a type; asm expression has the output as the result.2499 /// 0b1 - operand is a type; asm expression has the output as the result.
2506 /// 0b0X is the first output, 0bX0 is the second, etc.2500 /// 0b0X is the first output, 0bX0 is the second, etc.
2507 output_type_bits: u32,2501 output_type_bits: u32,
2502 clobbers: Ref,
2503
2504 pub const Small = packed struct(u16) {
2505 is_volatile: bool,
2506 outputs_len: u7,
2507 inputs_len: u8,
2508 };
25082509
2509 pub const Output = struct {2510 pub const Output = struct {
2510 /// index into string_bytes (null terminated)2511 /// index into string_bytes (null terminated)
...@@ -3482,6 +3483,7 @@ pub const Inst = struct {...@@ -3482,6 +3483,7 @@ pub const Inst = struct {
3482 extern_options,3483 extern_options,
3483 type_info,3484 type_info,
3484 branch_hint,3485 branch_hint,
3486 clobbers,
3485 // Values3487 // Values
3486 calling_convention_c,3488 calling_convention_c,
3487 calling_convention_inline,3489 calling_convention_inline,
lib/std/zig/ZonGen.zig+1-1
...@@ -227,7 +227,7 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator...@@ -227,7 +227,7 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
227 => try zg.addErrorNode(node, "control flow is not allowed in ZON", .{}),227 => try zg.addErrorNode(node, "control flow is not allowed in ZON", .{}),
228228
229 .@"comptime" => try zg.addErrorNode(node, "keyword 'comptime' is not allowed in ZON", .{}),229 .@"comptime" => try zg.addErrorNode(node, "keyword 'comptime' is not allowed in ZON", .{}),
230 .asm_simple, .@"asm" => try zg.addErrorNode(node, "inline asm is not allowed in ZON", .{}),230 .asm_simple, .@"asm", .asm_legacy => try zg.addErrorNode(node, "inline asm is not allowed in ZON", .{}),
231231
232 .builtin_call_two,232 .builtin_call_two,
233 .builtin_call_two_comma,233 .builtin_call_two_comma,
lib/std/zig/render.zig+150-10
...@@ -852,6 +852,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {...@@ -852,6 +852,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
852 .@"asm",852 .@"asm",
853 => return renderAsm(r, tree.fullAsm(node).?, space),853 => return renderAsm(r, tree.fullAsm(node).?, space),
854854
855 // To be removed after 0.15.0 is tagged
856 .asm_legacy => return renderAsmLegacy(r, tree.legacyAsm(node).?, space),
857
855 .enum_literal => {858 .enum_literal => {
856 try renderToken(r, tree.nodeMainToken(node) - 1, .none); // .859 try renderToken(r, tree.nodeMainToken(node) - 1, .none); // .
857 return renderIdentifier(r, tree.nodeMainToken(node), space, .eagerly_unquote); // name860 return renderIdentifier(r, tree.nodeMainToken(node), space, .eagerly_unquote); // name
...@@ -2363,9 +2366,9 @@ fn renderContainerDecl(...@@ -2363,9 +2366,9 @@ fn renderContainerDecl(
2363 return renderToken(r, rbrace, space); // rbrace2366 return renderToken(r, rbrace, space); // rbrace
2364}2367}
23652368
2366fn renderAsm(2369fn renderAsmLegacy(
2367 r: *Render,2370 r: *Render,
2368 asm_node: Ast.full.Asm,2371 asm_node: Ast.full.AsmLegacy,
2369 space: Space,2372 space: Space,
2370) Error!void {2373) Error!void {
2371 const tree = r.tree;2374 const tree = r.tree;
...@@ -2391,12 +2394,17 @@ fn renderAsm(...@@ -2391,12 +2394,17 @@ fn renderAsm(
2391 try renderToken(r, first_clobber - 2, .none);2394 try renderToken(r, first_clobber - 2, .none);
2392 try renderToken(r, first_clobber - 1, .space);2395 try renderToken(r, first_clobber - 1, .space);
23932396
2397 try ais.writer().writeAll(".{ ");
2398
2394 var tok_i = first_clobber;2399 var tok_i = first_clobber;
2395 while (true) : (tok_i += 1) {2400 while (true) : (tok_i += 1) {
2396 try renderToken(r, tok_i, .none);2401 try ais.writer().writeAll(".@");
2402 try ais.writer().writeAll(tokenSliceForRender(tree, tok_i));
2403
2397 tok_i += 1;2404 tok_i += 1;
2398 switch (tree.tokenTag(tok_i)) {2405 switch (tree.tokenTag(tok_i)) {
2399 .r_paren => {2406 .r_paren => {
2407 try ais.writer().writeAll(" }");
2400 ais.popIndent();2408 ais.popIndent();
2401 return renderToken(r, tok_i, space);2409 return renderToken(r, tok_i, space);
2402 },2410 },
...@@ -2412,10 +2420,7 @@ fn renderAsm(...@@ -2412,10 +2420,7 @@ fn renderAsm(
2412 }2420 }
2413 }2421 }
2414 } else {2422 } else {
2415 // asm ("foo")2423 unreachable;
2416 try renderExpression(r, asm_node.ast.template, .none);
2417 ais.popIndent();
2418 return renderToken(r, asm_node.ast.rparen, space); // rparen
2419 }2424 }
2420 }2425 }
24212426
...@@ -2499,13 +2504,18 @@ fn renderAsm(...@@ -2499,13 +2504,18 @@ fn renderAsm(
2499 };2504 };
25002505
2501 try renderToken(r, colon3, .space); // :2506 try renderToken(r, colon3, .space); // :
2507 try ais.writer().writeAll(".{ ");
2502 const first_clobber = asm_node.first_clobber.?;2508 const first_clobber = asm_node.first_clobber.?;
2503 var tok_i = first_clobber;2509 var tok_i = first_clobber;
2504 while (true) {2510 while (true) {
2505 switch (tree.tokenTag(tok_i + 1)) {2511 switch (tree.tokenTag(tok_i + 1)) {
2506 .r_paren => {2512 .r_paren => {
2507 ais.setIndentDelta(indent_delta);2513 ais.setIndentDelta(indent_delta);
2508 try renderToken(r, tok_i, .newline);2514 try ais.writer().writeAll(".@");
2515 const lexeme = tokenSliceForRender(tree, tok_i);
2516 try ais.writer().writeAll(lexeme);
2517 try ais.writer().writeAll(" }");
2518 try renderSpace(r, tok_i, lexeme.len, .newline);
2509 ais.popIndent();2519 ais.popIndent();
2510 return renderToken(r, tok_i + 1, space);2520 return renderToken(r, tok_i + 1, space);
2511 },2521 },
...@@ -2513,12 +2523,17 @@ fn renderAsm(...@@ -2513,12 +2523,17 @@ fn renderAsm(
2513 switch (tree.tokenTag(tok_i + 2)) {2523 switch (tree.tokenTag(tok_i + 2)) {
2514 .r_paren => {2524 .r_paren => {
2515 ais.setIndentDelta(indent_delta);2525 ais.setIndentDelta(indent_delta);
2516 try renderToken(r, tok_i, .newline);2526 try ais.writer().writeAll(".@");
2527 const lexeme = tokenSliceForRender(tree, tok_i);
2528 try ais.writer().writeAll(lexeme);
2529 try ais.writer().writeAll(" }");
2530 try renderSpace(r, tok_i, lexeme.len, .newline);
2517 ais.popIndent();2531 ais.popIndent();
2518 return renderToken(r, tok_i + 2, space);2532 return renderToken(r, tok_i + 2, space);
2519 },2533 },
2520 else => {2534 else => {
2521 try renderToken(r, tok_i, .none);2535 try ais.writer().writeAll(".@");
2536 try ais.writer().writeAll(tokenSliceForRender(tree, tok_i));
2522 try renderToken(r, tok_i + 1, .space);2537 try renderToken(r, tok_i + 1, .space);
2523 tok_i += 2;2538 tok_i += 2;
2524 },2539 },
...@@ -2529,6 +2544,131 @@ fn renderAsm(...@@ -2529,6 +2544,131 @@ fn renderAsm(
2529 }2544 }
2530}2545}
25312546
2547fn renderAsm(
2548 r: *Render,
2549 asm_node: Ast.full.Asm,
2550 space: Space,
2551) Error!void {
2552 const tree = r.tree;
2553 const ais = r.ais;
2554
2555 try renderToken(r, asm_node.ast.asm_token, .space); // asm
2556
2557 if (asm_node.volatile_token) |volatile_token| {
2558 try renderToken(r, volatile_token, .space); // volatile
2559 try renderToken(r, volatile_token + 1, .none); // lparen
2560 } else {
2561 try renderToken(r, asm_node.ast.asm_token + 1, .none); // lparen
2562 }
2563
2564 if (asm_node.ast.items.len == 0) {
2565 try ais.forcePushIndent(.normal);
2566 if (asm_node.ast.clobbers.unwrap()) |clobbers| {
2567 // asm ("foo" ::: clobbers)
2568 try renderExpression(r, asm_node.ast.template, .space);
2569 // Render the three colons.
2570 const first_clobber = tree.firstToken(clobbers);
2571 try renderToken(r, first_clobber - 3, .none);
2572 try renderToken(r, first_clobber - 2, .none);
2573 try renderToken(r, first_clobber - 1, .space);
2574 try renderExpression(r, clobbers, .none);
2575 ais.popIndent();
2576 return renderToken(r, asm_node.ast.rparen, space); // rparen
2577 }
2578
2579 // asm ("foo")
2580 try renderExpression(r, asm_node.ast.template, .none);
2581 ais.popIndent();
2582 return renderToken(r, asm_node.ast.rparen, space); // rparen
2583 }
2584
2585 try ais.forcePushIndent(.normal);
2586 try renderExpression(r, asm_node.ast.template, .newline);
2587 ais.setIndentDelta(asm_indent_delta);
2588 const colon1 = tree.lastToken(asm_node.ast.template) + 1;
2589
2590 const colon2 = if (asm_node.outputs.len == 0) colon2: {
2591 try renderToken(r, colon1, .newline); // :
2592 break :colon2 colon1 + 1;
2593 } else colon2: {
2594 try renderToken(r, colon1, .space); // :
2595
2596 try ais.forcePushIndent(.normal);
2597 for (asm_node.outputs, 0..) |asm_output, i| {
2598 if (i + 1 < asm_node.outputs.len) {
2599 const next_asm_output = asm_node.outputs[i + 1];
2600 try renderAsmOutput(r, asm_output, .none);
2601
2602 const comma = tree.firstToken(next_asm_output) - 1;
2603 try renderToken(r, comma, .newline); // ,
2604 try renderExtraNewlineToken(r, tree.firstToken(next_asm_output));
2605 } else if (asm_node.inputs.len == 0 and asm_node.ast.clobbers == .none) {
2606 try ais.pushSpace(.comma);
2607 try renderAsmOutput(r, asm_output, .comma);
2608 ais.popSpace();
2609 ais.popIndent();
2610 ais.setIndentDelta(indent_delta);
2611 ais.popIndent();
2612 return renderToken(r, asm_node.ast.rparen, space); // rparen
2613 } else {
2614 try ais.pushSpace(.comma);
2615 try renderAsmOutput(r, asm_output, .comma);
2616 ais.popSpace();
2617 const comma_or_colon = tree.lastToken(asm_output) + 1;
2618 ais.popIndent();
2619 break :colon2 switch (tree.tokenTag(comma_or_colon)) {
2620 .comma => comma_or_colon + 1,
2621 else => comma_or_colon,
2622 };
2623 }
2624 } else unreachable;
2625 };
2626
2627 const colon3 = if (asm_node.inputs.len == 0) colon3: {
2628 try renderToken(r, colon2, .newline); // :
2629 break :colon3 colon2 + 1;
2630 } else colon3: {
2631 try renderToken(r, colon2, .space); // :
2632 try ais.forcePushIndent(.normal);
2633 for (asm_node.inputs, 0..) |asm_input, i| {
2634 if (i + 1 < asm_node.inputs.len) {
2635 const next_asm_input = asm_node.inputs[i + 1];
2636 try renderAsmInput(r, asm_input, .none);
2637
2638 const first_token = tree.firstToken(next_asm_input);
2639 try renderToken(r, first_token - 1, .newline); // ,
2640 try renderExtraNewlineToken(r, first_token);
2641 } else if (asm_node.ast.clobbers == .none) {
2642 try ais.pushSpace(.comma);
2643 try renderAsmInput(r, asm_input, .comma);
2644 ais.popSpace();
2645 ais.popIndent();
2646 ais.setIndentDelta(indent_delta);
2647 ais.popIndent();
2648 return renderToken(r, asm_node.ast.rparen, space); // rparen
2649 } else {
2650 try ais.pushSpace(.comma);
2651 try renderAsmInput(r, asm_input, .comma);
2652 ais.popSpace();
2653 const comma_or_colon = tree.lastToken(asm_input) + 1;
2654 ais.popIndent();
2655 break :colon3 switch (tree.tokenTag(comma_or_colon)) {
2656 .comma => comma_or_colon + 1,
2657 else => comma_or_colon,
2658 };
2659 }
2660 }
2661 unreachable;
2662 };
2663
2664 try renderToken(r, colon3, .space); // :
2665 const clobbers = asm_node.ast.clobbers.unwrap().?;
2666 try renderExpression(r, clobbers, .none);
2667 ais.setIndentDelta(indent_delta);
2668 ais.popIndent();
2669 return renderToken(r, asm_node.ast.rparen, space); // rparen
2670}
2671
2532fn renderCall(2672fn renderCall(
2533 r: *Render,2673 r: *Render,
2534 call: Ast.full.Call,2674 call: Ast.full.Call,
src/Air.zig+10-9
...@@ -1413,19 +1413,20 @@ pub const ShuffleTwoMask = enum(u32) {...@@ -1413,19 +1413,20 @@ pub const ShuffleTwoMask = enum(u32) {
1413/// terminated string.1413/// terminated string.
1414/// - name: memory at this position is reinterpreted as a null1414/// - name: memory at this position is reinterpreted as a null
1415/// terminated string. pad to the next u32 after the null byte.1415/// terminated string. pad to the next u32 after the null byte.
1416/// 4. for every clobbers_len1416/// 4. A number of u32 elements follow according to the equation `(source_len + 3) / 4`.
1417/// - clobber_name: memory at this position is reinterpreted as a null
1418/// terminated string. pad to the next u32 after the null byte.
1419/// 5. A number of u32 elements follow according to the equation `(source_len + 3) / 4`.
1420/// Memory starting at this position is reinterpreted as the source bytes.1417/// Memory starting at this position is reinterpreted as the source bytes.
1421pub const Asm = struct {1418pub const Asm = struct {
1422 /// Length of the assembly source in bytes.1419 /// Length of the assembly source in bytes.
1423 source_len: u32,1420 source_len: u32,
1424 outputs_len: u32,
1425 inputs_len: u32,1421 inputs_len: u32,
1426 /// The MSB is `is_volatile`.1422 /// A comptime `std.builtin.assembly.Clobbers` value for the target architecture.
1427 /// The rest of the bits are `clobbers_len`.1423 clobbers: InternPool.Index,
1428 flags: u32,1424 flags: Flags,
1425
1426 pub const Flags = packed struct(u32) {
1427 outputs_len: u31,
1428 is_volatile: bool,
1429 };
1429};1430};
14301431
1431pub const Cmpxchg = struct {1432pub const Cmpxchg = struct {
...@@ -1749,7 +1750,7 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end...@@ -1749,7 +1750,7 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end
1749 @field(result, field.name) = switch (field.type) {1750 @field(result, field.name) = switch (field.type) {
1750 u32 => air.extra.items[i],1751 u32 => air.extra.items[i],
1751 InternPool.Index, Inst.Ref => @enumFromInt(air.extra.items[i]),1752 InternPool.Index, Inst.Ref => @enumFromInt(air.extra.items[i]),
1752 i32, CondBr.BranchHints => @bitCast(air.extra.items[i]),1753 i32, CondBr.BranchHints, Asm.Flags => @bitCast(air.extra.items[i]),
1753 else => @compileError("bad field type: " ++ @typeName(field.type)),1754 else => @compileError("bad field type: " ++ @typeName(field.type)),
1754 };1755 };
1755 i += 1;1756 i += 1;
src/Air/Liveness.zig+2-1
...@@ -1208,8 +1208,9 @@ fn analyzeInst(...@@ -1208,8 +1208,9 @@ fn analyzeInst(
12081208
1209 .assembly => {1209 .assembly => {
1210 const extra = a.air.extraData(Air.Asm, inst_datas[@intFromEnum(inst)].ty_pl.payload);1210 const extra = a.air.extraData(Air.Asm, inst_datas[@intFromEnum(inst)].ty_pl.payload);
1211 const outputs_len = extra.data.flags.outputs_len;
1211 var extra_i: usize = extra.end;1212 var extra_i: usize = extra.end;
1212 const outputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..extra.data.outputs_len]));1213 const outputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..outputs_len]));
1213 extra_i += outputs.len;1214 extra_i += outputs.len;
1214 const inputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..extra.data.inputs_len]));1215 const inputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..extra.data.inputs_len]));
1215 extra_i += inputs.len;1216 extra_i += inputs.len;
src/Air/Liveness/Verify.zig+3-8
...@@ -366,16 +366,11 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -366,16 +366,11 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
366 .assembly => {366 .assembly => {
367 const ty_pl = data[@intFromEnum(inst)].ty_pl;367 const ty_pl = data[@intFromEnum(inst)].ty_pl;
368 const extra = self.air.extraData(Air.Asm, ty_pl.payload);368 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
369 const outputs_len = extra.data.flags.outputs_len;
369 var extra_i = extra.end;370 var extra_i = extra.end;
370 const outputs = @as(371 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
371 []const Air.Inst.Ref,
372 @ptrCast(self.air.extra.items[extra_i..][0..extra.data.outputs_len]),
373 );
374 extra_i += outputs.len;372 extra_i += outputs.len;
375 const inputs = @as(373 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
376 []const Air.Inst.Ref,
377 @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]),
378 );
379 extra_i += inputs.len;374 extra_i += inputs.len;
380375
381 var bt = self.liveness.iterateBigTomb(inst);376 var bt = self.liveness.iterateBigTomb(inst);
src/Air/print.zig+35-18
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
34
4const build_options = @import("build_options");5const build_options = @import("build_options");
5const Zcu = @import("../Zcu.zig");6const Zcu = @import("../Zcu.zig");
...@@ -9,7 +10,7 @@ const Air = @import("../Air.zig");...@@ -9,7 +10,7 @@ const Air = @import("../Air.zig");
9const InternPool = @import("../InternPool.zig");10const InternPool = @import("../InternPool.zig");
1011
11pub fn write(air: Air, stream: *std.io.Writer, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {12pub fn write(air: Air, stream: *std.io.Writer, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
12 comptime std.debug.assert(build_options.enable_debug_extensions);13 comptime assert(build_options.enable_debug_extensions);
13 const instruction_bytes = air.instructions.len *14 const instruction_bytes = air.instructions.len *
14 // Here we don't use @sizeOf(Air.Inst.Data) because it would include15 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
15 // the debug safety tag but we want to measure release size.16 // the debug safety tag but we want to measure release size.
...@@ -59,7 +60,7 @@ pub fn writeInst(...@@ -59,7 +60,7 @@ pub fn writeInst(
59 pt: Zcu.PerThread,60 pt: Zcu.PerThread,
60 liveness: ?Air.Liveness,61 liveness: ?Air.Liveness,
61) void {62) void {
62 comptime std.debug.assert(build_options.enable_debug_extensions);63 comptime assert(build_options.enable_debug_extensions);
63 var writer: Writer = .{64 var writer: Writer = .{
64 .pt = pt,65 .pt = pt,
65 .gpa = pt.zcu.gpa,66 .gpa = pt.zcu.gpa,
...@@ -643,8 +644,8 @@ const Writer = struct {...@@ -643,8 +644,8 @@ const Writer = struct {
643 fn writeAssembly(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {644 fn writeAssembly(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
644 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;645 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
645 const extra = w.air.extraData(Air.Asm, ty_pl.payload);646 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
646 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;647 const is_volatile = extra.data.flags.is_volatile;
647 const clobbers_len = @as(u31, @truncate(extra.data.flags));648 const outputs_len = extra.data.flags.outputs_len;
648 var extra_i: usize = extra.end;649 var extra_i: usize = extra.end;
649 var op_index: usize = 0;650 var op_index: usize = 0;
650651
...@@ -655,7 +656,7 @@ const Writer = struct {...@@ -655,7 +656,7 @@ const Writer = struct {
655 try s.writeAll(", volatile");656 try s.writeAll(", volatile");
656 }657 }
657658
658 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.outputs_len]));659 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..outputs_len]));
659 extra_i += outputs.len;660 extra_i += outputs.len;
660 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));661 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));
661 extra_i += inputs.len;662 extra_i += inputs.len;
...@@ -695,19 +696,35 @@ const Writer = struct {...@@ -695,19 +696,35 @@ const Writer = struct {
695 try s.writeByte(')');696 try s.writeByte(')');
696 }697 }
697698
698 {699 const zcu = w.pt.zcu;
699 var clobber_i: u32 = 0;700 const ip = &zcu.intern_pool;
700 while (clobber_i < clobbers_len) : (clobber_i += 1) {701 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
701 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);702 const struct_type: Type = .fromInterned(aggregate.ty);
702 const clobber = std.mem.sliceTo(extra_bytes, 0);703 switch (aggregate.storage) {
703 // This equation accounts for the fact that even if we have exactly 4 bytes704 .elems => |elems| for (elems, 0..) |elem, i| {
704 // for the string, we still use the next u32 for the null terminator.705 switch (elem) {
705 extra_i += clobber.len / 4 + 1;706 .bool_true => {
706707 const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
707 try s.writeAll(", ~{");708 assert(clobber.len != 0);
708 try s.writeAll(clobber);709 try s.writeAll(", ~{");
709 try s.writeAll("}");710 try s.writeAll(clobber);
710 }711 try s.writeAll("}");
712 },
713 .bool_false => continue,
714 else => unreachable,
715 }
716 },
717 .repeated_elem => |elem| {
718 try s.writeAll(", ");
719 try s.writeAll(switch (elem) {
720 .bool_true => "<all clobbers>",
721 .bool_false => "<no clobbers>",
722 else => unreachable,
723 });
724 },
725 .bytes => |bytes| {
726 try s.print(", {x}", .{bytes});
727 },
711 }728 }
712 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];729 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
713 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});730 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
src/Air/types_resolved.zig+3-2
...@@ -416,8 +416,9 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {...@@ -416,8 +416,9 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
416 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;416 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
417 // Luckily, we only care about the inputs and outputs, so we don't have to do417 // Luckily, we only care about the inputs and outputs, so we don't have to do
418 // the whole null-terminated string dance.418 // the whole null-terminated string dance.
419 const outputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.outputs_len]);419 const outputs_len = extra.data.flags.outputs_len;
420 const inputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end + extra.data.outputs_len ..][0..extra.data.inputs_len]);420 const outputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..outputs_len]);
421 const inputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end + outputs_len ..][0..extra.data.inputs_len]);
421 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;422 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;
422 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;423 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
423 },424 },
src/InternPool.zig+6
...@@ -54,6 +54,7 @@ namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.In...@@ -54,6 +54,7 @@ namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.In
54memoized_state_main_deps: DepEntry.Index.Optional,54memoized_state_main_deps: DepEntry.Index.Optional,
55memoized_state_panic_deps: DepEntry.Index.Optional,55memoized_state_panic_deps: DepEntry.Index.Optional,
56memoized_state_va_list_deps: DepEntry.Index.Optional,56memoized_state_va_list_deps: DepEntry.Index.Optional,
57memoized_state_assembly_deps: DepEntry.Index.Optional,
5758
58/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`59/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
59/// matches. The `next_dependee` field can be used to iterate all such entries60/// matches. The `next_dependee` field can be used to iterate all such entries
...@@ -96,6 +97,7 @@ pub const empty: InternPool = .{...@@ -96,6 +97,7 @@ pub const empty: InternPool = .{
96 .memoized_state_main_deps = .none,97 .memoized_state_main_deps = .none,
97 .memoized_state_panic_deps = .none,98 .memoized_state_panic_deps = .none,
98 .memoized_state_va_list_deps = .none,99 .memoized_state_va_list_deps = .none,
100 .memoized_state_assembly_deps = .none,
99 .first_dependency = .empty,101 .first_dependency = .empty,
100 .dep_entries = .empty,102 .dep_entries = .empty,
101 .free_dep_entries = .empty,103 .free_dep_entries = .empty,
...@@ -458,6 +460,8 @@ pub const MemoizedStateStage = enum(u32) {...@@ -458,6 +460,8 @@ pub const MemoizedStateStage = enum(u32) {
458 panic,460 panic,
459 /// Specifically `std.builtin.VaList`. See `Zcu.BuiltinDecl.stage`.461 /// Specifically `std.builtin.VaList`. See `Zcu.BuiltinDecl.stage`.
460 va_list,462 va_list,
463 /// Everything within `std.builtin.assembly`. See `Zcu.BuiltinDecl.stage`.
464 assembly,
461};465};
462466
463pub const ComptimeUnit = extern struct {467pub const ComptimeUnit = extern struct {
...@@ -880,6 +884,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI...@@ -880,6 +884,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
880 .main => ip.memoized_state_main_deps.unwrap(),884 .main => ip.memoized_state_main_deps.unwrap(),
881 .panic => ip.memoized_state_panic_deps.unwrap(),885 .panic => ip.memoized_state_panic_deps.unwrap(),
882 .va_list => ip.memoized_state_va_list_deps.unwrap(),886 .va_list => ip.memoized_state_va_list_deps.unwrap(),
887 .assembly => ip.memoized_state_assembly_deps.unwrap(),
883 },888 },
884 } orelse return .{889 } orelse return .{
885 .ip = ip,890 .ip = ip,
...@@ -915,6 +920,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -915,6 +920,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
915 .main => &ip.memoized_state_main_deps,920 .main => &ip.memoized_state_main_deps,
916 .panic => &ip.memoized_state_panic_deps,921 .panic => &ip.memoized_state_panic_deps,
917 .va_list => &ip.memoized_state_va_list_deps,922 .va_list => &ip.memoized_state_va_list_deps,
923 .assembly => &ip.memoized_state_assembly_deps,
918 };924 };
919925
920 if (deps.unwrap()) |first| {926 if (deps.unwrap()) |first| {
src/Sema.zig+17-23
...@@ -16413,10 +16413,10 @@ fn zirAsm(...@@ -16413,10 +16413,10 @@ fn zirAsm(
16413 const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);16413 const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
16414 const src = block.nodeOffset(extra.data.src_node);16414 const src = block.nodeOffset(extra.data.src_node);
16415 const ret_ty_src = block.src(.{ .node_offset_asm_ret_ty = extra.data.src_node });16415 const ret_ty_src = block.src(.{ .node_offset_asm_ret_ty = extra.data.src_node });
16416 const outputs_len: u4 = @truncate(extended.small);16416 const small: Zir.Inst.Asm.Small = @bitCast(extended.small);
16417 const inputs_len: u5 = @truncate(extended.small >> 4);16417 const outputs_len = small.outputs_len;
16418 const clobbers_len: u6 = @truncate(extended.small >> 9);16418 const inputs_len = small.inputs_len;
16419 const is_volatile = @as(u1, @truncate(extended.small >> 15)) != 0;16419 const is_volatile = small.is_volatile;
16420 const is_global_assembly = sema.func_index == .none;16420 const is_global_assembly = sema.func_index == .none;
16421 const zir_tags = sema.code.instructions.items(.tag);16421 const zir_tags = sema.code.instructions.items(.tag);
1642216422
...@@ -16432,7 +16432,7 @@ fn zirAsm(...@@ -16432,7 +16432,7 @@ fn zirAsm(
16432 if (inputs_len != 0) {16432 if (inputs_len != 0) {
16433 return sema.fail(block, src, "module-level assembly does not support inputs", .{});16433 return sema.fail(block, src, "module-level assembly does not support inputs", .{});
16434 }16434 }
16435 if (clobbers_len != 0) {16435 if (extra.data.clobbers != .none) {
16436 return sema.fail(block, src, "module-level assembly does not support clobbers", .{});16436 return sema.fail(block, src, "module-level assembly does not support clobbers", .{});
16437 }16437 }
16438 if (is_volatile) {16438 if (is_volatile) {
...@@ -16506,15 +16506,11 @@ fn zirAsm(...@@ -16506,15 +16506,11 @@ fn zirAsm(
16506 inputs[arg_i] = .{ .c = constraint, .n = name };16506 inputs[arg_i] = .{ .c = constraint, .n = name };
16507 }16507 }
1650816508
16509 const clobbers = try sema.arena.alloc([]const u8, clobbers_len);16509 const clobbers = if (extra.data.clobbers == .none) empty: {
16510 for (clobbers) |*name| {16510 const clobbers_ty = try sema.getBuiltinType(src, .@"assembly.Clobbers");
16511 const name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_i]);16511 break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);
16512 name.* = sema.code.nullTerminatedString(name_index);16512 } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
16513 extra_i += 1;16513 const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });
16514
16515 needed_capacity += name.*.len / 4 + 1;
16516 }
16517
16518 needed_capacity += (asm_source.len + 3) / 4;16514 needed_capacity += (asm_source.len + 3) / 4;
1651916515
16520 const gpa = sema.gpa;16516 const gpa = sema.gpa;
...@@ -16525,9 +16521,12 @@ fn zirAsm(...@@ -16525,9 +16521,12 @@ fn zirAsm(
16525 .ty = expr_ty,16521 .ty = expr_ty,
16526 .payload = sema.addExtraAssumeCapacity(Air.Asm{16522 .payload = sema.addExtraAssumeCapacity(Air.Asm{
16527 .source_len = @intCast(asm_source.len),16523 .source_len = @intCast(asm_source.len),
16528 .outputs_len = outputs_len,
16529 .inputs_len = @intCast(args.len),16524 .inputs_len = @intCast(args.len),
16530 .flags = (@as(u32, @intFromBool(is_volatile)) << 31) | @as(u32, @intCast(clobbers.len)),16525 .clobbers = clobbers_val.toIntern(),
16526 .flags = .{
16527 .is_volatile = is_volatile,
16528 .outputs_len = outputs_len,
16529 },
16531 }),16530 }),
16532 } },16531 } },
16533 });16532 });
...@@ -16549,12 +16548,6 @@ fn zirAsm(...@@ -16549,12 +16548,6 @@ fn zirAsm(
16549 buffer[input.c.len + 1 + input.n.len] = 0;16548 buffer[input.c.len + 1 + input.n.len] = 0;
16550 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;16549 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
16551 }16550 }
16552 for (clobbers) |clobber| {
16553 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
16554 @memcpy(buffer[0..clobber.len], clobber);
16555 buffer[clobber.len] = 0;
16556 sema.air_extra.items.len += clobber.len / 4 + 1;
16557 }
16558 {16551 {
16559 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());16552 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
16560 @memcpy(buffer[0..asm_source.len], asm_source);16553 @memcpy(buffer[0..asm_source.len], asm_source);
...@@ -26197,6 +26190,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD...@@ -26197,6 +26190,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
26197 .extern_options => try sema.getBuiltinType(src, .ExternOptions),26190 .extern_options => try sema.getBuiltinType(src, .ExternOptions),
26198 .type_info => try sema.getBuiltinType(src, .Type),26191 .type_info => try sema.getBuiltinType(src, .Type),
26199 .branch_hint => try sema.getBuiltinType(src, .BranchHint),26192 .branch_hint => try sema.getBuiltinType(src, .BranchHint),
26193 .clobbers => try sema.getBuiltinType(src, .@"assembly.Clobbers"),
26200 // zig fmt: on26194 // zig fmt: on
2620126195
26202 // Values are handled here.26196 // Values are handled here.
...@@ -36546,7 +36540,7 @@ fn payloadToExtraItems(data: anytype) [@typeInfo(@TypeOf(data)).@"struct".fields...@@ -36546,7 +36540,7 @@ fn payloadToExtraItems(data: anytype) [@typeInfo(@TypeOf(data)).@"struct".fields
36546 inline for (&result, fields) |*val, field| {36540 inline for (&result, fields) |*val, field| {
36547 val.* = switch (field.type) {36541 val.* = switch (field.type) {
36548 u32 => @field(data, field.name),36542 u32 => @field(data, field.name),
36549 i32, Air.CondBr.BranchHints => @bitCast(@field(data, field.name)),36543 i32, Air.CondBr.BranchHints, Air.Asm.Flags => @bitCast(@field(data, field.name)),
36550 Air.Inst.Ref, InternPool.Index => @intFromEnum(@field(data, field.name)),36544 Air.Inst.Ref, InternPool.Index => @intFromEnum(@field(data, field.name)),
36551 else => @compileError("bad field type: " ++ @typeName(field.type)),36545 else => @compileError("bad field type: " ++ @typeName(field.type)),
36552 };36546 };
src/Zcu.zig+19-7
...@@ -460,6 +460,9 @@ pub const BuiltinDecl = enum {...@@ -460,6 +460,9 @@ pub const BuiltinDecl = enum {
460460
461 VaList,461 VaList,
462462
463 assembly,
464 @"assembly.Clobbers",
465
463 /// Determines what kind of validation will be done to the decl's value.466 /// Determines what kind of validation will be done to the decl's value.
464 pub fn kind(decl: BuiltinDecl) enum { type, func, string } {467 pub fn kind(decl: BuiltinDecl) enum { type, func, string } {
465 return switch (decl) {468 return switch (decl) {
...@@ -480,6 +483,8 @@ pub const BuiltinDecl = enum {...@@ -480,6 +483,8 @@ pub const BuiltinDecl = enum {
480 .ExportOptions,483 .ExportOptions,
481 .ExternOptions,484 .ExternOptions,
482 .BranchHint,485 .BranchHint,
486 .assembly,
487 .@"assembly.Clobbers",
483 => .type,488 => .type,
484489
485 .Type,490 .Type,
...@@ -540,6 +545,7 @@ pub const BuiltinDecl = enum {...@@ -540,6 +545,7 @@ pub const BuiltinDecl = enum {
540 /// Resolution of these values is done in three distinct stages:545 /// Resolution of these values is done in three distinct stages:
541 /// * Resolution of `std.builtin.Panic` and everything under it546 /// * Resolution of `std.builtin.Panic` and everything under it
542 /// * Resolution of `VaList`547 /// * Resolution of `VaList`
548 /// * Resolution of `assembly`
543 /// * Everything else549 /// * Everything else
544 ///550 ///
545 /// Panics are separated because they are provided by the user, so must be able to use551 /// Panics are separated because they are provided by the user, so must be able to use
...@@ -548,14 +554,20 @@ pub const BuiltinDecl = enum {...@@ -548,14 +554,20 @@ pub const BuiltinDecl = enum {
548 /// `VaList` is separate because its value depends on the target, so it needs some reflection554 /// `VaList` is separate because its value depends on the target, so it needs some reflection
549 /// machinery to work; additionally, it is `@compileError` on some targets, so must be referenced555 /// machinery to work; additionally, it is `@compileError` on some targets, so must be referenced
550 /// by itself.556 /// by itself.
557 ///
558 /// `assembly` is separate because its value depends on the target.
551 pub fn stage(decl: BuiltinDecl) InternPool.MemoizedStateStage {559 pub fn stage(decl: BuiltinDecl) InternPool.MemoizedStateStage {
552 if (decl == .VaList) return .va_list;560 return switch (decl) {
553561 .VaList => .va_list,
554 if (@intFromEnum(decl) <= @intFromEnum(BuiltinDecl.@"Type.Declaration")) {562 .assembly, .@"assembly.Clobbers" => .assembly,
555 return .main;563 else => {
556 } else {564 if (@intFromEnum(decl) <= @intFromEnum(BuiltinDecl.@"Type.Declaration")) {
557 return .panic;565 return .main;
558 }566 } else {
567 return .panic;
568 }
569 },
570 };
559 }571 }
560572
561 /// Based on the tag name, determines how to access this decl; either as a direct child of the573 /// Based on the tag name, determines how to access this decl; either as a direct child of the
src/Zcu/PerThread.zig+1
...@@ -635,6 +635,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized...@@ -635,6 +635,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
635 .main => .Type,635 .main => .Type,
636 .panic => .panic,636 .panic => .panic,
637 .va_list => .VaList,637 .va_list => .VaList,
638 .assembly => .assembly,
638 };639 };
639 if (zcu.builtin_decl_values.get(to_check) != .none) return;640 if (zcu.builtin_decl_values.get(to_check) != .none) return;
640 }641 }
src/arch/riscv64/CodeGen.zig+28-16
...@@ -6047,10 +6047,10 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {...@@ -6047,10 +6047,10 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
6047fn airAsm(func: *Func, inst: Air.Inst.Index) !void {6047fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6048 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6048 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6049 const extra = func.air.extraData(Air.Asm, ty_pl.payload);6049 const extra = func.air.extraData(Air.Asm, ty_pl.payload);
6050 const clobbers_len: u31 = @truncate(extra.data.flags);6050 const outputs_len = extra.data.flags.outputs_len;
6051 var extra_i: usize = extra.end;6051 var extra_i: usize = extra.end;
6052 const outputs: []const Air.Inst.Ref =6052 const outputs: []const Air.Inst.Ref =
6053 @ptrCast(func.air.extra.items[extra_i..][0..extra.data.outputs_len]);6053 @ptrCast(func.air.extra.items[extra_i..][0..outputs_len]);
6054 extra_i += outputs.len;6054 extra_i += outputs.len;
6055 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra.items[extra_i..][0..extra.data.inputs_len]);6055 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra.items[extra_i..][0..extra.data.inputs_len]);
6056 extra_i += inputs.len;6056 extra_i += inputs.len;
...@@ -6161,21 +6161,33 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6161,21 +6161,33 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6161 args.appendAssumeCapacity(arg_mcv);6161 args.appendAssumeCapacity(arg_mcv);
6162 }6162 }
61636163
6164 {6164 const zcu = func.pt.zcu;
6165 var clobber_i: u32 = 0;6165 const ip = &zcu.intern_pool;
6166 while (clobber_i < clobbers_len) : (clobber_i += 1) {6166 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
6167 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra.items[extra_i..]), 0);6167 const struct_type: Type = .fromInterned(aggregate.ty);
6168 // This equation accounts for the fact that even if we have exactly 4 bytes6168 switch (aggregate.storage) {
6169 // for the string, we still use the next u32 for the null terminator.6169 .elems => |elems| for (elems, 0..) |elem, i| {
6170 extra_i += clobber.len / 4 + 1;6170 switch (elem) {
61716171 .bool_true => {
6172 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {6172 const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
6173 // nothing really to do6173 assert(clobber.len != 0);
6174 } else {6174 if (std.mem.eql(u8, clobber, "memory")) {
6175 try func.register_manager.getReg(parseRegName(clobber) orelse6175 // nothing really to do
6176 return func.fail("invalid clobber: '{s}'", .{clobber}), null);6176 } else {
6177 try func.register_manager.getReg(parseRegName(clobber) orelse
6178 return func.fail("invalid clobber: '{s}'", .{clobber}), null);
6179 }
6180 },
6181 .bool_false => continue,
6182 else => unreachable,
6177 }6183 }
6178 }6184 },
6185 .repeated_elem => |elem| switch (elem) {
6186 .bool_true => @panic("TODO"),
6187 .bool_false => {},
6188 else => unreachable,
6189 },
6190 .bytes => @panic("TODO"),
6179 }6191 }
61806192
6181 const Label = struct {6193 const Label = struct {
src/arch/sparc64/CodeGen.zig+5-14
...@@ -873,10 +873,10 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -873,10 +873,10 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
873fn airAsm(self: *Self, inst: Air.Inst.Index) !void {873fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
874 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;874 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
875 const extra = self.air.extraData(Air.Asm, ty_pl.payload);875 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
876 const is_volatile = (extra.data.flags & 0x80000000) != 0;876 const is_volatile = extra.data.flags.is_volatile;
877 const clobbers_len: u31 = @truncate(extra.data.flags);877 const outputs_len = extra.data.flags.outputs_len;
878 var extra_i: usize = extra.end;878 var extra_i: usize = extra.end;
879 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + extra.data.outputs_len]);879 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + outputs_len]);
880 extra_i += outputs.len;880 extra_i += outputs.len;
881 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + extra.data.inputs_len]);881 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + extra.data.inputs_len]);
882 extra_i += inputs.len;882 extra_i += inputs.len;
...@@ -921,17 +921,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -921,17 +921,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
921 try self.genSetReg(self.typeOf(input), reg, arg_mcv);921 try self.genSetReg(self.typeOf(input), reg, arg_mcv);
922 }922 }
923923
924 {924 // TODO honor the clobbers
925 var clobber_i: u32 = 0;925 _ = extra.data.clobbers;
926 while (clobber_i < clobbers_len) : (clobber_i += 1) {
927 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);
928 // This equation accounts for the fact that even if we have exactly 4 bytes
929 // for the string, we still use the next u32 for the null terminator.
930 extra_i += clobber.len / 4 + 1;
931
932 // TODO honor these
933 }
934 }
935926
936 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];927 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];
937928
src/arch/x86_64/CodeGen.zig+38-26
...@@ -179788,9 +179788,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -179788,9 +179788,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
179788 const zcu = pt.zcu;179788 const zcu = pt.zcu;
179789 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;179789 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
179790 const extra = self.air.extraData(Air.Asm, ty_pl.payload);179790 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
179791 const clobbers_len: u31 = @truncate(extra.data.flags);179791 const outputs_len = extra.data.flags.outputs_len;
179792 var extra_i: usize = extra.end;179792 var extra_i: usize = extra.end;
179793 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.outputs_len]);179793 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
179794 extra_i += outputs.len;179794 extra_i += outputs.len;
179795 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);179795 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
179796 extra_i += inputs.len;179796 extra_i += inputs.len;
...@@ -179981,30 +179981,42 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -179981,30 +179981,42 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
179981 args.appendAssumeCapacity(arg_mcv);179981 args.appendAssumeCapacity(arg_mcv);
179982 }179982 }
179983179983
179984 {179984 const ip = &zcu.intern_pool;
179985 var clobber_i: u32 = 0;179985 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
179986 while (clobber_i < clobbers_len) : (clobber_i += 1) {179986 const struct_type: Type = .fromInterned(aggregate.ty);
179987 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);179987 switch (aggregate.storage) {
179988 // This equation accounts for the fact that even if we have exactly 4 bytes179988 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
179989 // for the string, we still use the next u32 for the null terminator.179989 .bool_true => {
179990 extra_i += clobber.len / 4 + 1;179990 const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
179991179991 assert(clobber.len != 0);
179992 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory") or179992
179993 std.mem.eql(u8, clobber, "fpsr") or std.mem.eql(u8, clobber, "fpcr") or179993 if (std.mem.eql(u8, clobber, "memory") or
179994 std.mem.eql(u8, clobber, "mxcsr") or std.mem.eql(u8, clobber, "dirflag"))179994 std.mem.eql(u8, clobber, "fpsr") or
179995 {179995 std.mem.eql(u8, clobber, "fpcr") or
179996 // ok, sure179996 std.mem.eql(u8, clobber, "mxcsr") or
179997 } else if (std.mem.eql(u8, clobber, "cc") or179997 std.mem.eql(u8, clobber, "dirflag"))
179998 std.mem.eql(u8, clobber, "flags") or179998 {
179999 std.mem.eql(u8, clobber, "eflags") or179999 // ok, sure
180000 std.mem.eql(u8, clobber, "rflags"))180000 } else if (std.mem.eql(u8, clobber, "cc") or
180001 {180001 std.mem.eql(u8, clobber, "flags") or
180002 try self.spillEflagsIfOccupied();180002 std.mem.eql(u8, clobber, "eflags") or
180003 } else {180003 std.mem.eql(u8, clobber, "rflags"))
180004 try self.register_manager.getReg(parseRegName(clobber) orelse180004 {
180005 return self.fail("invalid clobber: '{s}'", .{clobber}), null);180005 try self.spillEflagsIfOccupied();
180006 }180006 } else {
180007 }180007 try self.register_manager.getReg(parseRegName(clobber) orelse
180008 return self.fail("invalid clobber: '{s}'", .{clobber}), null);
180009 }
180010 },
180011 .bool_false => continue,
180012 else => unreachable,
180013 },
180014 .repeated_elem => |elem| switch (elem) {
180015 .bool_true => @panic("TODO"),
180016 .bool_false => {},
180017 else => unreachable,
180018 },
180019 .bytes => @panic("TODO"),
180008 }180020 }
180009180021
180010 const Label = struct {180022 const Label = struct {
src/codegen/c.zig+24-19
...@@ -5545,11 +5545,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5545,11 +5545,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5545 const zcu = pt.zcu;5545 const zcu = pt.zcu;
5546 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5546 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5547 const extra = f.air.extraData(Air.Asm, ty_pl.payload);5547 const extra = f.air.extraData(Air.Asm, ty_pl.payload);
5548 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;5548 const is_volatile = extra.data.flags.is_volatile;
5549 const clobbers_len: u31 = @truncate(extra.data.flags);5549 const outputs_len = extra.data.flags.outputs_len;
5550 const gpa = f.object.dg.gpa;5550 const gpa = f.object.dg.gpa;
5551 var extra_i: usize = extra.end;5551 var extra_i: usize = extra.end;
5552 const outputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..extra.data.outputs_len]);5552 const outputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..outputs_len]);
5553 extra_i += outputs.len;5553 extra_i += outputs.len;
5554 const inputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..extra.data.inputs_len]);5554 const inputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..extra.data.inputs_len]);
5555 extra_i += inputs.len;5555 extra_i += inputs.len;
...@@ -5645,12 +5645,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5645,12 +5645,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5645 try f.object.newline();5645 try f.object.newline();
5646 }5646 }
5647 }5647 }
5648 for (0..clobbers_len) |_| {
5649 const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra.items[extra_i..]), 0);
5650 // This equation accounts for the fact that even if we have exactly 4 bytes
5651 // for the string, we still use the next u32 for the null terminator.
5652 extra_i += clobber.len / 4 + 1;
5653 }
56545648
5655 {5649 {
5656 const asm_source = mem.sliceAsBytes(f.air.extra.items[extra_i..])[0..extra.data.source_len];5650 const asm_source = mem.sliceAsBytes(f.air.extra.items[extra_i..])[0..extra.data.source_len];
...@@ -5757,17 +5751,28 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5757,17 +5751,28 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5757 try w.writeByte(')');5751 try w.writeByte(')');
5758 }5752 }
5759 try w.writeByte(':');5753 try w.writeByte(':');
5760 for (0..clobbers_len) |clobber_i| {5754 const ip = &zcu.intern_pool;
5761 const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra.items[extra_i..]), 0);5755 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
5762 // This equation accounts for the fact that even if we have exactly 4 bytes5756 const struct_type: Type = .fromInterned(aggregate.ty);
5763 // for the string, we still use the next u32 for the null terminator.5757 switch (aggregate.storage) {
5764 extra_i += clobber.len / 4 + 1;5758 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
57655759 .bool_true => {
5766 if (clobber.len == 0) continue;5760 const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
57675761 assert(name.len != 0);
5768 if (clobber_i > 0) try w.writeByte(',');5762 try w.print(" {f}", .{fmtStringLiteral(name, null)});
5769 try w.print(" {f}", .{fmtStringLiteral(clobber, null)});5763 (try w.writableArray(1))[0] = ',';
5764 },
5765 .bool_false => continue,
5766 else => unreachable,
5767 },
5768 .repeated_elem => |elem| switch (elem) {
5769 .bool_true => @panic("TODO"),
5770 .bool_false => {},
5771 else => unreachable,
5772 },
5773 .bytes => @panic("TODO"),
5770 }5774 }
5775 w.undo(1); // erase the last comma
5771 try w.writeAll(");");5776 try w.writeAll(");");
5772 try f.object.newline();5777 try f.object.newline();
57735778
src/codegen/llvm.zig+47-29
...@@ -7241,19 +7241,20 @@ pub const FuncGen = struct {...@@ -7241,19 +7241,20 @@ pub const FuncGen = struct {
7241 const o = self.ng.object;7241 const o = self.ng.object;
7242 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;7242 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
7243 const extra = self.air.extraData(Air.Asm, ty_pl.payload);7243 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
7244 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;7244 const is_volatile = extra.data.flags.is_volatile;
7245 const clobbers_len: u31 = @truncate(extra.data.flags);7245 const outputs_len = extra.data.flags.outputs_len;
7246 const gpa = self.gpa;
7246 var extra_i: usize = extra.end;7247 var extra_i: usize = extra.end;
72477248
7248 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.outputs_len]);7249 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
7249 extra_i += outputs.len;7250 extra_i += outputs.len;
7250 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);7251 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
7251 extra_i += inputs.len;7252 extra_i += inputs.len;
72527253
7253 var llvm_constraints: std.ArrayListUnmanaged(u8) = .empty;7254 var llvm_constraints: std.ArrayListUnmanaged(u8) = .empty;
7254 defer llvm_constraints.deinit(self.gpa);7255 defer llvm_constraints.deinit(gpa);
72557256
7256 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);7257 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
7257 defer arena_allocator.deinit();7258 defer arena_allocator.deinit();
7258 const arena = arena_allocator.allocator();7259 const arena = arena_allocator.allocator();
72597260
...@@ -7290,7 +7291,7 @@ pub const FuncGen = struct {...@@ -7290,7 +7291,7 @@ pub const FuncGen = struct {
7290 // for the string, we still use the next u32 for the null terminator.7291 // for the string, we still use the next u32 for the null terminator.
7291 extra_i += (constraint.len + name.len + (2 + 3)) / 4;7292 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
72927293
7293 try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 3);7294 try llvm_constraints.ensureUnusedCapacity(gpa, constraint.len + 3);
7294 if (total_i != 0) {7295 if (total_i != 0) {
7295 llvm_constraints.appendAssumeCapacity(',');7296 llvm_constraints.appendAssumeCapacity(',');
7296 }7297 }
...@@ -7399,7 +7400,7 @@ pub const FuncGen = struct {...@@ -7399,7 +7400,7 @@ pub const FuncGen = struct {
7399 }7400 }
7400 }7401 }
74017402
7402 try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1);7403 try llvm_constraints.ensureUnusedCapacity(gpa, constraint.len + 1);
7403 if (total_i != 0) {7404 if (total_i != 0) {
7404 llvm_constraints.appendAssumeCapacity(',');7405 llvm_constraints.appendAssumeCapacity(',');
7405 }7406 }
...@@ -7456,7 +7457,7 @@ pub const FuncGen = struct {...@@ -7456,7 +7457,7 @@ pub const FuncGen = struct {
7456 llvm_param_types[llvm_param_i] = llvm_elem_ty;7457 llvm_param_types[llvm_param_i] = llvm_elem_ty;
7457 }7458 }
74587459
7459 try llvm_constraints.print(self.gpa, ",{d}", .{output_index});7460 try llvm_constraints.print(gpa, ",{d}", .{output_index});
74607461
7461 // In the case of indirect inputs, LLVM requires the callsite to have7462 // In the case of indirect inputs, LLVM requires the callsite to have
7462 // an elementtype(<ty>) attribute.7463 // an elementtype(<ty>) attribute.
...@@ -7466,24 +7467,41 @@ pub const FuncGen = struct {...@@ -7466,24 +7467,41 @@ pub const FuncGen = struct {
7466 total_i += 1;7467 total_i += 1;
7467 }7468 }
74687469
7469 {7470 const ip = &zcu.intern_pool;
7470 var clobber_i: u32 = 0;7471 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
7471 while (clobber_i < clobbers_len) : (clobber_i += 1) {7472 const struct_type: Type = .fromInterned(aggregate.ty);
7472 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);7473 switch (aggregate.storage) {
7473 // This equation accounts for the fact that even if we have exactly 4 bytes7474 .elems => |elems| for (elems, 0..) |elem, i| {
7474 // for the string, we still use the next u32 for the null terminator.7475 switch (elem) {
7475 extra_i += clobber.len / 4 + 1;7476 .bool_true => {
74767477 const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
7477 try llvm_constraints.ensureUnusedCapacity(self.gpa, clobber.len + 4);7478 try llvm_constraints.ensureUnusedCapacity(gpa, name.len + 4);
7478 if (total_i != 0) {7479 if (total_i != 0) llvm_constraints.appendAssumeCapacity(',');
7479 llvm_constraints.appendAssumeCapacity(',');7480 llvm_constraints.appendSliceAssumeCapacity("~{");
7481 llvm_constraints.appendSliceAssumeCapacity(name);
7482 llvm_constraints.appendSliceAssumeCapacity("}");
7483
7484 total_i += 1;
7485 },
7486 .bool_false => continue,
7487 else => unreachable,
7480 }7488 }
7481 llvm_constraints.appendSliceAssumeCapacity("~{");7489 },
7482 llvm_constraints.appendSliceAssumeCapacity(clobber);7490 .repeated_elem => |elem| switch (elem) {
7483 llvm_constraints.appendSliceAssumeCapacity("}");7491 .bool_true => for (0..struct_type.structFieldCount(zcu)) |i| {
7492 const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
7493 try llvm_constraints.ensureUnusedCapacity(gpa, name.len + 4);
7494 if (total_i != 0) llvm_constraints.appendAssumeCapacity(',');
7495 llvm_constraints.appendSliceAssumeCapacity("~{");
7496 llvm_constraints.appendSliceAssumeCapacity(name);
7497 llvm_constraints.appendSliceAssumeCapacity("}");
74847498
7485 total_i += 1;7499 total_i += 1;
7486 }7500 },
7501 .bool_false => {},
7502 else => unreachable,
7503 },
7504 .bytes => @panic("TODO"),
7487 }7505 }
74887506
7489 // We have finished scanning through all inputs/outputs, so the number of7507 // We have finished scanning through all inputs/outputs, so the number of
...@@ -7497,13 +7515,13 @@ pub const FuncGen = struct {...@@ -7497,13 +7515,13 @@ pub const FuncGen = struct {
7497 // to be buggy and regress often.7515 // to be buggy and regress often.
7498 switch (target.cpu.arch) {7516 switch (target.cpu.arch) {
7499 .x86_64, .x86 => {7517 .x86_64, .x86 => {
7500 if (total_i != 0) try llvm_constraints.append(self.gpa, ',');7518 if (total_i != 0) try llvm_constraints.append(gpa, ',');
7501 try llvm_constraints.appendSlice(self.gpa, "~{dirflag},~{fpsr},~{flags}");7519 try llvm_constraints.appendSlice(gpa, "~{dirflag},~{fpsr},~{flags}");
7502 total_i += 3;7520 total_i += 3;
7503 },7521 },
7504 .mips, .mipsel, .mips64, .mips64el => {7522 .mips, .mipsel, .mips64, .mips64el => {
7505 if (total_i != 0) try llvm_constraints.append(self.gpa, ',');7523 if (total_i != 0) try llvm_constraints.append(gpa, ',');
7506 try llvm_constraints.appendSlice(self.gpa, "~{$1}");7524 try llvm_constraints.appendSlice(gpa, "~{$1}");
7507 total_i += 1;7525 total_i += 1;
7508 },7526 },
7509 else => {},7527 else => {},
...@@ -7512,7 +7530,7 @@ pub const FuncGen = struct {...@@ -7512,7 +7530,7 @@ pub const FuncGen = struct {
7512 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];7530 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];
75137531
7514 // hackety hacks until stage2 has proper inline asm in the frontend.7532 // hackety hacks until stage2 has proper inline asm in the frontend.
7515 var rendered_template = std.ArrayList(u8).init(self.gpa);7533 var rendered_template = std.ArrayList(u8).init(gpa);
7516 defer rendered_template.deinit();7534 defer rendered_template.deinit();
75177535
7518 const State = enum { start, percent, input, modifier };7536 const State = enum { start, percent, input, modifier };
src/codegen/spirv.zig+6-12
...@@ -6387,13 +6387,13 @@ const NavGen = struct {...@@ -6387,13 +6387,13 @@ const NavGen = struct {
6387 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6387 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6388 const extra = self.air.extraData(Air.Asm, ty_pl.payload);6388 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
63896389
6390 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;6390 const is_volatile = extra.data.flags.is_volatile;
6391 const clobbers_len: u31 = @truncate(extra.data.flags);6391 const outputs_len = extra.data.flags.outputs_len;
63926392
6393 if (!is_volatile and self.liveness.isUnused(inst)) return null;6393 if (!is_volatile and self.liveness.isUnused(inst)) return null;
63946394
6395 var extra_i: usize = extra.end;6395 var extra_i: usize = extra.end;
6396 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.outputs_len]);6396 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
6397 extra_i += outputs.len;6397 extra_i += outputs.len;
6398 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);6398 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
6399 extra_i += inputs.len;6399 extra_i += inputs.len;
...@@ -6402,7 +6402,7 @@ const NavGen = struct {...@@ -6402,7 +6402,7 @@ const NavGen = struct {
6402 return self.todo("implement inline asm with more than 1 output", .{});6402 return self.todo("implement inline asm with more than 1 output", .{});
6403 }6403 }
64046404
6405 var as = SpvAssembler{6405 var as: SpvAssembler = .{
6406 .gpa = self.gpa,6406 .gpa = self.gpa,
6407 .spv = self.spv,6407 .spv = self.spv,
6408 .func = &self.func,6408 .func = &self.func,
...@@ -6486,14 +6486,8 @@ const NavGen = struct {...@@ -6486,14 +6486,8 @@ const NavGen = struct {
6486 }6486 }
6487 }6487 }
64886488
6489 {6489 // TODO: do something with clobbers
6490 var clobber_i: u32 = 0;6490 _ = extra.data.clobbers;
6491 while (clobber_i < clobbers_len) : (clobber_i += 1) {
6492 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);
6493 extra_i += clobber.len / 4 + 1;
6494 // TODO: Record clobber and use it somewhere.
6495 }
6496 }
64976491
6498 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];6492 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];
64996493