blob: a4b4f0b61bcf87dd67e8e4750c80175e1799a2c7 [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.
Russ Cox0ad4f8b2015-04-17 00:25:10 -040016 * if wb is true, need to emit write barriers.
Russ Coxb115c352015-03-18 17:26:36 -040017 */
Russ Cox0ad4f8b2015-04-17 00:25:10 -040018func Cgen(n, res *Node) {
19 cgen_wb(n, res, false)
20}
21
22func cgen_wb(n, res *Node, wb bool) {
Russ Coxb115c352015-03-18 17:26:36 -040023 if Debug['g'] != 0 {
Russ Cox0ad4f8b2015-04-17 00:25:10 -040024 op := "cgen"
25 if wb {
26 op = "cgen_wb"
27 }
28 Dump("\n"+op+"-n", n)
29 Dump(op+"-res", res)
Russ Coxb115c352015-03-18 17:26:36 -040030 }
31
32 if n == nil || n.Type == nil {
33 return
34 }
35
36 if res == nil || res.Type == nil {
37 Fatal("cgen: res nil")
38 }
39
40 for n.Op == OCONVNOP {
41 n = n.Left
42 }
43
44 switch n.Op {
45 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
Russ Coxd4472792015-05-06 12:35:53 -040046 cgen_slice(n, res, wb)
Russ Coxb115c352015-03-18 17:26:36 -040047 return
48
49 case OEFACE:
Russ Cox0ad4f8b2015-04-17 00:25:10 -040050 if res.Op != ONAME || !res.Addable || wb {
Russ Coxb115c352015-03-18 17:26:36 -040051 var n1 Node
52 Tempname(&n1, n.Type)
53 Cgen_eface(n, &n1)
Russ Cox0ad4f8b2015-04-17 00:25:10 -040054 cgen_wb(&n1, res, wb)
Russ Coxb115c352015-03-18 17:26:36 -040055 } else {
56 Cgen_eface(n, res)
57 }
58 return
Russ Cox4224d812015-03-20 00:06:10 -040059
60 case ODOTTYPE:
Russ Cox0ad4f8b2015-04-17 00:25:10 -040061 cgen_dottype(n, res, nil, wb)
Russ Cox4224d812015-03-20 00:06:10 -040062 return
Russ Cox85520472015-05-06 12:34:30 -040063
64 case OAPPEND:
65 cgen_append(n, res)
66 return
Russ Coxb115c352015-03-18 17:26:36 -040067 }
68
69 if n.Ullman >= UINF {
70 if n.Op == OINDREG {
71 Fatal("cgen: this is going to miscompile")
72 }
73 if res.Ullman >= UINF {
74 var n1 Node
75 Tempname(&n1, n.Type)
76 Cgen(n, &n1)
Russ Cox0ad4f8b2015-04-17 00:25:10 -040077 cgen_wb(&n1, res, wb)
Russ Coxb115c352015-03-18 17:26:36 -040078 return
79 }
80 }
81
82 if Isfat(n.Type) {
83 if n.Type.Width < 0 {
Russ Cox17228f42015-04-17 12:03:22 -040084 Fatal("forgot to compute width for %v", n.Type)
Russ Coxb115c352015-03-18 17:26:36 -040085 }
Russ Cox0ad4f8b2015-04-17 00:25:10 -040086 sgen_wb(n, res, n.Type.Width, wb)
Russ Coxb115c352015-03-18 17:26:36 -040087 return
88 }
89
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -070090 if !res.Addable {
Russ Coxb115c352015-03-18 17:26:36 -040091 if n.Ullman > res.Ullman {
92 if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
93 var n1 Node
94 Tempname(&n1, n.Type)
95 Cgen(n, &n1)
Russ Cox0ad4f8b2015-04-17 00:25:10 -040096 cgen_wb(&n1, res, wb)
Russ Coxb115c352015-03-18 17:26:36 -040097 return
98 }
99
100 var n1 Node
101 Regalloc(&n1, n.Type, res)
102 Cgen(n, &n1)
103 if n1.Ullman > res.Ullman {
104 Dump("n1", &n1)
105 Dump("res", res)
106 Fatal("loop in cgen")
107 }
108
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400109 cgen_wb(&n1, res, wb)
Russ Coxb115c352015-03-18 17:26:36 -0400110 Regfree(&n1)
111 return
112 }
113
114 var f int
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400115 if res.Ullman < UINF {
116 if Complexop(n, res) {
117 Complexgen(n, res)
118 return
119 }
Russ Coxb115c352015-03-18 17:26:36 -0400120
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400121 f = 1 // gen thru register
122 switch n.Op {
123 case OLITERAL:
124 if Smallintconst(n) {
125 f = 0
126 }
Russ Coxb115c352015-03-18 17:26:36 -0400127
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400128 case OREGISTER:
Russ Coxb115c352015-03-18 17:26:36 -0400129 f = 0
130 }
131
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400132 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 && !wb {
133 a := Thearch.Optoas(OAS, res.Type)
134 var addr obj.Addr
135 if Thearch.Sudoaddable(a, res, &addr) {
136 var p1 *obj.Prog
137 if f != 0 {
138 var n2 Node
139 Regalloc(&n2, res.Type, nil)
140 Cgen(n, &n2)
141 p1 = Thearch.Gins(a, &n2, nil)
142 Regfree(&n2)
143 } else {
144 p1 = Thearch.Gins(a, n, nil)
145 }
146 p1.To = addr
147 if Debug['g'] != 0 {
148 fmt.Printf("%v [ignore previous line]\n", p1)
149 }
150 Thearch.Sudoclean()
151 return
Russ Coxb115c352015-03-18 17:26:36 -0400152 }
Russ Coxb115c352015-03-18 17:26:36 -0400153 }
154 }
155
Russ Coxb115c352015-03-18 17:26:36 -0400156 if Ctxt.Arch.Thechar == '8' {
157 // no registers to speak of
158 var n1, n2 Node
159 Tempname(&n1, n.Type)
160 Cgen(n, &n1)
161 Igen(res, &n2, nil)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400162 cgen_wb(&n1, &n2, wb)
Russ Coxb115c352015-03-18 17:26:36 -0400163 Regfree(&n2)
164 return
165 }
166
167 var n1 Node
168 Igen(res, &n1, nil)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400169 cgen_wb(n, &n1, wb)
Russ Coxb115c352015-03-18 17:26:36 -0400170 Regfree(&n1)
171 return
172 }
173
174 // update addressability for string, slice
175 // can't do in walk because n->left->addable
176 // changes if n->left is an escaping local variable.
177 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700178 case OSPTR, OLEN:
Russ Coxb115c352015-03-18 17:26:36 -0400179 if Isslice(n.Left.Type) || Istype(n.Left.Type, TSTRING) {
180 n.Addable = n.Left.Addable
181 }
182
183 case OCAP:
184 if Isslice(n.Left.Type) {
185 n.Addable = n.Left.Addable
186 }
187
188 case OITAB:
189 n.Addable = n.Left.Addable
190 }
191
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400192 if wb {
193 if int(Simtype[res.Type.Etype]) != Tptr {
194 Fatal("cgen_wb of type %v", res.Type)
195 }
196 if n.Ullman >= UINF {
197 var n1 Node
198 Tempname(&n1, n.Type)
199 Cgen(n, &n1)
200 n = &n1
201 }
202 cgen_wbptr(n, res)
203 return
204 }
205
206 // Write barrier now handled. Code below this line can ignore wb.
207
Russ Coxb115c352015-03-18 17:26:36 -0400208 if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
209 // if both are addressable, move
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700210 if n.Addable && res.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400211 if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] {
212 Thearch.Gmove(n, res)
213 } else {
214 var n1 Node
215 Regalloc(&n1, n.Type, nil)
216 Thearch.Gmove(n, &n1)
217 Cgen(&n1, res)
218 Regfree(&n1)
219 }
220
221 return
222 }
223
224 // if both are not addressable, use a temporary.
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700225 if !n.Addable && !res.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400226 // could use regalloc here sometimes,
227 // but have to check for ullman >= UINF.
228 var n1 Node
229 Tempname(&n1, n.Type)
230 Cgen(n, &n1)
231 Cgen(&n1, res)
232 return
233 }
234
235 // if result is not addressable directly but n is,
236 // compute its address and then store via the address.
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700237 if !res.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400238 var n1 Node
239 Igen(res, &n1, nil)
240 Cgen(n, &n1)
241 Regfree(&n1)
242 return
243 }
244 }
245
246 if Complexop(n, res) {
247 Complexgen(n, res)
248 return
249 }
250
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700251 if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400252 Thearch.Gmove(n, res)
253 return
254 }
255
256 if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
257 // if both are addressable, move
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700258 if n.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400259 if n.Op == OREGISTER || res.Op == OREGISTER {
260 Thearch.Gmove(n, res)
261 } else {
262 var n1 Node
263 Regalloc(&n1, n.Type, nil)
264 Thearch.Gmove(n, &n1)
265 Cgen(&n1, res)
266 Regfree(&n1)
267 }
268 return
269 }
270 }
271
272 // if n is sudoaddable generate addr and move
273 if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !Iscomplex[n.Type.Etype] && !Iscomplex[res.Type.Etype] {
274 a := Thearch.Optoas(OAS, n.Type)
275 var addr obj.Addr
276 if Thearch.Sudoaddable(a, n, &addr) {
277 if res.Op != OREGISTER {
278 var n2 Node
279 Regalloc(&n2, res.Type, nil)
280 p1 := Thearch.Gins(a, nil, &n2)
281 p1.From = addr
282 if Debug['g'] != 0 {
283 fmt.Printf("%v [ignore previous line]\n", p1)
284 }
285 Thearch.Gmove(&n2, res)
286 Regfree(&n2)
287 } else {
288 p1 := Thearch.Gins(a, nil, res)
289 p1.From = addr
290 if Debug['g'] != 0 {
291 fmt.Printf("%v [ignore previous line]\n", p1)
292 }
293 }
294 Thearch.Sudoclean()
295 return
296 }
297 }
298
299 nl := n.Left
300 nr := n.Right
301
302 if nl != nil && nl.Ullman >= UINF {
303 if nr != nil && nr.Ullman >= UINF {
304 var n1 Node
305 Tempname(&n1, nl.Type)
306 Cgen(nl, &n1)
307 n2 := *n
308 n2.Left = &n1
309 Cgen(&n2, res)
310 return
311 }
312 }
313
314 // 64-bit ops are hard on 32-bit machine.
315 if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
316 switch n.Op {
317 // math goes to cgen64.
318 case OMINUS,
319 OCOM,
320 OADD,
321 OSUB,
322 OMUL,
323 OLROT,
324 OLSH,
325 ORSH,
326 OAND,
327 OOR,
328 OXOR:
329 Thearch.Cgen64(n, res)
330 return
331 }
332 }
333
334 if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] {
335 Thearch.Cgen_float(n, res)
336 return
337 }
338
339 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
340 a := Thearch.Optoas(OAS, n.Type)
341 var addr obj.Addr
342 if Thearch.Sudoaddable(a, n, &addr) {
343 if res.Op == OREGISTER {
344 p1 := Thearch.Gins(a, nil, res)
345 p1.From = addr
346 } else {
347 var n2 Node
348 Regalloc(&n2, n.Type, nil)
349 p1 := Thearch.Gins(a, nil, &n2)
350 p1.From = addr
351 Thearch.Gins(a, &n2, res)
352 Regfree(&n2)
353 }
354
355 Thearch.Sudoclean()
356 return
357 }
358 }
359
360 var a int
361 switch n.Op {
362 default:
363 Dump("cgen", n)
364 Dump("cgen-res", res)
365 Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
366
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700367 case OOROR, OANDAND,
368 OEQ, ONE,
369 OLT, OLE,
370 OGE, OGT,
Russ Coxb115c352015-03-18 17:26:36 -0400371 ONOT:
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -0700372 Bvgen(n, res, true)
Russ Coxb115c352015-03-18 17:26:36 -0400373 return
374
375 case OPLUS:
376 Cgen(nl, res)
377 return
378
379 // unary
380 case OCOM:
381 a := Thearch.Optoas(OXOR, nl.Type)
382
383 var n1 Node
384 Regalloc(&n1, nl.Type, nil)
385 Cgen(nl, &n1)
386 var n2 Node
387 Nodconst(&n2, nl.Type, -1)
388 Thearch.Gins(a, &n2, &n1)
389 cgen_norm(n, &n1, res)
390 return
391
392 case OMINUS:
393 if Isfloat[nl.Type.Etype] {
394 nr = Nodintconst(-1)
395 Convlit(&nr, n.Type)
396 a = Thearch.Optoas(OMUL, nl.Type)
397 goto sbop
398 }
399
400 a := Thearch.Optoas(int(n.Op), nl.Type)
401 // unary
402 var n1 Node
403 Regalloc(&n1, nl.Type, res)
404
405 Cgen(nl, &n1)
406 if Ctxt.Arch.Thechar == '5' {
407 var n2 Node
408 Nodconst(&n2, nl.Type, 0)
409 Thearch.Gins(a, &n2, &n1)
410 } else if Ctxt.Arch.Thechar == '7' {
411 Thearch.Gins(a, &n1, &n1)
412 } else {
413 Thearch.Gins(a, nil, &n1)
414 }
415 cgen_norm(n, &n1, res)
416 return
417
Russ Cox92dba0d2015-04-01 16:02:34 -0400418 case OSQRT:
419 var n1 Node
420 Regalloc(&n1, nl.Type, res)
421 Cgen(n.Left, &n1)
422 Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1)
423 Thearch.Gmove(&n1, res)
424 Regfree(&n1)
425 return
426
Russ Cox92c826b2015-04-03 12:23:28 -0400427 case OGETG:
428 Thearch.Getg(res)
429 return
430
Russ Coxb115c352015-03-18 17:26:36 -0400431 // symmetric binary
432 case OAND,
433 OOR,
434 OXOR,
435 OADD,
436 OMUL:
437 if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(int(n.Op), nl, nr, res) {
438 break
439 }
440 a = Thearch.Optoas(int(n.Op), nl.Type)
441 goto sbop
442
443 // asymmetric binary
444 case OSUB:
445 a = Thearch.Optoas(int(n.Op), nl.Type)
446 goto abop
447
448 case OHMUL:
449 Thearch.Cgen_hmul(nl, nr, res)
450
451 case OCONV:
452 if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) {
453 Cgen(nl, res)
454 return
455 }
456
457 if Ctxt.Arch.Thechar == '8' {
458 var n1 Node
459 var n2 Node
460 Tempname(&n2, n.Type)
461 Mgen(nl, &n1, res)
462 Thearch.Gmove(&n1, &n2)
463 Thearch.Gmove(&n2, res)
464 Mfree(&n1)
465 break
466 }
467
468 var n1 Node
469 var n2 Node
470 if Ctxt.Arch.Thechar == '5' {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700471 if nl.Addable && !Is64(nl.Type) {
Russ Coxb115c352015-03-18 17:26:36 -0400472 Regalloc(&n1, nl.Type, res)
473 Thearch.Gmove(nl, &n1)
474 } else {
475 if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] {
476 Tempname(&n1, nl.Type)
477 } else {
478 Regalloc(&n1, nl.Type, res)
479 }
480 Cgen(nl, &n1)
481 }
482 if n.Type.Width > int64(Widthptr) || Is64(n.Type) || Isfloat[n.Type.Etype] {
483 Tempname(&n2, n.Type)
484 } else {
485 Regalloc(&n2, n.Type, nil)
486 }
487 } else {
488 if n.Type.Width > nl.Type.Width {
489 // If loading from memory, do conversion during load,
490 // so as to avoid use of 8-bit register in, say, int(*byteptr).
491 switch nl.Op {
492 case ODOT, ODOTPTR, OINDEX, OIND, ONAME:
493 Igen(nl, &n1, res)
494 Regalloc(&n2, n.Type, res)
495 Thearch.Gmove(&n1, &n2)
496 Thearch.Gmove(&n2, res)
497 Regfree(&n2)
498 Regfree(&n1)
499 return
500 }
501 }
502 Regalloc(&n1, nl.Type, res)
503 Regalloc(&n2, n.Type, &n1)
504 Cgen(nl, &n1)
505 }
506
507 // if we do the conversion n1 -> n2 here
508 // reusing the register, then gmove won't
509 // have to allocate its own register.
510 Thearch.Gmove(&n1, &n2)
511 Thearch.Gmove(&n2, res)
512 if n2.Op == OREGISTER {
513 Regfree(&n2)
514 }
515 if n1.Op == OREGISTER {
516 Regfree(&n1)
517 }
518
519 case ODOT,
520 ODOTPTR,
521 OINDEX,
522 OIND,
523 ONAME: // PHEAP or PPARAMREF var
524 var n1 Node
525 Igen(n, &n1, res)
526
527 Thearch.Gmove(&n1, res)
528 Regfree(&n1)
529
530 // interface table is first word of interface value
531 case OITAB:
532 var n1 Node
533 Igen(nl, &n1, res)
534
535 n1.Type = n.Type
536 Thearch.Gmove(&n1, res)
537 Regfree(&n1)
538
539 case OSPTR:
540 // pointer is the first word of string or slice.
541 if Isconst(nl, CTSTR) {
542 var n1 Node
543 Regalloc(&n1, Types[Tptr], res)
544 p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1)
545 Datastring(nl.Val.U.Sval, &p1.From)
546 p1.From.Type = obj.TYPE_ADDR
547 Thearch.Gmove(&n1, res)
548 Regfree(&n1)
549 break
550 }
551
552 var n1 Node
553 Igen(nl, &n1, res)
554 n1.Type = n.Type
555 Thearch.Gmove(&n1, res)
556 Regfree(&n1)
557
558 case OLEN:
559 if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) {
560 // map and chan have len in the first int-sized word.
561 // a zero pointer means zero length
562 var n1 Node
563 Regalloc(&n1, Types[Tptr], res)
564
565 Cgen(nl, &n1)
566
567 var n2 Node
568 Nodconst(&n2, Types[Tptr], 0)
Russ Coxf8d14fc2015-05-06 12:28:19 -0400569 p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0)
Russ Coxb115c352015-03-18 17:26:36 -0400570
571 n2 = n1
572 n2.Op = OINDREG
573 n2.Type = Types[Simtype[TINT]]
574 Thearch.Gmove(&n2, &n1)
575
576 Patch(p1, Pc)
577
578 Thearch.Gmove(&n1, res)
579 Regfree(&n1)
580 break
581 }
582
583 if Istype(nl.Type, TSTRING) || Isslice(nl.Type) {
584 // both slice and string have len one pointer into the struct.
585 // a zero pointer means zero length
586 var n1 Node
587 Igen(nl, &n1, res)
588
589 n1.Type = Types[Simtype[TUINT]]
590 n1.Xoffset += int64(Array_nel)
591 Thearch.Gmove(&n1, res)
592 Regfree(&n1)
593 break
594 }
595
596 Fatal("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong))
597
598 case OCAP:
599 if Istype(nl.Type, TCHAN) {
600 // chan has cap in the second int-sized word.
601 // a zero pointer means zero length
602 var n1 Node
603 Regalloc(&n1, Types[Tptr], res)
604
605 Cgen(nl, &n1)
606
607 var n2 Node
608 Nodconst(&n2, Types[Tptr], 0)
Russ Coxf8d14fc2015-05-06 12:28:19 -0400609 p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0)
Russ Coxb115c352015-03-18 17:26:36 -0400610
611 n2 = n1
612 n2.Op = OINDREG
613 n2.Xoffset = int64(Widthint)
614 n2.Type = Types[Simtype[TINT]]
615 Thearch.Gmove(&n2, &n1)
616
617 Patch(p1, Pc)
618
619 Thearch.Gmove(&n1, res)
620 Regfree(&n1)
621 break
622 }
623
624 if Isslice(nl.Type) {
625 var n1 Node
626 Igen(nl, &n1, res)
627 n1.Type = Types[Simtype[TUINT]]
628 n1.Xoffset += int64(Array_cap)
629 Thearch.Gmove(&n1, res)
630 Regfree(&n1)
631 break
632 }
633
634 Fatal("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong))
635
636 case OADDR:
637 if n.Bounded { // let race detector avoid nil checks
638 Disable_checknil++
639 }
640 Agen(nl, res)
641 if n.Bounded {
642 Disable_checknil--
643 }
644
645 case OCALLMETH:
646 cgen_callmeth(n, 0)
647 cgen_callret(n, res)
648
649 case OCALLINTER:
650 cgen_callinter(n, res, 0)
651 cgen_callret(n, res)
652
653 case OCALLFUNC:
654 cgen_call(n, 0)
655 cgen_callret(n, res)
656
657 case OMOD, ODIV:
658 if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil {
659 a = Thearch.Optoas(int(n.Op), nl.Type)
660 goto abop
661 }
662
663 if nl.Ullman >= nr.Ullman {
664 var n1 Node
665 Regalloc(&n1, nl.Type, res)
666 Cgen(nl, &n1)
667 cgen_div(int(n.Op), &n1, nr, res)
668 Regfree(&n1)
669 } else {
670 var n2 Node
671 if !Smallintconst(nr) {
672 Regalloc(&n2, nr.Type, res)
673 Cgen(nr, &n2)
674 } else {
675 n2 = *nr
676 }
677
678 cgen_div(int(n.Op), nl, &n2, res)
679 if n2.Op != OLITERAL {
680 Regfree(&n2)
681 }
682 }
683
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700684 case OLSH, ORSH, OLROT:
Russ Coxb115c352015-03-18 17:26:36 -0400685 Thearch.Cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
686 }
687
688 return
689
690 /*
691 * put simplest on right - we'll generate into left
692 * and then adjust it using the computation of right.
693 * constants and variables have the same ullman
694 * count, so look for constants specially.
695 *
696 * an integer constant we can use as an immediate
697 * is simpler than a variable - we can use the immediate
698 * in the adjustment instruction directly - so it goes
699 * on the right.
700 *
701 * other constants, like big integers or floating point
702 * constants, require a mov into a register, so those
703 * might as well go on the left, so we can reuse that
704 * register for the computation.
705 */
706sbop: // symmetric binary
707 if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) {
708 r := nl
709 nl = nr
710 nr = r
711 }
712
713abop: // asymmetric binary
714 var n1 Node
715 var n2 Node
716 if Ctxt.Arch.Thechar == '8' {
717 // no registers, sigh
718 if Smallintconst(nr) {
719 var n1 Node
720 Mgen(nl, &n1, res)
721 var n2 Node
722 Regalloc(&n2, nl.Type, &n1)
723 Thearch.Gmove(&n1, &n2)
724 Thearch.Gins(a, nr, &n2)
725 Thearch.Gmove(&n2, res)
726 Regfree(&n2)
727 Mfree(&n1)
728 } else if nl.Ullman >= nr.Ullman {
729 var nt Node
730 Tempname(&nt, nl.Type)
731 Cgen(nl, &nt)
732 var n2 Node
733 Mgen(nr, &n2, nil)
734 var n1 Node
735 Regalloc(&n1, nl.Type, res)
736 Thearch.Gmove(&nt, &n1)
737 Thearch.Gins(a, &n2, &n1)
738 Thearch.Gmove(&n1, res)
739 Regfree(&n1)
740 Mfree(&n2)
741 } else {
742 var n2 Node
743 Regalloc(&n2, nr.Type, res)
744 Cgen(nr, &n2)
745 var n1 Node
746 Regalloc(&n1, nl.Type, nil)
747 Cgen(nl, &n1)
748 Thearch.Gins(a, &n2, &n1)
749 Regfree(&n2)
750 Thearch.Gmove(&n1, res)
751 Regfree(&n1)
752 }
753 return
754 }
755
756 if nl.Ullman >= nr.Ullman {
757 Regalloc(&n1, nl.Type, res)
758 Cgen(nl, &n1)
759
760 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
761 n2 = *nr
762 } else {
763 Regalloc(&n2, nr.Type, nil)
764 Cgen(nr, &n2)
765 }
766 } else {
767 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
768 n2 = *nr
769 } else {
770 Regalloc(&n2, nr.Type, res)
771 Cgen(nr, &n2)
772 }
773
774 Regalloc(&n1, nl.Type, nil)
775 Cgen(nl, &n1)
776 }
777
778 Thearch.Gins(a, &n2, &n1)
779 if n2.Op != OLITERAL {
780 Regfree(&n2)
781 }
782 cgen_norm(n, &n1, res)
783}
784
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400785var sys_wbptr *Node
786
787func cgen_wbptr(n, res *Node) {
788 if Debug_wb > 0 {
789 Warn("write barrier")
790 }
Russ Cox653d5602015-04-24 14:13:06 -0400791
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400792 var dst, src Node
Russ Cox653d5602015-04-24 14:13:06 -0400793 Igen(res, &dst, nil)
794 if n.Op == OREGISTER {
795 src = *n
796 Regrealloc(&src)
797 } else {
798 Cgenr(n, &src, nil)
799 }
800
Shenghou Ma2b7505e2015-04-28 19:44:00 -0400801 wbEnabled := syslook("writeBarrierEnabled", 0)
Russ Coxf8d14fc2015-05-06 12:28:19 -0400802 pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
Russ Cox653d5602015-04-24 14:13:06 -0400803 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
804 pjmp := Gbranch(obj.AJMP, nil, 0)
805 Patch(pbr, Pc)
806 var adst Node
807 Agenr(&dst, &adst, &dst)
808 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &adst, nil)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400809 a := &p.To
810 a.Type = obj.TYPE_MEM
811 a.Reg = int16(Thearch.REGSP)
812 a.Offset = 0
813 if HasLinkRegister() {
814 a.Offset += int64(Widthptr)
815 }
816 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
817 p2.To = p.To
818 p2.To.Offset += int64(Widthptr)
Russ Cox653d5602015-04-24 14:13:06 -0400819 Regfree(&adst)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400820 if sys_wbptr == nil {
821 sys_wbptr = writebarrierfn("writebarrierptr", Types[Tptr], Types[Tptr])
822 }
823 Ginscall(sys_wbptr, 0)
Russ Cox653d5602015-04-24 14:13:06 -0400824 Patch(pjmp, Pc)
825
826 Regfree(&dst)
827 Regfree(&src)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400828}
829
830func cgen_wbfat(n, res *Node) {
831 if Debug_wb > 0 {
832 Warn("write barrier")
833 }
834 needType := true
835 funcName := "typedmemmove"
836 var dst, src Node
837 if n.Ullman >= res.Ullman {
838 Agenr(n, &src, nil)
839 Agenr(res, &dst, nil)
840 } else {
841 Agenr(res, &dst, nil)
842 Agenr(n, &src, nil)
843 }
844 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil)
845 a := &p.To
846 a.Type = obj.TYPE_MEM
847 a.Reg = int16(Thearch.REGSP)
848 a.Offset = 0
849 if HasLinkRegister() {
850 a.Offset += int64(Widthptr)
851 }
852 if needType {
853 a.Offset += int64(Widthptr)
854 }
855 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
856 p2.To = p.To
857 p2.To.Offset += int64(Widthptr)
858 Regfree(&dst)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400859 if needType {
Russ Cox2a735592015-04-17 11:07:38 -0400860 src.Type = Types[Tptr]
861 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), &src)
862 p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400863 p3.To = p2.To
864 p3.To.Offset -= 2 * int64(Widthptr)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400865 }
Russ Cox2a735592015-04-17 11:07:38 -0400866 Regfree(&src)
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400867 Ginscall(writebarrierfn(funcName, Types[Tptr], Types[Tptr]), 0)
868}
869
Russ Coxb115c352015-03-18 17:26:36 -0400870// cgen_norm moves n1 to res, truncating to expected type if necessary.
871// n1 is a register, and cgen_norm frees it.
872func cgen_norm(n, n1, res *Node) {
873 switch Ctxt.Arch.Thechar {
874 case '6', '8':
875 // We use sized math, so the result is already truncated.
876 default:
877 switch n.Op {
878 case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS:
879 // TODO(rsc): What about left shift?
880 Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1)
881 }
882 }
883
884 Thearch.Gmove(n1, res)
885 Regfree(n1)
886}
887
888func Mgen(n *Node, n1 *Node, rg *Node) {
889 n1.Op = OEMPTY
890
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700891 if n.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400892 *n1 = *n
893 if n1.Op == OREGISTER || n1.Op == OINDREG {
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700894 reg[n.Reg-int16(Thearch.REGMIN)]++
Russ Coxb115c352015-03-18 17:26:36 -0400895 }
896 return
897 }
898
899 Tempname(n1, n.Type)
900 Cgen(n, n1)
901 if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] {
902 n2 := *n1
903 Regalloc(n1, n.Type, rg)
904 Thearch.Gmove(&n2, n1)
905 }
906}
907
908func Mfree(n *Node) {
909 if n.Op == OREGISTER {
910 Regfree(n)
911 }
912}
913
914/*
915 * allocate a register (reusing res if possible) and generate
916 * a = n
917 * The caller must call Regfree(a).
918 */
919func Cgenr(n *Node, a *Node, res *Node) {
920 if Debug['g'] != 0 {
921 Dump("cgenr-n", n)
922 }
923
924 if Isfat(n.Type) {
925 Fatal("cgenr on fat node")
926 }
927
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700928 if n.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400929 Regalloc(a, n.Type, res)
930 Thearch.Gmove(n, a)
931 return
932 }
933
934 switch n.Op {
935 case ONAME,
936 ODOT,
937 ODOTPTR,
938 OINDEX,
939 OCALLFUNC,
940 OCALLMETH,
941 OCALLINTER:
942 var n1 Node
943 Igen(n, &n1, res)
944 Regalloc(a, Types[Tptr], &n1)
945 Thearch.Gmove(&n1, a)
946 Regfree(&n1)
947
948 default:
949 Regalloc(a, n.Type, res)
950 Cgen(n, a)
951 }
952}
953
954/*
955 * allocate a register (reusing res if possible) and generate
956 * a = &n
957 * The caller must call Regfree(a).
958 * The generated code checks that the result is not nil.
959 */
960func Agenr(n *Node, a *Node, res *Node) {
961 if Debug['g'] != 0 {
962 Dump("\nagenr-n", n)
963 }
964
965 nl := n.Left
966 nr := n.Right
967
968 switch n.Op {
969 case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER:
970 var n1 Node
971 Igen(n, &n1, res)
972 Regalloc(a, Types[Tptr], &n1)
973 Agen(&n1, a)
974 Regfree(&n1)
975
976 case OIND:
977 Cgenr(n.Left, a, res)
978 Cgen_checknil(a)
979
980 case OINDEX:
981 if Ctxt.Arch.Thechar == '5' {
982 var p2 *obj.Prog // to be patched to panicindex.
983 w := uint32(n.Type.Width)
984 bounded := Debug['B'] != 0 || n.Bounded
985 var n1 Node
986 var n3 Node
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700987 if nr.Addable {
Russ Coxb115c352015-03-18 17:26:36 -0400988 var tmp Node
989 if !Isconst(nr, CTINT) {
990 Tempname(&tmp, Types[TINT32])
991 }
992 if !Isconst(nl, CTSTR) {
993 Agenr(nl, &n3, res)
994 }
995 if !Isconst(nr, CTINT) {
996 p2 = Thearch.Cgenindex(nr, &tmp, bounded)
997 Regalloc(&n1, tmp.Type, nil)
998 Thearch.Gmove(&tmp, &n1)
999 }
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001000 } else if nl.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04001001 if !Isconst(nr, CTINT) {
1002 var tmp Node
1003 Tempname(&tmp, Types[TINT32])
1004 p2 = Thearch.Cgenindex(nr, &tmp, bounded)
1005 Regalloc(&n1, tmp.Type, nil)
1006 Thearch.Gmove(&tmp, &n1)
1007 }
1008
1009 if !Isconst(nl, CTSTR) {
1010 Agenr(nl, &n3, res)
1011 }
1012 } else {
1013 var tmp Node
1014 Tempname(&tmp, Types[TINT32])
1015 p2 = Thearch.Cgenindex(nr, &tmp, bounded)
1016 nr = &tmp
1017 if !Isconst(nl, CTSTR) {
1018 Agenr(nl, &n3, res)
1019 }
1020 Regalloc(&n1, tmp.Type, nil)
1021 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
1022 }
1023
1024 // &a is in &n3 (allocated in res)
1025 // i is in &n1 (if not constant)
1026 // w is width
1027
1028 // constant index
1029 if Isconst(nr, CTINT) {
1030 if Isconst(nl, CTSTR) {
1031 Fatal("constant string constant index")
1032 }
1033 v := uint64(Mpgetfix(nr.Val.U.Xval))
1034 var n2 Node
1035 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1036 if Debug['B'] == 0 && !n.Bounded {
1037 n1 = n3
1038 n1.Op = OINDREG
1039 n1.Type = Types[Tptr]
1040 n1.Xoffset = int64(Array_nel)
Russ Cox5ed4bb62015-05-12 15:51:22 -04001041 Nodconst(&n2, Types[TUINT32], int64(v))
Russ Coxf8d14fc2015-05-06 12:28:19 -04001042 p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &n1, &n2, +1)
Russ Coxfc595b72015-05-06 12:30:59 -04001043 Ginscall(Panicindex, -1)
Russ Coxb115c352015-03-18 17:26:36 -04001044 Patch(p1, Pc)
1045 }
1046
1047 n1 = n3
1048 n1.Op = OINDREG
1049 n1.Type = Types[Tptr]
1050 n1.Xoffset = int64(Array_array)
1051 Thearch.Gmove(&n1, &n3)
1052 }
1053
1054 Nodconst(&n2, Types[Tptr], int64(v*uint64(w)))
1055 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1056 *a = n3
1057 break
1058 }
1059
1060 var n2 Node
1061 Regalloc(&n2, Types[TINT32], &n1) // i
1062 Thearch.Gmove(&n1, &n2)
1063 Regfree(&n1)
1064
1065 var n4 Node
1066 if Debug['B'] == 0 && !n.Bounded {
1067 // check bounds
1068 if Isconst(nl, CTSTR) {
1069 Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval)))
1070 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1071 n1 = n3
1072 n1.Op = OINDREG
1073 n1.Type = Types[Tptr]
1074 n1.Xoffset = int64(Array_nel)
1075 Regalloc(&n4, Types[TUINT32], nil)
1076 Thearch.Gmove(&n1, &n4)
1077 } else {
1078 Nodconst(&n4, Types[TUINT32], nl.Type.Bound)
1079 }
Russ Coxf8d14fc2015-05-06 12:28:19 -04001080 p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1)
Russ Coxb115c352015-03-18 17:26:36 -04001081 if n4.Op == OREGISTER {
1082 Regfree(&n4)
1083 }
Russ Coxb115c352015-03-18 17:26:36 -04001084 if p2 != nil {
1085 Patch(p2, Pc)
1086 }
Russ Coxfc595b72015-05-06 12:30:59 -04001087 Ginscall(Panicindex, -1)
Russ Coxb115c352015-03-18 17:26:36 -04001088 Patch(p1, Pc)
1089 }
1090
1091 if Isconst(nl, CTSTR) {
1092 Regalloc(&n3, Types[Tptr], res)
1093 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
1094 Datastring(nl.Val.U.Sval, &p1.From)
1095 p1.From.Type = obj.TYPE_ADDR
1096 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1097 n1 = n3
1098 n1.Op = OINDREG
1099 n1.Type = Types[Tptr]
1100 n1.Xoffset = int64(Array_array)
1101 Thearch.Gmove(&n1, &n3)
1102 }
1103
1104 if w == 0 {
1105 // nothing to do
1106 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
1107 // done by back end
1108 } else if w == 1 {
1109 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1110 } else {
Keith Randall135389d2015-04-30 10:41:57 -07001111 if w&(w-1) == 0 {
1112 // Power of 2. Use shift.
1113 Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
1114 } else {
1115 // Not a power of 2. Use multiply.
1116 Regalloc(&n4, Types[TUINT32], nil)
1117 Nodconst(&n1, Types[TUINT32], int64(w))
1118 Thearch.Gmove(&n1, &n4)
1119 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
1120 Regfree(&n4)
1121 }
Russ Coxb115c352015-03-18 17:26:36 -04001122 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
Russ Coxb115c352015-03-18 17:26:36 -04001123 }
1124 *a = n3
1125 Regfree(&n2)
1126 break
1127 }
1128 if Ctxt.Arch.Thechar == '8' {
1129 var p2 *obj.Prog // to be patched to panicindex.
1130 w := uint32(n.Type.Width)
1131 bounded := Debug['B'] != 0 || n.Bounded
1132 var n3 Node
1133 var tmp Node
1134 var n1 Node
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001135 if nr.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04001136 // Generate &nl first, and move nr into register.
1137 if !Isconst(nl, CTSTR) {
1138 Igen(nl, &n3, res)
1139 }
1140 if !Isconst(nr, CTINT) {
1141 p2 = Thearch.Igenindex(nr, &tmp, bounded)
1142 Regalloc(&n1, tmp.Type, nil)
1143 Thearch.Gmove(&tmp, &n1)
1144 }
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001145 } else if nl.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04001146 // Generate nr first, and move &nl into register.
1147 if !Isconst(nr, CTINT) {
1148 p2 = Thearch.Igenindex(nr, &tmp, bounded)
1149 Regalloc(&n1, tmp.Type, nil)
1150 Thearch.Gmove(&tmp, &n1)
1151 }
1152
1153 if !Isconst(nl, CTSTR) {
1154 Igen(nl, &n3, res)
1155 }
1156 } else {
1157 p2 = Thearch.Igenindex(nr, &tmp, bounded)
1158 nr = &tmp
1159 if !Isconst(nl, CTSTR) {
1160 Igen(nl, &n3, res)
1161 }
1162 Regalloc(&n1, tmp.Type, nil)
1163 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
1164 }
1165
1166 // For fixed array we really want the pointer in n3.
1167 var n2 Node
1168 if Isfixedarray(nl.Type) {
1169 Regalloc(&n2, Types[Tptr], &n3)
1170 Agen(&n3, &n2)
1171 Regfree(&n3)
1172 n3 = n2
1173 }
1174
1175 // &a[0] is in n3 (allocated in res)
1176 // i is in n1 (if not constant)
1177 // len(a) is in nlen (if needed)
1178 // w is width
1179
1180 // constant index
1181 if Isconst(nr, CTINT) {
1182 if Isconst(nl, CTSTR) {
1183 Fatal("constant string constant index") // front end should handle
1184 }
1185 v := uint64(Mpgetfix(nr.Val.U.Xval))
1186 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1187 if Debug['B'] == 0 && !n.Bounded {
1188 nlen := n3
1189 nlen.Type = Types[TUINT32]
1190 nlen.Xoffset += int64(Array_nel)
1191 Nodconst(&n2, Types[TUINT32], int64(v))
Russ Coxf8d14fc2015-05-06 12:28:19 -04001192 p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &nlen, &n2, +1)
Russ Coxb115c352015-03-18 17:26:36 -04001193 Ginscall(Panicindex, -1)
1194 Patch(p1, Pc)
1195 }
1196 }
1197
1198 // Load base pointer in n2 = n3.
1199 Regalloc(&n2, Types[Tptr], &n3)
1200
1201 n3.Type = Types[Tptr]
1202 n3.Xoffset += int64(Array_array)
1203 Thearch.Gmove(&n3, &n2)
1204 Regfree(&n3)
1205 if v*uint64(w) != 0 {
1206 Nodconst(&n1, Types[Tptr], int64(v*uint64(w)))
1207 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2)
1208 }
1209 *a = n2
1210 break
1211 }
1212
1213 // i is in register n1, extend to 32 bits.
1214 t := Types[TUINT32]
1215
1216 if Issigned[n1.Type.Etype] {
1217 t = Types[TINT32]
1218 }
1219
1220 Regalloc(&n2, t, &n1) // i
1221 Thearch.Gmove(&n1, &n2)
1222 Regfree(&n1)
1223
1224 if Debug['B'] == 0 && !n.Bounded {
1225 // check bounds
1226 t := Types[TUINT32]
1227
1228 var nlen Node
1229 if Isconst(nl, CTSTR) {
1230 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
1231 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1232 nlen = n3
1233 nlen.Type = t
1234 nlen.Xoffset += int64(Array_nel)
1235 } else {
1236 Nodconst(&nlen, t, nl.Type.Bound)
1237 }
1238
Russ Coxf8d14fc2015-05-06 12:28:19 -04001239 p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
Russ Coxb115c352015-03-18 17:26:36 -04001240 if p2 != nil {
1241 Patch(p2, Pc)
1242 }
1243 Ginscall(Panicindex, -1)
1244 Patch(p1, Pc)
1245 }
1246
1247 if Isconst(nl, CTSTR) {
1248 Regalloc(&n3, Types[Tptr], res)
1249 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
1250 Datastring(nl.Val.U.Sval, &p1.From)
1251 p1.From.Type = obj.TYPE_ADDR
1252 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
1253 goto indexdone1
1254 }
1255
1256 // Load base pointer in n3.
1257 Regalloc(&tmp, Types[Tptr], &n3)
1258
1259 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1260 n3.Type = Types[Tptr]
1261 n3.Xoffset += int64(Array_array)
1262 Thearch.Gmove(&n3, &tmp)
1263 }
1264
1265 Regfree(&n3)
1266 n3 = tmp
1267
1268 if w == 0 {
1269 // nothing to do
1270 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
1271 // done by back end
1272 } else if w == 1 {
1273 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1274 } else {
Keith Randall135389d2015-04-30 10:41:57 -07001275 if w&(w-1) == 0 {
1276 // Power of 2. Use shift.
1277 Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
1278 } else {
1279 // Not a power of 2. Use multiply.
1280 Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT32]), int64(w), &n2)
1281 }
Russ Coxb115c352015-03-18 17:26:36 -04001282 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1283 }
1284
1285 indexdone1:
1286 *a = n3
1287 Regfree(&n2)
1288 break
1289 }
1290
1291 freelen := 0
1292 w := uint64(n.Type.Width)
1293
1294 // Generate the non-addressable child first.
1295 var n3 Node
1296 var nlen Node
1297 var tmp Node
1298 var n1 Node
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001299 if nr.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04001300 goto irad
1301 }
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001302 if nl.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04001303 Cgenr(nr, &n1, nil)
1304 if !Isconst(nl, CTSTR) {
1305 if Isfixedarray(nl.Type) {
1306 Agenr(nl, &n3, res)
1307 } else {
1308 Igen(nl, &nlen, res)
1309 freelen = 1
1310 nlen.Type = Types[Tptr]
1311 nlen.Xoffset += int64(Array_array)
1312 Regalloc(&n3, Types[Tptr], res)
1313 Thearch.Gmove(&nlen, &n3)
1314 nlen.Type = Types[Simtype[TUINT]]
1315 nlen.Xoffset += int64(Array_nel) - int64(Array_array)
1316 }
1317 }
1318
1319 goto index
1320 }
1321
1322 Tempname(&tmp, nr.Type)
1323 Cgen(nr, &tmp)
1324 nr = &tmp
1325
1326 irad:
1327 if !Isconst(nl, CTSTR) {
1328 if Isfixedarray(nl.Type) {
1329 Agenr(nl, &n3, res)
1330 } else {
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001331 if !nl.Addable {
Russ Cox4224d812015-03-20 00:06:10 -04001332 if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet.
1333 Regfree(res)
1334 }
1335
Russ Coxb115c352015-03-18 17:26:36 -04001336 // igen will need an addressable node.
1337 var tmp2 Node
1338 Tempname(&tmp2, nl.Type)
Russ Coxb115c352015-03-18 17:26:36 -04001339 Cgen(nl, &tmp2)
1340 nl = &tmp2
Russ Cox4224d812015-03-20 00:06:10 -04001341
1342 if res != nil && res.Op == OREGISTER { // reacquire res
1343 Regrealloc(res)
1344 }
Russ Coxb115c352015-03-18 17:26:36 -04001345 }
1346
1347 Igen(nl, &nlen, res)
1348 freelen = 1
1349 nlen.Type = Types[Tptr]
1350 nlen.Xoffset += int64(Array_array)
1351 Regalloc(&n3, Types[Tptr], res)
1352 Thearch.Gmove(&nlen, &n3)
1353 nlen.Type = Types[Simtype[TUINT]]
1354 nlen.Xoffset += int64(Array_nel) - int64(Array_array)
1355 }
1356 }
1357
1358 if !Isconst(nr, CTINT) {
1359 Cgenr(nr, &n1, nil)
1360 }
1361
1362 goto index
1363
1364 // &a is in &n3 (allocated in res)
1365 // i is in &n1 (if not constant)
1366 // len(a) is in nlen (if needed)
1367 // w is width
1368
1369 // constant index
1370 index:
1371 if Isconst(nr, CTINT) {
1372 if Isconst(nl, CTSTR) {
1373 Fatal("constant string constant index") // front end should handle
1374 }
1375 v := uint64(Mpgetfix(nr.Val.U.Xval))
1376 if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
1377 if Debug['B'] == 0 && !n.Bounded {
Russ Coxf8d14fc2015-05-06 12:28:19 -04001378 p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1)
Russ Coxb115c352015-03-18 17:26:36 -04001379 Ginscall(Panicindex, -1)
1380 Patch(p1, Pc)
1381 }
1382
1383 Regfree(&nlen)
1384 }
1385
1386 if v*w != 0 {
1387 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3)
1388 }
1389 *a = n3
1390 break
1391 }
1392
1393 // type of the index
1394 t := Types[TUINT64]
1395
1396 if Issigned[n1.Type.Etype] {
1397 t = Types[TINT64]
1398 }
1399
1400 var n2 Node
1401 Regalloc(&n2, t, &n1) // i
1402 Thearch.Gmove(&n1, &n2)
1403 Regfree(&n1)
1404
1405 if Debug['B'] == 0 && !n.Bounded {
1406 // check bounds
1407 t = Types[Simtype[TUINT]]
1408
1409 if Is64(nr.Type) {
1410 t = Types[TUINT64]
1411 }
1412 if Isconst(nl, CTSTR) {
1413 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
1414 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
Russ Coxf8d14fc2015-05-06 12:28:19 -04001415 // nlen already initialized
Russ Coxb115c352015-03-18 17:26:36 -04001416 } else {
1417 Nodconst(&nlen, t, nl.Type.Bound)
Russ Coxb115c352015-03-18 17:26:36 -04001418 }
1419
Russ Coxf8d14fc2015-05-06 12:28:19 -04001420 p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
Russ Coxb115c352015-03-18 17:26:36 -04001421 Ginscall(Panicindex, -1)
1422 Patch(p1, Pc)
1423 }
1424
1425 if Isconst(nl, CTSTR) {
1426 Regalloc(&n3, Types[Tptr], res)
1427 p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ!
1428 Datastring(nl.Val.U.Sval, &p1.From)
1429 p1.From.Type = obj.TYPE_ADDR
1430 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
1431 goto indexdone
1432 }
1433
1434 if w == 0 {
1435 // nothing to do
1436 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
1437 // done by back end
1438 } else if w == 1 {
1439 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1440 } else {
Keith Randall135389d2015-04-30 10:41:57 -07001441 if w&(w-1) == 0 {
1442 // Power of 2. Use shift.
1443 Thearch.Ginscon(Thearch.Optoas(OLSH, t), int64(log2(w)), &n2)
1444 } else {
1445 // Not a power of 2. Use multiply.
1446 Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
1447 }
Russ Coxb115c352015-03-18 17:26:36 -04001448 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
1449 }
1450
1451 indexdone:
1452 *a = n3
1453 Regfree(&n2)
1454 if freelen != 0 {
1455 Regfree(&nlen)
1456 }
1457
1458 default:
1459 Regalloc(a, Types[Tptr], res)
1460 Agen(n, a)
1461 }
1462}
1463
Keith Randall135389d2015-04-30 10:41:57 -07001464// log2 returns the logarithm base 2 of n. n must be a power of 2.
1465func log2(n uint64) int {
1466 x := 0
1467 for n>>uint(x) != 1 {
1468 x++
1469 }
1470 return x
1471}
1472
Russ Coxb115c352015-03-18 17:26:36 -04001473/*
1474 * generate:
1475 * res = &n;
1476 * The generated code checks that the result is not nil.
1477 */
1478func Agen(n *Node, res *Node) {
1479 if Debug['g'] != 0 {
1480 Dump("\nagen-res", res)
1481 Dump("agen-r", n)
1482 }
1483
1484 if n == nil || n.Type == nil {
1485 return
1486 }
1487
1488 for n.Op == OCONVNOP {
1489 n = n.Left
1490 }
1491
1492 if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) {
1493 // Use of a nil interface or nil slice.
1494 // Create a temporary we can take the address of and read.
1495 // The generated code is just going to panic, so it need not
1496 // be terribly efficient. See issue 3670.
1497 var n1 Node
1498 Tempname(&n1, n.Type)
1499
1500 Gvardef(&n1)
1501 Thearch.Clearfat(&n1)
1502 var n2 Node
1503 Regalloc(&n2, Types[Tptr], res)
1504 var n3 Node
1505 n3.Op = OADDR
1506 n3.Left = &n1
1507 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2)
1508 Thearch.Gmove(&n2, res)
1509 Regfree(&n2)
1510 return
1511 }
1512
Russ Cox0f0bc0f2015-04-24 10:50:18 -04001513 if n.Op == OINDREG && n.Xoffset == 0 {
1514 // Generate MOVW R0, R1 instead of MOVW $0(R0), R1.
1515 // This allows better move propagation in the back ends
1516 // (and maybe it helps the processor).
1517 n1 := *n
1518 n1.Op = OREGISTER
1519 n1.Type = res.Type
1520 Thearch.Gmove(&n1, res)
1521 return
1522 }
1523
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001524 if n.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04001525 if n.Op == OREGISTER {
1526 Fatal("agen OREGISTER")
1527 }
1528 var n1 Node
1529 n1.Op = OADDR
1530 n1.Left = n
1531 var n2 Node
1532 Regalloc(&n2, Types[Tptr], res)
1533 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2)
1534 Thearch.Gmove(&n2, res)
1535 Regfree(&n2)
1536 return
1537 }
1538
1539 nl := n.Left
1540
1541 switch n.Op {
1542 default:
1543 Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
1544
1545 case OCALLMETH:
1546 cgen_callmeth(n, 0)
1547 cgen_aret(n, res)
1548
1549 case OCALLINTER:
1550 cgen_callinter(n, res, 0)
1551 cgen_aret(n, res)
1552
1553 case OCALLFUNC:
1554 cgen_call(n, 0)
1555 cgen_aret(n, res)
1556
Russ Cox4224d812015-03-20 00:06:10 -04001557 case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
Russ Coxb115c352015-03-18 17:26:36 -04001558 var n1 Node
1559 Tempname(&n1, n.Type)
Russ Cox4224d812015-03-20 00:06:10 -04001560 Cgen(n, &n1)
Russ Coxb115c352015-03-18 17:26:36 -04001561 Agen(&n1, res)
1562
1563 case OINDEX:
1564 var n1 Node
1565 Agenr(n, &n1, res)
1566 Thearch.Gmove(&n1, res)
1567 Regfree(&n1)
1568
1569 case ONAME:
1570 // should only get here with names in this func.
1571 if n.Funcdepth > 0 && n.Funcdepth != Funcdepth {
1572 Dump("bad agen", n)
1573 Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth)
1574 }
1575
1576 // should only get here for heap vars or paramref
1577 if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
1578 Dump("bad agen", n)
1579 Fatal("agen: bad ONAME class %#x", n.Class)
1580 }
1581
1582 Cgen(n.Heapaddr, res)
1583 if n.Xoffset != 0 {
1584 addOffset(res, n.Xoffset)
1585 }
1586
1587 case OIND:
1588 Cgen(nl, res)
1589 Cgen_checknil(res)
1590
1591 case ODOT:
1592 Agen(nl, res)
1593 if n.Xoffset != 0 {
1594 addOffset(res, n.Xoffset)
1595 }
1596
1597 case ODOTPTR:
1598 Cgen(nl, res)
1599 Cgen_checknil(res)
1600 if n.Xoffset != 0 {
1601 addOffset(res, n.Xoffset)
1602 }
1603 }
1604}
1605
1606func addOffset(res *Node, offset int64) {
1607 if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
1608 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
1609 return
1610 }
1611
1612 var n1, n2 Node
1613 Regalloc(&n1, Types[Tptr], nil)
1614 Thearch.Gmove(res, &n1)
1615 Regalloc(&n2, Types[Tptr], nil)
1616 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2)
1617 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1)
1618 Thearch.Gmove(&n1, res)
1619 Regfree(&n1)
1620 Regfree(&n2)
1621}
1622
Russ Cox4224d812015-03-20 00:06:10 -04001623// Igen computes the address &n, stores it in a register r,
1624// and rewrites a to refer to *r. The chosen r may be the
1625// stack pointer, it may be borrowed from res, or it may
1626// be a newly allocated register. The caller must call Regfree(a)
1627// to free r when the address is no longer needed.
1628// The generated code ensures that &n is not nil.
Russ Coxb115c352015-03-18 17:26:36 -04001629func Igen(n *Node, a *Node, res *Node) {
1630 if Debug['g'] != 0 {
1631 Dump("\nigen-n", n)
1632 }
1633
1634 switch n.Op {
1635 case ONAME:
1636 if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
1637 break
1638 }
1639 *a = *n
1640 return
1641
1642 case OINDREG:
1643 // Increase the refcount of the register so that igen's caller
1644 // has to call Regfree.
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -07001645 if n.Reg != int16(Thearch.REGSP) {
1646 reg[n.Reg-int16(Thearch.REGMIN)]++
Russ Coxb115c352015-03-18 17:26:36 -04001647 }
1648 *a = *n
1649 return
1650
1651 case ODOT:
1652 Igen(n.Left, a, res)
1653 a.Xoffset += n.Xoffset
1654 a.Type = n.Type
1655 Fixlargeoffset(a)
1656 return
1657
1658 case ODOTPTR:
1659 Cgenr(n.Left, a, res)
1660 Cgen_checknil(a)
1661 a.Op = OINDREG
1662 a.Xoffset += n.Xoffset
1663 a.Type = n.Type
1664 Fixlargeoffset(a)
1665 return
1666
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001667 case OCALLFUNC, OCALLMETH, OCALLINTER:
Russ Coxb115c352015-03-18 17:26:36 -04001668 switch n.Op {
1669 case OCALLFUNC:
1670 cgen_call(n, 0)
1671
1672 case OCALLMETH:
1673 cgen_callmeth(n, 0)
1674
1675 case OCALLINTER:
1676 cgen_callinter(n, nil, 0)
1677 }
1678
1679 var flist Iter
1680 fp := Structfirst(&flist, Getoutarg(n.Left.Type))
1681 *a = Node{}
1682 a.Op = OINDREG
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -07001683 a.Reg = int16(Thearch.REGSP)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07001684 a.Addable = true
Russ Coxb115c352015-03-18 17:26:36 -04001685 a.Xoffset = fp.Width
1686 if HasLinkRegister() {
1687 a.Xoffset += int64(Ctxt.Arch.Ptrsize)
1688 }
1689 a.Type = n.Type
1690 return
1691
1692 // Index of fixed-size array by constant can
1693 // put the offset in the addressing.
1694 // Could do the same for slice except that we need
1695 // to use the real index for the bounds checking.
1696 case OINDEX:
1697 if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) {
1698 if Isconst(n.Right, CTINT) {
1699 // Compute &a.
1700 if !Isptr[n.Left.Type.Etype] {
1701 Igen(n.Left, a, res)
1702 } else {
1703 var n1 Node
1704 Igen(n.Left, &n1, res)
1705 Cgen_checknil(&n1)
1706 Regalloc(a, Types[Tptr], res)
1707 Thearch.Gmove(&n1, a)
1708 Regfree(&n1)
1709 a.Op = OINDREG
1710 }
1711
1712 // Compute &a[i] as &a + i*width.
1713 a.Type = n.Type
1714
1715 a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
1716 Fixlargeoffset(a)
1717 return
1718 }
1719 }
1720 }
1721
1722 Agenr(n, a, res)
1723 a.Op = OINDREG
1724 a.Type = n.Type
1725}
1726
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001727// Bgen generates code for branches:
1728//
1729// if n == wantTrue {
1730// goto to
1731// }
1732func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) {
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001733 bgenx(n, nil, wantTrue, likely, to)
1734}
1735
1736// Bvgen generates code for calculating boolean values:
1737// res = n == wantTrue
1738func Bvgen(n, res *Node, wantTrue bool) {
1739 if Thearch.Ginsboolval == nil {
1740 // Direct value generation not implemented for this architecture.
1741 // Implement using jumps.
1742 bvgenjump(n, res, wantTrue, true)
1743 return
Russ Coxb115c352015-03-18 17:26:36 -04001744 }
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001745 bgenx(n, res, wantTrue, 0, nil)
1746}
1747
1748// bvgenjump implements boolean value generation using jumps:
1749// if n == wantTrue {
1750// res = 1
1751// } else {
1752// res = 0
1753// }
1754// geninit controls whether n's Ninit is generated.
1755func bvgenjump(n, res *Node, wantTrue, geninit bool) {
1756 init := n.Ninit
1757 if !geninit {
1758 n.Ninit = nil
1759 }
1760 p1 := Gbranch(obj.AJMP, nil, 0)
1761 p2 := Pc
1762 Thearch.Gmove(Nodbool(true), res)
1763 p3 := Gbranch(obj.AJMP, nil, 0)
1764 Patch(p1, Pc)
1765 Bgen(n, wantTrue, 0, p2)
1766 Thearch.Gmove(Nodbool(false), res)
1767 Patch(p3, Pc)
1768 n.Ninit = init
1769}
1770
1771// bgenx is the backend for Bgen and Bvgen.
1772// If res is nil, it generates a branch.
1773// Otherwise, it generates a boolean value.
1774func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
1775 if Debug['g'] != 0 {
1776 fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to)
1777 Dump("n", n)
1778 Dump("res", res)
1779 }
1780
1781 genval := res != nil
Russ Coxb115c352015-03-18 17:26:36 -04001782
1783 if n == nil {
1784 n = Nodbool(true)
1785 }
1786
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001787 Genlist(n.Ninit)
Russ Coxb115c352015-03-18 17:26:36 -04001788
1789 if n.Type == nil {
1790 Convlit(&n, Types[TBOOL])
1791 if n.Type == nil {
1792 return
1793 }
1794 }
1795
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001796 if n.Type.Etype != TBOOL {
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001797 Fatal("bgen: bad type %v for %v", n.Type, Oconv(int(n.Op), 0))
Russ Coxb115c352015-03-18 17:26:36 -04001798 }
1799
1800 for n.Op == OCONVNOP {
1801 n = n.Left
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001802 Genlist(n.Ninit)
Russ Coxb115c352015-03-18 17:26:36 -04001803 }
1804
1805 if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001806 if genval {
1807 bvgenjump(n, res, wantTrue, false)
1808 return
1809 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001810 Thearch.Bgen_float(n, wantTrue, likely, to)
Russ Coxb115c352015-03-18 17:26:36 -04001811 return
1812 }
1813
Russ Coxb115c352015-03-18 17:26:36 -04001814 switch n.Op {
1815 default:
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001816 if genval {
1817 Cgen(n, res)
1818 if !wantTrue {
1819 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
1820 }
1821 return
1822 }
1823
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001824 var tmp Node
1825 Regalloc(&tmp, n.Type, nil)
1826 Cgen(n, &tmp)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001827 bgenNonZero(&tmp, nil, wantTrue, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001828 Regfree(&tmp)
1829 return
Russ Coxb115c352015-03-18 17:26:36 -04001830
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001831 case ONAME:
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001832 if genval {
1833 // 5g, 7g, and 9g might need a temporary or other help here,
1834 // but they don't support direct generation of a bool value yet.
1835 // We can fix that as we go.
1836 switch Ctxt.Arch.Thechar {
1837 case '5', '7', '9':
1838 Fatal("genval 5g, 7g, 9g ONAMES not fully implemented")
1839 }
1840 Cgen(n, res)
1841 if !wantTrue {
1842 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
1843 }
1844 return
1845 }
1846
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001847 if n.Addable && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
1848 // no need for a temporary
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001849 bgenNonZero(n, nil, wantTrue, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001850 return
1851 }
1852 var tmp Node
1853 Regalloc(&tmp, n.Type, nil)
1854 Cgen(n, &tmp)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001855 bgenNonZero(&tmp, nil, wantTrue, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001856 Regfree(&tmp)
1857 return
1858
Russ Coxb115c352015-03-18 17:26:36 -04001859 case OLITERAL:
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001860 // n is a constant.
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001861 if !Isconst(n, CTBOOL) {
1862 Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong))
1863 }
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001864 if genval {
1865 Cgen(Nodbool(wantTrue == n.Val.U.Bval), res)
1866 return
1867 }
1868 // If n == wantTrue, jump; otherwise do nothing.
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001869 if wantTrue == n.Val.U.Bval {
Russ Coxb115c352015-03-18 17:26:36 -04001870 Patch(Gbranch(obj.AJMP, nil, likely), to)
1871 }
1872 return
1873
Russ Coxb115c352015-03-18 17:26:36 -04001874 case OANDAND, OOROR:
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001875 and := (n.Op == OANDAND) == wantTrue
1876 if genval {
1877 p1 := Gbranch(obj.AJMP, nil, 0)
1878 p2 := Gbranch(obj.AJMP, nil, 0)
1879 Patch(p2, Pc)
1880 Cgen(Nodbool(!and), res)
1881 p3 := Gbranch(obj.AJMP, nil, 0)
1882 Patch(p1, Pc)
1883 Bgen(n.Left, wantTrue != and, 0, p2)
1884 Bvgen(n.Right, res, wantTrue)
1885 Patch(p3, Pc)
1886 return
1887 }
1888
1889 if and {
Russ Coxb115c352015-03-18 17:26:36 -04001890 p1 := Gbranch(obj.AJMP, nil, 0)
1891 p2 := Gbranch(obj.AJMP, nil, 0)
1892 Patch(p1, Pc)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001893 Bgen(n.Left, !wantTrue, -likely, p2)
1894 Bgen(n.Right, !wantTrue, -likely, p2)
Russ Coxb115c352015-03-18 17:26:36 -04001895 p1 = Gbranch(obj.AJMP, nil, 0)
1896 Patch(p1, to)
1897 Patch(p2, Pc)
1898 } else {
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001899 Bgen(n.Left, wantTrue, likely, to)
1900 Bgen(n.Right, wantTrue, likely, to)
Russ Coxb115c352015-03-18 17:26:36 -04001901 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001902 return
Russ Coxb115c352015-03-18 17:26:36 -04001903
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001904 case ONOT: // unary
1905 if n.Left == nil || n.Left.Type == nil {
1906 return
1907 }
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001908 bgenx(n.Left, res, !wantTrue, likely, to)
Russ Coxb115c352015-03-18 17:26:36 -04001909 return
1910
1911 case OEQ, ONE, OLT, OGT, OLE, OGE:
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001912 if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil {
Russ Coxb115c352015-03-18 17:26:36 -04001913 return
1914 }
1915 }
1916
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001917 // n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE
1918 nl := n.Left
1919 nr := n.Right
1920 a := int(n.Op)
Russ Coxb115c352015-03-18 17:26:36 -04001921
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001922 if !wantTrue {
1923 if Isfloat[nr.Type.Etype] {
1924 // Brcom is not valid on floats when NaN is involved.
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001925 ll := n.Ninit // avoid re-genning Ninit
1926 n.Ninit = nil
1927 if genval {
1928 bgenx(n, res, true, likely, to)
1929 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res
1930 n.Ninit = ll
1931 return
1932 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001933 p1 := Gbranch(obj.AJMP, nil, 0)
1934 p2 := Gbranch(obj.AJMP, nil, 0)
1935 Patch(p1, Pc)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001936 bgenx(n, res, true, -likely, p2)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001937 Patch(Gbranch(obj.AJMP, nil, 0), to)
1938 Patch(p2, Pc)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001939 n.Ninit = ll
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001940 return
Russ Coxb115c352015-03-18 17:26:36 -04001941 }
1942
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001943 a = Brcom(a)
1944 }
1945 wantTrue = true
Russ Coxb115c352015-03-18 17:26:36 -04001946
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001947 // make simplest on right
1948 if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
1949 a = Brrev(a)
1950 nl, nr = nr, nl
1951 }
1952
1953 if Isslice(nl.Type) || Isinter(nl.Type) {
1954 // front end should only leave cmp to literal nil
1955 if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
1956 if Isslice(nl.Type) {
Russ Coxb115c352015-03-18 17:26:36 -04001957 Yyerror("illegal slice comparison")
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001958 } else {
Russ Coxb115c352015-03-18 17:26:36 -04001959 Yyerror("illegal interface comparison")
Russ Coxb115c352015-03-18 17:26:36 -04001960 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001961 return
Russ Coxb115c352015-03-18 17:26:36 -04001962 }
1963
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001964 var ptr Node
1965 Igen(nl, &ptr, nil)
1966 if Isslice(nl.Type) {
1967 ptr.Xoffset += int64(Array_array)
Russ Coxb115c352015-03-18 17:26:36 -04001968 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001969 ptr.Type = Types[Tptr]
1970 var tmp Node
1971 Regalloc(&tmp, ptr.Type, &ptr)
1972 Cgen(&ptr, &tmp)
1973 Regfree(&ptr)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001974 bgenNonZero(&tmp, res, a == OEQ != wantTrue, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001975 Regfree(&tmp)
1976 return
1977 }
Russ Coxb115c352015-03-18 17:26:36 -04001978
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001979 if Iscomplex[nl.Type.Etype] {
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001980 complexbool(a, nl, nr, res, wantTrue, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001981 return
1982 }
Russ Coxb115c352015-03-18 17:26:36 -04001983
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001984 if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07001985 if genval {
1986 // TODO: Teach Cmp64 to generate boolean values and remove this.
1987 bvgenjump(n, res, wantTrue, false)
1988 return
1989 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001990 if !nl.Addable || Isconst(nl, CTINT) {
1991 nl = CgenTemp(nl)
Russ Coxb115c352015-03-18 17:26:36 -04001992 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07001993 if !nr.Addable {
1994 nr = CgenTemp(nr)
1995 }
1996 Thearch.Cmp64(nl, nr, a, likely, to)
1997 return
1998 }
Russ Coxb115c352015-03-18 17:26:36 -04001999
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002000 if nr.Ullman >= UINF {
Russ Coxb115c352015-03-18 17:26:36 -04002001 var n1 Node
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002002 Regalloc(&n1, nl.Type, nil)
2003 Cgen(nl, &n1)
2004
2005 var tmp Node
2006 Tempname(&tmp, nl.Type)
2007 Thearch.Gmove(&n1, &tmp)
2008 Regfree(&n1)
2009
Russ Coxb115c352015-03-18 17:26:36 -04002010 var n2 Node
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002011 Regalloc(&n2, nr.Type, nil)
2012 Cgen(nr, &n2)
2013 Regfree(&n2)
Russ Coxb115c352015-03-18 17:26:36 -04002014
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002015 Regalloc(&n1, nl.Type, nil)
2016 Cgen(&tmp, &n1)
2017 Regfree(&n1)
2018 } else {
2019 var n1 Node
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07002020 if !nl.Addable && Ctxt.Arch.Thechar == '8' {
Russ Coxb115c352015-03-18 17:26:36 -04002021 Tempname(&n1, nl.Type)
2022 } else {
2023 Regalloc(&n1, nl.Type, nil)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002024 defer Regfree(&n1)
Russ Coxb115c352015-03-18 17:26:36 -04002025 }
2026 Cgen(nl, &n1)
2027 nl = &n1
2028
2029 if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
2030 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002031 bins(nr.Type, res, a, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002032 return
Russ Coxb115c352015-03-18 17:26:36 -04002033 }
2034
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07002035 if !nr.Addable && Ctxt.Arch.Thechar == '8' {
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002036 nr = CgenTemp(nr)
Russ Coxb115c352015-03-18 17:26:36 -04002037 }
2038
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002039 var n2 Node
Russ Coxb115c352015-03-18 17:26:36 -04002040 Regalloc(&n2, nr.Type, nil)
2041 Cgen(nr, &n2)
2042 nr = &n2
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002043 Regfree(&n2)
2044 }
Russ Coxb115c352015-03-18 17:26:36 -04002045
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002046 l, r := nl, nr
Russ Coxb115c352015-03-18 17:26:36 -04002047
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002048 // On x86, only < and <= work right with NaN; reverse if needed
2049 if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
2050 l, r = r, l
2051 a = Brrev(a)
2052 }
Russ Coxb115c352015-03-18 17:26:36 -04002053
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002054 // Do the comparison.
2055 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
2056
2057 // Handle floating point special cases.
2058 // Note that 8g has Bgen_float and is handled above.
2059 if Isfloat[nl.Type.Etype] {
2060 switch Ctxt.Arch.Thechar {
2061 case '5':
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002062 if genval {
2063 Fatal("genval 5g Isfloat special cases not implemented")
2064 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002065 switch n.Op {
2066 case ONE:
2067 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
2068 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
2069 default:
2070 p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
2071 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
2072 Patch(p, Pc)
2073 }
2074 return
2075 case '6':
2076 switch n.Op {
2077 case OEQ:
Russ Coxb115c352015-03-18 17:26:36 -04002078 // neither NE nor P
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002079 if genval {
2080 var reg Node
2081 Regalloc(&reg, Types[TBOOL], nil)
2082 Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), &reg)
2083 Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res)
2084 Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), &reg, res)
2085 Regfree(&reg)
2086 } else {
2087 p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
2088 p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
2089 Patch(Gbranch(obj.AJMP, nil, 0), to)
2090 Patch(p1, Pc)
2091 Patch(p2, Pc)
2092 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002093 return
2094 case ONE:
Russ Coxb115c352015-03-18 17:26:36 -04002095 // either NE or P
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002096 if genval {
2097 var reg Node
2098 Regalloc(&reg, Types[TBOOL], nil)
2099 Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), &reg)
2100 Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res)
2101 Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), &reg, res)
2102 Regfree(&reg)
2103 } else {
2104 Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
2105 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
2106 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002107 return
Russ Coxb115c352015-03-18 17:26:36 -04002108 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002109 case '7', '9':
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002110 if genval {
2111 Fatal("genval 7g, 9g Isfloat special cases not implemented")
2112 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002113 switch n.Op {
Russ Coxb115c352015-03-18 17:26:36 -04002114 // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002115 // TODO(josh): Convert a <= b to b > a instead?
2116 case OLE, OGE:
2117 if a == OLE {
2118 a = OLT
2119 } else {
2120 a = OGT
2121 }
2122 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
2123 Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
2124 return
Russ Coxb115c352015-03-18 17:26:36 -04002125 }
Russ Coxb115c352015-03-18 17:26:36 -04002126 }
2127 }
2128
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002129 // Not a special case. Insert the conditional jump or value gen.
2130 bins(nr.Type, res, a, likely, to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002131}
Russ Coxb115c352015-03-18 17:26:36 -04002132
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002133func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
Russ Coxb115c352015-03-18 17:26:36 -04002134 // TODO: Optimize on systems that can compare to zero easily.
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002135 a := ONE
2136 if !wantTrue {
2137 a = OEQ
Russ Coxb115c352015-03-18 17:26:36 -04002138 }
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -07002139 var zero Node
2140 Nodconst(&zero, n.Type, 0)
2141 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero)
Josh Bleecher Snyder13cb62c2015-04-08 09:54:15 -07002142 bins(n.Type, res, a, likely, to)
2143}
2144
2145// bins inserts an instruction to handle the result of a compare.
2146// If res is non-nil, it inserts appropriate value generation instructions.
2147// If res is nil, it inserts a branch to to.
2148func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) {
2149 a = Thearch.Optoas(a, typ)
2150 if res != nil {
2151 // value gen
2152 Thearch.Ginsboolval(a, res)
2153 } else {
2154 // jump
2155 Patch(Gbranch(a, typ, likely), to)
2156 }
Russ Coxb115c352015-03-18 17:26:36 -04002157}
2158
2159/*
2160 * n is on stack, either local variable
2161 * or return value from function call.
2162 * return n's offset from SP.
2163 */
2164func stkof(n *Node) int64 {
2165 switch n.Op {
2166 case OINDREG:
2167 return n.Xoffset
2168
2169 case ODOT:
2170 t := n.Left.Type
2171 if Isptr[t.Etype] {
2172 break
2173 }
2174 off := stkof(n.Left)
2175 if off == -1000 || off == 1000 {
2176 return off
2177 }
2178 return off + n.Xoffset
2179
2180 case OINDEX:
2181 t := n.Left.Type
2182 if !Isfixedarray(t) {
2183 break
2184 }
2185 off := stkof(n.Left)
2186 if off == -1000 || off == 1000 {
2187 return off
2188 }
2189 if Isconst(n.Right, CTINT) {
2190 return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval)
2191 }
2192 return 1000
2193
2194 case OCALLMETH, OCALLINTER, OCALLFUNC:
2195 t := n.Left.Type
2196 if Isptr[t.Etype] {
2197 t = t.Type
2198 }
2199
2200 var flist Iter
2201 t = Structfirst(&flist, Getoutarg(t))
2202 if t != nil {
2203 w := t.Width
2204 if HasLinkRegister() {
2205 w += int64(Ctxt.Arch.Ptrsize)
2206 }
2207 return w
2208 }
2209 }
2210
2211 // botch - probably failing to recognize address
2212 // arithmetic on the above. eg INDEX and DOT
2213 return -1000
2214}
2215
2216/*
2217 * block copy:
2218 * memmove(&ns, &n, w);
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002219 * if wb is true, needs write barrier.
Russ Coxb115c352015-03-18 17:26:36 -04002220 */
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002221func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
Russ Coxb115c352015-03-18 17:26:36 -04002222 if Debug['g'] != 0 {
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002223 op := "sgen"
2224 if wb {
2225 op = "sgen-wb"
2226 }
2227 fmt.Printf("\n%s w=%d\n", op, w)
Russ Coxb115c352015-03-18 17:26:36 -04002228 Dump("r", n)
2229 Dump("res", ns)
2230 }
2231
2232 if n.Ullman >= UINF && ns.Ullman >= UINF {
2233 Fatal("sgen UINF")
2234 }
2235
2236 if w < 0 {
2237 Fatal("sgen copy %d", w)
2238 }
2239
2240 // If copying .args, that's all the results, so record definition sites
2241 // for them for the liveness analysis.
2242 if ns.Op == ONAME && ns.Sym.Name == ".args" {
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002243 for l := Curfn.Func.Dcl; l != nil; l = l.Next {
Russ Coxb115c352015-03-18 17:26:36 -04002244 if l.N.Class == PPARAMOUT {
2245 Gvardef(l.N)
2246 }
2247 }
2248 }
2249
2250 // Avoid taking the address for simple enough types.
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002251 if componentgen_wb(n, ns, wb) {
Russ Coxb115c352015-03-18 17:26:36 -04002252 return
2253 }
2254
2255 if w == 0 {
2256 // evaluate side effects only
2257 var nodr Node
2258 Regalloc(&nodr, Types[Tptr], nil)
2259 Agen(ns, &nodr)
2260 Agen(n, &nodr)
2261 Regfree(&nodr)
2262 return
2263 }
2264
2265 // offset on the stack
2266 osrc := stkof(n)
2267 odst := stkof(ns)
2268
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002269 if odst != -1000 {
2270 // on stack, write barrier not needed after all
2271 wb = false
2272 }
2273
2274 if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -1000 {
Russ Coxb115c352015-03-18 17:26:36 -04002275 // osrc and odst both on stack, and at least one is in
2276 // an unknown position. Could generate code to test
2277 // for forward/backward copy, but instead just copy
2278 // to a temporary location first.
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002279 //
2280 // OR: write barrier needed and source is on stack.
2281 // Invoking the write barrier will use the stack to prepare its call.
2282 // Copy to temporary.
Russ Coxb115c352015-03-18 17:26:36 -04002283 var tmp Node
2284 Tempname(&tmp, n.Type)
Russ Cox0ad4f8b2015-04-17 00:25:10 -04002285 sgen_wb(n, &tmp, w, false)
2286 sgen_wb(&tmp, ns, w, wb)
2287 return
2288 }
2289
2290 if wb {
2291 cgen_wbfat(n, ns)
Russ Coxb115c352015-03-18 17:26:36 -04002292 return
2293 }
2294
Shenghou Mae7dd2882015-04-08 13:34:42 -04002295 Thearch.Blockcopy(n, ns, osrc, odst, w)
Russ Coxb115c352015-03-18 17:26:36 -04002296}
2297
2298/*
2299 * generate:
2300 * call f
2301 * proc=-1 normal call but no return
2302 * proc=0 normal call
2303 * proc=1 goroutine run in new proc
2304 * proc=2 defer call save away stack
2305 * proc=3 normal call to C pointer (not Go func value)
2306*/
2307func Ginscall(f *Node, proc int) {
2308 if f.Type != nil {
2309 extra := int32(0)
2310 if proc == 1 || proc == 2 {
2311 extra = 2 * int32(Widthptr)
2312 }
2313 Setmaxarg(f.Type, extra)
2314 }
2315
2316 switch proc {
2317 default:
2318 Fatal("Ginscall: bad proc %d", proc)
2319
2320 case 0, // normal call
2321 -1: // normal call but no return
2322 if f.Op == ONAME && f.Class == PFUNC {
2323 if f == Deferreturn {
2324 // Deferred calls will appear to be returning to
2325 // the CALL deferreturn(SB) that we are about to emit.
2326 // However, the stack trace code will show the line
2327 // of the instruction byte before the return PC.
2328 // To avoid that being an unrelated instruction,
2329 // insert an actual hardware NOP that will have the right line number.
2330 // This is different from obj.ANOP, which is a virtual no-op
2331 // that doesn't make it into the instruction stream.
2332 Thearch.Ginsnop()
2333 }
2334
2335 p := Thearch.Gins(obj.ACALL, nil, f)
2336 Afunclit(&p.To, f)
2337 if proc == -1 || Noreturn(p) {
2338 Thearch.Gins(obj.AUNDEF, nil, nil)
2339 }
2340 break
2341 }
2342
2343 var reg Node
2344 Nodreg(&reg, Types[Tptr], Thearch.REGCTXT)
2345 var r1 Node
2346 Nodreg(&r1, Types[Tptr], Thearch.REGCALLX)
2347 Thearch.Gmove(f, &reg)
2348 reg.Op = OINDREG
2349 Thearch.Gmove(&reg, &r1)
2350 reg.Op = OREGISTER
2351 Thearch.Gins(obj.ACALL, &reg, &r1)
2352
2353 case 3: // normal call of c function pointer
2354 Thearch.Gins(obj.ACALL, nil, f)
2355
2356 case 1, // call in new proc (go)
2357 2: // deferred call (defer)
2358 var stk Node
2359
2360 // size of arguments at 0(SP)
2361 stk.Op = OINDREG
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -07002362 stk.Reg = int16(Thearch.REGSP)
Russ Coxb115c352015-03-18 17:26:36 -04002363 stk.Xoffset = 0
2364 if HasLinkRegister() {
2365 stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
2366 }
Shenghou Ma931328b2015-05-02 04:36:53 -04002367 Thearch.Ginscon(Thearch.Optoas(OAS, Types[TINT32]), int64(Argsize(f.Type)), &stk)
Russ Coxb115c352015-03-18 17:26:36 -04002368
2369 // FuncVal* at 8(SP)
2370 stk.Xoffset = int64(Widthptr)
2371 if HasLinkRegister() {
2372 stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
2373 }
2374
2375 var reg Node
2376 Nodreg(&reg, Types[Tptr], Thearch.REGCALLX2)
2377 Thearch.Gmove(f, &reg)
2378 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &reg, &stk)
2379
2380 if proc == 1 {
2381 Ginscall(Newproc, 0)
2382 } else {
2383 if Hasdefer == 0 {
2384 Fatal("hasdefer=0 but has defer")
2385 }
2386 Ginscall(Deferproc, 0)
2387 }
2388
2389 if proc == 2 {
2390 Nodreg(&reg, Types[TINT32], Thearch.REGRETURN)
Russ Coxf8d14fc2015-05-06 12:28:19 -04002391 p := Thearch.Ginscmp(OEQ, Types[TINT32], &reg, Nodintconst(0), +1)
Russ Coxb115c352015-03-18 17:26:36 -04002392 cgen_ret(nil)
2393 Patch(p, Pc)
2394 }
2395 }
2396}
2397
2398/*
2399 * n is call to interface method.
2400 * generate res = n.
2401 */
2402func cgen_callinter(n *Node, res *Node, proc int) {
2403 i := n.Left
2404 if i.Op != ODOTINTER {
2405 Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0))
2406 }
2407
2408 f := i.Right // field
2409 if f.Op != ONAME {
2410 Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0))
2411 }
2412
2413 i = i.Left // interface
2414
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07002415 if !i.Addable {
Russ Coxb115c352015-03-18 17:26:36 -04002416 var tmpi Node
2417 Tempname(&tmpi, i.Type)
2418 Cgen(i, &tmpi)
2419 i = &tmpi
2420 }
2421
2422 Genlist(n.List) // assign the args
2423
2424 // i is now addable, prepare an indirected
2425 // register to hold its address.
2426 var nodi Node
2427 Igen(i, &nodi, res) // REG = &inter
2428
2429 var nodsp Node
2430 Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP)
2431 nodsp.Xoffset = 0
2432 if HasLinkRegister() {
2433 nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize)
2434 }
2435 if proc != 0 {
2436 nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn
2437 }
2438 nodi.Type = Types[Tptr]
2439 nodi.Xoffset += int64(Widthptr)
2440 Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
2441
2442 var nodo Node
2443 Regalloc(&nodo, Types[Tptr], res)
2444
2445 nodi.Type = Types[Tptr]
2446 nodi.Xoffset -= int64(Widthptr)
2447 Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
2448 Regfree(&nodi)
2449
2450 var nodr Node
2451 Regalloc(&nodr, Types[Tptr], &nodo)
2452 if n.Left.Xoffset == BADWIDTH {
2453 Fatal("cgen_callinter: badwidth")
2454 }
2455 Cgen_checknil(&nodo) // in case offset is huge
2456 nodo.Op = OINDREG
2457 nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8
2458 if proc == 0 {
2459 // plain call: use direct c function pointer - more efficient
2460 Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
2461 proc = 3
2462 } else {
2463 // go/defer. generate go func value.
2464 Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
2465 }
2466
2467 nodr.Type = n.Left.Type
2468 Ginscall(&nodr, proc)
2469
2470 Regfree(&nodr)
2471 Regfree(&nodo)
2472}
2473
2474/*
2475 * generate function call;
2476 * proc=0 normal call
2477 * proc=1 goroutine run in new proc
2478 * proc=2 defer call save away stack
2479 */
2480func cgen_call(n *Node, proc int) {
2481 if n == nil {
2482 return
2483 }
2484
2485 var afun Node
2486 if n.Left.Ullman >= UINF {
2487 // if name involves a fn call
2488 // precompute the address of the fn
2489 Tempname(&afun, Types[Tptr])
2490
2491 Cgen(n.Left, &afun)
2492 }
2493
2494 Genlist(n.List) // assign the args
2495 t := n.Left.Type
2496
2497 // call tempname pointer
2498 if n.Left.Ullman >= UINF {
2499 var nod Node
2500 Regalloc(&nod, Types[Tptr], nil)
2501 Cgen_as(&nod, &afun)
2502 nod.Type = t
2503 Ginscall(&nod, proc)
2504 Regfree(&nod)
2505 return
2506 }
2507
2508 // call pointer
2509 if n.Left.Op != ONAME || n.Left.Class != PFUNC {
2510 var nod Node
2511 Regalloc(&nod, Types[Tptr], nil)
2512 Cgen_as(&nod, n.Left)
2513 nod.Type = t
2514 Ginscall(&nod, proc)
2515 Regfree(&nod)
2516 return
2517 }
2518
2519 // call direct
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07002520 n.Left.Method = true
Russ Coxb115c352015-03-18 17:26:36 -04002521
2522 Ginscall(n.Left, proc)
2523}
2524
2525func HasLinkRegister() bool {
2526 c := Ctxt.Arch.Thechar
2527 return c != '6' && c != '8'
2528}
2529
2530/*
2531 * call to n has already been generated.
2532 * generate:
2533 * res = return value from call.
2534 */
2535func cgen_callret(n *Node, res *Node) {
2536 t := n.Left.Type
2537 if t.Etype == TPTR32 || t.Etype == TPTR64 {
2538 t = t.Type
2539 }
2540
2541 var flist Iter
2542 fp := Structfirst(&flist, Getoutarg(t))
2543 if fp == nil {
2544 Fatal("cgen_callret: nil")
2545 }
2546
2547 var nod Node
2548 nod.Op = OINDREG
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -07002549 nod.Reg = int16(Thearch.REGSP)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07002550 nod.Addable = true
Russ Coxb115c352015-03-18 17:26:36 -04002551
2552 nod.Xoffset = fp.Width
2553 if HasLinkRegister() {
2554 nod.Xoffset += int64(Ctxt.Arch.Ptrsize)
2555 }
2556 nod.Type = fp.Type
2557 Cgen_as(res, &nod)
2558}
2559
2560/*
2561 * call to n has already been generated.
2562 * generate:
2563 * res = &return value from call.
2564 */
2565func cgen_aret(n *Node, res *Node) {
2566 t := n.Left.Type
2567 if Isptr[t.Etype] {
2568 t = t.Type
2569 }
2570
2571 var flist Iter
2572 fp := Structfirst(&flist, Getoutarg(t))
2573 if fp == nil {
2574 Fatal("cgen_aret: nil")
2575 }
2576
2577 var nod1 Node
2578 nod1.Op = OINDREG
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -07002579 nod1.Reg = int16(Thearch.REGSP)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -07002580 nod1.Addable = true
Russ Coxb115c352015-03-18 17:26:36 -04002581 nod1.Xoffset = fp.Width
2582 if HasLinkRegister() {
2583 nod1.Xoffset += int64(Ctxt.Arch.Ptrsize)
2584 }
2585 nod1.Type = fp.Type
2586
2587 if res.Op != OREGISTER {
2588 var nod2 Node
2589 Regalloc(&nod2, Types[Tptr], res)
2590 Agen(&nod1, &nod2)
2591 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res)
2592 Regfree(&nod2)
2593 } else {
2594 Agen(&nod1, res)
2595 }
2596}
2597
2598/*
2599 * generate return.
2600 * n->left is assignments to return values.
2601 */
2602func cgen_ret(n *Node) {
2603 if n != nil {
2604 Genlist(n.List) // copy out args
2605 }
2606 if Hasdefer != 0 {
2607 Ginscall(Deferreturn, 0)
2608 }
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -07002609 Genlist(Curfn.Func.Exit)
Russ Coxb115c352015-03-18 17:26:36 -04002610 p := Thearch.Gins(obj.ARET, nil, nil)
2611 if n != nil && n.Op == ORETJMP {
2612 p.To.Type = obj.TYPE_MEM
2613 p.To.Name = obj.NAME_EXTERN
2614 p.To.Sym = Linksym(n.Left.Sym)
2615 }
2616}
2617
2618/*
2619 * generate division according to op, one of:
2620 * res = nl / nr
2621 * res = nl % nr
2622 */
2623func cgen_div(op int, nl *Node, nr *Node, res *Node) {
2624 var w int
2625
2626 // TODO(rsc): arm64 needs to support the relevant instructions
2627 // in peep and optoas in order to enable this.
2628 // TODO(rsc): ppc64 needs to support the relevant instructions
2629 // in peep and optoas in order to enable this.
2630 if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
2631 goto longdiv
2632 }
2633 w = int(nl.Type.Width * 8)
2634
2635 // Front end handled 32-bit division. We only need to handle 64-bit.
2636 // try to do division by multiply by (2^w)/d
2637 // see hacker's delight chapter 10
2638 switch Simtype[nl.Type.Etype] {
2639 default:
2640 goto longdiv
2641
2642 case TUINT64:
2643 var m Magic
2644 m.W = w
2645 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
2646 Umagic(&m)
2647 if m.Bad != 0 {
2648 break
2649 }
2650 if op == OMOD {
2651 goto longmod
2652 }
2653
2654 var n1 Node
2655 Cgenr(nl, &n1, nil)
2656 var n2 Node
2657 Nodconst(&n2, nl.Type, int64(m.Um))
2658 var n3 Node
2659 Regalloc(&n3, nl.Type, res)
2660 Thearch.Cgen_hmul(&n1, &n2, &n3)
2661
2662 if m.Ua != 0 {
2663 // need to add numerator accounting for overflow
2664 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
2665
2666 Nodconst(&n2, nl.Type, 1)
2667 Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
2668 Nodconst(&n2, nl.Type, int64(m.S)-1)
2669 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
2670 } else {
2671 Nodconst(&n2, nl.Type, int64(m.S))
2672 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx
2673 }
2674
2675 Thearch.Gmove(&n3, res)
2676 Regfree(&n1)
2677 Regfree(&n3)
2678 return
2679
2680 case TINT64:
2681 var m Magic
2682 m.W = w
2683 m.Sd = Mpgetfix(nr.Val.U.Xval)
2684 Smagic(&m)
2685 if m.Bad != 0 {
2686 break
2687 }
2688 if op == OMOD {
2689 goto longmod
2690 }
2691
2692 var n1 Node
2693 Cgenr(nl, &n1, res)
2694 var n2 Node
2695 Nodconst(&n2, nl.Type, m.Sm)
2696 var n3 Node
2697 Regalloc(&n3, nl.Type, nil)
2698 Thearch.Cgen_hmul(&n1, &n2, &n3)
2699
2700 if m.Sm < 0 {
2701 // need to add numerator
2702 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
2703 }
2704
2705 Nodconst(&n2, nl.Type, int64(m.S))
2706 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3
2707
2708 Nodconst(&n2, nl.Type, int64(w)-1)
2709
2710 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg
2711 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added
2712
2713 if m.Sd < 0 {
2714 // this could probably be removed
2715 // by factoring it into the multiplier
2716 Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
2717 }
2718
2719 Thearch.Gmove(&n3, res)
2720 Regfree(&n1)
2721 Regfree(&n3)
2722 return
2723 }
2724
2725 goto longdiv
2726
2727 // division and mod using (slow) hardware instruction
2728longdiv:
2729 Thearch.Dodiv(op, nl, nr, res)
2730
2731 return
2732
2733 // mod using formula A%B = A-(A/B*B) but
2734 // we know that there is a fast algorithm for A/B
2735longmod:
2736 var n1 Node
2737 Regalloc(&n1, nl.Type, res)
2738
2739 Cgen(nl, &n1)
2740 var n2 Node
2741 Regalloc(&n2, nl.Type, nil)
2742 cgen_div(ODIV, &n1, nr, &n2)
2743 a := Thearch.Optoas(OMUL, nl.Type)
2744 if w == 8 {
2745 // use 2-operand 16-bit multiply
2746 // because there is no 2-operand 8-bit multiply
2747 a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW
2748 }
2749
2750 if !Smallintconst(nr) {
2751 var n3 Node
2752 Regalloc(&n3, nl.Type, nil)
2753 Cgen(nr, &n3)
2754 Thearch.Gins(a, &n3, &n2)
2755 Regfree(&n3)
2756 } else {
2757 Thearch.Gins(a, nr, &n2)
2758 }
2759 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1)
2760 Thearch.Gmove(&n1, res)
2761 Regfree(&n1)
2762 Regfree(&n2)
2763}
2764
2765func Fixlargeoffset(n *Node) {
2766 if n == nil {
2767 return
2768 }
2769 if n.Op != OINDREG {
2770 return
2771 }
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -07002772 if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
Russ Coxb115c352015-03-18 17:26:36 -04002773 return
2774 }
2775 if n.Xoffset != int64(int32(n.Xoffset)) {
2776 // offset too large, add to register instead.
2777 a := *n
2778
2779 a.Op = OREGISTER
2780 a.Type = Types[Tptr]
2781 a.Xoffset = 0
2782 Cgen_checknil(&a)
2783 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a)
2784 n.Xoffset = 0
2785 }
2786}
Russ Cox85520472015-05-06 12:34:30 -04002787
2788func cgen_append(n, res *Node) {
2789 if Debug['g'] != 0 {
2790 Dump("cgen_append-n", n)
2791 Dump("cgen_append-res", res)
2792 }
2793 if res.Op != ONAME && !samesafeexpr(res, n.List.N) {
2794 Dump("cgen_append-n", n)
2795 Dump("cgen_append-res", res)
2796 Fatal("append not lowered")
2797 }
2798 for l := n.List; l != nil; l = l.Next {
2799 if l.N.Ullman >= UINF {
2800 Fatal("append with function call arguments")
2801 }
2802 }
2803
2804 // res = append(src, x, y, z)
2805 //
2806 // If res and src are the same, we can avoid writing to base and cap
2807 // unless we grow the underlying array.
2808 needFullUpdate := !samesafeexpr(res, n.List.N)
2809
2810 // Copy src triple into base, len, cap.
2811 base := temp(Types[Tptr])
2812 len := temp(Types[TUINT])
2813 cap := temp(Types[TUINT])
2814
2815 var src Node
2816 Igen(n.List.N, &src, nil)
2817 src.Type = Types[Tptr]
2818 Thearch.Gmove(&src, base)
2819 src.Type = Types[TUINT]
2820 src.Xoffset += int64(Widthptr)
2821 Thearch.Gmove(&src, len)
2822 src.Xoffset += int64(Widthptr)
2823 Thearch.Gmove(&src, cap)
2824
2825 // if len+argc <= cap goto L1
2826 var rlen Node
2827 Regalloc(&rlen, Types[TUINT], nil)
2828 Thearch.Gmove(len, &rlen)
2829 Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &rlen)
2830 p := Thearch.Ginscmp(OLE, Types[TUINT], &rlen, cap, +1)
2831 // Note: rlen and src are Regrealloc'ed below at the target of the
2832 // branch we just emitted; do not reuse these Go variables for
2833 // other purposes. They need to still describe the same things
2834 // below that they describe right here.
2835 Regfree(&src)
2836
2837 // base, len, cap = growslice(type, base, len, cap, newlen)
2838 var arg Node
2839 arg.Op = OINDREG
2840 arg.Reg = int16(Thearch.REGSP)
2841 arg.Addable = true
2842 arg.Xoffset = 0
2843 if HasLinkRegister() {
2844 arg.Xoffset = int64(Ctxt.Arch.Ptrsize)
2845 }
2846 arg.Type = Ptrto(Types[TUINT8])
2847 Cgen(typename(res.Type), &arg)
2848 arg.Xoffset += int64(Widthptr)
2849
2850 arg.Type = Types[Tptr]
2851 Cgen(base, &arg)
2852 arg.Xoffset += int64(Widthptr)
2853
2854 arg.Type = Types[TUINT]
2855 Cgen(len, &arg)
2856 arg.Xoffset += int64(Widthptr)
2857
2858 arg.Type = Types[TUINT]
2859 Cgen(cap, &arg)
2860 arg.Xoffset += int64(Widthptr)
2861
2862 arg.Type = Types[TUINT]
2863 Cgen(&rlen, &arg)
2864 arg.Xoffset += int64(Widthptr)
2865 Regfree(&rlen)
2866
2867 fn := syslook("growslice", 1)
2868 substArgTypes(fn, res.Type.Type, res.Type.Type)
2869 Ginscall(fn, 0)
2870
2871 if Widthptr == 4 && Widthreg == 8 {
2872 arg.Xoffset += 4
2873 }
2874
2875 arg.Type = Types[Tptr]
2876 Cgen(&arg, base)
2877 arg.Xoffset += int64(Widthptr)
2878
2879 arg.Type = Types[TUINT]
2880 Cgen(&arg, len)
2881 arg.Xoffset += int64(Widthptr)
2882
2883 arg.Type = Types[TUINT]
2884 Cgen(&arg, cap)
2885
2886 // Update res with base, len+argc, cap.
2887 if needFullUpdate {
2888 if Debug_append > 0 {
2889 Warn("append: full update")
2890 }
2891 Patch(p, Pc)
2892 }
2893 if res.Op == ONAME {
2894 Gvardef(res)
2895 }
2896 var dst, r1 Node
2897 Igen(res, &dst, nil)
2898 dst.Type = Types[TUINT]
2899 dst.Xoffset += int64(Widthptr)
2900 Regalloc(&r1, Types[TUINT], nil)
2901 Thearch.Gmove(len, &r1)
2902 Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &r1)
2903 Thearch.Gmove(&r1, &dst)
2904 Regfree(&r1)
2905 dst.Xoffset += int64(Widthptr)
2906 Thearch.Gmove(cap, &dst)
2907 dst.Type = Types[Tptr]
2908 dst.Xoffset -= 2 * int64(Widthptr)
2909 cgen_wb(base, &dst, needwritebarrier(&dst, base))
2910 Regfree(&dst)
2911
2912 if !needFullUpdate {
2913 if Debug_append > 0 {
2914 Warn("append: len-only update")
2915 }
2916 // goto L2;
2917 // L1:
2918 // update len only
2919 // L2:
2920 q := Gbranch(obj.AJMP, nil, 0)
2921 Patch(p, Pc)
2922 // At the goto above, src refers to cap and rlen holds the new len
2923 if src.Op == OREGISTER || src.Op == OINDREG {
2924 Regrealloc(&src)
2925 }
2926 Regrealloc(&rlen)
2927 src.Xoffset -= int64(Widthptr)
2928 Thearch.Gmove(&rlen, &src)
2929 Regfree(&src)
2930 Regfree(&rlen)
2931 Patch(q, Pc)
2932 }
2933
2934 // Copy data into place.
2935 // Could do write barrier check around entire copy instead of each element.
2936 // Could avoid reloading registers on each iteration if we know the cgen_wb
2937 // is not going to use a write barrier.
2938 i := 0
2939 var r2 Node
2940 for l := n.List.Next; l != nil; l = l.Next {
2941 Regalloc(&r1, Types[Tptr], nil)
2942 Thearch.Gmove(base, &r1)
2943 Regalloc(&r2, Types[TUINT], nil)
2944 Thearch.Gmove(len, &r2)
2945 if i > 0 {
2946 Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2)
2947 }
2948 w := res.Type.Type.Width
2949 if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) {
2950 // r1 updated by back end
2951 } else if w == 1 {
2952 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
2953 } else {
2954 Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), int64(w), &r2)
2955 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
2956 }
2957 Regfree(&r2)
2958
2959 r1.Op = OINDREG
2960 r1.Type = res.Type.Type
2961 cgen_wb(l.N, &r1, needwritebarrier(&r1, l.N))
2962 Regfree(&r1)
2963 i++
2964 }
2965}
Russ Coxd4472792015-05-06 12:35:53 -04002966
2967// Generate res = n, where n is x[i:j] or x[i:j:k].
2968// If wb is true, need write barrier updating res's base pointer.
2969// On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values.
2970func cgen_slice(n, res *Node, wb bool) {
2971 needFullUpdate := !samesafeexpr(n.Left, res)
2972
2973 // orderexpr has made sure that x is safe (but possibly expensive)
2974 // and i, j, k are cheap. On a system with registers (anything but 386)
2975 // we can evaluate x first and then know we have enough registers
2976 // for i, j, k as well.
2977 var x, xbase, xlen, xcap, i, j, k Node
2978 if n.Op != OSLICEARR && n.Op != OSLICE3ARR {
2979 Igen(n.Left, &x, nil)
2980 }
2981
2982 indexRegType := Types[TUINT]
2983 if Widthreg > Widthptr { // amd64p32
2984 indexRegType = Types[TUINT64]
2985 }
2986
2987 // On most systems, we use registers.
2988 // The 386 has basically no registers, so substitute functions
2989 // that can work with temporaries instead.
2990 regalloc := Regalloc
2991 ginscon := Thearch.Ginscon
2992 gins := Thearch.Gins
2993 if Thearch.Thechar == '8' {
2994 regalloc = func(n *Node, t *Type, reuse *Node) {
2995 Tempname(n, t)
2996 }
2997 ginscon = func(as int, c int64, n *Node) {
2998 var n1 Node
2999 Regalloc(&n1, n.Type, n)
3000 Thearch.Gmove(n, &n1)
3001 Thearch.Ginscon(as, c, &n1)
3002 Thearch.Gmove(&n1, n)
3003 Regfree(&n1)
3004 }
3005 gins = func(as int, f, t *Node) *obj.Prog {
3006 var n1 Node
3007 Regalloc(&n1, t.Type, t)
3008 Thearch.Gmove(t, &n1)
3009 Thearch.Gins(as, f, &n1)
3010 Thearch.Gmove(&n1, t)
3011 Regfree(&n1)
3012 return nil
3013 }
3014 }
3015
3016 panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks
3017
3018 loadlen := func() {
3019 if xlen.Op != 0 {
3020 return
3021 }
3022 if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
3023 Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound)
3024 return
3025 }
3026 if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
3027 Nodconst(&xlen, indexRegType, int64(len(n.Left.Val.U.Sval)))
3028 return
3029 }
3030 regalloc(&xlen, indexRegType, nil)
3031 x.Xoffset += int64(Widthptr)
3032 x.Type = Types[TUINT]
3033 Thearch.Gmove(&x, &xlen)
3034 x.Xoffset -= int64(Widthptr)
3035 }
3036
3037 loadcap := func() {
3038 if xcap.Op != 0 {
3039 return
3040 }
3041 if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR {
3042 loadlen()
3043 xcap = xlen
3044 if xcap.Op == OREGISTER {
3045 Regrealloc(&xcap)
3046 }
3047 return
3048 }
3049 regalloc(&xcap, indexRegType, nil)
3050 x.Xoffset += 2 * int64(Widthptr)
3051 x.Type = Types[TUINT]
3052 Thearch.Gmove(&x, &xcap)
3053 x.Xoffset -= 2 * int64(Widthptr)
3054 }
3055
3056 var x1, x2, x3 *Node // unevaluated index arguments
3057 x1 = n.Right.Left
3058 switch n.Op {
3059 default:
3060 x2 = n.Right.Right
3061 case OSLICE3, OSLICE3ARR:
3062 x2 = n.Right.Right.Left
3063 x3 = n.Right.Right.Right
3064 }
3065
3066 // load computes src into targ, but if src refers to the len or cap of n.Left,
3067 // load copies those from xlen, xcap, loading xlen if needed.
3068 // If targ.Op == OREGISTER on return, it must be Regfreed,
3069 // but it should not be modified without first checking whether it is
3070 // xlen or xcap's register.
3071 load := func(src, targ *Node) {
3072 if src == nil {
3073 return
3074 }
3075 switch src.Op {
3076 case OLITERAL:
3077 *targ = *src
3078 return
3079 case OLEN:
3080 // NOTE(rsc): This doesn't actually trigger, because order.go
3081 // has pulled all the len and cap calls into separate assignments
3082 // to temporaries. There are tests in test/sliceopt.go that could
3083 // be enabled if this is fixed.
3084 if samesafeexpr(n.Left, src.Left) {
3085 if Debug_slice > 0 {
3086 Warn("slice: reuse len")
3087 }
3088 loadlen()
3089 *targ = xlen
3090 if targ.Op == OREGISTER {
3091 Regrealloc(targ)
3092 }
3093 return
3094 }
3095 case OCAP:
3096 // NOTE(rsc): This doesn't actually trigger; see note in case OLEN above.
3097 if samesafeexpr(n.Left, src.Left) {
3098 if Debug_slice > 0 {
3099 Warn("slice: reuse cap")
3100 }
3101 loadcap()
3102 *targ = xcap
3103 if targ.Op == OREGISTER {
3104 Regrealloc(targ)
3105 }
3106 return
3107 }
3108 }
3109 if i.Op != 0 && samesafeexpr(x1, src) {
3110 if Debug_slice > 0 {
3111 Warn("slice: reuse 1st index")
3112 }
3113 *targ = i
3114 if targ.Op == OREGISTER {
3115 Regrealloc(targ)
3116 }
3117 return
3118 }
3119 if j.Op != 0 && samesafeexpr(x2, src) {
3120 if Debug_slice > 0 {
3121 Warn("slice: reuse 2nd index")
3122 }
3123 *targ = j
3124 if targ.Op == OREGISTER {
3125 Regrealloc(targ)
3126 }
3127 return
3128 }
3129 if Thearch.Cgenindex != nil {
3130 regalloc(targ, indexRegType, nil)
3131 p := Thearch.Cgenindex(src, targ, false)
3132 if p != nil {
3133 panics = append(panics, p)
3134 }
3135 } else if Thearch.Igenindex != nil {
3136 p := Thearch.Igenindex(src, targ, false)
3137 if p != nil {
3138 panics = append(panics, p)
3139 }
3140 } else {
3141 regalloc(targ, indexRegType, nil)
3142 var tmp Node
3143 Cgenr(src, &tmp, targ)
3144 Thearch.Gmove(&tmp, targ)
3145 Regfree(&tmp)
3146 }
3147 }
3148
3149 load(x1, &i)
3150 load(x2, &j)
3151 load(x3, &k)
3152
3153 // i defaults to 0.
3154 if i.Op == 0 {
3155 Nodconst(&i, indexRegType, 0)
3156 }
3157
3158 // j defaults to len(x)
3159 if j.Op == 0 {
3160 loadlen()
3161 j = xlen
3162 if j.Op == OREGISTER {
3163 Regrealloc(&j)
3164 }
3165 }
3166
3167 // k defaults to cap(x)
3168 // Only need to load it if we're recalculating cap or doing a full update.
3169 if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) {
3170 loadcap()
3171 k = xcap
3172 if k.Op == OREGISTER {
3173 Regrealloc(&k)
3174 }
3175 }
3176
3177 // Check constant indexes for negative values, and against constant length if known.
3178 // The func obvious below checks for out-of-order constant indexes.
3179 var bound int64 = -1
3180 if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
3181 bound = n.Left.Type.Type.Bound
3182 } else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
3183 bound = int64(len(n.Left.Val.U.Sval))
3184 }
3185 if Isconst(&i, CTINT) {
3186 if mpcmpfixc(i.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(i.Val.U.Xval, bound) > 0 {
3187 Yyerror("slice index out of bounds")
3188 }
3189 }
3190 if Isconst(&j, CTINT) {
3191 if mpcmpfixc(j.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(j.Val.U.Xval, bound) > 0 {
3192 Yyerror("slice index out of bounds")
3193 }
3194 }
3195 if Isconst(&k, CTINT) {
3196 if mpcmpfixc(k.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(k.Val.U.Xval, bound) > 0 {
3197 Yyerror("slice index out of bounds")
3198 }
3199 }
3200
3201 // same reports whether n1 and n2 are the same register or constant.
3202 same := func(n1, n2 *Node) bool {
3203 return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg ||
3204 n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset ||
3205 n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) == 0
3206 }
3207
3208 // obvious reports whether n1 <= n2 is obviously true,
3209 // and it calls Yyerror if n1 <= n2 is obviously false.
3210 obvious := func(n1, n2 *Node) bool {
3211 if Debug['B'] != 0 { // -B disables bounds checks
3212 return true
3213 }
3214 if same(n1, n2) {
3215 return true // n1 == n2
3216 }
3217 if iszero(n1) {
3218 return true // using unsigned compare, so 0 <= n2 always true
3219 }
3220 if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) {
3221 return true // len(x) <= cap(x) always true
3222 }
3223 if Isconst(n1, CTINT) && Isconst(n2, CTINT) {
3224 if Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) <= 0 {
3225 return true // n1, n2 constants such that n1 <= n2
3226 }
3227 Yyerror("slice index out of bounds")
3228 return true
3229 }
3230 return false
3231 }
3232
3233 compare := func(n1, n2 *Node) {
3234 p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1)
3235 panics = append(panics, p)
3236 }
3237
3238 loadcap()
3239 max := &xcap
3240 if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) {
3241 if obvious(&k, max) {
3242 if Debug_slice > 0 {
3243 Warn("slice: omit check for 3rd index")
3244 }
3245 } else {
3246 compare(&k, max)
3247 }
3248 max = &k
3249 }
3250 if j.Op != 0 {
3251 if obvious(&j, max) {
3252 if Debug_slice > 0 {
3253 Warn("slice: omit check for 2nd index")
3254 }
3255 } else {
3256 compare(&j, max)
3257 }
3258 max = &j
3259 }
3260 if i.Op != 0 {
3261 if obvious(&i, max) {
3262 if Debug_slice > 0 {
3263 Warn("slice: omit check for 1st index")
3264 }
3265 } else {
3266 compare(&i, max)
3267 }
3268 max = &i
3269 }
3270 if k.Op != 0 && i.Op != 0 {
3271 obvious(&i, &k) // emit compile-time error for x[3:n:2]
3272 }
3273
3274 if len(panics) > 0 {
3275 p := Gbranch(obj.AJMP, nil, 0)
3276 for _, q := range panics {
3277 Patch(q, Pc)
3278 }
3279 Ginscall(panicslice, -1)
3280 Patch(p, Pc)
3281 }
3282
3283 // Checks are done.
3284 // Compute new len as j-i, cap as k-i.
3285 // If i and j are same register, len is constant 0.
3286 // If i and k are same register, cap is constant 0.
3287 // If j and k are same register, len and cap are same.
3288
3289 // Done with xlen and xcap.
3290 // Now safe to modify j and k even if they alias xlen, xcap.
3291 if xlen.Op == OREGISTER {
3292 Regfree(&xlen)
3293 }
3294 if xcap.Op == OREGISTER {
3295 Regfree(&xcap)
3296 }
3297
3298 // are j and k the same value?
3299 sameJK := same(&j, &k)
3300
3301 if i.Op != 0 {
3302 // j -= i
3303 if same(&i, &j) {
3304 if Debug_slice > 0 {
3305 Warn("slice: result len == 0")
3306 }
3307 if j.Op == OREGISTER {
3308 Regfree(&j)
3309 }
3310 Nodconst(&j, indexRegType, 0)
3311 } else {
3312 switch j.Op {
3313 case OLITERAL:
3314 if Isconst(&i, CTINT) {
3315 Nodconst(&j, indexRegType, Mpgetfix(j.Val.U.Xval)-Mpgetfix(i.Val.U.Xval))
3316 if Debug_slice > 0 {
3317 Warn("slice: result len == %d", Mpgetfix(j.Val.U.Xval))
3318 }
3319 break
3320 }
3321 fallthrough
3322 case ONAME:
3323 if !istemp(&j) {
3324 var r Node
3325 regalloc(&r, indexRegType, nil)
3326 Thearch.Gmove(&j, &r)
3327 j = r
3328 }
3329 fallthrough
3330 case OREGISTER:
3331 if i.Op == OLITERAL {
3332 v := Mpgetfix(i.Val.U.Xval)
3333 if v != 0 {
3334 ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j)
3335 }
3336 } else {
3337 gins(Thearch.Optoas(OSUB, indexRegType), &i, &j)
3338 }
3339 }
3340 }
3341
3342 // k -= i if k different from j and cap is needed.j
3343 // (The modifications to j above cannot affect i: if j and i were aliased,
3344 // we replace j with a constant 0 instead of doing a subtraction,
3345 // leaving i unmodified.)
3346 if k.Op == 0 {
3347 if Debug_slice > 0 && n.Op != OSLICESTR {
3348 Warn("slice: result cap not computed")
3349 }
3350 // no need
3351 } else if same(&i, &k) {
3352 if k.Op == OREGISTER {
3353 Regfree(&k)
3354 }
3355 Nodconst(&k, indexRegType, 0)
3356 if Debug_slice > 0 {
3357 Warn("slice: result cap == 0")
3358 }
3359 } else if sameJK {
3360 if Debug_slice > 0 {
3361 Warn("slice: result cap == result len")
3362 }
3363 // k and j were the same value; make k-i the same as j-i.
3364 if k.Op == OREGISTER {
3365 Regfree(&k)
3366 }
3367 k = j
3368 if k.Op == OREGISTER {
3369 Regrealloc(&k)
3370 }
3371 } else {
3372 switch k.Op {
3373 case OLITERAL:
3374 if Isconst(&i, CTINT) {
3375 Nodconst(&k, indexRegType, Mpgetfix(k.Val.U.Xval)-Mpgetfix(i.Val.U.Xval))
3376 if Debug_slice > 0 {
3377 Warn("slice: result cap == %d", Mpgetfix(k.Val.U.Xval))
3378 }
3379 break
3380 }
3381 fallthrough
3382 case ONAME:
3383 if !istemp(&k) {
3384 var r Node
3385 regalloc(&r, indexRegType, nil)
3386 Thearch.Gmove(&k, &r)
3387 k = r
3388 }
3389 fallthrough
3390 case OREGISTER:
3391 if same(&i, &k) {
3392 Regfree(&k)
3393 Nodconst(&k, indexRegType, 0)
3394 if Debug_slice > 0 {
3395 Warn("slice: result cap == 0")
3396 }
3397 } else if i.Op == OLITERAL {
3398 v := Mpgetfix(i.Val.U.Xval)
3399 if v != 0 {
3400 ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k)
3401 }
3402 } else {
3403 gins(Thearch.Optoas(OSUB, indexRegType), &i, &k)
3404 }
3405 }
3406 }
3407 }
3408
3409 adjustBase := true
3410 if i.Op == 0 || iszero(&i) {
3411 if Debug_slice > 0 {
3412 Warn("slice: skip base adjustment for 1st index 0")
3413 }
3414 adjustBase = false
3415 } else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) {
3416 if Debug_slice > 0 {
3417 if n.Op == OSLICESTR {
3418 Warn("slice: skip base adjustment for string len == 0")
3419 } else {
3420 Warn("slice: skip base adjustment for cap == 0")
3421 }
3422 }
3423 adjustBase = false
3424 }
3425
3426 if !adjustBase && !needFullUpdate {
3427 if Debug_slice > 0 {
3428 if k.Op != 0 {
3429 Warn("slice: len/cap-only update")
3430 } else {
3431 Warn("slice: len-only update")
3432 }
3433 }
3434 if i.Op == OREGISTER {
3435 Regfree(&i)
3436 }
3437 // Write len (and cap if needed) back to x.
3438 x.Xoffset += int64(Widthptr)
3439 x.Type = Types[TUINT]
3440 Thearch.Gmove(&j, &x)
3441 x.Xoffset -= int64(Widthptr)
3442 if k.Op != 0 {
3443 x.Xoffset += 2 * int64(Widthptr)
3444 x.Type = Types[TUINT]
3445 Thearch.Gmove(&k, &x)
3446 x.Xoffset -= 2 * int64(Widthptr)
3447 }
3448 Regfree(&x)
3449 } else {
3450 // Compute new base. May smash i.
3451 if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
3452 Cgenr(n.Left, &xbase, nil)
3453 Cgen_checknil(&xbase)
3454 } else {
3455 regalloc(&xbase, Ptrto(res.Type.Type), nil)
3456 x.Type = xbase.Type
3457 Thearch.Gmove(&x, &xbase)
3458 Regfree(&x)
3459 }
3460 if i.Op != 0 && adjustBase {
3461 // Branch around the base adjustment if the resulting cap will be 0.
3462 var p *obj.Prog
3463 size := &k
3464 if k.Op == 0 {
3465 size = &j
3466 }
3467 if Isconst(size, CTINT) {
3468 // zero was checked above, must be non-zero.
3469 } else {
3470 var tmp Node
3471 Nodconst(&tmp, indexRegType, 0)
3472 p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1)
3473 }
3474 var w int64
3475 if n.Op == OSLICESTR {
3476 w = 1 // res is string, elem size is 1 (byte)
3477 } else {
3478 w = res.Type.Type.Width // res is []T, elem size is T.width
3479 }
3480 if Isconst(&i, CTINT) {
3481 ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val.U.Xval)*w, &xbase)
3482 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) {
3483 // done by back end
3484 } else if w == 1 {
3485 gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
3486 } else {
3487 if i.Op == ONAME && !istemp(&i) {
3488 var tmp Node
3489 Tempname(&tmp, i.Type)
3490 Thearch.Gmove(&i, &tmp)
3491 i = tmp
3492 }
3493 ginscon(Thearch.Optoas(OMUL, i.Type), w, &i)
3494 gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
3495 }
3496 if p != nil {
3497 Patch(p, Pc)
3498 }
3499 }
3500 if i.Op == OREGISTER {
3501 Regfree(&i)
3502 }
3503
3504 // Write len, cap, base to result.
3505 if res.Op == ONAME {
3506 Gvardef(res)
3507 }
3508 Igen(res, &x, nil)
3509 x.Xoffset += int64(Widthptr)
3510 x.Type = Types[TUINT]
3511 Thearch.Gmove(&j, &x)
3512 x.Xoffset -= int64(Widthptr)
3513 if k.Op != 0 {
3514 x.Xoffset += 2 * int64(Widthptr)
3515 Thearch.Gmove(&k, &x)
3516 x.Xoffset -= 2 * int64(Widthptr)
3517 }
3518 x.Type = xbase.Type
3519 cgen_wb(&xbase, &x, wb)
3520 Regfree(&xbase)
3521 Regfree(&x)
3522 }
3523
3524 if j.Op == OREGISTER {
3525 Regfree(&j)
3526 }
3527 if k.Op == OREGISTER {
3528 Regfree(&k)
3529 }
3530}