blob: da5215ab20ed8d2644770beef6af61072cdb46e4 [file] [log] [blame]
Shenghou Maf00c19a2015-03-08 04:32:55 -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 main
6
7import (
8 "cmd/internal/gc"
9 "cmd/internal/obj"
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +010010 "cmd/internal/obj/arm64"
Shenghou Maf00c19a2015-03-08 04:32:55 -040011 "fmt"
12)
13
14func defframe(ptxt *obj.Prog) {
15 var n *gc.Node
16
17 // fill in argument size, stack size
18 ptxt.To.Type = obj.TYPE_TEXTSIZE
19
Russ Cox532ccae2015-03-16 15:54:44 -040020 ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
Shenghou Maf00c19a2015-03-08 04:32:55 -040021 frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
22 ptxt.To.Offset = int64(frame)
23
24 // insert code to zero ambiguously live variables
25 // so that the garbage collector only sees initialized values
26 // when it looks for pointers.
27 p := ptxt
28
29 hi := int64(0)
30 lo := hi
31
32 // iterate through declarations - they are sorted in decreasing xoffset order.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070033 for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
Shenghou Maf00c19a2015-03-08 04:32:55 -040034 n = l.N
35 if !n.Needzero {
36 continue
37 }
38 if n.Class != gc.PAUTO {
39 gc.Fatal("needzero class %d", n.Class)
40 }
41 if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
42 gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
43 }
44
45 if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
46 // merge with range we already have
47 lo = n.Xoffset
48
49 continue
50 }
51
52 // zero old range
53 p = zerorange(p, int64(frame), lo, hi)
54
55 // set new range
56 hi = n.Xoffset + n.Type.Width
57
58 lo = n.Xoffset
59 }
60
61 // zero final range
62 zerorange(p, int64(frame), lo, hi)
63}
64
65func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
66 cnt := hi - lo
67 if cnt == 0 {
68 return p
69 }
70 if cnt < int64(4*gc.Widthptr) {
71 for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +010072 p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+frame+lo+i)
Shenghou Maf00c19a2015-03-08 04:32:55 -040073 }
74 } else if cnt <= int64(128*gc.Widthptr) {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +010075 p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
76 p = appendpp(p, arm64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGRT1, 0)
77 p.Reg = arm64.REGRT1
Shenghou Maf00c19a2015-03-08 04:32:55 -040078 p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
79 f := gc.Sysfunc("duffzero")
Russ Cox8b9a3d42015-03-16 15:27:19 -040080 gc.Naddr(&p.To, f)
Shenghou Maf00c19a2015-03-08 04:32:55 -040081 gc.Afunclit(&p.To, f)
82 p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
83 } else {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +010084 p = appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGTMP, 0)
85 p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
86 p = appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
87 p.Reg = arm64.REGRT1
88 p = appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm64.REGTMP, 0)
89 p = appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT2, 0)
90 p.Reg = arm64.REGRT1
91 p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGRT1, int64(gc.Widthptr))
92 p.Scond = arm64.C_XPRE
Shenghou Maf00c19a2015-03-08 04:32:55 -040093 p1 := p
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +010094 p = appendpp(p, arm64.ACMP, obj.TYPE_REG, arm64.REGRT1, 0, obj.TYPE_NONE, 0, 0)
95 p.Reg = arm64.REGRT2
96 p = appendpp(p, arm64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
Shenghou Maf00c19a2015-03-08 04:32:55 -040097 gc.Patch(p, p1)
98 }
99
100 return p
101}
102
103func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
104 q := gc.Ctxt.NewProg()
105 gc.Clearp(q)
106 q.As = int16(as)
107 q.Lineno = p.Lineno
108 q.From.Type = int16(ftype)
109 q.From.Reg = int16(freg)
110 q.From.Offset = foffset
111 q.To.Type = int16(ttype)
112 q.To.Reg = int16(treg)
113 q.To.Offset = toffset
114 q.Link = p.Link
115 p.Link = q
116 return q
117}
118
Russ Coxb115c352015-03-18 17:26:36 -0400119func ginsnop() {
120 var con gc.Node
121 gc.Nodconst(&con, gc.Types[gc.TINT], 0)
122 gins(arm64.AHINT, &con, nil)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400123}
124
125/*
126 * generate division.
127 * generates one of:
128 * res = nl / nr
129 * res = nl % nr
130 * according to op.
131 */
132func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
133 // Have to be careful about handling
134 // most negative int divided by -1 correctly.
135 // The hardware will generate undefined result.
136 // Also need to explicitly trap on division on zero,
137 // the hardware will silently generate undefined result.
138 // DIVW will leave unpredicable result in higher 32-bit,
139 // so always use DIVD/DIVDU.
140 t := nl.Type
141
142 t0 := t
143 check := 0
144 if gc.Issigned[t.Etype] {
145 check = 1
146 if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
147 check = 0
148 } else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
149 check = 0
150 }
151 }
152
153 if t.Width < 8 {
154 if gc.Issigned[t.Etype] {
155 t = gc.Types[gc.TINT64]
156 } else {
157 t = gc.Types[gc.TUINT64]
158 }
159 check = 0
160 }
161
162 a := optoas(gc.ODIV, t)
163
164 var tl gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400165 gc.Regalloc(&tl, t0, nil)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400166 var tr gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400167 gc.Regalloc(&tr, t0, nil)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400168 if nl.Ullman >= nr.Ullman {
Russ Coxb115c352015-03-18 17:26:36 -0400169 gc.Cgen(nl, &tl)
170 gc.Cgen(nr, &tr)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400171 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400172 gc.Cgen(nr, &tr)
173 gc.Cgen(nl, &tl)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400174 }
175
176 if t != t0 {
177 // Convert
178 tl2 := tl
179
180 tr2 := tr
181 tl.Type = t
182 tr.Type = t
183 gmove(&tl2, &tl)
184 gmove(&tr2, &tr)
185 }
186
187 // Handle divide-by-zero panic.
188 p1 := gins(optoas(gc.OCMP, t), &tr, nil)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100189 p1.Reg = arm64.REGZERO
Shenghou Maf00c19a2015-03-08 04:32:55 -0400190 p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
191 if panicdiv == nil {
192 panicdiv = gc.Sysfunc("panicdivide")
193 }
Russ Coxb115c352015-03-18 17:26:36 -0400194 gc.Ginscall(panicdiv, -1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400195 gc.Patch(p1, gc.Pc)
196
197 var p2 *obj.Prog
198 if check != 0 {
199 var nm1 gc.Node
200 gc.Nodconst(&nm1, t, -1)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100201 gcmp(optoas(gc.OCMP, t), &tr, &nm1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400202 p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
203 if op == gc.ODIV {
204 // a / (-1) is -a.
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100205 gins(optoas(gc.OMINUS, t), &tl, &tl)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400206
207 gmove(&tl, res)
208 } else {
209 // a % (-1) is 0.
210 var nz gc.Node
211 gc.Nodconst(&nz, t, 0)
212
213 gmove(&nz, res)
214 }
215
216 p2 = gc.Gbranch(obj.AJMP, nil, 0)
217 gc.Patch(p1, gc.Pc)
218 }
219
220 p1 = gins(a, &tr, &tl)
221 if op == gc.ODIV {
Russ Coxb115c352015-03-18 17:26:36 -0400222 gc.Regfree(&tr)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400223 gmove(&tl, res)
224 } else {
225 // A%B = A-(A/B*B)
226 var tm gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400227 gc.Regalloc(&tm, t, nil)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400228
229 // patch div to use the 3 register form
230 // TODO(minux): add gins3?
231 p1.Reg = p1.To.Reg
232
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700233 p1.To.Reg = tm.Reg
Shenghou Maf00c19a2015-03-08 04:32:55 -0400234 gins(optoas(gc.OMUL, t), &tr, &tm)
Russ Coxb115c352015-03-18 17:26:36 -0400235 gc.Regfree(&tr)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400236 gins(optoas(gc.OSUB, t), &tm, &tl)
Russ Coxb115c352015-03-18 17:26:36 -0400237 gc.Regfree(&tm)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400238 gmove(&tl, res)
239 }
240
Russ Coxb115c352015-03-18 17:26:36 -0400241 gc.Regfree(&tl)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400242 if check != 0 {
243 gc.Patch(p2, gc.Pc)
244 }
245}
246
247/*
Shenghou Maf00c19a2015-03-08 04:32:55 -0400248 * generate high multiply:
249 * res = (nl*nr) >> width
250 */
251func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
252 // largest ullman on left.
253 if nl.Ullman < nr.Ullman {
254 tmp := (*gc.Node)(nl)
255 nl = nr
256 nr = tmp
257 }
258
259 t := (*gc.Type)(nl.Type)
260 w := int(int(t.Width * 8))
261 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400262 gc.Cgenr(nl, &n1, res)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400263 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400264 gc.Cgenr(nr, &n2, nil)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400265 switch gc.Simtype[t.Etype] {
266 case gc.TINT8,
267 gc.TINT16,
268 gc.TINT32:
269 gins(optoas(gc.OMUL, t), &n2, &n1)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100270 p := (*obj.Prog)(gins(arm64.AASR, nil, &n1))
Shenghou Maf00c19a2015-03-08 04:32:55 -0400271 p.From.Type = obj.TYPE_CONST
272 p.From.Offset = int64(w)
273
274 case gc.TUINT8,
275 gc.TUINT16,
276 gc.TUINT32:
277 gins(optoas(gc.OMUL, t), &n2, &n1)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100278 p := (*obj.Prog)(gins(arm64.ALSR, nil, &n1))
Shenghou Maf00c19a2015-03-08 04:32:55 -0400279 p.From.Type = obj.TYPE_CONST
280 p.From.Offset = int64(w)
281
282 case gc.TINT64,
283 gc.TUINT64:
284 if gc.Issigned[t.Etype] {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100285 gins(arm64.ASMULH, &n2, &n1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400286 } else {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100287 gins(arm64.AUMULH, &n2, &n1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400288 }
289
290 default:
291 gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
292 }
293
Russ Coxb115c352015-03-18 17:26:36 -0400294 gc.Cgen(&n1, res)
295 gc.Regfree(&n1)
296 gc.Regfree(&n2)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400297}
298
299/*
300 * generate shift according to op, one of:
301 * res = nl << nr
302 * res = nl >> nr
303 */
304func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
305 a := int(optoas(op, nl.Type))
306
307 if nr.Op == gc.OLITERAL {
308 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400309 gc.Regalloc(&n1, nl.Type, res)
310 gc.Cgen(nl, &n1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400311 sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
312 if sc >= uint64(nl.Type.Width*8) {
313 // large shift gets 2 shifts by width-1
314 var n3 gc.Node
315 gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
316
317 gins(a, &n3, &n1)
318 gins(a, &n3, &n1)
319 } else {
320 gins(a, nr, &n1)
321 }
322 gmove(&n1, res)
Russ Coxb115c352015-03-18 17:26:36 -0400323 gc.Regfree(&n1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400324 return
325 }
326
327 if nl.Ullman >= gc.UINF {
328 var n4 gc.Node
329 gc.Tempname(&n4, nl.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400330 gc.Cgen(nl, &n4)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400331 nl = &n4
332 }
333
334 if nr.Ullman >= gc.UINF {
335 var n5 gc.Node
336 gc.Tempname(&n5, nr.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400337 gc.Cgen(nr, &n5)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400338 nr = &n5
339 }
340
341 // Allow either uint32 or uint64 as shift type,
342 // to avoid unnecessary conversion from uint32 to uint64
343 // just to do the comparison.
344 tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
345
346 if tcount.Etype < gc.TUINT32 {
347 tcount = gc.Types[gc.TUINT32]
348 }
349
350 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400351 gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
Shenghou Maf00c19a2015-03-08 04:32:55 -0400352 var n3 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400353 gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
Shenghou Maf00c19a2015-03-08 04:32:55 -0400354
355 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400356 gc.Regalloc(&n2, nl.Type, res)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400357
358 if nl.Ullman >= nr.Ullman {
Russ Coxb115c352015-03-18 17:26:36 -0400359 gc.Cgen(nl, &n2)
360 gc.Cgen(nr, &n1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400361 gmove(&n1, &n3)
362 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400363 gc.Cgen(nr, &n1)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400364 gmove(&n1, &n3)
Russ Coxb115c352015-03-18 17:26:36 -0400365 gc.Cgen(nl, &n2)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400366 }
367
Russ Coxb115c352015-03-18 17:26:36 -0400368 gc.Regfree(&n3)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400369
370 // test and fix up large shifts
371 if !bounded {
372 gc.Nodconst(&n3, tcount, nl.Type.Width*8)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100373 gcmp(optoas(gc.OCMP, tcount), &n1, &n3)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400374 p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, tcount), nil, +1))
375 if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
376 gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
377 gins(a, &n3, &n2)
378 } else {
379 gc.Nodconst(&n3, nl.Type, 0)
380 gmove(&n3, &n2)
381 }
382
383 gc.Patch(p1, gc.Pc)
384 }
385
386 gins(a, &n1, &n2)
387
388 gmove(&n2, res)
389
Russ Coxb115c352015-03-18 17:26:36 -0400390 gc.Regfree(&n1)
391 gc.Regfree(&n2)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400392}
393
394func clearfat(nl *gc.Node) {
395 /* clear a fat object */
396 if gc.Debug['g'] != 0 {
397 fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width)
398 }
399
400 w := uint64(uint64(nl.Type.Width))
401
402 // Avoid taking the address for simple enough types.
Dave Cheney5c22a4a2015-04-08 23:58:04 +1000403 if gc.Componentgen(nil, nl) {
404 return
405 }
Shenghou Maf00c19a2015-03-08 04:32:55 -0400406
407 c := uint64(w % 8) // bytes
408 q := uint64(w / 8) // dwords
409
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100410 if reg[arm64.REGRT1-arm64.REG_R0] > 0 {
411 gc.Fatal("R%d in use during clearfat", arm64.REGRT1-arm64.REG_R0)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400412 }
413
414 var r0 gc.Node
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100415 gc.Nodreg(&r0, gc.Types[gc.TUINT64], arm64.REGZERO)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400416 var dst gc.Node
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100417 gc.Nodreg(&dst, gc.Types[gc.Tptr], arm64.REGRT1)
418 reg[arm64.REGRT1-arm64.REG_R0]++
Russ Coxb115c352015-03-18 17:26:36 -0400419 gc.Agen(nl, &dst)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400420
421 var boff uint64
422 if q > 128 {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100423 p := gins(arm64.ASUB, nil, &dst)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400424 p.From.Type = obj.TYPE_CONST
425 p.From.Offset = 8
426
427 var end gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400428 gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100429 p = gins(arm64.AMOVD, &dst, &end)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400430 p.From.Type = obj.TYPE_ADDR
431 p.From.Offset = int64(q * 8)
432
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100433 p = gins(arm64.AMOVD, &r0, &dst)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400434 p.To.Type = obj.TYPE_MEM
435 p.To.Offset = 8
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100436 p.Scond = arm64.C_XPRE
Shenghou Maf00c19a2015-03-08 04:32:55 -0400437 pl := (*obj.Prog)(p)
438
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100439 p = gcmp(arm64.ACMP, &dst, &end)
440 gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), pl)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400441
Russ Coxb115c352015-03-18 17:26:36 -0400442 gc.Regfree(&end)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400443
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100444 // The loop leaves R16 on the last zeroed dword
Shenghou Maf00c19a2015-03-08 04:32:55 -0400445 boff = 8
446 } else if q >= 4 {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100447 p := gins(arm64.ASUB, nil, &dst)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400448 p.From.Type = obj.TYPE_CONST
449 p.From.Offset = 8
450 f := (*gc.Node)(gc.Sysfunc("duffzero"))
451 p = gins(obj.ADUFFZERO, nil, f)
452 gc.Afunclit(&p.To, f)
453
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100454 // 4 and 128 = magic constants: see ../../runtime/asm_arm64x.s
Shenghou Maf00c19a2015-03-08 04:32:55 -0400455 p.To.Offset = int64(4 * (128 - q))
456
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100457 // duffzero leaves R16 on the last zeroed dword
Shenghou Maf00c19a2015-03-08 04:32:55 -0400458 boff = 8
459 } else {
460 var p *obj.Prog
461 for t := uint64(0); t < q; t++ {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100462 p = gins(arm64.AMOVD, &r0, &dst)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400463 p.To.Type = obj.TYPE_MEM
464 p.To.Offset = int64(8 * t)
465 }
466
467 boff = 8 * q
468 }
469
470 var p *obj.Prog
471 for t := uint64(0); t < c; t++ {
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100472 p = gins(arm64.AMOVB, &r0, &dst)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400473 p.To.Type = obj.TYPE_MEM
474 p.To.Offset = int64(t + boff)
475 }
476
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100477 reg[arm64.REGRT1-arm64.REG_R0]--
Shenghou Maf00c19a2015-03-08 04:32:55 -0400478}
479
480// Called after regopt and peep have run.
481// Expand CHECKNIL pseudo-op into actual nil pointer check.
482func expandchecks(firstp *obj.Prog) {
483 var p1 *obj.Prog
484 var p2 *obj.Prog
485
486 for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
487 if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
488 fmt.Printf("expandchecks: %v\n", p)
489 }
490 if p.As != obj.ACHECKNIL {
491 continue
492 }
493 if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
494 gc.Warnl(int(p.Lineno), "generated nil check")
495 }
496 if p.From.Type != obj.TYPE_REG {
497 gc.Fatal("invalid nil check %v\n", p)
498 }
499
Shenghou Maf00c19a2015-03-08 04:32:55 -0400500 // check is
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100501 // CMP arg, ZR
Shenghou Maf00c19a2015-03-08 04:32:55 -0400502 // BNE 2(PC) [likely]
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100503 // MOVD ZR, 0(arg)
Shenghou Maf00c19a2015-03-08 04:32:55 -0400504 p1 = gc.Ctxt.NewProg()
505
506 p2 = gc.Ctxt.NewProg()
507 gc.Clearp(p1)
508 gc.Clearp(p2)
509 p1.Link = p2
510 p2.Link = p.Link
511 p.Link = p1
512 p1.Lineno = p.Lineno
513 p2.Lineno = p.Lineno
514 p1.Pc = 9999
515 p2.Pc = 9999
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100516 p.As = arm64.ACMP
517 p.Reg = arm64.REGZERO
518 p1.As = arm64.ABNE
Shenghou Maf00c19a2015-03-08 04:32:55 -0400519
520 //p1->from.type = TYPE_CONST;
521 //p1->from.offset = 1; // likely
522 p1.To.Type = obj.TYPE_BRANCH
523
Russ Cox532ccae2015-03-16 15:54:44 -0400524 p1.To.Val = p2.Link
Shenghou Maf00c19a2015-03-08 04:32:55 -0400525
526 // crash by write to memory address 0.
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100527 p2.As = arm64.AMOVD
Shenghou Maf00c19a2015-03-08 04:32:55 -0400528 p2.From.Type = obj.TYPE_REG
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100529 p2.From.Reg = arm64.REGZERO
Shenghou Maf00c19a2015-03-08 04:32:55 -0400530 p2.To.Type = obj.TYPE_MEM
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100531 p2.To.Reg = p.From.Reg
Shenghou Maf00c19a2015-03-08 04:32:55 -0400532 p2.To.Offset = 0
533 }
534}
Russ Cox92c826b2015-04-03 12:23:28 -0400535
536// res = runtime.getg()
537func getg(res *gc.Node) {
538 var n1 gc.Node
539 gc.Nodreg(&n1, res.Type, arm64.REGG)
540 gmove(&n1, res)
541}