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 p := c.cursym.Func().Text
166
167 if p == nil || p.Link == nil {
168 return
169 }
170
171 if p.As != obj.ATEXT {
172 c.ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
173 return
174 }
175
176 textstksiz := p.To.Offset
177 if textstksiz == -ctxt.Arch.FixedFrameSize {
178
179 p.From.Sym.Set(obj.AttrNoFrame, true)
180 textstksiz = 0
181 }
182
183 if textstksiz < 0 {
184 c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
185 }
186
187 if p.From.Sym.NoFrame() {
188 if textstksiz != 0 {
189 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
190 }
191 }
192
193 if textstksiz%8 != 0 {
194 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
195 }
196
197 c.cursym.Func().Args = p.To.Val.(int32)
198 c.cursym.Func().Locals = int32(textstksiz)
199
200
203 for p := c.cursym.Func().Text; p != nil; p = p.Link {
204 switch p.As {
205 case obj.ATEXT:
206 p.Mark |= LEAF
207
208 case AJAL:
209 c.cursym.Func().Text.Mark &^= LEAF
210 }
211 }
212
213 var q, q1 *obj.Prog
214 for p := c.cursym.Func().Text; p != nil; p = p.Link {
215 o := p.As
216 switch o {
217 case obj.ATEXT:
218 c.autosize = int32(textstksiz)
219 if p.Mark&LEAF != 0 && c.autosize == 0 {
220
221 p.From.Sym.Set(obj.AttrNoFrame, true)
222 }
223
224 if !p.From.Sym.NoFrame() {
225
226
227 c.autosize += int32(c.ctxt.Arch.FixedFrameSize)
228 }
229
230 if p.Mark&LEAF != 0 && c.autosize < abi.StackSmall {
231
232
233 p.From.Sym.Set(obj.AttrNoSplit, true)
234 }
235
236 if c.autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
237 if c.cursym.Func().Text.From.Sym.NoSplit() {
238 if ctxt.Debugvlog {
239 ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
240 }
241
242 c.cursym.Func().Text.Mark |= LEAF
243 }
244 }
245
246 p.To.Offset = int64(c.autosize) - ctxt.Arch.FixedFrameSize
247
248 if c.cursym.Func().Text.Mark&LEAF != 0 {
249 c.cursym.Set(obj.AttrLeaf, true)
250 if p.From.Sym.NoFrame() {
251 break
252 }
253 }
254
255 if !p.From.Sym.NoSplit() {
256 p = c.stacksplit(p, c.autosize)
257 }
258
259 q = p
260
261 if c.autosize != 0 {
262
263
264
265
266
267
268
269 q = c.ctxt.StartUnsafePoint(q, c.newprog)
270
271
272 q = obj.Appendp(q, newprog)
273 q.As = AMOVV
274 q.Pos = p.Pos
275 q.From.Type = obj.TYPE_REG
276 q.From.Reg = REGLINK
277 q.To.Type = obj.TYPE_MEM
278 q.To.Offset = int64(-c.autosize)
279 q.To.Reg = REGSP
280
281
282 q = obj.Appendp(q, newprog)
283 q.As = AADDV
284 q.Pos = p.Pos
285 q.Pos = q.Pos.WithXlogue(src.PosPrologueEnd)
286 q.From.Type = obj.TYPE_CONST
287 q.From.Offset = int64(-c.autosize)
288 q.To.Type = obj.TYPE_REG
289 q.To.Reg = REGSP
290 q.Spadj = +c.autosize
291
292 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
293
294
295
296
297
298
299
300
301 q = obj.Appendp(q, newprog)
302 q.As = AMOVV
303 q.Pos = p.Pos
304 q.From.Type = obj.TYPE_REG
305 q.From.Reg = REGLINK
306 q.To.Type = obj.TYPE_MEM
307 q.To.Offset = 0
308 q.To.Reg = REGSP
309 }
310
311 case ARET:
312 if p.From.Type == obj.TYPE_CONST {
313 ctxt.Diag("using BECOME (%v) is not supported!", p)
314 break
315 }
316
317 retSym, retReg := p.To.Sym, p.To.Reg
318 if retReg == obj.REG_NONE {
319 retReg = REGLINK
320 }
321 p.To.Name = obj.NAME_NONE
322 p.To.Sym = nil
323 p.To.Reg = obj.REG_NONE
324
325 if c.cursym.Func().Text.Mark&LEAF != 0 {
326 if c.autosize == 0 {
327 p.As = AJMP
328 p.From = obj.Addr{}
329 if retSym != nil {
330 p.To.Type = obj.TYPE_BRANCH
331 p.To.Name = obj.NAME_EXTERN
332 p.To.Sym = retSym
333 } else {
334 p.To.Type = obj.TYPE_MEM
335 p.To.Reg = retReg
336 p.To.Offset = 0
337 }
338 break
339 }
340
341 p.As = AADDV
342 p.From.Type = obj.TYPE_CONST
343 p.From.Offset = int64(c.autosize)
344 p.To.Type = obj.TYPE_REG
345 p.To.Reg = REGSP
346 p.Spadj = -c.autosize
347
348 q = c.newprog()
349 q.As = AJMP
350 q.Pos = p.Pos
351 if retSym != nil {
352 q.To.Type = obj.TYPE_BRANCH
353 q.To.Name = obj.NAME_EXTERN
354 q.To.Sym = retSym
355 } else {
356 q.To.Type = obj.TYPE_MEM
357 q.To.Offset = 0
358 q.To.Reg = retReg
359 }
360 q.Spadj = +c.autosize
361
362 q.Link = p.Link
363 p.Link = q
364 break
365 }
366
367 p.As = AMOVV
368 p.From.Type = obj.TYPE_MEM
369 p.From.Offset = 0
370 p.From.Reg = REGSP
371 p.To.Type = obj.TYPE_REG
372 p.To.Reg = REGLINK
373
374 if c.autosize != 0 {
375 q = c.newprog()
376 q.As = AADDV
377 q.Pos = p.Pos
378 q.From.Type = obj.TYPE_CONST
379 q.From.Offset = int64(c.autosize)
380 q.To.Type = obj.TYPE_REG
381 q.To.Reg = REGSP
382 q.Spadj = -c.autosize
383
384 q.Link = p.Link
385 p.Link = q
386 }
387
388 q1 = c.newprog()
389 q1.As = AJMP
390 q1.Pos = p.Pos
391 if retSym != nil {
392 q1.To.Type = obj.TYPE_BRANCH
393 q1.To.Name = obj.NAME_EXTERN
394 q1.To.Sym = retSym
395 } else {
396 q1.To.Type = obj.TYPE_MEM
397 q1.To.Offset = 0
398 q1.To.Reg = retReg
399 }
400 q1.Spadj = +c.autosize
401
402 q1.Link = q.Link
403 q.Link = q1
404
405 case AADD, AADDV, AADDVU:
406 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
407 p.Spadj = int32(-p.From.Offset)
408 }
409
410 case obj.AGETCALLERPC:
411 if cursym.Leaf() {
412
413 p.As = AMOVV
414 p.From.Type = obj.TYPE_REG
415 p.From.Reg = REGLINK
416 } else {
417
418 p.As = AMOVV
419 p.From.Type = obj.TYPE_MEM
420 p.From.Reg = REGSP
421 }
422 }
423
424 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
425 f := c.cursym.Func()
426 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
427 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
428 if ctxt.Debugvlog || !ctxt.IsAsm {
429 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
430 if !ctxt.IsAsm {
431 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
432 ctxt.DiagFlush()
433 log.Fatalf("bad SPWRITE")
434 }
435 }
436 }
437 }
438 }
439 }
440
441 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
442 if c.ctxt.Flag_maymorestack != "" {
443
444 frameSize := 2 * c.ctxt.Arch.PtrSize
445
446 p = c.ctxt.StartUnsafePoint(p, c.newprog)
447
448
449
450 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
451
452
453 p = obj.Appendp(p, c.newprog)
454 p.As = AMOVV
455 p.From.Type = obj.TYPE_REG
456 p.From.Reg = REGLINK
457 p.To.Type = obj.TYPE_MEM
458 p.To.Offset = int64(-frameSize)
459 p.To.Reg = REGSP
460
461
462 p = obj.Appendp(p, c.newprog)
463 p.As = AMOVV
464 p.From.Type = obj.TYPE_REG
465 p.From.Reg = REGCTXT
466 p.To.Type = obj.TYPE_MEM
467 p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
468 p.To.Reg = REGSP
469
470
471 p = obj.Appendp(p, c.newprog)
472 p.As = AADDV
473 p.From.Type = obj.TYPE_CONST
474 p.From.Offset = int64(-frameSize)
475 p.To.Type = obj.TYPE_REG
476 p.To.Reg = REGSP
477 p.Spadj = int32(frameSize)
478
479
480 p = obj.Appendp(p, c.newprog)
481 p.As = AJAL
482 p.To.Type = obj.TYPE_BRANCH
483
484 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
485
486
487
488
489 p = obj.Appendp(p, c.newprog)
490 p.As = AMOVV
491 p.From.Type = obj.TYPE_MEM
492 p.From.Offset = 0
493 p.From.Reg = REGSP
494 p.To.Type = obj.TYPE_REG
495 p.To.Reg = REGLINK
496
497
498 p = obj.Appendp(p, c.newprog)
499 p.As = AMOVV
500 p.From.Type = obj.TYPE_MEM
501 p.From.Offset = int64(c.ctxt.Arch.PtrSize)
502 p.From.Reg = REGSP
503 p.To.Type = obj.TYPE_REG
504 p.To.Reg = REGCTXT
505
506
507 p = obj.Appendp(p, c.newprog)
508 p.As = AADDV
509 p.From.Type = obj.TYPE_CONST
510 p.From.Offset = int64(frameSize)
511 p.To.Type = obj.TYPE_REG
512 p.To.Reg = REGSP
513 p.Spadj = int32(-frameSize)
514
515
516 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
517 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
518 }
519
520
521 startPred := p
522
523
524 p = obj.Appendp(p, c.newprog)
525 p.As = AMOVV
526 p.From.Type = obj.TYPE_MEM
527 p.From.Reg = REGG
528 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
529 if c.cursym.CFunc() {
530 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
531 }
532 p.To.Type = obj.TYPE_REG
533 p.To.Reg = REGRT1
534
535
536
537
538
539 p = c.ctxt.StartUnsafePoint(p, c.newprog)
540
541 to_more0 := (*obj.Prog)(nil)
542 to_more1 := (*obj.Prog)(nil)
543
544 if framesize <= abi.StackSmall {
545
546
547
548 p = obj.Appendp(p, c.newprog)
549 p.As = ABGEU
550 p.From.Type = obj.TYPE_REG
551 p.From.Reg = REGRT1
552 p.Reg = REGSP
553 p.To.Type = obj.TYPE_BRANCH
554 to_more0 = p
555 } else {
556
557 offset := int64(framesize) - abi.StackSmall
558 if framesize > abi.StackBig {
559
560
561
562
563
564
565
566
567
568
569 p = obj.Appendp(p, c.newprog)
570 p.As = AMOVV
571 p.From.Type = obj.TYPE_CONST
572 p.From.Offset = offset
573 p.To.Type = obj.TYPE_REG
574 p.To.Reg = REGRT2
575
576 p = obj.Appendp(p, c.newprog)
577 p.As = ABLTU
578 p.From.Type = obj.TYPE_REG
579 p.From.Reg = REGSP
580 p.Reg = REGRT2
581 p.To.Type = obj.TYPE_BRANCH
582 to_more0 = p
583 }
584
585
586
587
588
589
590 if framesize > abi.StackBig {
591 p = obj.Appendp(p, c.newprog)
592 p.As = ASUBV
593 p.From.Type = obj.TYPE_REG
594 p.From.Reg = REGRT2
595 p.Reg = REGSP
596 p.To.Type = obj.TYPE_REG
597 p.To.Reg = REGRT2
598 } else {
599 p = obj.Appendp(p, c.newprog)
600 p.As = AADDV
601 p.From.Type = obj.TYPE_CONST
602 p.From.Offset = -offset
603 p.Reg = REGSP
604 p.To.Type = obj.TYPE_REG
605 p.To.Reg = REGRT2
606 }
607
608 p = obj.Appendp(p, c.newprog)
609 p.As = ABGEU
610 p.From.Type = obj.TYPE_REG
611 p.From.Reg = REGRT1
612 p.Reg = REGRT2
613 p.To.Type = obj.TYPE_BRANCH
614 to_more1 = p
615 }
616
617 end := c.ctxt.EndUnsafePoint(p, c.newprog, -1)
618
619 var last *obj.Prog
620 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
621 }
622
623
624
625
626 spfix := obj.Appendp(last, c.newprog)
627 spfix.As = obj.ANOP
628 spfix.Spadj = -framesize
629
630 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
631 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
632
633 if to_more0 != nil {
634 to_more0.To.SetTarget(pcdata)
635 }
636
637 if to_more1 != nil {
638 to_more1.To.SetTarget(pcdata)
639 }
640
641 p = c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
642
643
644 p = obj.Appendp(p, c.newprog)
645 p.As = AMOVV
646 p.From.Type = obj.TYPE_REG
647 p.From.Reg = REGLINK
648 p.To.Type = obj.TYPE_REG
649 p.To.Reg = REG_R31
650
651
652 call := obj.Appendp(p, c.newprog)
653 call.As = AJAL
654 call.To.Type = obj.TYPE_BRANCH
655
656 morestack := "runtime.morestack"
657 if c.cursym.CFunc() {
658 morestack = "runtime.morestackc"
659 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
660 morestack = "runtime.morestack_noctxt"
661 }
662 call.To.Sym = c.ctxt.Lookup(morestack)
663
664
665 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
666 unspill := c.cursym.Func().UnspillRegisterArgs(pcdata, c.newprog)
667
668
669 jmp := obj.Appendp(unspill, c.newprog)
670 jmp.As = AJMP
671 jmp.To.Type = obj.TYPE_BRANCH
672 jmp.To.SetTarget(startPred.Link)
673 jmp.Spadj = +framesize
674
675 return end
676 }
677
678 var Linkloong64 = obj.LinkArch{
679 Arch: sys.ArchLoong64,
680 Init: buildop,
681 Preprocess: preprocess,
682 Assemble: span0,
683 Progedit: progedit,
684 UnaryDst: unaryDst,
685 DWARFRegisters: LOONG64DWARFRegisters,
686 }
687
View as plain text