1
2
3
4
5 package loong64
6
7 import (
8 "cmd/internal/obj"
9 "cmd/internal/objabi"
10 "cmd/internal/src"
11 "cmd/internal/sys"
12 "internal/abi"
13 "log"
14 "math"
15 )
16
17 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
18
19 switch p.As {
20 case AJMP,
21 AJAL,
22 ARET,
23 obj.ADUFFZERO,
24 obj.ADUFFCOPY:
25 if p.To.Sym != nil {
26 p.To.Type = obj.TYPE_BRANCH
27 }
28 }
29
30
31 switch p.As {
32 case AMOVF:
33 if p.From.Type == obj.TYPE_FCONST {
34 f32 := float32(p.From.Val.(float64))
35 if math.Float32bits(f32) == 0 {
36 p.As = AMOVW
37 p.From.Type = obj.TYPE_REG
38 p.From.Reg = REGZERO
39 break
40 }
41 p.From.Type = obj.TYPE_MEM
42 p.From.Sym = ctxt.Float32Sym(f32)
43 p.From.Name = obj.NAME_EXTERN
44 p.From.Offset = 0
45 }
46
47 case AMOVD:
48 if p.From.Type == obj.TYPE_FCONST {
49 f64 := p.From.Val.(float64)
50 if math.Float64bits(f64) == 0 {
51 p.As = AMOVV
52 p.From.Type = obj.TYPE_REG
53 p.From.Reg = REGZERO
54 break
55 }
56 p.From.Type = obj.TYPE_MEM
57 p.From.Sym = ctxt.Float64Sym(f64)
58 p.From.Name = obj.NAME_EXTERN
59 p.From.Offset = 0
60 }
61 }
62
63
64 switch p.As {
65 case ASUB:
66 if p.From.Type == obj.TYPE_CONST {
67 p.From.Offset = -p.From.Offset
68 p.As = AADD
69 }
70
71 case ASUBU:
72 if p.From.Type == obj.TYPE_CONST {
73 p.From.Offset = -p.From.Offset
74 p.As = AADDU
75 }
76
77 case ASUBV:
78 if p.From.Type == obj.TYPE_CONST {
79 p.From.Offset = -p.From.Offset
80 p.As = AADDV
81 }
82
83 case ASUBVU:
84 if p.From.Type == obj.TYPE_CONST {
85 p.From.Offset = -p.From.Offset
86 p.As = AADDVU
87 }
88 }
89
90 if ctxt.Flag_dynlink {
91 rewriteToUseGot(ctxt, p, newprog)
92 }
93 }
94
95 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
96
97
98
99
100
101 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
102 var sym *obj.LSym
103 if p.As == obj.ADUFFZERO {
104 sym = ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
105 } else {
106 sym = ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
107 }
108 offset := p.To.Offset
109 p.As = AMOVV
110 p.From.Type = obj.TYPE_MEM
111 p.From.Sym = sym
112 p.From.Name = obj.NAME_GOTREF
113 p.To.Type = obj.TYPE_REG
114 p.To.Reg = REGTMP
115 p.To.Name = obj.NAME_NONE
116 p.To.Offset = 0
117 p.To.Sym = nil
118 p1 := obj.Appendp(p, newprog)
119 p1.As = AADDV
120 p1.From.Type = obj.TYPE_CONST
121 p1.From.Offset = offset
122 p1.To.Type = obj.TYPE_REG
123 p1.To.Reg = REGTMP
124 p2 := obj.Appendp(p1, newprog)
125 p2.As = AJAL
126 p2.To.Type = obj.TYPE_MEM
127 p2.To.Reg = REGTMP
128 }
129
130
131
132
133 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
134
135
136 if p.As != AMOVV {
137 ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -shared", p)
138 }
139 if p.To.Type != obj.TYPE_REG {
140 ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -shared", p)
141 }
142 p.From.Type = obj.TYPE_MEM
143 p.From.Name = obj.NAME_GOTREF
144 if p.From.Offset != 0 {
145 q := obj.Appendp(p, newprog)
146 q.As = AADDV
147 q.From.Type = obj.TYPE_CONST
148 q.From.Offset = p.From.Offset
149 q.To = p.To
150 p.From.Offset = 0
151 }
152 }
153 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
154 ctxt.Diag("don't know how to handle %v with -shared", p)
155 }
156
157 var source *obj.Addr
158
159
160
161 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
162 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
163 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -shared", p)
164 }
165 source = &p.From
166 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
167 source = &p.To
168 } else {
169 return
170 }
171 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
172 return
173 }
174 if source.Sym.Type == objabi.STLSBSS {
175 return
176 }
177 if source.Type != obj.TYPE_MEM {
178 ctxt.Diag("don't know how to handle %v with -shared", p)
179 }
180 p1 := obj.Appendp(p, newprog)
181 p2 := obj.Appendp(p1, newprog)
182 p1.As = AMOVV
183 p1.From.Type = obj.TYPE_MEM
184 p1.From.Sym = source.Sym
185 p1.From.Name = obj.NAME_GOTREF
186 p1.To.Type = obj.TYPE_REG
187 p1.To.Reg = REGTMP
188
189 p2.As = p.As
190 p2.From = p.From
191 p2.To = p.To
192 if p.From.Name == obj.NAME_EXTERN {
193 p2.From.Reg = REGTMP
194 p2.From.Name = obj.NAME_NONE
195 p2.From.Sym = nil
196 } else if p.To.Name == obj.NAME_EXTERN {
197 p2.To.Reg = REGTMP
198 p2.To.Name = obj.NAME_NONE
199 p2.To.Sym = nil
200 } else {
201 return
202 }
203
204 obj.Nopout(p)
205 }
206
207 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
208 c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
209
210 p := c.cursym.Func().Text
211 textstksiz := p.To.Offset
212
213 if textstksiz < 0 {
214 c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
215 }
216 if p.From.Sym.NoFrame() {
217 if textstksiz != 0 {
218 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
219 }
220 }
221
222 c.cursym.Func().Args = p.To.Val.(int32)
223 c.cursym.Func().Locals = int32(textstksiz)
224
225
229
230 for p := c.cursym.Func().Text; p != nil; p = p.Link {
231 switch p.As {
232 case obj.ATEXT:
233 p.Mark |= LABEL | LEAF | SYNC
234 if p.Link != nil {
235 p.Link.Mark |= LABEL
236 }
237
238 case AMOVW,
239 AMOVV:
240 if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
241 p.Mark |= LABEL | SYNC
242 break
243 }
244 if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
245 p.Mark |= LABEL | SYNC
246 }
247
248 case ASYSCALL,
249 AWORD:
250 p.Mark |= LABEL | SYNC
251
252 case ANOR:
253 if p.To.Type == obj.TYPE_REG {
254 if p.To.Reg == REGZERO {
255 p.Mark |= LABEL | SYNC
256 }
257 }
258
259 case AJAL,
260 obj.ADUFFZERO,
261 obj.ADUFFCOPY:
262 c.cursym.Func().Text.Mark &^= LEAF
263 fallthrough
264
265 case AJMP,
266 ABEQ,
267 ABGEU,
268 ABLTU,
269 ABLTZ,
270 ABNE,
271 ABFPT, ABFPF:
272 p.Mark |= BRANCH
273 q1 := p.To.Target()
274 if q1 != nil {
275 for q1.As == obj.ANOP {
276 q1 = q1.Link
277 p.To.SetTarget(q1)
278 }
279
280 if q1.Mark&LEAF == 0 {
281 q1.Mark |= LABEL
282 }
283 }
284 q1 = p.Link
285 if q1 != nil {
286 q1.Mark |= LABEL
287 }
288
289 case ARET:
290 if p.Link != nil {
291 p.Link.Mark |= LABEL
292 }
293 }
294 }
295
296 var mov, add obj.As
297
298 add = AADDV
299 mov = AMOVV
300
301 var q *obj.Prog
302 var q1 *obj.Prog
303 autosize := int32(0)
304 for p := c.cursym.Func().Text; p != nil; p = p.Link {
305 o := p.As
306 switch o {
307 case obj.ATEXT:
308 autosize = int32(textstksiz)
309
310 if p.Mark&LEAF != 0 && autosize == 0 {
311
312 p.From.Sym.Set(obj.AttrNoFrame, true)
313 }
314
315 if !p.From.Sym.NoFrame() {
316
317
318 autosize += int32(c.ctxt.Arch.FixedFrameSize)
319 }
320
321 if p.Mark&LEAF != 0 && autosize < abi.StackSmall {
322
323
324 p.From.Sym.Set(obj.AttrNoSplit, true)
325 }
326
327 if autosize&4 != 0 {
328 autosize += 4
329 }
330
331 if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
332 if c.cursym.Func().Text.From.Sym.NoSplit() {
333 if ctxt.Debugvlog {
334 ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
335 }
336
337 c.cursym.Func().Text.Mark |= LEAF
338 }
339 }
340
341 p.To.Offset = int64(autosize) - ctxt.Arch.FixedFrameSize
342
343 if c.cursym.Func().Text.Mark&LEAF != 0 {
344 c.cursym.Set(obj.AttrLeaf, true)
345 if p.From.Sym.NoFrame() {
346 break
347 }
348 }
349
350 if !p.From.Sym.NoSplit() {
351 p = c.stacksplit(p, autosize)
352 }
353
354 q = p
355
356 if autosize != 0 {
357
358
359
360
361
362
363
364 q = c.ctxt.StartUnsafePoint(q, c.newprog)
365
366 q = obj.Appendp(q, newprog)
367 q.As = mov
368 q.Pos = p.Pos
369 q.From.Type = obj.TYPE_REG
370 q.From.Reg = REGLINK
371 q.To.Type = obj.TYPE_MEM
372 q.To.Offset = int64(-autosize)
373 q.To.Reg = REGSP
374
375 q = obj.Appendp(q, newprog)
376 q.As = add
377 q.Pos = p.Pos
378 q.Pos = q.Pos.WithXlogue(src.PosPrologueEnd)
379 q.From.Type = obj.TYPE_CONST
380 q.From.Offset = int64(-autosize)
381 q.To.Type = obj.TYPE_REG
382 q.To.Reg = REGSP
383 q.Spadj = +autosize
384
385 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
386
387
388
389
390
391
392 q = obj.Appendp(q, newprog)
393 q.As = mov
394 q.Pos = p.Pos
395 q.From.Type = obj.TYPE_REG
396 q.From.Reg = REGLINK
397 q.To.Type = obj.TYPE_MEM
398 q.To.Offset = 0
399 q.To.Reg = REGSP
400 }
401
402 case ARET:
403 if p.From.Type == obj.TYPE_CONST {
404 ctxt.Diag("using BECOME (%v) is not supported!", p)
405 break
406 }
407
408 retSym := p.To.Sym
409 p.To.Name = obj.NAME_NONE
410 p.To.Sym = nil
411
412 if c.cursym.Func().Text.Mark&LEAF != 0 {
413 if autosize == 0 {
414 p.As = AJMP
415 p.From = obj.Addr{}
416 if retSym != nil {
417 p.To.Type = obj.TYPE_BRANCH
418 p.To.Name = obj.NAME_EXTERN
419 p.To.Sym = retSym
420 } else {
421 p.To.Type = obj.TYPE_MEM
422 p.To.Reg = REGLINK
423 p.To.Offset = 0
424 }
425 p.Mark |= BRANCH
426 break
427 }
428
429 p.As = add
430 p.From.Type = obj.TYPE_CONST
431 p.From.Offset = int64(autosize)
432 p.To.Type = obj.TYPE_REG
433 p.To.Reg = REGSP
434 p.Spadj = -autosize
435
436 q = c.newprog()
437 q.As = AJMP
438 q.Pos = p.Pos
439 if retSym != nil {
440 q.To.Type = obj.TYPE_BRANCH
441 q.To.Name = obj.NAME_EXTERN
442 q.To.Sym = retSym
443 } else {
444 q.To.Type = obj.TYPE_MEM
445 q.To.Offset = 0
446 q.To.Reg = REGLINK
447 }
448 q.Mark |= BRANCH
449 q.Spadj = +autosize
450
451 q.Link = p.Link
452 p.Link = q
453 break
454 }
455
456 p.As = mov
457 p.From.Type = obj.TYPE_MEM
458 p.From.Offset = 0
459 p.From.Reg = REGSP
460 p.To.Type = obj.TYPE_REG
461 p.To.Reg = REGLINK
462
463 if autosize != 0 {
464 q = c.newprog()
465 q.As = add
466 q.Pos = p.Pos
467 q.From.Type = obj.TYPE_CONST
468 q.From.Offset = int64(autosize)
469 q.To.Type = obj.TYPE_REG
470 q.To.Reg = REGSP
471 q.Spadj = -autosize
472
473 q.Link = p.Link
474 p.Link = q
475 }
476
477 q1 = c.newprog()
478 q1.As = AJMP
479 q1.Pos = p.Pos
480 if retSym != nil {
481 q1.To.Type = obj.TYPE_BRANCH
482 q1.To.Name = obj.NAME_EXTERN
483 q1.To.Sym = retSym
484 } else {
485 q1.To.Type = obj.TYPE_MEM
486 q1.To.Offset = 0
487 q1.To.Reg = REGLINK
488 }
489 q1.Mark |= BRANCH
490 q1.Spadj = +autosize
491
492 q1.Link = q.Link
493 q.Link = q1
494
495 case AADD,
496 AADDU,
497 AADDV,
498 AADDVU:
499 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
500 p.Spadj = int32(-p.From.Offset)
501 }
502
503 case obj.AGETCALLERPC:
504 if cursym.Leaf() {
505
506 p.As = mov
507 p.From.Type = obj.TYPE_REG
508 p.From.Reg = REGLINK
509 } else {
510
511 p.As = mov
512 p.From.Type = obj.TYPE_MEM
513 p.From.Reg = REGSP
514 }
515 }
516
517 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
518 f := c.cursym.Func()
519 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
520 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
521 if ctxt.Debugvlog || !ctxt.IsAsm {
522 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
523 if !ctxt.IsAsm {
524 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
525 ctxt.DiagFlush()
526 log.Fatalf("bad SPWRITE")
527 }
528 }
529 }
530 }
531 }
532 }
533
534 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
535 var mov, add obj.As
536
537 add = AADDV
538 mov = AMOVV
539 if c.ctxt.Flag_maymorestack != "" {
540
541 frameSize := 2 * c.ctxt.Arch.PtrSize
542
543 p = c.ctxt.StartUnsafePoint(p, c.newprog)
544
545
546
547 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
548
549
550 p = obj.Appendp(p, c.newprog)
551 p.As = mov
552 p.From.Type = obj.TYPE_REG
553 p.From.Reg = REGLINK
554 p.To.Type = obj.TYPE_MEM
555 p.To.Offset = int64(-frameSize)
556 p.To.Reg = REGSP
557
558
559 p = obj.Appendp(p, c.newprog)
560 p.As = mov
561 p.From.Type = obj.TYPE_REG
562 p.From.Reg = REGCTXT
563 p.To.Type = obj.TYPE_MEM
564 p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
565 p.To.Reg = REGSP
566
567
568 p = obj.Appendp(p, c.newprog)
569 p.As = add
570 p.From.Type = obj.TYPE_CONST
571 p.From.Offset = int64(-frameSize)
572 p.To.Type = obj.TYPE_REG
573 p.To.Reg = REGSP
574 p.Spadj = int32(frameSize)
575
576
577 p = obj.Appendp(p, c.newprog)
578 p.As = AJAL
579 p.To.Type = obj.TYPE_BRANCH
580
581 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
582 p.Mark |= BRANCH
583
584
585
586
587 p = obj.Appendp(p, c.newprog)
588 p.As = mov
589 p.From.Type = obj.TYPE_MEM
590 p.From.Offset = 0
591 p.From.Reg = REGSP
592 p.To.Type = obj.TYPE_REG
593 p.To.Reg = REGLINK
594
595
596 p = obj.Appendp(p, c.newprog)
597 p.As = mov
598 p.From.Type = obj.TYPE_MEM
599 p.From.Offset = int64(c.ctxt.Arch.PtrSize)
600 p.From.Reg = REGSP
601 p.To.Type = obj.TYPE_REG
602 p.To.Reg = REGCTXT
603
604
605 p = obj.Appendp(p, c.newprog)
606 p.As = add
607 p.From.Type = obj.TYPE_CONST
608 p.From.Offset = int64(frameSize)
609 p.To.Type = obj.TYPE_REG
610 p.To.Reg = REGSP
611 p.Spadj = int32(-frameSize)
612
613
614 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
615 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
616 }
617
618
619 startPred := p
620
621
622 p = obj.Appendp(p, c.newprog)
623
624 p.As = mov
625 p.From.Type = obj.TYPE_MEM
626 p.From.Reg = REGG
627 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
628 if c.cursym.CFunc() {
629 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
630 }
631 p.To.Type = obj.TYPE_REG
632 p.To.Reg = REG_R20
633
634
635
636
637
638 p = c.ctxt.StartUnsafePoint(p, c.newprog)
639
640 var q *obj.Prog
641 if framesize <= abi.StackSmall {
642
643
644 p = obj.Appendp(p, c.newprog)
645
646 p.As = ASGTU
647 p.From.Type = obj.TYPE_REG
648 p.From.Reg = REGSP
649 p.Reg = REG_R20
650 p.To.Type = obj.TYPE_REG
651 p.To.Reg = REG_R20
652 } else {
653
654 offset := int64(framesize) - abi.StackSmall
655 if framesize > abi.StackBig {
656
657
658
659
660
661
662
663
664
665
666 p = obj.Appendp(p, c.newprog)
667 p.As = ASGTU
668 p.From.Type = obj.TYPE_CONST
669 p.From.Offset = offset
670 p.Reg = REGSP
671 p.To.Type = obj.TYPE_REG
672 p.To.Reg = REG_R24
673
674 p = obj.Appendp(p, c.newprog)
675 q = p
676 p.As = ABNE
677 p.From.Type = obj.TYPE_REG
678 p.From.Reg = REG_R24
679 p.To.Type = obj.TYPE_BRANCH
680 p.Mark |= BRANCH
681 }
682
683 p = obj.Appendp(p, c.newprog)
684
685 p.As = add
686 p.From.Type = obj.TYPE_CONST
687 p.From.Offset = -offset
688 p.Reg = REGSP
689 p.To.Type = obj.TYPE_REG
690 p.To.Reg = REG_R24
691
692 p = obj.Appendp(p, c.newprog)
693 p.As = ASGTU
694 p.From.Type = obj.TYPE_REG
695 p.From.Reg = REG_R24
696 p.Reg = REG_R20
697 p.To.Type = obj.TYPE_REG
698 p.To.Reg = REG_R20
699 }
700
701
702 p = obj.Appendp(p, c.newprog)
703 q1 := p
704
705 p.As = ABEQ
706 p.From.Type = obj.TYPE_REG
707 p.From.Reg = REG_R20
708 p.To.Type = obj.TYPE_BRANCH
709 p.Mark |= BRANCH
710
711 end := c.ctxt.EndUnsafePoint(p, c.newprog, -1)
712
713 var last *obj.Prog
714 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
715 }
716
717
718
719
720 spfix := obj.Appendp(last, c.newprog)
721 spfix.As = obj.ANOP
722 spfix.Spadj = -framesize
723
724 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
725 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
726
727 if q != nil {
728 q.To.SetTarget(pcdata)
729 }
730 q1.To.SetTarget(pcdata)
731
732 p = c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
733
734
735 p = obj.Appendp(p, c.newprog)
736 p.As = mov
737 p.From.Type = obj.TYPE_REG
738 p.From.Reg = REGLINK
739 p.To.Type = obj.TYPE_REG
740 p.To.Reg = REG_R31
741 if q != nil {
742 q.To.SetTarget(p)
743 p.Mark |= LABEL
744 }
745
746
747 call := obj.Appendp(p, c.newprog)
748 call.As = AJAL
749 call.To.Type = obj.TYPE_BRANCH
750
751 if c.cursym.CFunc() {
752 call.To.Sym = c.ctxt.Lookup("runtime.morestackc")
753 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
754 call.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
755 } else {
756 call.To.Sym = c.ctxt.Lookup("runtime.morestack")
757 }
758 call.Mark |= BRANCH
759
760
761 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
762 unspill := c.cursym.Func().UnspillRegisterArgs(pcdata, c.newprog)
763
764
765 jmp := obj.Appendp(unspill, c.newprog)
766 jmp.As = AJMP
767 jmp.To.Type = obj.TYPE_BRANCH
768 jmp.To.SetTarget(startPred.Link)
769 jmp.Spadj = +framesize
770
771 return end
772 }
773
774 func (c *ctxt0) addnop(p *obj.Prog) {
775 q := c.newprog()
776 q.As = ANOOP
777 q.Pos = p.Pos
778 q.Link = p.Link
779 p.Link = q
780 }
781
782 var Linkloong64 = obj.LinkArch{
783 Arch: sys.ArchLoong64,
784 Init: buildop,
785 Preprocess: preprocess,
786 Assemble: span0,
787 Progedit: progedit,
788 DWARFRegisters: LOONG64DWARFRegisters,
789 }
790
View as plain text