Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Robert Griesemer | def9c0b | 2016-03-10 20:35:27 -0800 | [diff] [blame] | 5 | // Portable half of code generator; mainly statements and control flow. |
| 6 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 7 | package gc |
| 8 | |
| 9 | import ( |
| 10 | "cmd/internal/obj" |
Matthew Dempsky | c6e11fe | 2016-04-06 12:01:40 -0700 | [diff] [blame] | 11 | "cmd/internal/sys" |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 12 | "fmt" |
| 13 | ) |
| 14 | |
Robert Griesemer | def9c0b | 2016-03-10 20:35:27 -0800 | [diff] [blame] | 15 | // TODO: labellist should become part of a "compilation state" for functions. |
| 16 | var labellist []*Label |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 17 | |
| 18 | func Sysfunc(name string) *Node { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 19 | n := newname(Pkglookup(name, Runtimepkg)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 20 | n.Class = PFUNC |
| 21 | return n |
| 22 | } |
| 23 | |
David Chase | 7fbb1b3 | 2015-03-26 16:36:15 -0400 | [diff] [blame] | 24 | // addrescapes tags node n as having had its address taken |
| 25 | // by "increasing" the "value" of n.Esc to EscHeap. |
| 26 | // Storage is allocated as necessary to allow the address |
| 27 | // to be taken. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 28 | func addrescapes(n *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 29 | switch n.Op { |
| 30 | // probably a type error already. |
| 31 | // dump("addrescapes", n); |
| 32 | default: |
| 33 | break |
| 34 | |
| 35 | case ONAME: |
| 36 | if n == nodfp { |
| 37 | break |
| 38 | } |
| 39 | |
| 40 | // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. |
| 41 | // on PPARAM it means something different. |
| 42 | if n.Class == PAUTO && n.Esc == EscNever { |
| 43 | break |
| 44 | } |
| 45 | |
Russ Cox | b6dc3e6 | 2016-05-25 01:33:24 -0400 | [diff] [blame^] | 46 | // A PPARAMREF is a closure reference. |
| 47 | // Mark the thing it refers to as escaping. |
| 48 | if n.Class == PPARAMREF { |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 49 | addrescapes(n.Name.Defn) |
Russ Cox | b6dc3e6 | 2016-05-25 01:33:24 -0400 | [diff] [blame^] | 50 | break |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 51 | } |
| 52 | |
Russ Cox | b6dc3e6 | 2016-05-25 01:33:24 -0400 | [diff] [blame^] | 53 | if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO { |
| 54 | break |
| 55 | } |
| 56 | |
| 57 | // This is a plain parameter or local variable that needs to move to the heap, |
| 58 | // but possibly for the function outside the one we're compiling. |
| 59 | // That is, if we have: |
| 60 | // |
| 61 | // func f(x int) { |
| 62 | // func() { |
| 63 | // global = &x |
| 64 | // } |
| 65 | // } |
| 66 | // |
| 67 | // then we're analyzing the inner closure but we need to move x to the |
| 68 | // heap in f, not in the inner closure. Flip over to f before calling moveToHeap. |
| 69 | oldfn := Curfn |
| 70 | Curfn = n.Name.Curfn |
| 71 | if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE { |
| 72 | Curfn = Curfn.Func.Closure |
| 73 | } |
| 74 | ln := lineno |
| 75 | lineno = Curfn.Lineno |
| 76 | moveToHeap(n) |
| 77 | Curfn = oldfn |
| 78 | lineno = ln |
| 79 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 80 | case OIND, ODOTPTR: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 81 | break |
| 82 | |
David Chase | 7fbb1b3 | 2015-03-26 16:36:15 -0400 | [diff] [blame] | 83 | // ODOTPTR has already been introduced, |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 84 | // so these are the non-pointer ODOT and OINDEX. |
| 85 | // In &x[0], if x is a slice, then x does not |
| 86 | // escape--the pointer inside x does, but that |
| 87 | // is always a heap pointer anyway. |
David Chase | 7fbb1b3 | 2015-03-26 16:36:15 -0400 | [diff] [blame] | 88 | case ODOT, OINDEX, OPAREN, OCONVNOP: |
Matthew Dempsky | 1624a9c | 2016-03-30 14:45:47 -0700 | [diff] [blame] | 89 | if !n.Left.Type.IsSlice() { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 90 | addrescapes(n.Left) |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
Russ Cox | b6dc3e6 | 2016-05-25 01:33:24 -0400 | [diff] [blame^] | 95 | // isParamStackCopy reports whether this is the on-stack copy of a |
| 96 | // function parameter that moved to the heap. |
| 97 | func (n *Node) isParamStackCopy() bool { |
| 98 | return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Heapaddr != nil |
| 99 | } |
| 100 | |
| 101 | // isParamHeapCopy reports whether this is the on-heap copy of |
| 102 | // a function parameter that moved to the heap. |
| 103 | func (n *Node) isParamHeapCopy() bool { |
| 104 | return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil |
| 105 | } |
| 106 | |
| 107 | // paramClass reports the parameter class (PPARAM or PPARAMOUT) |
| 108 | // of the node, which may be an unmoved on-stack parameter |
| 109 | // or the on-heap or on-stack copy of a parameter that moved to the heap. |
| 110 | // If the node is not a parameter, paramClass returns Pxxx. |
| 111 | func (n *Node) paramClass() Class { |
| 112 | if n.Op != ONAME { |
| 113 | return Pxxx |
| 114 | } |
| 115 | if n.Class == PPARAM || n.Class == PPARAMOUT { |
| 116 | return n.Class |
| 117 | } |
| 118 | if n.isParamHeapCopy() { |
| 119 | return n.Name.Param.Stackcopy.Class |
| 120 | } |
| 121 | return Pxxx |
| 122 | } |
| 123 | |
| 124 | // moveToHeap records the parameter or local variable n as moved to the heap. |
| 125 | func moveToHeap(n *Node) { |
| 126 | if Debug['r'] != 0 { |
| 127 | Dump("MOVE", n) |
| 128 | } |
| 129 | if compiling_runtime { |
| 130 | Yyerror("%v escapes to heap, not allowed in runtime.", n) |
| 131 | } |
| 132 | if n.Class == PAUTOHEAP { |
| 133 | Dump("n", n) |
| 134 | Fatalf("double move to heap") |
| 135 | } |
| 136 | |
| 137 | // Allocate a local stack variable to hold the pointer to the heap copy. |
| 138 | // temp will add it to the function declaration list automatically. |
| 139 | heapaddr := temp(Ptrto(n.Type)) |
| 140 | heapaddr.Sym = Lookup("&" + n.Sym.Name) |
| 141 | heapaddr.Orig.Sym = heapaddr.Sym |
| 142 | |
| 143 | // Parameters have a local stack copy used at function start/end |
| 144 | // in addition to the copy in the heap that may live longer than |
| 145 | // the function. |
| 146 | if n.Class == PPARAM || n.Class == PPARAMOUT { |
| 147 | if n.Xoffset == BADWIDTH { |
| 148 | Fatalf("addrescapes before param assignment") |
| 149 | } |
| 150 | |
| 151 | // We rewrite n below to be a heap variable (indirection of heapaddr). |
| 152 | // Preserve a copy so we can still write code referring to the original, |
| 153 | // and substitute that copy into the function declaration list |
| 154 | // so that analyses of the local (on-stack) variables use it. |
| 155 | stackcopy := Nod(ONAME, nil, nil) |
| 156 | stackcopy.Sym = n.Sym |
| 157 | stackcopy.Type = n.Type |
| 158 | stackcopy.Xoffset = n.Xoffset |
| 159 | stackcopy.Class = n.Class |
| 160 | stackcopy.Name.Heapaddr = heapaddr |
| 161 | if n.Class == PPARAM { |
| 162 | stackcopy.SetNotLiveAtEnd(true) |
| 163 | } |
| 164 | n.Name.Param.Stackcopy = stackcopy |
| 165 | |
| 166 | // Substitute the stackcopy into the function variable list so that |
| 167 | // liveness and other analyses use the underlying stack slot |
| 168 | // and not the now-pseudo-variable n. |
| 169 | found := false |
| 170 | for i, d := range Curfn.Func.Dcl { |
| 171 | if d == n { |
| 172 | Curfn.Func.Dcl[i] = stackcopy |
| 173 | found = true |
| 174 | break |
| 175 | } |
| 176 | // Parameters are before locals, so can stop early. |
| 177 | // This limits the search even in functions with many local variables. |
| 178 | if d.Class == PAUTO { |
| 179 | break |
| 180 | } |
| 181 | } |
| 182 | if !found { |
| 183 | Fatalf("cannot find %v in local variable list", n) |
| 184 | } |
| 185 | Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) |
| 186 | } |
| 187 | |
| 188 | // Modify n in place so that uses of n now mean indirection of the heapaddr. |
| 189 | n.Class = PAUTOHEAP |
| 190 | n.Ullman = 2 |
| 191 | n.Xoffset = 0 |
| 192 | n.Name.Heapaddr = heapaddr |
| 193 | n.Esc = EscHeap |
| 194 | if Debug['m'] != 0 { |
| 195 | fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) |
| 196 | } |
| 197 | } |
| 198 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 199 | func clearlabels() { |
Robert Griesemer | def9c0b | 2016-03-10 20:35:27 -0800 | [diff] [blame] | 200 | for _, l := range labellist { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 201 | l.Sym.Label = nil |
| 202 | } |
Robert Griesemer | def9c0b | 2016-03-10 20:35:27 -0800 | [diff] [blame] | 203 | labellist = labellist[:0] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | func newlab(n *Node) *Label { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 207 | s := n.Left.Sym |
| 208 | lab := s.Label |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 209 | if lab == nil { |
| 210 | lab = new(Label) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 211 | lab.Sym = s |
| 212 | s.Label = lab |
Robert Griesemer | def9c0b | 2016-03-10 20:35:27 -0800 | [diff] [blame] | 213 | labellist = append(labellist, lab) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 214 | } |
| 215 | |
| 216 | if n.Op == OLABEL { |
| 217 | if lab.Def != nil { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 218 | Yyerror("label %v already defined at %v", s, lab.Def.Line()) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 219 | } else { |
| 220 | lab.Def = n |
| 221 | } |
| 222 | } else { |
Håvard Haugen | dd42eff | 2015-08-30 22:24:53 +0200 | [diff] [blame] | 223 | lab.Use = append(lab.Use, n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 224 | } |
| 225 | |
| 226 | return lab |
| 227 | } |
| 228 | |
Josh Bleecher Snyder | 61aa095 | 2015-07-20 15:39:14 -0700 | [diff] [blame] | 229 | // There is a copy of checkgoto in the new SSA backend. |
| 230 | // Please keep them in sync. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 231 | func checkgoto(from *Node, to *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 232 | if from.Sym == to.Sym { |
| 233 | return |
| 234 | } |
| 235 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 236 | nf := 0 |
| 237 | for fs := from.Sym; fs != nil; fs = fs.Link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 238 | nf++ |
| 239 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 240 | nt := 0 |
| 241 | for fs := to.Sym; fs != nil; fs = fs.Link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 242 | nt++ |
| 243 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 244 | fs := from.Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 245 | for ; nf > nt; nf-- { |
| 246 | fs = fs.Link |
| 247 | } |
| 248 | if fs != to.Sym { |
Robert Griesemer | c41608f | 2016-03-02 17:34:42 -0800 | [diff] [blame] | 249 | lno := lineno |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 250 | setlineno(from) |
| 251 | |
| 252 | // decide what to complain about. |
| 253 | // prefer to complain about 'into block' over declarations, |
| 254 | // so scan backward to find most recent block or else dcl. |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 255 | var block *Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 256 | |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 257 | var dcl *Sym |
Brad Fitzpatrick | 97494a4 | 2015-05-15 16:35:43 +0000 | [diff] [blame] | 258 | ts := to.Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 259 | for ; nt > nf; nt-- { |
| 260 | if ts.Pkg == nil { |
| 261 | block = ts |
Brad Fitzpatrick | 97494a4 | 2015-05-15 16:35:43 +0000 | [diff] [blame] | 262 | } else { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 263 | dcl = ts |
| 264 | } |
| 265 | ts = ts.Link |
| 266 | } |
| 267 | |
| 268 | for ts != fs { |
| 269 | if ts.Pkg == nil { |
| 270 | block = ts |
Brad Fitzpatrick | 97494a4 | 2015-05-15 16:35:43 +0000 | [diff] [blame] | 271 | } else { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 272 | dcl = ts |
| 273 | } |
| 274 | ts = ts.Link |
| 275 | fs = fs.Link |
| 276 | } |
| 277 | |
| 278 | if block != nil { |
Robert Griesemer | 2faf5bc | 2016-03-02 11:30:29 -0800 | [diff] [blame] | 279 | Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 280 | } else { |
Robert Griesemer | 2faf5bc | 2016-03-02 11:30:29 -0800 | [diff] [blame] | 281 | Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 282 | } |
Robert Griesemer | c41608f | 2016-03-02 17:34:42 -0800 | [diff] [blame] | 283 | lineno = lno |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 284 | } |
| 285 | } |
| 286 | |
| 287 | func stmtlabel(n *Node) *Label { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 288 | if n.Sym != nil { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 289 | lab := n.Sym.Label |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 290 | if lab != nil { |
| 291 | if lab.Def != nil { |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 292 | if lab.Def.Name.Defn == n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 293 | return lab |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | return nil |
| 299 | } |
| 300 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 301 | // compile statements |
Ian Lance Taylor | c4012b6 | 2016-03-08 10:26:20 -0800 | [diff] [blame] | 302 | func Genlist(l Nodes) { |
Ian Lance Taylor | 38921b3 | 2016-03-08 15:10:26 -0800 | [diff] [blame] | 303 | for _, n := range l.Slice() { |
| 304 | gen(n) |
Ian Lance Taylor | 188e3d2 | 2016-02-26 14:28:48 -0800 | [diff] [blame] | 305 | } |
| 306 | } |
| 307 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 308 | // generate code to start new proc running call n. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 309 | func cgen_proc(n *Node, proc int) { |
| 310 | switch n.Left.Op { |
| 311 | default: |
Dave Cheney | d3c79d3 | 2016-04-27 15:10:10 +1000 | [diff] [blame] | 312 | Fatalf("cgen_proc: unknown call %v", n.Left.Op) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 313 | |
| 314 | case OCALLMETH: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 315 | cgen_callmeth(n.Left, proc) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 316 | |
| 317 | case OCALLINTER: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 318 | cgen_callinter(n.Left, nil, proc) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 319 | |
| 320 | case OCALLFUNC: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 321 | cgen_call(n.Left, proc) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 322 | } |
| 323 | } |
| 324 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 325 | // generate declaration. |
| 326 | // have to allocate heap copy |
| 327 | // for escaped variables. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 328 | func cgen_dcl(n *Node) { |
| 329 | if Debug['g'] != 0 { |
| 330 | Dump("\ncgen-dcl", n) |
| 331 | } |
| 332 | if n.Op != ONAME { |
| 333 | Dump("cgen_dcl", n) |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 334 | Fatalf("cgen_dcl") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 335 | } |
| 336 | |
Russ Cox | b6dc3e6 | 2016-05-25 01:33:24 -0400 | [diff] [blame^] | 337 | if n.Class == PAUTOHEAP { |
| 338 | Fatalf("cgen_dcl %v", n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 339 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 340 | } |
| 341 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 342 | // generate discard of value |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 343 | func cgen_discard(nr *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 344 | if nr == nil { |
| 345 | return |
| 346 | } |
| 347 | |
| 348 | switch nr.Op { |
| 349 | case ONAME: |
Russ Cox | b6dc3e6 | 2016-05-25 01:33:24 -0400 | [diff] [blame^] | 350 | if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 351 | gused(nr) |
| 352 | } |
| 353 | |
| 354 | // unary |
| 355 | case OADD, |
| 356 | OAND, |
| 357 | ODIV, |
| 358 | OEQ, |
| 359 | OGE, |
| 360 | OGT, |
| 361 | OLE, |
| 362 | OLSH, |
| 363 | OLT, |
| 364 | OMOD, |
| 365 | OMUL, |
| 366 | ONE, |
| 367 | OOR, |
| 368 | ORSH, |
| 369 | OSUB, |
| 370 | OXOR: |
| 371 | cgen_discard(nr.Left) |
| 372 | |
| 373 | cgen_discard(nr.Right) |
| 374 | |
| 375 | // binary |
| 376 | case OCAP, |
| 377 | OCOM, |
| 378 | OLEN, |
| 379 | OMINUS, |
| 380 | ONOT, |
| 381 | OPLUS: |
| 382 | cgen_discard(nr.Left) |
| 383 | |
| 384 | case OIND: |
| 385 | Cgen_checknil(nr.Left) |
| 386 | |
| 387 | // special enough to just evaluate |
| 388 | default: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 389 | var tmp Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 390 | Tempname(&tmp, nr.Type) |
| 391 | |
| 392 | Cgen_as(&tmp, nr) |
| 393 | gused(&tmp) |
| 394 | } |
| 395 | } |
| 396 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 397 | // clearslim generates code to zero a slim node. |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 398 | func Clearslim(n *Node) { |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 399 | var z Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 400 | z.Op = OLITERAL |
| 401 | z.Type = n.Type |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 402 | z.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 403 | |
| 404 | switch Simtype[n.Type.Etype] { |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 405 | case TCOMPLEX64, TCOMPLEX128: |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 406 | z.SetVal(Val{new(Mpcplx)}) |
Matthew Dempsky | d325387 | 2016-03-20 13:55:42 -0700 | [diff] [blame] | 407 | z.Val().U.(*Mpcplx).Real.SetFloat64(0.0) |
| 408 | z.Val().U.(*Mpcplx).Imag.SetFloat64(0.0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 409 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 410 | case TFLOAT32, TFLOAT64: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 411 | var zero Mpflt |
Matthew Dempsky | d325387 | 2016-03-20 13:55:42 -0700 | [diff] [blame] | 412 | zero.SetFloat64(0.0) |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 413 | z.SetVal(Val{&zero}) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 414 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 415 | case TPTR32, TPTR64, TCHAN, TMAP: |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 416 | z.SetVal(Val{new(NilVal)}) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 417 | |
| 418 | case TBOOL: |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 419 | z.SetVal(Val{false}) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 420 | |
| 421 | case TINT8, |
| 422 | TINT16, |
| 423 | TINT32, |
| 424 | TINT64, |
| 425 | TUINT8, |
| 426 | TUINT16, |
| 427 | TUINT32, |
| 428 | TUINT64: |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 429 | z.SetVal(Val{new(Mpint)}) |
Matthew Dempsky | d325387 | 2016-03-20 13:55:42 -0700 | [diff] [blame] | 430 | z.Val().U.(*Mpint).SetInt64(0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 431 | |
| 432 | default: |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 433 | Fatalf("clearslim called on type %v", n.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 434 | } |
| 435 | |
| 436 | ullmancalc(&z) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 437 | Cgen(&z, n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 438 | } |
| 439 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 440 | // generate: |
| 441 | // res = iface{typ, data} |
| 442 | // n->left is typ |
| 443 | // n->right is data |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 444 | func Cgen_eface(n *Node, res *Node) { |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 445 | // the right node of an eface may contain function calls that uses res as an argument, |
| 446 | // so it's important that it is done first |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 447 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 448 | tmp := temp(Types[Tptr]) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 449 | Cgen(n.Right, tmp) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 450 | |
| 451 | Gvardef(res) |
| 452 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 453 | dst := *res |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 454 | dst.Type = Types[Tptr] |
| 455 | dst.Xoffset += int64(Widthptr) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 456 | Cgen(tmp, &dst) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 457 | |
| 458 | dst.Xoffset -= int64(Widthptr) |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 459 | Cgen(n.Left, &dst) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 460 | } |
| 461 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 462 | // generate one of: |
| 463 | // res, resok = x.(T) |
| 464 | // res = x.(T) (when resok == nil) |
| 465 | // n.Left is x |
| 466 | // n.Type is T |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 467 | func cgen_dottype(n *Node, res, resok *Node, wb bool) { |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 468 | if Debug_typeassert > 0 { |
| 469 | Warn("type assertion inlined") |
| 470 | } |
| 471 | // iface := n.Left |
| 472 | // r1 := iword(iface) |
| 473 | // if n.Left is non-empty interface { |
| 474 | // r1 = *r1 |
| 475 | // } |
| 476 | // if r1 == T { |
| 477 | // res = idata(iface) |
| 478 | // resok = true |
| 479 | // } else { |
| 480 | // assert[EI]2T(x, T, nil) // (when resok == nil; does not return) |
| 481 | // resok = false // (when resok != nil) |
| 482 | // } |
| 483 | // |
| 484 | var iface Node |
| 485 | Igen(n.Left, &iface, res) |
| 486 | var r1, r2 Node |
| 487 | byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte) |
| 488 | Regalloc(&r1, byteptr, nil) |
| 489 | iface.Type = byteptr |
| 490 | Cgen(&iface, &r1) |
Matthew Dempsky | 00e5a68 | 2016-04-01 13:36:24 -0700 | [diff] [blame] | 491 | if !n.Left.Type.IsEmptyInterface() { |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 492 | // Holding itab, want concrete type in second word. |
Russ Cox | f8d14fc | 2015-05-06 12:28:19 -0400 | [diff] [blame] | 493 | p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 494 | r2 = r1 |
| 495 | r2.Op = OINDREG |
| 496 | r2.Xoffset = int64(Widthptr) |
| 497 | Cgen(&r2, &r1) |
| 498 | Patch(p, Pc) |
| 499 | } |
| 500 | Regalloc(&r2, byteptr, nil) |
| 501 | Cgen(typename(n.Type), &r2) |
Russ Cox | f8d14fc | 2015-05-06 12:28:19 -0400 | [diff] [blame] | 502 | p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1) |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 503 | Regfree(&r2) // not needed for success path; reclaimed on one failure path |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 504 | iface.Xoffset += int64(Widthptr) |
| 505 | Cgen(&iface, &r1) |
| 506 | Regfree(&iface) |
| 507 | |
| 508 | if resok == nil { |
| 509 | r1.Type = res.Type |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 510 | cgen_wb(&r1, res, wb) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 511 | q := Gbranch(obj.AJMP, nil, 0) |
| 512 | Patch(p, Pc) |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 513 | Regrealloc(&r2) // reclaim from above, for this failure path |
Matthew Dempsky | dafbcf6 | 2016-03-04 15:19:06 -0800 | [diff] [blame] | 514 | fn := syslook("panicdottype") |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 515 | dowidth(fn.Type) |
| 516 | call := Nod(OCALLFUNC, fn, nil) |
| 517 | r1.Type = byteptr |
| 518 | r2.Type = byteptr |
Ian Lance Taylor | f444b8a | 2016-03-09 20:29:21 -0800 | [diff] [blame] | 519 | call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)}) |
Matthew Dempsky | d20b92e | 2016-03-09 19:32:10 -0800 | [diff] [blame] | 520 | call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil)) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 521 | gen(call) |
| 522 | Regfree(&r1) |
| 523 | Regfree(&r2) |
| 524 | Thearch.Gins(obj.AUNDEF, nil, nil) |
| 525 | Patch(q, Pc) |
| 526 | } else { |
| 527 | // This half is handling the res, resok = x.(T) case, |
| 528 | // which is called from gen, not cgen, and is consequently fussier |
| 529 | // about blank assignments. We have to avoid calling cgen for those. |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 530 | r1.Type = res.Type |
| 531 | if !isblank(res) { |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 532 | cgen_wb(&r1, res, wb) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 533 | } |
| 534 | Regfree(&r1) |
| 535 | if !isblank(resok) { |
| 536 | Cgen(Nodbool(true), resok) |
| 537 | } |
| 538 | q := Gbranch(obj.AJMP, nil, 0) |
| 539 | Patch(p, Pc) |
| 540 | if !isblank(res) { |
| 541 | n := nodnil() |
| 542 | n.Type = res.Type |
| 543 | Cgen(n, res) |
| 544 | } |
| 545 | if !isblank(resok) { |
| 546 | Cgen(Nodbool(false), resok) |
| 547 | } |
| 548 | Patch(q, Pc) |
| 549 | } |
| 550 | } |
| 551 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 552 | // generate: |
| 553 | // res, resok = x.(T) |
| 554 | // n.Left is x |
| 555 | // n.Type is T |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 556 | func Cgen_As2dottype(n, res, resok *Node) { |
| 557 | if Debug_typeassert > 0 { |
| 558 | Warn("type assertion inlined") |
| 559 | } |
| 560 | // iface := n.Left |
| 561 | // r1 := iword(iface) |
| 562 | // if n.Left is non-empty interface { |
| 563 | // r1 = *r1 |
| 564 | // } |
| 565 | // if r1 == T { |
| 566 | // res = idata(iface) |
| 567 | // resok = true |
| 568 | // } else { |
| 569 | // res = nil |
| 570 | // resok = false |
| 571 | // } |
| 572 | // |
| 573 | var iface Node |
| 574 | Igen(n.Left, &iface, nil) |
| 575 | var r1, r2 Node |
| 576 | byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte) |
| 577 | Regalloc(&r1, byteptr, res) |
| 578 | iface.Type = byteptr |
| 579 | Cgen(&iface, &r1) |
Matthew Dempsky | 00e5a68 | 2016-04-01 13:36:24 -0700 | [diff] [blame] | 580 | if !n.Left.Type.IsEmptyInterface() { |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 581 | // Holding itab, want concrete type in second word. |
Russ Cox | f8d14fc | 2015-05-06 12:28:19 -0400 | [diff] [blame] | 582 | p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 583 | r2 = r1 |
| 584 | r2.Op = OINDREG |
| 585 | r2.Xoffset = int64(Widthptr) |
| 586 | Cgen(&r2, &r1) |
| 587 | Patch(p, Pc) |
| 588 | } |
| 589 | Regalloc(&r2, byteptr, nil) |
| 590 | Cgen(typename(n.Type), &r2) |
Russ Cox | f8d14fc | 2015-05-06 12:28:19 -0400 | [diff] [blame] | 591 | p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 592 | iface.Type = n.Type |
| 593 | iface.Xoffset += int64(Widthptr) |
| 594 | Cgen(&iface, &r1) |
| 595 | if iface.Op != 0 { |
| 596 | Regfree(&iface) |
| 597 | } |
| 598 | Cgen(&r1, res) |
| 599 | q := Gbranch(obj.AJMP, nil, 0) |
| 600 | Patch(p, Pc) |
| 601 | |
Matthew Dempsky | dafbcf6 | 2016-03-04 15:19:06 -0800 | [diff] [blame] | 602 | fn := syslook("panicdottype") |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 603 | dowidth(fn.Type) |
| 604 | call := Nod(OCALLFUNC, fn, nil) |
Ian Lance Taylor | f444b8a | 2016-03-09 20:29:21 -0800 | [diff] [blame] | 605 | call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)}) |
Matthew Dempsky | d20b92e | 2016-03-09 19:32:10 -0800 | [diff] [blame] | 606 | call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil)) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 607 | gen(call) |
| 608 | Regfree(&r1) |
| 609 | Regfree(&r2) |
| 610 | Thearch.Gins(obj.AUNDEF, nil, nil) |
| 611 | Patch(q, Pc) |
| 612 | } |
| 613 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 614 | // gather series of offsets |
| 615 | // >=0 is direct addressed field |
| 616 | // <0 is pointer to next field (+1) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 617 | func Dotoffset(n *Node, oary []int64, nn **Node) int { |
| 618 | var i int |
| 619 | |
| 620 | switch n.Op { |
| 621 | case ODOT: |
| 622 | if n.Xoffset == BADWIDTH { |
| 623 | Dump("bad width in dotoffset", n) |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 624 | Fatalf("bad width in dotoffset") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 625 | } |
| 626 | |
| 627 | i = Dotoffset(n.Left, oary, nn) |
| 628 | if i > 0 { |
| 629 | if oary[i-1] >= 0 { |
| 630 | oary[i-1] += n.Xoffset |
| 631 | } else { |
| 632 | oary[i-1] -= n.Xoffset |
| 633 | } |
| 634 | break |
| 635 | } |
| 636 | |
| 637 | if i < 10 { |
| 638 | oary[i] = n.Xoffset |
| 639 | i++ |
| 640 | } |
| 641 | |
| 642 | case ODOTPTR: |
| 643 | if n.Xoffset == BADWIDTH { |
| 644 | Dump("bad width in dotoffset", n) |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 645 | Fatalf("bad width in dotoffset") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 646 | } |
| 647 | |
| 648 | i = Dotoffset(n.Left, oary, nn) |
| 649 | if i < 10 { |
| 650 | oary[i] = -(n.Xoffset + 1) |
| 651 | i++ |
| 652 | } |
| 653 | |
| 654 | default: |
| 655 | *nn = n |
| 656 | return 0 |
| 657 | } |
| 658 | |
| 659 | if i >= 10 { |
| 660 | *nn = nil |
| 661 | } |
| 662 | return i |
| 663 | } |
| 664 | |
Jeremy Jackins | 6327e8d | 2015-10-22 09:51:12 +0900 | [diff] [blame] | 665 | // make a new off the books |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 666 | func Tempname(nn *Node, t *Type) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 667 | if Curfn == nil { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 668 | Fatalf("no curfn for tempname") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 669 | } |
Ian Lance Taylor | b66a892 | 2016-02-25 10:35:19 -0800 | [diff] [blame] | 670 | if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE { |
| 671 | Dump("Tempname", Curfn) |
| 672 | Fatalf("adding tempname to wrong closure function") |
| 673 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 674 | |
| 675 | if t == nil { |
| 676 | Yyerror("tempname called with nil type") |
| 677 | t = Types[TINT32] |
| 678 | } |
| 679 | |
| 680 | // give each tmp a different name so that there |
| 681 | // a chance to registerizer them |
Brad Fitzpatrick | 060a691 | 2016-03-19 18:17:58 -0700 | [diff] [blame] | 682 | s := LookupN("autotmp_", statuniqgen) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 683 | statuniqgen++ |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 684 | n := Nod(ONAME, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 685 | n.Sym = s |
| 686 | s.Def = n |
| 687 | n.Type = t |
| 688 | n.Class = PAUTO |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 689 | n.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 690 | n.Ullman = 1 |
| 691 | n.Esc = EscNever |
Russ Cox | fd2154f | 2015-05-27 07:31:56 -0400 | [diff] [blame] | 692 | n.Name.Curfn = Curfn |
Ian Lance Taylor | b66a892 | 2016-02-25 10:35:19 -0800 | [diff] [blame] | 693 | Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 694 | |
| 695 | dowidth(t) |
| 696 | n.Xoffset = 0 |
| 697 | *nn = *n |
| 698 | } |
| 699 | |
| 700 | func temp(t *Type) *Node { |
Dave Cheney | edca4cd | 2016-03-23 16:01:15 +1100 | [diff] [blame] | 701 | var n Node |
| 702 | Tempname(&n, t) |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 703 | n.Sym.Def.Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 704 | return n.Orig |
| 705 | } |
| 706 | |
| 707 | func gen(n *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 708 | //dump("gen", n); |
| 709 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 710 | lno := setlineno(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 711 | |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 712 | wasregalloc := Anyregalloc() |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 713 | |
| 714 | if n == nil { |
| 715 | goto ret |
| 716 | } |
| 717 | |
Ian Lance Taylor | 38921b3 | 2016-03-08 15:10:26 -0800 | [diff] [blame] | 718 | if n.Ninit.Len() > 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 719 | Genlist(n.Ninit) |
| 720 | } |
| 721 | |
| 722 | setlineno(n) |
| 723 | |
| 724 | switch n.Op { |
| 725 | default: |
Matthew Dempsky | 6314202 | 2016-03-15 13:06:58 -0700 | [diff] [blame] | 726 | Fatalf("gen: unknown op %v", Nconv(n, FmtShort|FmtSign)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 727 | |
| 728 | case OCASE, |
| 729 | OFALL, |
| 730 | OXCASE, |
| 731 | OXFALL, |
| 732 | ODCLCONST, |
| 733 | ODCLFUNC, |
| 734 | ODCLTYPE: |
| 735 | break |
| 736 | |
| 737 | case OEMPTY: |
| 738 | break |
| 739 | |
| 740 | case OBLOCK: |
| 741 | Genlist(n.List) |
| 742 | |
| 743 | case OLABEL: |
| 744 | if isblanksym(n.Left.Sym) { |
| 745 | break |
| 746 | } |
| 747 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 748 | lab := newlab(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 749 | |
| 750 | // if there are pending gotos, resolve them all to the current pc. |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 751 | var p2 *obj.Prog |
| 752 | for p1 := lab.Gotopc; p1 != nil; p1 = p2 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 753 | p2 = unpatch(p1) |
| 754 | Patch(p1, Pc) |
| 755 | } |
| 756 | |
| 757 | lab.Gotopc = nil |
| 758 | if lab.Labelpc == nil { |
| 759 | lab.Labelpc = Pc |
| 760 | } |
| 761 | |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 762 | if n.Name.Defn != nil { |
| 763 | switch n.Name.Defn.Op { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 764 | // so stmtlabel can find the label |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 765 | case OFOR, OSWITCH, OSELECT: |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 766 | n.Name.Defn.Sym = lab.Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 767 | } |
| 768 | } |
| 769 | |
| 770 | // if label is defined, emit jump to it. |
| 771 | // otherwise save list of pending gotos in lab->gotopc. |
| 772 | // the list is linked through the normal jump target field |
| 773 | // to avoid a second list. (the jumps are actually still |
| 774 | // valid code, since they're just going to another goto |
| 775 | // to the same label. we'll unwind it when we learn the pc |
| 776 | // of the label in the OLABEL case above.) |
| 777 | case OGOTO: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 778 | lab := newlab(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 779 | |
| 780 | if lab.Labelpc != nil { |
| 781 | gjmp(lab.Labelpc) |
| 782 | } else { |
| 783 | lab.Gotopc = gjmp(lab.Gotopc) |
| 784 | } |
| 785 | |
| 786 | case OBREAK: |
| 787 | if n.Left != nil { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 788 | lab := n.Left.Sym.Label |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 789 | if lab == nil { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 790 | Yyerror("break label not defined: %v", n.Left.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 791 | break |
| 792 | } |
| 793 | |
Dave Cheney | 8712e18 | 2015-09-07 11:11:14 +1000 | [diff] [blame] | 794 | lab.Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 795 | if lab.Breakpc == nil { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 796 | Yyerror("invalid break label %v", n.Left.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 797 | break |
| 798 | } |
| 799 | |
| 800 | gjmp(lab.Breakpc) |
| 801 | break |
| 802 | } |
| 803 | |
| 804 | if breakpc == nil { |
| 805 | Yyerror("break is not in a loop") |
| 806 | break |
| 807 | } |
| 808 | |
| 809 | gjmp(breakpc) |
| 810 | |
| 811 | case OCONTINUE: |
| 812 | if n.Left != nil { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 813 | lab := n.Left.Sym.Label |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 814 | if lab == nil { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 815 | Yyerror("continue label not defined: %v", n.Left.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 816 | break |
| 817 | } |
| 818 | |
Dave Cheney | 8712e18 | 2015-09-07 11:11:14 +1000 | [diff] [blame] | 819 | lab.Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 820 | if lab.Continpc == nil { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 821 | Yyerror("invalid continue label %v", n.Left.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 822 | break |
| 823 | } |
| 824 | |
| 825 | gjmp(lab.Continpc) |
| 826 | break |
| 827 | } |
| 828 | |
| 829 | if continpc == nil { |
| 830 | Yyerror("continue is not in a loop") |
| 831 | break |
| 832 | } |
| 833 | |
| 834 | gjmp(continpc) |
| 835 | |
| 836 | case OFOR: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 837 | sbreak := breakpc |
| 838 | p1 := gjmp(nil) // goto test |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 839 | breakpc = gjmp(nil) // break: goto done |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 840 | scontin := continpc |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 841 | continpc = Pc |
| 842 | |
| 843 | // define break and continue labels |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 844 | lab := stmtlabel(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 845 | if lab != nil { |
| 846 | lab.Breakpc = breakpc |
| 847 | lab.Continpc = continpc |
| 848 | } |
| 849 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 850 | gen(n.Right) // contin: incr |
| 851 | Patch(p1, Pc) // test: |
| 852 | Bgen(n.Left, false, -1, breakpc) // if(!test) goto break |
Ian Lance Taylor | bf39098 | 2016-03-03 15:08:25 -0800 | [diff] [blame] | 853 | Genlist(n.Nbody) // body |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 854 | gjmp(continpc) |
| 855 | Patch(breakpc, Pc) // done: |
| 856 | continpc = scontin |
| 857 | breakpc = sbreak |
| 858 | if lab != nil { |
| 859 | lab.Breakpc = nil |
| 860 | lab.Continpc = nil |
| 861 | } |
| 862 | |
| 863 | case OIF: |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 864 | p1 := gjmp(nil) // goto test |
| 865 | p2 := gjmp(nil) // p2: goto else |
| 866 | Patch(p1, Pc) // test: |
| 867 | Bgen(n.Left, false, int(-n.Likely), p2) // if(!test) goto p2 |
Ian Lance Taylor | bf39098 | 2016-03-03 15:08:25 -0800 | [diff] [blame] | 868 | Genlist(n.Nbody) // then |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 869 | p3 := gjmp(nil) // goto done |
| 870 | Patch(p2, Pc) // else: |
| 871 | Genlist(n.Rlist) // else |
| 872 | Patch(p3, Pc) // done: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 873 | |
| 874 | case OSWITCH: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 875 | sbreak := breakpc |
| 876 | p1 := gjmp(nil) // goto test |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 877 | breakpc = gjmp(nil) // break: goto done |
| 878 | |
| 879 | // define break label |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 880 | lab := stmtlabel(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 881 | if lab != nil { |
| 882 | lab.Breakpc = breakpc |
| 883 | } |
| 884 | |
Ian Lance Taylor | bf39098 | 2016-03-03 15:08:25 -0800 | [diff] [blame] | 885 | Patch(p1, Pc) // test: |
| 886 | Genlist(n.Nbody) // switch(test) body |
| 887 | Patch(breakpc, Pc) // done: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 888 | breakpc = sbreak |
| 889 | if lab != nil { |
| 890 | lab.Breakpc = nil |
| 891 | } |
| 892 | |
| 893 | case OSELECT: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 894 | sbreak := breakpc |
| 895 | p1 := gjmp(nil) // goto test |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 896 | breakpc = gjmp(nil) // break: goto done |
| 897 | |
| 898 | // define break label |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 899 | lab := stmtlabel(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 900 | if lab != nil { |
| 901 | lab.Breakpc = breakpc |
| 902 | } |
| 903 | |
Ian Lance Taylor | bf39098 | 2016-03-03 15:08:25 -0800 | [diff] [blame] | 904 | Patch(p1, Pc) // test: |
| 905 | Genlist(n.Nbody) // select() body |
| 906 | Patch(breakpc, Pc) // done: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 907 | breakpc = sbreak |
| 908 | if lab != nil { |
| 909 | lab.Breakpc = nil |
| 910 | } |
| 911 | |
| 912 | case ODCL: |
| 913 | cgen_dcl(n.Left) |
| 914 | |
| 915 | case OAS: |
Josh Bleecher Snyder | 6b41665 | 2015-07-28 10:56:39 -0700 | [diff] [blame] | 916 | if gen_as_init(n, false) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 917 | break |
| 918 | } |
| 919 | Cgen_as(n.Left, n.Right) |
| 920 | |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 921 | case OASWB: |
| 922 | Cgen_as_wb(n.Left, n.Right, true) |
| 923 | |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 924 | case OAS2DOTTYPE: |
Ian Lance Taylor | 38921b3 | 2016-03-08 15:10:26 -0800 | [diff] [blame] | 925 | cgen_dottype(n.Rlist.First(), n.List.First(), n.List.Second(), needwritebarrier(n.List.First(), n.Rlist.First())) |
Russ Cox | 4224d81 | 2015-03-20 00:06:10 -0400 | [diff] [blame] | 926 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 927 | case OCALLMETH: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 928 | cgen_callmeth(n, 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 929 | |
| 930 | case OCALLINTER: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 931 | cgen_callinter(n, nil, 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 932 | |
| 933 | case OCALLFUNC: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 934 | cgen_call(n, 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 935 | |
| 936 | case OPROC: |
| 937 | cgen_proc(n, 1) |
| 938 | |
| 939 | case ODEFER: |
| 940 | cgen_proc(n, 2) |
| 941 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 942 | case ORETURN, ORETJMP: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 943 | cgen_ret(n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 944 | |
Russ Cox | 92c826b | 2015-04-03 12:23:28 -0400 | [diff] [blame] | 945 | // Function calls turned into compiler intrinsics. |
| 946 | // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any. |
| 947 | case OGETG: |
| 948 | // nothing |
Russ Cox | 92dba0d | 2015-04-01 16:02:34 -0400 | [diff] [blame] | 949 | case OSQRT: |
| 950 | cgen_discard(n.Left) |
| 951 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 952 | case OCHECKNIL: |
| 953 | Cgen_checknil(n.Left) |
| 954 | |
| 955 | case OVARKILL: |
Michael Pratt | a4e31d4 | 2016-03-12 14:07:40 -0800 | [diff] [blame] | 956 | Gvarkill(n.Left) |
Russ Cox | 1ac637c | 2016-01-13 00:46:28 -0500 | [diff] [blame] | 957 | |
| 958 | case OVARLIVE: |
Michael Pratt | a4e31d4 | 2016-03-12 14:07:40 -0800 | [diff] [blame] | 959 | Gvarlive(n.Left) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 960 | } |
| 961 | |
| 962 | ret: |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 963 | if Anyregalloc() != wasregalloc { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 964 | Dump("node", n) |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 965 | Fatalf("registers left allocated") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 966 | } |
| 967 | |
| 968 | lineno = lno |
| 969 | } |
| 970 | |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 971 | func Cgen_as(nl, nr *Node) { |
| 972 | Cgen_as_wb(nl, nr, false) |
| 973 | } |
| 974 | |
| 975 | func Cgen_as_wb(nl, nr *Node, wb bool) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 976 | if Debug['g'] != 0 { |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 977 | op := "cgen_as" |
| 978 | if wb { |
| 979 | op = "cgen_as_wb" |
| 980 | } |
| 981 | Dump(op, nl) |
| 982 | Dump(op+" = ", nr) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 983 | } |
| 984 | |
| 985 | for nr != nil && nr.Op == OCONVNOP { |
| 986 | nr = nr.Left |
| 987 | } |
| 988 | |
| 989 | if nl == nil || isblank(nl) { |
| 990 | cgen_discard(nr) |
| 991 | return |
| 992 | } |
| 993 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 994 | if nr == nil || iszero(nr) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 995 | tl := nl.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 996 | if tl == nil { |
| 997 | return |
| 998 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 999 | if Isfat(tl) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1000 | if nl.Op == ONAME { |
| 1001 | Gvardef(nl) |
| 1002 | } |
| 1003 | Thearch.Clearfat(nl) |
| 1004 | return |
| 1005 | } |
| 1006 | |
| 1007 | Clearslim(nl) |
| 1008 | return |
| 1009 | } |
| 1010 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1011 | tl := nl.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1012 | if tl == nil { |
| 1013 | return |
| 1014 | } |
| 1015 | |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1016 | cgen_wb(nr, nl, wb) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1017 | } |
| 1018 | |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 1019 | func cgen_callmeth(n *Node, proc int) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1020 | // generate a rewrite in n2 for the method call |
| 1021 | // (p.f)(...) goes to (f)(p,...) |
| 1022 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1023 | l := n.Left |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1024 | |
| 1025 | if l.Op != ODOTMETH { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1026 | Fatalf("cgen_callmeth: not dotmethod: %v", l) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1027 | } |
| 1028 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1029 | n2 := *n |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1030 | n2.Op = OCALLFUNC |
Ian Lance Taylor | 5f525ca | 2016-03-18 16:52:30 -0700 | [diff] [blame] | 1031 | n2.Left = newname(l.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1032 | n2.Left.Type = l.Type |
| 1033 | |
| 1034 | if n2.Left.Op == ONAME { |
| 1035 | n2.Left.Class = PFUNC |
| 1036 | } |
Russ Cox | b115c35 | 2015-03-18 17:26:36 -0400 | [diff] [blame] | 1037 | cgen_call(&n2, proc) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1038 | } |
| 1039 | |
Josh Bleecher Snyder | 4a7e5bc | 2015-04-06 19:36:36 -0700 | [diff] [blame] | 1040 | // CgenTemp creates a temporary node, assigns n to it, and returns it. |
| 1041 | func CgenTemp(n *Node) *Node { |
| 1042 | var tmp Node |
| 1043 | Tempname(&tmp, n.Type) |
| 1044 | Cgen(n, &tmp) |
| 1045 | return &tmp |
| 1046 | } |
| 1047 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1048 | func checklabels() { |
Robert Griesemer | def9c0b | 2016-03-10 20:35:27 -0800 | [diff] [blame] | 1049 | for _, lab := range labellist { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1050 | if lab.Def == nil { |
Håvard Haugen | dd42eff | 2015-08-30 22:24:53 +0200 | [diff] [blame] | 1051 | for _, n := range lab.Use { |
Robert Griesemer | b83f397 | 2016-03-02 11:01:25 -0800 | [diff] [blame] | 1052 | yyerrorl(n.Lineno, "label %v not defined", lab.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1053 | } |
| 1054 | continue |
| 1055 | } |
| 1056 | |
Dave Cheney | 8712e18 | 2015-09-07 11:11:14 +1000 | [diff] [blame] | 1057 | if lab.Use == nil && !lab.Used { |
Robert Griesemer | b83f397 | 2016-03-02 11:01:25 -0800 | [diff] [blame] | 1058 | yyerrorl(lab.Def.Lineno, "label %v defined and not used", lab.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1059 | continue |
| 1060 | } |
| 1061 | |
| 1062 | if lab.Gotopc != nil { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1063 | Fatalf("label %v never resolved", lab.Sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1064 | } |
Håvard Haugen | dd42eff | 2015-08-30 22:24:53 +0200 | [diff] [blame] | 1065 | for _, n := range lab.Use { |
| 1066 | checkgoto(n, lab.Def) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1067 | } |
| 1068 | } |
| 1069 | } |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1070 | |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1071 | // Componentgen copies a composite value by moving its individual components. |
| 1072 | // Slices, strings and interfaces are supported. Small structs or arrays with |
| 1073 | // elements of basic type are also supported. |
| 1074 | // nr is nil when assigning a zero value. |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1075 | func Componentgen(nr, nl *Node) bool { |
| 1076 | return componentgen_wb(nr, nl, false) |
| 1077 | } |
| 1078 | |
| 1079 | // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates. |
| 1080 | func componentgen_wb(nr, nl *Node, wb bool) bool { |
| 1081 | // Don't generate any code for complete copy of a variable into itself. |
| 1082 | // It's useless, and the VARDEF will incorrectly mark the old value as dead. |
| 1083 | // (This check assumes that the arguments passed to componentgen did not |
| 1084 | // themselves come from Igen, or else we could have Op==ONAME but |
| 1085 | // with a Type and Xoffset describing an individual field, not the entire |
| 1086 | // variable.) |
| 1087 | if nl.Op == ONAME && nl == nr { |
| 1088 | return true |
| 1089 | } |
| 1090 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1091 | // Count number of moves required to move components. |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1092 | // If using write barrier, can only emit one pointer. |
| 1093 | // TODO(rsc): Allow more pointers, for reflect.Value. |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1094 | const maxMoves = 8 |
| 1095 | n := 0 |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1096 | numPtr := 0 |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1097 | visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { |
| 1098 | n++ |
Marvin Stenger | 8e7a3ea | 2015-09-24 23:21:18 +0200 | [diff] [blame] | 1099 | if Simtype[t.Etype] == Tptr && t != itable { |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1100 | numPtr++ |
| 1101 | } |
| 1102 | return n <= maxMoves && (!wb || numPtr <= 1) |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1103 | }) |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1104 | if n > maxMoves || wb && numPtr > 1 { |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1105 | return false |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1106 | } |
| 1107 | |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1108 | // Must call emitVardef after evaluating rhs but before writing to lhs. |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1109 | emitVardef := func() { |
| 1110 | // Emit vardef if needed. |
| 1111 | if nl.Op == ONAME { |
| 1112 | switch nl.Type.Etype { |
Matthew Dempsky | 40f1d0c | 2016-04-18 14:02:08 -0700 | [diff] [blame] | 1113 | case TARRAY, TSLICE, TSTRING, TINTER, TSTRUCT: |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1114 | Gvardef(nl) |
| 1115 | } |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1116 | } |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1117 | } |
| 1118 | |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1119 | isConstString := Isconst(nr, CTSTR) |
| 1120 | |
| 1121 | if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString { |
| 1122 | return false |
| 1123 | } |
| 1124 | |
| 1125 | var nodl Node |
| 1126 | if cadable(nl) { |
| 1127 | nodl = *nl |
| 1128 | } else { |
| 1129 | if nr != nil && !cadable(nr) && !isConstString { |
| 1130 | return false |
| 1131 | } |
| 1132 | if nr == nil || isConstString || nl.Ullman >= nr.Ullman { |
| 1133 | Igen(nl, &nodl, nil) |
| 1134 | defer Regfree(&nodl) |
| 1135 | } |
| 1136 | } |
| 1137 | lbase := nodl.Xoffset |
| 1138 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1139 | // Special case: zeroing. |
| 1140 | var nodr Node |
| 1141 | if nr == nil { |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1142 | // When zeroing, prepare a register containing zero. |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1143 | // TODO(rsc): Check that this is actually generating the best code. |
Dave Cheney | 888d44d | 2015-04-09 21:25:48 +1000 | [diff] [blame] | 1144 | if Thearch.REGZERO != 0 { |
| 1145 | // cpu has a dedicated zero register |
| 1146 | Nodreg(&nodr, Types[TUINT], Thearch.REGZERO) |
| 1147 | } else { |
| 1148 | // no dedicated zero register |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1149 | var zero Node |
| 1150 | Nodconst(&zero, nl.Type, 0) |
Dave Cheney | 888d44d | 2015-04-09 21:25:48 +1000 | [diff] [blame] | 1151 | Regalloc(&nodr, Types[TUINT], nil) |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1152 | Thearch.Gmove(&zero, &nodr) |
Dave Cheney | 888d44d | 2015-04-09 21:25:48 +1000 | [diff] [blame] | 1153 | defer Regfree(&nodr) |
| 1154 | } |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1155 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1156 | emitVardef() |
| 1157 | visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { |
| 1158 | nodl.Type = t |
| 1159 | nodl.Xoffset = lbase + offset |
| 1160 | nodr.Type = t |
Matthew Dempsky | e76fc1b | 2016-03-30 15:09:25 -0700 | [diff] [blame] | 1161 | if t.IsFloat() { |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1162 | // TODO(rsc): Cache zero register like we do for integers? |
| 1163 | Clearslim(&nodl) |
| 1164 | } else { |
| 1165 | Thearch.Gmove(&nodr, &nodl) |
| 1166 | } |
| 1167 | return true |
| 1168 | }) |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1169 | return true |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1170 | } |
| 1171 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1172 | // Special case: assignment of string constant. |
| 1173 | if isConstString { |
| 1174 | emitVardef() |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1175 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1176 | // base |
| 1177 | nodl.Type = Ptrto(Types[TUINT8]) |
| 1178 | Regalloc(&nodr, Types[Tptr], nil) |
| 1179 | p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 1180 | Datastring(nr.Val().U.(string), &p.From) |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1181 | p.From.Type = obj.TYPE_ADDR |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1182 | Thearch.Gmove(&nodr, &nodl) |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1183 | Regfree(&nodr) |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1184 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1185 | // length |
| 1186 | nodl.Type = Types[Simtype[TUINT]] |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1187 | nodl.Xoffset += int64(Array_nel) - int64(Array_array) |
Russ Cox | 81d5810 | 2015-05-27 00:47:05 -0400 | [diff] [blame] | 1188 | Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string)))) |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1189 | Thearch.Gmove(&nodr, &nodl) |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1190 | return true |
| 1191 | } |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1192 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1193 | // General case: copy nl = nr. |
| 1194 | nodr = *nr |
| 1195 | if !cadable(nr) { |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1196 | if nr.Ullman >= UINF && nodl.Op == OINDREG { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1197 | Fatalf("miscompile") |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1198 | } |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1199 | Igen(nr, &nodr, nil) |
| 1200 | defer Regfree(&nodr) |
| 1201 | } |
| 1202 | rbase := nodr.Xoffset |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1203 | |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1204 | if nodl.Op == 0 { |
| 1205 | Igen(nl, &nodl, nil) |
| 1206 | defer Regfree(&nodl) |
| 1207 | lbase = nodl.Xoffset |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1208 | } |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1209 | |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1210 | emitVardef() |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1211 | var ( |
| 1212 | ptrType *Type |
| 1213 | ptrOffset int64 |
| 1214 | ) |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1215 | visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { |
Marvin Stenger | 8e7a3ea | 2015-09-24 23:21:18 +0200 | [diff] [blame] | 1216 | if wb && Simtype[t.Etype] == Tptr && t != itable { |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1217 | if ptrType != nil { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1218 | Fatalf("componentgen_wb %v", Tconv(nl.Type, 0)) |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1219 | } |
| 1220 | ptrType = t |
| 1221 | ptrOffset = offset |
| 1222 | return true |
| 1223 | } |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1224 | nodl.Type = t |
| 1225 | nodl.Xoffset = lbase + offset |
| 1226 | nodr.Type = t |
| 1227 | nodr.Xoffset = rbase + offset |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1228 | Thearch.Gmove(&nodr, &nodl) |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1229 | return true |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1230 | }) |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1231 | if ptrType != nil { |
| 1232 | nodl.Type = ptrType |
| 1233 | nodl.Xoffset = lbase + ptrOffset |
| 1234 | nodr.Type = ptrType |
| 1235 | nodr.Xoffset = rbase + ptrOffset |
| 1236 | cgen_wbptr(&nodr, &nodl) |
| 1237 | } |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1238 | return true |
| 1239 | } |
| 1240 | |
| 1241 | // visitComponents walks the individual components of the type t, |
| 1242 | // walking into array elements, struct fields, the real and imaginary |
| 1243 | // parts of complex numbers, and on 32-bit systems the high and |
| 1244 | // low halves of 64-bit integers. |
| 1245 | // It calls f for each such component, passing the component (aka element) |
| 1246 | // type and memory offset, assuming t starts at startOffset. |
| 1247 | // If f ever returns false, visitComponents returns false without any more |
| 1248 | // calls to f. Otherwise visitComponents returns true. |
| 1249 | func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool { |
| 1250 | switch t.Etype { |
| 1251 | case TINT64: |
| 1252 | if Widthreg == 8 { |
| 1253 | break |
| 1254 | } |
| 1255 | // NOTE: Assuming little endian (signed top half at offset 4). |
| 1256 | // We don't have any 32-bit big-endian systems. |
Matthew Dempsky | c6e11fe | 2016-04-06 12:01:40 -0700 | [diff] [blame] | 1257 | if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1258 | Fatalf("unknown 32-bit architecture") |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1259 | } |
| 1260 | return f(Types[TUINT32], startOffset) && |
| 1261 | f(Types[TINT32], startOffset+4) |
| 1262 | |
| 1263 | case TUINT64: |
| 1264 | if Widthreg == 8 { |
| 1265 | break |
| 1266 | } |
| 1267 | return f(Types[TUINT32], startOffset) && |
| 1268 | f(Types[TUINT32], startOffset+4) |
| 1269 | |
| 1270 | case TCOMPLEX64: |
| 1271 | return f(Types[TFLOAT32], startOffset) && |
| 1272 | f(Types[TFLOAT32], startOffset+4) |
| 1273 | |
| 1274 | case TCOMPLEX128: |
| 1275 | return f(Types[TFLOAT64], startOffset) && |
| 1276 | f(Types[TFLOAT64], startOffset+8) |
| 1277 | |
| 1278 | case TINTER: |
Russ Cox | 0ad4f8b | 2015-04-17 00:25:10 -0400 | [diff] [blame] | 1279 | return f(itable, startOffset) && |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1280 | f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr)) |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1281 | |
| 1282 | case TSTRING: |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1283 | return f(Ptrto(Types[TUINT8]), startOffset) && |
| 1284 | f(Types[Simtype[TUINT]], startOffset+int64(Widthptr)) |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1285 | |
Matthew Dempsky | 40f1d0c | 2016-04-18 14:02:08 -0700 | [diff] [blame] | 1286 | case TSLICE: |
| 1287 | return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) && |
| 1288 | f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) && |
| 1289 | f(Types[Simtype[TUINT]], startOffset+int64(Array_cap)) |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1290 | |
Matthew Dempsky | 40f1d0c | 2016-04-18 14:02:08 -0700 | [diff] [blame] | 1291 | case TARRAY: |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1292 | // Short-circuit [1e6]struct{}. |
Josh Bleecher Snyder | 8640b51 | 2016-03-30 10:57:47 -0700 | [diff] [blame] | 1293 | if t.Elem().Width == 0 { |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1294 | return true |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1295 | } |
| 1296 | |
Josh Bleecher Snyder | 3a0783c | 2016-03-31 14:46:04 -0700 | [diff] [blame] | 1297 | for i := int64(0); i < t.NumElem(); i++ { |
Josh Bleecher Snyder | 8640b51 | 2016-03-30 10:57:47 -0700 | [diff] [blame] | 1298 | if !visitComponents(t.Elem(), startOffset+i*t.Elem().Width, f) { |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1299 | return false |
| 1300 | } |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1301 | } |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1302 | return true |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1303 | |
| 1304 | case TSTRUCT: |
Matthew Dempsky | f6bca3f | 2016-03-17 01:32:18 -0700 | [diff] [blame] | 1305 | for _, field := range t.Fields().Slice() { |
Matthew Dempsky | 62dddd4 | 2016-03-28 09:40:53 -0700 | [diff] [blame] | 1306 | if !visitComponents(field.Type, startOffset+field.Offset, f) { |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1307 | return false |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1308 | } |
| 1309 | } |
Dave Cheney | 4b21be4 | 2015-04-09 20:10:16 +1000 | [diff] [blame] | 1310 | return true |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1311 | } |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1312 | return f(t, startOffset) |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1313 | } |
| 1314 | |
| 1315 | func cadable(n *Node) bool { |
Russ Cox | 35b1dcc | 2015-04-16 16:22:30 -0400 | [diff] [blame] | 1316 | // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can. |
| 1317 | return n.Addable && n.Op == ONAME |
Russ Cox | b960263 | 2015-03-18 12:29:40 -0400 | [diff] [blame] | 1318 | } |