blob: 85ae808c31d5c644aa263902c27299ec3a565f11 [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
Russ Cox17eba6e2015-05-21 13:28:10 -04005package x86
Russ Cox8c195bd2015-02-13 14:40:36 -05006
7import (
Russ Cox17eba6e2015-05-21 13:28:10 -04008 "cmd/compile/internal/gc"
Russ Cox8c195bd2015-02-13 14:40:36 -05009 "cmd/internal/obj"
Russ Cox8afb3962015-03-04 22:58:27 -050010 "cmd/internal/obj/x86"
Russ Cox8c195bd2015-02-13 14:40:36 -050011)
Russ Cox8c195bd2015-02-13 14:40:36 -050012
13func defframe(ptxt *obj.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -050014 var n *gc.Node
15
16 // fill in argument size, stack size
17 ptxt.To.Type = obj.TYPE_TEXTSIZE
18
Russ Cox532ccae2015-03-16 15:54:44 -040019 ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
Russ Cox382b44e2015-02-23 16:07:24 -050020 frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
Russ Cox8c195bd2015-02-13 14:40:36 -050021 ptxt.To.Offset = int64(frame)
22
23 // insert code to zero ambiguously live variables
24 // so that the garbage collector only sees initialized values
25 // when it looks for pointers.
Russ Cox382b44e2015-02-23 16:07:24 -050026 p := ptxt
Russ Cox8c195bd2015-02-13 14:40:36 -050027
Russ Cox382b44e2015-02-23 16:07:24 -050028 hi := int64(0)
29 lo := hi
30 ax := uint32(0)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070031 for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050032 n = l.N
Josh Bleecher Snyder8fa14ea2015-05-15 10:02:19 -070033 if !n.Name.Needzero {
Russ Cox8c195bd2015-02-13 14:40:36 -050034 continue
35 }
36 if n.Class != gc.PAUTO {
Håvard Haugen3c9fa382015-08-30 23:10:03 +020037 gc.Fatalf("needzero class %d", n.Class)
Russ Cox8c195bd2015-02-13 14:40:36 -050038 }
39 if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
Håvard Haugen3c9fa382015-08-30 23:10:03 +020040 gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
Russ Cox8c195bd2015-02-13 14:40:36 -050041 }
42 if lo != hi && n.Xoffset+n.Type.Width == lo-int64(2*gc.Widthptr) {
43 // merge with range we already have
44 lo = n.Xoffset
45
46 continue
47 }
48
49 // zero old range
50 p = zerorange(p, int64(frame), lo, hi, &ax)
51
52 // set new range
53 hi = n.Xoffset + n.Type.Width
54
55 lo = n.Xoffset
56 }
57
58 // zero final range
59 zerorange(p, int64(frame), lo, hi, &ax)
60}
61
62func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog {
Russ Cox382b44e2015-02-23 16:07:24 -050063 cnt := hi - lo
Russ Cox8c195bd2015-02-13 14:40:36 -050064 if cnt == 0 {
65 return p
66 }
67 if *ax == 0 {
Russ Cox8afb3962015-03-04 22:58:27 -050068 p = appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -050069 *ax = 1
70 }
71
72 if cnt <= int64(4*gc.Widthreg) {
Russ Cox382b44e2015-02-23 16:07:24 -050073 for i := int64(0); i < cnt; i += int64(gc.Widthreg) {
Russ Cox8afb3962015-03-04 22:58:27 -050074 p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i)
Russ Cox8c195bd2015-02-13 14:40:36 -050075 }
76 } else if !gc.Nacl && cnt <= int64(128*gc.Widthreg) {
Russ Cox8afb3962015-03-04 22:58:27 -050077 p = appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -050078 p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg)))
79 p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
80 } else {
Russ Cox8afb3962015-03-04 22:58:27 -050081 p = appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
82 p = appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
83 p = appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
84 p = appendpp(p, x86.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -050085 }
86
87 return p
88}
89
90func 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 -050091 q := gc.Ctxt.NewProg()
Russ Cox8c195bd2015-02-13 14:40:36 -050092 gc.Clearp(q)
93 q.As = int16(as)
94 q.Lineno = p.Lineno
95 q.From.Type = int16(ftype)
96 q.From.Reg = int16(freg)
97 q.From.Offset = foffset
98 q.To.Type = int16(ttype)
99 q.To.Reg = int16(treg)
100 q.To.Offset = toffset
101 q.Link = p.Link
102 p.Link = q
103 return q
104}
105
106func clearfat(nl *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500107 /* clear a fat object */
108 if gc.Debug['g'] != 0 {
109 gc.Dump("\nclearfat", nl)
110 }
111
Russ Cox382b44e2015-02-23 16:07:24 -0500112 w := uint32(nl.Type.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -0500113
114 // Avoid taking the address for simple enough types.
Russ Coxb9602632015-03-18 12:29:40 -0400115 if gc.Componentgen(nil, nl) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500116 return
117 }
118
Russ Cox382b44e2015-02-23 16:07:24 -0500119 c := w % 4 // bytes
120 q := w / 4 // quads
Russ Cox8c195bd2015-02-13 14:40:36 -0500121
122 if q < 4 {
123 // Write sequence of MOV 0, off(base) instead of using STOSL.
124 // The hope is that although the code will be slightly longer,
125 // the MOVs will have no dependencies and pipeline better
126 // than the unrolled STOSL loop.
127 // NOTE: Must use agen, not igen, so that optimizer sees address
128 // being taken. We are not writing on field boundaries.
Russ Cox382b44e2015-02-23 16:07:24 -0500129 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400130 gc.Regalloc(&n1, gc.Types[gc.Tptr], nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500131
Russ Coxb115c352015-03-18 17:26:36 -0400132 gc.Agen(nl, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500133 n1.Op = gc.OINDREG
Russ Cox382b44e2015-02-23 16:07:24 -0500134 var z gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500135 gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
Marvin Stenger932c1e32015-09-06 16:59:57 +0200136 for ; q > 0; q-- {
Russ Cox8c195bd2015-02-13 14:40:36 -0500137 n1.Type = z.Type
Russ Cox8afb3962015-03-04 22:58:27 -0500138 gins(x86.AMOVL, &z, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500139 n1.Xoffset += 4
140 }
141
142 gc.Nodconst(&z, gc.Types[gc.TUINT8], 0)
Marvin Stenger932c1e32015-09-06 16:59:57 +0200143 for ; c > 0; c-- {
Russ Cox8c195bd2015-02-13 14:40:36 -0500144 n1.Type = z.Type
Russ Cox8afb3962015-03-04 22:58:27 -0500145 gins(x86.AMOVB, &z, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500146 n1.Xoffset++
147 }
148
Russ Coxb115c352015-03-18 17:26:36 -0400149 gc.Regfree(&n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500150 return
151 }
152
Russ Cox382b44e2015-02-23 16:07:24 -0500153 var n1 gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -0500154 gc.Nodreg(&n1, gc.Types[gc.Tptr], x86.REG_DI)
Russ Coxb115c352015-03-18 17:26:36 -0400155 gc.Agen(nl, &n1)
Russ Cox8afb3962015-03-04 22:58:27 -0500156 gconreg(x86.AMOVL, 0, x86.REG_AX)
Russ Cox8c195bd2015-02-13 14:40:36 -0500157
158 if q > 128 || (q >= 4 && gc.Nacl) {
Russ Cox8afb3962015-03-04 22:58:27 -0500159 gconreg(x86.AMOVL, int64(q), x86.REG_CX)
160 gins(x86.AREP, nil, nil) // repeat
161 gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
Russ Cox8c195bd2015-02-13 14:40:36 -0500162 } else if q >= 4 {
Russ Cox382b44e2015-02-23 16:07:24 -0500163 p := gins(obj.ADUFFZERO, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500164 p.To.Type = obj.TYPE_ADDR
165 p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
166
167 // 1 and 128 = magic constants: see ../../runtime/asm_386.s
168 p.To.Offset = 1 * (128 - int64(q))
169 } else {
170 for q > 0 {
Russ Cox8afb3962015-03-04 22:58:27 -0500171 gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
Russ Cox8c195bd2015-02-13 14:40:36 -0500172 q--
173 }
174 }
175
176 for c > 0 {
Russ Cox8afb3962015-03-04 22:58:27 -0500177 gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+
Russ Cox8c195bd2015-02-13 14:40:36 -0500178 c--
179 }
180}
181
Brad Fitzpatrick05efc182015-04-13 18:26:08 -0500182var panicdiv *gc.Node
183
Russ Cox8c195bd2015-02-13 14:40:36 -0500184/*
Russ Cox8c195bd2015-02-13 14:40:36 -0500185 * generate division.
186 * caller must set:
187 * ax = allocated AX register
188 * dx = allocated DX register
189 * generates one of:
190 * res = nl / nr
191 * res = nl % nr
192 * according to op.
193 */
194func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 // Have to be careful about handling
196 // most negative int divided by -1 correctly.
197 // The hardware will trap.
198 // Also the byte divide instruction needs AH,
199 // which we otherwise don't have to deal with.
200 // Easiest way to avoid for int8, int16: use int32.
201 // For int32 and int64, use explicit test.
202 // Could use int64 hw for int32.
Russ Cox382b44e2015-02-23 16:07:24 -0500203 t := nl.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500204
Russ Cox382b44e2015-02-23 16:07:24 -0500205 t0 := t
Marvin Stenger932c1e32015-09-06 16:59:57 +0200206 check := false
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000207 if gc.Issigned[t.Etype] {
Marvin Stenger932c1e32015-09-06 16:59:57 +0200208 check = true
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700209 if gc.Isconst(nl, gc.CTINT) && nl.Int() != -1<<uint64(t.Width*8-1) {
Marvin Stenger932c1e32015-09-06 16:59:57 +0200210 check = false
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700211 } else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
Marvin Stenger932c1e32015-09-06 16:59:57 +0200212 check = false
Russ Cox8c195bd2015-02-13 14:40:36 -0500213 }
214 }
215
216 if t.Width < 4 {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000217 if gc.Issigned[t.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500218 t = gc.Types[gc.TINT32]
219 } else {
220 t = gc.Types[gc.TUINT32]
221 }
Marvin Stenger932c1e32015-09-06 16:59:57 +0200222 check = false
Russ Cox8c195bd2015-02-13 14:40:36 -0500223 }
224
Russ Cox382b44e2015-02-23 16:07:24 -0500225 var t1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500226 gc.Tempname(&t1, t)
Russ Cox382b44e2015-02-23 16:07:24 -0500227 var t2 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500228 gc.Tempname(&t2, t)
229 if t0 != t {
Russ Cox382b44e2015-02-23 16:07:24 -0500230 var t3 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500231 gc.Tempname(&t3, t0)
Russ Cox382b44e2015-02-23 16:07:24 -0500232 var t4 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500233 gc.Tempname(&t4, t0)
Russ Coxb115c352015-03-18 17:26:36 -0400234 gc.Cgen(nl, &t3)
235 gc.Cgen(nr, &t4)
Russ Cox8c195bd2015-02-13 14:40:36 -0500236
237 // Convert.
238 gmove(&t3, &t1)
239
240 gmove(&t4, &t2)
241 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400242 gc.Cgen(nl, &t1)
243 gc.Cgen(nr, &t2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500244 }
245
Russ Cox382b44e2015-02-23 16:07:24 -0500246 var n1 gc.Node
Russ Coxdc7b54b2015-02-17 22:13:49 -0500247 if !gc.Samereg(ax, res) && !gc.Samereg(dx, res) {
Russ Coxb115c352015-03-18 17:26:36 -0400248 gc.Regalloc(&n1, t, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500249 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400250 gc.Regalloc(&n1, t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500251 }
252 gmove(&t2, &n1)
253 gmove(&t1, ax)
Russ Cox175929b2015-03-02 14:22:05 -0500254 var p2 *obj.Prog
Russ Cox382b44e2015-02-23 16:07:24 -0500255 var n4 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500256 if gc.Nacl {
257 // Native Client does not relay the divide-by-zero trap
258 // to the executing program, so we must insert a check
259 // for ourselves.
260 gc.Nodconst(&n4, t, 0)
261
262 gins(optoas(gc.OCMP, t), &n1, &n4)
Russ Cox382b44e2015-02-23 16:07:24 -0500263 p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500264 if panicdiv == nil {
265 panicdiv = gc.Sysfunc("panicdivide")
266 }
Russ Coxb115c352015-03-18 17:26:36 -0400267 gc.Ginscall(panicdiv, -1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500268 gc.Patch(p1, gc.Pc)
269 }
270
Marvin Stenger932c1e32015-09-06 16:59:57 +0200271 if check {
Russ Cox8c195bd2015-02-13 14:40:36 -0500272 gc.Nodconst(&n4, t, -1)
273 gins(optoas(gc.OCMP, t), &n1, &n4)
Russ Cox382b44e2015-02-23 16:07:24 -0500274 p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500275 if op == gc.ODIV {
276 // a / (-1) is -a.
277 gins(optoas(gc.OMINUS, t), nil, ax)
278
279 gmove(ax, res)
280 } else {
281 // a % (-1) is 0.
282 gc.Nodconst(&n4, t, 0)
283
284 gmove(&n4, res)
285 }
286
287 p2 = gc.Gbranch(obj.AJMP, nil, 0)
288 gc.Patch(p1, gc.Pc)
289 }
290
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000291 if !gc.Issigned[t.Etype] {
Russ Cox382b44e2015-02-23 16:07:24 -0500292 var nz gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500293 gc.Nodconst(&nz, t, 0)
294 gmove(&nz, dx)
295 } else {
296 gins(optoas(gc.OEXTEND, t), nil, nil)
297 }
298 gins(optoas(op, t), &n1, nil)
Russ Coxb115c352015-03-18 17:26:36 -0400299 gc.Regfree(&n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500300
301 if op == gc.ODIV {
302 gmove(ax, res)
303 } else {
304 gmove(dx, res)
305 }
Marvin Stenger932c1e32015-09-06 16:59:57 +0200306 if check {
Russ Cox8c195bd2015-02-13 14:40:36 -0500307 gc.Patch(p2, gc.Pc)
308 }
309}
310
311func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
Keith Randalle97ab0a2015-08-13 12:25:19 -0700312 r := gc.GetReg(dr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500313 gc.Nodreg(x, gc.Types[gc.TINT32], dr)
314
315 // save current ax and dx if they are live
316 // and not the destination
317 *oldx = gc.Node{}
318
Russ Coxdc7b54b2015-02-17 22:13:49 -0500319 if r > 0 && !gc.Samereg(x, res) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500320 gc.Tempname(oldx, gc.Types[gc.TINT32])
321 gmove(x, oldx)
322 }
323
Russ Coxb115c352015-03-18 17:26:36 -0400324 gc.Regalloc(x, t, x)
Russ Cox8c195bd2015-02-13 14:40:36 -0500325}
326
327func restx(x *gc.Node, oldx *gc.Node) {
Russ Coxb115c352015-03-18 17:26:36 -0400328 gc.Regfree(x)
Russ Cox8c195bd2015-02-13 14:40:36 -0500329
330 if oldx.Op != 0 {
331 x.Type = gc.Types[gc.TINT32]
332 gmove(oldx, x)
333 }
334}
335
336/*
337 * generate division according to op, one of:
338 * res = nl / nr
339 * res = nl % nr
340 */
341func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500342 if gc.Is64(nl.Type) {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200343 gc.Fatalf("cgen_div %v", nl.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500344 }
345
Russ Cox382b44e2015-02-23 16:07:24 -0500346 var t *gc.Type
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000347 if gc.Issigned[nl.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500348 t = gc.Types[gc.TINT32]
349 } else {
350 t = gc.Types[gc.TUINT32]
351 }
Russ Cox382b44e2015-02-23 16:07:24 -0500352 var ax gc.Node
353 var oldax gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -0500354 savex(x86.REG_AX, &ax, &oldax, res, t)
Russ Cox382b44e2015-02-23 16:07:24 -0500355 var olddx gc.Node
356 var dx gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -0500357 savex(x86.REG_DX, &dx, &olddx, res, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500358 dodiv(op, nl, nr, res, &ax, &dx)
359 restx(&dx, &olddx)
360 restx(&ax, &oldax)
361}
362
363/*
364 * generate shift according to op, one of:
365 * res = nl << nr
366 * res = nl >> nr
367 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500368func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500369 if nl.Type.Width > 4 {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200370 gc.Fatalf("cgen_shift %v", nl.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500371 }
372
Russ Cox382b44e2015-02-23 16:07:24 -0500373 w := int(nl.Type.Width * 8)
Russ Cox8c195bd2015-02-13 14:40:36 -0500374
Russ Cox382b44e2015-02-23 16:07:24 -0500375 a := optoas(op, nl.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500376
377 if nr.Op == gc.OLITERAL {
Russ Cox382b44e2015-02-23 16:07:24 -0500378 var n2 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500379 gc.Tempname(&n2, nl.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400380 gc.Cgen(nl, &n2)
Russ Cox382b44e2015-02-23 16:07:24 -0500381 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400382 gc.Regalloc(&n1, nl.Type, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500383 gmove(&n2, &n1)
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700384 sc := uint64(nr.Int())
Russ Cox8c195bd2015-02-13 14:40:36 -0500385 if sc >= uint64(nl.Type.Width*8) {
386 // large shift gets 2 shifts by width-1
387 gins(a, ncon(uint32(w)-1), &n1)
388
389 gins(a, ncon(uint32(w)-1), &n1)
390 } else {
391 gins(a, nr, &n1)
392 }
393 gmove(&n1, res)
Russ Coxb115c352015-03-18 17:26:36 -0400394 gc.Regfree(&n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500395 return
396 }
397
Russ Cox175929b2015-03-02 14:22:05 -0500398 var oldcx gc.Node
Russ Cox382b44e2015-02-23 16:07:24 -0500399 var cx gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -0500400 gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
Keith Randalle97ab0a2015-08-13 12:25:19 -0700401 if gc.GetReg(x86.REG_CX) > 1 && !gc.Samereg(&cx, res) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500402 gc.Tempname(&oldcx, gc.Types[gc.TUINT32])
403 gmove(&cx, &oldcx)
404 }
405
Russ Cox382b44e2015-02-23 16:07:24 -0500406 var n1 gc.Node
407 var nt gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500408 if nr.Type.Width > 4 {
409 gc.Tempname(&nt, nr.Type)
410 n1 = nt
411 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500412 gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
Russ Coxb115c352015-03-18 17:26:36 -0400413 gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
Russ Cox8c195bd2015-02-13 14:40:36 -0500414 }
415
Russ Cox382b44e2015-02-23 16:07:24 -0500416 var n2 gc.Node
Russ Coxdc7b54b2015-02-17 22:13:49 -0500417 if gc.Samereg(&cx, res) {
Russ Coxb115c352015-03-18 17:26:36 -0400418 gc.Regalloc(&n2, nl.Type, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500419 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400420 gc.Regalloc(&n2, nl.Type, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500421 }
422 if nl.Ullman >= nr.Ullman {
Russ Coxb115c352015-03-18 17:26:36 -0400423 gc.Cgen(nl, &n2)
424 gc.Cgen(nr, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500425 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400426 gc.Cgen(nr, &n1)
427 gc.Cgen(nl, &n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500428 }
429
430 // test and fix up large shifts
Russ Coxdc7b54b2015-02-17 22:13:49 -0500431 if bounded {
Russ Cox8c195bd2015-02-13 14:40:36 -0500432 if nr.Type.Width > 4 {
433 // delayed reg alloc
Russ Cox8afb3962015-03-04 22:58:27 -0500434 gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
Russ Cox8c195bd2015-02-13 14:40:36 -0500435
Russ Coxb115c352015-03-18 17:26:36 -0400436 gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
Russ Cox382b44e2015-02-23 16:07:24 -0500437 var lo gc.Node
438 var hi gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500439 split64(&nt, &lo, &hi)
440 gmove(&lo, &n1)
441 splitclean()
442 }
443 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500444 var p1 *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500445 if nr.Type.Width > 4 {
446 // delayed reg alloc
Russ Cox8afb3962015-03-04 22:58:27 -0500447 gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
Russ Cox8c195bd2015-02-13 14:40:36 -0500448
Russ Coxb115c352015-03-18 17:26:36 -0400449 gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
Russ Cox382b44e2015-02-23 16:07:24 -0500450 var lo gc.Node
451 var hi gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500452 split64(&nt, &lo, &hi)
453 gmove(&lo, &n1)
454 gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &hi, ncon(0))
Russ Cox382b44e2015-02-23 16:07:24 -0500455 p2 := gc.Gbranch(optoas(gc.ONE, gc.Types[gc.TUINT32]), nil, +1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500456 gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n1, ncon(uint32(w)))
457 p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
458 splitclean()
459 gc.Patch(p2, gc.Pc)
460 } else {
461 gins(optoas(gc.OCMP, nr.Type), &n1, ncon(uint32(w)))
462 p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
463 }
464
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000465 if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500466 gins(a, ncon(uint32(w)-1), &n2)
467 } else {
468 gmove(ncon(0), &n2)
469 }
470
471 gc.Patch(p1, gc.Pc)
472 }
473
474 gins(a, &n1, &n2)
475
476 if oldcx.Op != 0 {
477 gmove(&oldcx, &cx)
478 }
479
480 gmove(&n2, res)
481
Russ Coxb115c352015-03-18 17:26:36 -0400482 gc.Regfree(&n1)
483 gc.Regfree(&n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500484}
485
486/*
487 * generate byte multiply:
488 * res = nl * nr
489 * there is no 2-operand byte multiply instruction so
490 * we do a full-width multiplication and truncate afterwards.
491 */
Russ Coxb115c352015-03-18 17:26:36 -0400492func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
493 if optoas(op, nl.Type) != x86.AIMULB {
494 return false
495 }
496
Russ Cox8c195bd2015-02-13 14:40:36 -0500497 // copy from byte to full registers
Russ Cox382b44e2015-02-23 16:07:24 -0500498 t := gc.Types[gc.TUINT32]
Russ Cox8c195bd2015-02-13 14:40:36 -0500499
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000500 if gc.Issigned[nl.Type.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500501 t = gc.Types[gc.TINT32]
502 }
503
504 // largest ullman on left.
505 if nl.Ullman < nr.Ullman {
Marvin Stenger932c1e32015-09-06 16:59:57 +0200506 nl, nr = nr, nl
Russ Cox8c195bd2015-02-13 14:40:36 -0500507 }
508
Russ Cox382b44e2015-02-23 16:07:24 -0500509 var nt gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500510 gc.Tempname(&nt, nl.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400511 gc.Cgen(nl, &nt)
Russ Cox382b44e2015-02-23 16:07:24 -0500512 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400513 gc.Regalloc(&n1, t, res)
514 gc.Cgen(nr, &n1)
Russ Cox382b44e2015-02-23 16:07:24 -0500515 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400516 gc.Regalloc(&n2, t, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500517 gmove(&nt, &n2)
Russ Cox382b44e2015-02-23 16:07:24 -0500518 a := optoas(op, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500519 gins(a, &n2, &n1)
Russ Coxb115c352015-03-18 17:26:36 -0400520 gc.Regfree(&n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500521 gmove(&n1, res)
Russ Coxb115c352015-03-18 17:26:36 -0400522 gc.Regfree(&n1)
523
524 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500525}
526
527/*
528 * generate high multiply:
529 * res = (nl*nr) >> width
530 */
531func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500532 var n1 gc.Node
533 var n2 gc.Node
534 var ax gc.Node
535 var dx gc.Node
536
Russ Cox382b44e2015-02-23 16:07:24 -0500537 t := nl.Type
538 a := optoas(gc.OHMUL, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500539
540 // gen nl in n1.
541 gc.Tempname(&n1, t)
542
Russ Coxb115c352015-03-18 17:26:36 -0400543 gc.Cgen(nl, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500544
545 // gen nr in n2.
Russ Coxb115c352015-03-18 17:26:36 -0400546 gc.Regalloc(&n2, t, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500547
Russ Coxb115c352015-03-18 17:26:36 -0400548 gc.Cgen(nr, &n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500549
550 // multiply.
Russ Cox8afb3962015-03-04 22:58:27 -0500551 gc.Nodreg(&ax, t, x86.REG_AX)
Russ Cox8c195bd2015-02-13 14:40:36 -0500552
553 gmove(&n2, &ax)
554 gins(a, &n1, nil)
Russ Coxb115c352015-03-18 17:26:36 -0400555 gc.Regfree(&n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500556
557 if t.Width == 1 {
558 // byte multiply behaves differently.
Russ Cox8afb3962015-03-04 22:58:27 -0500559 gc.Nodreg(&ax, t, x86.REG_AH)
Russ Cox8c195bd2015-02-13 14:40:36 -0500560
Russ Cox8afb3962015-03-04 22:58:27 -0500561 gc.Nodreg(&dx, t, x86.REG_DX)
Russ Cox8c195bd2015-02-13 14:40:36 -0500562 gmove(&ax, &dx)
563 }
564
Russ Cox8afb3962015-03-04 22:58:27 -0500565 gc.Nodreg(&dx, t, x86.REG_DX)
Russ Cox8c195bd2015-02-13 14:40:36 -0500566 gmove(&dx, res)
567}
568
569/*
570 * generate floating-point operation.
571 */
572func cgen_float(n *gc.Node, res *gc.Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500573 nl := n.Left
Russ Cox8c195bd2015-02-13 14:40:36 -0500574 switch n.Op {
575 case gc.OEQ,
576 gc.ONE,
577 gc.OLT,
578 gc.OLE,
579 gc.OGE:
Russ Cox382b44e2015-02-23 16:07:24 -0500580 p1 := gc.Gbranch(obj.AJMP, nil, 0)
581 p2 := gc.Pc
Russ Coxdc7b54b2015-02-17 22:13:49 -0500582 gmove(gc.Nodbool(true), res)
Russ Cox382b44e2015-02-23 16:07:24 -0500583 p3 := gc.Gbranch(obj.AJMP, nil, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500584 gc.Patch(p1, gc.Pc)
Russ Coxb115c352015-03-18 17:26:36 -0400585 gc.Bgen(n, true, 0, p2)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500586 gmove(gc.Nodbool(false), res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500587 gc.Patch(p3, gc.Pc)
588 return
589
590 case gc.OPLUS:
Russ Coxb115c352015-03-18 17:26:36 -0400591 gc.Cgen(nl, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500592 return
593
594 case gc.OCONV:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500595 if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
Russ Coxb115c352015-03-18 17:26:36 -0400596 gc.Cgen(nl, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500597 return
598 }
599
Russ Cox382b44e2015-02-23 16:07:24 -0500600 var n2 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500601 gc.Tempname(&n2, n.Type)
Russ Cox382b44e2015-02-23 16:07:24 -0500602 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400603 gc.Mgen(nl, &n1, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500604 gmove(&n1, &n2)
605 gmove(&n2, res)
Russ Coxb115c352015-03-18 17:26:36 -0400606 gc.Mfree(&n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500607 return
608 }
609
Dave Cheney01d005c2015-03-25 09:17:09 +1100610 if gc.Thearch.Use387 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500611 cgen_float387(n, res)
Dave Cheney01d005c2015-03-25 09:17:09 +1100612 } else {
613 cgen_floatsse(n, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500614 }
615}
616
617// floating-point. 387 (not SSE2)
618func cgen_float387(n *gc.Node, res *gc.Node) {
619 var f0 gc.Node
620 var f1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500621
Russ Cox382b44e2015-02-23 16:07:24 -0500622 nl := n.Left
623 nr := n.Right
Russ Cox8afb3962015-03-04 22:58:27 -0500624 gc.Nodreg(&f0, nl.Type, x86.REG_F0)
625 gc.Nodreg(&f1, n.Type, x86.REG_F0+1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500626 if nr != nil {
Russ Cox79f727a2015-03-02 12:35:15 -0500627 // binary
628 if nl.Ullman >= nr.Ullman {
Russ Coxb115c352015-03-18 17:26:36 -0400629 gc.Cgen(nl, &f0)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700630 if nr.Addable {
Russ Cox79f727a2015-03-02 12:35:15 -0500631 gins(foptoas(int(n.Op), n.Type, 0), nr, &f0)
632 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400633 gc.Cgen(nr, &f0)
Russ Cox79f727a2015-03-02 12:35:15 -0500634 gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1)
635 }
636 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400637 gc.Cgen(nr, &f0)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700638 if nl.Addable {
Russ Cox79f727a2015-03-02 12:35:15 -0500639 gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0)
640 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400641 gc.Cgen(nl, &f0)
Russ Cox79f727a2015-03-02 12:35:15 -0500642 gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1)
643 }
644 }
645
646 gmove(&f0, res)
647 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500648 }
649
650 // unary
Russ Coxb115c352015-03-18 17:26:36 -0400651 gc.Cgen(nl, &f0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500652
653 if n.Op != gc.OCONV && n.Op != gc.OPLUS {
654 gins(foptoas(int(n.Op), n.Type, 0), nil, nil)
655 }
656 gmove(&f0, res)
657 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500658}
659
660func cgen_floatsse(n *gc.Node, res *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500661 var a int
662
Russ Cox382b44e2015-02-23 16:07:24 -0500663 nl := n.Left
664 nr := n.Right
Russ Cox8c195bd2015-02-13 14:40:36 -0500665 switch n.Op {
666 default:
667 gc.Dump("cgen_floatsse", n)
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200668 gc.Fatalf("cgen_floatsse %v", gc.Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500669 return
670
671 case gc.OMINUS,
672 gc.OCOM:
673 nr = gc.Nodintconst(-1)
674 gc.Convlit(&nr, n.Type)
675 a = foptoas(gc.OMUL, nl.Type, 0)
676 goto sbop
677
678 // symmetric binary
679 case gc.OADD,
680 gc.OMUL:
681 a = foptoas(int(n.Op), nl.Type, 0)
682
683 goto sbop
684
685 // asymmetric binary
686 case gc.OSUB,
687 gc.OMOD,
688 gc.ODIV:
689 a = foptoas(int(n.Op), nl.Type, 0)
690
691 goto abop
692 }
693
694sbop: // symmetric binary
695 if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL {
Marvin Stenger932c1e32015-09-06 16:59:57 +0200696 nl, nr = nr, nl
Russ Cox8c195bd2015-02-13 14:40:36 -0500697 }
698
699abop: // asymmetric binary
700 if nl.Ullman >= nr.Ullman {
Russ Cox382b44e2015-02-23 16:07:24 -0500701 var nt gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500702 gc.Tempname(&nt, nl.Type)
Russ Coxb115c352015-03-18 17:26:36 -0400703 gc.Cgen(nl, &nt)
Russ Cox382b44e2015-02-23 16:07:24 -0500704 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400705 gc.Mgen(nr, &n2, nil)
Russ Cox382b44e2015-02-23 16:07:24 -0500706 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400707 gc.Regalloc(&n1, nl.Type, res)
Russ Cox8c195bd2015-02-13 14:40:36 -0500708 gmove(&nt, &n1)
709 gins(a, &n2, &n1)
710 gmove(&n1, res)
Russ Coxb115c352015-03-18 17:26:36 -0400711 gc.Regfree(&n1)
712 gc.Mfree(&n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500713 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500714 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400715 gc.Regalloc(&n2, nr.Type, res)
716 gc.Cgen(nr, &n2)
Russ Cox382b44e2015-02-23 16:07:24 -0500717 var n1 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400718 gc.Regalloc(&n1, nl.Type, nil)
719 gc.Cgen(nl, &n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500720 gins(a, &n2, &n1)
Russ Coxb115c352015-03-18 17:26:36 -0400721 gc.Regfree(&n2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500722 gmove(&n1, res)
Russ Coxb115c352015-03-18 17:26:36 -0400723 gc.Regfree(&n1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500724 }
725
726 return
727}
728
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700729func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
Russ Cox382b44e2015-02-23 16:07:24 -0500730 nl := n.Left
731 nr := n.Right
732 a := int(n.Op)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700733 if !wantTrue {
Russ Cox8c195bd2015-02-13 14:40:36 -0500734 // brcom is not valid on floats when NaN is involved.
Russ Cox382b44e2015-02-23 16:07:24 -0500735 p1 := gc.Gbranch(obj.AJMP, nil, 0)
Russ Cox382b44e2015-02-23 16:07:24 -0500736 p2 := gc.Gbranch(obj.AJMP, nil, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500737 gc.Patch(p1, gc.Pc)
738
739 // No need to avoid re-genning ninit.
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700740 bgen_float(n, true, -likely, p2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500741
742 gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
743 gc.Patch(p2, gc.Pc)
744 return
745 }
746
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700747 if gc.Thearch.Use387 {
748 a = gc.Brrev(a) // because the args are stacked
749 if a == gc.OGE || a == gc.OGT {
750 // only < and <= work right with NaN; reverse if needed
751 nl, nr = nr, nl
752 a = gc.Brrev(a)
Russ Cox79f727a2015-03-02 12:35:15 -0500753 }
754
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700755 var ax, n2, tmp gc.Node
756 gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
757 gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
758 gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
759 if gc.Simsimtype(nr.Type) == gc.TFLOAT64 {
760 if nl.Ullman > nr.Ullman {
761 gc.Cgen(nl, &tmp)
762 gc.Cgen(nr, &tmp)
763 gins(x86.AFXCHD, &tmp, &n2)
764 } else {
765 gc.Cgen(nr, &tmp)
766 gc.Cgen(nl, &tmp)
767 }
768
769 gins(x86.AFUCOMIP, &tmp, &n2)
770 gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
771 } else {
772 // TODO(rsc): The moves back and forth to memory
773 // here are for truncating the value to 32 bits.
774 // This handles 32-bit comparison but presumably
775 // all the other ops have the same problem.
776 // We need to figure out what the right general
777 // solution is, besides telling people to use float64.
778 var t1 gc.Node
779 gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
780
781 var t2 gc.Node
782 gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
783 gc.Cgen(nr, &t1)
784 gc.Cgen(nl, &t2)
785 gmove(&t2, &tmp)
786 gins(x86.AFCOMFP, &t1, &tmp)
787 gins(x86.AFSTSW, nil, &ax)
788 gins(x86.ASAHF, nil, nil)
789 }
790 } else {
791 // Not 387
792 if !nl.Addable {
793 nl = gc.CgenTemp(nl)
794 }
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700795 if !nr.Addable {
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700796 nr = gc.CgenTemp(nr)
Russ Cox79f727a2015-03-02 12:35:15 -0500797 }
798
799 var n2 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400800 gc.Regalloc(&n2, nr.Type, nil)
Russ Cox79f727a2015-03-02 12:35:15 -0500801 gmove(nr, &n2)
802 nr = &n2
803
804 if nl.Op != gc.OREGISTER {
805 var n3 gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400806 gc.Regalloc(&n3, nl.Type, nil)
Russ Cox79f727a2015-03-02 12:35:15 -0500807 gmove(nl, &n3)
808 nl = &n3
809 }
810
811 if a == gc.OGE || a == gc.OGT {
812 // only < and <= work right with NaN; reverse if needed
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700813 nl, nr = nr, nl
Russ Cox79f727a2015-03-02 12:35:15 -0500814 a = gc.Brrev(a)
815 }
816
817 gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
818 if nl.Op == gc.OREGISTER {
Russ Coxb115c352015-03-18 17:26:36 -0400819 gc.Regfree(nl)
Russ Cox79f727a2015-03-02 12:35:15 -0500820 }
Russ Coxb115c352015-03-18 17:26:36 -0400821 gc.Regfree(nr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500822 }
823
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700824 switch a {
825 case gc.OEQ:
Russ Cox8c195bd2015-02-13 14:40:36 -0500826 // neither NE nor P
Russ Cox8afb3962015-03-04 22:58:27 -0500827 p1 := gc.Gbranch(x86.AJNE, nil, -likely)
Russ Cox8afb3962015-03-04 22:58:27 -0500828 p2 := gc.Gbranch(x86.AJPS, nil, -likely)
Russ Cox8c195bd2015-02-13 14:40:36 -0500829 gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
830 gc.Patch(p1, gc.Pc)
831 gc.Patch(p2, gc.Pc)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700832 case gc.ONE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500833 // either NE or P
Russ Cox8afb3962015-03-04 22:58:27 -0500834 gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
Russ Cox8afb3962015-03-04 22:58:27 -0500835 gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
Josh Bleecher Snyder4a7e5bc2015-04-06 19:36:36 -0700836 default:
Russ Cox8c195bd2015-02-13 14:40:36 -0500837 gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to)
838 }
839}
840
841// Called after regopt and peep have run.
842// Expand CHECKNIL pseudo-op into actual nil pointer check.
843func expandchecks(firstp *obj.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500844 var p1 *obj.Prog
845 var p2 *obj.Prog
846
Russ Cox382b44e2015-02-23 16:07:24 -0500847 for p := firstp; p != nil; p = p.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500848 if p.As != obj.ACHECKNIL {
849 continue
850 }
851 if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
852 gc.Warnl(int(p.Lineno), "generated nil check")
853 }
854
855 // check is
856 // CMP arg, $0
857 // JNE 2(PC) (likely)
858 // MOV AX, 0
859 p1 = gc.Ctxt.NewProg()
860
861 p2 = gc.Ctxt.NewProg()
862 gc.Clearp(p1)
863 gc.Clearp(p2)
864 p1.Link = p2
865 p2.Link = p.Link
866 p.Link = p1
867 p1.Lineno = p.Lineno
868 p2.Lineno = p.Lineno
869 p1.Pc = 9999
870 p2.Pc = 9999
Russ Cox8afb3962015-03-04 22:58:27 -0500871 p.As = x86.ACMPL
Russ Cox8c195bd2015-02-13 14:40:36 -0500872 p.To.Type = obj.TYPE_CONST
873 p.To.Offset = 0
Russ Cox8afb3962015-03-04 22:58:27 -0500874 p1.As = x86.AJNE
Russ Cox8c195bd2015-02-13 14:40:36 -0500875 p1.From.Type = obj.TYPE_CONST
876 p1.From.Offset = 1 // likely
877 p1.To.Type = obj.TYPE_BRANCH
Russ Cox532ccae2015-03-16 15:54:44 -0400878 p1.To.Val = p2.Link
Russ Cox8c195bd2015-02-13 14:40:36 -0500879
880 // crash by write to memory address 0.
881 // if possible, since we know arg is 0, use 0(arg),
882 // which will be shorter to encode than plain 0.
Russ Cox8afb3962015-03-04 22:58:27 -0500883 p2.As = x86.AMOVL
Russ Cox8c195bd2015-02-13 14:40:36 -0500884
885 p2.From.Type = obj.TYPE_REG
Russ Cox8afb3962015-03-04 22:58:27 -0500886 p2.From.Reg = x86.REG_AX
Russ Coxdc7b54b2015-02-17 22:13:49 -0500887 if regtyp(&p.From) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500888 p2.To.Type = obj.TYPE_MEM
889 p2.To.Reg = p.From.Reg
890 } else {
891 p2.To.Type = obj.TYPE_MEM
892 }
893 p2.To.Offset = 0
894 }
895}
Russ Coxb115c352015-03-18 17:26:36 -0400896
897// addr += index*width if possible.
898func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
899 switch width {
900 case 1, 2, 4, 8:
901 p1 := gins(x86.ALEAL, index, addr)
902 p1.From.Type = obj.TYPE_MEM
903 p1.From.Scale = int16(width)
904 p1.From.Index = p1.From.Reg
905 p1.From.Reg = p1.To.Reg
906 return true
907 }
908 return false
909}
Russ Cox92c826b2015-04-03 12:23:28 -0400910
911// res = runtime.getg()
912func getg(res *gc.Node) {
913 var n1 gc.Node
914 gc.Regalloc(&n1, res.Type, res)
915 mov := optoas(gc.OAS, gc.Types[gc.Tptr])
916 p := gins(mov, nil, &n1)
917 p.From.Type = obj.TYPE_REG
918 p.From.Reg = x86.REG_TLS
919 p = gins(mov, nil, &n1)
920 p.From = p.To
921 p.From.Type = obj.TYPE_MEM
922 p.From.Index = x86.REG_TLS
923 p.From.Scale = 1
924 gmove(&n1, res)
925 gc.Regfree(&n1)
926}