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