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