Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1 | // Derived from Inferno utils/6c/txt.c |
| 2 | // http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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 | |
| 31 | package gc |
| 32 | |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 33 | import ( |
| 34 | "cmd/internal/obj" |
| 35 | "fmt" |
| 36 | "runtime" |
| 37 | "strings" |
| 38 | ) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 39 | |
| 40 | var ddumped int |
| 41 | |
| 42 | var dfirst *obj.Prog |
| 43 | |
| 44 | var dpc *obj.Prog |
| 45 | |
| 46 | /* |
| 47 | * Is this node a memory operand? |
| 48 | */ |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 49 | func Ismem(n *Node) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 50 | switch n.Op { |
| 51 | case OITAB, |
| 52 | OSPTR, |
| 53 | OLEN, |
| 54 | OCAP, |
| 55 | OINDREG, |
| 56 | ONAME, |
| 57 | OPARAM, |
| 58 | OCLOSUREVAR: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 59 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 60 | |
| 61 | case OADDR: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 62 | return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 63 | } |
| 64 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 65 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 66 | } |
| 67 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 68 | func Samereg(a *Node, b *Node) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 69 | if a == nil || b == nil { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 70 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 71 | } |
| 72 | if a.Op != OREGISTER { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 73 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 74 | } |
| 75 | if b.Op != OREGISTER { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 76 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 77 | } |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 78 | if a.Reg != b.Reg { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 79 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 80 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 81 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 82 | } |
| 83 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 84 | func Gbranch(as int, t *Type, likely int) *obj.Prog { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 85 | p := Prog(as) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 86 | p.To.Type = obj.TYPE_BRANCH |
Russ Cox | 532ccae | 2015-03-16 15:54:44 -0400 | [diff] [blame] | 87 | p.To.Val = nil |
Aram Hăvărneanu | 02c1a9d | 2015-03-08 14:16:29 +0100 | [diff] [blame] | 88 | if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 89 | p.From.Type = obj.TYPE_CONST |
Michael Hudson-Doyle | ac1cdd1 | 2015-04-22 12:41:14 +1200 | [diff] [blame] | 90 | p.From.Offset = int64(obj.Bool2int(likely > 0)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 91 | } |
| 92 | |
Russ Cox | 351897d | 2015-05-07 10:34:12 -0400 | [diff] [blame] | 93 | if Debug['g'] != 0 { |
| 94 | fmt.Printf("%v\n", p) |
| 95 | } |
| 96 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 97 | return p |
| 98 | } |
| 99 | |
| 100 | func Prog(as int) *obj.Prog { |
| 101 | var p *obj.Prog |
| 102 | |
| 103 | if as == obj.ADATA || as == obj.AGLOBL { |
| 104 | if ddumped != 0 { |
| 105 | Fatal("already dumped data") |
| 106 | } |
| 107 | if dpc == nil { |
| 108 | dpc = Ctxt.NewProg() |
| 109 | dfirst = dpc |
| 110 | } |
| 111 | |
| 112 | p = dpc |
| 113 | dpc = Ctxt.NewProg() |
| 114 | p.Link = dpc |
| 115 | } else { |
| 116 | p = Pc |
| 117 | Pc = Ctxt.NewProg() |
| 118 | Clearp(Pc) |
| 119 | p.Link = Pc |
| 120 | } |
| 121 | |
| 122 | if lineno == 0 { |
| 123 | if Debug['K'] != 0 { |
| 124 | Warn("prog: line 0") |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | p.As = int16(as) |
| 129 | p.Lineno = lineno |
| 130 | return p |
| 131 | } |
| 132 | |
| 133 | func Nodreg(n *Node, t *Type, r int) { |
| 134 | if t == nil { |
| 135 | Fatal("nodreg: t nil") |
| 136 | } |
| 137 | |
| 138 | *n = Node{} |
| 139 | n.Op = OREGISTER |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 140 | n.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 141 | ullmancalc(n) |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 142 | n.Reg = int16(r) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 143 | n.Type = t |
| 144 | } |
| 145 | |
| 146 | func Nodindreg(n *Node, t *Type, r int) { |
| 147 | Nodreg(n, t, r) |
| 148 | n.Op = OINDREG |
| 149 | } |
| 150 | |
| 151 | func Afunclit(a *obj.Addr, n *Node) { |
| 152 | if a.Type == obj.TYPE_ADDR && a.Name == obj.NAME_EXTERN { |
| 153 | a.Type = obj.TYPE_MEM |
| 154 | a.Sym = Linksym(n.Sym) |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | func Clearp(p *obj.Prog) { |
| 159 | obj.Nopout(p) |
| 160 | p.As = obj.AEND |
| 161 | p.Pc = int64(pcloc) |
| 162 | pcloc++ |
| 163 | } |
| 164 | |
| 165 | func dumpdata() { |
| 166 | ddumped = 1 |
| 167 | if dfirst == nil { |
| 168 | return |
| 169 | } |
| 170 | newplist() |
| 171 | *Pc = *dfirst |
| 172 | Pc = dpc |
| 173 | Clearp(Pc) |
| 174 | } |
| 175 | |
Russ Cox | cdb7d7d | 2015-03-05 13:57:36 -0500 | [diff] [blame] | 176 | // Fixup instructions after allocauto (formerly compactframe) has moved all autos around. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 177 | func fixautoused(p *obj.Prog) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 178 | for lp := &p; ; { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 179 | p = *lp |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 180 | if p == nil { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 181 | break |
| 182 | } |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 183 | if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !((p.From.Node).(*Node)).Used { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 184 | *lp = p.Link |
| 185 | continue |
| 186 | } |
| 187 | |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 188 | if (p.As == obj.AVARDEF || p.As == obj.AVARKILL) && p.To.Node != nil && !((p.To.Node).(*Node)).Used { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 189 | // Cannot remove VARDEF instruction, because - unlike TYPE handled above - |
| 190 | // VARDEFs are interspersed with other code, and a jump might be using the |
| 191 | // VARDEF as a target. Replace with a no-op instead. A later pass will remove |
| 192 | // the no-ops. |
| 193 | obj.Nopout(p) |
| 194 | |
| 195 | continue |
| 196 | } |
| 197 | |
| 198 | if p.From.Name == obj.NAME_AUTO && p.From.Node != nil { |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 199 | p.From.Offset += stkdelta[p.From.Node.(*Node)] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | if p.To.Name == obj.NAME_AUTO && p.To.Node != nil { |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 203 | p.To.Offset += stkdelta[p.To.Node.(*Node)] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | lp = &p.Link |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | func ggloblnod(nam *Node) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 211 | p := Thearch.Gins(obj.AGLOBL, nam, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 212 | p.Lineno = nam.Lineno |
| 213 | p.From.Sym.Gotype = Linksym(ngotype(nam)) |
| 214 | p.To.Sym = nil |
| 215 | p.To.Type = obj.TYPE_CONST |
| 216 | p.To.Offset = nam.Type.Width |
Russ Cox | c413c45 | 2015-05-27 15:01:44 -0400 | [diff] [blame] | 217 | p.From3 = new(obj.Addr) |
Josh Bleecher Snyder | 8fa14ea | 2015-05-15 10:02:19 -0700 | [diff] [blame] | 218 | if nam.Name.Readonly { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 219 | p.From3.Offset = obj.RODATA |
| 220 | } |
| 221 | if nam.Type != nil && !haspointers(nam.Type) { |
| 222 | p.From3.Offset |= obj.NOPTR |
| 223 | } |
| 224 | } |
| 225 | |
Michael Hudson-Doyle | 029c7bb | 2015-04-18 08:14:08 +1200 | [diff] [blame] | 226 | func ggloblsym(s *Sym, width int32, flags int16) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 227 | p := Thearch.Gins(obj.AGLOBL, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 228 | p.From.Type = obj.TYPE_MEM |
| 229 | p.From.Name = obj.NAME_EXTERN |
| 230 | p.From.Sym = Linksym(s) |
Michael Hudson-Doyle | 029c7bb | 2015-04-18 08:14:08 +1200 | [diff] [blame] | 231 | if flags&obj.LOCAL != 0 { |
| 232 | p.From.Sym.Local = true |
| 233 | flags &= ^obj.LOCAL |
| 234 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 235 | p.To.Type = obj.TYPE_CONST |
| 236 | p.To.Offset = int64(width) |
Russ Cox | c413c45 | 2015-05-27 15:01:44 -0400 | [diff] [blame] | 237 | p.From3 = new(obj.Addr) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 238 | p.From3.Offset = int64(flags) |
| 239 | } |
| 240 | |
| 241 | func gjmp(to *obj.Prog) *obj.Prog { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 242 | p := Gbranch(obj.AJMP, nil, 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 243 | if to != nil { |
| 244 | Patch(p, to) |
| 245 | } |
| 246 | return p |
| 247 | } |
| 248 | |
| 249 | func gtrack(s *Sym) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 250 | p := Thearch.Gins(obj.AUSEFIELD, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 251 | p.From.Type = obj.TYPE_MEM |
| 252 | p.From.Name = obj.NAME_EXTERN |
| 253 | p.From.Sym = Linksym(s) |
| 254 | } |
| 255 | |
| 256 | func gused(n *Node) { |
| 257 | Thearch.Gins(obj.ANOP, n, nil) // used |
| 258 | } |
| 259 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 260 | func Isfat(t *Type) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 261 | if t != nil { |
| 262 | switch t.Etype { |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 263 | case TSTRUCT, TARRAY, TSTRING, |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 264 | TINTER: // maybe remove later |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 265 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 266 | } |
| 267 | } |
| 268 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 269 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 270 | } |
| 271 | |
Russ Cox | cdb7d7d | 2015-03-05 13:57:36 -0500 | [diff] [blame] | 272 | // Sweep the prog list to mark any used nodes. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 273 | func markautoused(p *obj.Prog) { |
| 274 | for ; p != nil; p = p.Link { |
| 275 | if p.As == obj.ATYPE || p.As == obj.AVARDEF || p.As == obj.AVARKILL { |
| 276 | continue |
| 277 | } |
| 278 | |
| 279 | if p.From.Node != nil { |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 280 | ((p.From.Node).(*Node)).Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 281 | } |
| 282 | |
| 283 | if p.To.Node != nil { |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 284 | ((p.To.Node).(*Node)).Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | } |
| 288 | |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 289 | // Naddr rewrites a to refer to n. |
| 290 | // It assumes that a is zeroed on entry. |
| 291 | func Naddr(a *obj.Addr, n *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 292 | if n == nil { |
| 293 | return |
| 294 | } |
| 295 | |
| 296 | if n.Type != nil && n.Type.Etype != TIDEAL { |
| 297 | // TODO(rsc): This is undone by the selective clearing of width below, |
| 298 | // to match architectures that were not as aggressive in setting width |
| 299 | // during naddr. Those widths must be cleared to avoid triggering |
| 300 | // failures in gins when it detects real but heretofore latent (and one |
| 301 | // hopes innocuous) type mismatches. |
| 302 | // The type mismatches should be fixed and the clearing below removed. |
| 303 | dowidth(n.Type) |
| 304 | |
| 305 | a.Width = n.Type.Width |
| 306 | } |
| 307 | |
| 308 | switch n.Op { |
| 309 | default: |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 310 | a := a // copy to let escape into Ctxt.Dconv |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 311 | Debug['h'] = 1 |
| 312 | Dump("naddr", n) |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 313 | Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 314 | |
| 315 | case OREGISTER: |
| 316 | a.Type = obj.TYPE_REG |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 317 | a.Reg = n.Reg |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 318 | a.Sym = nil |
| 319 | if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width. |
| 320 | a.Width = 0 |
| 321 | } |
| 322 | |
| 323 | case OINDREG: |
| 324 | a.Type = obj.TYPE_MEM |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 325 | a.Reg = n.Reg |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 326 | a.Sym = Linksym(n.Sym) |
| 327 | a.Offset = n.Xoffset |
| 328 | if a.Offset != int64(int32(a.Offset)) { |
| 329 | Yyerror("offset %d too large for OINDREG", a.Offset) |
| 330 | } |
| 331 | if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width. |
| 332 | a.Width = 0 |
| 333 | } |
| 334 | |
| 335 | // n->left is PHEAP ONAME for stack parameter. |
| 336 | // compute address of actual parameter on stack. |
| 337 | case OPARAM: |
| 338 | a.Etype = Simtype[n.Left.Type.Etype] |
| 339 | |
| 340 | a.Width = n.Left.Type.Width |
| 341 | a.Offset = n.Xoffset |
| 342 | a.Sym = Linksym(n.Left.Sym) |
| 343 | a.Type = obj.TYPE_MEM |
| 344 | a.Name = obj.NAME_PARAM |
| 345 | a.Node = n.Left.Orig |
| 346 | |
| 347 | case OCLOSUREVAR: |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 348 | if !Curfn.Func.Needctxt { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 349 | Fatal("closurevar without needctxt") |
| 350 | } |
| 351 | a.Type = obj.TYPE_MEM |
| 352 | a.Reg = int16(Thearch.REGCTXT) |
| 353 | a.Sym = nil |
| 354 | a.Offset = n.Xoffset |
| 355 | |
| 356 | case OCFUNC: |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 357 | Naddr(a, n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 358 | a.Sym = Linksym(n.Left.Sym) |
| 359 | |
| 360 | case ONAME: |
| 361 | a.Etype = 0 |
| 362 | if n.Type != nil { |
| 363 | a.Etype = Simtype[n.Type.Etype] |
| 364 | } |
| 365 | a.Offset = n.Xoffset |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 366 | s := n.Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 367 | a.Node = n.Orig |
| 368 | |
| 369 | //if(a->node >= (Node*)&n) |
| 370 | // fatal("stack node"); |
| 371 | if s == nil { |
| 372 | s = Lookup(".noname") |
| 373 | } |
Josh Bleecher Snyder | 8fa14ea | 2015-05-15 10:02:19 -0700 | [diff] [blame] | 374 | if n.Name.Method { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 375 | if n.Type != nil { |
| 376 | if n.Type.Sym != nil { |
| 377 | if n.Type.Sym.Pkg != nil { |
| 378 | s = Pkglookup(s.Name, n.Type.Sym.Pkg) |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | a.Type = obj.TYPE_MEM |
| 385 | switch n.Class { |
| 386 | default: |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 387 | Fatal("naddr: ONAME class %v %d\n", n.Sym, n.Class) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 388 | |
| 389 | case PEXTERN: |
| 390 | a.Name = obj.NAME_EXTERN |
| 391 | |
| 392 | case PAUTO: |
| 393 | a.Name = obj.NAME_AUTO |
| 394 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 395 | case PPARAM, PPARAMOUT: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 396 | a.Name = obj.NAME_PARAM |
| 397 | |
| 398 | case PFUNC: |
| 399 | a.Name = obj.NAME_EXTERN |
| 400 | a.Type = obj.TYPE_ADDR |
| 401 | a.Width = int64(Widthptr) |
| 402 | s = funcsym(s) |
| 403 | } |
| 404 | |
| 405 | a.Sym = Linksym(s) |
| 406 | |
| 407 | case OLITERAL: |
| 408 | if Thearch.Thechar == '8' { |
| 409 | a.Width = 0 |
| 410 | } |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 411 | switch n.Val().Ctype() { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 412 | default: |
| 413 | Fatal("naddr: const %v", Tconv(n.Type, obj.FmtLong)) |
| 414 | |
| 415 | case CTFLT: |
| 416 | a.Type = obj.TYPE_FCONST |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 417 | a.Val = mpgetflt(n.Val().U.(*Mpflt)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 418 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 419 | case CTINT, CTRUNE: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 420 | a.Sym = nil |
| 421 | a.Type = obj.TYPE_CONST |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 422 | a.Offset = Mpgetfix(n.Val().U.(*Mpint)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 423 | |
| 424 | case CTSTR: |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 425 | datagostring(n.Val().U.(string), a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 426 | |
| 427 | case CTBOOL: |
| 428 | a.Sym = nil |
| 429 | a.Type = obj.TYPE_CONST |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 430 | a.Offset = int64(obj.Bool2int(n.Val().U.(bool))) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 431 | |
| 432 | case CTNIL: |
| 433 | a.Sym = nil |
| 434 | a.Type = obj.TYPE_CONST |
| 435 | a.Offset = 0 |
| 436 | } |
| 437 | |
| 438 | case OADDR: |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 439 | Naddr(a, n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 440 | a.Etype = uint8(Tptr) |
Aram Hăvărneanu | 02c1a9d | 2015-03-08 14:16:29 +0100 | [diff] [blame] | 441 | if Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 442 | a.Width = int64(Widthptr) |
| 443 | } |
| 444 | if a.Type != obj.TYPE_MEM { |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 445 | a := a // copy to let escape into Ctxt.Dconv |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 446 | Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 447 | } |
| 448 | a.Type = obj.TYPE_ADDR |
| 449 | |
| 450 | // itable of interface value |
| 451 | case OITAB: |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 452 | Naddr(a, n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 453 | |
| 454 | if a.Type == obj.TYPE_CONST && a.Offset == 0 { |
| 455 | break // itab(nil) |
| 456 | } |
| 457 | a.Etype = uint8(Tptr) |
| 458 | a.Width = int64(Widthptr) |
| 459 | |
| 460 | // pointer in a string or slice |
| 461 | case OSPTR: |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 462 | Naddr(a, n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 463 | |
| 464 | if a.Type == obj.TYPE_CONST && a.Offset == 0 { |
| 465 | break // ptr(nil) |
| 466 | } |
| 467 | a.Etype = Simtype[Tptr] |
| 468 | a.Offset += int64(Array_array) |
| 469 | a.Width = int64(Widthptr) |
| 470 | |
| 471 | // len of string or slice |
| 472 | case OLEN: |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 473 | Naddr(a, n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 474 | |
| 475 | if a.Type == obj.TYPE_CONST && a.Offset == 0 { |
| 476 | break // len(nil) |
| 477 | } |
| 478 | a.Etype = Simtype[TUINT] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 479 | a.Offset += int64(Array_nel) |
| 480 | if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. |
| 481 | a.Width = int64(Widthint) |
| 482 | } |
| 483 | |
| 484 | // cap of string or slice |
| 485 | case OCAP: |
Russ Cox | 8b9a3d4 | 2015-03-16 15:27:19 -0400 | [diff] [blame] | 486 | Naddr(a, n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 487 | |
| 488 | if a.Type == obj.TYPE_CONST && a.Offset == 0 { |
| 489 | break // cap(nil) |
| 490 | } |
| 491 | a.Etype = Simtype[TUINT] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 492 | a.Offset += int64(Array_cap) |
| 493 | if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. |
| 494 | a.Width = int64(Widthint) |
| 495 | } |
| 496 | } |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 497 | return |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 498 | } |
| 499 | |
| 500 | func newplist() *obj.Plist { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 501 | pl := obj.Linknewplist(Ctxt) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 502 | |
| 503 | Pc = Ctxt.NewProg() |
| 504 | Clearp(Pc) |
| 505 | pl.Firstpc = Pc |
| 506 | |
| 507 | return pl |
| 508 | } |
| 509 | |
| 510 | func nodarg(t *Type, fp int) *Node { |
| 511 | var n *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 512 | |
| 513 | // entire argument struct, not just one arg |
| 514 | if t.Etype == TSTRUCT && t.Funarg != 0 { |
| 515 | n = Nod(ONAME, nil, nil) |
| 516 | n.Sym = Lookup(".args") |
| 517 | n.Type = t |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 518 | var savet Iter |
| 519 | first := Structfirst(&savet, &t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 520 | if first == nil { |
| 521 | Fatal("nodarg: bad struct") |
| 522 | } |
| 523 | if first.Width == BADWIDTH { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 524 | Fatal("nodarg: offset not computed for %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 525 | } |
| 526 | n.Xoffset = first.Width |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 527 | n.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 528 | goto fp |
| 529 | } |
| 530 | |
| 531 | if t.Etype != TFIELD { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 532 | Fatal("nodarg: not field %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 533 | } |
| 534 | |
| 535 | if fp == 1 { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 536 | var n *Node |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 537 | for l := Curfn.Func.Dcl; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 538 | n = l.N |
| 539 | if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym { |
| 540 | return n |
| 541 | } |
| 542 | } |
| 543 | } |
| 544 | |
| 545 | n = Nod(ONAME, nil, nil) |
| 546 | n.Type = t.Type |
| 547 | n.Sym = t.Sym |
| 548 | |
| 549 | if t.Width == BADWIDTH { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 550 | Fatal("nodarg: offset not computed for %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 551 | } |
| 552 | n.Xoffset = t.Width |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 553 | n.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 554 | n.Orig = t.Nname |
| 555 | |
| 556 | // Rewrite argument named _ to __, |
| 557 | // or else the assignment to _ will be |
| 558 | // discarded during code generation. |
| 559 | fp: |
| 560 | if isblank(n) { |
| 561 | n.Sym = Lookup("__") |
| 562 | } |
| 563 | |
| 564 | switch fp { |
| 565 | case 0: // output arg |
| 566 | n.Op = OINDREG |
| 567 | |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 568 | n.Reg = int16(Thearch.REGSP) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 569 | if HasLinkRegister() { |
| 570 | n.Xoffset += int64(Ctxt.Arch.Ptrsize) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 571 | } |
| 572 | |
| 573 | case 1: // input arg |
| 574 | n.Class = PPARAM |
| 575 | |
| 576 | case 2: // offset output arg |
| 577 | Fatal("shouldn't be used") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 578 | } |
| 579 | |
| 580 | n.Typecheck = 1 |
| 581 | return n |
| 582 | } |
| 583 | |
| 584 | func Patch(p *obj.Prog, to *obj.Prog) { |
| 585 | if p.To.Type != obj.TYPE_BRANCH { |
| 586 | Fatal("patch: not a branch") |
| 587 | } |
Russ Cox | 532ccae | 2015-03-16 15:54:44 -0400 | [diff] [blame] | 588 | p.To.Val = to |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 589 | p.To.Offset = to.Pc |
| 590 | } |
| 591 | |
| 592 | func unpatch(p *obj.Prog) *obj.Prog { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 593 | if p.To.Type != obj.TYPE_BRANCH { |
| 594 | Fatal("unpatch: not a branch") |
| 595 | } |
Russ Cox | 532ccae | 2015-03-16 15:54:44 -0400 | [diff] [blame] | 596 | q, _ := p.To.Val.(*obj.Prog) |
| 597 | p.To.Val = nil |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 598 | p.To.Offset = 0 |
| 599 | return q |
| 600 | } |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 601 | |
| 602 | var reg [100]int // count of references to reg |
| 603 | var regstk [100][]byte // allocation sites, when -v is given |
| 604 | |
Keith Randall | e97ab0a | 2015-08-13 12:25:19 -0700 | [diff] [blame^] | 605 | func GetReg(r int) int { |
| 606 | return reg[r-Thearch.REGMIN] |
| 607 | } |
| 608 | func SetReg(r, v int) { |
| 609 | reg[r-Thearch.REGMIN] = v |
| 610 | } |
| 611 | |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 612 | func ginit() { |
| 613 | for r := range reg { |
| 614 | reg[r] = 1 |
| 615 | } |
| 616 | |
| 617 | for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { |
| 618 | reg[r-Thearch.REGMIN] = 0 |
| 619 | } |
| 620 | for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { |
| 621 | reg[r-Thearch.REGMIN] = 0 |
| 622 | } |
| 623 | |
| 624 | for _, r := range Thearch.ReservedRegs { |
| 625 | reg[r-Thearch.REGMIN] = 1 |
| 626 | } |
| 627 | } |
| 628 | |
| 629 | func gclean() { |
| 630 | for _, r := range Thearch.ReservedRegs { |
| 631 | reg[r-Thearch.REGMIN]-- |
| 632 | } |
| 633 | |
| 634 | for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { |
| 635 | n := reg[r-Thearch.REGMIN] |
| 636 | if n != 0 { |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 637 | if Debug['v'] != 0 { |
| 638 | Regdump() |
| 639 | } |
Russ Cox | c70b4b5 | 2015-05-06 12:22:05 -0400 | [diff] [blame] | 640 | Yyerror("reg %v left allocated", obj.Rconv(r)) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 641 | } |
| 642 | } |
| 643 | |
| 644 | for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { |
| 645 | n := reg[r-Thearch.REGMIN] |
| 646 | if n != 0 { |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 647 | if Debug['v'] != 0 { |
| 648 | Regdump() |
| 649 | } |
Russ Cox | c70b4b5 | 2015-05-06 12:22:05 -0400 | [diff] [blame] | 650 | Yyerror("reg %v left allocated", obj.Rconv(r)) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 651 | } |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | func Anyregalloc() bool { |
| 656 | n := 0 |
| 657 | for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { |
| 658 | if reg[r-Thearch.REGMIN] == 0 { |
| 659 | n++ |
| 660 | } |
| 661 | } |
| 662 | return n > len(Thearch.ReservedRegs) |
| 663 | } |
| 664 | |
| 665 | /* |
| 666 | * allocate register of type t, leave in n. |
| 667 | * if o != N, o may be reusable register. |
| 668 | * caller must Regfree(n). |
| 669 | */ |
| 670 | func Regalloc(n *Node, t *Type, o *Node) { |
| 671 | if t == nil { |
| 672 | Fatal("regalloc: t nil") |
| 673 | } |
| 674 | et := int(Simtype[t.Etype]) |
| 675 | if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) { |
| 676 | Fatal("regalloc 64bit") |
| 677 | } |
| 678 | |
| 679 | var i int |
| 680 | Switch: |
| 681 | switch et { |
| 682 | default: |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 683 | Fatal("regalloc: unknown type %v", t) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 684 | |
| 685 | case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL: |
| 686 | if o != nil && o.Op == OREGISTER { |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 687 | i = int(o.Reg) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 688 | if Thearch.REGMIN <= i && i <= Thearch.REGMAX { |
| 689 | break Switch |
| 690 | } |
| 691 | } |
| 692 | for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ { |
| 693 | if reg[i-Thearch.REGMIN] == 0 { |
| 694 | break Switch |
| 695 | } |
| 696 | } |
| 697 | Flusherrors() |
| 698 | Regdump() |
| 699 | Fatal("out of fixed registers") |
| 700 | |
| 701 | case TFLOAT32, TFLOAT64: |
Dave Cheney | 01d005c | 2015-03-25 09:17:09 +1100 | [diff] [blame] | 702 | if Thearch.Use387 { |
Dave Cheney | 8fc73a3 | 2015-03-24 22:16:48 +1100 | [diff] [blame] | 703 | i = Thearch.FREGMIN // x86.REG_F0 |
| 704 | break Switch |
| 705 | } |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 706 | if o != nil && o.Op == OREGISTER { |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 707 | i = int(o.Reg) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 708 | if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX { |
| 709 | break Switch |
| 710 | } |
| 711 | } |
| 712 | for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ { |
| 713 | if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN |
| 714 | break Switch |
| 715 | } |
| 716 | } |
| 717 | Flusherrors() |
| 718 | Regdump() |
| 719 | Fatal("out of floating registers") |
| 720 | |
| 721 | case TCOMPLEX64, TCOMPLEX128: |
| 722 | Tempname(n, t) |
| 723 | return |
| 724 | } |
| 725 | |
| 726 | ix := i - Thearch.REGMIN |
| 727 | if reg[ix] == 0 && Debug['v'] > 0 { |
| 728 | if regstk[ix] == nil { |
| 729 | regstk[ix] = make([]byte, 4096) |
| 730 | } |
| 731 | stk := regstk[ix] |
| 732 | n := runtime.Stack(stk[:cap(stk)], false) |
| 733 | regstk[ix] = stk[:n] |
| 734 | } |
| 735 | reg[ix]++ |
| 736 | Nodreg(n, t, i) |
| 737 | } |
| 738 | |
| 739 | func Regfree(n *Node) { |
| 740 | if n.Op == ONAME { |
| 741 | return |
| 742 | } |
| 743 | if n.Op != OREGISTER && n.Op != OINDREG { |
| 744 | Fatal("regfree: not a register") |
| 745 | } |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 746 | i := int(n.Reg) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 747 | if i == Thearch.REGSP { |
| 748 | return |
| 749 | } |
| 750 | switch { |
| 751 | case Thearch.REGMIN <= i && i <= Thearch.REGMAX, |
| 752 | Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: |
| 753 | // ok |
| 754 | default: |
| 755 | Fatal("regfree: reg out of range") |
| 756 | } |
| 757 | |
| 758 | i -= Thearch.REGMIN |
| 759 | if reg[i] <= 0 { |
| 760 | Fatal("regfree: reg not allocated") |
| 761 | } |
| 762 | reg[i]-- |
| 763 | if reg[i] == 0 { |
| 764 | regstk[i] = regstk[i][:0] |
| 765 | } |
| 766 | } |
| 767 | |
| 768 | // Reginuse reports whether r is in use. |
| 769 | func Reginuse(r int) bool { |
| 770 | switch { |
| 771 | case Thearch.REGMIN <= r && r <= Thearch.REGMAX, |
| 772 | Thearch.FREGMIN <= r && r <= Thearch.FREGMAX: |
| 773 | // ok |
| 774 | default: |
| 775 | Fatal("reginuse: reg out of range") |
| 776 | } |
| 777 | |
| 778 | return reg[r-Thearch.REGMIN] > 0 |
| 779 | } |
| 780 | |
| 781 | // Regrealloc(n) undoes the effect of Regfree(n), |
| 782 | // so that a register can be given up but then reclaimed. |
| 783 | func Regrealloc(n *Node) { |
| 784 | if n.Op != OREGISTER && n.Op != OINDREG { |
| 785 | Fatal("regrealloc: not a register") |
| 786 | } |
Josh Bleecher Snyder | 5ed90cb | 2015-04-13 10:28:57 -0700 | [diff] [blame] | 787 | i := int(n.Reg) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 788 | if i == Thearch.REGSP { |
| 789 | return |
| 790 | } |
| 791 | switch { |
| 792 | case Thearch.REGMIN <= i && i <= Thearch.REGMAX, |
| 793 | Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: |
| 794 | // ok |
| 795 | default: |
| 796 | Fatal("regrealloc: reg out of range") |
| 797 | } |
| 798 | |
| 799 | i -= Thearch.REGMIN |
| 800 | if reg[i] == 0 && Debug['v'] > 0 { |
| 801 | if regstk[i] == nil { |
| 802 | regstk[i] = make([]byte, 4096) |
| 803 | } |
| 804 | stk := regstk[i] |
| 805 | n := runtime.Stack(stk[:cap(stk)], false) |
| 806 | regstk[i] = stk[:n] |
| 807 | } |
| 808 | reg[i]++ |
| 809 | } |
| 810 | |
| 811 | func Regdump() { |
| 812 | if Debug['v'] == 0 { |
| 813 | fmt.Printf("run compiler with -v for register allocation sites\n") |
| 814 | return |
| 815 | } |
| 816 | |
| 817 | dump := func(r int) { |
| 818 | stk := regstk[r-Thearch.REGMIN] |
| 819 | if len(stk) == 0 { |
| 820 | return |
| 821 | } |
| 822 | fmt.Printf("reg %v allocated at:\n", obj.Rconv(r)) |
| 823 | fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1)) |
| 824 | } |
| 825 | |
| 826 | for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { |
| 827 | if reg[r-Thearch.REGMIN] != 0 { |
| 828 | dump(r) |
| 829 | } |
| 830 | } |
| 831 | for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { |
| 832 | if reg[r-Thearch.REGMIN] == 0 { |
| 833 | dump(r) |
| 834 | } |
| 835 | } |
| 836 | } |