Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1 | // 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 Cox | 17eba6e | 2015-05-21 13:28:10 -0400 | [diff] [blame] | 31 | package x86 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 32 | |
| 33 | import ( |
Russ Cox | 17eba6e | 2015-05-21 13:28:10 -0400 | [diff] [blame] | 34 | "cmd/compile/internal/gc" |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 35 | "cmd/internal/obj" |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 36 | "cmd/internal/obj/x86" |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 37 | "fmt" |
| 38 | ) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 39 | |
| 40 | const ( |
| 41 | REGEXT = 0 |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 42 | exregoffset = x86.REG_DI |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 43 | ) |
| 44 | |
| 45 | var gactive uint32 |
| 46 | |
| 47 | // do we need the carry bit |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 48 | func needc(p *obj.Prog) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 49 | for p != nil { |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 50 | if p.Info.Flags&gc.UseCarry != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 51 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 52 | } |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 53 | if p.Info.Flags&(gc.SetCarry|gc.KillCarry) != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 54 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 55 | } |
| 56 | p = p.Link |
| 57 | } |
| 58 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 59 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | func rnops(r *gc.Flow) *gc.Flow { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 63 | if r != nil { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 64 | var p *obj.Prog |
| 65 | var r1 *gc.Flow |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 66 | 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 | |
| 82 | func peep(firstp *obj.Prog) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 83 | g := gc.Flowstart(firstp, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 84 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 96 | var p *obj.Prog |
| 97 | for r := g.Start; r != nil; r = r.Link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 98 | p = r.Prog |
| 99 | switch p.As { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 100 | case x86.ALEAL: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 101 | if regtyp(&p.To) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 102 | if p.From.Sym != nil { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 103 | if p.From.Index == x86.REG_NONE { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 104 | conprop(r) |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 109 | case x86.AMOVB, |
| 110 | x86.AMOVW, |
| 111 | x86.AMOVL, |
| 112 | x86.AMOVSS, |
| 113 | x86.AMOVSD: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 114 | if regtyp(&p.To) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 115 | if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST { |
| 116 | conprop(r) |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 122 | var r1 *gc.Flow |
| 123 | var p1 *obj.Prog |
| 124 | var r *gc.Flow |
| 125 | var t int |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 126 | loop1: |
| 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 Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 135 | case x86.AMOVL, |
| 136 | x86.AMOVSS, |
| 137 | x86.AMOVSD: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 138 | if regtyp(&p.To) { |
| 139 | if regtyp(&p.From) { |
| 140 | if copyprop(g, r) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 141 | excise(r) |
| 142 | t++ |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 143 | } else if subprop(r) && copyprop(g, r) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 144 | excise(r) |
| 145 | t++ |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 150 | case x86.AMOVBLZX, |
| 151 | x86.AMOVWLZX, |
| 152 | x86.AMOVBLSX, |
| 153 | x86.AMOVWLSX: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 154 | if regtyp(&p.To) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 155 | 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 Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 159 | p1.As = x86.AMOVL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 160 | t++ |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 165 | case x86.AADDL, |
| 166 | x86.AADDW: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 167 | if p.From.Type != obj.TYPE_CONST || needc(p.Link) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 168 | break |
| 169 | } |
| 170 | if p.From.Offset == -1 { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 171 | if p.As == x86.AADDL { |
| 172 | p.As = x86.ADECL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 173 | } else { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 174 | p.As = x86.ADECW |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 175 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 176 | p.From = obj.Addr{} |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 177 | break |
| 178 | } |
| 179 | |
| 180 | if p.From.Offset == 1 { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 181 | if p.As == x86.AADDL { |
| 182 | p.As = x86.AINCL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 183 | } else { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 184 | p.As = x86.AINCW |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 185 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 186 | p.From = obj.Addr{} |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 187 | break |
| 188 | } |
| 189 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 190 | case x86.ASUBL, |
| 191 | x86.ASUBW: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 192 | if p.From.Type != obj.TYPE_CONST || needc(p.Link) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 193 | break |
| 194 | } |
| 195 | if p.From.Offset == -1 { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 196 | if p.As == x86.ASUBL { |
| 197 | p.As = x86.AINCL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 198 | } else { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 199 | p.As = x86.AINCW |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 200 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 201 | p.From = obj.Addr{} |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 202 | break |
| 203 | } |
| 204 | |
| 205 | if p.From.Offset == 1 { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 206 | if p.As == x86.ASUBL { |
| 207 | p.As = x86.ADECL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 208 | } else { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 209 | p.As = x86.ADECW |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 210 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 211 | p.From = obj.Addr{} |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 212 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 226 | for r := g.Start; r != nil; r = r.Link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 227 | p = r.Prog |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 228 | if p.As == x86.AMOVSD { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 229 | if regtyp(&p.From) { |
| 230 | if regtyp(&p.To) { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 231 | p.As = x86.AMOVAPD |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 232 | } |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | gc.Flowend(g) |
| 238 | } |
| 239 | |
| 240 | func excise(r *gc.Flow) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 241 | p := r.Prog |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 242 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 251 | func regtyp(a *obj.Addr) bool { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 252 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 253 | } |
| 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. |
| 262 | func elimshortmov(g *gc.Graph) { |
| 263 | var p *obj.Prog |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 264 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 265 | for r := g.Start; r != nil; r = r.Link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 266 | p = r.Prog |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 267 | if regtyp(&p.To) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 268 | switch p.As { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 269 | case x86.AINCB, |
| 270 | x86.AINCW: |
| 271 | p.As = x86.AINCL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 272 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 273 | case x86.ADECB, |
| 274 | x86.ADECW: |
| 275 | p.As = x86.ADECL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 276 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 277 | case x86.ANEGB, |
| 278 | x86.ANEGW: |
| 279 | p.As = x86.ANEGL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 280 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 281 | case x86.ANOTB, |
| 282 | x86.ANOTW: |
| 283 | p.As = x86.ANOTL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 284 | } |
| 285 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 286 | if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 287 | // 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 Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 292 | case x86.AMOVB, |
| 293 | x86.AMOVW: |
| 294 | p.As = x86.AMOVL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 295 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 296 | case x86.AADDB, |
| 297 | x86.AADDW: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 298 | if !needc(p.Link) { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 299 | p.As = x86.AADDL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 300 | } |
| 301 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 302 | case x86.ASUBB, |
| 303 | x86.ASUBW: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 304 | if !needc(p.Link) { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 305 | p.As = x86.ASUBL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 306 | } |
| 307 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 308 | case x86.AMULB, |
| 309 | x86.AMULW: |
| 310 | p.As = x86.AMULL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 311 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 312 | case x86.AIMULB, |
| 313 | x86.AIMULW: |
| 314 | p.As = x86.AIMULL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 315 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 316 | case x86.AANDB, |
| 317 | x86.AANDW: |
| 318 | p.As = x86.AANDL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 319 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 320 | case x86.AORB, |
| 321 | x86.AORW: |
| 322 | p.As = x86.AORL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 323 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 324 | case x86.AXORB, |
| 325 | x86.AXORW: |
| 326 | p.As = x86.AXORL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 327 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 328 | case x86.ASHLB, |
| 329 | x86.ASHLW: |
| 330 | p.As = x86.ASHLL |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 331 | } |
| 332 | } else { |
| 333 | // explicit zero extension |
| 334 | switch p.As { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 335 | case x86.AMOVB: |
| 336 | p.As = x86.AMOVBLZX |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 337 | |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 338 | case x86.AMOVW: |
| 339 | p.As = x86.AMOVWLZX |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 340 | } |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 360 | func subprop(r0 *gc.Flow) bool { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 361 | p := r0.Prog |
| 362 | v1 := &p.From |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 363 | if !regtyp(v1) { |
| 364 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 365 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 366 | v2 := &p.To |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 367 | if !regtyp(v2) { |
| 368 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 369 | } |
Russ Cox | 79f727a | 2015-03-02 12:35:15 -0500 | [diff] [blame] | 370 | for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 371 | 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 Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 381 | if p.Info.Flags&gc.Call != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 382 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 383 | } |
| 384 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 385 | if p.Info.Reguse|p.Info.Regset != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 386 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 387 | } |
| 388 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 389 | 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 Cox | 79f727a | 2015-03-02 12:35:15 -0500 | [diff] [blame] | 390 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 415 | } |
| 416 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 417 | if copyau(&p.From, v2) || copyau(&p.To, v2) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 418 | break |
| 419 | } |
| 420 | if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { |
| 421 | break |
| 422 | } |
| 423 | } |
| 424 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 425 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 426 | } |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 440 | func copyprop(g *gc.Graph, r0 *gc.Flow) bool { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 441 | p := r0.Prog |
| 442 | v1 := &p.From |
| 443 | v2 := &p.To |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 444 | if copyas(v1, v2) { |
| 445 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 446 | } |
| 447 | gactive++ |
| 448 | return copy1(v1, v2, r0.S1, 0) |
| 449 | } |
| 450 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 451 | func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 452 | if uint32(r.Active) == gactive { |
| 453 | if gc.Debug['P'] != 0 { |
| 454 | fmt.Printf("act set; return 1\n") |
| 455 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 456 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 457 | } |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 463 | var t int |
| 464 | var p *obj.Prog |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 465 | for ; r != nil; r = r.S1 { |
| 466 | p = r.Prog |
| 467 | if gc.Debug['P'] != 0 { |
| 468 | fmt.Printf("%v", p) |
| 469 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 470 | if f == 0 && gc.Uniqp(r) == nil { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 471 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 483 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 484 | |
| 485 | case 3: /* set */ |
| 486 | if gc.Debug['P'] != 0 { |
| 487 | fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) |
| 488 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 489 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 490 | |
| 491 | case 1, /* used, substitute */ |
| 492 | 4: /* use and set */ |
| 493 | if f != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 494 | if gc.Debug['P'] == 0 { |
| 495 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 496 | } |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 502 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 503 | } |
| 504 | |
| 505 | if copyu(p, v2, v1) != 0 { |
| 506 | if gc.Debug['P'] != 0 { |
| 507 | fmt.Printf("; sub fail; return 0\n") |
| 508 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 509 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 510 | } |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 519 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 520 | } |
| 521 | } |
| 522 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 523 | if f == 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 524 | t = copyu(p, v1, nil) |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 525 | if f == 0 && (t == 2 || t == 3 || t == 4) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 526 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 537 | if !copy1(v1, v2, r.S2, f) { |
| 538 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 539 | } |
| 540 | } |
| 541 | } |
| 542 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 543 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 544 | } |
| 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 | */ |
| 554 | func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 555 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 564 | if copyau(&p.To, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 565 | 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 Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 579 | if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 580 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 593 | if copyau(&p.To, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 594 | return 4 |
| 595 | } |
| 596 | return 3 |
| 597 | |
| 598 | case obj.ATEXT: |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 599 | if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 600 | return 3 |
| 601 | } |
| 602 | return 0 |
| 603 | } |
| 604 | |
| 605 | if p.As == obj.AVARDEF || p.As == obj.AVARKILL { |
| 606 | return 0 |
| 607 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 608 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 609 | if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 610 | return 2 |
| 611 | } |
| 612 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 613 | if p.Info.Flags&gc.LeftAddr != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 614 | if copyas(&p.From, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 615 | return 2 |
| 616 | } |
| 617 | } |
| 618 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 619 | if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 620 | if copyas(&p.To, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 621 | return 2 |
| 622 | } |
| 623 | } |
| 624 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 625 | if p.Info.Flags&gc.RightWrite != 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 626 | if copyas(&p.To, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 627 | if s != nil { |
| 628 | return copysub(&p.From, v, s, 1) |
| 629 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 630 | if copyau(&p.From, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 631 | return 4 |
| 632 | } |
| 633 | return 3 |
| 634 | } |
| 635 | } |
| 636 | |
Russ Cox | fd38dbc | 2015-03-16 16:46:25 -0400 | [diff] [blame] | 637 | if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 638 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 645 | if copyau(&p.From, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 646 | return 1 |
| 647 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 648 | if copyau(&p.To, v) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 649 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 661 | func copyas(a *obj.Addr, v *obj.Addr) bool { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 662 | if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_BL { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 663 | gc.Fatalf("use of byte register") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 664 | } |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 665 | if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_BL { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 666 | gc.Fatalf("use of byte register") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 667 | } |
| 668 | |
| 669 | if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 670 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 671 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 672 | if regtyp(v) { |
| 673 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 674 | } |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 675 | if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 676 | if v.Offset == a.Offset { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 677 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 678 | } |
| 679 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 680 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 681 | } |
| 682 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 683 | func sameaddr(a *obj.Addr, v *obj.Addr) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 684 | if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 685 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 686 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 687 | if regtyp(v) { |
| 688 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 689 | } |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 690 | if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 691 | if v.Offset == a.Offset { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 692 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 693 | } |
| 694 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 695 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 696 | } |
| 697 | |
| 698 | /* |
| 699 | * either direct or indirect |
| 700 | */ |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 701 | func copyau(a *obj.Addr, v *obj.Addr) bool { |
| 702 | if copyas(a, v) { |
| 703 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 704 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 705 | if regtyp(v) { |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 706 | if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 707 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 708 | } |
| 709 | if a.Index == v.Reg { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 710 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 711 | } |
| 712 | } |
| 713 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 714 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 715 | } |
| 716 | |
| 717 | /* |
| 718 | * substitute s for v in a |
| 719 | * return failure to substitute |
| 720 | */ |
| 721 | func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 722 | if copyas(a, v) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 723 | reg := int(s.Reg) |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 724 | if reg >= x86.REG_AX && reg <= x86.REG_DI || reg >= x86.REG_X0 && reg <= x86.REG_X7 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 725 | if f != 0 { |
| 726 | a.Reg = int16(reg) |
| 727 | } |
| 728 | } |
| 729 | |
| 730 | return 0 |
| 731 | } |
| 732 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 733 | if regtyp(v) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 734 | reg := int(v.Reg) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 735 | if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && int(a.Reg) == reg { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 736 | if (s.Reg == x86.REG_BP) && a.Index != obj.TYPE_NONE { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 737 | 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 | |
| 758 | func conprop(r0 *gc.Flow) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 759 | var p *obj.Prog |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 760 | var t int |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 761 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 762 | p0 := r0.Prog |
| 763 | v0 := &p0.To |
| 764 | r := r0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 765 | |
| 766 | loop: |
| 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 Cox | 532ccae | 2015-03-16 15:54:44 -0400 | [diff] [blame] | 793 | if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 794 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 808 | func smallindir(a *obj.Addr, reg *obj.Addr) bool { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 809 | return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 810 | } |
| 811 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 812 | func stackaddr(a *obj.Addr) bool { |
Russ Cox | 8afb396 | 2015-03-04 22:58:27 -0500 | [diff] [blame] | 813 | return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 814 | } |