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 := p.To.Sym
363 p.To.Name = obj.NAME_NONE
364 p.To.Sym = nil
365
366 if c.cursym.Func().Text.Mark&LEAF != 0 {
367 if autosize == 0 {
368 p.As = AJMP
369 p.From = obj.Addr{}
370 if retSym != nil {
371 p.To.Type = obj.TYPE_BRANCH
372 p.To.Name = obj.NAME_EXTERN
373 p.To.Sym = retSym
374 } else {
375 p.To.Type = obj.TYPE_MEM
376 p.To.Reg = REGLINK
377 p.To.Offset = 0
378 }
379 p.Mark |= BRANCH
380 break
381 }
382
383 p.As = add
384 p.From.Type = obj.TYPE_CONST
385 p.From.Offset = int64(autosize)
386 p.To.Type = obj.TYPE_REG
387 p.To.Reg = REGSP
388 p.Spadj = -autosize
389
390 q = c.newprog()
391 q.As = AJMP
392 q.Pos = p.Pos
393 if retSym != nil {
394 q.To.Type = obj.TYPE_BRANCH
395 q.To.Name = obj.NAME_EXTERN
396 q.To.Sym = retSym
397 } else {
398 q.To.Type = obj.TYPE_MEM
399 q.To.Offset = 0
400 q.To.Reg = REGLINK
401 }
402 q.Mark |= BRANCH
403 q.Spadj = +autosize
404
405 q.Link = p.Link
406 p.Link = q
407 break
408 }
409
410 p.As = mov
411 p.From.Type = obj.TYPE_MEM
412 p.From.Offset = 0
413 p.From.Reg = REGSP
414 p.To.Type = obj.TYPE_REG
415 p.To.Reg = REGLINK
416
417 if autosize != 0 {
418 q = c.newprog()
419 q.As = add
420 q.Pos = p.Pos
421 q.From.Type = obj.TYPE_CONST
422 q.From.Offset = int64(autosize)
423 q.To.Type = obj.TYPE_REG
424 q.To.Reg = REGSP
425 q.Spadj = -autosize
426
427 q.Link = p.Link
428 p.Link = q
429 }
430
431 q1 = c.newprog()
432 q1.As = AJMP
433 q1.Pos = p.Pos
434 if retSym != nil {
435 q1.To.Type = obj.TYPE_BRANCH
436 q1.To.Name = obj.NAME_EXTERN
437 q1.To.Sym = retSym
438 } else {
439 q1.To.Type = obj.TYPE_MEM
440 q1.To.Offset = 0
441 q1.To.Reg = REGLINK
442 }
443 q1.Mark |= BRANCH
444 q1.Spadj = +autosize
445
446 q1.Link = q.Link
447 q.Link = q1
448
449 case AADD,
450 AADDV,
451 AADDVU:
452 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
453 p.Spadj = int32(-p.From.Offset)
454 }
455
456 case obj.AGETCALLERPC:
457 if cursym.Leaf() {
458
459 p.As = mov
460 p.From.Type = obj.TYPE_REG
461 p.From.Reg = REGLINK
462 } else {
463
464 p.As = mov
465 p.From.Type = obj.TYPE_MEM
466 p.From.Reg = REGSP
467 }
468 }
469
470 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
471 f := c.cursym.Func()
472 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
473 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
474 if ctxt.Debugvlog || !ctxt.IsAsm {
475 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
476 if !ctxt.IsAsm {
477 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
478 ctxt.DiagFlush()
479 log.Fatalf("bad SPWRITE")
480 }
481 }
482 }
483 }
484 }
485 }
486
487 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
488 var mov, add obj.As
489
490 add = AADDV
491 mov = AMOVV
492 if c.ctxt.Flag_maymorestack != "" {
493
494 frameSize := 2 * c.ctxt.Arch.PtrSize
495
496 p = c.ctxt.StartUnsafePoint(p, c.newprog)
497
498
499
500 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
501
502
503 p = obj.Appendp(p, c.newprog)
504 p.As = mov
505 p.From.Type = obj.TYPE_REG
506 p.From.Reg = REGLINK
507 p.To.Type = obj.TYPE_MEM
508 p.To.Offset = int64(-frameSize)
509 p.To.Reg = REGSP
510
511
512 p = obj.Appendp(p, c.newprog)
513 p.As = mov
514 p.From.Type = obj.TYPE_REG
515 p.From.Reg = REGCTXT
516 p.To.Type = obj.TYPE_MEM
517 p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
518 p.To.Reg = REGSP
519
520
521 p = obj.Appendp(p, c.newprog)
522 p.As = add
523 p.From.Type = obj.TYPE_CONST
524 p.From.Offset = int64(-frameSize)
525 p.To.Type = obj.TYPE_REG
526 p.To.Reg = REGSP
527 p.Spadj = int32(frameSize)
528
529
530 p = obj.Appendp(p, c.newprog)
531 p.As = AJAL
532 p.To.Type = obj.TYPE_BRANCH
533
534 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
535 p.Mark |= BRANCH
536
537
538
539
540 p = obj.Appendp(p, c.newprog)
541 p.As = mov
542 p.From.Type = obj.TYPE_MEM
543 p.From.Offset = 0
544 p.From.Reg = REGSP
545 p.To.Type = obj.TYPE_REG
546 p.To.Reg = REGLINK
547
548
549 p = obj.Appendp(p, c.newprog)
550 p.As = mov
551 p.From.Type = obj.TYPE_MEM
552 p.From.Offset = int64(c.ctxt.Arch.PtrSize)
553 p.From.Reg = REGSP
554 p.To.Type = obj.TYPE_REG
555 p.To.Reg = REGCTXT
556
557
558 p = obj.Appendp(p, c.newprog)
559 p.As = add
560 p.From.Type = obj.TYPE_CONST
561 p.From.Offset = int64(frameSize)
562 p.To.Type = obj.TYPE_REG
563 p.To.Reg = REGSP
564 p.Spadj = int32(-frameSize)
565
566
567 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
568 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
569 }
570
571
572 startPred := p
573
574
575 p = obj.Appendp(p, c.newprog)
576
577 p.As = mov
578 p.From.Type = obj.TYPE_MEM
579 p.From.Reg = REGG
580 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
581 if c.cursym.CFunc() {
582 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
583 }
584 p.To.Type = obj.TYPE_REG
585 p.To.Reg = REG_R20
586
587
588
589
590
591 p = c.ctxt.StartUnsafePoint(p, c.newprog)
592
593 var q *obj.Prog
594 if framesize <= abi.StackSmall {
595
596
597 p = obj.Appendp(p, c.newprog)
598
599 p.As = ASGTU
600 p.From.Type = obj.TYPE_REG
601 p.From.Reg = REGSP
602 p.Reg = REG_R20
603 p.To.Type = obj.TYPE_REG
604 p.To.Reg = REG_R20
605 } else {
606
607 offset := int64(framesize) - abi.StackSmall
608 if framesize > abi.StackBig {
609
610
611
612
613
614
615
616
617
618
619 p = obj.Appendp(p, c.newprog)
620 p.As = ASGTU
621 p.From.Type = obj.TYPE_CONST
622 p.From.Offset = offset
623 p.Reg = REGSP
624 p.To.Type = obj.TYPE_REG
625 p.To.Reg = REG_R24
626
627 p = obj.Appendp(p, c.newprog)
628 q = p
629 p.As = ABNE
630 p.From.Type = obj.TYPE_REG
631 p.From.Reg = REG_R24
632 p.To.Type = obj.TYPE_BRANCH
633 p.Mark |= BRANCH
634 }
635
636 p = obj.Appendp(p, c.newprog)
637
638 p.As = add
639 p.From.Type = obj.TYPE_CONST
640 p.From.Offset = -offset
641 p.Reg = REGSP
642 p.To.Type = obj.TYPE_REG
643 p.To.Reg = REG_R24
644
645 p = obj.Appendp(p, c.newprog)
646 p.As = ASGTU
647 p.From.Type = obj.TYPE_REG
648 p.From.Reg = REG_R24
649 p.Reg = REG_R20
650 p.To.Type = obj.TYPE_REG
651 p.To.Reg = REG_R20
652 }
653
654
655 p = obj.Appendp(p, c.newprog)
656 q1 := p
657
658 p.As = ABEQ
659 p.From.Type = obj.TYPE_REG
660 p.From.Reg = REG_R20
661 p.To.Type = obj.TYPE_BRANCH
662 p.Mark |= BRANCH
663
664 end := c.ctxt.EndUnsafePoint(p, c.newprog, -1)
665
666 var last *obj.Prog
667 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
668 }
669
670
671
672
673 spfix := obj.Appendp(last, c.newprog)
674 spfix.As = obj.ANOP
675 spfix.Spadj = -framesize
676
677 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
678 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
679
680 if q != nil {
681 q.To.SetTarget(pcdata)
682 }
683 q1.To.SetTarget(pcdata)
684
685 p = c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
686
687
688 p = obj.Appendp(p, c.newprog)
689 p.As = mov
690 p.From.Type = obj.TYPE_REG
691 p.From.Reg = REGLINK
692 p.To.Type = obj.TYPE_REG
693 p.To.Reg = REG_R31
694 if q != nil {
695 q.To.SetTarget(p)
696 p.Mark |= LABEL
697 }
698
699
700 call := obj.Appendp(p, c.newprog)
701 call.As = AJAL
702 call.To.Type = obj.TYPE_BRANCH
703
704 if c.cursym.CFunc() {
705 call.To.Sym = c.ctxt.Lookup("runtime.morestackc")
706 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
707 call.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
708 } else {
709 call.To.Sym = c.ctxt.Lookup("runtime.morestack")
710 }
711 call.Mark |= BRANCH
712
713
714 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
715 unspill := c.cursym.Func().UnspillRegisterArgs(pcdata, c.newprog)
716
717
718 jmp := obj.Appendp(unspill, c.newprog)
719 jmp.As = AJMP
720 jmp.To.Type = obj.TYPE_BRANCH
721 jmp.To.SetTarget(startPred.Link)
722 jmp.Spadj = +framesize
723
724 return end
725 }
726
727 var Linkloong64 = obj.LinkArch{
728 Arch: sys.ArchLoong64,
729 Init: buildop,
730 Preprocess: preprocess,
731 Assemble: span0,
732 Progedit: progedit,
733 DWARFRegisters: LOONG64DWARFRegisters,
734 }
735
View as plain text