1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package mips
31
32 import (
33 "cmd/internal/obj"
34 "cmd/internal/sys"
35 "encoding/binary"
36 "fmt"
37 "internal/abi"
38 "log"
39 "math"
40 )
41
42 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
43 c := ctxt0{ctxt: ctxt, newprog: newprog}
44
45 p.From.Class = 0
46 p.To.Class = 0
47
48
49 switch p.As {
50 case AJMP,
51 AJAL,
52 ARET,
53 obj.ADUFFZERO,
54 obj.ADUFFCOPY:
55 if p.To.Sym != nil {
56 p.To.Type = obj.TYPE_BRANCH
57 }
58 }
59
60
61 switch p.As {
62 case AMOVF:
63 if p.From.Type == obj.TYPE_FCONST {
64 f32 := float32(p.From.Val.(float64))
65 if math.Float32bits(f32) == 0 {
66 p.As = AMOVW
67 p.From.Type = obj.TYPE_REG
68 p.From.Reg = REGZERO
69 break
70 }
71 p.From.Type = obj.TYPE_MEM
72 p.From.Sym = ctxt.Float32Sym(f32)
73 p.From.Name = obj.NAME_EXTERN
74 p.From.Offset = 0
75 }
76
77 case AMOVD:
78 if p.From.Type == obj.TYPE_FCONST {
79 f64 := p.From.Val.(float64)
80 if math.Float64bits(f64) == 0 && c.ctxt.Arch.Family == sys.MIPS64 {
81 p.As = AMOVV
82 p.From.Type = obj.TYPE_REG
83 p.From.Reg = REGZERO
84 break
85 }
86 p.From.Type = obj.TYPE_MEM
87 p.From.Sym = ctxt.Float64Sym(f64)
88 p.From.Name = obj.NAME_EXTERN
89 p.From.Offset = 0
90 }
91
92
93 case AMOVV:
94 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
95 p.From.Type = obj.TYPE_MEM
96 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
97 p.From.Name = obj.NAME_EXTERN
98 p.From.Offset = 0
99 }
100 }
101
102
103 switch p.As {
104 case ASUB:
105 if p.From.Type == obj.TYPE_CONST {
106 p.From.Offset = -p.From.Offset
107 p.As = AADD
108 }
109
110 case ASUBU:
111 if p.From.Type == obj.TYPE_CONST {
112 p.From.Offset = -p.From.Offset
113 p.As = AADDU
114 }
115
116 case ASUBV:
117 if p.From.Type == obj.TYPE_CONST {
118 p.From.Offset = -p.From.Offset
119 p.As = AADDV
120 }
121
122 case ASUBVU:
123 if p.From.Type == obj.TYPE_CONST {
124 p.From.Offset = -p.From.Offset
125 p.As = AADDVU
126 }
127 }
128 }
129
130 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
131
132 c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
133
134
135 nosched := true
136
137 if c.cursym.Func().Text == nil || c.cursym.Func().Text.Link == nil {
138 return
139 }
140
141 p := c.cursym.Func().Text
142 textstksiz := p.To.Offset
143 if textstksiz == -ctxt.Arch.FixedFrameSize {
144
145 p.From.Sym.Set(obj.AttrNoFrame, true)
146 textstksiz = 0
147 }
148 if textstksiz < 0 {
149 c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
150 }
151 if p.From.Sym.NoFrame() {
152 if textstksiz != 0 {
153 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
154 }
155 }
156
157 c.cursym.Func().Args = p.To.Val.(int32)
158 c.cursym.Func().Locals = int32(textstksiz)
159
160
165
166 for p := c.cursym.Func().Text; p != nil; p = p.Link {
167 switch p.As {
168
169 case obj.ATEXT:
170 p.Mark |= LABEL | LEAF | SYNC
171 if p.Link != nil {
172 p.Link.Mark |= LABEL
173 }
174
175
176 case AMOVW,
177 AMOVV:
178 if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
179 p.Mark |= LABEL | SYNC
180 break
181 }
182 if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
183 p.Mark |= LABEL | SYNC
184 }
185
186
187 case ASYSCALL,
188 AWORD,
189 ATLBWR,
190 ATLBWI,
191 ATLBP,
192 ATLBR:
193 p.Mark |= LABEL | SYNC
194
195 case ANOR:
196 if p.To.Type == obj.TYPE_REG {
197 if p.To.Reg == REGZERO {
198 p.Mark |= LABEL | SYNC
199 }
200 }
201
202 case ABGEZAL,
203 ABLTZAL,
204 AJAL,
205 obj.ADUFFZERO,
206 obj.ADUFFCOPY:
207 c.cursym.Func().Text.Mark &^= LEAF
208 fallthrough
209
210 case AJMP,
211 ABEQ,
212 ABGEZ,
213 ABGTZ,
214 ABLEZ,
215 ABLTZ,
216 ABNE,
217 ABFPT, ABFPF:
218 if p.As == ABFPT || p.As == ABFPF {
219
220
221
222
223
224
225
226
227 p.Mark |= SYNC
228 } else {
229 p.Mark |= BRANCH
230 }
231 q1 := p.To.Target()
232 if q1 != nil {
233 for q1.As == obj.ANOP {
234 q1 = q1.Link
235 p.To.SetTarget(q1)
236 }
237
238 if q1.Mark&LEAF == 0 {
239 q1.Mark |= LABEL
240 }
241 }
242
243
244
245 q1 = p.Link
246 if q1 != nil {
247 q1.Mark |= LABEL
248 }
249
250 case ARET:
251 if p.Link != nil {
252 p.Link.Mark |= LABEL
253 }
254 }
255 }
256
257 var mov, add obj.As
258 if c.ctxt.Arch.Family == sys.MIPS64 {
259 add = AADDV
260 mov = AMOVV
261 } else {
262 add = AADDU
263 mov = AMOVW
264 }
265
266 var q *obj.Prog
267 var q1 *obj.Prog
268 autosize := int32(0)
269 var p1 *obj.Prog
270 var p2 *obj.Prog
271 for p := c.cursym.Func().Text; p != nil; p = p.Link {
272 o := p.As
273 switch o {
274 case obj.ATEXT:
275 autosize = int32(textstksiz)
276
277 if p.Mark&LEAF != 0 && autosize == 0 {
278
279 p.From.Sym.Set(obj.AttrNoFrame, true)
280 }
281
282 if !p.From.Sym.NoFrame() {
283
284
285 autosize += int32(c.ctxt.Arch.FixedFrameSize)
286 }
287
288 if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
289 autosize += 4
290 }
291
292 if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
293 if c.cursym.Func().Text.From.Sym.NoSplit() {
294 if ctxt.Debugvlog {
295 ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
296 }
297
298 c.cursym.Func().Text.Mark |= LEAF
299 }
300 }
301
302 p.To.Offset = int64(autosize) - ctxt.Arch.FixedFrameSize
303
304 if c.cursym.Func().Text.Mark&LEAF != 0 {
305 c.cursym.Set(obj.AttrLeaf, true)
306 if p.From.Sym.NoFrame() {
307 break
308 }
309 }
310
311 if !p.From.Sym.NoSplit() {
312 p = c.stacksplit(p, autosize)
313 }
314
315 q = p
316
317 if autosize != 0 {
318
319
320
321
322
323
324
325 q = c.ctxt.StartUnsafePoint(q, c.newprog)
326
327 q = obj.Appendp(q, newprog)
328 q.As = mov
329 q.Pos = p.Pos
330 q.From.Type = obj.TYPE_REG
331 q.From.Reg = REGLINK
332 q.To.Type = obj.TYPE_MEM
333 q.To.Offset = int64(-autosize)
334 q.To.Reg = REGSP
335
336 q = obj.Appendp(q, newprog)
337 q.As = add
338 q.Pos = p.Pos
339 q.From.Type = obj.TYPE_CONST
340 q.From.Offset = int64(-autosize)
341 q.To.Type = obj.TYPE_REG
342 q.To.Reg = REGSP
343 q.Spadj = +autosize
344
345 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
346
347
348
349
350
351
352 q = obj.Appendp(q, newprog)
353 q.As = mov
354 q.Pos = p.Pos
355 q.From.Type = obj.TYPE_REG
356 q.From.Reg = REGLINK
357 q.To.Type = obj.TYPE_MEM
358 q.To.Offset = 0
359 q.To.Reg = REGSP
360 }
361
362 if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 q = obj.Appendp(q, newprog)
382
383 q.As = mov
384 q.From.Type = obj.TYPE_MEM
385 q.From.Reg = REGG
386 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
387 q.To.Type = obj.TYPE_REG
388 q.To.Reg = REG_R1
389
390 q = obj.Appendp(q, newprog)
391 q.As = ABEQ
392 q.From.Type = obj.TYPE_REG
393 q.From.Reg = REG_R1
394 q.To.Type = obj.TYPE_BRANCH
395 q.Mark |= BRANCH
396 p1 = q
397
398 q = obj.Appendp(q, newprog)
399 q.As = mov
400 q.From.Type = obj.TYPE_MEM
401 q.From.Reg = REG_R1
402 q.From.Offset = 0
403 q.To.Type = obj.TYPE_REG
404 q.To.Reg = REG_R2
405
406 q = obj.Appendp(q, newprog)
407 q.As = add
408 q.From.Type = obj.TYPE_CONST
409 q.From.Offset = int64(autosize) + ctxt.Arch.FixedFrameSize
410 q.Reg = REGSP
411 q.To.Type = obj.TYPE_REG
412 q.To.Reg = REG_R3
413
414 q = obj.Appendp(q, newprog)
415 q.As = ABNE
416 q.From.Type = obj.TYPE_REG
417 q.From.Reg = REG_R2
418 q.Reg = REG_R3
419 q.To.Type = obj.TYPE_BRANCH
420 q.Mark |= BRANCH
421 p2 = q
422
423 q = obj.Appendp(q, newprog)
424 q.As = add
425 q.From.Type = obj.TYPE_CONST
426 q.From.Offset = ctxt.Arch.FixedFrameSize
427 q.Reg = REGSP
428 q.To.Type = obj.TYPE_REG
429 q.To.Reg = REG_R2
430
431 q = obj.Appendp(q, newprog)
432 q.As = mov
433 q.From.Type = obj.TYPE_REG
434 q.From.Reg = REG_R2
435 q.To.Type = obj.TYPE_MEM
436 q.To.Reg = REG_R1
437 q.To.Offset = 0
438
439 q = obj.Appendp(q, newprog)
440
441 q.As = obj.ANOP
442 p1.To.SetTarget(q)
443 p2.To.SetTarget(q)
444 }
445
446 case ARET:
447 if p.From.Type == obj.TYPE_CONST {
448 ctxt.Diag("using BECOME (%v) is not supported!", p)
449 break
450 }
451
452 retSym := p.To.Sym
453 p.To.Name = obj.NAME_NONE
454 p.To.Sym = nil
455
456 if c.cursym.Func().Text.Mark&LEAF != 0 {
457 if autosize == 0 {
458 p.As = AJMP
459 p.From = obj.Addr{}
460 if retSym != nil {
461 p.To.Type = obj.TYPE_BRANCH
462 p.To.Name = obj.NAME_EXTERN
463 p.To.Sym = retSym
464 } else {
465 p.To.Type = obj.TYPE_MEM
466 p.To.Reg = REGLINK
467 p.To.Offset = 0
468 }
469 p.Mark |= BRANCH
470 break
471 }
472
473 p.As = add
474 p.From.Type = obj.TYPE_CONST
475 p.From.Offset = int64(autosize)
476 p.To.Type = obj.TYPE_REG
477 p.To.Reg = REGSP
478 p.Spadj = -autosize
479
480 q = c.newprog()
481 q.As = AJMP
482 q.Pos = p.Pos
483 if retSym != nil {
484 q.To.Type = obj.TYPE_BRANCH
485 q.To.Name = obj.NAME_EXTERN
486 q.To.Sym = retSym
487 } else {
488 q.To.Type = obj.TYPE_MEM
489 q.To.Reg = REGLINK
490 q.To.Offset = 0
491 }
492 q.Mark |= BRANCH
493 q.Spadj = +autosize
494
495 q.Link = p.Link
496 p.Link = q
497 break
498 }
499
500 p.As = mov
501 p.From.Type = obj.TYPE_MEM
502 p.From.Offset = 0
503 p.From.Reg = REGSP
504 p.To.Type = obj.TYPE_REG
505 p.To.Reg = REGLINK
506
507 if autosize != 0 {
508 q = c.newprog()
509 q.As = add
510 q.Pos = p.Pos
511 q.From.Type = obj.TYPE_CONST
512 q.From.Offset = int64(autosize)
513 q.To.Type = obj.TYPE_REG
514 q.To.Reg = REGSP
515 q.Spadj = -autosize
516
517 q.Link = p.Link
518 p.Link = q
519 }
520
521 q1 = c.newprog()
522 q1.As = AJMP
523 q1.Pos = p.Pos
524 if retSym != nil {
525 q1.To.Type = obj.TYPE_BRANCH
526 q1.To.Name = obj.NAME_EXTERN
527 q1.To.Sym = retSym
528 } else {
529 q1.To.Type = obj.TYPE_MEM
530 q1.To.Offset = 0
531 q1.To.Reg = REGLINK
532 }
533 q1.Mark |= BRANCH
534 q1.Spadj = +autosize
535
536 q1.Link = q.Link
537 q.Link = q1
538
539 case AADD,
540 AADDU,
541 AADDV,
542 AADDVU:
543 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
544 p.Spadj = int32(-p.From.Offset)
545 }
546
547 case obj.AGETCALLERPC:
548 if cursym.Leaf() {
549
550 p.As = mov
551 p.From.Type = obj.TYPE_REG
552 p.From.Reg = REGLINK
553 } else {
554
555 p.As = mov
556 p.From.Type = obj.TYPE_MEM
557 p.From.Reg = REGSP
558 }
559 }
560
561 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
562 f := c.cursym.Func()
563 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
564 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
565 if ctxt.Debugvlog || !ctxt.IsAsm {
566 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
567 if !ctxt.IsAsm {
568 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
569 ctxt.DiagFlush()
570 log.Fatalf("bad SPWRITE")
571 }
572 }
573 }
574 }
575 }
576
577 if c.ctxt.Arch.Family == sys.MIPS {
578
579 for p = c.cursym.Func().Text; p != nil; p = p1 {
580 p1 = p.Link
581
582 if p.As != AMOVD {
583 continue
584 }
585 if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
586 continue
587 }
588
589 p.As = AMOVF
590 q = c.newprog()
591 *q = *p
592 q.Link = p.Link
593 p.Link = q
594 p1 = q.Link
595
596 var addrOff int64
597 if c.ctxt.Arch.ByteOrder == binary.BigEndian {
598 addrOff = 4
599 }
600 if p.From.Type == obj.TYPE_MEM {
601 reg := REG_F0 + (p.To.Reg-REG_F0)&^1
602 p.To.Reg = reg
603 q.To.Reg = reg + 1
604 p.From.Offset += addrOff
605 q.From.Offset += 4 - addrOff
606 } else if p.To.Type == obj.TYPE_MEM {
607 reg := REG_F0 + (p.From.Reg-REG_F0)&^1
608 p.From.Reg = reg
609 q.From.Reg = reg + 1
610 p.To.Offset += addrOff
611 q.To.Offset += 4 - addrOff
612 }
613 }
614 }
615
616 if nosched {
617
618
619 for p = c.cursym.Func().Text; p != nil; p = p.Link {
620 if p.Mark&BRANCH != 0 {
621 c.addnop(p)
622 }
623 }
624 return
625 }
626
627
628 q = nil
629 q1 = c.cursym.Func().Text
630 o := 0
631 for p = c.cursym.Func().Text; p != nil; p = p1 {
632 p1 = p.Link
633 o++
634 if p.Mark&NOSCHED != 0 {
635 if q1 != p {
636 c.sched(q1, q)
637 }
638 for ; p != nil; p = p.Link {
639 if p.Mark&NOSCHED == 0 {
640 break
641 }
642 q = p
643 }
644 p1 = p
645 q1 = p
646 o = 0
647 continue
648 }
649 if p.Mark&(LABEL|SYNC) != 0 {
650 if q1 != p {
651 c.sched(q1, q)
652 }
653 q1 = p
654 o = 1
655 }
656 if p.Mark&(BRANCH|SYNC) != 0 {
657 c.sched(q1, p)
658 q1 = p1
659 o = 0
660 }
661 if o >= NSCHED {
662 c.sched(q1, p)
663 q1 = p1
664 o = 0
665 }
666 q = p
667 }
668 }
669
670 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
671 var mov, add obj.As
672
673 if c.ctxt.Arch.Family == sys.MIPS64 {
674 add = AADDV
675 mov = AMOVV
676 } else {
677 add = AADDU
678 mov = AMOVW
679 }
680
681 if c.ctxt.Flag_maymorestack != "" {
682
683 frameSize := 2 * c.ctxt.Arch.PtrSize
684
685 p = c.ctxt.StartUnsafePoint(p, c.newprog)
686
687
688 p = obj.Appendp(p, c.newprog)
689 p.As = mov
690 p.From.Type = obj.TYPE_REG
691 p.From.Reg = REGLINK
692 p.To.Type = obj.TYPE_MEM
693 p.To.Offset = int64(-frameSize)
694 p.To.Reg = REGSP
695
696
697 p = obj.Appendp(p, c.newprog)
698 p.As = mov
699 p.From.Type = obj.TYPE_REG
700 p.From.Reg = REGCTXT
701 p.To.Type = obj.TYPE_MEM
702 p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
703 p.To.Reg = REGSP
704
705
706 p = obj.Appendp(p, c.newprog)
707 p.As = add
708 p.From.Type = obj.TYPE_CONST
709 p.From.Offset = int64(-frameSize)
710 p.To.Type = obj.TYPE_REG
711 p.To.Reg = REGSP
712 p.Spadj = int32(frameSize)
713
714
715 p = obj.Appendp(p, c.newprog)
716 p.As = AJAL
717 p.To.Type = obj.TYPE_BRANCH
718
719 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
720 p.Mark |= BRANCH
721
722
723
724
725 p = obj.Appendp(p, c.newprog)
726 p.As = mov
727 p.From.Type = obj.TYPE_MEM
728 p.From.Offset = 0
729 p.From.Reg = REGSP
730 p.To.Type = obj.TYPE_REG
731 p.To.Reg = REGLINK
732
733
734 p = obj.Appendp(p, c.newprog)
735 p.As = mov
736 p.From.Type = obj.TYPE_MEM
737 p.From.Offset = int64(c.ctxt.Arch.PtrSize)
738 p.From.Reg = REGSP
739 p.To.Type = obj.TYPE_REG
740 p.To.Reg = REGCTXT
741
742
743 p = obj.Appendp(p, c.newprog)
744 p.As = add
745 p.From.Type = obj.TYPE_CONST
746 p.From.Offset = int64(frameSize)
747 p.To.Type = obj.TYPE_REG
748 p.To.Reg = REGSP
749 p.Spadj = int32(-frameSize)
750
751 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
752 }
753
754
755 startPred := p
756
757
758 p = obj.Appendp(p, c.newprog)
759
760 p.As = mov
761 p.From.Type = obj.TYPE_MEM
762 p.From.Reg = REGG
763 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
764 if c.cursym.CFunc() {
765 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
766 }
767 p.To.Type = obj.TYPE_REG
768 p.To.Reg = REG_R1
769
770
771
772
773
774 p = c.ctxt.StartUnsafePoint(p, c.newprog)
775
776 var q *obj.Prog
777 if framesize <= abi.StackSmall {
778
779
780 p = obj.Appendp(p, c.newprog)
781
782 p.As = ASGTU
783 p.From.Type = obj.TYPE_REG
784 p.From.Reg = REGSP
785 p.Reg = REG_R1
786 p.To.Type = obj.TYPE_REG
787 p.To.Reg = REG_R1
788 } else {
789
790 offset := int64(framesize) - abi.StackSmall
791 if framesize > abi.StackBig {
792
793
794
795
796
797
798
799
800
801
802 p = obj.Appendp(p, c.newprog)
803 p.As = ASGTU
804 p.From.Type = obj.TYPE_CONST
805 p.From.Offset = offset
806 p.Reg = REGSP
807 p.To.Type = obj.TYPE_REG
808 p.To.Reg = REG_R2
809
810 p = obj.Appendp(p, c.newprog)
811 q = p
812 p.As = ABNE
813 p.From.Type = obj.TYPE_REG
814 p.From.Reg = REG_R2
815 p.To.Type = obj.TYPE_BRANCH
816 p.Mark |= BRANCH
817 }
818
819
820
821
822 p = obj.Appendp(p, c.newprog)
823
824 p.As = add
825 p.From.Type = obj.TYPE_CONST
826 p.From.Offset = -offset
827 p.Reg = REGSP
828 p.To.Type = obj.TYPE_REG
829 p.To.Reg = REG_R2
830
831 p = obj.Appendp(p, c.newprog)
832 p.As = ASGTU
833 p.From.Type = obj.TYPE_REG
834 p.From.Reg = REG_R2
835 p.Reg = REG_R1
836 p.To.Type = obj.TYPE_REG
837 p.To.Reg = REG_R1
838 }
839
840
841 p = obj.Appendp(p, c.newprog)
842 q1 := p
843
844 p.As = ABNE
845 p.From.Type = obj.TYPE_REG
846 p.From.Reg = REG_R1
847 p.To.Type = obj.TYPE_BRANCH
848 p.Mark |= BRANCH
849
850
851 p = obj.Appendp(p, c.newprog)
852
853 p.As = mov
854 p.From.Type = obj.TYPE_REG
855 p.From.Reg = REGLINK
856 p.To.Type = obj.TYPE_REG
857 p.To.Reg = REG_R3
858 if q != nil {
859 q.To.SetTarget(p)
860 p.Mark |= LABEL
861 }
862
863 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
864
865
866 p = obj.Appendp(p, c.newprog)
867
868 p.As = AJAL
869 p.To.Type = obj.TYPE_BRANCH
870 if c.cursym.CFunc() {
871 p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
872 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
873 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
874 } else {
875 p.To.Sym = c.ctxt.Lookup("runtime.morestack")
876 }
877 p.Mark |= BRANCH
878
879 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
880
881
882 p = obj.Appendp(p, c.newprog)
883
884 p.As = AJMP
885 p.To.Type = obj.TYPE_BRANCH
886 p.To.SetTarget(startPred.Link)
887 startPred.Link.Mark |= LABEL
888 p.Mark |= BRANCH
889
890
891 p = obj.Appendp(p, c.newprog)
892
893 p.As = obj.ANOP
894 q1.To.SetTarget(p)
895
896 return p
897 }
898
899 func (c *ctxt0) addnop(p *obj.Prog) {
900 q := c.newprog()
901 q.As = ANOOP
902 q.Pos = p.Pos
903 q.Link = p.Link
904 p.Link = q
905 }
906
907 const (
908 E_HILO = 1 << 0
909 E_FCR = 1 << 1
910 E_MCR = 1 << 2
911 E_MEM = 1 << 3
912 E_MEMSP = 1 << 4
913 E_MEMSB = 1 << 5
914 ANYMEM = E_MEM | E_MEMSP | E_MEMSB
915
916 DELAY = BRANCH
917 )
918
919 type Dep struct {
920 ireg uint32
921 freg uint32
922 cc uint32
923 }
924
925 type Sch struct {
926 p obj.Prog
927 set Dep
928 used Dep
929 soffset int32
930 size uint8
931 nop uint8
932 comp bool
933 }
934
935 func (c *ctxt0) sched(p0, pe *obj.Prog) {
936 var sch [NSCHED]Sch
937
938
941 s := sch[:]
942 for p := p0; ; p = p.Link {
943 s[0].p = *p
944 c.markregused(&s[0])
945 if p == pe {
946 break
947 }
948 s = s[1:]
949 }
950 se := s
951
952 for i := cap(sch) - cap(se); i >= 0; i-- {
953 s = sch[i:]
954 if s[0].p.Mark&DELAY == 0 {
955 continue
956 }
957 if -cap(s) < -cap(se) {
958 if !conflict(&s[0], &s[1]) {
959 continue
960 }
961 }
962
963 var t []Sch
964 var j int
965 for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
966 t = sch[j:]
967 if t[0].comp {
968 if s[0].p.Mark&BRANCH != 0 {
969 continue
970 }
971 }
972 if t[0].p.Mark&DELAY != 0 {
973 if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
974 continue
975 }
976 }
977 for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
978 if c.depend(&u[0], &t[0]) {
979 continue
980 }
981 }
982 goto out2
983 }
984
985 if s[0].p.Mark&BRANCH != 0 {
986 s[0].nop = 1
987 }
988 continue
989
990 out2:
991
992 stmp := t[0]
993 copy(t[:i-j], t[1:i-j+1])
994 s[0] = stmp
995
996 if t[i-j-1].p.Mark&BRANCH != 0 {
997
998
999 t[i-j-1].p.Spadj += t[i-j].p.Spadj
1000 t[i-j].p.Spadj = 0
1001 }
1002
1003 i--
1004 }
1005
1006
1009 var p *obj.Prog
1010 var q *obj.Prog
1011 for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
1012 q = p.Link
1013 if q != s[0].p.Link {
1014 *p = s[0].p
1015 p.Link = q
1016 }
1017 for s[0].nop != 0 {
1018 s[0].nop--
1019 c.addnop(p)
1020 }
1021 }
1022 }
1023
1024 func (c *ctxt0) markregused(s *Sch) {
1025 p := &s.p
1026 s.comp = c.compound(p)
1027 s.nop = 0
1028 if s.comp {
1029 s.set.ireg |= 1 << (REGTMP - REG_R0)
1030 s.used.ireg |= 1 << (REGTMP - REG_R0)
1031 }
1032
1033 ar := 0
1034 ad := 0
1035 ld := 0
1036 sz := 20
1037
1038
1041 switch p.As {
1042 case obj.ATEXT:
1043 c.autosize = int32(p.To.Offset + 8)
1044 ad = 1
1045
1046 case AJAL:
1047 r := p.Reg
1048 if r == 0 {
1049 r = REGLINK
1050 }
1051 s.set.ireg |= 1 << uint(r-REG_R0)
1052 ar = 1
1053 ad = 1
1054
1055 case ABGEZAL,
1056 ABLTZAL:
1057 s.set.ireg |= 1 << (REGLINK - REG_R0)
1058 fallthrough
1059 case ABEQ,
1060 ABGEZ,
1061 ABGTZ,
1062 ABLEZ,
1063 ABLTZ,
1064 ABNE:
1065 ar = 1
1066 ad = 1
1067
1068 case ABFPT,
1069 ABFPF:
1070 ad = 1
1071 s.used.cc |= E_FCR
1072
1073 case ACMPEQD,
1074 ACMPEQF,
1075 ACMPGED,
1076 ACMPGEF,
1077 ACMPGTD,
1078 ACMPGTF:
1079 ar = 1
1080 s.set.cc |= E_FCR
1081 p.Mark |= FCMP
1082
1083 case AJMP:
1084 ar = 1
1085 ad = 1
1086
1087 case AMOVB,
1088 AMOVBU:
1089 sz = 1
1090 ld = 1
1091
1092 case AMOVH,
1093 AMOVHU:
1094 sz = 2
1095 ld = 1
1096
1097 case AMOVF,
1098 AMOVW,
1099 AMOVWL,
1100 AMOVWR:
1101 sz = 4
1102 ld = 1
1103
1104 case AMOVD,
1105 AMOVV,
1106 AMOVVL,
1107 AMOVVR:
1108 sz = 8
1109 ld = 1
1110
1111 case ADIV,
1112 ADIVU,
1113 AMUL,
1114 AMULU,
1115 AREM,
1116 AREMU,
1117 ADIVV,
1118 ADIVVU,
1119 AMULV,
1120 AMULVU,
1121 AREMV,
1122 AREMVU:
1123 s.set.cc = E_HILO
1124 fallthrough
1125 case AADD,
1126 AADDU,
1127 AADDV,
1128 AADDVU,
1129 AAND,
1130 ANOR,
1131 AOR,
1132 ASGT,
1133 ASGTU,
1134 ASLL,
1135 ASRA,
1136 ASRL,
1137 ASLLV,
1138 ASRAV,
1139 ASRLV,
1140 ASUB,
1141 ASUBU,
1142 ASUBV,
1143 ASUBVU,
1144 AXOR,
1145
1146 AADDD,
1147 AADDF,
1148 AADDW,
1149 ASUBD,
1150 ASUBF,
1151 ASUBW,
1152 AMULF,
1153 AMULD,
1154 AMULW,
1155 ADIVF,
1156 ADIVD,
1157 ADIVW:
1158 if p.Reg == 0 {
1159 if p.To.Type == obj.TYPE_REG {
1160 p.Reg = p.To.Reg
1161 }
1162
1163
1164 }
1165 }
1166
1167
1170 cls := int(p.To.Class)
1171 if cls == 0 {
1172 cls = c.aclass(&p.To) + 1
1173 p.To.Class = int8(cls)
1174 }
1175 cls--
1176 switch cls {
1177 default:
1178 fmt.Printf("unknown class %d %v\n", cls, p)
1179
1180 case C_ZCON,
1181 C_SCON,
1182 C_ADD0CON,
1183 C_AND0CON,
1184 C_ADDCON,
1185 C_ANDCON,
1186 C_UCON,
1187 C_LCON,
1188 C_NONE,
1189 C_SBRA,
1190 C_LBRA,
1191 C_ADDR,
1192 C_TEXTSIZE:
1193 break
1194
1195 case C_HI,
1196 C_LO:
1197 s.set.cc |= E_HILO
1198
1199 case C_FCREG:
1200 s.set.cc |= E_FCR
1201
1202 case C_MREG:
1203 s.set.cc |= E_MCR
1204
1205 case C_ZOREG,
1206 C_SOREG,
1207 C_LOREG:
1208 cls = int(p.To.Reg)
1209 s.used.ireg |= 1 << uint(cls-REG_R0)
1210 if ad != 0 {
1211 break
1212 }
1213 s.size = uint8(sz)
1214 s.soffset = c.regoff(&p.To)
1215
1216 m := uint32(ANYMEM)
1217 if cls == REGSB {
1218 m = E_MEMSB
1219 }
1220 if cls == REGSP {
1221 m = E_MEMSP
1222 }
1223
1224 if ar != 0 {
1225 s.used.cc |= m
1226 } else {
1227 s.set.cc |= m
1228 }
1229
1230 case C_SACON,
1231 C_LACON:
1232 s.used.ireg |= 1 << (REGSP - REG_R0)
1233
1234 case C_SECON,
1235 C_LECON:
1236 s.used.ireg |= 1 << (REGSB - REG_R0)
1237
1238 case C_REG:
1239 if ar != 0 {
1240 s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
1241 } else {
1242 s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
1243 }
1244
1245 case C_FREG:
1246 if ar != 0 {
1247 s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
1248 } else {
1249 s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
1250 }
1251 if ld != 0 && p.From.Type == obj.TYPE_REG {
1252 p.Mark |= LOAD
1253 }
1254
1255 case C_SAUTO,
1256 C_LAUTO:
1257 s.used.ireg |= 1 << (REGSP - REG_R0)
1258 if ad != 0 {
1259 break
1260 }
1261 s.size = uint8(sz)
1262 s.soffset = c.regoff(&p.To)
1263
1264 if ar != 0 {
1265 s.used.cc |= E_MEMSP
1266 } else {
1267 s.set.cc |= E_MEMSP
1268 }
1269
1270 case C_SEXT,
1271 C_LEXT:
1272 s.used.ireg |= 1 << (REGSB - REG_R0)
1273 if ad != 0 {
1274 break
1275 }
1276 s.size = uint8(sz)
1277 s.soffset = c.regoff(&p.To)
1278
1279 if ar != 0 {
1280 s.used.cc |= E_MEMSB
1281 } else {
1282 s.set.cc |= E_MEMSB
1283 }
1284 }
1285
1286
1289 cls = int(p.From.Class)
1290 if cls == 0 {
1291 cls = c.aclass(&p.From) + 1
1292 p.From.Class = int8(cls)
1293 }
1294 cls--
1295 switch cls {
1296 default:
1297 fmt.Printf("unknown class %d %v\n", cls, p)
1298
1299 case C_ZCON,
1300 C_SCON,
1301 C_ADD0CON,
1302 C_AND0CON,
1303 C_ADDCON,
1304 C_ANDCON,
1305 C_UCON,
1306 C_LCON,
1307 C_NONE,
1308 C_SBRA,
1309 C_LBRA,
1310 C_ADDR,
1311 C_TEXTSIZE:
1312 break
1313
1314 case C_HI,
1315 C_LO:
1316 s.used.cc |= E_HILO
1317
1318 case C_FCREG:
1319 s.used.cc |= E_FCR
1320
1321 case C_MREG:
1322 s.used.cc |= E_MCR
1323
1324 case C_ZOREG,
1325 C_SOREG,
1326 C_LOREG:
1327 cls = int(p.From.Reg)
1328 s.used.ireg |= 1 << uint(cls-REG_R0)
1329 if ld != 0 {
1330 p.Mark |= LOAD
1331 }
1332 s.size = uint8(sz)
1333 s.soffset = c.regoff(&p.From)
1334
1335 m := uint32(ANYMEM)
1336 if cls == REGSB {
1337 m = E_MEMSB
1338 }
1339 if cls == REGSP {
1340 m = E_MEMSP
1341 }
1342
1343 s.used.cc |= m
1344
1345 case C_SACON,
1346 C_LACON:
1347 cls = int(p.From.Reg)
1348 if cls == 0 {
1349 cls = REGSP
1350 }
1351 s.used.ireg |= 1 << uint(cls-REG_R0)
1352
1353 case C_SECON,
1354 C_LECON:
1355 s.used.ireg |= 1 << (REGSB - REG_R0)
1356
1357 case C_REG:
1358 s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
1359
1360 case C_FREG:
1361 s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
1362 if ld != 0 && p.To.Type == obj.TYPE_REG {
1363 p.Mark |= LOAD
1364 }
1365
1366 case C_SAUTO,
1367 C_LAUTO:
1368 s.used.ireg |= 1 << (REGSP - REG_R0)
1369 if ld != 0 {
1370 p.Mark |= LOAD
1371 }
1372 if ad != 0 {
1373 break
1374 }
1375 s.size = uint8(sz)
1376 s.soffset = c.regoff(&p.From)
1377
1378 s.used.cc |= E_MEMSP
1379
1380 case C_SEXT:
1381 case C_LEXT:
1382 s.used.ireg |= 1 << (REGSB - REG_R0)
1383 if ld != 0 {
1384 p.Mark |= LOAD
1385 }
1386 if ad != 0 {
1387 break
1388 }
1389 s.size = uint8(sz)
1390 s.soffset = c.regoff(&p.From)
1391
1392 s.used.cc |= E_MEMSB
1393 }
1394
1395 cls = int(p.Reg)
1396 if cls != 0 {
1397 if REG_F0 <= cls && cls <= REG_F31 {
1398 s.used.freg |= 1 << uint(cls-REG_F0)
1399 } else {
1400 s.used.ireg |= 1 << uint(cls-REG_R0)
1401 }
1402 }
1403 s.set.ireg &^= (1 << (REGZERO - REG_R0))
1404 }
1405
1406
1410 func (c *ctxt0) depend(sa, sb *Sch) bool {
1411 if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
1412 return true
1413 }
1414 if sb.set.ireg&sa.used.ireg != 0 {
1415 return true
1416 }
1417
1418 if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
1419 return true
1420 }
1421 if sb.set.freg&sa.used.freg != 0 {
1422 return true
1423 }
1424
1425
1430 if sa.used.cc&sb.used.cc&E_MEM != 0 {
1431 if sa.p.Reg == sb.p.Reg {
1432 if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
1433 return true
1434 }
1435 }
1436 }
1437
1438 x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
1439 if x != 0 {
1440
1445 if x != E_MEMSP && x != E_MEMSB {
1446 return true
1447 }
1448 x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
1449 if x&E_MEM != 0 {
1450 return true
1451 }
1452 if offoverlap(sa, sb) {
1453 return true
1454 }
1455 }
1456
1457 return false
1458 }
1459
1460 func offoverlap(sa, sb *Sch) bool {
1461 if sa.soffset < sb.soffset {
1462 if sa.soffset+int32(sa.size) > sb.soffset {
1463 return true
1464 }
1465 return false
1466 }
1467 if sb.soffset+int32(sb.size) > sa.soffset {
1468 return true
1469 }
1470 return false
1471 }
1472
1473
1478 func conflict(sa, sb *Sch) bool {
1479 if sa.set.ireg&sb.used.ireg != 0 {
1480 return true
1481 }
1482 if sa.set.freg&sb.used.freg != 0 {
1483 return true
1484 }
1485 if sa.set.cc&sb.used.cc != 0 {
1486 return true
1487 }
1488 return false
1489 }
1490
1491 func (c *ctxt0) compound(p *obj.Prog) bool {
1492 o := c.oplook(p)
1493 if o.size != 4 {
1494 return true
1495 }
1496 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
1497 return true
1498 }
1499 return false
1500 }
1501
1502 var Linkmips64 = obj.LinkArch{
1503 Arch: sys.ArchMIPS64,
1504 Init: buildop,
1505 Preprocess: preprocess,
1506 Assemble: span0,
1507 Progedit: progedit,
1508 DWARFRegisters: MIPSDWARFRegisters,
1509 }
1510
1511 var Linkmips64le = obj.LinkArch{
1512 Arch: sys.ArchMIPS64LE,
1513 Init: buildop,
1514 Preprocess: preprocess,
1515 Assemble: span0,
1516 Progedit: progedit,
1517 DWARFRegisters: MIPSDWARFRegisters,
1518 }
1519
1520 var Linkmips = obj.LinkArch{
1521 Arch: sys.ArchMIPS,
1522 Init: buildop,
1523 Preprocess: preprocess,
1524 Assemble: span0,
1525 Progedit: progedit,
1526 DWARFRegisters: MIPSDWARFRegisters,
1527 }
1528
1529 var Linkmipsle = obj.LinkArch{
1530 Arch: sys.ArchMIPSLE,
1531 Init: buildop,
1532 Preprocess: preprocess,
1533 Assemble: span0,
1534 Progedit: progedit,
1535 DWARFRegisters: MIPSDWARFRegisters,
1536 }
1537
View as plain text