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