Source file
src/runtime/mkpreempt.go
1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "flag"
13 "fmt"
14 "io"
15 "log"
16 "os"
17 "strings"
18 )
19
20
21
22 var regNames386 = []string{
23 "AX",
24 "CX",
25 "DX",
26 "BX",
27 "SP",
28 "BP",
29 "SI",
30 "DI",
31 "X0",
32 "X1",
33 "X2",
34 "X3",
35 "X4",
36 "X5",
37 "X6",
38 "X7",
39 }
40
41 var regNamesAMD64 = []string{
42 "AX",
43 "CX",
44 "DX",
45 "BX",
46 "SP",
47 "BP",
48 "SI",
49 "DI",
50 "R8",
51 "R9",
52 "R10",
53 "R11",
54 "R12",
55 "R13",
56 "R14",
57 "R15",
58 "X0",
59 "X1",
60 "X2",
61 "X3",
62 "X4",
63 "X5",
64 "X6",
65 "X7",
66 "X8",
67 "X9",
68 "X10",
69 "X11",
70 "X12",
71 "X13",
72 "X14",
73 "X15",
74 }
75
76 var out io.Writer
77
78 var arches = map[string]func(){
79 "386": gen386,
80 "amd64": genAMD64,
81 "arm": genARM,
82 "arm64": genARM64,
83 "loong64": genLoong64,
84 "mips64x": func() { genMIPS(true) },
85 "mipsx": func() { genMIPS(false) },
86 "ppc64x": genPPC64,
87 "riscv64": genRISCV64,
88 "s390x": genS390X,
89 "wasm": genWasm,
90 }
91 var beLe = map[string]bool{"mips64x": true, "mipsx": true, "ppc64x": true}
92
93 func main() {
94 flag.Parse()
95 if flag.NArg() > 0 {
96 out = os.Stdout
97 for _, arch := range flag.Args() {
98 gen, ok := arches[arch]
99 if !ok {
100 log.Fatalf("unknown arch %s", arch)
101 }
102 header(arch)
103 gen()
104 }
105 return
106 }
107
108 for arch, gen := range arches {
109 f, err := os.Create(fmt.Sprintf("preempt_%s.s", arch))
110 if err != nil {
111 log.Fatal(err)
112 }
113 out = f
114 header(arch)
115 gen()
116 if err := f.Close(); err != nil {
117 log.Fatal(err)
118 }
119 }
120 }
121
122 func header(arch string) {
123 fmt.Fprintf(out, "// Code generated by mkpreempt.go; DO NOT EDIT.\n\n")
124 if beLe[arch] {
125 base := arch[:len(arch)-1]
126 fmt.Fprintf(out, "//go:build %s || %sle\n\n", base, base)
127 }
128 fmt.Fprintf(out, "#include \"go_asm.h\"\n")
129 fmt.Fprintf(out, "#include \"textflag.h\"\n\n")
130 fmt.Fprintf(out, "TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0\n")
131 }
132
133 func p(f string, args ...any) {
134 fmted := fmt.Sprintf(f, args...)
135 fmt.Fprintf(out, "\t%s\n", strings.ReplaceAll(fmted, "\n", "\n\t"))
136 }
137
138 func label(l string) {
139 fmt.Fprintf(out, "%s\n", l)
140 }
141
142 type layout struct {
143 stack int
144 regs []regPos
145 sp string
146 }
147
148 type regPos struct {
149 pos int
150
151 saveOp string
152 restoreOp string
153 reg string
154
155
156
157
158 save, restore string
159 }
160
161 func (l *layout) add(op, reg string, size int) {
162 l.regs = append(l.regs, regPos{saveOp: op, restoreOp: op, reg: reg, pos: l.stack})
163 l.stack += size
164 }
165
166 func (l *layout) add2(sop, rop, reg string, size int) {
167 l.regs = append(l.regs, regPos{saveOp: sop, restoreOp: rop, reg: reg, pos: l.stack})
168 l.stack += size
169 }
170
171 func (l *layout) addSpecial(save, restore string, size int) {
172 l.regs = append(l.regs, regPos{save: save, restore: restore, pos: l.stack})
173 l.stack += size
174 }
175
176 func (l *layout) save() {
177 for _, reg := range l.regs {
178 if reg.save != "" {
179 p(reg.save, reg.pos)
180 } else {
181 p("%s %s, %d(%s)", reg.saveOp, reg.reg, reg.pos, l.sp)
182 }
183 }
184 }
185
186 func (l *layout) restore() {
187 for i := len(l.regs) - 1; i >= 0; i-- {
188 reg := l.regs[i]
189 if reg.restore != "" {
190 p(reg.restore, reg.pos)
191 } else {
192 p("%s %d(%s), %s", reg.restoreOp, reg.pos, l.sp, reg.reg)
193 }
194 }
195 }
196
197 func gen386() {
198 p("PUSHFL")
199
200 var l = layout{sp: "SP"}
201 for _, reg := range regNames386 {
202 if reg == "SP" || strings.HasPrefix(reg, "X") {
203 continue
204 }
205 l.add("MOVL", reg, 4)
206 }
207
208 softfloat := "GO386_softfloat"
209
210
211 lSSE := layout{stack: l.stack, sp: "SP"}
212 for i := 0; i < 8; i++ {
213 lSSE.add("MOVUPS", fmt.Sprintf("X%d", i), 16)
214 }
215
216 p("ADJSP $%d", lSSE.stack)
217 p("NOP SP")
218 l.save()
219 p("#ifndef %s", softfloat)
220 lSSE.save()
221 p("#endif")
222 p("CALL ·asyncPreempt2(SB)")
223 p("#ifndef %s", softfloat)
224 lSSE.restore()
225 p("#endif")
226 l.restore()
227 p("ADJSP $%d", -lSSE.stack)
228
229 p("POPFL")
230 p("RET")
231 }
232
233 func genAMD64() {
234
235 var l = layout{sp: "SP"}
236 for _, reg := range regNamesAMD64 {
237 if reg == "SP" || reg == "BP" {
238 continue
239 }
240 if !strings.HasPrefix(reg, "X") {
241 l.add("MOVQ", reg, 8)
242 }
243 }
244 lSSE := layout{stack: l.stack, sp: "SP"}
245 for _, reg := range regNamesAMD64 {
246 if strings.HasPrefix(reg, "X") {
247 lSSE.add("MOVUPS", reg, 16)
248 }
249 }
250
251
252
253 p("PUSHQ BP")
254 p("MOVQ SP, BP")
255 p("// Save flags before clobbering them")
256 p("PUSHFQ")
257 p("// obj doesn't understand ADD/SUB on SP, but does understand ADJSP")
258 p("ADJSP $%d", lSSE.stack)
259 p("// But vet doesn't know ADJSP, so suppress vet stack checking")
260 p("NOP SP")
261
262 l.save()
263
264
265
266
267
268
269 p("#ifdef GOOS_darwin")
270 p("CMPB internal∕cpu·X86+const_offsetX86HasAVX(SB), $0")
271 p("JE 2(PC)")
272 p("VZEROUPPER")
273 p("#endif")
274
275 lSSE.save()
276 p("CALL ·asyncPreempt2(SB)")
277 lSSE.restore()
278 l.restore()
279 p("ADJSP $%d", -lSSE.stack)
280 p("POPFQ")
281 p("POPQ BP")
282 p("RET")
283 }
284
285 func genARM() {
286
287
288 var l = layout{sp: "R13", stack: 4}
289 for i := 0; i <= 12; i++ {
290 reg := fmt.Sprintf("R%d", i)
291 if i == 10 {
292 continue
293 }
294 l.add("MOVW", reg, 4)
295 }
296
297 l.addSpecial(
298 "MOVW CPSR, R0\nMOVW R0, %d(R13)",
299 "MOVW %d(R13), R0\nMOVW R0, CPSR",
300 4)
301
302
303 var lfp = layout{stack: l.stack, sp: "R13"}
304 lfp.addSpecial(
305 "MOVW FPCR, R0\nMOVW R0, %d(R13)",
306 "MOVW %d(R13), R0\nMOVW R0, FPCR",
307 4)
308 for i := 0; i <= 15; i++ {
309 reg := fmt.Sprintf("F%d", i)
310 lfp.add("MOVD", reg, 8)
311 }
312
313 p("MOVW.W R14, -%d(R13)", lfp.stack)
314 l.save()
315 p("MOVB ·goarm(SB), R0\nCMP $6, R0\nBLT nofp")
316 lfp.save()
317 label("nofp:")
318 p("CALL ·asyncPreempt2(SB)")
319 p("MOVB ·goarm(SB), R0\nCMP $6, R0\nBLT nofp2")
320 lfp.restore()
321 label("nofp2:")
322 l.restore()
323
324 p("MOVW %d(R13), R14", lfp.stack)
325 p("MOVW.P %d(R13), R15", lfp.stack+4)
326 p("UNDEF")
327 }
328
329 func genARM64() {
330
331
332
333 var l = layout{sp: "RSP", stack: 8}
334 for i := 0; i < 26; i += 2 {
335 if i == 18 {
336 i--
337 continue
338 }
339 reg := fmt.Sprintf("(R%d, R%d)", i, i+1)
340 l.add2("STP", "LDP", reg, 16)
341 }
342
343 l.addSpecial(
344 "MOVD NZCV, R0\nMOVD R0, %d(RSP)",
345 "MOVD %d(RSP), R0\nMOVD R0, NZCV",
346 8)
347 l.addSpecial(
348 "MOVD FPSR, R0\nMOVD R0, %d(RSP)",
349 "MOVD %d(RSP), R0\nMOVD R0, FPSR",
350 8)
351
352
353 for i := 0; i < 31; i += 2 {
354 reg := fmt.Sprintf("(F%d, F%d)", i, i+1)
355 l.add2("FSTPD", "FLDPD", reg, 16)
356 }
357 if l.stack%16 != 0 {
358 l.stack += 8
359 }
360
361
362 p("MOVD R30, %d(RSP)", -l.stack)
363 p("SUB $%d, RSP", l.stack)
364 p("MOVD R29, -8(RSP)")
365 p("SUB $8, RSP, R29")
366
367
368
369 p("#ifdef GOOS_ios")
370 p("MOVD R30, (RSP)")
371 p("#endif")
372
373 l.save()
374 p("CALL ·asyncPreempt2(SB)")
375 l.restore()
376
377 p("MOVD %d(RSP), R30", l.stack)
378 p("MOVD -8(RSP), R29")
379 p("MOVD (RSP), R27")
380 p("ADD $%d, RSP", l.stack+16)
381 p("JMP (R27)")
382 }
383
384 func genMIPS(_64bit bool) {
385 mov := "MOVW"
386 movf := "MOVF"
387 add := "ADD"
388 sub := "SUB"
389 r28 := "R28"
390 regsize := 4
391 softfloat := "GOMIPS_softfloat"
392 if _64bit {
393 mov = "MOVV"
394 movf = "MOVD"
395 add = "ADDV"
396 sub = "SUBV"
397 r28 = "RSB"
398 regsize = 8
399 softfloat = "GOMIPS64_softfloat"
400 }
401
402
403
404
405 var l = layout{sp: "R29", stack: regsize}
406 for i := 1; i <= 25; i++ {
407 if i == 23 {
408 continue
409 }
410 reg := fmt.Sprintf("R%d", i)
411 l.add(mov, reg, regsize)
412 }
413 l.add(mov, r28, regsize)
414 l.addSpecial(
415 mov+" HI, R1\n"+mov+" R1, %d(R29)",
416 mov+" %d(R29), R1\n"+mov+" R1, HI",
417 regsize)
418 l.addSpecial(
419 mov+" LO, R1\n"+mov+" R1, %d(R29)",
420 mov+" %d(R29), R1\n"+mov+" R1, LO",
421 regsize)
422
423
424 var lfp = layout{sp: "R29", stack: l.stack}
425 lfp.addSpecial(
426 mov+" FCR31, R1\n"+mov+" R1, %d(R29)",
427 mov+" %d(R29), R1\n"+mov+" R1, FCR31",
428 regsize)
429
430 for i := 0; i <= 31; i++ {
431 reg := fmt.Sprintf("F%d", i)
432 lfp.add(movf, reg, regsize)
433 }
434
435
436 p(mov+" R31, -%d(R29)", lfp.stack)
437 p(sub+" $%d, R29", lfp.stack)
438
439 l.save()
440 p("#ifndef %s", softfloat)
441 lfp.save()
442 p("#endif")
443 p("CALL ·asyncPreempt2(SB)")
444 p("#ifndef %s", softfloat)
445 lfp.restore()
446 p("#endif")
447 l.restore()
448
449 p(mov+" %d(R29), R31", lfp.stack)
450 p(mov + " (R29), R23")
451 p(add+" $%d, R29", lfp.stack+regsize)
452 p("JMP (R23)")
453 }
454
455 func genLoong64() {
456 mov := "MOVV"
457 movf := "MOVD"
458 add := "ADDV"
459 sub := "SUBV"
460 r31 := "RSB"
461 regsize := 8
462
463
464
465 var l = layout{sp: "R3", stack: regsize}
466 for i := 4; i <= 29; i++ {
467 if i == 22 {
468 continue
469 }
470 reg := fmt.Sprintf("R%d", i)
471 l.add(mov, reg, regsize)
472 }
473 l.add(mov, r31, regsize)
474
475
476 for i := 0; i <= 31; i++ {
477 reg := fmt.Sprintf("F%d", i)
478 l.add(movf, reg, regsize)
479 }
480
481
482 p(mov+" R1, -%d(R3)", l.stack)
483 p(sub+" $%d, R3", l.stack)
484
485 l.save()
486 p("CALL ·asyncPreempt2(SB)")
487 l.restore()
488
489 p(mov+" %d(R3), R1", l.stack)
490 p(mov + " (R3), R30")
491 p(add+" $%d, R3", l.stack+regsize)
492 p("JMP (R30)")
493 }
494
495 func genPPC64() {
496
497
498
499
500 var l = layout{sp: "R1", stack: 32 + 8}
501 for i := 3; i <= 29; i++ {
502 if i == 12 || i == 13 {
503
504
505
506
507 continue
508 }
509 reg := fmt.Sprintf("R%d", i)
510 l.add("MOVD", reg, 8)
511 }
512 l.addSpecial(
513 "MOVW CR, R31\nMOVW R31, %d(R1)",
514 "MOVW %d(R1), R31\nMOVFL R31, $0xff",
515 8)
516 l.addSpecial(
517 "MOVD XER, R31\nMOVD R31, %d(R1)",
518 "MOVD %d(R1), R31\nMOVD R31, XER",
519 8)
520
521 for i := 0; i <= 31; i++ {
522 reg := fmt.Sprintf("F%d", i)
523 l.add("FMOVD", reg, 8)
524 }
525
526 l.addSpecial(
527 "MOVFL FPSCR, F0\nFMOVD F0, %d(R1)",
528 "FMOVD %d(R1), F0\nMOVFL F0, FPSCR",
529 8)
530
531 p("MOVD R31, -%d(R1)", l.stack-32)
532 p("MOVD LR, R31")
533 p("MOVDU R31, -%d(R1)", l.stack)
534
535 l.save()
536 p("CALL ·asyncPreempt2(SB)")
537 l.restore()
538
539 p("MOVD %d(R1), R31", l.stack)
540 p("MOVD R31, LR")
541 p("MOVD %d(R1), R2", l.stack+8)
542 p("MOVD %d(R1), R12", l.stack+16)
543 p("MOVD (R1), R31")
544 p("MOVD R31, CTR")
545 p("MOVD 32(R1), R31")
546 p("ADD $%d, R1", l.stack+32)
547 p("JMP (CTR)")
548 }
549
550 func genRISCV64() {
551
552 var l = layout{sp: "X2", stack: 8}
553
554
555 for i := 5; i < 31; i++ {
556 if i == 27 {
557 continue
558 }
559 reg := fmt.Sprintf("X%d", i)
560 l.add("MOV", reg, 8)
561 }
562
563
564 for i := 0; i <= 31; i++ {
565 reg := fmt.Sprintf("F%d", i)
566 l.add("MOVD", reg, 8)
567 }
568
569 p("MOV X1, -%d(X2)", l.stack)
570 p("ADD $-%d, X2", l.stack)
571 l.save()
572 p("CALL ·asyncPreempt2(SB)")
573 l.restore()
574 p("MOV %d(X2), X1", l.stack)
575 p("MOV (X2), X31")
576 p("ADD $%d, X2", l.stack+8)
577 p("JMP (X31)")
578 }
579
580 func genS390X() {
581
582
583
584 var l = layout{sp: "R15", stack: 16}
585 l.addSpecial(
586 "STMG R0, R12, %d(R15)",
587 "LMG %d(R15), R0, R12",
588 13*8)
589
590 for i := 0; i <= 15; i++ {
591 reg := fmt.Sprintf("F%d", i)
592 l.add("FMOVD", reg, 8)
593 }
594
595
596 p("IPM R10")
597 p("MOVD R14, -%d(R15)", l.stack)
598 p("ADD $-%d, R15", l.stack)
599 p("MOVW R10, 8(R15)")
600
601 l.save()
602 p("CALL ·asyncPreempt2(SB)")
603 l.restore()
604
605 p("MOVD %d(R15), R14", l.stack)
606 p("ADD $%d, R15", l.stack+8)
607 p("MOVWZ -%d(R15), R10", l.stack)
608 p("TMLH R10, $(3<<12)")
609 p("MOVD -%d(R15), R10", l.stack+8)
610 p("JMP (R10)")
611 }
612
613 func genWasm() {
614 p("// No async preemption on wasm")
615 p("UNDEF")
616 }
617
618 func notImplemented() {
619 p("// Not implemented yet")
620 p("JMP ·abort(SB)")
621 }
622
View as plain text