blob: 610f251070026f5118d895a84c5e88e542543ffa [file] [log] [blame]
Russ Coxb115c352015-03-18 17:26:36 -04001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gc
6
7import (
8 "cmd/internal/obj"
9 "fmt"
10)
11
12/*
13 * generate:
14 * res = n;
15 * simplifies and calls Thearch.Gmove.
16 */
17func Cgen(n *Node, res *Node) {
18 if Debug['g'] != 0 {
19 Dump("\ncgen-n", n)
20 Dump("cgen-res", res)
21 }
22
23 if n == nil || n.Type == nil {
24 return
25 }
26
27 if res == nil || res.Type == nil {
28 Fatal("cgen: res nil")
29 }
30
31 for n.Op == OCONVNOP {
32 n = n.Left
33 }
34
35 switch n.Op {
36 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
37 if res.Op != ONAME || res.Addable == 0 {
38 var n1 Node
39 Tempname(&n1, n.Type)
40 Cgen_slice(n, &n1)
41 Cgen(&n1, res)
42 } else {
43 Cgen_slice(n, res)
44 }
45 return
46
47 case OEFACE:
48 if res.Op != ONAME || res.Addable == 0 {
49 var n1 Node
50 Tempname(&n1, n.Type)
51 Cgen_eface(n, &n1)
52 Cgen(&n1, res)
53 } else {
54 Cgen_eface(n, res)
55 }
56 return
57 }
58
59 if n.Ullman >= UINF {
60 if n.Op == OINDREG {
61 Fatal("cgen: this is going to miscompile")
62 }
63 if res.Ullman >= UINF {
64 var n1 Node
65 Tempname(&n1, n.Type)
66 Cgen(n, &n1)
67 Cgen(&n1, res)
68 return
69 }
70 }
71
72 if Isfat(n.Type) {
73 if n.Type.Width < 0 {
74 Fatal("forgot to compute width for %v", Tconv(n.Type, 0))
75 }
76 sgen(n, res, n.Type.Width)
77 return
78 }
79
80 if res.Addable == 0 {
81 if n.Ullman > res.Ullman {
82 if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
83 var n1 Node
84 Tempname(&n1, n.Type)
85 Cgen(n, &n1)
86 Cgen(&n1, res)
87 return
88 }
89
90 var n1 Node
91 Regalloc(&n1, n.Type, res)
92 Cgen(n, &n1)
93 if n1.Ullman > res.Ullman {
94 Dump("n1", &n1)
95 Dump("res", res)
96 Fatal("loop in cgen")
97 }
98
99 Cgen(&n1, res)
100 Regfree(&n1)
101 return
102 }
103
104 var f int
105 if res.Ullman >= UINF {
106 goto gen
107 }
108
109 if Complexop(n, res) {
110 Complexgen(n, res)
111 return
112 }
113
114 f = 1 // gen thru register
115 switch n.Op {
116 case OLITERAL:
117 if Smallintconst(n) {
118 f = 0
119 }
120
121 case OREGISTER:
122 f = 0
123 }
124
125 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
126 a := Thearch.Optoas(OAS, res.Type)
127 var addr obj.Addr
128 if Thearch.Sudoaddable(a, res, &addr) {
129 var p1 *obj.Prog
130 if f != 0 {
131 var n2 Node
132 Regalloc(&n2, res.Type, nil)
133 Cgen(n, &n2)
134 p1 = Thearch.Gins(a, &n2, nil)
135 Regfree(&n2)
136 } else {
137 p1 = Thearch.Gins(a, n, nil)
138 }
139 p1.To = addr
140 if Debug['g'] != 0 {
141 fmt.Printf("%v [ignore previous line]\n", p1)
142 }
143 Thearch.Sudoclean()
144 return
145 }
146 }
147
148 gen:
149 if Ctxt.Arch.Thechar == '8' {
150 // no registers to speak of
151 var n1, n2 Node
152 Tempname(&n1, n.Type)
153 Cgen(n, &n1)
154 Igen(res, &n2, nil)
155 Thearch.Gmove(&n1, &n2)
156 Regfree(&n2)
157 return
158 }
159
160 var n1 Node
161 Igen(res, &n1, nil)
162 Cgen(n, &n1)
163 Regfree(&n1)
164 return
165 }
166
167 // update addressability for string, slice
168 // can't do in walk because n->left->addable
169 // changes if n->left is an escaping local variable.
170 switch n.Op {
171 case OSPTR,
172 OLEN:
173 if Isslice(n.Left.Type) || Istype(n.Left.Type, TSTRING) {
174 n.Addable = n.Left.Addable
175 }
176
177 case OCAP:
178 if Isslice(n.Left.Type) {
179 n.Addable = n.Left.Addable
180 }
181
182 case OITAB:
183 n.Addable = n.Left.Addable
184 }
185
186 if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
187 // if both are addressable, move
188 if n.Addable != 0 && res.Addable != 0 {
189 if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] {
190 Thearch.Gmove(n, res)
191 } else {
192 var n1 Node
193 Regalloc(&n1, n.Type, nil)
194 Thearch.Gmove(n, &n1)
195 Cgen(&n1, res)
196 Regfree(&n1)
197 }
198
199 return
200 }
201
202 // if both are not addressable, use a temporary.
203 if n.Addable == 0 && res.Addable == 0 {
204 // could use regalloc here sometimes,
205 // but have to check for ullman >= UINF.
206 var n1 Node
207 Tempname(&n1, n.Type)
208 Cgen(n, &n1)
209 Cgen(&n1, res)
210 return
211 }
212
213 // if result is not addressable directly but n is,
214 // compute its address and then store via the address.
215 if res.Addable == 0 {
216 var n1 Node
217 Igen(res, &n1, nil)
218 Cgen(n, &n1)
219 Regfree(&n1)
220 return
221 }
222 }
223
224 if Complexop(n, res) {
225 Complexgen(n, res)
226 return
227 }
228
229 if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable != 0 {
230 Thearch.Gmove(n, res)
231 return
232 }
233
234 if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
235 // if both are addressable, move
236 if n.Addable != 0 {
237 if n.Op == OREGISTER || res.Op == OREGISTER {
238 Thearch.Gmove(n, res)
239 } else {
240 var n1 Node
241 Regalloc(&n1, n.Type, nil)
242 Thearch.Gmove(n, &n1)
243 Cgen(&n1, res)
244 Regfree(&n1)
245 }
246 return
247 }
248 }
249
250 // if n is sudoaddable generate addr and move
251 if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !Iscomplex[n.Type.Etype] && !Iscomplex[res.Type.Etype] {
252 a := Thearch.Optoas(OAS, n.Type)
253 var addr obj.Addr
254 if Thearch.Sudoaddable(a, n, &addr) {
255 if res.Op != OREGISTER {
256 var n2 Node
257 Regalloc(&n2, res.Type, nil)
258 p1 := Thearch.Gins(a, nil, &n2)
259 p1.From = addr
260 if Debug['g'] != 0 {
261 fmt.Printf("%v [ignore previous line]\n", p1)
262 }
263 Thearch.Gmove(&n2, res)
264 Regfree(&n2)
265 } else {
266 p1 := Thearch.Gins(a, nil, res)
267 p1.From = addr
268 if Debug['g'] != 0 {
269 fmt.Printf("%v [ignore previous line]\n", p1)
270 }
271 }
272 Thearch.Sudoclean()
273 return
274 }
275 }
276
277 nl := n.Left
278 nr := n.Right
279
280 if nl != nil && nl.Ullman >= UINF {
281 if nr != nil && nr.Ullman >= UINF {
282 var n1 Node
283 Tempname(&n1, nl.Type)
284 Cgen(nl, &n1)
285 n2 := *n
286 n2.Left = &n1
287 Cgen(&n2, res)
288 return
289 }
290 }
291
292 // 64-bit ops are hard on 32-bit machine.
293 if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
294 switch n.Op {
295 // math goes to cgen64.
296 case OMINUS,
297 OCOM,
298 OADD,
299 OSUB,
300 OMUL,
301 OLROT,
302 OLSH,
303 ORSH,
304 OAND,
305 OOR,
306 OXOR:
307 Thearch.Cgen64(n, res)
308 return
309 }
310 }
311
312 if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] {
313 Thearch.Cgen_float(n, res)
314 return
315 }
316
317 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
318 a := Thearch.Optoas(OAS, n.Type)
319 var addr obj.Addr
320 if Thearch.Sudoaddable(a, n, &addr) {
321 if res.Op == OREGISTER {
322 p1 := Thearch.Gins(a, nil, res)
323 p1.From = addr
324 } else {
325 var n2 Node
326 Regalloc(&n2, n.Type, nil)
327 p1 := Thearch.Gins(a, nil, &n2)
328 p1.From = addr
329 Thearch.Gins(a, &n2, res)
330 Regfree(&n2)
331 }
332
333 Thearch.Sudoclean()
334 return
335 }
336 }
337
338 var a int
339 switch n.Op {
340 default:
341 Dump("cgen", n)
342 Dump("cgen-res", res)
343 Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
344
345 // these call bgen to get a bool value
346 case OOROR,
347 OANDAND,
348 OEQ,
349 ONE,
350 OLT,
351 OLE,
352 OGE,
353 OGT,
354 ONOT:
355 p1 := Gbranch(obj.AJMP, nil, 0)
356
357 p2 := Pc
358 Thearch.Gmove(Nodbool(true), res)
359 p3 := Gbranch(obj.AJMP, nil, 0)
360 Patch(p1, Pc)
361 Bgen(n, true, 0, p2)
362 Thearch.Gmove(Nodbool(false), res)
363 Patch(p3, Pc)
364 return
365
366 case OPLUS:
367 Cgen(nl, res)
368 return
369
370 // unary
371 case OCOM:
372 a := Thearch.Optoas(OXOR, nl.Type)
373
374 var n1 Node
375 Regalloc(&n1, nl.Type, nil)
376 Cgen(nl, &n1)
377 var n2 Node
378 Nodconst(&n2, nl.Type, -1)
379 Thearch.Gins(a, &n2, &n1)
380 cgen_norm(n, &n1, res)
381 return
382
383 case OMINUS:
384 if Isfloat[nl.Type.Etype] {
385 nr = Nodintconst(-1)
386 Convlit(&nr, n.Type)
387 a = Thearch.Optoas(OMUL, nl.Type)
388 goto sbop
389 }
390
391 a := Thearch.Optoas(int(n.Op), nl.Type)
392 // unary
393 var n1 Node
394 Regalloc(&n1, nl.Type, res)
395
396 Cgen(nl, &n1)
397 if Ctxt.Arch.Thechar == '5' {
398 var n2 Node
399 Nodconst(&n2, nl.Type, 0)
400 Thearch.Gins(a, &n2, &n1)
401 } else if Ctxt.Arch.Thechar == '7' {
402 Thearch.Gins(a, &n1, &n1)
403 } else {
404 Thearch.Gins(a, nil, &n1)
405 }
406 cgen_norm(n, &n1, res)
407 return
408
409 // symmetric binary
410 case OAND,
411 OOR,
412 OXOR,
413 OADD,
414 OMUL:
415 if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(int(n.Op), nl, nr, res) {
416 break
417 }
418 a = Thearch.Optoas(int(n.Op), nl.Type)
419 goto sbop
420
421 // asymmetric binary
422 case OSUB:
423 a = Thearch.Optoas(int(n.Op), nl.Type)
424 goto abop
425
426 case OHMUL:
427 Thearch.Cgen_hmul(nl, nr, res)
428
429 case OCONV:
430 if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) {
431 Cgen(nl, res)
432 return
433 }
434
435 if Ctxt.Arch.Thechar == '8' {
436 var n1 Node
437 var n2 Node
438 Tempname(&n2, n.Type)
439 Mgen(nl, &n1, res)
440 Thearch.Gmove(&n1, &n2)
441 Thearch.Gmove(&n2, res)
442 Mfree(&n1)
443 break
444 }
445
446 var n1 Node
447 var n2 Node
448 if Ctxt.Arch.Thechar == '5' {
449 if nl.Addable != 0 && !Is64(nl.Type) {
450 Regalloc(&n1, nl.Type, res)
451 Thearch.Gmove(nl, &n1)
452 } else {
453 if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] {
454 Tempname(&n1, nl.Type)
455 } else {
456 Regalloc(&n1, nl.Type, res)
457 }
458 Cgen(nl, &n1)
459 }
460 if n.Type.Width > int64(Widthptr) || Is64(n.Type) || Isfloat[n.Type.Etype] {
461 Tempname(&n2, n.Type)
462 } else {
463 Regalloc(&n2, n.Type, nil)
464 }
465 } else {
466 if n.Type.Width > nl.Type.Width {
467 // If loading from memory, do conversion during load,
468 // so as to avoid use of 8-bit register in, say, int(*byteptr).
469 switch nl.Op {
470 case ODOT, ODOTPTR, OINDEX, OIND, ONAME:
471 Igen(nl, &n1, res)
472 Regalloc(&n2, n.Type, res)
473 Thearch.Gmove(&n1, &n2)
474 Thearch.Gmove(&n2, res)
475 Regfree(&n2)
476 Regfree(&n1)
477 return
478 }
479 }
480 Regalloc(&n1, nl.Type, res)
481 Regalloc(&n2, n.Type, &n1)
482 Cgen(nl, &n1)
483 }
484
485 // if we do the conversion n1 -> n2 here
486 // reusing the register, then gmove won't
487 // have to allocate its own register.
488 Thearch.Gmove(&n1, &n2)
489 Thearch.Gmove(&n2, res)
490 if n2.Op == OREGISTER {
491 Regfree(&n2)
492 }
493 if n1.Op == OREGISTER {
494 Regfree(&n1)
495 }
496
497 case ODOT,
498 ODOTPTR,
499 OINDEX,
500 OIND,
501 ONAME: // PHEAP or PPARAMREF var
502 var n1 Node
503 Igen(n, &n1, res)
504
505 Thearch.Gmove(&n1, res)
506 Regfree(&n1)
507
508 // interface table is first word of interface value
509 case OITAB:
510 var n1 Node
511 Igen(nl, &n1, res)
512
513 n1.Type = n.Type
514 Thearch.Gmove(&n1, res)
515 Regfree(&n1)
516
517 case OSPTR:
518 // pointer is the first word of string or slice.
519 if Isconst(nl, CTSTR) {
520 var n1 Node
521 Regalloc(&n1, Types[Tptr], res)
522 p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1)
523 Datastring(nl.Val.U.Sval, &p1.From)
524 p1.From.Type = obj.TYPE_ADDR
525 Thearch.Gmove(&n1, res)
526 Regfree(&n1)
527 break
528 }
529
530 var n1 Node
531 Igen(nl, &n1, res)
532 n1.Type = n.Type
533 Thearch.Gmove(&n1, res)
534 Regfree(&n1)
535
536 case OLEN:
537 if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) {
538 // map and chan have len in the first int-sized word.
539 // a zero pointer means zero length
540 var n1 Node
541 Regalloc(&n1, Types[Tptr], res)
542
543 Cgen(nl, &n1)
544
545 var n2 Node
546 Nodconst(&n2, Types[Tptr], 0)
547 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
548 p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
549
550 n2 = n1
551 n2.Op = OINDREG
552 n2.Type = Types[Simtype[TINT]]
553 Thearch.Gmove(&n2, &n1)
554
555 Patch(p1, Pc)
556
557 Thearch.Gmove(&n1, res)
558 Regfree(&n1)
559 break
560 }
561
562 if Istype(nl.Type, TSTRING) || Isslice(nl.Type) {
563 // both slice and string have len one pointer into the struct.
564 // a zero pointer means zero length
565 var n1 Node
566 Igen(nl, &n1, res)
567
568 n1.Type = Types[Simtype[TUINT]]
569 n1.Xoffset += int64(Array_nel)
570 Thearch.Gmove(&n1, res)
571 Regfree(&n1)
572 break
573 }
574
575 Fatal("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong))
576
577 case OCAP:
578 if Istype(nl.Type, TCHAN) {
579 // chan has cap in the second int-sized word.
580 // a zero pointer means zero length
581 var n1 Node
582 Regalloc(&n1, Types[Tptr], res)
583
584 Cgen(nl, &n1)
585
586 var n2 Node
587 Nodconst(&n2, Types[Tptr], 0)
588 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
589 p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
590
591 n2 = n1
592 n2.Op = OINDREG
593 n2.Xoffset = int64(Widthint)
594 n2.Type = Types[Simtype[TINT]]
595 Thearch.Gmove(&n2, &n1)
596
597 Patch(p1, Pc)
598
599 Thearch.Gmove(&n1, res)
600 Regfree(&n1)
601 break
602 }
603
604 if Isslice(nl.Type) {
605 var n1 Node
606 Igen(nl, &n1, res)
607 n1.Type = Types[Simtype[TUINT]]
608 n1.Xoffset += int64(Array_cap)
609 Thearch.Gmove(&n1, res)
610 Regfree(&n1)
611 break
612 }
613
614 Fatal("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong))
615
616 case OADDR:
617 if n.Bounded { // let race detector avoid nil checks
618 Disable_checknil++
619 }
620 Agen(nl, res)
621 if n.Bounded {
622 Disable_checknil--
623 }
624
625 case OCALLMETH:
626 cgen_callmeth(n, 0)
627 cgen_callret(n, res)
628
629 case OCALLINTER:
630 cgen_callinter(n, res, 0)
631 cgen_callret(n, res)
632
633 case OCALLFUNC:
634 cgen_call(n, 0)
635 cgen_callret(n, res)
636
637 case OMOD, ODIV:
638 if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil {
639 a = Thearch.Optoas(int(n.Op), nl.Type)
640 goto abop
641 }
642
643 if nl.Ullman >= nr.Ullman {
644 var n1 Node
645 Regalloc(&n1, nl.Type, res)
646 Cgen(nl, &n1)
647 cgen_div(int(n.Op), &n1, nr, res)
648 Regfree(&n1)
649 } else {
650 var n2 Node
651 if !Smallintconst(nr) {
652 Regalloc(&n2, nr.Type, res)
653 Cgen(nr, &n2)
654 } else {
655 n2 = *nr
656 }
657
658 cgen_div(int(n.Op), nl, &n2, res)
659 if n2.Op != OLITERAL {
660 Regfree(&n2)
661 }
662 }
663
664 case OLSH,
665 ORSH,
666 OLROT:
667 Thearch.Cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
668 }
669
670 return
671
672 /*
673 * put simplest on right - we'll generate into left
674 * and then adjust it using the computation of right.
675 * constants and variables have the same ullman
676 * count, so look for constants specially.
677 *
678 * an integer constant we can use as an immediate
679 * is simpler than a variable - we can use the immediate
680 * in the adjustment instruction directly - so it goes
681 * on the right.
682 *
683 * other constants, like big integers or floating point
684 * constants, require a mov into a register, so those
685 * might as well go on the left, so we can reuse that
686 * register for the computation.
687 */
688sbop: // symmetric binary
689 if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) {
690 r := nl
691 nl = nr
692 nr = r
693 }
694
695abop: // asymmetric binary
696 var n1 Node
697 var n2 Node
698 if Ctxt.Arch.Thechar == '8' {
699 // no registers, sigh
700 if Smallintconst(nr) {
701 var n1 Node
702 Mgen(nl, &n1, res)
703 var n2 Node
704 Regalloc(&n2, nl.Type, &n1)
705 Thearch.Gmove(&n1, &n2)
706 Thearch.Gins(a, nr, &n2)
707 Thearch.Gmove(&n2, res)
708 Regfree(&n2)
709 Mfree(&n1)
710 } else if nl.Ullman >= nr.Ullman {
711 var nt Node
712 Tempname(&nt, nl.Type)
713 Cgen(nl, &nt)
714 var n2 Node
715 Mgen(nr, &n2, nil)
716 var n1 Node
717 Regalloc(&n1, nl.Type, res)
718 Thearch.Gmove(&nt, &n1)
719 Thearch.Gins(a, &n2, &n1)
720 Thearch.Gmove(&n1, res)
721 Regfree(&n1)
722 Mfree(&n2)
723 } else {
724 var n2 Node
725 Regalloc(&n2, nr.Type, res)
726 Cgen(nr, &n2)
727 var n1 Node
728 Regalloc(&n1, nl.Type, nil)
729 Cgen(nl, &n1)
730 Thearch.Gins(a, &n2, &n1)
731 Regfree(&n2)
732 Thearch.Gmove(&n1, res)
733 Regfree(&n1)
734 }
735 return
736 }
737
738 if nl.Ullman >= nr.Ullman {
739 Regalloc(&n1, nl.Type, res)
740 Cgen(nl, &n1)
741
742 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
743 n2 = *nr
744 } else {
745 Regalloc(&n2, nr.Type, nil)
746 Cgen(nr, &n2)
747 }
748 } else {
749 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
750 n2 = *nr
751 } else {
752 Regalloc(&n2, nr.Type, res)
753 Cgen(nr, &n2)
754 }
755
756 Regalloc(&n1, nl.Type, nil)
757 Cgen(nl, &n1)
758 }
759
760 Thearch.Gins(a, &n2, &n1)
761 if n2.Op != OLITERAL {
762 Regfree(&n2)
763 }
764 cgen_norm(n, &n1, res)
765}
766
767// cgen_norm moves n1 to res, truncating to expected type if necessary.
768// n1 is a register, and cgen_norm frees it.
769func cgen_norm(n, n1, res *Node) {
770 switch Ctxt.Arch.Thechar {
771 case '6', '8':
772 // We use sized math, so the result is already truncated.
773 default:
774 switch n.Op {
775 case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS:
776 // TODO(rsc): What about left shift?
777 Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1)
778 }
779 }
780
781 Thearch.Gmove(n1, res)
782 Regfree(n1)
783}
784
785func Mgen(n *Node, n1 *Node, rg *Node) {
786 n1.Op = OEMPTY
787
788 if n.Addable != 0 {
789 *n1 = *n
790 if n1.Op == OREGISTER || n1.Op == OINDREG {
791 reg[n.Val.U.Reg-int16(Thearch.REGMIN)]++
792 }
793 return
794 }
795
796 Tempname(n1, n.Type)
797 Cgen(n, n1)
798 if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] {
799 n2 := *n1
800 Regalloc(n1, n.Type, rg)
801 Thearch.Gmove(&n2, n1)
802 }
803}
804
805func Mfree(n *Node) {
806 if n.Op == OREGISTER {
807 Regfree(n)
808 }
809}
810
811/*
812 * allocate a register (reusing res if possible) and generate
813 * a = n
814 * The caller must call Regfree(a).
815 */
816func Cgenr(n *Node, a *Node, res *Node) {
817 if Debug['g'] != 0 {
818 Dump("cgenr-n", n)
819 }
820
821 if Isfat(n.Type) {
822 Fatal("cgenr on fat node")
823 }
824
825 if n.Addable != 0 {
826 Regalloc(a, n.Type, res)
827 Thearch.Gmove(n, a)
828 return
829 }
830
831 switch n.Op {
832 case ONAME,
833 ODOT,
834 ODOTPTR,
835 OINDEX,
836 OCALLFUNC,
837 OCALLMETH,
838 OCALLINTER:
839 var n1 Node
840 Igen(n, &n1, res)
841 Regalloc(a, Types[Tptr], &n1)
842 Thearch.Gmove(&n1, a)
843 Regfree(&n1)
844
845 default:
846 Regalloc(a, n.Type, res)
847 Cgen(n, a)
848 }
849}
850
851/*
852 * allocate a register (reusing res if possible) and generate
853 * a = &n
854 * The caller must call Regfree(a).
855 * The generated code checks that the result is not nil.
856 */
857func Agenr(n *Node, a *Node, res *Node) {
858 if Debug['g'] != 0 {
859 Dump("\nagenr-n", n)
860 }
861
862 nl := n.Left
863 nr := n.Right
864
865 switch n.Op {
866 case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER:
867 var n1 Node
868 Igen(n, &n1, res)
869 Regalloc(a, Types[Tptr], &n1)
870 Agen(&n1, a)
871 Regfree(&n1)
872
873 case OIND:
874 Cgenr(n.Left, a, res)
875 Cgen_checknil(a)
876
877 case OINDEX:
878 if Ctxt.Arch.Thechar == '5' {
879 var p2 *obj.Prog // to be patched to panicindex.
880 w := uint32(n.Type.Width)
881 bounded := Debug['B'] != 0 || n.Bounded
882 var n1 Node
883 var n3 Node
884 if nr.Addable != 0 {
885 var tmp Node
886 if !Isconst(nr, CTINT) {
887 Tempname(&tmp, Types[TINT32])
888 }
889 if !Isconst(nl, CTSTR) {
890 Agenr(nl, &n3, res)
891 }
892 if !Isconst(nr, CTINT) {
893 p2 = Thearch.Cgenindex(nr, &tmp, bounded)
894 Regalloc(&n1, tmp.Type, nil)
895 Thearch.Gmove(&tmp, &n1)
896 }
897 } else if nl.Addable != 0 {
898 if !Isconst(nr, CTINT) {
899 var tmp Node
900 Tempname(&tmp, Types[TINT32])
901 p2 = Thearch.Cgenindex(nr, &tmp, bounded)
902 Regalloc(&n1, tmp.Type, nil)
903 Thearch.Gmove(&tmp, &n1)
904 }
905
906 if !Isconst(nl, CTSTR) {
907 Agenr(nl, &n3, res)
908 }
909 } else {
910 var tmp Node
911 Tempname(&tmp, Types[TINT32])
912 p2 = Thearch.Cgenindex(nr, &tmp, bounded)
913 nr = &tmp
914 if !Isconst(nl, CTSTR) {
915 Agenr(nl, &n3, res)
916 }
917 Regalloc(&n1, tmp.Type, nil)
918 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
919 }
920
921 // &a is in &n3 (allocated in res)
922 // i is in &n1 (if not constant)
923 // w is width
924
925 // constant index
926 if Isconst(nr, CTINT) {
927 if Isconst(nl, CTSTR) {
928 Fatal("constant string constant index")
929 }
930 v := uint64(Mpgetfix(nr.Val.U.Xval))
931 var n2 Node
932 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
933 if Debug['B'] == 0 && !n.Bounded {
934 n1 = n3
935 n1.Op = OINDREG
936 n1.Type = Types[Tptr]
937 n1.Xoffset = int64(Array_nel)
938 var n4 Node
939 Regalloc(&n4, n1.Type, nil)
940 Thearch.Gmove(&n1, &n4)
941 Nodconst(&n2, Types[TUINT32], int64(v))
942 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2)
943 Regfree(&n4)
944 p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
945 Ginscall(Panicindex, 0)
946 Patch(p1, Pc)
947 }
948
949 n1 = n3
950 n1.Op = OINDREG
951 n1.Type = Types[Tptr]
952 n1.Xoffset = int64(Array_array)
953 Thearch.Gmove(&n1, &n3)
954 }
955
956 Nodconst(&n2, Types[Tptr], int64(v*uint64(w)))
957 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
958 *a = n3
959 break
960 }
961
962 var n2 Node
963 Regalloc(&n2, Types[TINT32], &n1) // i
964 Thearch.Gmove(&n1, &n2)
965 Regfree(&n1)
966
967 var n4 Node
968 if Debug['B'] == 0 && !n.Bounded {
969 // check bounds
970 if Isconst(nl, CTSTR) {
971 Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval)))
972 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
973 n1 = n3
974 n1.Op = OINDREG
975 n1.Type = Types[Tptr]
976 n1.Xoffset = int64(Array_nel)
977 Regalloc(&n4, Types[TUINT32], nil)
978 Thearch.Gmove(&n1, &n4)
979 } else {
980 Nodconst(&n4, Types[TUINT32], nl.Type.Bound)
981 }
982
983 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4)
984 if n4.Op == OREGISTER {
985 Regfree(&n4)
986 }
987 p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1)
988 if p2 != nil {
989 Patch(p2, Pc)
990 }
991 Ginscall(Panicindex, 0)
992 Patch(p1, Pc)
993 }
994
995 if Isconst(nl, CTSTR) {
996 Regalloc(&n3, Types[Tptr], res)
997 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
998 Datastring(nl.Val.U.Sval, &p1.From)
999 p1.From.Type = obj.TYPE_ADDR
1000 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1001 n1 = n3
1002 n1.Op = OINDREG
1003 n1.Type = Types[Tptr]
1004 n1.Xoffset = int64(Array_array)
1005 Thearch.Gmove(&n1, &n3)
1006 }
1007
1008 if w == 0 {
1009 // nothing to do
1010 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
1011 // done by back end
1012 } else if w == 1 {
1013 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1014 } else {
1015 Regalloc(&n4, Types[TUINT32], nil)
1016 Nodconst(&n1, Types[TUINT32], int64(w))
1017 Thearch.Gmove(&n1, &n4)
1018 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
1019 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1020 Regfree(&n4)
1021 }
1022 *a = n3
1023 Regfree(&n2)
1024 break
1025 }
1026 if Ctxt.Arch.Thechar == '8' {
1027 var p2 *obj.Prog // to be patched to panicindex.
1028 w := uint32(n.Type.Width)
1029 bounded := Debug['B'] != 0 || n.Bounded
1030 var n3 Node
1031 var tmp Node
1032 var n1 Node
1033 if nr.Addable != 0 {
1034 // Generate &nl first, and move nr into register.
1035 if !Isconst(nl, CTSTR) {
1036 Igen(nl, &n3, res)
1037 }
1038 if !Isconst(nr, CTINT) {
1039 p2 = Thearch.Igenindex(nr, &tmp, bounded)
1040 Regalloc(&n1, tmp.Type, nil)
1041 Thearch.Gmove(&tmp, &n1)
1042 }
1043 } else if nl.Addable != 0 {
1044 // Generate nr first, and move &nl into register.
1045 if !Isconst(nr, CTINT) {
1046 p2 = Thearch.Igenindex(nr, &tmp, bounded)
1047 Regalloc(&n1, tmp.Type, nil)
1048 Thearch.Gmove(&tmp, &n1)
1049 }
1050
1051 if !Isconst(nl, CTSTR) {
1052 Igen(nl, &n3, res)
1053 }
1054 } else {
1055 p2 = Thearch.Igenindex(nr, &tmp, bounded)
1056 nr = &tmp
1057 if !Isconst(nl, CTSTR) {
1058 Igen(nl, &n3, res)
1059 }
1060 Regalloc(&n1, tmp.Type, nil)
1061 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
1062 }
1063
1064 // For fixed array we really want the pointer in n3.
1065 var n2 Node
1066 if Isfixedarray(nl.Type) {
1067 Regalloc(&n2, Types[Tptr], &n3)
1068 Agen(&n3, &n2)
1069 Regfree(&n3)
1070 n3 = n2
1071 }
1072
1073 // &a[0] is in n3 (allocated in res)
1074 // i is in n1 (if not constant)
1075 // len(a) is in nlen (if needed)
1076 // w is width
1077
1078 // constant index
1079 if Isconst(nr, CTINT) {
1080 if Isconst(nl, CTSTR) {
1081 Fatal("constant string constant index") // front end should handle
1082 }
1083 v := uint64(Mpgetfix(nr.Val.U.Xval))
1084 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1085 if Debug['B'] == 0 && !n.Bounded {
1086 nlen := n3
1087 nlen.Type = Types[TUINT32]
1088 nlen.Xoffset += int64(Array_nel)
1089 Nodconst(&n2, Types[TUINT32], int64(v))
1090 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2)
1091 p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
1092 Ginscall(Panicindex, -1)
1093 Patch(p1, Pc)
1094 }
1095 }
1096
1097 // Load base pointer in n2 = n3.
1098 Regalloc(&n2, Types[Tptr], &n3)
1099
1100 n3.Type = Types[Tptr]
1101 n3.Xoffset += int64(Array_array)
1102 Thearch.Gmove(&n3, &n2)
1103 Regfree(&n3)
1104 if v*uint64(w) != 0 {
1105 Nodconst(&n1, Types[Tptr], int64(v*uint64(w)))
1106 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2)
1107 }
1108 *a = n2
1109 break
1110 }
1111
1112 // i is in register n1, extend to 32 bits.
1113 t := Types[TUINT32]
1114
1115 if Issigned[n1.Type.Etype] {
1116 t = Types[TINT32]
1117 }
1118
1119 Regalloc(&n2, t, &n1) // i
1120 Thearch.Gmove(&n1, &n2)
1121 Regfree(&n1)
1122
1123 if Debug['B'] == 0 && !n.Bounded {
1124 // check bounds
1125 t := Types[TUINT32]
1126
1127 var nlen Node
1128 if Isconst(nl, CTSTR) {
1129 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
1130 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1131 nlen = n3
1132 nlen.Type = t
1133 nlen.Xoffset += int64(Array_nel)
1134 } else {
1135 Nodconst(&nlen, t, nl.Type.Bound)
1136 }
1137
1138 Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
1139 p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
1140 if p2 != nil {
1141 Patch(p2, Pc)
1142 }
1143 Ginscall(Panicindex, -1)
1144 Patch(p1, Pc)
1145 }
1146
1147 if Isconst(nl, CTSTR) {
1148 Regalloc(&n3, Types[Tptr], res)
1149 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
1150 Datastring(nl.Val.U.Sval, &p1.From)
1151 p1.From.Type = obj.TYPE_ADDR
1152 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
1153 goto indexdone1
1154 }
1155
1156 // Load base pointer in n3.
1157 Regalloc(&tmp, Types[Tptr], &n3)
1158
1159 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1160 n3.Type = Types[Tptr]
1161 n3.Xoffset += int64(Array_array)
1162 Thearch.Gmove(&n3, &tmp)
1163 }
1164
1165 Regfree(&n3)
1166 n3 = tmp
1167
1168 if w == 0 {
1169 // nothing to do
1170 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
1171 // done by back end
1172 } else if w == 1 {
1173 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1174 } else {
1175 Nodconst(&tmp, Types[TUINT32], int64(w))
1176 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &tmp, &n2)
1177 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1178 }
1179
1180 indexdone1:
1181 *a = n3
1182 Regfree(&n2)
1183 break
1184 }
1185
1186 freelen := 0
1187 w := uint64(n.Type.Width)
1188
1189 // Generate the non-addressable child first.
1190 var n3 Node
1191 var nlen Node
1192 var tmp Node
1193 var n1 Node
1194 if nr.Addable != 0 {
1195 goto irad
1196 }
1197 if nl.Addable != 0 {
1198 Cgenr(nr, &n1, nil)
1199 if !Isconst(nl, CTSTR) {
1200 if Isfixedarray(nl.Type) {
1201 Agenr(nl, &n3, res)
1202 } else {
1203 Igen(nl, &nlen, res)
1204 freelen = 1
1205 nlen.Type = Types[Tptr]
1206 nlen.Xoffset += int64(Array_array)
1207 Regalloc(&n3, Types[Tptr], res)
1208 Thearch.Gmove(&nlen, &n3)
1209 nlen.Type = Types[Simtype[TUINT]]
1210 nlen.Xoffset += int64(Array_nel) - int64(Array_array)
1211 }
1212 }
1213
1214 goto index
1215 }
1216
1217 Tempname(&tmp, nr.Type)
1218 Cgen(nr, &tmp)
1219 nr = &tmp
1220
1221 irad:
1222 if !Isconst(nl, CTSTR) {
1223 if Isfixedarray(nl.Type) {
1224 Agenr(nl, &n3, res)
1225 } else {
1226 if nl.Addable == 0 {
1227 // igen will need an addressable node.
1228 var tmp2 Node
1229 Tempname(&tmp2, nl.Type)
1230
1231 Cgen(nl, &tmp2)
1232 nl = &tmp2
1233 }
1234
1235 Igen(nl, &nlen, res)
1236 freelen = 1
1237 nlen.Type = Types[Tptr]
1238 nlen.Xoffset += int64(Array_array)
1239 Regalloc(&n3, Types[Tptr], res)
1240 Thearch.Gmove(&nlen, &n3)
1241 nlen.Type = Types[Simtype[TUINT]]
1242 nlen.Xoffset += int64(Array_nel) - int64(Array_array)
1243 }
1244 }
1245
1246 if !Isconst(nr, CTINT) {
1247 Cgenr(nr, &n1, nil)
1248 }
1249
1250 goto index
1251
1252 // &a is in &n3 (allocated in res)
1253 // i is in &n1 (if not constant)
1254 // len(a) is in nlen (if needed)
1255 // w is width
1256
1257 // constant index
1258 index:
1259 if Isconst(nr, CTINT) {
1260 if Isconst(nl, CTSTR) {
1261 Fatal("constant string constant index") // front end should handle
1262 }
1263 v := uint64(Mpgetfix(nr.Val.U.Xval))
1264 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1265 if Debug['B'] == 0 && !n.Bounded {
1266 if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') {
1267 var tmp2 Node
1268 Regalloc(&tmp2, Types[Simtype[TUINT]], nil)
1269 Thearch.Gmove(&nlen, &tmp2)
1270 Regfree(&nlen) // in case it is OINDREG
1271 nlen = tmp2
1272 }
1273 var n2 Node
1274 Nodconst(&n2, Types[Simtype[TUINT]], int64(v))
1275 if Smallintconst(nr) {
1276 Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2)
1277 } else {
1278 Regalloc(&tmp, Types[Simtype[TUINT]], nil)
1279 Thearch.Gmove(&n2, &tmp)
1280 Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp)
1281 Regfree(&tmp)
1282 }
1283
1284 p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1)
1285 Ginscall(Panicindex, -1)
1286 Patch(p1, Pc)
1287 }
1288
1289 Regfree(&nlen)
1290 }
1291
1292 if v*w != 0 {
1293 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3)
1294 }
1295 *a = n3
1296 break
1297 }
1298
1299 // type of the index
1300 t := Types[TUINT64]
1301
1302 if Issigned[n1.Type.Etype] {
1303 t = Types[TINT64]
1304 }
1305
1306 var n2 Node
1307 Regalloc(&n2, t, &n1) // i
1308 Thearch.Gmove(&n1, &n2)
1309 Regfree(&n1)
1310
1311 if Debug['B'] == 0 && !n.Bounded {
1312 // check bounds
1313 t = Types[Simtype[TUINT]]
1314
1315 if Is64(nr.Type) {
1316 t = Types[TUINT64]
1317 }
1318 if Isconst(nl, CTSTR) {
1319 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
1320 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1321 if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
1322 var n5 Node
1323 Regalloc(&n5, t, nil)
1324 Thearch.Gmove(&nlen, &n5)
1325 Regfree(&nlen)
1326 nlen = n5
1327 }
1328 } else {
1329 Nodconst(&nlen, t, nl.Type.Bound)
1330 if !Smallintconst(&nlen) {
1331 var n5 Node
1332 Regalloc(&n5, t, nil)
1333 Thearch.Gmove(&nlen, &n5)
1334 nlen = n5
1335 freelen = 1
1336 }
1337 }
1338
1339 Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
1340 p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
1341 Ginscall(Panicindex, -1)
1342 Patch(p1, Pc)
1343 }
1344
1345 if Isconst(nl, CTSTR) {
1346 Regalloc(&n3, Types[Tptr], res)
1347 p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ!
1348 Datastring(nl.Val.U.Sval, &p1.From)
1349 p1.From.Type = obj.TYPE_ADDR
1350 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
1351 goto indexdone
1352 }
1353
1354 if w == 0 {
1355 // nothing to do
1356 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
1357 // done by back end
1358 } else if w == 1 {
1359 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1360 } else {
1361 Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
1362 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1363 }
1364
1365 indexdone:
1366 *a = n3
1367 Regfree(&n2)
1368 if freelen != 0 {
1369 Regfree(&nlen)
1370 }
1371
1372 default:
1373 Regalloc(a, Types[Tptr], res)
1374 Agen(n, a)
1375 }
1376}
1377
1378/*
1379 * generate:
1380 * res = &n;
1381 * The generated code checks that the result is not nil.
1382 */
1383func Agen(n *Node, res *Node) {
1384 if Debug['g'] != 0 {
1385 Dump("\nagen-res", res)
1386 Dump("agen-r", n)
1387 }
1388
1389 if n == nil || n.Type == nil {
1390 return
1391 }
1392
1393 for n.Op == OCONVNOP {
1394 n = n.Left
1395 }
1396
1397 if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) {
1398 // Use of a nil interface or nil slice.
1399 // Create a temporary we can take the address of and read.
1400 // The generated code is just going to panic, so it need not
1401 // be terribly efficient. See issue 3670.
1402 var n1 Node
1403 Tempname(&n1, n.Type)
1404
1405 Gvardef(&n1)
1406 Thearch.Clearfat(&n1)
1407 var n2 Node
1408 Regalloc(&n2, Types[Tptr], res)
1409 var n3 Node
1410 n3.Op = OADDR
1411 n3.Left = &n1
1412 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2)
1413 Thearch.Gmove(&n2, res)
1414 Regfree(&n2)
1415 return
1416 }
1417
1418 if n.Addable != 0 {
1419 if n.Op == OREGISTER {
1420 Fatal("agen OREGISTER")
1421 }
1422 var n1 Node
1423 n1.Op = OADDR
1424 n1.Left = n
1425 var n2 Node
1426 Regalloc(&n2, Types[Tptr], res)
1427 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2)
1428 Thearch.Gmove(&n2, res)
1429 Regfree(&n2)
1430 return
1431 }
1432
1433 nl := n.Left
1434
1435 switch n.Op {
1436 default:
1437 Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
1438
1439 case OCALLMETH:
1440 cgen_callmeth(n, 0)
1441 cgen_aret(n, res)
1442
1443 case OCALLINTER:
1444 cgen_callinter(n, res, 0)
1445 cgen_aret(n, res)
1446
1447 case OCALLFUNC:
1448 cgen_call(n, 0)
1449 cgen_aret(n, res)
1450
1451 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
1452 var n1 Node
1453 Tempname(&n1, n.Type)
1454 Cgen_slice(n, &n1)
1455 Agen(&n1, res)
1456
1457 case OEFACE:
1458 var n1 Node
1459 Tempname(&n1, n.Type)
1460 Cgen_eface(n, &n1)
1461 Agen(&n1, res)
1462
1463 case OINDEX:
1464 var n1 Node
1465 Agenr(n, &n1, res)
1466 Thearch.Gmove(&n1, res)
1467 Regfree(&n1)
1468
1469 case ONAME:
1470 // should only get here with names in this func.
1471 if n.Funcdepth > 0 && n.Funcdepth != Funcdepth {
1472 Dump("bad agen", n)
1473 Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth)
1474 }
1475
1476 // should only get here for heap vars or paramref
1477 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
1478 Dump("bad agen", n)
1479 Fatal("agen: bad ONAME class %#x", n.Class)
1480 }
1481
1482 Cgen(n.Heapaddr, res)
1483 if n.Xoffset != 0 {
1484 addOffset(res, n.Xoffset)
1485 }
1486
1487 case OIND:
1488 Cgen(nl, res)
1489 Cgen_checknil(res)
1490
1491 case ODOT:
1492 Agen(nl, res)
1493 if n.Xoffset != 0 {
1494 addOffset(res, n.Xoffset)
1495 }
1496
1497 case ODOTPTR:
1498 Cgen(nl, res)
1499 Cgen_checknil(res)
1500 if n.Xoffset != 0 {
1501 addOffset(res, n.Xoffset)
1502 }
1503 }
1504}
1505
1506func addOffset(res *Node, offset int64) {
1507 if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
1508 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
1509 return
1510 }
1511
1512 var n1, n2 Node
1513 Regalloc(&n1, Types[Tptr], nil)
1514 Thearch.Gmove(res, &n1)
1515 Regalloc(&n2, Types[Tptr], nil)
1516 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2)
1517 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1)
1518 Thearch.Gmove(&n1, res)
1519 Regfree(&n1)
1520 Regfree(&n2)
1521}
1522
1523/*
1524 * generate:
1525 * newreg = &n;
1526 * res = newreg
1527 *
1528 * on exit, a has been changed to be *newreg.
1529 * caller must Regfree(a).
1530 * The generated code checks that the result is not *nil.
1531 */
1532func Igen(n *Node, a *Node, res *Node) {
1533 if Debug['g'] != 0 {
1534 Dump("\nigen-n", n)
1535 }
1536
1537 switch n.Op {
1538 case ONAME:
1539 if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
1540 break
1541 }
1542 *a = *n
1543 return
1544
1545 case OINDREG:
1546 // Increase the refcount of the register so that igen's caller
1547 // has to call Regfree.
1548 if n.Val.U.Reg != int16(Thearch.REGSP) {
1549 reg[n.Val.U.Reg-int16(Thearch.REGMIN)]++
1550 }
1551 *a = *n
1552 return
1553
1554 case ODOT:
1555 Igen(n.Left, a, res)
1556 a.Xoffset += n.Xoffset
1557 a.Type = n.Type
1558 Fixlargeoffset(a)
1559 return
1560
1561 case ODOTPTR:
1562 Cgenr(n.Left, a, res)
1563 Cgen_checknil(a)
1564 a.Op = OINDREG
1565 a.Xoffset += n.Xoffset
1566 a.Type = n.Type
1567 Fixlargeoffset(a)
1568 return
1569
1570 case OCALLFUNC,
1571 OCALLMETH,
1572 OCALLINTER:
1573 switch n.Op {
1574 case OCALLFUNC:
1575 cgen_call(n, 0)
1576
1577 case OCALLMETH:
1578 cgen_callmeth(n, 0)
1579
1580 case OCALLINTER:
1581 cgen_callinter(n, nil, 0)
1582 }
1583
1584 var flist Iter
1585 fp := Structfirst(&flist, Getoutarg(n.Left.Type))
1586 *a = Node{}
1587 a.Op = OINDREG
1588 a.Val.U.Reg = int16(Thearch.REGSP)
1589 a.Addable = 1
1590 a.Xoffset = fp.Width
1591 if HasLinkRegister() {
1592 a.Xoffset += int64(Ctxt.Arch.Ptrsize)
1593 }
1594 a.Type = n.Type
1595 return
1596
1597 // Index of fixed-size array by constant can
1598 // put the offset in the addressing.
1599 // Could do the same for slice except that we need
1600 // to use the real index for the bounds checking.
1601 case OINDEX:
1602 if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) {
1603 if Isconst(n.Right, CTINT) {
1604 // Compute &a.
1605 if !Isptr[n.Left.Type.Etype] {
1606 Igen(n.Left, a, res)
1607 } else {
1608 var n1 Node
1609 Igen(n.Left, &n1, res)
1610 Cgen_checknil(&n1)
1611 Regalloc(a, Types[Tptr], res)
1612 Thearch.Gmove(&n1, a)
1613 Regfree(&n1)
1614 a.Op = OINDREG
1615 }
1616
1617 // Compute &a[i] as &a + i*width.
1618 a.Type = n.Type
1619
1620 a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
1621 Fixlargeoffset(a)
1622 return
1623 }
1624 }
1625 }
1626
1627 Agenr(n, a, res)
1628 a.Op = OINDREG
1629 a.Type = n.Type
1630}
1631
1632/*
1633 * generate:
1634 * if(n == true) goto to;
1635 */
1636func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
1637 if Debug['g'] != 0 {
1638 Dump("\nbgen", n)
1639 }
1640
1641 if n == nil {
1642 n = Nodbool(true)
1643 }
1644
1645 if n.Ninit != nil {
1646 Genlist(n.Ninit)
1647 }
1648
1649 if n.Type == nil {
1650 Convlit(&n, Types[TBOOL])
1651 if n.Type == nil {
1652 return
1653 }
1654 }
1655
1656 et := int(n.Type.Etype)
1657 if et != TBOOL {
1658 Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0))
1659 Patch(Thearch.Gins(obj.AEND, nil, nil), to)
1660 return
1661 }
1662
1663 for n.Op == OCONVNOP {
1664 n = n.Left
1665 if n.Ninit != nil {
1666 Genlist(n.Ninit)
1667 }
1668 }
1669
1670 if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
1671 Thearch.Bgen_float(n, bool2int(true_), likely, to)
1672 return
1673 }
1674
1675 var nl *Node
1676 var nr *Node
1677 switch n.Op {
1678 default:
1679 goto def
1680
1681 // need to ask if it is bool?
1682 case OLITERAL:
1683 if !true_ == (n.Val.U.Bval == 0) {
1684 Patch(Gbranch(obj.AJMP, nil, likely), to)
1685 }
1686 return
1687
1688 case ONAME:
1689 if n.Addable == 0 || Ctxt.Arch.Thechar == '5' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
1690 goto def
1691 }
1692 var n1 Node
1693 Nodconst(&n1, n.Type, 0)
1694 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &n1)
1695 a := Thearch.Optoas(ONE, n.Type)
1696 if !true_ {
1697 a = Thearch.Optoas(OEQ, n.Type)
1698 }
1699 Patch(Gbranch(a, n.Type, likely), to)
1700 return
1701
1702 case OANDAND, OOROR:
1703 if (n.Op == OANDAND) == true_ {
1704 p1 := Gbranch(obj.AJMP, nil, 0)
1705 p2 := Gbranch(obj.AJMP, nil, 0)
1706 Patch(p1, Pc)
1707 Bgen(n.Left, !true_, -likely, p2)
1708 Bgen(n.Right, !true_, -likely, p2)
1709 p1 = Gbranch(obj.AJMP, nil, 0)
1710 Patch(p1, to)
1711 Patch(p2, Pc)
1712 } else {
1713 Bgen(n.Left, true_, likely, to)
1714 Bgen(n.Right, true_, likely, to)
1715 }
1716
1717 return
1718
1719 case OEQ, ONE, OLT, OGT, OLE, OGE:
1720 nr = n.Right
1721 if nr == nil || nr.Type == nil {
1722 return
1723 }
1724 fallthrough
1725
1726 case ONOT: // unary
1727 nl = n.Left
1728
1729 if nl == nil || nl.Type == nil {
1730 return
1731 }
1732 }
1733
1734 switch n.Op {
1735 case ONOT:
1736 Bgen(nl, !true_, likely, to)
1737 return
1738
1739 case OEQ, ONE, OLT, OGT, OLE, OGE:
1740 a := int(n.Op)
1741 if !true_ {
1742 if Isfloat[nr.Type.Etype] {
1743 // brcom is not valid on floats when NaN is involved.
1744 p1 := Gbranch(obj.AJMP, nil, 0)
1745 p2 := Gbranch(obj.AJMP, nil, 0)
1746 Patch(p1, Pc)
1747 ll := n.Ninit // avoid re-genning ninit
1748 n.Ninit = nil
1749 Bgen(n, true, -likely, p2)
1750 n.Ninit = ll
1751 Patch(Gbranch(obj.AJMP, nil, 0), to)
1752 Patch(p2, Pc)
1753 return
1754 }
1755
1756 a = Brcom(a)
1757 true_ = !true_
1758 }
1759
1760 // make simplest on right
1761 if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
1762 a = Brrev(a)
1763 r := nl
1764 nl = nr
1765 nr = r
1766 }
1767
1768 if Isslice(nl.Type) {
1769 // front end should only leave cmp to literal nil
1770 if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
1771 Yyerror("illegal slice comparison")
1772 break
1773 }
1774
1775 a = Thearch.Optoas(a, Types[Tptr])
1776 var n1 Node
1777 Igen(nl, &n1, nil)
1778 n1.Xoffset += int64(Array_array)
1779 n1.Type = Types[Tptr]
1780 var n2 Node
1781 Regalloc(&n2, Types[Tptr], &n1)
1782 Cgen(&n1, &n2)
1783 Regfree(&n1)
1784 var tmp Node
1785 Nodconst(&tmp, Types[Tptr], 0)
1786 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
1787 Patch(Gbranch(a, Types[Tptr], likely), to)
1788 Regfree(&n2)
1789 break
1790 }
1791
1792 if Isinter(nl.Type) {
1793 // front end should only leave cmp to literal nil
1794 if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
1795 Yyerror("illegal interface comparison")
1796 break
1797 }
1798
1799 a = Thearch.Optoas(a, Types[Tptr])
1800 var n1 Node
1801 Igen(nl, &n1, nil)
1802 n1.Type = Types[Tptr]
1803 var n2 Node
1804 Regalloc(&n2, Types[Tptr], &n1)
1805 Cgen(&n1, &n2)
1806 Regfree(&n1)
1807 var tmp Node
1808 Nodconst(&tmp, Types[Tptr], 0)
1809 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
1810 Patch(Gbranch(a, Types[Tptr], likely), to)
1811 Regfree(&n2)
1812 break
1813 }
1814
1815 if Iscomplex[nl.Type.Etype] {
1816 Complexbool(a, nl, nr, true_, likely, to)
1817 break
1818 }
1819
1820 if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
1821 if nl.Addable == 0 || Isconst(nl, CTINT) {
1822 var n1 Node
1823 Tempname(&n1, nl.Type)
1824 Cgen(nl, &n1)
1825 nl = &n1
1826 }
1827
1828 if nr.Addable == 0 {
1829 var n2 Node
1830 Tempname(&n2, nr.Type)
1831 Cgen(nr, &n2)
1832 nr = &n2
1833 }
1834
1835 Thearch.Cmp64(nl, nr, a, likely, to)
1836 break
1837 }
1838
1839 var n1 Node
1840 var n2 Node
1841 if nr.Ullman >= UINF {
1842 Regalloc(&n1, nl.Type, nil)
1843 Cgen(nl, &n1)
1844
1845 var tmp Node
1846 Tempname(&tmp, nl.Type)
1847 Thearch.Gmove(&n1, &tmp)
1848 Regfree(&n1)
1849
1850 Regalloc(&n2, nr.Type, nil)
1851 Cgen(nr, &n2)
1852
1853 Regalloc(&n1, nl.Type, nil)
1854 Cgen(&tmp, &n1)
1855
1856 goto cmp
1857 }
1858
1859 if nl.Addable == 0 && Ctxt.Arch.Thechar == '8' {
1860 Tempname(&n1, nl.Type)
1861 } else {
1862 Regalloc(&n1, nl.Type, nil)
1863 }
1864 Cgen(nl, &n1)
1865 nl = &n1
1866
1867 if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
1868 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
1869 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
1870 if n1.Op == OREGISTER {
1871 Regfree(&n1)
1872 }
1873 break
1874 }
1875
1876 if nr.Addable == 0 && Ctxt.Arch.Thechar == '8' {
1877 var tmp Node
1878 Tempname(&tmp, nr.Type)
1879 Cgen(nr, &tmp)
1880 nr = &tmp
1881 }
1882
1883 Regalloc(&n2, nr.Type, nil)
1884 Cgen(nr, &n2)
1885 nr = &n2
1886
1887 cmp:
1888 l, r := nl, nr
1889 // On x86, only < and <= work right with NaN; reverse if needed
1890 if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
1891 l, r = r, l
1892 a = Brrev(a)
1893 }
1894
1895 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
1896
1897 if Ctxt.Arch.Thechar == '6' && Isfloat[nr.Type.Etype] && (n.Op == OEQ || n.Op == ONE) {
1898 if n.Op == OEQ {
1899 // neither NE nor P
1900 p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
1901 p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
1902 Patch(Gbranch(obj.AJMP, nil, 0), to)
1903 Patch(p1, Pc)
1904 Patch(p2, Pc)
1905 } else {
1906 // either NE or P
1907 Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
1908 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
1909 }
1910 } else if Ctxt.Arch.Thechar == '5' && Isfloat[nl.Type.Etype] {
1911 if n.Op == ONE {
1912 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
1913 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
1914 } else {
1915 p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
1916 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
1917 Patch(p, Pc)
1918 }
1919 } else if (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') && Isfloat[nl.Type.Etype] && (a == OLE || a == OGE) {
1920 // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
1921 if a == OLE {
1922 a = OLT
1923 } else {
1924 a = OGT
1925 }
1926 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
1927 Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
1928 } else {
1929 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
1930 }
1931 if n1.Op == OREGISTER {
1932 Regfree(&n1)
1933 }
1934 if n2.Op == OREGISTER {
1935 Regfree(&n2)
1936 }
1937 }
1938
1939 return
1940
1941def:
1942 // TODO: Optimize on systems that can compare to zero easily.
1943 var n1 Node
1944 Regalloc(&n1, n.Type, nil)
1945 Cgen(n, &n1)
1946 var n2 Node
1947 Nodconst(&n2, n.Type, 0)
1948 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), &n1, &n2)
1949 a := Thearch.Optoas(ONE, n.Type)
1950 if !true_ {
1951 a = Thearch.Optoas(OEQ, n.Type)
1952 }
1953 Patch(Gbranch(a, n.Type, likely), to)
1954 Regfree(&n1)
1955 return
1956}
1957
1958/*
1959 * n is on stack, either local variable
1960 * or return value from function call.
1961 * return n's offset from SP.
1962 */
1963func stkof(n *Node) int64 {
1964 switch n.Op {
1965 case OINDREG:
1966 return n.Xoffset
1967
1968 case ODOT:
1969 t := n.Left.Type
1970 if Isptr[t.Etype] {
1971 break
1972 }
1973 off := stkof(n.Left)
1974 if off == -1000 || off == 1000 {
1975 return off
1976 }
1977 return off + n.Xoffset
1978
1979 case OINDEX:
1980 t := n.Left.Type
1981 if !Isfixedarray(t) {
1982 break
1983 }
1984 off := stkof(n.Left)
1985 if off == -1000 || off == 1000 {
1986 return off
1987 }
1988 if Isconst(n.Right, CTINT) {
1989 return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval)
1990 }
1991 return 1000
1992
1993 case OCALLMETH, OCALLINTER, OCALLFUNC:
1994 t := n.Left.Type
1995 if Isptr[t.Etype] {
1996 t = t.Type
1997 }
1998
1999 var flist Iter
2000 t = Structfirst(&flist, Getoutarg(t))
2001 if t != nil {
2002 w := t.Width
2003 if HasLinkRegister() {
2004 w += int64(Ctxt.Arch.Ptrsize)
2005 }
2006 return w
2007 }
2008 }
2009
2010 // botch - probably failing to recognize address
2011 // arithmetic on the above. eg INDEX and DOT
2012 return -1000
2013}
2014
2015/*
2016 * block copy:
2017 * memmove(&ns, &n, w);
2018 */
2019func sgen(n *Node, ns *Node, w int64) {
2020 if Debug['g'] != 0 {
2021 fmt.Printf("\nsgen w=%d\n", w)
2022 Dump("r", n)
2023 Dump("res", ns)
2024 }
2025
2026 if n.Ullman >= UINF && ns.Ullman >= UINF {
2027 Fatal("sgen UINF")
2028 }
2029
2030 if w < 0 {
2031 Fatal("sgen copy %d", w)
2032 }
2033
2034 // If copying .args, that's all the results, so record definition sites
2035 // for them for the liveness analysis.
2036 if ns.Op == ONAME && ns.Sym.Name == ".args" {
2037 for l := Curfn.Dcl; l != nil; l = l.Next {
2038 if l.N.Class == PPARAMOUT {
2039 Gvardef(l.N)
2040 }
2041 }
2042 }
2043
2044 // Avoid taking the address for simple enough types.
2045 if Componentgen(n, ns) {
2046 return
2047 }
2048
2049 if w == 0 {
2050 // evaluate side effects only
2051 var nodr Node
2052 Regalloc(&nodr, Types[Tptr], nil)
2053 Agen(ns, &nodr)
2054 Agen(n, &nodr)
2055 Regfree(&nodr)
2056 return
2057 }
2058
2059 // offset on the stack
2060 osrc := stkof(n)
2061 odst := stkof(ns)
2062
2063 if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
2064 // osrc and odst both on stack, and at least one is in
2065 // an unknown position. Could generate code to test
2066 // for forward/backward copy, but instead just copy
2067 // to a temporary location first.
2068 var tmp Node
2069 Tempname(&tmp, n.Type)
2070 sgen(n, &tmp, w)
2071 sgen(&tmp, ns, w)
2072 return
2073 }
2074
2075 Thearch.Stackcopy(n, ns, osrc, odst, w)
2076}
2077
2078/*
2079 * generate:
2080 * call f
2081 * proc=-1 normal call but no return
2082 * proc=0 normal call
2083 * proc=1 goroutine run in new proc
2084 * proc=2 defer call save away stack
2085 * proc=3 normal call to C pointer (not Go func value)
2086*/
2087func Ginscall(f *Node, proc int) {
2088 if f.Type != nil {
2089 extra := int32(0)
2090 if proc == 1 || proc == 2 {
2091 extra = 2 * int32(Widthptr)
2092 }
2093 Setmaxarg(f.Type, extra)
2094 }
2095
2096 switch proc {
2097 default:
2098 Fatal("Ginscall: bad proc %d", proc)
2099
2100 case 0, // normal call
2101 -1: // normal call but no return
2102 if f.Op == ONAME && f.Class == PFUNC {
2103 if f == Deferreturn {
2104 // Deferred calls will appear to be returning to
2105 // the CALL deferreturn(SB) that we are about to emit.
2106 // However, the stack trace code will show the line
2107 // of the instruction byte before the return PC.
2108 // To avoid that being an unrelated instruction,
2109 // insert an actual hardware NOP that will have the right line number.
2110 // This is different from obj.ANOP, which is a virtual no-op
2111 // that doesn't make it into the instruction stream.
2112 Thearch.Ginsnop()
2113 }
2114
2115 p := Thearch.Gins(obj.ACALL, nil, f)
2116 Afunclit(&p.To, f)
2117 if proc == -1 || Noreturn(p) {
2118 Thearch.Gins(obj.AUNDEF, nil, nil)
2119 }
2120 break
2121 }
2122
2123 var reg Node
2124 Nodreg(&reg, Types[Tptr], Thearch.REGCTXT)
2125 var r1 Node
2126 Nodreg(&r1, Types[Tptr], Thearch.REGCALLX)
2127 Thearch.Gmove(f, &reg)
2128 reg.Op = OINDREG
2129 Thearch.Gmove(&reg, &r1)
2130 reg.Op = OREGISTER
2131 Thearch.Gins(obj.ACALL, &reg, &r1)
2132
2133 case 3: // normal call of c function pointer
2134 Thearch.Gins(obj.ACALL, nil, f)
2135
2136 case 1, // call in new proc (go)
2137 2: // deferred call (defer)
2138 var stk Node
2139
2140 // size of arguments at 0(SP)
2141 stk.Op = OINDREG
2142 stk.Val.U.Reg = int16(Thearch.REGSP)
2143 stk.Xoffset = 0
2144 if HasLinkRegister() {
2145 stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
2146 }
2147 Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk)
2148
2149 // FuncVal* at 8(SP)
2150 stk.Xoffset = int64(Widthptr)
2151 if HasLinkRegister() {
2152 stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
2153 }
2154
2155 var reg Node
2156 Nodreg(&reg, Types[Tptr], Thearch.REGCALLX2)
2157 Thearch.Gmove(f, &reg)
2158 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &reg, &stk)
2159
2160 if proc == 1 {
2161 Ginscall(Newproc, 0)
2162 } else {
2163 if Hasdefer == 0 {
2164 Fatal("hasdefer=0 but has defer")
2165 }
2166 Ginscall(Deferproc, 0)
2167 }
2168
2169 if proc == 2 {
2170 Nodreg(&reg, Types[TINT32], Thearch.REGRETURN)
2171 Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), &reg, Nodintconst(0))
2172 p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1)
2173 cgen_ret(nil)
2174 Patch(p, Pc)
2175 }
2176 }
2177}
2178
2179/*
2180 * n is call to interface method.
2181 * generate res = n.
2182 */
2183func cgen_callinter(n *Node, res *Node, proc int) {
2184 i := n.Left
2185 if i.Op != ODOTINTER {
2186 Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0))
2187 }
2188
2189 f := i.Right // field
2190 if f.Op != ONAME {
2191 Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0))
2192 }
2193
2194 i = i.Left // interface
2195
2196 if i.Addable == 0 {
2197 var tmpi Node
2198 Tempname(&tmpi, i.Type)
2199 Cgen(i, &tmpi)
2200 i = &tmpi
2201 }
2202
2203 Genlist(n.List) // assign the args
2204
2205 // i is now addable, prepare an indirected
2206 // register to hold its address.
2207 var nodi Node
2208 Igen(i, &nodi, res) // REG = &inter
2209
2210 var nodsp Node
2211 Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP)
2212 nodsp.Xoffset = 0
2213 if HasLinkRegister() {
2214 nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize)
2215 }
2216 if proc != 0 {
2217 nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn
2218 }
2219 nodi.Type = Types[Tptr]
2220 nodi.Xoffset += int64(Widthptr)
2221 Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
2222
2223 var nodo Node
2224 Regalloc(&nodo, Types[Tptr], res)
2225
2226 nodi.Type = Types[Tptr]
2227 nodi.Xoffset -= int64(Widthptr)
2228 Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
2229 Regfree(&nodi)
2230
2231 var nodr Node
2232 Regalloc(&nodr, Types[Tptr], &nodo)
2233 if n.Left.Xoffset == BADWIDTH {
2234 Fatal("cgen_callinter: badwidth")
2235 }
2236 Cgen_checknil(&nodo) // in case offset is huge
2237 nodo.Op = OINDREG
2238 nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8
2239 if proc == 0 {
2240 // plain call: use direct c function pointer - more efficient
2241 Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
2242 proc = 3
2243 } else {
2244 // go/defer. generate go func value.
2245 Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
2246 }
2247
2248 nodr.Type = n.Left.Type
2249 Ginscall(&nodr, proc)
2250
2251 Regfree(&nodr)
2252 Regfree(&nodo)
2253}
2254
2255/*
2256 * generate function call;
2257 * proc=0 normal call
2258 * proc=1 goroutine run in new proc
2259 * proc=2 defer call save away stack
2260 */
2261func cgen_call(n *Node, proc int) {
2262 if n == nil {
2263 return
2264 }
2265
2266 var afun Node
2267 if n.Left.Ullman >= UINF {
2268 // if name involves a fn call
2269 // precompute the address of the fn
2270 Tempname(&afun, Types[Tptr])
2271
2272 Cgen(n.Left, &afun)
2273 }
2274
2275 Genlist(n.List) // assign the args
2276 t := n.Left.Type
2277
2278 // call tempname pointer
2279 if n.Left.Ullman >= UINF {
2280 var nod Node
2281 Regalloc(&nod, Types[Tptr], nil)
2282 Cgen_as(&nod, &afun)
2283 nod.Type = t
2284 Ginscall(&nod, proc)
2285 Regfree(&nod)
2286 return
2287 }
2288
2289 // call pointer
2290 if n.Left.Op != ONAME || n.Left.Class != PFUNC {
2291 var nod Node
2292 Regalloc(&nod, Types[Tptr], nil)
2293 Cgen_as(&nod, n.Left)
2294 nod.Type = t
2295 Ginscall(&nod, proc)
2296 Regfree(&nod)
2297 return
2298 }
2299
2300 // call direct
2301 n.Left.Method = 1
2302
2303 Ginscall(n.Left, proc)
2304}
2305
2306func HasLinkRegister() bool {
2307 c := Ctxt.Arch.Thechar
2308 return c != '6' && c != '8'
2309}
2310
2311/*
2312 * call to n has already been generated.
2313 * generate:
2314 * res = return value from call.
2315 */
2316func cgen_callret(n *Node, res *Node) {
2317 t := n.Left.Type
2318 if t.Etype == TPTR32 || t.Etype == TPTR64 {
2319 t = t.Type
2320 }
2321
2322 var flist Iter
2323 fp := Structfirst(&flist, Getoutarg(t))
2324 if fp == nil {
2325 Fatal("cgen_callret: nil")
2326 }
2327
2328 var nod Node
2329 nod.Op = OINDREG
2330 nod.Val.U.Reg = int16(Thearch.REGSP)
2331 nod.Addable = 1
2332
2333 nod.Xoffset = fp.Width
2334 if HasLinkRegister() {
2335 nod.Xoffset += int64(Ctxt.Arch.Ptrsize)
2336 }
2337 nod.Type = fp.Type
2338 Cgen_as(res, &nod)
2339}
2340
2341/*
2342 * call to n has already been generated.
2343 * generate:
2344 * res = &return value from call.
2345 */
2346func cgen_aret(n *Node, res *Node) {
2347 t := n.Left.Type
2348 if Isptr[t.Etype] {
2349 t = t.Type
2350 }
2351
2352 var flist Iter
2353 fp := Structfirst(&flist, Getoutarg(t))
2354 if fp == nil {
2355 Fatal("cgen_aret: nil")
2356 }
2357
2358 var nod1 Node
2359 nod1.Op = OINDREG
2360 nod1.Val.U.Reg = int16(Thearch.REGSP)
2361 nod1.Addable = 1
2362 nod1.Xoffset = fp.Width
2363 if HasLinkRegister() {
2364 nod1.Xoffset += int64(Ctxt.Arch.Ptrsize)
2365 }
2366 nod1.Type = fp.Type
2367
2368 if res.Op != OREGISTER {
2369 var nod2 Node
2370 Regalloc(&nod2, Types[Tptr], res)
2371 Agen(&nod1, &nod2)
2372 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res)
2373 Regfree(&nod2)
2374 } else {
2375 Agen(&nod1, res)
2376 }
2377}
2378
2379/*
2380 * generate return.
2381 * n->left is assignments to return values.
2382 */
2383func cgen_ret(n *Node) {
2384 if n != nil {
2385 Genlist(n.List) // copy out args
2386 }
2387 if Hasdefer != 0 {
2388 Ginscall(Deferreturn, 0)
2389 }
2390 Genlist(Curfn.Exit)
2391 p := Thearch.Gins(obj.ARET, nil, nil)
2392 if n != nil && n.Op == ORETJMP {
2393 p.To.Type = obj.TYPE_MEM
2394 p.To.Name = obj.NAME_EXTERN
2395 p.To.Sym = Linksym(n.Left.Sym)
2396 }
2397}
2398
2399/*
2400 * generate division according to op, one of:
2401 * res = nl / nr
2402 * res = nl % nr
2403 */
2404func cgen_div(op int, nl *Node, nr *Node, res *Node) {
2405 var w int
2406
2407 // TODO(rsc): arm64 needs to support the relevant instructions
2408 // in peep and optoas in order to enable this.
2409 // TODO(rsc): ppc64 needs to support the relevant instructions
2410 // in peep and optoas in order to enable this.
2411 if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
2412 goto longdiv
2413 }
2414 w = int(nl.Type.Width * 8)
2415
2416 // Front end handled 32-bit division. We only need to handle 64-bit.
2417 // try to do division by multiply by (2^w)/d
2418 // see hacker's delight chapter 10
2419 switch Simtype[nl.Type.Etype] {
2420 default:
2421 goto longdiv
2422
2423 case TUINT64:
2424 var m Magic
2425 m.W = w
2426 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
2427 Umagic(&m)
2428 if m.Bad != 0 {
2429 break
2430 }
2431 if op == OMOD {
2432 goto longmod
2433 }
2434
2435 var n1 Node
2436 Cgenr(nl, &n1, nil)
2437 var n2 Node
2438 Nodconst(&n2, nl.Type, int64(m.Um))
2439 var n3 Node
2440 Regalloc(&n3, nl.Type, res)
2441 Thearch.Cgen_hmul(&n1, &n2, &n3)
2442
2443 if m.Ua != 0 {
2444 // need to add numerator accounting for overflow
2445 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
2446
2447 Nodconst(&n2, nl.Type, 1)
2448 Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
2449 Nodconst(&n2, nl.Type, int64(m.S)-1)
2450 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
2451 } else {
2452 Nodconst(&n2, nl.Type, int64(m.S))
2453 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx
2454 }
2455
2456 Thearch.Gmove(&n3, res)
2457 Regfree(&n1)
2458 Regfree(&n3)
2459 return
2460
2461 case TINT64:
2462 var m Magic
2463 m.W = w
2464 m.Sd = Mpgetfix(nr.Val.U.Xval)
2465 Smagic(&m)
2466 if m.Bad != 0 {
2467 break
2468 }
2469 if op == OMOD {
2470 goto longmod
2471 }
2472
2473 var n1 Node
2474 Cgenr(nl, &n1, res)
2475 var n2 Node
2476 Nodconst(&n2, nl.Type, m.Sm)
2477 var n3 Node
2478 Regalloc(&n3, nl.Type, nil)
2479 Thearch.Cgen_hmul(&n1, &n2, &n3)
2480
2481 if m.Sm < 0 {
2482 // need to add numerator
2483 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
2484 }
2485
2486 Nodconst(&n2, nl.Type, int64(m.S))
2487 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3
2488
2489 Nodconst(&n2, nl.Type, int64(w)-1)
2490
2491 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg
2492 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added
2493
2494 if m.Sd < 0 {
2495 // this could probably be removed
2496 // by factoring it into the multiplier
2497 Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
2498 }
2499
2500 Thearch.Gmove(&n3, res)
2501 Regfree(&n1)
2502 Regfree(&n3)
2503 return
2504 }
2505
2506 goto longdiv
2507
2508 // division and mod using (slow) hardware instruction
2509longdiv:
2510 Thearch.Dodiv(op, nl, nr, res)
2511
2512 return
2513
2514 // mod using formula A%B = A-(A/B*B) but
2515 // we know that there is a fast algorithm for A/B
2516longmod:
2517 var n1 Node
2518 Regalloc(&n1, nl.Type, res)
2519
2520 Cgen(nl, &n1)
2521 var n2 Node
2522 Regalloc(&n2, nl.Type, nil)
2523 cgen_div(ODIV, &n1, nr, &n2)
2524 a := Thearch.Optoas(OMUL, nl.Type)
2525 if w == 8 {
2526 // use 2-operand 16-bit multiply
2527 // because there is no 2-operand 8-bit multiply
2528 a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW
2529 }
2530
2531 if !Smallintconst(nr) {
2532 var n3 Node
2533 Regalloc(&n3, nl.Type, nil)
2534 Cgen(nr, &n3)
2535 Thearch.Gins(a, &n3, &n2)
2536 Regfree(&n3)
2537 } else {
2538 Thearch.Gins(a, nr, &n2)
2539 }
2540 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1)
2541 Thearch.Gmove(&n1, res)
2542 Regfree(&n1)
2543 Regfree(&n2)
2544}
2545
2546func Fixlargeoffset(n *Node) {
2547 if n == nil {
2548 return
2549 }
2550 if n.Op != OINDREG {
2551 return
2552 }
2553 if n.Val.U.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
2554 return
2555 }
2556 if n.Xoffset != int64(int32(n.Xoffset)) {
2557 // offset too large, add to register instead.
2558 a := *n
2559
2560 a.Op = OREGISTER
2561 a.Type = Types[Tptr]
2562 a.Xoffset = 0
2563 Cgen_checknil(&a)
2564 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a)
2565 n.Xoffset = 0
2566 }
2567}