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