blob: 63e64cb77c057f9dd40b9cbe1e82514132336e0f [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// Derived from Inferno utils/6c/peep.c
2// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
3//
4// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6// Portions Copyright © 1997-1999 Vita Nuova Limited
7// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8// Portions Copyright © 2004,2006 Bruce Ellis
9// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11// Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
Russ Cox17eba6e2015-05-21 13:28:10 -040031package x86
Russ Cox8c195bd2015-02-13 14:40:36 -050032
33import (
Russ Cox17eba6e2015-05-21 13:28:10 -040034 "cmd/compile/internal/gc"
Russ Cox8c195bd2015-02-13 14:40:36 -050035 "cmd/internal/obj"
Russ Cox8afb3962015-03-04 22:58:27 -050036 "cmd/internal/obj/x86"
Russ Cox8c195bd2015-02-13 14:40:36 -050037 "fmt"
38)
Russ Cox8c195bd2015-02-13 14:40:36 -050039
40const (
41 REGEXT = 0
Russ Cox8afb3962015-03-04 22:58:27 -050042 exregoffset = x86.REG_DI
Russ Cox8c195bd2015-02-13 14:40:36 -050043)
44
45var gactive uint32
46
47// do we need the carry bit
Russ Coxdc7b54b2015-02-17 22:13:49 -050048func needc(p *obj.Prog) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -050049 for p != nil {
Russ Coxfd38dbc2015-03-16 16:46:25 -040050 if p.Info.Flags&gc.UseCarry != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -050051 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050052 }
Russ Coxfd38dbc2015-03-16 16:46:25 -040053 if p.Info.Flags&(gc.SetCarry|gc.KillCarry) != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -050054 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050055 }
56 p = p.Link
57 }
58
Russ Coxdc7b54b2015-02-17 22:13:49 -050059 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050060}
61
62func rnops(r *gc.Flow) *gc.Flow {
Russ Cox8c195bd2015-02-13 14:40:36 -050063 if r != nil {
Russ Cox382b44e2015-02-23 16:07:24 -050064 var p *obj.Prog
65 var r1 *gc.Flow
Russ Cox8c195bd2015-02-13 14:40:36 -050066 for {
67 p = r.Prog
68 if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
69 break
70 }
71 r1 = gc.Uniqs(r)
72 if r1 == nil {
73 break
74 }
75 r = r1
76 }
77 }
78
79 return r
80}
81
82func peep(firstp *obj.Prog) {
Russ Cox382b44e2015-02-23 16:07:24 -050083 g := gc.Flowstart(firstp, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -050084 if g == nil {
85 return
86 }
87 gactive = 0
88
89 // byte, word arithmetic elimination.
90 elimshortmov(g)
91
92 // constant propagation
93 // find MOV $con,R followed by
94 // another MOV $con,R without
95 // setting R in the interim
Russ Cox382b44e2015-02-23 16:07:24 -050096 var p *obj.Prog
97 for r := g.Start; r != nil; r = r.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -050098 p = r.Prog
99 switch p.As {
Russ Cox8afb3962015-03-04 22:58:27 -0500100 case x86.ALEAL:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500101 if regtyp(&p.To) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500102 if p.From.Sym != nil {
Russ Cox8afb3962015-03-04 22:58:27 -0500103 if p.From.Index == x86.REG_NONE {
Russ Cox8c195bd2015-02-13 14:40:36 -0500104 conprop(r)
105 }
106 }
107 }
108
Russ Cox8afb3962015-03-04 22:58:27 -0500109 case x86.AMOVB,
110 x86.AMOVW,
111 x86.AMOVL,
112 x86.AMOVSS,
113 x86.AMOVSD:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500114 if regtyp(&p.To) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500115 if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
116 conprop(r)
117 }
118 }
119 }
120 }
121
Russ Cox382b44e2015-02-23 16:07:24 -0500122 var r1 *gc.Flow
123 var p1 *obj.Prog
124 var r *gc.Flow
125 var t int
Russ Cox8c195bd2015-02-13 14:40:36 -0500126loop1:
127 if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
128 gc.Dumpit("loop1", g.Start, 0)
129 }
130
131 t = 0
132 for r = g.Start; r != nil; r = r.Link {
133 p = r.Prog
134 switch p.As {
Russ Cox8afb3962015-03-04 22:58:27 -0500135 case x86.AMOVL,
136 x86.AMOVSS,
137 x86.AMOVSD:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500138 if regtyp(&p.To) {
139 if regtyp(&p.From) {
140 if copyprop(g, r) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500141 excise(r)
142 t++
Russ Coxdc7b54b2015-02-17 22:13:49 -0500143 } else if subprop(r) && copyprop(g, r) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500144 excise(r)
145 t++
146 }
147 }
148 }
149
Russ Cox8afb3962015-03-04 22:58:27 -0500150 case x86.AMOVBLZX,
151 x86.AMOVWLZX,
152 x86.AMOVBLSX,
153 x86.AMOVWLSX:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500154 if regtyp(&p.To) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500155 r1 = rnops(gc.Uniqs(r))
156 if r1 != nil {
157 p1 = r1.Prog
158 if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
Russ Cox8afb3962015-03-04 22:58:27 -0500159 p1.As = x86.AMOVL
Russ Cox8c195bd2015-02-13 14:40:36 -0500160 t++
161 }
162 }
163 }
164
Russ Cox8afb3962015-03-04 22:58:27 -0500165 case x86.AADDL,
166 x86.AADDW:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500167 if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500168 break
169 }
170 if p.From.Offset == -1 {
Russ Cox8afb3962015-03-04 22:58:27 -0500171 if p.As == x86.AADDL {
172 p.As = x86.ADECL
Russ Cox8c195bd2015-02-13 14:40:36 -0500173 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500174 p.As = x86.ADECW
Russ Cox8c195bd2015-02-13 14:40:36 -0500175 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500176 p.From = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500177 break
178 }
179
180 if p.From.Offset == 1 {
Russ Cox8afb3962015-03-04 22:58:27 -0500181 if p.As == x86.AADDL {
182 p.As = x86.AINCL
Russ Cox8c195bd2015-02-13 14:40:36 -0500183 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500184 p.As = x86.AINCW
Russ Cox8c195bd2015-02-13 14:40:36 -0500185 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500186 p.From = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500187 break
188 }
189
Russ Cox8afb3962015-03-04 22:58:27 -0500190 case x86.ASUBL,
191 x86.ASUBW:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500192 if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500193 break
194 }
195 if p.From.Offset == -1 {
Russ Cox8afb3962015-03-04 22:58:27 -0500196 if p.As == x86.ASUBL {
197 p.As = x86.AINCL
Russ Cox8c195bd2015-02-13 14:40:36 -0500198 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500199 p.As = x86.AINCW
Russ Cox8c195bd2015-02-13 14:40:36 -0500200 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500201 p.From = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500202 break
203 }
204
205 if p.From.Offset == 1 {
Russ Cox8afb3962015-03-04 22:58:27 -0500206 if p.As == x86.ASUBL {
207 p.As = x86.ADECL
Russ Cox8c195bd2015-02-13 14:40:36 -0500208 } else {
Russ Cox8afb3962015-03-04 22:58:27 -0500209 p.As = x86.ADECW
Russ Cox8c195bd2015-02-13 14:40:36 -0500210 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500211 p.From = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500212 break
213 }
214 }
215 }
216
217 if t != 0 {
218 goto loop1
219 }
220
221 // MOVSD removal.
222 // We never use packed registers, so a MOVSD between registers
223 // can be replaced by MOVAPD, which moves the pair of float64s
224 // instead of just the lower one. We only use the lower one, but
225 // the processor can do better if we do moves using both.
Russ Cox382b44e2015-02-23 16:07:24 -0500226 for r := g.Start; r != nil; r = r.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500227 p = r.Prog
Russ Cox8afb3962015-03-04 22:58:27 -0500228 if p.As == x86.AMOVSD {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500229 if regtyp(&p.From) {
230 if regtyp(&p.To) {
Russ Cox8afb3962015-03-04 22:58:27 -0500231 p.As = x86.AMOVAPD
Russ Cox8c195bd2015-02-13 14:40:36 -0500232 }
233 }
234 }
235 }
236
237 gc.Flowend(g)
238}
239
240func excise(r *gc.Flow) {
Russ Cox382b44e2015-02-23 16:07:24 -0500241 p := r.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500242 if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
243 fmt.Printf("%v ===delete===\n", p)
244 }
245
246 obj.Nopout(p)
247
248 gc.Ostats.Ndelmov++
249}
250
Russ Coxdc7b54b2015-02-17 22:13:49 -0500251func regtyp(a *obj.Addr) bool {
Russ Cox8afb3962015-03-04 22:58:27 -0500252 return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_DI || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X7)
Russ Cox8c195bd2015-02-13 14:40:36 -0500253}
254
255// movb elimination.
256// movb is simulated by the linker
257// when a register other than ax, bx, cx, dx
258// is used, so rewrite to other instructions
259// when possible. a movb into a register
260// can smash the entire 64-bit register without
261// causing any trouble.
262func elimshortmov(g *gc.Graph) {
263 var p *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500264
Russ Cox382b44e2015-02-23 16:07:24 -0500265 for r := g.Start; r != nil; r = r.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500266 p = r.Prog
Russ Coxdc7b54b2015-02-17 22:13:49 -0500267 if regtyp(&p.To) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500268 switch p.As {
Russ Cox8afb3962015-03-04 22:58:27 -0500269 case x86.AINCB,
270 x86.AINCW:
271 p.As = x86.AINCL
Russ Cox8c195bd2015-02-13 14:40:36 -0500272
Russ Cox8afb3962015-03-04 22:58:27 -0500273 case x86.ADECB,
274 x86.ADECW:
275 p.As = x86.ADECL
Russ Cox8c195bd2015-02-13 14:40:36 -0500276
Russ Cox8afb3962015-03-04 22:58:27 -0500277 case x86.ANEGB,
278 x86.ANEGW:
279 p.As = x86.ANEGL
Russ Cox8c195bd2015-02-13 14:40:36 -0500280
Russ Cox8afb3962015-03-04 22:58:27 -0500281 case x86.ANOTB,
282 x86.ANOTW:
283 p.As = x86.ANOTL
Russ Cox8c195bd2015-02-13 14:40:36 -0500284 }
285
Russ Coxdc7b54b2015-02-17 22:13:49 -0500286 if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
Russ Cox8c195bd2015-02-13 14:40:36 -0500287 // move or artihmetic into partial register.
288 // from another register or constant can be movl.
289 // we don't switch to 32-bit arithmetic if it can
290 // change how the carry bit is set (and the carry bit is needed).
291 switch p.As {
Russ Cox8afb3962015-03-04 22:58:27 -0500292 case x86.AMOVB,
293 x86.AMOVW:
294 p.As = x86.AMOVL
Russ Cox8c195bd2015-02-13 14:40:36 -0500295
Russ Cox8afb3962015-03-04 22:58:27 -0500296 case x86.AADDB,
297 x86.AADDW:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500298 if !needc(p.Link) {
Russ Cox8afb3962015-03-04 22:58:27 -0500299 p.As = x86.AADDL
Russ Cox8c195bd2015-02-13 14:40:36 -0500300 }
301
Russ Cox8afb3962015-03-04 22:58:27 -0500302 case x86.ASUBB,
303 x86.ASUBW:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500304 if !needc(p.Link) {
Russ Cox8afb3962015-03-04 22:58:27 -0500305 p.As = x86.ASUBL
Russ Cox8c195bd2015-02-13 14:40:36 -0500306 }
307
Russ Cox8afb3962015-03-04 22:58:27 -0500308 case x86.AMULB,
309 x86.AMULW:
310 p.As = x86.AMULL
Russ Cox8c195bd2015-02-13 14:40:36 -0500311
Russ Cox8afb3962015-03-04 22:58:27 -0500312 case x86.AIMULB,
313 x86.AIMULW:
314 p.As = x86.AIMULL
Russ Cox8c195bd2015-02-13 14:40:36 -0500315
Russ Cox8afb3962015-03-04 22:58:27 -0500316 case x86.AANDB,
317 x86.AANDW:
318 p.As = x86.AANDL
Russ Cox8c195bd2015-02-13 14:40:36 -0500319
Russ Cox8afb3962015-03-04 22:58:27 -0500320 case x86.AORB,
321 x86.AORW:
322 p.As = x86.AORL
Russ Cox8c195bd2015-02-13 14:40:36 -0500323
Russ Cox8afb3962015-03-04 22:58:27 -0500324 case x86.AXORB,
325 x86.AXORW:
326 p.As = x86.AXORL
Russ Cox8c195bd2015-02-13 14:40:36 -0500327
Russ Cox8afb3962015-03-04 22:58:27 -0500328 case x86.ASHLB,
329 x86.ASHLW:
330 p.As = x86.ASHLL
Russ Cox8c195bd2015-02-13 14:40:36 -0500331 }
332 } else {
333 // explicit zero extension
334 switch p.As {
Russ Cox8afb3962015-03-04 22:58:27 -0500335 case x86.AMOVB:
336 p.As = x86.AMOVBLZX
Russ Cox8c195bd2015-02-13 14:40:36 -0500337
Russ Cox8afb3962015-03-04 22:58:27 -0500338 case x86.AMOVW:
339 p.As = x86.AMOVWLZX
Russ Cox8c195bd2015-02-13 14:40:36 -0500340 }
341 }
342 }
343 }
344}
345
346/*
347 * the idea is to substitute
348 * one register for another
349 * from one MOV to another
350 * MOV a, R0
351 * ADD b, R0 / no use of R1
352 * MOV R0, R1
353 * would be converted to
354 * MOV a, R1
355 * ADD b, R1
356 * MOV R1, R0
357 * hopefully, then the former or latter MOV
358 * will be eliminated by copy propagation.
359 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500360func subprop(r0 *gc.Flow) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500361 p := r0.Prog
362 v1 := &p.From
Russ Coxdc7b54b2015-02-17 22:13:49 -0500363 if !regtyp(v1) {
364 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500365 }
Russ Cox382b44e2015-02-23 16:07:24 -0500366 v2 := &p.To
Russ Coxdc7b54b2015-02-17 22:13:49 -0500367 if !regtyp(v2) {
368 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500369 }
Russ Cox79f727a2015-03-02 12:35:15 -0500370 for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500371 if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
372 fmt.Printf("\t? %v\n", r.Prog)
373 }
374 if gc.Uniqs(r) == nil {
375 break
376 }
377 p = r.Prog
378 if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
379 continue
380 }
Russ Coxfd38dbc2015-03-16 16:46:25 -0400381 if p.Info.Flags&gc.Call != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500382 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500383 }
384
Russ Coxfd38dbc2015-03-16 16:46:25 -0400385 if p.Info.Reguse|p.Info.Regset != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500386 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500387 }
388
Russ Coxfd38dbc2015-03-16 16:46:25 -0400389 if (p.Info.Flags&gc.Move != 0) && (p.Info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
Russ Cox79f727a2015-03-02 12:35:15 -0500390 copysub(&p.To, v1, v2, 1)
391 if gc.Debug['P'] != 0 {
392 fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
393 if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
394 fmt.Printf(" excise")
395 }
396 fmt.Printf("\n")
397 }
398
399 for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
400 p = r.Prog
401 copysub(&p.From, v1, v2, 1)
402 copysub(&p.To, v1, v2, 1)
403 if gc.Debug['P'] != 0 {
404 fmt.Printf("%v\n", r.Prog)
405 }
406 }
407
408 t := int(v1.Reg)
409 v1.Reg = v2.Reg
410 v2.Reg = int16(t)
411 if gc.Debug['P'] != 0 {
412 fmt.Printf("%v last\n", r.Prog)
413 }
414 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500415 }
416
Russ Coxdc7b54b2015-02-17 22:13:49 -0500417 if copyau(&p.From, v2) || copyau(&p.To, v2) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500418 break
419 }
420 if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
421 break
422 }
423 }
424
Russ Coxdc7b54b2015-02-17 22:13:49 -0500425 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500426}
427
428/*
429 * The idea is to remove redundant copies.
430 * v1->v2 F=0
431 * (use v2 s/v2/v1/)*
432 * set v1 F=1
433 * use v2 return fail
434 * -----------------
435 * v1->v2 F=0
436 * (use v2 s/v2/v1/)*
437 * set v1 F=1
438 * set v2 return success
439 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500440func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500441 p := r0.Prog
442 v1 := &p.From
443 v2 := &p.To
Russ Coxdc7b54b2015-02-17 22:13:49 -0500444 if copyas(v1, v2) {
445 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500446 }
447 gactive++
448 return copy1(v1, v2, r0.S1, 0)
449}
450
Russ Coxdc7b54b2015-02-17 22:13:49 -0500451func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500452 if uint32(r.Active) == gactive {
453 if gc.Debug['P'] != 0 {
454 fmt.Printf("act set; return 1\n")
455 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500456 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500457 }
458
459 r.Active = int32(gactive)
460 if gc.Debug['P'] != 0 {
461 fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
462 }
Russ Cox382b44e2015-02-23 16:07:24 -0500463 var t int
464 var p *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500465 for ; r != nil; r = r.S1 {
466 p = r.Prog
467 if gc.Debug['P'] != 0 {
468 fmt.Printf("%v", p)
469 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500470 if f == 0 && gc.Uniqp(r) == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500471 f = 1
472 if gc.Debug['P'] != 0 {
473 fmt.Printf("; merge; f=%d", f)
474 }
475 }
476
477 t = copyu(p, v2, nil)
478 switch t {
479 case 2: /* rar, can't split */
480 if gc.Debug['P'] != 0 {
481 fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
482 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500483 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500484
485 case 3: /* set */
486 if gc.Debug['P'] != 0 {
487 fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
488 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500489 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500490
491 case 1, /* used, substitute */
492 4: /* use and set */
493 if f != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500494 if gc.Debug['P'] == 0 {
495 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500496 }
497 if t == 4 {
498 fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
499 } else {
500 fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
501 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500502 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500503 }
504
505 if copyu(p, v2, v1) != 0 {
506 if gc.Debug['P'] != 0 {
507 fmt.Printf("; sub fail; return 0\n")
508 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500509 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500510 }
511
512 if gc.Debug['P'] != 0 {
513 fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
514 }
515 if t == 4 {
516 if gc.Debug['P'] != 0 {
517 fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
518 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500519 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500520 }
521 }
522
Russ Coxdc7b54b2015-02-17 22:13:49 -0500523 if f == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500524 t = copyu(p, v1, nil)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500525 if f == 0 && (t == 2 || t == 3 || t == 4) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500526 f = 1
527 if gc.Debug['P'] != 0 {
528 fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
529 }
530 }
531 }
532
533 if gc.Debug['P'] != 0 {
534 fmt.Printf("\n")
535 }
536 if r.S2 != nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500537 if !copy1(v1, v2, r.S2, f) {
538 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500539 }
540 }
541 }
542
Russ Coxdc7b54b2015-02-17 22:13:49 -0500543 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500544}
545
546/*
547 * return
548 * 1 if v only used (and substitute),
549 * 2 if read-alter-rewrite
550 * 3 if set
551 * 4 if set and used
552 * 0 otherwise (not touched)
553 */
554func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
Russ Cox8c195bd2015-02-13 14:40:36 -0500555 switch p.As {
556 case obj.AJMP:
557 if s != nil {
558 if copysub(&p.To, v, s, 1) != 0 {
559 return 1
560 }
561 return 0
562 }
563
Russ Coxdc7b54b2015-02-17 22:13:49 -0500564 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500565 return 1
566 }
567 return 0
568
569 case obj.ARET:
570 if s != nil {
571 return 1
572 }
573 return 3
574
575 case obj.ACALL:
576 if REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= REGEXT && v.Reg > exregoffset {
577 return 2
578 }
Russ Cox8afb3962015-03-04 22:58:27 -0500579 if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
Russ Cox8c195bd2015-02-13 14:40:36 -0500580 return 2
581 }
582 if v.Type == p.From.Type && v.Reg == p.From.Reg {
583 return 2
584 }
585
586 if s != nil {
587 if copysub(&p.To, v, s, 1) != 0 {
588 return 1
589 }
590 return 0
591 }
592
Russ Coxdc7b54b2015-02-17 22:13:49 -0500593 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500594 return 4
595 }
596 return 3
597
598 case obj.ATEXT:
Russ Cox8afb3962015-03-04 22:58:27 -0500599 if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
Russ Cox8c195bd2015-02-13 14:40:36 -0500600 return 3
601 }
602 return 0
603 }
604
605 if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
606 return 0
607 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500608
Russ Coxfd38dbc2015-03-16 16:46:25 -0400609 if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500610 return 2
611 }
612
Russ Coxfd38dbc2015-03-16 16:46:25 -0400613 if p.Info.Flags&gc.LeftAddr != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500614 if copyas(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500615 return 2
616 }
617 }
618
Russ Coxfd38dbc2015-03-16 16:46:25 -0400619 if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500620 if copyas(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500621 return 2
622 }
623 }
624
Russ Coxfd38dbc2015-03-16 16:46:25 -0400625 if p.Info.Flags&gc.RightWrite != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500626 if copyas(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500627 if s != nil {
628 return copysub(&p.From, v, s, 1)
629 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500630 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500631 return 4
632 }
633 return 3
634 }
635 }
636
Russ Coxfd38dbc2015-03-16 16:46:25 -0400637 if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500638 if s != nil {
639 if copysub(&p.From, v, s, 1) != 0 {
640 return 1
641 }
642 return copysub(&p.To, v, s, 1)
643 }
644
Russ Coxdc7b54b2015-02-17 22:13:49 -0500645 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500646 return 1
647 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500648 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500649 return 1
650 }
651 }
652
653 return 0
654}
655
656/*
657 * direct reference,
658 * could be set/use depending on
659 * semantics
660 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500661func copyas(a *obj.Addr, v *obj.Addr) bool {
Russ Cox8afb3962015-03-04 22:58:27 -0500662 if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_BL {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200663 gc.Fatalf("use of byte register")
Russ Cox8c195bd2015-02-13 14:40:36 -0500664 }
Russ Cox8afb3962015-03-04 22:58:27 -0500665 if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_BL {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200666 gc.Fatalf("use of byte register")
Russ Cox8c195bd2015-02-13 14:40:36 -0500667 }
668
669 if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500670 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500671 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500672 if regtyp(v) {
673 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500674 }
Russ Coxb115c352015-03-18 17:26:36 -0400675 if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500676 if v.Offset == a.Offset {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500677 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500678 }
679 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500680 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500681}
682
Russ Coxdc7b54b2015-02-17 22:13:49 -0500683func sameaddr(a *obj.Addr, v *obj.Addr) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500684 if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500685 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500686 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500687 if regtyp(v) {
688 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500689 }
Russ Coxb115c352015-03-18 17:26:36 -0400690 if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500691 if v.Offset == a.Offset {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500692 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500693 }
694 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500695 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500696}
697
698/*
699 * either direct or indirect
700 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500701func copyau(a *obj.Addr, v *obj.Addr) bool {
702 if copyas(a, v) {
703 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500704 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500705 if regtyp(v) {
Russ Coxb115c352015-03-18 17:26:36 -0400706 if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500707 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500708 }
709 if a.Index == v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500710 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500711 }
712 }
713
Russ Coxdc7b54b2015-02-17 22:13:49 -0500714 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500715}
716
717/*
718 * substitute s for v in a
719 * return failure to substitute
720 */
721func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500722 if copyas(a, v) {
Russ Cox382b44e2015-02-23 16:07:24 -0500723 reg := int(s.Reg)
Russ Cox8afb3962015-03-04 22:58:27 -0500724 if reg >= x86.REG_AX && reg <= x86.REG_DI || reg >= x86.REG_X0 && reg <= x86.REG_X7 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500725 if f != 0 {
726 a.Reg = int16(reg)
727 }
728 }
729
730 return 0
731 }
732
Russ Coxdc7b54b2015-02-17 22:13:49 -0500733 if regtyp(v) {
Russ Cox382b44e2015-02-23 16:07:24 -0500734 reg := int(v.Reg)
Russ Coxb115c352015-03-18 17:26:36 -0400735 if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && int(a.Reg) == reg {
Russ Cox8afb3962015-03-04 22:58:27 -0500736 if (s.Reg == x86.REG_BP) && a.Index != obj.TYPE_NONE {
Russ Cox8c195bd2015-02-13 14:40:36 -0500737 return 1 /* can't use BP-base with index */
738 }
739 if f != 0 {
740 a.Reg = s.Reg
741 }
742 }
743
744 // return 0;
745 if int(a.Index) == reg {
746 if f != 0 {
747 a.Index = s.Reg
748 }
749 return 0
750 }
751
752 return 0
753 }
754
755 return 0
756}
757
758func conprop(r0 *gc.Flow) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500759 var p *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500760 var t int
Russ Cox8c195bd2015-02-13 14:40:36 -0500761
Russ Cox382b44e2015-02-23 16:07:24 -0500762 p0 := r0.Prog
763 v0 := &p0.To
764 r := r0
Russ Cox8c195bd2015-02-13 14:40:36 -0500765
766loop:
767 r = gc.Uniqs(r)
768 if r == nil || r == r0 {
769 return
770 }
771 if gc.Uniqp(r) == nil {
772 return
773 }
774
775 p = r.Prog
776 t = copyu(p, v0, nil)
777 switch t {
778 case 0, // miss
779 1: // use
780 goto loop
781
782 case 2, // rar
783 4: // use and set
784 break
785
786 case 3: // set
787 if p.As == p0.As {
788 if p.From.Type == p0.From.Type {
789 if p.From.Reg == p0.From.Reg {
790 if p.From.Node == p0.From.Node {
791 if p.From.Offset == p0.From.Offset {
792 if p.From.Scale == p0.From.Scale {
Russ Cox532ccae2015-03-16 15:54:44 -0400793 if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500794 if p.From.Index == p0.From.Index {
795 excise(r)
796 goto loop
797 }
798 }
799 }
800 }
801 }
802 }
803 }
804 }
805 }
806}
807
Russ Coxdc7b54b2015-02-17 22:13:49 -0500808func smallindir(a *obj.Addr, reg *obj.Addr) bool {
Russ Cox8afb3962015-03-04 22:58:27 -0500809 return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
Russ Cox8c195bd2015-02-13 14:40:36 -0500810}
811
Russ Coxdc7b54b2015-02-17 22:13:49 -0500812func stackaddr(a *obj.Addr) bool {
Russ Cox8afb3962015-03-04 22:58:27 -0500813 return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
Russ Cox8c195bd2015-02-13 14:40:36 -0500814}