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/objabi"
35 "cmd/internal/sys"
36 "encoding/binary"
37 "fmt"
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.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.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.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 if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367 q = obj.Appendp(q, newprog)
368
369 q.As = mov
370 q.From.Type = obj.TYPE_MEM
371 q.From.Reg = REGG
372 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
373 q.To.Type = obj.TYPE_REG
374 q.To.Reg = REG_R1
375
376 q = obj.Appendp(q, newprog)
377 q.As = ABEQ
378 q.From.Type = obj.TYPE_REG
379 q.From.Reg = REG_R1
380 q.To.Type = obj.TYPE_BRANCH
381 q.Mark |= BRANCH
382 p1 = q
383
384 q = obj.Appendp(q, newprog)
385 q.As = mov
386 q.From.Type = obj.TYPE_MEM
387 q.From.Reg = REG_R1
388 q.From.Offset = 0
389 q.To.Type = obj.TYPE_REG
390 q.To.Reg = REG_R2
391
392 q = obj.Appendp(q, newprog)
393 q.As = add
394 q.From.Type = obj.TYPE_CONST
395 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
396 q.Reg = REGSP
397 q.To.Type = obj.TYPE_REG
398 q.To.Reg = REG_R3
399
400 q = obj.Appendp(q, newprog)
401 q.As = ABNE
402 q.From.Type = obj.TYPE_REG
403 q.From.Reg = REG_R2
404 q.Reg = REG_R3
405 q.To.Type = obj.TYPE_BRANCH
406 q.Mark |= BRANCH
407 p2 = q
408
409 q = obj.Appendp(q, newprog)
410 q.As = add
411 q.From.Type = obj.TYPE_CONST
412 q.From.Offset = ctxt.FixedFrameSize()
413 q.Reg = REGSP
414 q.To.Type = obj.TYPE_REG
415 q.To.Reg = REG_R2
416
417 q = obj.Appendp(q, newprog)
418 q.As = mov
419 q.From.Type = obj.TYPE_REG
420 q.From.Reg = REG_R2
421 q.To.Type = obj.TYPE_MEM
422 q.To.Reg = REG_R1
423 q.To.Offset = 0
424
425 q = obj.Appendp(q, newprog)
426
427 q.As = obj.ANOP
428 p1.To.SetTarget(q)
429 p2.To.SetTarget(q)
430 }
431
432 case ARET:
433 if p.From.Type == obj.TYPE_CONST {
434 ctxt.Diag("using BECOME (%v) is not supported!", p)
435 break
436 }
437
438 retSym := p.To.Sym
439 p.To.Name = obj.NAME_NONE
440 p.To.Sym = nil
441
442 if c.cursym.Func().Text.Mark&LEAF != 0 {
443 if autosize == 0 {
444 p.As = AJMP
445 p.From = obj.Addr{}
446 if retSym != nil {
447 p.To.Type = obj.TYPE_BRANCH
448 p.To.Name = obj.NAME_EXTERN
449 p.To.Sym = retSym
450 } else {
451 p.To.Type = obj.TYPE_MEM
452 p.To.Reg = REGLINK
453 p.To.Offset = 0
454 }
455 p.Mark |= BRANCH
456 break
457 }
458
459 p.As = add
460 p.From.Type = obj.TYPE_CONST
461 p.From.Offset = int64(autosize)
462 p.To.Type = obj.TYPE_REG
463 p.To.Reg = REGSP
464 p.Spadj = -autosize
465
466 q = c.newprog()
467 q.As = AJMP
468 q.Pos = p.Pos
469 if retSym != nil {
470 q.To.Type = obj.TYPE_BRANCH
471 q.To.Name = obj.NAME_EXTERN
472 q.To.Sym = retSym
473 } else {
474 q.To.Type = obj.TYPE_MEM
475 q.To.Reg = REGLINK
476 q.To.Offset = 0
477 }
478 q.Mark |= BRANCH
479 q.Spadj = +autosize
480
481 q.Link = p.Link
482 p.Link = q
483 break
484 }
485
486 p.As = mov
487 p.From.Type = obj.TYPE_MEM
488 p.From.Offset = 0
489 p.From.Reg = REGSP
490 p.To.Type = obj.TYPE_REG
491 p.To.Reg = REGLINK
492
493 if autosize != 0 {
494 q = c.newprog()
495 q.As = add
496 q.Pos = p.Pos
497 q.From.Type = obj.TYPE_CONST
498 q.From.Offset = int64(autosize)
499 q.To.Type = obj.TYPE_REG
500 q.To.Reg = REGSP
501 q.Spadj = -autosize
502
503 q.Link = p.Link
504 p.Link = q
505 }
506
507 q1 = c.newprog()
508 q1.As = AJMP
509 q1.Pos = p.Pos
510 if retSym != nil {
511 q1.To.Type = obj.TYPE_BRANCH
512 q1.To.Name = obj.NAME_EXTERN
513 q1.To.Sym = retSym
514 } else {
515 q1.To.Type = obj.TYPE_MEM
516 q1.To.Offset = 0
517 q1.To.Reg = REGLINK
518 }
519 q1.Mark |= BRANCH
520 q1.Spadj = +autosize
521
522 q1.Link = q.Link
523 q.Link = q1
524
525 case AADD,
526 AADDU,
527 AADDV,
528 AADDVU:
529 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
530 p.Spadj = int32(-p.From.Offset)
531 }
532
533 case obj.AGETCALLERPC:
534 if cursym.Leaf() {
535
536 p.As = mov
537 p.From.Type = obj.TYPE_REG
538 p.From.Reg = REGLINK
539 } else {
540
541 p.As = mov
542 p.From.Type = obj.TYPE_MEM
543 p.From.Reg = REGSP
544 }
545 }
546
547 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
548 f := c.cursym.Func()
549 if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
550 c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
551 if ctxt.Debugvlog || !ctxt.IsAsm {
552 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
553 if !ctxt.IsAsm {
554 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
555 ctxt.DiagFlush()
556 log.Fatalf("bad SPWRITE")
557 }
558 }
559 }
560 }
561 }
562
563 if c.ctxt.Arch.Family == sys.MIPS {
564
565 for p = c.cursym.Func().Text; p != nil; p = p1 {
566 p1 = p.Link
567
568 if p.As != AMOVD {
569 continue
570 }
571 if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
572 continue
573 }
574
575 p.As = AMOVF
576 q = c.newprog()
577 *q = *p
578 q.Link = p.Link
579 p.Link = q
580 p1 = q.Link
581
582 var addrOff int64
583 if c.ctxt.Arch.ByteOrder == binary.BigEndian {
584 addrOff = 4
585 }
586 if p.From.Type == obj.TYPE_MEM {
587 reg := REG_F0 + (p.To.Reg-REG_F0)&^1
588 p.To.Reg = reg
589 q.To.Reg = reg + 1
590 p.From.Offset += addrOff
591 q.From.Offset += 4 - addrOff
592 } else if p.To.Type == obj.TYPE_MEM {
593 reg := REG_F0 + (p.From.Reg-REG_F0)&^1
594 p.From.Reg = reg
595 q.From.Reg = reg + 1
596 p.To.Offset += addrOff
597 q.To.Offset += 4 - addrOff
598 }
599 }
600 }
601
602 if nosched {
603
604
605 for p = c.cursym.Func().Text; p != nil; p = p.Link {
606 if p.Mark&BRANCH != 0 {
607 c.addnop(p)
608 }
609 }
610 return
611 }
612
613
614 q = nil
615 q1 = c.cursym.Func().Text
616 o := 0
617 for p = c.cursym.Func().Text; p != nil; p = p1 {
618 p1 = p.Link
619 o++
620 if p.Mark&NOSCHED != 0 {
621 if q1 != p {
622 c.sched(q1, q)
623 }
624 for ; p != nil; p = p.Link {
625 if p.Mark&NOSCHED == 0 {
626 break
627 }
628 q = p
629 }
630 p1 = p
631 q1 = p
632 o = 0
633 continue
634 }
635 if p.Mark&(LABEL|SYNC) != 0 {
636 if q1 != p {
637 c.sched(q1, q)
638 }
639 q1 = p
640 o = 1
641 }
642 if p.Mark&(BRANCH|SYNC) != 0 {
643 c.sched(q1, p)
644 q1 = p1
645 o = 0
646 }
647 if o >= NSCHED {
648 c.sched(q1, p)
649 q1 = p1
650 o = 0
651 }
652 q = p
653 }
654 }
655
656 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
657 var mov, add obj.As
658
659 if c.ctxt.Arch.Family == sys.MIPS64 {
660 add = AADDV
661 mov = AMOVV
662 } else {
663 add = AADDU
664 mov = AMOVW
665 }
666
667 if c.ctxt.Flag_maymorestack != "" {
668
669 frameSize := 2 * c.ctxt.Arch.PtrSize
670
671 p = c.ctxt.StartUnsafePoint(p, c.newprog)
672
673
674 p = obj.Appendp(p, c.newprog)
675 p.As = mov
676 p.From.Type = obj.TYPE_REG
677 p.From.Reg = REGLINK
678 p.To.Type = obj.TYPE_MEM
679 p.To.Offset = int64(-frameSize)
680 p.To.Reg = REGSP
681
682
683 p = obj.Appendp(p, c.newprog)
684 p.As = mov
685 p.From.Type = obj.TYPE_REG
686 p.From.Reg = REGCTXT
687 p.To.Type = obj.TYPE_MEM
688 p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
689 p.To.Reg = REGSP
690
691
692 p = obj.Appendp(p, c.newprog)
693 p.As = add
694 p.From.Type = obj.TYPE_CONST
695 p.From.Offset = int64(-frameSize)
696 p.To.Type = obj.TYPE_REG
697 p.To.Reg = REGSP
698 p.Spadj = int32(frameSize)
699
700
701 p = obj.Appendp(p, c.newprog)
702 p.As = AJAL
703 p.To.Type = obj.TYPE_BRANCH
704
705 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
706 p.Mark |= BRANCH
707
708
709
710
711 p = obj.Appendp(p, c.newprog)
712 p.As = mov
713 p.From.Type = obj.TYPE_MEM
714 p.From.Offset = 0
715 p.From.Reg = REGSP
716 p.To.Type = obj.TYPE_REG
717 p.To.Reg = REGLINK
718
719
720 p = obj.Appendp(p, c.newprog)
721 p.As = mov
722 p.From.Type = obj.TYPE_MEM
723 p.From.Offset = int64(c.ctxt.Arch.PtrSize)
724 p.From.Reg = REGSP
725 p.To.Type = obj.TYPE_REG
726 p.To.Reg = REGCTXT
727
728
729 p = obj.Appendp(p, c.newprog)
730 p.As = add
731 p.From.Type = obj.TYPE_CONST
732 p.From.Offset = int64(frameSize)
733 p.To.Type = obj.TYPE_REG
734 p.To.Reg = REGSP
735 p.Spadj = int32(-frameSize)
736
737 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
738 }
739
740
741 startPred := p
742
743
744 p = obj.Appendp(p, c.newprog)
745
746 p.As = mov
747 p.From.Type = obj.TYPE_MEM
748 p.From.Reg = REGG
749 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
750 if c.cursym.CFunc() {
751 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
752 }
753 p.To.Type = obj.TYPE_REG
754 p.To.Reg = REG_R1
755
756
757
758
759
760 p = c.ctxt.StartUnsafePoint(p, c.newprog)
761
762 var q *obj.Prog
763 if framesize <= objabi.StackSmall {
764
765
766 p = obj.Appendp(p, c.newprog)
767
768 p.As = ASGTU
769 p.From.Type = obj.TYPE_REG
770 p.From.Reg = REGSP
771 p.Reg = REG_R1
772 p.To.Type = obj.TYPE_REG
773 p.To.Reg = REG_R1
774 } else {
775
776 offset := int64(framesize) - objabi.StackSmall
777 if framesize > objabi.StackBig {
778
779
780
781
782
783
784
785
786
787
788 p = obj.Appendp(p, c.newprog)
789 p.As = ASGTU
790 p.From.Type = obj.TYPE_CONST
791 p.From.Offset = offset
792 p.Reg = REGSP
793 p.To.Type = obj.TYPE_REG
794 p.To.Reg = REG_R2
795
796 p = obj.Appendp(p, c.newprog)
797 q = p
798 p.As = ABNE
799 p.From.Type = obj.TYPE_REG
800 p.From.Reg = REG_R2
801 p.To.Type = obj.TYPE_BRANCH
802 p.Mark |= BRANCH
803 }
804
805
806
807
808 p = obj.Appendp(p, c.newprog)
809
810 p.As = add
811 p.From.Type = obj.TYPE_CONST
812 p.From.Offset = -offset
813 p.Reg = REGSP
814 p.To.Type = obj.TYPE_REG
815 p.To.Reg = REG_R2
816
817 p = obj.Appendp(p, c.newprog)
818 p.As = ASGTU
819 p.From.Type = obj.TYPE_REG
820 p.From.Reg = REG_R2
821 p.Reg = REG_R1
822 p.To.Type = obj.TYPE_REG
823 p.To.Reg = REG_R1
824 }
825
826
827 p = obj.Appendp(p, c.newprog)
828 q1 := p
829
830 p.As = ABNE
831 p.From.Type = obj.TYPE_REG
832 p.From.Reg = REG_R1
833 p.To.Type = obj.TYPE_BRANCH
834 p.Mark |= BRANCH
835
836
837 p = obj.Appendp(p, c.newprog)
838
839 p.As = mov
840 p.From.Type = obj.TYPE_REG
841 p.From.Reg = REGLINK
842 p.To.Type = obj.TYPE_REG
843 p.To.Reg = REG_R3
844 if q != nil {
845 q.To.SetTarget(p)
846 p.Mark |= LABEL
847 }
848
849 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
850
851
852 p = obj.Appendp(p, c.newprog)
853
854 p.As = AJAL
855 p.To.Type = obj.TYPE_BRANCH
856 if c.cursym.CFunc() {
857 p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
858 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
859 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
860 } else {
861 p.To.Sym = c.ctxt.Lookup("runtime.morestack")
862 }
863 p.Mark |= BRANCH
864
865 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
866
867
868 p = obj.Appendp(p, c.newprog)
869
870 p.As = AJMP
871 p.To.Type = obj.TYPE_BRANCH
872 p.To.SetTarget(startPred.Link)
873 startPred.Link.Mark |= LABEL
874 p.Mark |= BRANCH
875
876
877 p = obj.Appendp(p, c.newprog)
878
879 p.As = obj.ANOP
880 q1.To.SetTarget(p)
881
882 return p
883 }
884
885 func (c *ctxt0) addnop(p *obj.Prog) {
886 q := c.newprog()
887 q.As = ANOOP
888 q.Pos = p.Pos
889 q.Link = p.Link
890 p.Link = q
891 }
892
893 const (
894 E_HILO = 1 << 0
895 E_FCR = 1 << 1
896 E_MCR = 1 << 2
897 E_MEM = 1 << 3
898 E_MEMSP = 1 << 4
899 E_MEMSB = 1 << 5
900 ANYMEM = E_MEM | E_MEMSP | E_MEMSB
901
902 DELAY = BRANCH
903 )
904
905 type Dep struct {
906 ireg uint32
907 freg uint32
908 cc uint32
909 }
910
911 type Sch struct {
912 p obj.Prog
913 set Dep
914 used Dep
915 soffset int32
916 size uint8
917 nop uint8
918 comp bool
919 }
920
921 func (c *ctxt0) sched(p0, pe *obj.Prog) {
922 var sch [NSCHED]Sch
923
924
927 s := sch[:]
928 for p := p0; ; p = p.Link {
929 s[0].p = *p
930 c.markregused(&s[0])
931 if p == pe {
932 break
933 }
934 s = s[1:]
935 }
936 se := s
937
938 for i := cap(sch) - cap(se); i >= 0; i-- {
939 s = sch[i:]
940 if s[0].p.Mark&DELAY == 0 {
941 continue
942 }
943 if -cap(s) < -cap(se) {
944 if !conflict(&s[0], &s[1]) {
945 continue
946 }
947 }
948
949 var t []Sch
950 var j int
951 for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
952 t = sch[j:]
953 if t[0].comp {
954 if s[0].p.Mark&BRANCH != 0 {
955 continue
956 }
957 }
958 if t[0].p.Mark&DELAY != 0 {
959 if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
960 continue
961 }
962 }
963 for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
964 if c.depend(&u[0], &t[0]) {
965 continue
966 }
967 }
968 goto out2
969 }
970
971 if s[0].p.Mark&BRANCH != 0 {
972 s[0].nop = 1
973 }
974 continue
975
976 out2:
977
978 stmp := t[0]
979 copy(t[:i-j], t[1:i-j+1])
980 s[0] = stmp
981
982 if t[i-j-1].p.Mark&BRANCH != 0 {
983
984
985 t[i-j-1].p.Spadj += t[i-j].p.Spadj
986 t[i-j].p.Spadj = 0
987 }
988
989 i--
990 }
991
992
995 var p *obj.Prog
996 var q *obj.Prog
997 for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
998 q = p.Link
999 if q != s[0].p.Link {
1000 *p = s[0].p
1001 p.Link = q
1002 }
1003 for s[0].nop != 0 {
1004 s[0].nop--
1005 c.addnop(p)
1006 }
1007 }
1008 }
1009
1010 func (c *ctxt0) markregused(s *Sch) {
1011 p := &s.p
1012 s.comp = c.compound(p)
1013 s.nop = 0
1014 if s.comp {
1015 s.set.ireg |= 1 << (REGTMP - REG_R0)
1016 s.used.ireg |= 1 << (REGTMP - REG_R0)
1017 }
1018
1019 ar := 0
1020 ad := 0
1021 ld := 0
1022 sz := 20
1023
1024
1027 switch p.As {
1028 case obj.ATEXT:
1029 c.autosize = int32(p.To.Offset + 8)
1030 ad = 1
1031
1032 case AJAL:
1033 r := p.Reg
1034 if r == 0 {
1035 r = REGLINK
1036 }
1037 s.set.ireg |= 1 << uint(r-REG_R0)
1038 ar = 1
1039 ad = 1
1040
1041 case ABGEZAL,
1042 ABLTZAL:
1043 s.set.ireg |= 1 << (REGLINK - REG_R0)
1044 fallthrough
1045 case ABEQ,
1046 ABGEZ,
1047 ABGTZ,
1048 ABLEZ,
1049 ABLTZ,
1050 ABNE:
1051 ar = 1
1052 ad = 1
1053
1054 case ABFPT,
1055 ABFPF:
1056 ad = 1
1057 s.used.cc |= E_FCR
1058
1059 case ACMPEQD,
1060 ACMPEQF,
1061 ACMPGED,
1062 ACMPGEF,
1063 ACMPGTD,
1064 ACMPGTF:
1065 ar = 1
1066 s.set.cc |= E_FCR
1067 p.Mark |= FCMP
1068
1069 case AJMP:
1070 ar = 1
1071 ad = 1
1072
1073 case AMOVB,
1074 AMOVBU:
1075 sz = 1
1076 ld = 1
1077
1078 case AMOVH,
1079 AMOVHU:
1080 sz = 2
1081 ld = 1
1082
1083 case AMOVF,
1084 AMOVW,
1085 AMOVWL,
1086 AMOVWR:
1087 sz = 4
1088 ld = 1
1089
1090 case AMOVD,
1091 AMOVV,
1092 AMOVVL,
1093 AMOVVR:
1094 sz = 8
1095 ld = 1
1096
1097 case ADIV,
1098 ADIVU,
1099 AMUL,
1100 AMULU,
1101 AREM,
1102 AREMU,
1103 ADIVV,
1104 ADIVVU,
1105 AMULV,
1106 AMULVU,
1107 AREMV,
1108 AREMVU:
1109 s.set.cc = E_HILO
1110 fallthrough
1111 case AADD,
1112 AADDU,
1113 AADDV,
1114 AADDVU,
1115 AAND,
1116 ANOR,
1117 AOR,
1118 ASGT,
1119 ASGTU,
1120 ASLL,
1121 ASRA,
1122 ASRL,
1123 ASLLV,
1124 ASRAV,
1125 ASRLV,
1126 ASUB,
1127 ASUBU,
1128 ASUBV,
1129 ASUBVU,
1130 AXOR,
1131
1132 AADDD,
1133 AADDF,
1134 AADDW,
1135 ASUBD,
1136 ASUBF,
1137 ASUBW,
1138 AMULF,
1139 AMULD,
1140 AMULW,
1141 ADIVF,
1142 ADIVD,
1143 ADIVW:
1144 if p.Reg == 0 {
1145 if p.To.Type == obj.TYPE_REG {
1146 p.Reg = p.To.Reg
1147 }
1148
1149
1150 }
1151 }
1152
1153
1156 cls := int(p.To.Class)
1157 if cls == 0 {
1158 cls = c.aclass(&p.To) + 1
1159 p.To.Class = int8(cls)
1160 }
1161 cls--
1162 switch cls {
1163 default:
1164 fmt.Printf("unknown class %d %v\n", cls, p)
1165
1166 case C_ZCON,
1167 C_SCON,
1168 C_ADD0CON,
1169 C_AND0CON,
1170 C_ADDCON,
1171 C_ANDCON,
1172 C_UCON,
1173 C_LCON,
1174 C_NONE,
1175 C_SBRA,
1176 C_LBRA,
1177 C_ADDR,
1178 C_TEXTSIZE:
1179 break
1180
1181 case C_HI,
1182 C_LO:
1183 s.set.cc |= E_HILO
1184
1185 case C_FCREG:
1186 s.set.cc |= E_FCR
1187
1188 case C_MREG:
1189 s.set.cc |= E_MCR
1190
1191 case C_ZOREG,
1192 C_SOREG,
1193 C_LOREG:
1194 cls = int(p.To.Reg)
1195 s.used.ireg |= 1 << uint(cls-REG_R0)
1196 if ad != 0 {
1197 break
1198 }
1199 s.size = uint8(sz)
1200 s.soffset = c.regoff(&p.To)
1201
1202 m := uint32(ANYMEM)
1203 if cls == REGSB {
1204 m = E_MEMSB
1205 }
1206 if cls == REGSP {
1207 m = E_MEMSP
1208 }
1209
1210 if ar != 0 {
1211 s.used.cc |= m
1212 } else {
1213 s.set.cc |= m
1214 }
1215
1216 case C_SACON,
1217 C_LACON:
1218 s.used.ireg |= 1 << (REGSP - REG_R0)
1219
1220 case C_SECON,
1221 C_LECON:
1222 s.used.ireg |= 1 << (REGSB - REG_R0)
1223
1224 case C_REG:
1225 if ar != 0 {
1226 s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
1227 } else {
1228 s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
1229 }
1230
1231 case C_FREG:
1232 if ar != 0 {
1233 s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
1234 } else {
1235 s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
1236 }
1237 if ld != 0 && p.From.Type == obj.TYPE_REG {
1238 p.Mark |= LOAD
1239 }
1240
1241 case C_SAUTO,
1242 C_LAUTO:
1243 s.used.ireg |= 1 << (REGSP - REG_R0)
1244 if ad != 0 {
1245 break
1246 }
1247 s.size = uint8(sz)
1248 s.soffset = c.regoff(&p.To)
1249
1250 if ar != 0 {
1251 s.used.cc |= E_MEMSP
1252 } else {
1253 s.set.cc |= E_MEMSP
1254 }
1255
1256 case C_SEXT,
1257 C_LEXT:
1258 s.used.ireg |= 1 << (REGSB - REG_R0)
1259 if ad != 0 {
1260 break
1261 }
1262 s.size = uint8(sz)
1263 s.soffset = c.regoff(&p.To)
1264
1265 if ar != 0 {
1266 s.used.cc |= E_MEMSB
1267 } else {
1268 s.set.cc |= E_MEMSB
1269 }
1270 }
1271
1272
1275 cls = int(p.From.Class)
1276 if cls == 0 {
1277 cls = c.aclass(&p.From) + 1
1278 p.From.Class = int8(cls)
1279 }
1280 cls--
1281 switch cls {
1282 default:
1283 fmt.Printf("unknown class %d %v\n", cls, p)
1284
1285 case C_ZCON,
1286 C_SCON,
1287 C_ADD0CON,
1288 C_AND0CON,
1289 C_ADDCON,
1290 C_ANDCON,
1291 C_UCON,
1292 C_LCON,
1293 C_NONE,
1294 C_SBRA,
1295 C_LBRA,
1296 C_ADDR,
1297 C_TEXTSIZE:
1298 break
1299
1300 case C_HI,
1301 C_LO:
1302 s.used.cc |= E_HILO
1303
1304 case C_FCREG:
1305 s.used.cc |= E_FCR
1306
1307 case C_MREG:
1308 s.used.cc |= E_MCR
1309
1310 case C_ZOREG,
1311 C_SOREG,
1312 C_LOREG:
1313 cls = int(p.From.Reg)
1314 s.used.ireg |= 1 << uint(cls-REG_R0)
1315 if ld != 0 {
1316 p.Mark |= LOAD
1317 }
1318 s.size = uint8(sz)
1319 s.soffset = c.regoff(&p.From)
1320
1321 m := uint32(ANYMEM)
1322 if cls == REGSB {
1323 m = E_MEMSB
1324 }
1325 if cls == REGSP {
1326 m = E_MEMSP
1327 }
1328
1329 s.used.cc |= m
1330
1331 case C_SACON,
1332 C_LACON:
1333 cls = int(p.From.Reg)
1334 if cls == 0 {
1335 cls = REGSP
1336 }
1337 s.used.ireg |= 1 << uint(cls-REG_R0)
1338
1339 case C_SECON,
1340 C_LECON:
1341 s.used.ireg |= 1 << (REGSB - REG_R0)
1342
1343 case C_REG:
1344 s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
1345
1346 case C_FREG:
1347 s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
1348 if ld != 0 && p.To.Type == obj.TYPE_REG {
1349 p.Mark |= LOAD
1350 }
1351
1352 case C_SAUTO,
1353 C_LAUTO:
1354 s.used.ireg |= 1 << (REGSP - REG_R0)
1355 if ld != 0 {
1356 p.Mark |= LOAD
1357 }
1358 if ad != 0 {
1359 break
1360 }
1361 s.size = uint8(sz)
1362 s.soffset = c.regoff(&p.From)
1363
1364 s.used.cc |= E_MEMSP
1365
1366 case C_SEXT:
1367 case C_LEXT:
1368 s.used.ireg |= 1 << (REGSB - 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_MEMSB
1379 }
1380
1381 cls = int(p.Reg)
1382 if cls != 0 {
1383 if REG_F0 <= cls && cls <= REG_F31 {
1384 s.used.freg |= 1 << uint(cls-REG_F0)
1385 } else {
1386 s.used.ireg |= 1 << uint(cls-REG_R0)
1387 }
1388 }
1389 s.set.ireg &^= (1 << (REGZERO - REG_R0))
1390 }
1391
1392
1396 func (c *ctxt0) depend(sa, sb *Sch) bool {
1397 if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
1398 return true
1399 }
1400 if sb.set.ireg&sa.used.ireg != 0 {
1401 return true
1402 }
1403
1404 if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
1405 return true
1406 }
1407 if sb.set.freg&sa.used.freg != 0 {
1408 return true
1409 }
1410
1411
1416 if sa.used.cc&sb.used.cc&E_MEM != 0 {
1417 if sa.p.Reg == sb.p.Reg {
1418 if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
1419 return true
1420 }
1421 }
1422 }
1423
1424 x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
1425 if x != 0 {
1426
1431 if x != E_MEMSP && x != E_MEMSB {
1432 return true
1433 }
1434 x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
1435 if x&E_MEM != 0 {
1436 return true
1437 }
1438 if offoverlap(sa, sb) {
1439 return true
1440 }
1441 }
1442
1443 return false
1444 }
1445
1446 func offoverlap(sa, sb *Sch) bool {
1447 if sa.soffset < sb.soffset {
1448 if sa.soffset+int32(sa.size) > sb.soffset {
1449 return true
1450 }
1451 return false
1452 }
1453 if sb.soffset+int32(sb.size) > sa.soffset {
1454 return true
1455 }
1456 return false
1457 }
1458
1459
1464 func conflict(sa, sb *Sch) bool {
1465 if sa.set.ireg&sb.used.ireg != 0 {
1466 return true
1467 }
1468 if sa.set.freg&sb.used.freg != 0 {
1469 return true
1470 }
1471 if sa.set.cc&sb.used.cc != 0 {
1472 return true
1473 }
1474 return false
1475 }
1476
1477 func (c *ctxt0) compound(p *obj.Prog) bool {
1478 o := c.oplook(p)
1479 if o.size != 4 {
1480 return true
1481 }
1482 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
1483 return true
1484 }
1485 return false
1486 }
1487
1488 var Linkmips64 = obj.LinkArch{
1489 Arch: sys.ArchMIPS64,
1490 Init: buildop,
1491 Preprocess: preprocess,
1492 Assemble: span0,
1493 Progedit: progedit,
1494 DWARFRegisters: MIPSDWARFRegisters,
1495 }
1496
1497 var Linkmips64le = obj.LinkArch{
1498 Arch: sys.ArchMIPS64LE,
1499 Init: buildop,
1500 Preprocess: preprocess,
1501 Assemble: span0,
1502 Progedit: progedit,
1503 DWARFRegisters: MIPSDWARFRegisters,
1504 }
1505
1506 var Linkmips = obj.LinkArch{
1507 Arch: sys.ArchMIPS,
1508 Init: buildop,
1509 Preprocess: preprocess,
1510 Assemble: span0,
1511 Progedit: progedit,
1512 DWARFRegisters: MIPSDWARFRegisters,
1513 }
1514
1515 var Linkmipsle = obj.LinkArch{
1516 Arch: sys.ArchMIPSLE,
1517 Init: buildop,
1518 Preprocess: preprocess,
1519 Assemble: span0,
1520 Progedit: progedit,
1521 DWARFRegisters: MIPSDWARFRegisters,
1522 }
1523
View as plain text