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 @@
11//! Types and values provided by the Zig language.
22
33const builtin = @import("builtin");
4const std = @import("std.zig");
5const root = @import("root");
6
7pub const assembly = @import("builtin/assembly.zig");
48
59/// `explicit_subsystem` is missing when the subsystem is automatically detected,
610/// so Zig standard library has the subsystem detection logic here. This should generally be
......@@ -1100,6 +1104,3 @@ pub noinline fn returnError() void {
11001104 st.instruction_addresses[st.index] = @returnAddress();
11011105 st.index += 1;
11021106}
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) {
740740 generic_call_target,
741741 wasm_memory_index,
742742 work_group_dim_index,
743 clobber,
743744
744745 // Evaluating at comptime because types must be comptime-known.
745746 // Reasons other than `.type` are just more specific messages.
......@@ -820,6 +821,7 @@ pub const SimpleComptimeReason = enum(u32) {
820821 .generic_call_target => "generic function being called must be comptime-known",
821822 .wasm_memory_index => "wasm memory index must be comptime-known",
822823 .work_group_dim_index => "work group dimension index must be comptime-known",
824 .clobber => "clobber must be comptime-known",
823825
824826 .type => "types must be comptime-known",
825827 .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 {
634634 .@"nosuspend",
635635 .asm_simple,
636636 .@"asm",
637 .asm_legacy,
637638 .array_type,
638639 .array_type_sentinel,
639640 .error_value,
......@@ -1047,6 +1048,11 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
10471048 n = @enumFromInt(tree.extra_data[@intFromEnum(members.end) - 1]); // last parameter
10481049 }
10491050 },
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 },
10501056 .@"asm" => {
10511057 _, const extra_index = tree.nodeData(n).node_and_extra;
10521058 const extra = tree.extraData(extra_index, Node.Asm);
......@@ -1885,6 +1891,19 @@ pub fn asmSimple(tree: Ast, node: Node.Index) full.Asm {
18851891 .template = template,
18861892 .items = &.{},
18871893 .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,
18881907 });
18891908}
18901909
......@@ -1896,6 +1915,7 @@ pub fn asmFull(tree: Ast, node: Node.Index) full.Asm {
18961915 .asm_token = tree.nodeMainToken(node),
18971916 .template = template,
18981917 .items = items,
1918 .clobbers = extra.clobbers,
18991919 .rparen = extra.rparen,
19001920 });
19011921}
......@@ -2192,8 +2212,8 @@ fn fullSwitchCaseComponents(tree: Ast, info: full.SwitchCase.Components, node: N
21922212 return result;
21932213}
21942214
2195fn fullAsmComponents(tree: Ast, info: full.Asm.Components) full.Asm {
2196 var result: full.Asm = .{
2215fn legacyAsmComponents(tree: Ast, info: full.AsmLegacy.Components) full.AsmLegacy {
2216 var result: full.AsmLegacy = .{
21972217 .ast = info,
21982218 .volatile_token = null,
21992219 .inputs = &.{},
......@@ -2253,6 +2273,29 @@ fn fullAsmComponents(tree: Ast, info: full.Asm.Components) full.Asm {
22532273 return result;
22542274}
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
22562299fn fullWhileComponents(tree: Ast, info: full.While.Components) full.While {
22572300 var result: full.While = .{
22582301 .ast = info,
......@@ -2447,6 +2490,14 @@ pub fn fullAsm(tree: Ast, node: Node.Index) ?full.Asm {
24472490 };
24482491}
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
24502501pub fn fullCall(tree: Ast, buffer: *[1]Ast.Node.Index, node: Node.Index) ?full.Call {
24512502 return switch (tree.nodeTag(node)) {
24522503 .call, .call_comma => tree.callFull(node),
......@@ -2827,6 +2878,21 @@ pub const full = struct {
28272878 };
28282879
28292880 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 {
28302896 ast: Components,
28312897 volatile_token: ?TokenIndex,
28322898 first_clobber: ?TokenIndex,
......@@ -3833,15 +3899,22 @@ pub const Node = struct {
38333899 /// Same as `block` except there is known to be a trailing comma before
38343900 /// the final rbrace.
38353901 block_semicolon,
3836 /// `asm(lhs)`.
3902 /// `asm(a)`.
38373903 ///
3838 /// rhs is a `Token.Index` to the `)` token.
38393904 /// The `main_token` field is the `asm` token.
38403905 asm_simple,
38413906 /// `asm(lhs, a)`.
38423907 ///
38433908 /// The `data` field is a `.node_and_extra`:
38443909 /// 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.
38453918 /// 2. a `ExtraIndex` to `Asm`.
38463919 ///
38473920 /// The `main_token` field is the `asm` token.
......@@ -4014,9 +4087,18 @@ pub const Node = struct {
40144087 callconv_expr: OptionalIndex,
40154088 };
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
40174098 pub const Asm = struct {
40184099 items_start: ExtraIndex,
40194100 items_end: ExtraIndex,
4101 clobbers: OptionalIndex,
40204102 /// Needed to make lastToken() work.
40214103 rparen: TokenIndex,
40224104 };
lib/std/zig/AstGen.zig+27-41
......@@ -505,6 +505,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
505505 .bool_or,
506506 .@"asm",
507507 .asm_simple,
508 .asm_legacy,
508509 .string_literal,
509510 .number_literal,
510511 .call,
......@@ -811,6 +812,12 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
811812 .@"asm",
812813 => 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
814821 .string_literal => return stringLiteral(gz, ri, node),
815822 .multiline_string_literal => return multilineStringLiteral(gz, ri, node),
816823
......@@ -8774,7 +8781,7 @@ fn asmExpr(
87748781 if (is_container_asm) {
87758782 if (full.volatile_token) |t|
87768783 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)
87788785 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{});
87798786 } else {
87808787 if (full.outputs.len == 0 and full.volatile_token == null) {
......@@ -8839,32 +8846,12 @@ fn asmExpr(
88398846 };
88408847 }
88418848
8842 var clobbers_buffer: [63]u32 = undefined;
8843 var clobber_i: usize = 0;
8844 if (full.first_clobber) |first_clobber| clobbers: {
8845 // asm ("foo" ::: "a", "b")
8846 // asm ("foo" ::: "a", "b",)
8847 var tok_i = first_clobber;
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 }
8849 const clobbers: Zir.Inst.Ref = if (full.ast.clobbers.unwrap()) |clobbers_node|
8850 try comptimeExpr(gz, scope, .{ .rl = .{
8851 .coerced_ty = try gz.addBuiltinValue(clobbers_node, .clobbers),
8852 } }, clobbers_node, .clobber)
8853 else
8854 .none;
88688855
88698856 const result = try gz.addAsm(.{
88708857 .tag = tag_and_tmpl.tag,
......@@ -8874,7 +8861,7 @@ fn asmExpr(
88748861 .output_type_bits = output_type_bits,
88758862 .outputs = outputs,
88768863 .inputs = inputs,
8877 .clobbers = clobbers_buffer[0..clobber_i],
8864 .clobbers = clobbers,
88788865 });
88798866 return rvalue(gz, ri, result, node);
88808867}
......@@ -10332,6 +10319,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
1033210319
1033310320 .@"asm",
1033410321 .asm_simple,
10322 .asm_legacy,
1033510323 .identifier,
1033610324 .field_access,
1033710325 .deref,
......@@ -10575,6 +10563,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
1057510563 .tagged_union_enum_tag_trailing,
1057610564 .@"asm",
1057710565 .asm_simple,
10566 .asm_legacy,
1057810567 .add,
1057910568 .add_wrap,
1058010569 .add_sat,
......@@ -10813,6 +10802,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
1081310802 .tagged_union_enum_tag_trailing,
1081410803 .@"asm",
1081510804 .asm_simple,
10805 .asm_legacy,
1081610806 .add,
1081710807 .add_wrap,
1081810808 .add_sat,
......@@ -12806,7 +12796,7 @@ const GenZir = struct {
1280612796 is_volatile: bool,
1280712797 outputs: []const Zir.Inst.Asm.Output,
1280812798 inputs: []const Zir.Inst.Asm.Input,
12809 clobbers: []const u32,
12799 clobbers: Zir.Inst.Ref,
1281012800 },
1281112801 ) !Zir.Inst.Ref {
1281212802 const astgen = gz.astgen;
......@@ -12816,13 +12806,13 @@ const GenZir = struct {
1281612806 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
1281712807 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).@"struct".fields.len +
1281812808 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).@"struct".fields.len +
12819 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).@"struct".fields.len +
12820 args.clobbers.len);
12809 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).@"struct".fields.len);
1282112810
1282212811 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{
1282312812 .src_node = gz.nodeIndexToRelative(args.node),
1282412813 .asm_source = args.asm_source,
1282512814 .output_type_bits = args.output_type_bits,
12815 .clobbers = args.clobbers,
1282612816 });
1282712817 for (args.outputs) |output| {
1282812818 _ = gz.astgen.addExtraAssumeCapacity(output);
......@@ -12830,23 +12820,19 @@ const GenZir = struct {
1283012820 for (args.inputs) |input| {
1283112821 _ = gz.astgen.addExtraAssumeCapacity(input);
1283212822 }
12833 gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers);
1283412823
12835 // * 0b00000000_0000XXXX - `outputs_len`.
12836 // * 0b0000000X_XXXX0000 - `inputs_len`.
12837 // * 0b0XXXXXX0_00000000 - `clobbers_len`.
12838 // * 0bX0000000_00000000 - is volatile
12839 const small: u16 = @as(u16, @as(u4, @intCast(args.outputs.len))) << 0 |
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;
12824 const small: Zir.Inst.Asm.Small = .{
12825 .outputs_len = @intCast(args.outputs.len),
12826 .inputs_len = @intCast(args.inputs.len),
12827 .is_volatile = args.is_volatile,
12828 };
1284312829
1284412830 const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
1284512831 astgen.instructions.appendAssumeCapacity(.{
1284612832 .tag = .extended,
1284712833 .data = .{ .extended = .{
1284812834 .opcode = args.tag,
12849 .small = small,
12835 .small = @bitCast(small),
1285012836 .operand = payload_index,
1285112837 } },
1285212838 });
lib/std/zig/AstRlAnnotate.zig+1
......@@ -310,6 +310,7 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
310310 .unreachable_literal,
311311 .asm_simple,
312312 .@"asm",
313 .asm_legacy,
313314 .enum_literal,
314315 .error_value,
315316 .anyframe_literal,
lib/std/zig/Parse.zig+27-4
......@@ -2801,7 +2801,7 @@ fn expectSwitchSuffix(p: *Parse, main_token: TokenIndex) !Node.Index {
28012801///
28022802/// AsmInput <- COLON AsmInputList AsmClobbers?
28032803///
2804/// AsmClobbers <- COLON StringList
2804/// AsmClobbers <- COLON Expr
28052805///
28062806/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
28072807///
......@@ -2841,7 +2841,8 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
28412841 else => try p.warnExpected(.comma),
28422842 }
28432843 }
2844 if (p.eatToken(.colon)) |_| {
2844
2845 const clobbers: Node.OptionalIndex = if (p.eatToken(.colon)) |_| clobbers: {
28452846 while (true) {
28462847 const input_item = try p.parseAsmInputItem() orelse break;
28472848 try p.scratch.append(p.gpa, input_item);
......@@ -2853,7 +2854,11 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
28532854 else => try p.warnExpected(.comma),
28542855 }
28552856 }
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) {
28572862 while (p.eatToken(.string_literal)) |_| {
28582863 switch (p.tokenTag(p.tok_i)) {
28592864 .comma => p.tok_i += 1,
......@@ -2862,8 +2867,25 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
28622867 else => try p.warnExpected(.comma),
28632868 }
28642869 }
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 });
28652884 }
2866 }
2885
2886 break :clobbers (try p.expectExpr()).toOptional();
2887 } else .none;
2888
28672889 const rparen = try p.expectToken(.r_paren);
28682890 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
28692891 return p.addNode(.{
......@@ -2874,6 +2896,7 @@ fn expectAsmExpr(p: *Parse) !Node.Index {
28742896 try p.addExtra(Node.Asm{
28752897 .items_start = span.start,
28762898 .items_end = span.end,
2899 .clobbers = clobbers,
28772900 .rparen = rparen,
28782901 }),
28792902 } },
lib/std/zig/Zir.zig+8-6
......@@ -1939,11 +1939,6 @@ pub const Inst = struct {
19391939 /// `operand` is payload index to `BinNode`.
19401940 builtin_extern,
19411941 /// Inline assembly.
1942 /// `small`:
1943 /// * 0b00000000_000XXXXX - `outputs_len`.
1944 /// * 0b000000XX_XXX00000 - `inputs_len`.
1945 /// * 0b0XXXXX00_00000000 - `clobbers_len`.
1946 /// * 0bX0000000_00000000 - is volatile
19471942 /// `operand` is payload index to `Asm`.
19481943 @"asm",
19491944 /// Same as `asm` except the assembly template is not a string literal but a comptime
......@@ -2495,7 +2490,6 @@ pub const Inst = struct {
24952490 /// Trailing:
24962491 /// 0. Output for every outputs_len
24972492 /// 1. Input for every inputs_len
2498 /// 2. clobber: NullTerminatedString // index into string_bytes (null terminated) for every clobbers_len.
24992493 pub const Asm = struct {
25002494 src_node: Ast.Node.Offset,
25012495 // null-terminated string index
......@@ -2505,6 +2499,13 @@ pub const Inst = struct {
25052499 /// 0b1 - operand is a type; asm expression has the output as the result.
25062500 /// 0b0X is the first output, 0bX0 is the second, etc.
25072501 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
25092510 pub const Output = struct {
25102511 /// index into string_bytes (null terminated)
......@@ -3482,6 +3483,7 @@ pub const Inst = struct {
34823483 extern_options,
34833484 type_info,
34843485 branch_hint,
3486 clobbers,
34853487 // Values
34863488 calling_convention_c,
34873489 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
227227 => try zg.addErrorNode(node, "control flow is not allowed in ZON", .{}),
228228
229229 .@"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
232232 .builtin_call_two,
233233 .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 {
852852 .@"asm",
853853 => 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
855858 .enum_literal => {
856859 try renderToken(r, tree.nodeMainToken(node) - 1, .none); // .
857860 return renderIdentifier(r, tree.nodeMainToken(node), space, .eagerly_unquote); // name
......@@ -2363,9 +2366,9 @@ fn renderContainerDecl(
23632366 return renderToken(r, rbrace, space); // rbrace
23642367}
23652368
2366fn renderAsm(
2369fn renderAsmLegacy(
23672370 r: *Render,
2368 asm_node: Ast.full.Asm,
2371 asm_node: Ast.full.AsmLegacy,
23692372 space: Space,
23702373) Error!void {
23712374 const tree = r.tree;
......@@ -2391,12 +2394,17 @@ fn renderAsm(
23912394 try renderToken(r, first_clobber - 2, .none);
23922395 try renderToken(r, first_clobber - 1, .space);
23932396
2397 try ais.writer().writeAll(".{ ");
2398
23942399 var tok_i = first_clobber;
23952400 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
23972404 tok_i += 1;
23982405 switch (tree.tokenTag(tok_i)) {
23992406 .r_paren => {
2407 try ais.writer().writeAll(" }");
24002408 ais.popIndent();
24012409 return renderToken(r, tok_i, space);
24022410 },
......@@ -2412,10 +2420,7 @@ fn renderAsm(
24122420 }
24132421 }
24142422 } else {
2415 // asm ("foo")
2416 try renderExpression(r, asm_node.ast.template, .none);
2417 ais.popIndent();
2418 return renderToken(r, asm_node.ast.rparen, space); // rparen
2423 unreachable;
24192424 }
24202425 }
24212426
......@@ -2499,13 +2504,18 @@ fn renderAsm(
24992504 };
25002505
25012506 try renderToken(r, colon3, .space); // :
2507 try ais.writer().writeAll(".{ ");
25022508 const first_clobber = asm_node.first_clobber.?;
25032509 var tok_i = first_clobber;
25042510 while (true) {
25052511 switch (tree.tokenTag(tok_i + 1)) {
25062512 .r_paren => {
25072513 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);
25092519 ais.popIndent();
25102520 return renderToken(r, tok_i + 1, space);
25112521 },
......@@ -2513,12 +2523,17 @@ fn renderAsm(
25132523 switch (tree.tokenTag(tok_i + 2)) {
25142524 .r_paren => {
25152525 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);
25172531 ais.popIndent();
25182532 return renderToken(r, tok_i + 2, space);
25192533 },
25202534 else => {
2521 try renderToken(r, tok_i, .none);
2535 try ais.writer().writeAll(".@");
2536 try ais.writer().writeAll(tokenSliceForRender(tree, tok_i));
25222537 try renderToken(r, tok_i + 1, .space);
25232538 tok_i += 2;
25242539 },
......@@ -2529,6 +2544,131 @@ fn renderAsm(
25292544 }
25302545}
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
25322672fn renderCall(
25332673 r: *Render,
25342674 call: Ast.full.Call,
src/Air.zig+10-9
......@@ -1413,19 +1413,20 @@ pub const ShuffleTwoMask = enum(u32) {
14131413/// terminated string.
14141414/// - name: memory at this position is reinterpreted as a null
14151415/// terminated string. pad to the next u32 after the null byte.
1416/// 4. for every clobbers_len
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`.
1416/// 4. A number of u32 elements follow according to the equation `(source_len + 3) / 4`.
14201417/// Memory starting at this position is reinterpreted as the source bytes.
14211418pub const Asm = struct {
14221419 /// Length of the assembly source in bytes.
14231420 source_len: u32,
1424 outputs_len: u32,
14251421 inputs_len: u32,
1426 /// The MSB is `is_volatile`.
1427 /// The rest of the bits are `clobbers_len`.
1428 flags: u32,
1422 /// A comptime `std.builtin.assembly.Clobbers` value for the target architecture.
1423 clobbers: InternPool.Index,
1424 flags: Flags,
1425
1426 pub const Flags = packed struct(u32) {
1427 outputs_len: u31,
1428 is_volatile: bool,
1429 };
14291430};
14301431
14311432pub const Cmpxchg = struct {
......@@ -1749,7 +1750,7 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end
17491750 @field(result, field.name) = switch (field.type) {
17501751 u32 => air.extra.items[i],
17511752 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]),
17531754 else => @compileError("bad field type: " ++ @typeName(field.type)),
17541755 };
17551756 i += 1;
src/Air/Liveness.zig+2-1
......@@ -1208,8 +1208,9 @@ fn analyzeInst(
12081208
12091209 .assembly => {
12101210 const extra = a.air.extraData(Air.Asm, inst_datas[@intFromEnum(inst)].ty_pl.payload);
1211 const outputs_len = extra.data.flags.outputs_len;
12111212 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]));
12131214 extra_i += outputs.len;
12141215 const inputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..extra.data.inputs_len]));
12151216 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 {
366366 .assembly => {
367367 const ty_pl = data[@intFromEnum(inst)].ty_pl;
368368 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
369 const outputs_len = extra.data.flags.outputs_len;
369370 var extra_i = extra.end;
370 const outputs = @as(
371 []const Air.Inst.Ref,
372 @ptrCast(self.air.extra.items[extra_i..][0..extra.data.outputs_len]),
373 );
371 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
374372 extra_i += outputs.len;
375 const inputs = @as(
376 []const Air.Inst.Ref,
377 @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]),
378 );
373 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
379374 extra_i += inputs.len;
380375
381376 var bt = self.liveness.iterateBigTomb(inst);
src/Air/print.zig+35-18
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
34
45const build_options = @import("build_options");
56const Zcu = @import("../Zcu.zig");
......@@ -9,7 +10,7 @@ const Air = @import("../Air.zig");
910const InternPool = @import("../InternPool.zig");
1011
1112pub 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);
1314 const instruction_bytes = air.instructions.len *
1415 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
1516 // the debug safety tag but we want to measure release size.
......@@ -59,7 +60,7 @@ pub fn writeInst(
5960 pt: Zcu.PerThread,
6061 liveness: ?Air.Liveness,
6162) void {
62 comptime std.debug.assert(build_options.enable_debug_extensions);
63 comptime assert(build_options.enable_debug_extensions);
6364 var writer: Writer = .{
6465 .pt = pt,
6566 .gpa = pt.zcu.gpa,
......@@ -643,8 +644,8 @@ const Writer = struct {
643644 fn writeAssembly(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
644645 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
645646 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
646 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
647 const clobbers_len = @as(u31, @truncate(extra.data.flags));
647 const is_volatile = extra.data.flags.is_volatile;
648 const outputs_len = extra.data.flags.outputs_len;
648649 var extra_i: usize = extra.end;
649650 var op_index: usize = 0;
650651
......@@ -655,7 +656,7 @@ const Writer = struct {
655656 try s.writeAll(", volatile");
656657 }
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]));
659660 extra_i += outputs.len;
660661 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));
661662 extra_i += inputs.len;
......@@ -695,19 +696,35 @@ const Writer = struct {
695696 try s.writeByte(')');
696697 }
697698
698 {
699 var clobber_i: u32 = 0;
700 while (clobber_i < clobbers_len) : (clobber_i += 1) {
701 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
702 const clobber = std.mem.sliceTo(extra_bytes, 0);
703 // This equation accounts for the fact that even if we have exactly 4 bytes
704 // for the string, we still use the next u32 for the null terminator.
705 extra_i += clobber.len / 4 + 1;
706
707 try s.writeAll(", ~{");
708 try s.writeAll(clobber);
709 try s.writeAll("}");
710 }
699 const zcu = w.pt.zcu;
700 const ip = &zcu.intern_pool;
701 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
702 const struct_type: Type = .fromInterned(aggregate.ty);
703 switch (aggregate.storage) {
704 .elems => |elems| for (elems, 0..) |elem, i| {
705 switch (elem) {
706 .bool_true => {
707 const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
708 assert(clobber.len != 0);
709 try s.writeAll(", ~{");
710 try s.writeAll(clobber);
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 },
711728 }
712729 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
713730 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 {
416416 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
417417 // Luckily, we only care about the inputs and outputs, so we don't have to do
418418 // the whole null-terminated string dance.
419 const outputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.outputs_len]);
420 const inputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end + extra.data.outputs_len ..][0..extra.data.inputs_len]);
419 const outputs_len = extra.data.flags.outputs_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]);
421422 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;
422423 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
423424 },
src/InternPool.zig+6
......@@ -54,6 +54,7 @@ namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.In
5454memoized_state_main_deps: DepEntry.Index.Optional,
5555memoized_state_panic_deps: DepEntry.Index.Optional,
5656memoized_state_va_list_deps: DepEntry.Index.Optional,
57memoized_state_assembly_deps: DepEntry.Index.Optional,
5758
5859/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
5960/// matches. The `next_dependee` field can be used to iterate all such entries
......@@ -96,6 +97,7 @@ pub const empty: InternPool = .{
9697 .memoized_state_main_deps = .none,
9798 .memoized_state_panic_deps = .none,
9899 .memoized_state_va_list_deps = .none,
100 .memoized_state_assembly_deps = .none,
99101 .first_dependency = .empty,
100102 .dep_entries = .empty,
101103 .free_dep_entries = .empty,
......@@ -458,6 +460,8 @@ pub const MemoizedStateStage = enum(u32) {
458460 panic,
459461 /// Specifically `std.builtin.VaList`. See `Zcu.BuiltinDecl.stage`.
460462 va_list,
463 /// Everything within `std.builtin.assembly`. See `Zcu.BuiltinDecl.stage`.
464 assembly,
461465};
462466
463467pub const ComptimeUnit = extern struct {
......@@ -880,6 +884,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
880884 .main => ip.memoized_state_main_deps.unwrap(),
881885 .panic => ip.memoized_state_panic_deps.unwrap(),
882886 .va_list => ip.memoized_state_va_list_deps.unwrap(),
887 .assembly => ip.memoized_state_assembly_deps.unwrap(),
883888 },
884889 } orelse return .{
885890 .ip = ip,
......@@ -915,6 +920,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
915920 .main => &ip.memoized_state_main_deps,
916921 .panic => &ip.memoized_state_panic_deps,
917922 .va_list => &ip.memoized_state_va_list_deps,
923 .assembly => &ip.memoized_state_assembly_deps,
918924 };
919925
920926 if (deps.unwrap()) |first| {
src/Sema.zig+17-23
......@@ -16413,10 +16413,10 @@ fn zirAsm(
1641316413 const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
1641416414 const src = block.nodeOffset(extra.data.src_node);
1641516415 const ret_ty_src = block.src(.{ .node_offset_asm_ret_ty = extra.data.src_node });
16416 const outputs_len: u4 = @truncate(extended.small);
16417 const inputs_len: u5 = @truncate(extended.small >> 4);
16418 const clobbers_len: u6 = @truncate(extended.small >> 9);
16419 const is_volatile = @as(u1, @truncate(extended.small >> 15)) != 0;
16416 const small: Zir.Inst.Asm.Small = @bitCast(extended.small);
16417 const outputs_len = small.outputs_len;
16418 const inputs_len = small.inputs_len;
16419 const is_volatile = small.is_volatile;
1642016420 const is_global_assembly = sema.func_index == .none;
1642116421 const zir_tags = sema.code.instructions.items(.tag);
1642216422
......@@ -16432,7 +16432,7 @@ fn zirAsm(
1643216432 if (inputs_len != 0) {
1643316433 return sema.fail(block, src, "module-level assembly does not support inputs", .{});
1643416434 }
16435 if (clobbers_len != 0) {
16435 if (extra.data.clobbers != .none) {
1643616436 return sema.fail(block, src, "module-level assembly does not support clobbers", .{});
1643716437 }
1643816438 if (is_volatile) {
......@@ -16506,15 +16506,11 @@ fn zirAsm(
1650616506 inputs[arg_i] = .{ .c = constraint, .n = name };
1650716507 }
1650816508
16509 const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
16510 for (clobbers) |*name| {
16511 const name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_i]);
16512 name.* = sema.code.nullTerminatedString(name_index);
16513 extra_i += 1;
16514
16515 needed_capacity += name.*.len / 4 + 1;
16516 }
16517
16509 const clobbers = if (extra.data.clobbers == .none) empty: {
16510 const clobbers_ty = try sema.getBuiltinType(src, .@"assembly.Clobbers");
16511 break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);
16512 } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
16513 const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });
1651816514 needed_capacity += (asm_source.len + 3) / 4;
1651916515
1652016516 const gpa = sema.gpa;
......@@ -16525,9 +16521,12 @@ fn zirAsm(
1652516521 .ty = expr_ty,
1652616522 .payload = sema.addExtraAssumeCapacity(Air.Asm{
1652716523 .source_len = @intCast(asm_source.len),
16528 .outputs_len = outputs_len,
1652916524 .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 },
1653116530 }),
1653216531 } },
1653316532 });
......@@ -16549,12 +16548,6 @@ fn zirAsm(
1654916548 buffer[input.c.len + 1 + input.n.len] = 0;
1655016549 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
1655116550 }
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 }
1655816551 {
1655916552 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
1656016553 @memcpy(buffer[0..asm_source.len], asm_source);
......@@ -26197,6 +26190,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
2619726190 .extern_options => try sema.getBuiltinType(src, .ExternOptions),
2619826191 .type_info => try sema.getBuiltinType(src, .Type),
2619926192 .branch_hint => try sema.getBuiltinType(src, .BranchHint),
26193 .clobbers => try sema.getBuiltinType(src, .@"assembly.Clobbers"),
2620026194 // zig fmt: on
2620126195
2620226196 // Values are handled here.
......@@ -36546,7 +36540,7 @@ fn payloadToExtraItems(data: anytype) [@typeInfo(@TypeOf(data)).@"struct".fields
3654636540 inline for (&result, fields) |*val, field| {
3654736541 val.* = switch (field.type) {
3654836542 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)),
3655036544 Air.Inst.Ref, InternPool.Index => @intFromEnum(@field(data, field.name)),
3655136545 else => @compileError("bad field type: " ++ @typeName(field.type)),
3655236546 };
src/Zcu.zig+19-7
......@@ -460,6 +460,9 @@ pub const BuiltinDecl = enum {
460460
461461 VaList,
462462
463 assembly,
464 @"assembly.Clobbers",
465
463466 /// Determines what kind of validation will be done to the decl's value.
464467 pub fn kind(decl: BuiltinDecl) enum { type, func, string } {
465468 return switch (decl) {
......@@ -480,6 +483,8 @@ pub const BuiltinDecl = enum {
480483 .ExportOptions,
481484 .ExternOptions,
482485 .BranchHint,
486 .assembly,
487 .@"assembly.Clobbers",
483488 => .type,
484489
485490 .Type,
......@@ -540,6 +545,7 @@ pub const BuiltinDecl = enum {
540545 /// Resolution of these values is done in three distinct stages:
541546 /// * Resolution of `std.builtin.Panic` and everything under it
542547 /// * Resolution of `VaList`
548 /// * Resolution of `assembly`
543549 /// * Everything else
544550 ///
545551 /// Panics are separated because they are provided by the user, so must be able to use
......@@ -548,14 +554,20 @@ pub const BuiltinDecl = enum {
548554 /// `VaList` is separate because its value depends on the target, so it needs some reflection
549555 /// machinery to work; additionally, it is `@compileError` on some targets, so must be referenced
550556 /// by itself.
557 ///
558 /// `assembly` is separate because its value depends on the target.
551559 pub fn stage(decl: BuiltinDecl) InternPool.MemoizedStateStage {
552 if (decl == .VaList) return .va_list;
553
554 if (@intFromEnum(decl) <= @intFromEnum(BuiltinDecl.@"Type.Declaration")) {
555 return .main;
556 } else {
557 return .panic;
558 }
560 return switch (decl) {
561 .VaList => .va_list,
562 .assembly, .@"assembly.Clobbers" => .assembly,
563 else => {
564 if (@intFromEnum(decl) <= @intFromEnum(BuiltinDecl.@"Type.Declaration")) {
565 return .main;
566 } else {
567 return .panic;
568 }
569 },
570 };
559571 }
560572
561573 /// 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
635635 .main => .Type,
636636 .panic => .panic,
637637 .va_list => .VaList,
638 .assembly => .assembly,
638639 };
639640 if (zcu.builtin_decl_values.get(to_check) != .none) return;
640641 }
src/arch/riscv64/CodeGen.zig+28-16
......@@ -6047,10 +6047,10 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
60476047fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
60486048 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
60496049 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;
60516051 var extra_i: usize = extra.end;
60526052 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]);
60546054 extra_i += outputs.len;
60556055 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra.items[extra_i..][0..extra.data.inputs_len]);
60566056 extra_i += inputs.len;
......@@ -6161,21 +6161,33 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
61616161 args.appendAssumeCapacity(arg_mcv);
61626162 }
61636163
6164 {
6165 var clobber_i: u32 = 0;
6166 while (clobber_i < clobbers_len) : (clobber_i += 1) {
6167 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra.items[extra_i..]), 0);
6168 // This equation accounts for the fact that even if we have exactly 4 bytes
6169 // for the string, we still use the next u32 for the null terminator.
6170 extra_i += clobber.len / 4 + 1;
6171
6172 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
6173 // nothing really to do
6174 } else {
6175 try func.register_manager.getReg(parseRegName(clobber) orelse
6176 return func.fail("invalid clobber: '{s}'", .{clobber}), null);
6164 const zcu = func.pt.zcu;
6165 const ip = &zcu.intern_pool;
6166 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
6167 const struct_type: Type = .fromInterned(aggregate.ty);
6168 switch (aggregate.storage) {
6169 .elems => |elems| for (elems, 0..) |elem, i| {
6170 switch (elem) {
6171 .bool_true => {
6172 const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
6173 assert(clobber.len != 0);
6174 if (std.mem.eql(u8, clobber, "memory")) {
6175 // nothing really to do
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,
61776183 }
6178 }
6184 },
6185 .repeated_elem => |elem| switch (elem) {
6186 .bool_true => @panic("TODO"),
6187 .bool_false => {},
6188 else => unreachable,
6189 },
6190 .bytes => @panic("TODO"),
61796191 }
61806192
61816193 const Label = struct {
src/arch/sparc64/CodeGen.zig+5-14
......@@ -873,10 +873,10 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
873873fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
874874 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
875875 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
876 const is_volatile = (extra.data.flags & 0x80000000) != 0;
877 const clobbers_len: u31 = @truncate(extra.data.flags);
876 const is_volatile = extra.data.flags.is_volatile;
877 const outputs_len = extra.data.flags.outputs_len;
878878 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]);
880880 extra_i += outputs.len;
881881 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + extra.data.inputs_len]);
882882 extra_i += inputs.len;
......@@ -921,17 +921,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
921921 try self.genSetReg(self.typeOf(input), reg, arg_mcv);
922922 }
923923
924 {
925 var clobber_i: u32 = 0;
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 }
924 // TODO honor the clobbers
925 _ = extra.data.clobbers;
935926
936927 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 {
179788179788 const zcu = pt.zcu;
179789179789 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
179790179790 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;
179792179792 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]);
179794179794 extra_i += outputs.len;
179795179795 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
179796179796 extra_i += inputs.len;
......@@ -179981,30 +179981,42 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
179981179981 args.appendAssumeCapacity(arg_mcv);
179982179982 }
179983179983
179984 {
179985 var clobber_i: u32 = 0;
179986 while (clobber_i < clobbers_len) : (clobber_i += 1) {
179987 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);
179988 // This equation accounts for the fact that even if we have exactly 4 bytes
179989 // for the string, we still use the next u32 for the null terminator.
179990 extra_i += clobber.len / 4 + 1;
179991
179992 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory") or
179993 std.mem.eql(u8, clobber, "fpsr") or std.mem.eql(u8, clobber, "fpcr") or
179994 std.mem.eql(u8, clobber, "mxcsr") or std.mem.eql(u8, clobber, "dirflag"))
179995 {
179996 // ok, sure
179997 } else if (std.mem.eql(u8, clobber, "cc") or
179998 std.mem.eql(u8, clobber, "flags") or
179999 std.mem.eql(u8, clobber, "eflags") or
180000 std.mem.eql(u8, clobber, "rflags"))
180001 {
180002 try self.spillEflagsIfOccupied();
180003 } else {
180004 try self.register_manager.getReg(parseRegName(clobber) orelse
180005 return self.fail("invalid clobber: '{s}'", .{clobber}), null);
180006 }
180007 }
179984 const ip = &zcu.intern_pool;
179985 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
179986 const struct_type: Type = .fromInterned(aggregate.ty);
179987 switch (aggregate.storage) {
179988 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
179989 .bool_true => {
179990 const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
179991 assert(clobber.len != 0);
179992
179993 if (std.mem.eql(u8, clobber, "memory") or
179994 std.mem.eql(u8, clobber, "fpsr") or
179995 std.mem.eql(u8, clobber, "fpcr") or
179996 std.mem.eql(u8, clobber, "mxcsr") or
179997 std.mem.eql(u8, clobber, "dirflag"))
179998 {
179999 // ok, sure
180000 } else if (std.mem.eql(u8, clobber, "cc") or
180001 std.mem.eql(u8, clobber, "flags") or
180002 std.mem.eql(u8, clobber, "eflags") or
180003 std.mem.eql(u8, clobber, "rflags"))
180004 {
180005 try self.spillEflagsIfOccupied();
180006 } else {
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"),
180008180020 }
180009180021
180010180022 const Label = struct {
src/codegen/c.zig+24-19
......@@ -5545,11 +5545,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
55455545 const zcu = pt.zcu;
55465546 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
55475547 const extra = f.air.extraData(Air.Asm, ty_pl.payload);
5548 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
5549 const clobbers_len: u31 = @truncate(extra.data.flags);
5548 const is_volatile = extra.data.flags.is_volatile;
5549 const outputs_len = extra.data.flags.outputs_len;
55505550 const gpa = f.object.dg.gpa;
55515551 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]);
55535553 extra_i += outputs.len;
55545554 const inputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..extra.data.inputs_len]);
55555555 extra_i += inputs.len;
......@@ -5645,12 +5645,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
56455645 try f.object.newline();
56465646 }
56475647 }
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
56555649 {
56565650 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 {
57575751 try w.writeByte(')');
57585752 }
57595753 try w.writeByte(':');
5760 for (0..clobbers_len) |clobber_i| {
5761 const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra.items[extra_i..]), 0);
5762 // This equation accounts for the fact that even if we have exactly 4 bytes
5763 // for the string, we still use the next u32 for the null terminator.
5764 extra_i += clobber.len / 4 + 1;
5765
5766 if (clobber.len == 0) continue;
5767
5768 if (clobber_i > 0) try w.writeByte(',');
5769 try w.print(" {f}", .{fmtStringLiteral(clobber, null)});
5754 const ip = &zcu.intern_pool;
5755 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
5756 const struct_type: Type = .fromInterned(aggregate.ty);
5757 switch (aggregate.storage) {
5758 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
5759 .bool_true => {
5760 const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
5761 assert(name.len != 0);
5762 try w.print(" {f}", .{fmtStringLiteral(name, 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"),
57705774 }
5775 w.undo(1); // erase the last comma
57715776 try w.writeAll(");");
57725777 try f.object.newline();
57735778
src/codegen/llvm.zig+47-29
......@@ -7241,19 +7241,20 @@ pub const FuncGen = struct {
72417241 const o = self.ng.object;
72427242 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
72437243 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
7244 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
7245 const clobbers_len: u31 = @truncate(extra.data.flags);
7244 const is_volatile = extra.data.flags.is_volatile;
7245 const outputs_len = extra.data.flags.outputs_len;
7246 const gpa = self.gpa;
72467247 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]);
72497250 extra_i += outputs.len;
72507251 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
72517252 extra_i += inputs.len;
72527253
72537254 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);
72577258 defer arena_allocator.deinit();
72587259 const arena = arena_allocator.allocator();
72597260
......@@ -7290,7 +7291,7 @@ pub const FuncGen = struct {
72907291 // for the string, we still use the next u32 for the null terminator.
72917292 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);
72947295 if (total_i != 0) {
72957296 llvm_constraints.appendAssumeCapacity(',');
72967297 }
......@@ -7399,7 +7400,7 @@ pub const FuncGen = struct {
73997400 }
74007401 }
74017402
7402 try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1);
7403 try llvm_constraints.ensureUnusedCapacity(gpa, constraint.len + 1);
74037404 if (total_i != 0) {
74047405 llvm_constraints.appendAssumeCapacity(',');
74057406 }
......@@ -7456,7 +7457,7 @@ pub const FuncGen = struct {
74567457 llvm_param_types[llvm_param_i] = llvm_elem_ty;
74577458 }
74587459
7459 try llvm_constraints.print(self.gpa, ",{d}", .{output_index});
7460 try llvm_constraints.print(gpa, ",{d}", .{output_index});
74607461
74617462 // In the case of indirect inputs, LLVM requires the callsite to have
74627463 // an elementtype(<ty>) attribute.
......@@ -7466,24 +7467,41 @@ pub const FuncGen = struct {
74667467 total_i += 1;
74677468 }
74687469
7469 {
7470 var clobber_i: u32 = 0;
7471 while (clobber_i < clobbers_len) : (clobber_i += 1) {
7472 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);
7473 // This equation accounts for the fact that even if we have exactly 4 bytes
7474 // for the string, we still use the next u32 for the null terminator.
7475 extra_i += clobber.len / 4 + 1;
7476
7477 try llvm_constraints.ensureUnusedCapacity(self.gpa, clobber.len + 4);
7478 if (total_i != 0) {
7479 llvm_constraints.appendAssumeCapacity(',');
7470 const ip = &zcu.intern_pool;
7471 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;
7472 const struct_type: Type = .fromInterned(aggregate.ty);
7473 switch (aggregate.storage) {
7474 .elems => |elems| for (elems, 0..) |elem, i| {
7475 switch (elem) {
7476 .bool_true => {
7477 const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
7478 try llvm_constraints.ensureUnusedCapacity(gpa, name.len + 4);
7479 if (total_i != 0) 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,
74807488 }
7481 llvm_constraints.appendSliceAssumeCapacity("~{");
7482 llvm_constraints.appendSliceAssumeCapacity(clobber);
7483 llvm_constraints.appendSliceAssumeCapacity("}");
7489 },
7490 .repeated_elem => |elem| switch (elem) {
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;
7486 }
7499 total_i += 1;
7500 },
7501 .bool_false => {},
7502 else => unreachable,
7503 },
7504 .bytes => @panic("TODO"),
74877505 }
74887506
74897507 // We have finished scanning through all inputs/outputs, so the number of
......@@ -7497,13 +7515,13 @@ pub const FuncGen = struct {
74977515 // to be buggy and regress often.
74987516 switch (target.cpu.arch) {
74997517 .x86_64, .x86 => {
7500 if (total_i != 0) try llvm_constraints.append(self.gpa, ',');
7501 try llvm_constraints.appendSlice(self.gpa, "~{dirflag},~{fpsr},~{flags}");
7518 if (total_i != 0) try llvm_constraints.append(gpa, ',');
7519 try llvm_constraints.appendSlice(gpa, "~{dirflag},~{fpsr},~{flags}");
75027520 total_i += 3;
75037521 },
75047522 .mips, .mipsel, .mips64, .mips64el => {
7505 if (total_i != 0) try llvm_constraints.append(self.gpa, ',');
7506 try llvm_constraints.appendSlice(self.gpa, "~{$1}");
7523 if (total_i != 0) try llvm_constraints.append(gpa, ',');
7524 try llvm_constraints.appendSlice(gpa, "~{$1}");
75077525 total_i += 1;
75087526 },
75097527 else => {},
......@@ -7512,7 +7530,7 @@ pub const FuncGen = struct {
75127530 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];
75137531
75147532 // 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);
75167534 defer rendered_template.deinit();
75177535
75187536 const State = enum { start, percent, input, modifier };
src/codegen/spirv.zig+6-12
......@@ -6387,13 +6387,13 @@ const NavGen = struct {
63876387 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
63886388 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
63896389
6390 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
6391 const clobbers_len: u31 = @truncate(extra.data.flags);
6390 const is_volatile = extra.data.flags.is_volatile;
6391 const outputs_len = extra.data.flags.outputs_len;
63926392
63936393 if (!is_volatile and self.liveness.isUnused(inst)) return null;
63946394
63956395 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]);
63976397 extra_i += outputs.len;
63986398 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
63996399 extra_i += inputs.len;
......@@ -6402,7 +6402,7 @@ const NavGen = struct {
64026402 return self.todo("implement inline asm with more than 1 output", .{});
64036403 }
64046404
6405 var as = SpvAssembler{
6405 var as: SpvAssembler = .{
64066406 .gpa = self.gpa,
64076407 .spv = self.spv,
64086408 .func = &self.func,
......@@ -6486,14 +6486,8 @@ const NavGen = struct {
64866486 }
64876487 }
64886488
6489 {
6490 var clobber_i: u32 = 0;
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 }
6489 // TODO: do something with clobbers
6490 _ = extra.data.clobbers;
64976491
64986492 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];
64996493