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