Source file src/cmd/internal/obj/s390x/objz.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package s390x
31
32 import (
33 "cmd/internal/obj"
34 "cmd/internal/objabi"
35 "cmd/internal/sys"
36 "math"
37 )
38
39 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
40 p.From.Class = 0
41 p.To.Class = 0
42
43 c := ctxtz{ctxt: ctxt, newprog: newprog}
44
45
46 switch p.As {
47 case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
48 if p.To.Sym != nil {
49 p.To.Type = obj.TYPE_BRANCH
50 }
51 }
52
53
54 switch p.As {
55 case AFMOVS:
56 if p.From.Type == obj.TYPE_FCONST {
57 f32 := float32(p.From.Val.(float64))
58 if math.Float32bits(f32) == 0 {
59 break
60 }
61 p.From.Type = obj.TYPE_MEM
62 p.From.Sym = ctxt.Float32Sym(f32)
63 p.From.Name = obj.NAME_EXTERN
64 p.From.Offset = 0
65 }
66
67 case AFMOVD:
68 if p.From.Type == obj.TYPE_FCONST {
69 f64 := p.From.Val.(float64)
70 if math.Float64bits(f64) == 0 {
71 break
72 }
73 p.From.Type = obj.TYPE_MEM
74 p.From.Sym = ctxt.Float64Sym(f64)
75 p.From.Name = obj.NAME_EXTERN
76 p.From.Offset = 0
77 }
78
79
80 case AMOVD:
81 if p.From.Type == obj.TYPE_CONST {
82 val := p.From.Offset
83 if int64(int32(val)) != val &&
84 int64(uint32(val)) != val &&
85 int64(uint64(val)&(0xffffffff<<32)) != val {
86 p.From.Type = obj.TYPE_MEM
87 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
88 p.From.Name = obj.NAME_EXTERN
89 p.From.Offset = 0
90 }
91 }
92 }
93
94
95 switch p.As {
96 case ASUBC:
97 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
98 p.From.Offset = -p.From.Offset
99 p.As = AADDC
100 }
101
102 case ASUB:
103 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
104 p.From.Offset = -p.From.Offset
105 p.As = AADD
106 }
107 }
108
109 if c.ctxt.Flag_dynlink {
110 c.rewriteToUseGot(p)
111 }
112 }
113
114
115 func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
116
117
118 if p.As == AEXRL {
119 return
120 }
121
122
123
124
125
126
127 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
128
129
130 if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
131 c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
132 }
133 p.From.Type = obj.TYPE_MEM
134 p.From.Name = obj.NAME_GOTREF
135 q := p
136 if p.From.Offset != 0 {
137 target := p.To.Reg
138 if target == REG_R0 {
139
140
141 p.To.Reg = REGTMP2
142 }
143 q = obj.Appendp(q, c.newprog)
144 q.As = AMOVD
145 q.From.Type = obj.TYPE_ADDR
146 q.From.Offset = p.From.Offset
147 q.From.Reg = p.To.Reg
148 q.To.Type = obj.TYPE_REG
149 q.To.Reg = target
150 p.From.Offset = 0
151 }
152 }
153 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
154 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
155 }
156 var source *obj.Addr
157
158
159
160 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
161 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
162 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
163 }
164 source = &p.From
165 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
166 source = &p.To
167 } else {
168 return
169 }
170 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
171 return
172 }
173 if source.Sym.Type == objabi.STLSBSS {
174 return
175 }
176 if source.Type != obj.TYPE_MEM {
177 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
178 }
179 p1 := obj.Appendp(p, c.newprog)
180 p2 := obj.Appendp(p1, c.newprog)
181
182 p1.As = AMOVD
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 = REGTMP2
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 = REGTMP2
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 = REGTMP2
198 p2.To.Name = obj.NAME_NONE
199 p2.To.Sym = nil
200 } else {
201 return
202 }
203 obj.Nopout(p)
204 }
205
206 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
207
208 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
209 return
210 }
211
212 c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
213
214 p := c.cursym.Func.Text
215 textstksiz := p.To.Offset
216 if textstksiz == -8 {
217
218 p.From.Sym.Set(obj.AttrNoFrame, true)
219 textstksiz = 0
220 }
221 if textstksiz%8 != 0 {
222 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
223 }
224 if p.From.Sym.NoFrame() {
225 if textstksiz != 0 {
226 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
227 }
228 }
229
230 c.cursym.Func.Args = p.To.Val.(int32)
231 c.cursym.Func.Locals = int32(textstksiz)
232
233
238
239 var q *obj.Prog
240 for p := c.cursym.Func.Text; p != nil; p = p.Link {
241 switch p.As {
242 case obj.ATEXT:
243 q = p
244 p.Mark |= LEAF
245
246 case ABL, ABCL:
247 q = p
248 c.cursym.Func.Text.Mark &^= LEAF
249 fallthrough
250
251 case ABC,
252 ABEQ,
253 ABGE,
254 ABGT,
255 ABLE,
256 ABLT,
257 ABLEU,
258 ABLTU,
259 ABNE,
260 ABR,
261 ABVC,
262 ABVS,
263 ACMPBEQ,
264 ACMPBGE,
265 ACMPBGT,
266 ACMPBLE,
267 ACMPBLT,
268 ACMPBNE,
269 ACMPUBEQ,
270 ACMPUBGE,
271 ACMPUBGT,
272 ACMPUBLE,
273 ACMPUBLT,
274 ACMPUBNE:
275 q = p
276 p.Mark |= BRANCH
277 if p.Pcond != nil {
278 q := p.Pcond
279 for q.As == obj.ANOP {
280 q = q.Link
281 p.Pcond = q
282 }
283 }
284
285 case obj.ANOP:
286 q.Link = p.Link
287 p.Link.Mark |= p.Mark
288
289 default:
290 q = p
291 }
292 }
293
294 autosize := int32(0)
295 var pLast *obj.Prog
296 var pPre *obj.Prog
297 var pPreempt *obj.Prog
298 wasSplit := false
299 for p := c.cursym.Func.Text; p != nil; p = p.Link {
300 pLast = p
301 switch p.As {
302 case obj.ATEXT:
303 autosize = int32(textstksiz)
304
305 if p.Mark&LEAF != 0 && autosize == 0 {
306
307 p.From.Sym.Set(obj.AttrNoFrame, true)
308 }
309
310 if !p.From.Sym.NoFrame() {
311
312
313 autosize += int32(c.ctxt.FixedFrameSize())
314 }
315
316 if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
317
318
319 p.From.Sym.Set(obj.AttrNoSplit, true)
320 }
321
322 p.To.Offset = int64(autosize)
323
324 q := p
325
326 if !p.From.Sym.NoSplit() {
327 p, pPreempt = c.stacksplitPre(p, autosize)
328 pPre = p
329 wasSplit = true
330 }
331
332 if autosize != 0 {
333
334
335
336
337
338 q = obj.Appendp(p, c.newprog)
339 q.As = AMOVD
340 q.From.Type = obj.TYPE_REG
341 q.From.Reg = REG_LR
342 q.To.Type = obj.TYPE_MEM
343 q.To.Reg = REGSP
344 q.To.Offset = int64(-autosize)
345
346 q = obj.Appendp(q, c.newprog)
347 q.As = AMOVD
348 q.From.Type = obj.TYPE_ADDR
349 q.From.Offset = int64(-autosize)
350 q.From.Reg = REGSP
351 q.To.Type = obj.TYPE_REG
352 q.To.Reg = REGSP
353 q.Spadj = autosize
354 } else if c.cursym.Func.Text.Mark&LEAF == 0 {
355
356
357
358 c.cursym.Func.Text.Mark |= LEAF
359 }
360
361 if c.cursym.Func.Text.Mark&LEAF != 0 {
362 c.cursym.Set(obj.AttrLeaf, true)
363 break
364 }
365
366 if c.cursym.Func.Text.From.Sym.Wrapper() {
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 q = obj.Appendp(q, c.newprog)
385
386 q.As = AMOVD
387 q.From.Type = obj.TYPE_MEM
388 q.From.Reg = REGG
389 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
390 q.To.Type = obj.TYPE_REG
391 q.To.Reg = REG_R3
392
393 q = obj.Appendp(q, c.newprog)
394 q.As = ACMP
395 q.From.Type = obj.TYPE_REG
396 q.From.Reg = REG_R3
397 q.To.Type = obj.TYPE_CONST
398 q.To.Offset = 0
399
400 q = obj.Appendp(q, c.newprog)
401 q.As = ABEQ
402 q.To.Type = obj.TYPE_BRANCH
403 p1 := q
404
405 q = obj.Appendp(q, c.newprog)
406 q.As = AMOVD
407 q.From.Type = obj.TYPE_MEM
408 q.From.Reg = REG_R3
409 q.From.Offset = 0
410 q.To.Type = obj.TYPE_REG
411 q.To.Reg = REG_R4
412
413 q = obj.Appendp(q, c.newprog)
414 q.As = AADD
415 q.From.Type = obj.TYPE_CONST
416 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
417 q.Reg = REGSP
418 q.To.Type = obj.TYPE_REG
419 q.To.Reg = REG_R5
420
421 q = obj.Appendp(q, c.newprog)
422 q.As = ACMP
423 q.From.Type = obj.TYPE_REG
424 q.From.Reg = REG_R4
425 q.To.Type = obj.TYPE_REG
426 q.To.Reg = REG_R5
427
428 q = obj.Appendp(q, c.newprog)
429 q.As = ABNE
430 q.To.Type = obj.TYPE_BRANCH
431 p2 := q
432
433 q = obj.Appendp(q, c.newprog)
434 q.As = AADD
435 q.From.Type = obj.TYPE_CONST
436 q.From.Offset = c.ctxt.FixedFrameSize()
437 q.Reg = REGSP
438 q.To.Type = obj.TYPE_REG
439 q.To.Reg = REG_R6
440
441 q = obj.Appendp(q, c.newprog)
442 q.As = AMOVD
443 q.From.Type = obj.TYPE_REG
444 q.From.Reg = REG_R6
445 q.To.Type = obj.TYPE_MEM
446 q.To.Reg = REG_R3
447 q.To.Offset = 0
448
449 q = obj.Appendp(q, c.newprog)
450
451 q.As = obj.ANOP
452 p1.Pcond = q
453 p2.Pcond = q
454 }
455
456 case obj.ARET:
457 retTarget := p.To.Sym
458
459 if c.cursym.Func.Text.Mark&LEAF != 0 {
460 if autosize == 0 {
461 p.As = ABR
462 p.From = obj.Addr{}
463 if retTarget == nil {
464 p.To.Type = obj.TYPE_REG
465 p.To.Reg = REG_LR
466 } else {
467 p.To.Type = obj.TYPE_BRANCH
468 p.To.Sym = retTarget
469 }
470 p.Mark |= BRANCH
471 break
472 }
473
474 p.As = AADD
475 p.From.Type = obj.TYPE_CONST
476 p.From.Offset = int64(autosize)
477 p.To.Type = obj.TYPE_REG
478 p.To.Reg = REGSP
479 p.Spadj = -autosize
480
481 q = obj.Appendp(p, c.newprog)
482 q.As = ABR
483 q.From = obj.Addr{}
484 q.To.Type = obj.TYPE_REG
485 q.To.Reg = REG_LR
486 q.Mark |= BRANCH
487 q.Spadj = autosize
488 break
489 }
490
491 p.As = AMOVD
492 p.From.Type = obj.TYPE_MEM
493 p.From.Reg = REGSP
494 p.From.Offset = 0
495 p.To.Type = obj.TYPE_REG
496 p.To.Reg = REG_LR
497
498 q = p
499
500 if autosize != 0 {
501 q = obj.Appendp(q, c.newprog)
502 q.As = AADD
503 q.From.Type = obj.TYPE_CONST
504 q.From.Offset = int64(autosize)
505 q.To.Type = obj.TYPE_REG
506 q.To.Reg = REGSP
507 q.Spadj = -autosize
508 }
509
510 q = obj.Appendp(q, c.newprog)
511 q.As = ABR
512 q.From = obj.Addr{}
513 if retTarget == nil {
514 q.To.Type = obj.TYPE_REG
515 q.To.Reg = REG_LR
516 } else {
517 q.To.Type = obj.TYPE_BRANCH
518 q.To.Sym = retTarget
519 }
520 q.Mark |= BRANCH
521 q.Spadj = autosize
522
523 case AADD:
524 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
525 p.Spadj = int32(-p.From.Offset)
526 }
527
528 case obj.AGETCALLERPC:
529 if cursym.Leaf() {
530
531 p.As = AMOVD
532 p.From.Type = obj.TYPE_REG
533 p.From.Reg = REG_LR
534 } else {
535
536 p.As = AMOVD
537 p.From.Type = obj.TYPE_MEM
538 p.From.Reg = REGSP
539 }
540 }
541 }
542 if wasSplit {
543 c.stacksplitPost(pLast, pPre, pPreempt, autosize)
544 }
545 }
546
547 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
548 var q *obj.Prog
549
550
551 p = obj.Appendp(p, c.newprog)
552
553 p.As = AMOVD
554 p.From.Type = obj.TYPE_MEM
555 p.From.Reg = REGG
556 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
557 if c.cursym.CFunc() {
558 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
559 }
560 p.To.Type = obj.TYPE_REG
561 p.To.Reg = REG_R3
562
563 q = nil
564 if framesize <= objabi.StackSmall {
565
566
567
568
569
570
571
572
573 p = obj.Appendp(p, c.newprog)
574
575 p.From.Type = obj.TYPE_REG
576 p.From.Reg = REG_R3
577 p.Reg = REGSP
578 p.As = ACMPUBGE
579 p.To.Type = obj.TYPE_BRANCH
580
581
582
583
584
585
586
587
588
589
590
591
592 } else if framesize <= objabi.StackBig {
593
594
595
596 p = obj.Appendp(p, c.newprog)
597
598 p.As = AADD
599 p.From.Type = obj.TYPE_CONST
600 p.From.Offset = -(int64(framesize) - objabi.StackSmall)
601 p.Reg = REGSP
602 p.To.Type = obj.TYPE_REG
603 p.To.Reg = REG_R4
604
605 p = obj.Appendp(p, c.newprog)
606 p.From.Type = obj.TYPE_REG
607 p.From.Reg = REG_R3
608 p.Reg = REG_R4
609 p.As = ACMPUBGE
610 p.To.Type = obj.TYPE_BRANCH
611
612 } else {
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628 p = obj.Appendp(p, c.newprog)
629
630 p.As = ACMP
631 p.From.Type = obj.TYPE_REG
632 p.From.Reg = REG_R3
633 p.To.Type = obj.TYPE_CONST
634 p.To.Offset = objabi.StackPreempt
635
636 p = obj.Appendp(p, c.newprog)
637 q = p
638 p.As = ABEQ
639 p.To.Type = obj.TYPE_BRANCH
640
641 p = obj.Appendp(p, c.newprog)
642 p.As = AADD
643 p.From.Type = obj.TYPE_CONST
644 p.From.Offset = int64(objabi.StackGuard)
645 p.Reg = REGSP
646 p.To.Type = obj.TYPE_REG
647 p.To.Reg = REG_R4
648
649 p = obj.Appendp(p, c.newprog)
650 p.As = ASUB
651 p.From.Type = obj.TYPE_REG
652 p.From.Reg = REG_R3
653 p.To.Type = obj.TYPE_REG
654 p.To.Reg = REG_R4
655
656 p = obj.Appendp(p, c.newprog)
657 p.As = AMOVD
658 p.From.Type = obj.TYPE_CONST
659 p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
660 p.To.Type = obj.TYPE_REG
661 p.To.Reg = REGTMP
662
663 p = obj.Appendp(p, c.newprog)
664 p.From.Type = obj.TYPE_REG
665 p.From.Reg = REGTMP
666 p.Reg = REG_R4
667 p.As = ACMPUBGE
668 p.To.Type = obj.TYPE_BRANCH
669 }
670
671 return p, q
672 }
673
674 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
675
676
677
678 spfix := obj.Appendp(p, c.newprog)
679 spfix.As = obj.ANOP
680 spfix.Spadj = -framesize
681
682 pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
683
684
685 p = obj.Appendp(pcdata, c.newprog)
686 pPre.Pcond = p
687 p.As = AMOVD
688 p.From.Type = obj.TYPE_REG
689 p.From.Reg = REG_LR
690 p.To.Type = obj.TYPE_REG
691 p.To.Reg = REG_R5
692 if pPreempt != nil {
693 pPreempt.Pcond = p
694 }
695
696
697 p = obj.Appendp(p, c.newprog)
698
699 p.As = ABL
700 p.To.Type = obj.TYPE_BRANCH
701 if c.cursym.CFunc() {
702 p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
703 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
704 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
705 } else {
706 p.To.Sym = c.ctxt.Lookup("runtime.morestack")
707 }
708
709
710 p = obj.Appendp(p, c.newprog)
711
712 p.As = ABR
713 p.To.Type = obj.TYPE_BRANCH
714 p.Pcond = c.cursym.Func.Text.Link
715 return p
716 }
717
718 var unaryDst = map[obj.As]bool{
719 ASTCK: true,
720 ASTCKC: true,
721 ASTCKE: true,
722 ASTCKF: true,
723 ANEG: true,
724 ANEGW: true,
725 AVONE: true,
726 AVZERO: true,
727 }
728
729 var Links390x = obj.LinkArch{
730 Arch: sys.ArchS390X,
731 Init: buildop,
732 Preprocess: preprocess,
733 Assemble: spanz,
734 Progedit: progedit,
735 UnaryDst: unaryDst,
736 DWARFRegisters: S390XDWARFRegisters,
737 }
738
View as plain text