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