blob: e59784b1f8b65e2398066bfa9789871ab5237547 [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
13/*
14 * attempt to generate 64-bit
15 * res = n
16 * return 1 on success, 0 if op not handled.
17 */
18func cgen64(n *gc.Node, res *gc.Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -050019 if res.Op != gc.OINDREG && res.Op != gc.ONAME {
20 gc.Dump("n", n)
21 gc.Dump("res", res)
Matthew Dempskyc3dfad52016-03-07 08:23:55 -080022 gc.Fatalf("cgen64 %v of %v", gc.Oconv(n.Op, 0), gc.Oconv(res.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -050023 }
24
25 switch n.Op {
26 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -080027 gc.Fatalf("cgen64 %v", gc.Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -050028
29 case gc.OMINUS:
Russ Coxb115c352015-03-18 17:26:36 -040030 gc.Cgen(n.Left, res)
Russ Cox382b44e2015-02-23 16:07:24 -050031 var hi1 gc.Node
32 var lo1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -050033 split64(res, &lo1, &hi1)
Russ Cox8afb3962015-03-04 22:58:27 -050034 gins(x86.ANEGL, nil, &lo1)
35 gins(x86.AADCL, ncon(0), &hi1)
36 gins(x86.ANEGL, nil, &hi1)
Russ Cox8c195bd2015-02-13 14:40:36 -050037 splitclean()
38 return
39
40 case gc.OCOM:
Russ Coxb115c352015-03-18 17:26:36 -040041 gc.Cgen(n.Left, res)
Russ Cox382b44e2015-02-23 16:07:24 -050042 var lo1 gc.Node
43 var hi1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -050044 split64(res, &lo1, &hi1)
Russ Cox8afb3962015-03-04 22:58:27 -050045 gins(x86.ANOTL, nil, &lo1)
46 gins(x86.ANOTL, nil, &hi1)
Russ Cox8c195bd2015-02-13 14:40:36 -050047 splitclean()
48 return
49
50 // binary operators.
51 // common setup below.
52 case gc.OADD,
53 gc.OSUB,
54 gc.OMUL,
55 gc.OLROT,
56 gc.OLSH,
57 gc.ORSH,
58 gc.OAND,
59 gc.OOR,
60 gc.OXOR:
61 break
62 }
63
Russ Cox382b44e2015-02-23 16:07:24 -050064 l := n.Left
65 r := n.Right
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -070066 if !l.Addable {
Russ Cox382b44e2015-02-23 16:07:24 -050067 var t1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -050068 gc.Tempname(&t1, l.Type)
Russ Coxb115c352015-03-18 17:26:36 -040069 gc.Cgen(l, &t1)
Russ Cox8c195bd2015-02-13 14:40:36 -050070 l = &t1
71 }
72
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -070073 if r != nil && !r.Addable {
Russ Cox382b44e2015-02-23 16:07:24 -050074 var t2 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -050075 gc.Tempname(&t2, r.Type)
Russ Coxb115c352015-03-18 17:26:36 -040076 gc.Cgen(r, &t2)
Russ Cox8c195bd2015-02-13 14:40:36 -050077 r = &t2
78 }
79
Russ Cox382b44e2015-02-23 16:07:24 -050080 var ax gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -050081 gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX)
Russ Cox382b44e2015-02-23 16:07:24 -050082 var cx gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -050083 gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
Russ Cox382b44e2015-02-23 16:07:24 -050084 var dx gc.Node
Russ Cox8afb3962015-03-04 22:58:27 -050085 gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX)
Russ Cox8c195bd2015-02-13 14:40:36 -050086
87 // Setup for binary operation.
Russ Cox382b44e2015-02-23 16:07:24 -050088 var hi1 gc.Node
89 var lo1 gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -050090 split64(l, &lo1, &hi1)
91
Russ Cox382b44e2015-02-23 16:07:24 -050092 var lo2 gc.Node
93 var hi2 gc.Node
Russ Coxdc7b54b2015-02-17 22:13:49 -050094 if gc.Is64(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -050095 split64(r, &lo2, &hi2)
96 }
97
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +000098 // Do op. Leave result in DX:AX.
Russ Cox8c195bd2015-02-13 14:40:36 -050099 switch n.Op {
100 // TODO: Constants
101 case gc.OADD:
Russ Cox8afb3962015-03-04 22:58:27 -0500102 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500103
Russ Cox8afb3962015-03-04 22:58:27 -0500104 gins(x86.AMOVL, &hi1, &dx)
105 gins(x86.AADDL, &lo2, &ax)
106 gins(x86.AADCL, &hi2, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500107
108 // TODO: Constants.
109 case gc.OSUB:
Russ Cox8afb3962015-03-04 22:58:27 -0500110 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500111
Russ Cox8afb3962015-03-04 22:58:27 -0500112 gins(x86.AMOVL, &hi1, &dx)
113 gins(x86.ASUBL, &lo2, &ax)
114 gins(x86.ASBBL, &hi2, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500115
Russ Cox8c195bd2015-02-13 14:40:36 -0500116 case gc.OMUL:
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300117 // let's call the next three EX, FX and GX
118 var ex, fx, gx gc.Node
Russ Coxb115c352015-03-18 17:26:36 -0400119 gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
Russ Coxb115c352015-03-18 17:26:36 -0400120 gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300121 gc.Regalloc(&gx, gc.Types[gc.TPTR32], nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500122
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300123 // load args into DX:AX and EX:GX.
Russ Cox8afb3962015-03-04 22:58:27 -0500124 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500125
Russ Cox8afb3962015-03-04 22:58:27 -0500126 gins(x86.AMOVL, &hi1, &dx)
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300127 gins(x86.AMOVL, &lo2, &gx)
Russ Cox8afb3962015-03-04 22:58:27 -0500128 gins(x86.AMOVL, &hi2, &ex)
Russ Cox8c195bd2015-02-13 14:40:36 -0500129
130 // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
Russ Cox8afb3962015-03-04 22:58:27 -0500131 gins(x86.AMOVL, &dx, &fx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500132
Russ Cox8afb3962015-03-04 22:58:27 -0500133 gins(x86.AORL, &ex, &fx)
134 p1 := gc.Gbranch(x86.AJNE, nil, 0)
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300135 gins(x86.AMULL, &gx, nil) // implicit &ax
Russ Cox382b44e2015-02-23 16:07:24 -0500136 p2 := gc.Gbranch(obj.AJMP, nil, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500137 gc.Patch(p1, gc.Pc)
138
139 // full 64x64 -> 64, from 32x32 -> 64.
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300140 gins(x86.AIMULL, &gx, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500141
Russ Cox8afb3962015-03-04 22:58:27 -0500142 gins(x86.AMOVL, &ax, &fx)
143 gins(x86.AIMULL, &ex, &fx)
144 gins(x86.AADDL, &dx, &fx)
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300145 gins(x86.AMOVL, &gx, &dx)
Russ Cox8afb3962015-03-04 22:58:27 -0500146 gins(x86.AMULL, &dx, nil) // implicit &ax
147 gins(x86.AADDL, &fx, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500148 gc.Patch(p2, gc.Pc)
149
Russ Coxb115c352015-03-18 17:26:36 -0400150 gc.Regfree(&ex)
151 gc.Regfree(&fx)
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300152 gc.Regfree(&gx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500153
Michael Hudson-Doyle95142852015-10-28 10:40:46 +1300154 // We only rotate by a constant c in [0,64).
Russ Cox8c195bd2015-02-13 14:40:36 -0500155 // if c >= 32:
156 // lo, hi = hi, lo
157 // c -= 32
158 // if c == 0:
159 // no-op
160 // else:
161 // t = hi
162 // shld hi:lo, c
163 // shld lo:t, c
164 case gc.OLROT:
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700165 v := uint64(r.Int())
Russ Cox8c195bd2015-02-13 14:40:36 -0500166
167 if v >= 32 {
168 // reverse during load to do the first 32 bits of rotate
169 v -= 32
170
Russ Cox8afb3962015-03-04 22:58:27 -0500171 gins(x86.AMOVL, &lo1, &dx)
172 gins(x86.AMOVL, &hi1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500173 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500174 gins(x86.AMOVL, &lo1, &ax)
175 gins(x86.AMOVL, &hi1, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500176 }
177
178 if v == 0 {
179 } else // done
180 {
Russ Cox8afb3962015-03-04 22:58:27 -0500181 gins(x86.AMOVL, &dx, &cx)
182 p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
183 p1.From.Index = x86.REG_AX // double-width shift
Russ Cox8c195bd2015-02-13 14:40:36 -0500184 p1.From.Scale = 0
Russ Cox8afb3962015-03-04 22:58:27 -0500185 p1 = gins(x86.ASHLL, ncon(uint32(v)), &ax)
186 p1.From.Index = x86.REG_CX // double-width shift
Russ Cox8c195bd2015-02-13 14:40:36 -0500187 p1.From.Scale = 0
188 }
189
190 case gc.OLSH:
191 if r.Op == gc.OLITERAL {
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700192 v := uint64(r.Int())
Russ Cox8c195bd2015-02-13 14:40:36 -0500193 if v >= 64 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500194 if gc.Is64(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 splitclean()
196 }
197 splitclean()
198 split64(res, &lo2, &hi2)
Russ Cox8afb3962015-03-04 22:58:27 -0500199 gins(x86.AMOVL, ncon(0), &lo2)
200 gins(x86.AMOVL, ncon(0), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500201 splitclean()
Russ Cox79f727a2015-03-02 12:35:15 -0500202 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500203 }
204
205 if v >= 32 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500206 if gc.Is64(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500207 splitclean()
208 }
209 split64(res, &lo2, &hi2)
210 gmove(&lo1, &hi2)
211 if v > 32 {
Russ Cox8afb3962015-03-04 22:58:27 -0500212 gins(x86.ASHLL, ncon(uint32(v-32)), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500213 }
214
Russ Cox8afb3962015-03-04 22:58:27 -0500215 gins(x86.AMOVL, ncon(0), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500216 splitclean()
217 splitclean()
Russ Cox79f727a2015-03-02 12:35:15 -0500218 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500219 }
220
221 // general shift
Russ Cox8afb3962015-03-04 22:58:27 -0500222 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500223
Russ Cox8afb3962015-03-04 22:58:27 -0500224 gins(x86.AMOVL, &hi1, &dx)
225 p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
226 p1.From.Index = x86.REG_AX // double-width shift
Russ Cox8c195bd2015-02-13 14:40:36 -0500227 p1.From.Scale = 0
Russ Cox8afb3962015-03-04 22:58:27 -0500228 gins(x86.ASHLL, ncon(uint32(v)), &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500229 break
230 }
231
232 // load value into DX:AX.
Russ Cox8afb3962015-03-04 22:58:27 -0500233 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500234
Russ Cox8afb3962015-03-04 22:58:27 -0500235 gins(x86.AMOVL, &hi1, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500236
237 // load shift value into register.
238 // if high bits are set, zero value.
Russ Cox175929b2015-03-02 14:22:05 -0500239 var p1 *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500240
Russ Coxdc7b54b2015-02-17 22:13:49 -0500241 if gc.Is64(r.Type) {
Russ Cox8afb3962015-03-04 22:58:27 -0500242 gins(x86.ACMPL, &hi2, ncon(0))
243 p1 = gc.Gbranch(x86.AJNE, nil, +1)
244 gins(x86.AMOVL, &lo2, &cx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500245 } else {
246 cx.Type = gc.Types[gc.TUINT32]
247 gmove(r, &cx)
248 }
249
250 // if shift count is >=64, zero value
Russ Cox8afb3962015-03-04 22:58:27 -0500251 gins(x86.ACMPL, &cx, ncon(64))
Russ Cox8c195bd2015-02-13 14:40:36 -0500252
Russ Cox382b44e2015-02-23 16:07:24 -0500253 p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500254 if p1 != nil {
255 gc.Patch(p1, gc.Pc)
256 }
Russ Cox8afb3962015-03-04 22:58:27 -0500257 gins(x86.AXORL, &dx, &dx)
258 gins(x86.AXORL, &ax, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500259 gc.Patch(p2, gc.Pc)
260
261 // if shift count is >= 32, zero low.
Russ Cox8afb3962015-03-04 22:58:27 -0500262 gins(x86.ACMPL, &cx, ncon(32))
Russ Cox8c195bd2015-02-13 14:40:36 -0500263
264 p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
Russ Cox8afb3962015-03-04 22:58:27 -0500265 gins(x86.AMOVL, &ax, &dx)
266 gins(x86.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count
267 gins(x86.AXORL, &ax, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500268 p2 = gc.Gbranch(obj.AJMP, nil, 0)
269 gc.Patch(p1, gc.Pc)
270
271 // general shift
Russ Cox8afb3962015-03-04 22:58:27 -0500272 p1 = gins(x86.ASHLL, &cx, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500273
Russ Cox8afb3962015-03-04 22:58:27 -0500274 p1.From.Index = x86.REG_AX // double-width shift
Russ Cox8c195bd2015-02-13 14:40:36 -0500275 p1.From.Scale = 0
Russ Cox8afb3962015-03-04 22:58:27 -0500276 gins(x86.ASHLL, &cx, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500277 gc.Patch(p2, gc.Pc)
278
279 case gc.ORSH:
280 if r.Op == gc.OLITERAL {
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700281 v := uint64(r.Int())
Russ Cox8c195bd2015-02-13 14:40:36 -0500282 if v >= 64 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500283 if gc.Is64(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500284 splitclean()
285 }
286 splitclean()
287 split64(res, &lo2, &hi2)
288 if hi1.Type.Etype == gc.TINT32 {
289 gmove(&hi1, &lo2)
Russ Cox8afb3962015-03-04 22:58:27 -0500290 gins(x86.ASARL, ncon(31), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500291 gmove(&hi1, &hi2)
Russ Cox8afb3962015-03-04 22:58:27 -0500292 gins(x86.ASARL, ncon(31), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500293 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500294 gins(x86.AMOVL, ncon(0), &lo2)
295 gins(x86.AMOVL, ncon(0), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500296 }
297
298 splitclean()
Russ Cox79f727a2015-03-02 12:35:15 -0500299 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500300 }
301
302 if v >= 32 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500303 if gc.Is64(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500304 splitclean()
305 }
306 split64(res, &lo2, &hi2)
307 gmove(&hi1, &lo2)
308 if v > 32 {
309 gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2)
310 }
311 if hi1.Type.Etype == gc.TINT32 {
312 gmove(&hi1, &hi2)
Russ Cox8afb3962015-03-04 22:58:27 -0500313 gins(x86.ASARL, ncon(31), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500314 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500315 gins(x86.AMOVL, ncon(0), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500316 }
317 splitclean()
318 splitclean()
Russ Cox79f727a2015-03-02 12:35:15 -0500319 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500320 }
321
322 // general shift
Russ Cox8afb3962015-03-04 22:58:27 -0500323 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500324
Russ Cox8afb3962015-03-04 22:58:27 -0500325 gins(x86.AMOVL, &hi1, &dx)
326 p1 := gins(x86.ASHRL, ncon(uint32(v)), &ax)
327 p1.From.Index = x86.REG_DX // double-width shift
Russ Cox8c195bd2015-02-13 14:40:36 -0500328 p1.From.Scale = 0
329 gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx)
330 break
331 }
332
333 // load value into DX:AX.
Russ Cox8afb3962015-03-04 22:58:27 -0500334 gins(x86.AMOVL, &lo1, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500335
Russ Cox8afb3962015-03-04 22:58:27 -0500336 gins(x86.AMOVL, &hi1, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500337
338 // load shift value into register.
339 // if high bits are set, zero value.
Russ Cox175929b2015-03-02 14:22:05 -0500340 var p1 *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500341
Russ Coxdc7b54b2015-02-17 22:13:49 -0500342 if gc.Is64(r.Type) {
Russ Cox8afb3962015-03-04 22:58:27 -0500343 gins(x86.ACMPL, &hi2, ncon(0))
344 p1 = gc.Gbranch(x86.AJNE, nil, +1)
345 gins(x86.AMOVL, &lo2, &cx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500346 } else {
347 cx.Type = gc.Types[gc.TUINT32]
348 gmove(r, &cx)
349 }
350
351 // if shift count is >=64, zero or sign-extend value
Russ Cox8afb3962015-03-04 22:58:27 -0500352 gins(x86.ACMPL, &cx, ncon(64))
Russ Cox8c195bd2015-02-13 14:40:36 -0500353
Russ Cox382b44e2015-02-23 16:07:24 -0500354 p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500355 if p1 != nil {
356 gc.Patch(p1, gc.Pc)
357 }
358 if hi1.Type.Etype == gc.TINT32 {
Russ Cox8afb3962015-03-04 22:58:27 -0500359 gins(x86.ASARL, ncon(31), &dx)
360 gins(x86.AMOVL, &dx, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500361 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500362 gins(x86.AXORL, &dx, &dx)
363 gins(x86.AXORL, &ax, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500364 }
365
366 gc.Patch(p2, gc.Pc)
367
368 // if shift count is >= 32, sign-extend hi.
Russ Cox8afb3962015-03-04 22:58:27 -0500369 gins(x86.ACMPL, &cx, ncon(32))
Russ Cox8c195bd2015-02-13 14:40:36 -0500370
371 p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
Russ Cox8afb3962015-03-04 22:58:27 -0500372 gins(x86.AMOVL, &dx, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500373 if hi1.Type.Etype == gc.TINT32 {
Russ Cox8afb3962015-03-04 22:58:27 -0500374 gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
375 gins(x86.ASARL, ncon(31), &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500376 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500377 gins(x86.ASHRL, &cx, &ax)
378 gins(x86.AXORL, &dx, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500379 }
380
381 p2 = gc.Gbranch(obj.AJMP, nil, 0)
382 gc.Patch(p1, gc.Pc)
383
384 // general shift
Russ Cox8afb3962015-03-04 22:58:27 -0500385 p1 = gins(x86.ASHRL, &cx, &ax)
Russ Cox8c195bd2015-02-13 14:40:36 -0500386
Russ Cox8afb3962015-03-04 22:58:27 -0500387 p1.From.Index = x86.REG_DX // double-width shift
Russ Cox8c195bd2015-02-13 14:40:36 -0500388 p1.From.Scale = 0
389 gins(optoas(gc.ORSH, hi1.Type), &cx, &dx)
390 gc.Patch(p2, gc.Pc)
391
392 // make constant the right side (it usually is anyway).
393 case gc.OXOR,
394 gc.OAND,
395 gc.OOR:
396 if lo1.Op == gc.OLITERAL {
397 nswap(&lo1, &lo2)
398 nswap(&hi1, &hi2)
399 }
400
401 if lo2.Op == gc.OLITERAL {
402 // special cases for constants.
Josh Bleecher Snyder0112f6f2015-04-22 20:08:03 -0700403 lv := uint32(lo2.Int())
404 hv := uint32(hi2.Int())
Russ Cox8c195bd2015-02-13 14:40:36 -0500405 splitclean() // right side
406 split64(res, &lo2, &hi2)
407 switch n.Op {
408 case gc.OXOR:
409 gmove(&lo1, &lo2)
410 gmove(&hi1, &hi2)
411 switch lv {
412 case 0:
413 break
414
415 case 0xffffffff:
Russ Cox8afb3962015-03-04 22:58:27 -0500416 gins(x86.ANOTL, nil, &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500417
418 default:
Russ Cox8afb3962015-03-04 22:58:27 -0500419 gins(x86.AXORL, ncon(lv), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500420 }
421
422 switch hv {
423 case 0:
424 break
425
426 case 0xffffffff:
Russ Cox8afb3962015-03-04 22:58:27 -0500427 gins(x86.ANOTL, nil, &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500428
429 default:
Russ Cox8afb3962015-03-04 22:58:27 -0500430 gins(x86.AXORL, ncon(hv), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500431 }
432
433 case gc.OAND:
434 switch lv {
435 case 0:
Russ Cox8afb3962015-03-04 22:58:27 -0500436 gins(x86.AMOVL, ncon(0), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500437
438 default:
439 gmove(&lo1, &lo2)
440 if lv != 0xffffffff {
Russ Cox8afb3962015-03-04 22:58:27 -0500441 gins(x86.AANDL, ncon(lv), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500442 }
443 }
444
445 switch hv {
446 case 0:
Russ Cox8afb3962015-03-04 22:58:27 -0500447 gins(x86.AMOVL, ncon(0), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500448
449 default:
450 gmove(&hi1, &hi2)
451 if hv != 0xffffffff {
Russ Cox8afb3962015-03-04 22:58:27 -0500452 gins(x86.AANDL, ncon(hv), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500453 }
454 }
455
456 case gc.OOR:
457 switch lv {
458 case 0:
459 gmove(&lo1, &lo2)
460
461 case 0xffffffff:
Russ Cox8afb3962015-03-04 22:58:27 -0500462 gins(x86.AMOVL, ncon(0xffffffff), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500463
464 default:
465 gmove(&lo1, &lo2)
Russ Cox8afb3962015-03-04 22:58:27 -0500466 gins(x86.AORL, ncon(lv), &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500467 }
468
469 switch hv {
470 case 0:
471 gmove(&hi1, &hi2)
472
473 case 0xffffffff:
Russ Cox8afb3962015-03-04 22:58:27 -0500474 gins(x86.AMOVL, ncon(0xffffffff), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500475
476 default:
477 gmove(&hi1, &hi2)
Russ Cox8afb3962015-03-04 22:58:27 -0500478 gins(x86.AORL, ncon(hv), &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500479 }
480 }
481
482 splitclean()
483 splitclean()
Russ Cox79f727a2015-03-02 12:35:15 -0500484 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500485 }
486
Russ Cox8afb3962015-03-04 22:58:27 -0500487 gins(x86.AMOVL, &lo1, &ax)
488 gins(x86.AMOVL, &hi1, &dx)
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200489 gins(optoas(n.Op, lo1.Type), &lo2, &ax)
490 gins(optoas(n.Op, lo1.Type), &hi2, &dx)
Russ Cox8c195bd2015-02-13 14:40:36 -0500491 }
492
Russ Coxdc7b54b2015-02-17 22:13:49 -0500493 if gc.Is64(r.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500494 splitclean()
495 }
496 splitclean()
497
498 split64(res, &lo1, &hi1)
Russ Cox8afb3962015-03-04 22:58:27 -0500499 gins(x86.AMOVL, &ax, &lo1)
500 gins(x86.AMOVL, &dx, &hi1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500501 splitclean()
Russ Cox8c195bd2015-02-13 14:40:36 -0500502}
503
504/*
505 * generate comparison of nl, nr, both 64-bit.
506 * nl is memory; nr is constant or memory.
507 */
Marvin Stenger8e7a3ea2015-09-24 23:21:18 +0200508func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500509 var lo1 gc.Node
510 var hi1 gc.Node
511 var lo2 gc.Node
512 var hi2 gc.Node
513 var rr gc.Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500514
515 split64(nl, &lo1, &hi1)
516 split64(nr, &lo2, &hi2)
517
518 // compare most significant word;
519 // if they differ, we're done.
Russ Cox382b44e2015-02-23 16:07:24 -0500520 t := hi1.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500521
522 if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
Russ Cox8afb3962015-03-04 22:58:27 -0500523 gins(x86.ACMPL, &hi1, &hi2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500524 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400525 gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
Russ Cox8afb3962015-03-04 22:58:27 -0500526 gins(x86.AMOVL, &hi1, &rr)
527 gins(x86.ACMPL, &rr, &hi2)
Russ Coxb115c352015-03-18 17:26:36 -0400528 gc.Regfree(&rr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500529 }
530
Russ Cox175929b2015-03-02 14:22:05 -0500531 var br *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500532 switch op {
533 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -0800534 gc.Fatalf("cmp64 %v %v", gc.Oconv(op, 0), t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500535
536 // cmp hi
537 // jne L
538 // cmp lo
539 // jeq to
540 // L:
541 case gc.OEQ:
Russ Cox8afb3962015-03-04 22:58:27 -0500542 br = gc.Gbranch(x86.AJNE, nil, -likely)
Russ Cox8c195bd2015-02-13 14:40:36 -0500543
544 // cmp hi
545 // jne to
546 // cmp lo
547 // jne to
548 case gc.ONE:
Russ Cox8afb3962015-03-04 22:58:27 -0500549 gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
Russ Cox8c195bd2015-02-13 14:40:36 -0500550
551 // cmp hi
552 // jgt to
553 // jlt L
554 // cmp lo
555 // jge to (or jgt to)
556 // L:
557 case gc.OGE,
558 gc.OGT:
559 gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
560
561 br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
562
563 // cmp hi
564 // jlt to
565 // jgt L
566 // cmp lo
567 // jle to (or jlt to)
568 // L:
569 case gc.OLE,
570 gc.OLT:
571 gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
572
573 br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
574 }
575
576 // compare least significant word
577 t = lo1.Type
578
579 if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
Russ Cox8afb3962015-03-04 22:58:27 -0500580 gins(x86.ACMPL, &lo1, &lo2)
Russ Cox8c195bd2015-02-13 14:40:36 -0500581 } else {
Russ Coxb115c352015-03-18 17:26:36 -0400582 gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
Russ Cox8afb3962015-03-04 22:58:27 -0500583 gins(x86.AMOVL, &lo1, &rr)
584 gins(x86.ACMPL, &rr, &lo2)
Russ Coxb115c352015-03-18 17:26:36 -0400585 gc.Regfree(&rr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500586 }
587
588 // jump again
589 gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
590
591 // point first branch down here if appropriate
592 if br != nil {
593 gc.Patch(br, gc.Pc)
594 }
595
596 splitclean()
597 splitclean()
598}