blob: a009186ecb507f877c7edbc79bb068fabe8eb792 [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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 (
Russ Cox5a16d6f2015-03-03 22:20:44 -05008 "cmd/internal/gc"
Russ Cox8c195bd2015-02-13 14:40:36 -05009 "cmd/internal/obj"
10 "cmd/internal/obj/ppc64"
11 "fmt"
12)
Russ Cox8c195bd2015-02-13 14:40:36 -050013
14func defframe(ptxt *obj.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -050015 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)))
Russ Cox382b44e2015-02-23 16:07:24 -050021 frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
Russ Cox8c195bd2015-02-13 14:40:36 -050022 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.
Russ Cox382b44e2015-02-23 16:07:24 -050027 p := ptxt
Russ Cox8c195bd2015-02-13 14:40:36 -050028
Russ Cox382b44e2015-02-23 16:07:24 -050029 hi := int64(0)
30 lo := hi
Russ Cox8c195bd2015-02-13 14:40:36 -050031
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 {
Russ Cox8c195bd2015-02-13 14:40:36 -050034 n = l.N
Dave Cheney38a61ff2015-03-05 07:11:40 +110035 if !n.Needzero {
Russ Cox8c195bd2015-02-13 14:40:36 -050036 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 {
Russ Cox382b44e2015-02-23 16:07:24 -050066 cnt := hi - lo
Russ Cox8c195bd2015-02-13 14:40:36 -050067 if cnt == 0 {
68 return p
69 }
70 if cnt < int64(4*gc.Widthptr) {
Russ Cox382b44e2015-02-23 16:07:24 -050071 for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
Russ Cox8c195bd2015-02-13 14:40:36 -050072 p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i)
73 }
74 } else if cnt <= int64(128*gc.Widthptr) {
75 p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
76 p.Reg = ppc64.REGSP
77 p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
Russ Cox382b44e2015-02-23 16:07:24 -050078 f := gc.Sysfunc("duffzero")
Russ Cox8b9a3d42015-03-16 15:27:19 -040079 gc.Naddr(&p.To, f)
Russ Cox8c195bd2015-02-13 14:40:36 -050080 gc.Afunclit(&p.To, f)
81 p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
82 } else {
83 p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0)
84 p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
85 p.Reg = ppc64.REGSP
86 p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
87 p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
88 p.Reg = ppc64.REGRT1
89 p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
Russ Cox382b44e2015-02-23 16:07:24 -050090 p1 := p
Russ Cox8c195bd2015-02-13 14:40:36 -050091 p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
92 p = appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
93 gc.Patch(p, p1)
94 }
95
96 return p
97}
98
99func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
Russ Cox382b44e2015-02-23 16:07:24 -0500100 q := gc.Ctxt.NewProg()
Russ Cox8c195bd2015-02-13 14:40:36 -0500101 gc.Clearp(q)
102 q.As = int16(as)
103 q.Lineno = p.Lineno
104 q.From.Type = int16(ftype)
105 q.From.Reg = int16(freg)
106 q.From.Offset = foffset
107 q.To.Type = int16(ttype)
108 q.To.Reg = int16(treg)
109 q.To.Offset = toffset
110 q.Link = p.Link
111 p.Link = q
112 return q
113}
114
Russ Coxb115c352015-03-18 17:26:36 -0400115func ginsnop() {
116 var reg gc.Node
117 gc.Nodreg(&reg, gc.Types[gc.TINT], ppc64.REG_R0)
118 gins(ppc64.AOR, &reg, &reg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500119}
120
Russ Coxb115c352015-03-18 17:26:36 -0400121var panicdiv *gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500122
123/*
124 * generate division.
125 * generates one of:
126 * res = nl / nr
127 * res = nl % nr
128 * according to op.
129 */
130func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500131 // Have to be careful about handling
132 // most negative int divided by -1 correctly.
133 // The hardware will generate undefined result.
134 // Also need to explicitly trap on division on zero,
135 // the hardware will silently generate undefined result.
136 // DIVW will leave unpredicable result in higher 32-bit,
137 // so always use DIVD/DIVDU.
Russ Cox382b44e2015-02-23 16:07:24 -0500138 t := nl.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500139
Russ Cox382b44e2015-02-23 16:07:24 -0500140 t0 := t
141 check := 0
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000142 if gc.Issigned[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500143 check = 1
Russ Coxdc7b54b2015-02-17 22:13:49 -0500144 if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500145 check = 0
Russ Coxdc7b54b2015-02-17 22:13:49 -0500146 } else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500147 check = 0
148 }
149 }
150
151 if t.Width < 8 {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000152 if gc.Issigned[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500153 t = gc.Types[gc.TINT64]
154 } else {
155 t = gc.Types[gc.TUINT64]
156 }
157 check = 0
158 }
159
Russ Cox382b44e2015-02-23 16:07:24 -0500160 a := optoas(gc.ODIV, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500161
Russ Cox382b44e2015-02-23 16:07:24 -0500162 var tl gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400163 gc.Regalloc(&tl, t0, nil)
Russ Cox382b44e2015-02-23 16:07:24 -0500164 var tr gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400165 gc.Regalloc(&tr, t0, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500166 if nl.Ullman >= nr.Ullman {
Russ Coxb115c352015-03-18 17:26:36 -0400167 gc.Cgen(nl, &tl)
168 gc.Cgen(nr, &tr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500169 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400170 gc.Cgen(nr, &tr)
171 gc.Cgen(nl, &tl)
Russ Cox8c195bd2015-02-13 14:40:36 -0500172 }
173
174 if t != t0 {
175 // Convert
Russ Cox382b44e2015-02-23 16:07:24 -0500176 tl2 := tl
Russ Cox8c195bd2015-02-13 14:40:36 -0500177
Russ Cox382b44e2015-02-23 16:07:24 -0500178 tr2 := tr
Russ Cox8c195bd2015-02-13 14:40:36 -0500179 tl.Type = t
180 tr.Type = t
181 gmove(&tl2, &tl)
182 gmove(&tr2, &tr)
183 }
184
185 // Handle divide-by-zero panic.
Russ Cox382b44e2015-02-23 16:07:24 -0500186 p1 := gins(optoas(gc.OCMP, t), &tr, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500187
188 p1.To.Type = obj.TYPE_REG
189 p1.To.Reg = ppc64.REGZERO
190 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)
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 gc.Patch(p1, gc.Pc)
196
Russ Cox382b44e2015-02-23 16:07:24 -0500197 var p2 *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500198 if check != 0 {
Russ Cox382b44e2015-02-23 16:07:24 -0500199 var nm1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500200 gc.Nodconst(&nm1, t, -1)
201 gins(optoas(gc.OCMP, t), &tr, &nm1)
Russ Cox382b44e2015-02-23 16:07:24 -0500202 p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500203 if op == gc.ODIV {
204 // a / (-1) is -a.
205 gins(optoas(gc.OMINUS, t), nil, &tl)
206
207 gmove(&tl, res)
208 } else {
209 // a % (-1) is 0.
Russ Cox382b44e2015-02-23 16:07:24 -0500210 var nz gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500211 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)
Russ Cox8c195bd2015-02-13 14:40:36 -0500223 gmove(&tl, res)
224 } else {
225 // A%B = A-(A/B*B)
Russ Cox382b44e2015-02-23 16:07:24 -0500226 var tm gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400227 gc.Regalloc(&tm, t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500228
229 // patch div to use the 3 register form
230 // TODO(minux): add gins3?
231 p1.Reg = p1.To.Reg
232
233 p1.To.Reg = tm.Val.U.Reg
234 gins(optoas(gc.OMUL, t), &tr, &tm)
Russ Coxb115c352015-03-18 17:26:36 -0400235 gc.Regfree(&tr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500236 gins(optoas(gc.OSUB, t), &tm, &tl)
Russ Coxb115c352015-03-18 17:26:36 -0400237 gc.Regfree(&tm)
Russ Cox8c195bd2015-02-13 14:40:36 -0500238 gmove(&tl, res)
239 }
240
Russ Coxb115c352015-03-18 17:26:36 -0400241 gc.Regfree(&tl)
Russ Cox8c195bd2015-02-13 14:40:36 -0500242 if check != 0 {
243 gc.Patch(p2, gc.Pc)
244 }
245}
246
247/*
Russ Cox8c195bd2015-02-13 14:40:36 -0500248 * generate high multiply:
249 * res = (nl*nr) >> width
250 */
251func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500252 // largest ullman on left.
253 if nl.Ullman < nr.Ullman {
Russ Cox382b44e2015-02-23 16:07:24 -0500254 tmp := (*gc.Node)(nl)
Russ Cox8c195bd2015-02-13 14:40:36 -0500255 nl = nr
256 nr = tmp
257 }
258
Russ Cox382b44e2015-02-23 16:07:24 -0500259 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)
Russ Cox382b44e2015-02-23 16:07:24 -0500263 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400264 gc.Cgenr(nr, &n2, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500265 switch gc.Simtype[t.Etype] {
266 case gc.TINT8,
267 gc.TINT16,
268 gc.TINT32:
269 gins(optoas(gc.OMUL, t), &n2, &n1)
Russ Cox382b44e2015-02-23 16:07:24 -0500270 p := (*obj.Prog)(gins(ppc64.ASRAD, nil, &n1))
Russ Cox8c195bd2015-02-13 14:40:36 -0500271 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)
Russ Cox382b44e2015-02-23 16:07:24 -0500278 p := (*obj.Prog)(gins(ppc64.ASRD, nil, &n1))
Russ Cox8c195bd2015-02-13 14:40:36 -0500279 p.From.Type = obj.TYPE_CONST
280 p.From.Offset = int64(w)
281
282 case gc.TINT64,
283 gc.TUINT64:
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000284 if gc.Issigned[t.Etype] {
Russ Cox382b44e2015-02-23 16:07:24 -0500285 gins(ppc64.AMULHD, &n2, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500286 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500287 gins(ppc64.AMULHDU, &n2, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500288 }
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)
Russ Cox8c195bd2015-02-13 14:40:36 -0500297}
298
299/*
300 * generate shift according to op, one of:
301 * res = nl << nr
302 * res = nl >> nr
303 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500304func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500305 a := int(optoas(op, nl.Type))
Russ Cox8c195bd2015-02-13 14:40:36 -0500306
307 if nr.Op == gc.OLITERAL {
Russ Cox382b44e2015-02-23 16:07:24 -0500308 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400309 gc.Regalloc(&n1, nl.Type, res)
310 gc.Cgen(nl, &n1)
Russ Cox382b44e2015-02-23 16:07:24 -0500311 sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
Russ Cox8c195bd2015-02-13 14:40:36 -0500312 if sc >= uint64(nl.Type.Width*8) {
313 // large shift gets 2 shifts by width-1
Russ Cox382b44e2015-02-23 16:07:24 -0500314 var n3 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500315 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)
Russ Cox79f727a2015-03-02 12:35:15 -0500324 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500325 }
326
327 if nl.Ullman >= gc.UINF {
Russ Cox382b44e2015-02-23 16:07:24 -0500328 var n4 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500329 gc.Tempname(&n4, nl.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400330 gc.Cgen(nl, &n4)
Russ Cox8c195bd2015-02-13 14:40:36 -0500331 nl = &n4
332 }
333
334 if nr.Ullman >= gc.UINF {
Russ Cox382b44e2015-02-23 16:07:24 -0500335 var n5 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500336 gc.Tempname(&n5, nr.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400337 gc.Cgen(nr, &n5)
Russ Cox8c195bd2015-02-13 14:40:36 -0500338 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.
Russ Cox79f727a2015-03-02 12:35:15 -0500344 tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
Russ Cox8c195bd2015-02-13 14:40:36 -0500345
346 if tcount.Etype < gc.TUINT32 {
347 tcount = gc.Types[gc.TUINT32]
348 }
349
Russ Cox79f727a2015-03-02 12:35:15 -0500350 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
Russ Cox79f727a2015-03-02 12:35:15 -0500352 var n3 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400353 gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
Russ Cox8c195bd2015-02-13 14:40:36 -0500354
Russ Cox79f727a2015-03-02 12:35:15 -0500355 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400356 gc.Regalloc(&n2, nl.Type, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500357
358 if nl.Ullman >= nr.Ullman {
Russ Coxb115c352015-03-18 17:26:36 -0400359 gc.Cgen(nl, &n2)
360 gc.Cgen(nr, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500361 gmove(&n1, &n3)
362 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400363 gc.Cgen(nr, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500364 gmove(&n1, &n3)
Russ Coxb115c352015-03-18 17:26:36 -0400365 gc.Cgen(nl, &n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500366 }
367
Russ Coxb115c352015-03-18 17:26:36 -0400368 gc.Regfree(&n3)
Russ Cox8c195bd2015-02-13 14:40:36 -0500369
370 // test and fix up large shifts
Russ Coxdc7b54b2015-02-17 22:13:49 -0500371 if !bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -0500372 gc.Nodconst(&n3, tcount, nl.Type.Width*8)
373 gins(optoas(gc.OCMP, tcount), &n1, &n3)
Russ Cox382b44e2015-02-23 16:07:24 -0500374 p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, tcount), nil, +1))
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000375 if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500376 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)
Russ Cox8c195bd2015-02-13 14:40:36 -0500392}
393
394func clearfat(nl *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500395 /* 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
Russ Cox382b44e2015-02-23 16:07:24 -0500400 w := uint64(uint64(nl.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -0500401
402 // Avoid taking the address for simple enough types.
Russ Coxb9602632015-03-18 12:29:40 -0400403 if gc.Componentgen(nil, nl) {
404 return
405 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500406
Russ Cox382b44e2015-02-23 16:07:24 -0500407 c := uint64(w % 8) // bytes
408 q := uint64(w / 8) // dwords
Russ Cox8c195bd2015-02-13 14:40:36 -0500409
Russ Coxb115c352015-03-18 17:26:36 -0400410 if gc.Reginuse(ppc64.REGRT1) {
411 gc.Fatal("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
Russ Cox8c195bd2015-02-13 14:40:36 -0500412 }
413
Russ Cox382b44e2015-02-23 16:07:24 -0500414 var r0 gc.Node
Shenghou Ma1e1c9dc2015-03-11 13:05:24 -0400415 gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REGZERO)
Russ Cox382b44e2015-02-23 16:07:24 -0500416 var dst gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500417 gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
Russ Coxb115c352015-03-18 17:26:36 -0400418 gc.Regrealloc(&dst)
419 gc.Agen(nl, &dst)
Russ Cox8c195bd2015-02-13 14:40:36 -0500420
Russ Cox382b44e2015-02-23 16:07:24 -0500421 var boff uint64
Russ Cox8c195bd2015-02-13 14:40:36 -0500422 if q > 128 {
Russ Cox79f727a2015-03-02 12:35:15 -0500423 p := gins(ppc64.ASUB, nil, &dst)
Russ Cox8c195bd2015-02-13 14:40:36 -0500424 p.From.Type = obj.TYPE_CONST
425 p.From.Offset = 8
426
Russ Cox382b44e2015-02-23 16:07:24 -0500427 var end gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400428 gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500429 p = gins(ppc64.AMOVD, &dst, &end)
430 p.From.Type = obj.TYPE_ADDR
431 p.From.Offset = int64(q * 8)
432
433 p = gins(ppc64.AMOVDU, &r0, &dst)
434 p.To.Type = obj.TYPE_MEM
435 p.To.Offset = 8
Russ Cox382b44e2015-02-23 16:07:24 -0500436 pl := (*obj.Prog)(p)
Russ Cox8c195bd2015-02-13 14:40:36 -0500437
438 p = gins(ppc64.ACMP, &dst, &end)
439 gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
440
Russ Coxb115c352015-03-18 17:26:36 -0400441 gc.Regfree(&end)
Russ Cox8c195bd2015-02-13 14:40:36 -0500442
443 // The loop leaves R3 on the last zeroed dword
444 boff = 8
445 } else if q >= 4 {
Russ Cox79f727a2015-03-02 12:35:15 -0500446 p := gins(ppc64.ASUB, nil, &dst)
Russ Cox8c195bd2015-02-13 14:40:36 -0500447 p.From.Type = obj.TYPE_CONST
448 p.From.Offset = 8
Russ Cox382b44e2015-02-23 16:07:24 -0500449 f := (*gc.Node)(gc.Sysfunc("duffzero"))
Russ Cox8c195bd2015-02-13 14:40:36 -0500450 p = gins(obj.ADUFFZERO, nil, f)
451 gc.Afunclit(&p.To, f)
452
453 // 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s
454 p.To.Offset = int64(4 * (128 - q))
455
456 // duffzero leaves R3 on the last zeroed dword
457 boff = 8
458 } else {
Russ Cox79f727a2015-03-02 12:35:15 -0500459 var p *obj.Prog
Russ Cox382b44e2015-02-23 16:07:24 -0500460 for t := uint64(0); t < q; t++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500461 p = gins(ppc64.AMOVD, &r0, &dst)
462 p.To.Type = obj.TYPE_MEM
463 p.To.Offset = int64(8 * t)
464 }
465
466 boff = 8 * q
467 }
468
Russ Cox79f727a2015-03-02 12:35:15 -0500469 var p *obj.Prog
Russ Cox382b44e2015-02-23 16:07:24 -0500470 for t := uint64(0); t < c; t++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500471 p = gins(ppc64.AMOVB, &r0, &dst)
472 p.To.Type = obj.TYPE_MEM
473 p.To.Offset = int64(t + boff)
474 }
475
Russ Coxb115c352015-03-18 17:26:36 -0400476 gc.Regfree(&dst)
Russ Cox8c195bd2015-02-13 14:40:36 -0500477}
478
479// Called after regopt and peep have run.
480// Expand CHECKNIL pseudo-op into actual nil pointer check.
481func expandchecks(firstp *obj.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500482 var p1 *obj.Prog
483 var p2 *obj.Prog
484
Russ Cox382b44e2015-02-23 16:07:24 -0500485 for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500486 if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
487 fmt.Printf("expandchecks: %v\n", p)
488 }
489 if p.As != obj.ACHECKNIL {
490 continue
491 }
492 if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
493 gc.Warnl(int(p.Lineno), "generated nil check")
494 }
495 if p.From.Type != obj.TYPE_REG {
496 gc.Fatal("invalid nil check %v\n", p)
497 }
498
499 /*
500 // check is
501 // TD $4, R0, arg (R0 is always zero)
502 // eqv. to:
503 // tdeq r0, arg
504 // NOTE: this needs special runtime support to make SIGTRAP recoverable.
505 reg = p->from.reg;
506 p->as = ATD;
507 p->from = p->to = p->from3 = zprog.from;
508 p->from.type = TYPE_CONST;
509 p->from.offset = 4;
510 p->from.reg = 0;
Shenghou Ma1e1c9dc2015-03-11 13:05:24 -0400511 p->reg = REGZERO;
Russ Cox8c195bd2015-02-13 14:40:36 -0500512 p->to.type = TYPE_REG;
513 p->to.reg = reg;
514 */
515 // check is
516 // CMP arg, R0
517 // BNE 2(PC) [likely]
518 // MOVD R0, 0(R0)
519 p1 = gc.Ctxt.NewProg()
520
521 p2 = gc.Ctxt.NewProg()
522 gc.Clearp(p1)
523 gc.Clearp(p2)
524 p1.Link = p2
525 p2.Link = p.Link
526 p.Link = p1
527 p1.Lineno = p.Lineno
528 p2.Lineno = p.Lineno
529 p1.Pc = 9999
530 p2.Pc = 9999
531 p.As = ppc64.ACMP
532 p.To.Type = obj.TYPE_REG
533 p.To.Reg = ppc64.REGZERO
534 p1.As = ppc64.ABNE
535
536 //p1->from.type = TYPE_CONST;
537 //p1->from.offset = 1; // likely
538 p1.To.Type = obj.TYPE_BRANCH
539
Russ Cox532ccae2015-03-16 15:54:44 -0400540 p1.To.Val = p2.Link
Russ Cox8c195bd2015-02-13 14:40:36 -0500541
542 // crash by write to memory address 0.
543 p2.As = ppc64.AMOVD
544
545 p2.From.Type = obj.TYPE_REG
Shenghou Ma1e1c9dc2015-03-11 13:05:24 -0400546 p2.From.Reg = ppc64.REGZERO
Russ Cox8c195bd2015-02-13 14:40:36 -0500547 p2.To.Type = obj.TYPE_MEM
Shenghou Ma1e1c9dc2015-03-11 13:05:24 -0400548 p2.To.Reg = ppc64.REGZERO
Russ Cox8c195bd2015-02-13 14:40:36 -0500549 p2.To.Offset = 0
550 }
551}