blob: 2c575f3d789a21b47379d15fb5fededde903f5fe [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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
31package gc
32
Russ Coxb115c352015-03-18 17:26:36 -040033import (
34 "cmd/internal/obj"
35 "fmt"
36 "runtime"
37 "strings"
38)
Russ Cox8c195bd2015-02-13 14:40:36 -050039
40var ddumped int
41
42var dfirst *obj.Prog
43
44var dpc *obj.Prog
45
46/*
47 * Is this node a memory operand?
48 */
Russ Coxdc7b54b2015-02-17 22:13:49 -050049func Ismem(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -050050 switch n.Op {
51 case OITAB,
52 OSPTR,
53 OLEN,
54 OCAP,
55 OINDREG,
56 ONAME,
57 OPARAM,
58 OCLOSUREVAR:
Russ Coxdc7b54b2015-02-17 22:13:49 -050059 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050060
61 case OADDR:
Russ Coxdc7b54b2015-02-17 22:13:49 -050062 return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
Russ Cox8c195bd2015-02-13 14:40:36 -050063 }
64
Russ Coxdc7b54b2015-02-17 22:13:49 -050065 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050066}
67
Russ Coxdc7b54b2015-02-17 22:13:49 -050068func Samereg(a *Node, b *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -050069 if a == nil || b == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -050070 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050071 }
72 if a.Op != OREGISTER {
Russ Coxdc7b54b2015-02-17 22:13:49 -050073 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050074 }
75 if b.Op != OREGISTER {
Russ Coxdc7b54b2015-02-17 22:13:49 -050076 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050077 }
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -070078 if a.Reg != b.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -050079 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050080 }
Russ Coxdc7b54b2015-02-17 22:13:49 -050081 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050082}
83
Russ Cox8c195bd2015-02-13 14:40:36 -050084func Gbranch(as int, t *Type, likely int) *obj.Prog {
Russ Cox382b44e2015-02-23 16:07:24 -050085 p := Prog(as)
Russ Cox8c195bd2015-02-13 14:40:36 -050086 p.To.Type = obj.TYPE_BRANCH
Russ Cox532ccae2015-03-16 15:54:44 -040087 p.To.Val = nil
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +010088 if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' {
Russ Cox8c195bd2015-02-13 14:40:36 -050089 p.From.Type = obj.TYPE_CONST
Michael Hudson-Doyleac1cdd12015-04-22 12:41:14 +120090 p.From.Offset = int64(obj.Bool2int(likely > 0))
Russ Cox8c195bd2015-02-13 14:40:36 -050091 }
92
Russ Cox351897d2015-05-07 10:34:12 -040093 if Debug['g'] != 0 {
94 fmt.Printf("%v\n", p)
95 }
96
Russ Cox8c195bd2015-02-13 14:40:36 -050097 return p
98}
99
100func 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
133func 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 Snyder75883ba2015-04-02 19:58:37 -0700140 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500141 ullmancalc(n)
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700142 n.Reg = int16(r)
Russ Cox8c195bd2015-02-13 14:40:36 -0500143 n.Type = t
144}
145
146func Nodindreg(n *Node, t *Type, r int) {
147 Nodreg(n, t, r)
148 n.Op = OINDREG
149}
150
151func 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
158func Clearp(p *obj.Prog) {
159 obj.Nopout(p)
160 p.As = obj.AEND
161 p.Pc = int64(pcloc)
162 pcloc++
163}
164
165func 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 Coxcdb7d7d2015-03-05 13:57:36 -0500176// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
Russ Cox8c195bd2015-02-13 14:40:36 -0500177func fixautoused(p *obj.Prog) {
Russ Cox382b44e2015-02-23 16:07:24 -0500178 for lp := &p; ; {
Russ Cox8c195bd2015-02-13 14:40:36 -0500179 p = *lp
Russ Coxdc7b54b2015-02-17 22:13:49 -0500180 if p == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500181 break
182 }
Dave Cheney44e90312015-03-06 21:18:41 +1100183 if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !((p.From.Node).(*Node)).Used {
Russ Cox8c195bd2015-02-13 14:40:36 -0500184 *lp = p.Link
185 continue
186 }
187
Dave Cheney44e90312015-03-06 21:18:41 +1100188 if (p.As == obj.AVARDEF || p.As == obj.AVARKILL) && p.To.Node != nil && !((p.To.Node).(*Node)).Used {
Russ Cox8c195bd2015-02-13 14:40:36 -0500189 // 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 Cox66be1482015-05-26 21:30:20 -0400199 p.From.Offset += stkdelta[p.From.Node.(*Node)]
Russ Cox8c195bd2015-02-13 14:40:36 -0500200 }
201
202 if p.To.Name == obj.NAME_AUTO && p.To.Node != nil {
Russ Cox66be1482015-05-26 21:30:20 -0400203 p.To.Offset += stkdelta[p.To.Node.(*Node)]
Russ Cox8c195bd2015-02-13 14:40:36 -0500204 }
205
206 lp = &p.Link
207 }
208}
209
210func ggloblnod(nam *Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500211 p := Thearch.Gins(obj.AGLOBL, nam, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500212 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 Coxc413c452015-05-27 15:01:44 -0400217 p.From3 = new(obj.Addr)
Josh Bleecher Snyder8fa14ea2015-05-15 10:02:19 -0700218 if nam.Name.Readonly {
Russ Cox8c195bd2015-02-13 14:40:36 -0500219 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-Doyle029c7bb2015-04-18 08:14:08 +1200226func ggloblsym(s *Sym, width int32, flags int16) {
Russ Cox382b44e2015-02-23 16:07:24 -0500227 p := Thearch.Gins(obj.AGLOBL, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500228 p.From.Type = obj.TYPE_MEM
229 p.From.Name = obj.NAME_EXTERN
230 p.From.Sym = Linksym(s)
Michael Hudson-Doyle029c7bb2015-04-18 08:14:08 +1200231 if flags&obj.LOCAL != 0 {
232 p.From.Sym.Local = true
233 flags &= ^obj.LOCAL
234 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500235 p.To.Type = obj.TYPE_CONST
236 p.To.Offset = int64(width)
Russ Coxc413c452015-05-27 15:01:44 -0400237 p.From3 = new(obj.Addr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500238 p.From3.Offset = int64(flags)
239}
240
241func gjmp(to *obj.Prog) *obj.Prog {
Russ Cox382b44e2015-02-23 16:07:24 -0500242 p := Gbranch(obj.AJMP, nil, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500243 if to != nil {
244 Patch(p, to)
245 }
246 return p
247}
248
249func gtrack(s *Sym) {
Russ Cox382b44e2015-02-23 16:07:24 -0500250 p := Thearch.Gins(obj.AUSEFIELD, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500251 p.From.Type = obj.TYPE_MEM
252 p.From.Name = obj.NAME_EXTERN
253 p.From.Sym = Linksym(s)
254}
255
256func gused(n *Node) {
257 Thearch.Gins(obj.ANOP, n, nil) // used
258}
259
Russ Coxdc7b54b2015-02-17 22:13:49 -0500260func Isfat(t *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500261 if t != nil {
262 switch t.Etype {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700263 case TSTRUCT, TARRAY, TSTRING,
Russ Cox8c195bd2015-02-13 14:40:36 -0500264 TINTER: // maybe remove later
Russ Coxdc7b54b2015-02-17 22:13:49 -0500265 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500266 }
267 }
268
Russ Coxdc7b54b2015-02-17 22:13:49 -0500269 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500270}
271
Russ Coxcdb7d7d2015-03-05 13:57:36 -0500272// Sweep the prog list to mark any used nodes.
Russ Cox8c195bd2015-02-13 14:40:36 -0500273func 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 Cheney44e90312015-03-06 21:18:41 +1100280 ((p.From.Node).(*Node)).Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500281 }
282
283 if p.To.Node != nil {
Dave Cheney44e90312015-03-06 21:18:41 +1100284 ((p.To.Node).(*Node)).Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500285 }
286 }
287}
288
Russ Cox8b9a3d42015-03-16 15:27:19 -0400289// Naddr rewrites a to refer to n.
290// It assumes that a is zeroed on entry.
291func Naddr(a *obj.Addr, n *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500292 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 Cox44928112015-03-02 20:34:22 -0500310 a := a // copy to let escape into Ctxt.Dconv
Russ Coxb115c352015-03-18 17:26:36 -0400311 Debug['h'] = 1
312 Dump("naddr", n)
Russ Cox8b9a3d42015-03-16 15:27:19 -0400313 Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a))
Russ Cox8c195bd2015-02-13 14:40:36 -0500314
315 case OREGISTER:
316 a.Type = obj.TYPE_REG
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700317 a.Reg = n.Reg
Russ Cox8c195bd2015-02-13 14:40:36 -0500318 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 Snyder5ed90cb2015-04-13 10:28:57 -0700325 a.Reg = n.Reg
Russ Cox8c195bd2015-02-13 14:40:36 -0500326 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 Snyder3ed9e4c2015-03-25 19:33:01 -0700348 if !Curfn.Func.Needctxt {
Russ Cox8c195bd2015-02-13 14:40:36 -0500349 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 Cox8b9a3d42015-03-16 15:27:19 -0400357 Naddr(a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500358 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 Cox382b44e2015-02-23 16:07:24 -0500366 s := n.Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500367 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 Snyder8fa14ea2015-05-15 10:02:19 -0700374 if n.Name.Method {
Russ Cox8c195bd2015-02-13 14:40:36 -0500375 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 Cox17228f42015-04-17 12:03:22 -0400387 Fatal("naddr: ONAME class %v %d\n", n.Sym, n.Class)
Russ Cox8c195bd2015-02-13 14:40:36 -0500388
389 case PEXTERN:
390 a.Name = obj.NAME_EXTERN
391
392 case PAUTO:
393 a.Name = obj.NAME_AUTO
394
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700395 case PPARAM, PPARAMOUT:
Russ Cox8c195bd2015-02-13 14:40:36 -0500396 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 Cox81d58102015-05-27 00:47:05 -0400411 switch n.Val().Ctype() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500412 default:
413 Fatal("naddr: const %v", Tconv(n.Type, obj.FmtLong))
414
415 case CTFLT:
416 a.Type = obj.TYPE_FCONST
Russ Cox81d58102015-05-27 00:47:05 -0400417 a.Val = mpgetflt(n.Val().U.(*Mpflt))
Russ Cox8c195bd2015-02-13 14:40:36 -0500418
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700419 case CTINT, CTRUNE:
Russ Cox8c195bd2015-02-13 14:40:36 -0500420 a.Sym = nil
421 a.Type = obj.TYPE_CONST
Russ Cox81d58102015-05-27 00:47:05 -0400422 a.Offset = Mpgetfix(n.Val().U.(*Mpint))
Russ Cox8c195bd2015-02-13 14:40:36 -0500423
424 case CTSTR:
Russ Cox81d58102015-05-27 00:47:05 -0400425 datagostring(n.Val().U.(string), a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500426
427 case CTBOOL:
428 a.Sym = nil
429 a.Type = obj.TYPE_CONST
Russ Cox81d58102015-05-27 00:47:05 -0400430 a.Offset = int64(obj.Bool2int(n.Val().U.(bool)))
Russ Cox8c195bd2015-02-13 14:40:36 -0500431
432 case CTNIL:
433 a.Sym = nil
434 a.Type = obj.TYPE_CONST
435 a.Offset = 0
436 }
437
438 case OADDR:
Russ Cox8b9a3d42015-03-16 15:27:19 -0400439 Naddr(a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500440 a.Etype = uint8(Tptr)
Aram Hăvărneanu02c1a9d2015-03-08 14:16:29 +0100441 if Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
Russ Cox8c195bd2015-02-13 14:40:36 -0500442 a.Width = int64(Widthptr)
443 }
444 if a.Type != obj.TYPE_MEM {
Russ Cox44928112015-03-02 20:34:22 -0500445 a := a // copy to let escape into Ctxt.Dconv
Russ Cox8b9a3d42015-03-16 15:27:19 -0400446 Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500447 }
448 a.Type = obj.TYPE_ADDR
449
450 // itable of interface value
451 case OITAB:
Russ Cox8b9a3d42015-03-16 15:27:19 -0400452 Naddr(a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500453
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 Cox8b9a3d42015-03-16 15:27:19 -0400462 Naddr(a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500463
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 Cox8b9a3d42015-03-16 15:27:19 -0400473 Naddr(a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500474
475 if a.Type == obj.TYPE_CONST && a.Offset == 0 {
476 break // len(nil)
477 }
478 a.Etype = Simtype[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -0500479 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 Cox8b9a3d42015-03-16 15:27:19 -0400486 Naddr(a, n.Left)
Russ Cox8c195bd2015-02-13 14:40:36 -0500487
488 if a.Type == obj.TYPE_CONST && a.Offset == 0 {
489 break // cap(nil)
490 }
491 a.Etype = Simtype[TUINT]
Russ Cox8c195bd2015-02-13 14:40:36 -0500492 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 Cox44928112015-03-02 20:34:22 -0500497 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500498}
499
500func newplist() *obj.Plist {
Russ Cox382b44e2015-02-23 16:07:24 -0500501 pl := obj.Linknewplist(Ctxt)
Russ Cox8c195bd2015-02-13 14:40:36 -0500502
503 Pc = Ctxt.NewProg()
504 Clearp(Pc)
505 pl.Firstpc = Pc
506
507 return pl
508}
509
510func nodarg(t *Type, fp int) *Node {
511 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500512
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 Cox382b44e2015-02-23 16:07:24 -0500518 var savet Iter
519 first := Structfirst(&savet, &t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500520 if first == nil {
521 Fatal("nodarg: bad struct")
522 }
523 if first.Width == BADWIDTH {
Russ Cox17228f42015-04-17 12:03:22 -0400524 Fatal("nodarg: offset not computed for %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500525 }
526 n.Xoffset = first.Width
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700527 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500528 goto fp
529 }
530
531 if t.Etype != TFIELD {
Russ Cox17228f42015-04-17 12:03:22 -0400532 Fatal("nodarg: not field %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500533 }
534
535 if fp == 1 {
Russ Cox382b44e2015-02-23 16:07:24 -0500536 var n *Node
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700537 for l := Curfn.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500538 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 Cox17228f42015-04-17 12:03:22 -0400550 Fatal("nodarg: offset not computed for %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500551 }
552 n.Xoffset = t.Width
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700553 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500554 n.Orig = t.Nname
555
556 // Rewrite argument named _ to __,
557 // or else the assignment to _ will be
558 // discarded during code generation.
559fp:
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 Snyder5ed90cb2015-04-13 10:28:57 -0700568 n.Reg = int16(Thearch.REGSP)
Russ Coxb115c352015-03-18 17:26:36 -0400569 if HasLinkRegister() {
570 n.Xoffset += int64(Ctxt.Arch.Ptrsize)
Russ Cox8c195bd2015-02-13 14:40:36 -0500571 }
572
573 case 1: // input arg
574 n.Class = PPARAM
575
576 case 2: // offset output arg
577 Fatal("shouldn't be used")
Russ Cox8c195bd2015-02-13 14:40:36 -0500578 }
579
580 n.Typecheck = 1
581 return n
582}
583
584func Patch(p *obj.Prog, to *obj.Prog) {
585 if p.To.Type != obj.TYPE_BRANCH {
586 Fatal("patch: not a branch")
587 }
Russ Cox532ccae2015-03-16 15:54:44 -0400588 p.To.Val = to
Russ Cox8c195bd2015-02-13 14:40:36 -0500589 p.To.Offset = to.Pc
590}
591
592func unpatch(p *obj.Prog) *obj.Prog {
Russ Cox8c195bd2015-02-13 14:40:36 -0500593 if p.To.Type != obj.TYPE_BRANCH {
594 Fatal("unpatch: not a branch")
595 }
Russ Cox532ccae2015-03-16 15:54:44 -0400596 q, _ := p.To.Val.(*obj.Prog)
597 p.To.Val = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500598 p.To.Offset = 0
599 return q
600}
Russ Coxb115c352015-03-18 17:26:36 -0400601
602var reg [100]int // count of references to reg
603var regstk [100][]byte // allocation sites, when -v is given
604
Keith Randalle97ab0a2015-08-13 12:25:19 -0700605func GetReg(r int) int {
606 return reg[r-Thearch.REGMIN]
607}
608func SetReg(r, v int) {
609 reg[r-Thearch.REGMIN] = v
610}
611
Russ Coxb115c352015-03-18 17:26:36 -0400612func 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
629func 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 Coxb115c352015-03-18 17:26:36 -0400637 if Debug['v'] != 0 {
638 Regdump()
639 }
Russ Coxc70b4b52015-05-06 12:22:05 -0400640 Yyerror("reg %v left allocated", obj.Rconv(r))
Russ Coxb115c352015-03-18 17:26:36 -0400641 }
642 }
643
644 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
645 n := reg[r-Thearch.REGMIN]
646 if n != 0 {
Russ Coxb115c352015-03-18 17:26:36 -0400647 if Debug['v'] != 0 {
648 Regdump()
649 }
Russ Coxc70b4b52015-05-06 12:22:05 -0400650 Yyerror("reg %v left allocated", obj.Rconv(r))
Russ Coxb115c352015-03-18 17:26:36 -0400651 }
652 }
653}
654
655func 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 */
670func 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
680Switch:
681 switch et {
682 default:
Russ Cox17228f42015-04-17 12:03:22 -0400683 Fatal("regalloc: unknown type %v", t)
Russ Coxb115c352015-03-18 17:26:36 -0400684
685 case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL:
686 if o != nil && o.Op == OREGISTER {
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700687 i = int(o.Reg)
Russ Coxb115c352015-03-18 17:26:36 -0400688 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 Cheney01d005c2015-03-25 09:17:09 +1100702 if Thearch.Use387 {
Dave Cheney8fc73a32015-03-24 22:16:48 +1100703 i = Thearch.FREGMIN // x86.REG_F0
704 break Switch
705 }
Russ Coxb115c352015-03-18 17:26:36 -0400706 if o != nil && o.Op == OREGISTER {
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700707 i = int(o.Reg)
Russ Coxb115c352015-03-18 17:26:36 -0400708 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
739func 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 Snyder5ed90cb2015-04-13 10:28:57 -0700746 i := int(n.Reg)
Russ Coxb115c352015-03-18 17:26:36 -0400747 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.
769func 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.
783func Regrealloc(n *Node) {
784 if n.Op != OREGISTER && n.Op != OINDREG {
785 Fatal("regrealloc: not a register")
786 }
Josh Bleecher Snyder5ed90cb2015-04-13 10:28:57 -0700787 i := int(n.Reg)
Russ Coxb115c352015-03-18 17:26:36 -0400788 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
811func 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}